Skip to content

chore: numeric key props #7404

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 5 commits into
base: build/v2
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
@@ -182,7 +182,7 @@ class DomContainer extends _SharedContainer implements ClientContainer {
// (undocumented)
ensureProjectionResolved(vNode: _VirtualVNode): void;
// (undocumented)
getHostProp<T>(host: HostElement, name: string): T | null;
getHostProp<T>(host: HostElement, name: NumericPropKey): T | null;
// (undocumented)
getParentHost(host: HostElement): HostElement | null;
// (undocumented)
@@ -209,8 +209,10 @@ class DomContainer extends _SharedContainer implements ClientContainer {
scheduleRender(): Promise<void>;
// (undocumented)
setContext<T>(host: HostElement, context: ContextId<T>, value: T): void;
// Warning: (ae-forgotten-export) The symbol "NumericPropKey" needs to be exported by the entry point index.d.ts
//
// (undocumented)
setHostProp<T>(host: HostElement, name: string, value: T): void;
setHostProp<T>(host: HostElement, name: NumericPropKey, value: T): void;
// (undocumented)
vNodeLocate: (id: string | Element) => _VNode;
}
@@ -247,7 +249,7 @@ _VNode | null | undefined,
Element,
//////////////////// 6 - Element
string | undefined,
(string | null)[]
(NumericPropKey | string | null)[]
] & {
__brand__: 'ElementVNode';
};
@@ -360,7 +362,7 @@ export interface ISsrComponentFrame {
// (undocumented)
distributeChildrenIntoSlots(children: JSXChildren, parentScopedStyle: string | null, parentComponentFrame: ISsrComponentFrame | null): void;
// (undocumented)
hasSlot(slotName: string): boolean;
hasSlot(slotNameKey: NumericPropKey): boolean;
// (undocumented)
projectionComponentFrame: ISsrComponentFrame | null;
// (undocumented)
@@ -416,11 +418,11 @@ export interface JSXNode<T extends string | FunctionComponent | unknown = unknow
// @internal
export interface JSXNodeInternal<T extends string | FunctionComponent | unknown = unknown> extends JSXNode<T> {
// (undocumented)
constProps: Record<any, unknown> | null;
constProps: Record<NumericPropKey, unknown> | null;
// (undocumented)
flags: number;
// (undocumented)
varProps: Record<any, unknown>;
varProps: Record<NumericPropKey, unknown>;
}

// @public
@@ -844,7 +846,7 @@ export abstract class _SharedContainer implements Container {
// (undocumented)
abstract ensureProjectionResolved(host: HostElement): void;
// (undocumented)
abstract getHostProp<T>(host: HostElement, name: string): T | null;
abstract getHostProp<T>(host: HostElement, name: NumericPropKey): T | null;
// (undocumented)
abstract getParentHost(host: HostElement): HostElement | null;
// (undocumented)
@@ -868,7 +870,7 @@ export abstract class _SharedContainer implements Container {
// (undocumented)
abstract setContext<T>(host: HostElement, context: ContextId<T>, value: T): void;
// (undocumented)
abstract setHostProp<T>(host: HostElement, name: string, value: T): void;
abstract setHostProp<T>(host: HostElement, name: NumericPropKey, value: T): void;
// (undocumented)
trackSignalValue<T>(signal: Signal, subscriber: HostElement, property: string, data: _EffectData): T;
}
@@ -1712,7 +1714,7 @@ _VNode | null,
_VNode | null,
/////////////// 4 - First child
_VNode | null,
(string | null | boolean)[]
(NumericPropKey | string | null | boolean)[]
] & {
__brand__: 'FragmentNode' & 'HostElement';
};
50 changes: 21 additions & 29 deletions packages/qwik/src/core/client/dom-container.ts
Original file line number Diff line number Diff line change
@@ -12,27 +12,19 @@ import { inflateQRL, parseQRL, wrapDeserializerProxy } from '../shared/shared-se
import { QContainerValue, type HostElement, type ObjToProxyMap } from '../shared/types';
import { EMPTY_ARRAY } from '../shared/utils/flyweight';
import {
ELEMENT_PROPS,
ELEMENT_SEQ,
ELEMENT_SEQ_IDX,
OnRenderProp,
QBaseAttr,
QContainerAttr,
QContainerSelector,
QCtxAttr,
QInstanceAttr,
QScopedStyle,
QSlotParent,
QStyle,
QStyleSelector,
QBackRefs,
Q_PROPS_SEPARATOR,
USE_ON_LOCAL_SEQ_IDX,
getQFuncs,
QLocaleAttr,
} from '../shared/utils/markers';
import { isPromise } from '../shared/utils/promises';
import { isSlotProp } from '../shared/utils/prop';
import { isSlotProp } from '../shared/utils/numeric-prop-key-flags';
import { StaticPropId, getPropId, type NumericPropKey } from '../shared/utils/numeric-prop-key';
import { qDev } from '../shared/utils/qdev';
import {
convertScopedStyleIdsToArray,
@@ -224,18 +216,18 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
}

setContext<T>(host: HostElement, context: ContextId<T>, value: T): void {
let ctx = this.getHostProp<Array<string | unknown>>(host, QCtxAttr);
let ctx = this.getHostProp<Array<string | unknown>>(host, StaticPropId.CTX);
if (!ctx) {
this.setHostProp(host, QCtxAttr, (ctx = []));
this.setHostProp(host, StaticPropId.CTX, (ctx = []));
}
mapArray_set(ctx, context.id, value, 0);
mapArray_set(ctx, getPropId(context.id), value, 0);
}

resolveContext<T>(host: HostElement, contextId: ContextId<T>): T | undefined {
while (host) {
const ctx = this.getHostProp<Array<string | unknown>>(host, QCtxAttr);
const ctx = this.getHostProp<Array<string | unknown>>(host, StaticPropId.CTX);
if (ctx) {
const value = mapArray_get(ctx, contextId.id, 0) as T;
const value = mapArray_get(ctx, getPropId(contextId.id), 0) as T;
if (value) {
return value as T;
}
@@ -249,38 +241,38 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
let vNode = vnode_getParent(host as any);
while (vNode) {
if (vnode_isVirtualVNode(vNode)) {
if (vnode_getProp(vNode, OnRenderProp, null) !== null) {
if (vnode_getProp(vNode, StaticPropId.ON_RENDER, null) !== null) {
return vNode as any as HostElement;
}
vNode =
vnode_getParent(vNode) ||
// If virtual node, than it could be a slot so we need to read its parent.
vnode_getProp<VNode>(vNode, QSlotParent, this.vNodeLocate);
vnode_getProp<VNode>(vNode, StaticPropId.SLOT_PARENT, this.vNodeLocate);
} else {
vNode = vnode_getParent(vNode);
}
}
return null;
}

setHostProp<T>(host: HostElement, name: string, value: T): void {
setHostProp<T>(host: HostElement, name: NumericPropKey, value: T): void {
const vNode: VirtualVNode = host as any;
vnode_setProp(vNode, name, value);
}

getHostProp<T>(host: HostElement, name: string): T | null {
getHostProp<T>(host: HostElement, name: NumericPropKey): T | null {
const vNode: VirtualVNode = host as any;
let getObjectById: ((id: string) => any) | null = null;
switch (name) {
case ELEMENT_SEQ:
case ELEMENT_PROPS:
case OnRenderProp:
case QCtxAttr:
case QBackRefs:
case StaticPropId.ELEMENT_SEQ:
case StaticPropId.ELEMENT_PROPS:
case StaticPropId.ON_RENDER:
case StaticPropId.CTX:
case StaticPropId.BACK_REFS:
getObjectById = this.$getObjectById$;
break;
case ELEMENT_SEQ_IDX:
case USE_ON_LOCAL_SEQ_IDX:
case StaticPropId.ELEMENT_SEQ_IDX:
case StaticPropId.USE_ON_LOCAL_SEQ_IDX:
getObjectById = parseInt;
break;
}
@@ -319,7 +311,7 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
vNode[VNodeProps.flags] |= VNodeFlags.Resolved;
const props = vnode_getProps(vNode);
for (let i = 0; i < props.length; i = i + 2) {
const prop = props[i] as string;
const prop = props[i] as NumericPropKey;
if (isSlotProp(prop)) {
const value = props[i + 1];
if (typeof value == 'string') {
@@ -349,10 +341,10 @@ export class DomContainer extends _SharedContainer implements IClientContainer {

$appendStyle$(content: string, styleId: string, host: VirtualVNode, scoped: boolean): void {
if (scoped) {
const scopedStyleIdsString = this.getHostProp<string>(host, QScopedStyle);
const scopedStyleIdsString = this.getHostProp<string>(host, StaticPropId.SCOPED_STYLE);
const scopedStyleIds = new Set(convertScopedStyleIdsToArray(scopedStyleIdsString));
scopedStyleIds.add(styleId);
this.setHostProp(host, QScopedStyle, convertStyleIdsToString(scopedStyleIds));
this.setHostProp(host, StaticPropId.SCOPED_STYLE, convertStyleIdsToString(scopedStyleIds));
}

if (this.$styleIds$ == null) {
10 changes: 5 additions & 5 deletions packages/qwik/src/core/client/types.ts
Original file line number Diff line number Diff line change
@@ -2,11 +2,11 @@

import type { QRL } from '../shared/qrl/qrl.public';
import type { Container } from '../shared/types';
import type { NumericPropKey } from '../shared/utils/numeric-prop-key';
import type { VNodeJournal } from './vnode';

export type ClientAttrKey = string;
export type ClientAttrValue = string | null;
export type ClientAttrs = Array<ClientAttrKey | ClientAttrValue>;
export type ClientAttrValue = unknown | null;
export type ClientAttrs = Array<NumericPropKey | ClientAttrValue>;

/** @internal */
export interface ClientContainer extends Container {
@@ -128,7 +128,7 @@ export type ElementVNode = [
Element, //////////////////// 6 - Element
string | undefined, ///////// 7 - tag
/// Props
(string | null)[], /////// 8 - attrs
(NumericPropKey | string | null)[], /////// 8 - attrs
] & { __brand__: 'ElementVNode' };

export const enum TextVNodeProps {
@@ -165,7 +165,7 @@ export type VirtualVNode = [
VNode | null, /////////////// 4 - First child
VNode | null, /////////////// 5 - Last child
/// Props
(string | null | boolean)[], /////// 6 - attrs
(NumericPropKey | string | null | boolean)[], /////// 6 - attrs
] & { __brand__: 'FragmentNode' & 'HostElement' };

/** @internal */
37 changes: 27 additions & 10 deletions packages/qwik/src/core/client/util-mapArray.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { assertTrue } from '../shared/error/assert';
import type { NumericPropKey } from '../shared/utils/numeric-prop-key';

export const mapApp_findIndx = <T>(array: (T | null)[], key: string, start: number): number => {
export const mapApp_findIndx = <T>(
array: (T | null)[],
key: NumericPropKey,
start: number = 0
): number => {
assertTrue(start % 2 === 0, 'Expecting even number.');
let bottom = (start as number) >> 1;
let top = (array.length - 2) >> 1;
while (bottom <= top) {
const mid = bottom + ((top - bottom) >> 1);
const midKey = array[mid << 1] as string;
const midKey = array[mid << 1] as NumericPropKey;
if (midKey === key) {
return mid << 1;
}
@@ -21,23 +26,27 @@ export const mapApp_findIndx = <T>(array: (T | null)[], key: string, start: numb

export const mapArray_set = <T>(
array: (T | null)[],
key: string,
value: T | null,
start: number
key: NumericPropKey,
value: unknown | null,
start: number = 0
) => {
const indx = mapApp_findIndx(array, key, start);
if (indx >= 0) {
if (value == null) {
array.splice(indx, 2);
} else {
array[indx + 1] = value;
array[indx + 1] = value as T;
}
} else if (value != null) {
array.splice(indx ^ -1, 0, key as any, value);
array.splice(indx ^ -1, 0, key as any, value as T);
}
};

export const mapApp_remove = <T>(array: (T | null)[], key: string, start: number): T | null => {
export const mapApp_remove = <T>(
array: (T | null)[],
key: NumericPropKey,
start: number = 0
): T | null => {
const indx = mapApp_findIndx(array, key, start);
let value: T | null = null;
if (indx >= 0) {
@@ -48,7 +57,11 @@ export const mapApp_remove = <T>(array: (T | null)[], key: string, start: number
return value;
};

export const mapArray_get = <T>(array: (T | null)[], key: string, start: number): T | null => {
export const mapArray_get = <T>(
array: (T | null)[],
key: NumericPropKey,
start: number = 0
): T | null => {
const indx = mapApp_findIndx(array, key, start);
if (indx >= 0) {
return array[indx + 1] as T | null;
@@ -57,6 +70,10 @@ export const mapArray_get = <T>(array: (T | null)[], key: string, start: number)
}
};

export const mapArray_has = <T>(array: (T | null)[], key: string, start: number): boolean => {
export const mapArray_has = <T>(
array: (T | null)[],
key: NumericPropKey,
start: number = 0
): boolean => {
return mapApp_findIndx(array, key, start) >= 0;
};
Loading
Loading