@fluffjs/fluff 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluffjs/fluff",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -51,6 +51,7 @@ export type CompactBinding = [
51
51
  p?: [number, number[]][];
52
52
  }?
53
53
  ];
54
+ export type CompactMarkerConfig = [0, ([number | null, CompactDep[] | null] | [])[]] | [1, number, number, boolean, CompactDep[] | null, number | null] | [2, number, CompactDep[] | null, [number, number[]][] | null] | [3, number, CompactDep[] | null, [boolean, boolean, number | null][]] | [4];
54
55
  export declare abstract class FluffBase extends HTMLElement {
55
56
  static __e: ExpressionFn[];
56
57
  static __h: HandlerFn[];
@@ -59,7 +60,10 @@ export declare abstract class FluffBase extends HTMLElement {
59
60
  private static __expressionsReady;
60
61
  private static readonly __pendingInitCallbacks;
61
62
  static __setExpressionTable(expressions: ExpressionFn[], handlers: HandlerFn[], strings?: string[]): void;
62
- private static __decodeDep;
63
+ static __decodeString(idx: number): string;
64
+ static __decodeDep(dep: number | number[]): string | string[];
65
+ static __decodeDeps(deps: (number | number[])[] | null): (string | string[])[] | undefined;
66
+ static __decodeMarkerConfig(compact: CompactMarkerConfig): unknown;
63
67
  private static __decodeBinding;
64
68
  static __areExpressionsReady(): boolean;
65
69
  static __addPendingInit(callback: () => void): void;
@@ -1,6 +1,23 @@
1
1
  import { Property } from '../utils/Property.js';
2
2
  import { Publisher } from '../utils/Publisher.js';
3
3
  const BINDING_TYPES = ['property', 'event', 'two-way', 'class', 'style', 'ref'];
4
+ /**
5
+ * Compact Marker Config Format (Decoder)
6
+ *
7
+ * Marker configs use the same string table as bindings. Type is numeric:
8
+ * 0=if, 1=for, 2=text, 3=switch, 4=break
9
+ *
10
+ * Format varies by type:
11
+ * - if: [0, branches[]] where branch = [exprId?, deps?]
12
+ * - for: [1, iteratorIdx, iterableExprId, hasEmpty, deps?, trackByIdx?]
13
+ * - text: [2, exprId, deps?, pipes?]
14
+ * - switch: [3, expressionExprId, deps?, cases[]]
15
+ * - break: [4]
16
+ *
17
+ * deps are interned as CompactDep[] (same as bindings)
18
+ * pipes are [pipeNameIdx, argExprIds[]][]
19
+ */
20
+ const MARKER_TYPES = ['if', 'for', 'text', 'switch', 'break'];
4
21
  export class FluffBase extends HTMLElement {
5
22
  static __e = [];
6
23
  static __h = [];
@@ -20,12 +37,89 @@ export class FluffBase extends HTMLElement {
20
37
  callback();
21
38
  }
22
39
  }
40
+ static __decodeString(idx) {
41
+ return FluffBase.__s[idx];
42
+ }
23
43
  static __decodeDep(dep) {
24
44
  if (Array.isArray(dep)) {
25
45
  return dep.map(idx => FluffBase.__s[idx]);
26
46
  }
27
47
  return FluffBase.__s[dep];
28
48
  }
49
+ static __decodeDeps(deps) {
50
+ if (!deps)
51
+ return undefined;
52
+ return deps.map(d => FluffBase.__decodeDep(d));
53
+ }
54
+ static __decodeMarkerConfig(compact) {
55
+ const [typeNum] = compact;
56
+ const type = MARKER_TYPES[typeNum];
57
+ switch (typeNum) {
58
+ case 0: // if
59
+ {
60
+ const [, rawBranches] = compact;
61
+ const branches = rawBranches.map(b => {
62
+ if (b.length === 0)
63
+ return {};
64
+ const [branchExprId, branchDeps] = b;
65
+ const result = {};
66
+ if (branchExprId !== null)
67
+ result.exprId = branchExprId;
68
+ if (branchDeps)
69
+ result.deps = FluffBase.__decodeDeps(branchDeps);
70
+ return result;
71
+ });
72
+ return { type, branches };
73
+ }
74
+ case 1: // for
75
+ {
76
+ const [, iteratorIdx, iterableExprId, hasEmpty, deps, trackByIdx] = compact;
77
+ const result = {
78
+ type,
79
+ iterator: FluffBase.__s[iteratorIdx],
80
+ iterableExprId,
81
+ hasEmpty
82
+ };
83
+ if (deps)
84
+ result.deps = FluffBase.__decodeDeps(deps);
85
+ if (trackByIdx !== null)
86
+ result.trackBy = FluffBase.__s[trackByIdx];
87
+ return result;
88
+ }
89
+ case 2: // text
90
+ {
91
+ const [, exprId, deps, pipes] = compact;
92
+ const result = { type, exprId };
93
+ if (deps)
94
+ result.deps = FluffBase.__decodeDeps(deps);
95
+ if (pipes) {
96
+ result.pipes = pipes.map(([nameIdx, argExprIds]) => ({
97
+ name: FluffBase.__s[nameIdx],
98
+ argExprIds
99
+ }));
100
+ }
101
+ return result;
102
+ }
103
+ case 3: // switch
104
+ {
105
+ const [, expressionExprId, deps, cases] = compact;
106
+ const result = { type, expressionExprId };
107
+ if (deps)
108
+ result.deps = FluffBase.__decodeDeps(deps);
109
+ result.cases = cases.map(([isDefault, fallthrough, valueExprId]) => {
110
+ const c = { isDefault, fallthrough };
111
+ if (valueExprId !== null)
112
+ c.valueExprId = valueExprId;
113
+ return c;
114
+ });
115
+ return result;
116
+ }
117
+ case 4: // break
118
+ return { type };
119
+ default:
120
+ return { type: 'unknown' };
121
+ }
122
+ }
29
123
  static __decodeBinding(compact) {
30
124
  const [nameIdx, bType, deps, id, extras] = compact;
31
125
  const n = FluffBase.__s[nameIdx];
@@ -22,7 +22,7 @@ export declare abstract class FluffElement extends FluffBase {
22
22
  protected __pipe(name: string, value: unknown, ...args: unknown[]): unknown;
23
23
  protected __getPipeFn(name: string): ((value: unknown, ...args: unknown[]) => unknown) | undefined;
24
24
  protected __getShadowRoot(): ShadowRoot;
25
- protected __createProp<T>(name: string, options: T | {
25
+ protected __createProp<T>(nameOrIdx: string | number, options: T | {
26
26
  initialValue: T;
27
27
  [key: string]: unknown;
28
28
  }): Property<T>;
@@ -101,7 +101,8 @@ export class FluffElement extends FluffBase {
101
101
  __getShadowRoot() {
102
102
  return this._shadowRoot;
103
103
  }
104
- __createProp(name, options) {
104
+ __createProp(nameOrIdx, options) {
105
+ const name = typeof nameOrIdx === 'number' ? FluffBase.__decodeString(nameOrIdx) : nameOrIdx;
105
106
  const prop = new Property(options);
106
107
  Object.defineProperty(this, name, {
107
108
  get() {
@@ -6,6 +6,9 @@ export declare class MarkerManager {
6
6
  private readonly host;
7
7
  private readonly shadowRoot;
8
8
  constructor(host: HTMLElement, shadowRoot: ShadowRoot);
9
+ private decodeConfig;
10
+ private isMarkerConfig;
11
+ private isCompactMarkerConfig;
9
12
  initializeFromConfig(entries: MarkerConfigEntries): void;
10
13
  ensureController(id: number, type: string, startMarker: Comment, endMarker: Comment | null): MarkerController | undefined;
11
14
  getController(id: number, startMarker: Comment): MarkerController | undefined;
@@ -1,4 +1,5 @@
1
1
  import { BreakController } from './BreakController.js';
2
+ import { FluffBase } from './FluffBase.js';
2
3
  import { ForController } from './ForController.js';
3
4
  import { IfController } from './IfController.js';
4
5
  import { MarkerConfigGuards } from './MarkerConfigGuards.js';
@@ -13,12 +14,45 @@ export class MarkerManager {
13
14
  this.host = host;
14
15
  this.shadowRoot = shadowRoot;
15
16
  }
17
+ decodeConfig(config) {
18
+ if (this.isCompactMarkerConfig(config)) {
19
+ const decoded = FluffBase.__decodeMarkerConfig(config);
20
+ if (this.isMarkerConfig(decoded)) {
21
+ return decoded;
22
+ }
23
+ throw new Error('Decoded marker config is invalid');
24
+ }
25
+ if (!Array.isArray(config)) {
26
+ return config;
27
+ }
28
+ throw new Error('Invalid marker config format');
29
+ }
30
+ isMarkerConfig(value) {
31
+ if (typeof value !== 'object' || value === null)
32
+ return false;
33
+ if (!('type' in value))
34
+ return false;
35
+ const typeVal = value.type;
36
+ return typeof typeVal === 'string' && ['if', 'for', 'text', 'switch', 'break'].includes(typeVal);
37
+ }
38
+ isCompactMarkerConfig(config) {
39
+ if (!Array.isArray(config))
40
+ return false;
41
+ if (config.length === 0)
42
+ return false;
43
+ const firstElement = config[0];
44
+ return typeof firstElement === 'number' && firstElement >= 0 && firstElement <= 4;
45
+ }
16
46
  initializeFromConfig(entries) {
17
47
  this.configs.clear();
18
- for (const [id, config] of entries) {
48
+ for (const [id, rawConfig] of entries) {
49
+ const config = this.decodeConfig(rawConfig);
19
50
  this.configs.set(id, config);
20
51
  }
21
- for (const [id, config] of entries) {
52
+ for (const [id] of entries) {
53
+ const config = this.configs.get(id);
54
+ if (!config)
55
+ continue;
22
56
  const { startMarker, endMarker } = this.findMarkers(id, config.type);
23
57
  if (!startMarker) {
24
58
  continue;
@@ -1,5 +1,6 @@
1
1
  import type { MarkerConfig } from '../interfaces/MarkerConfig.js';
2
- export type MarkerConfigEntries = [number, MarkerConfig][];
2
+ import type { CompactMarkerConfig } from './FluffBase.js';
3
+ export type MarkerConfigEntries = [number, MarkerConfig | CompactMarkerConfig][];
3
4
  export interface MarkerManagerInterface {
4
5
  initializeFromConfig: (entries: MarkerConfigEntries) => void;
5
6
  cleanup: () => void;
package/utils/Property.js CHANGED
@@ -174,11 +174,11 @@ export class Property {
174
174
  if (this.value === undefined)
175
175
  return;
176
176
  this.onChange.emit(this.value);
177
- if (direction == Direction.Outbound) {
177
+ if (direction === Direction.Outbound) {
178
178
  this.onOutboundChange.emit(this.value);
179
179
  }
180
- if (direction == Direction.Inbound) {
181
- this.onOutboundChange.emit(this.value);
180
+ if (direction === Direction.Inbound) {
181
+ this.onInboundChange.emit(this.value);
182
182
  }
183
183
  }
184
184
  subscribe(direction, cb) {