vsn 1.0.1 → 1.0.3

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.
@@ -0,0 +1,481 @@
1
+ declare class Scope {
2
+ readonly parent?: Scope | undefined;
3
+ private data;
4
+ private root;
5
+ private listeners;
6
+ private anyListeners;
7
+ isEachItem: boolean;
8
+ constructor(parent?: Scope | undefined);
9
+ createChild(): Scope;
10
+ get(key: string): any;
11
+ set(key: string, value: any): void;
12
+ hasKey(path: string): boolean;
13
+ getPath(path: string): any;
14
+ setPath(path: string, value: any): void;
15
+ on(path: string, handler: () => void): void;
16
+ off(path: string, handler: () => void): void;
17
+ onAny(handler: () => void): void;
18
+ offAny(handler: () => void): void;
19
+ private emitChange;
20
+ private resolveScope;
21
+ private getLocalPathValue;
22
+ private findNearestScopeWithKey;
23
+ }
24
+
25
+ interface ExecutionContext {
26
+ scope: {
27
+ getPath(key: string): any;
28
+ setPath?(key: string, value: any): void;
29
+ hasKey?(key: string): boolean;
30
+ createChild?(): ExecutionContext["scope"];
31
+ } | undefined;
32
+ rootScope: ExecutionContext["scope"];
33
+ globals?: Record<string, any>;
34
+ element?: Element;
35
+ returnValue?: any;
36
+ returning?: boolean;
37
+ breaking?: boolean;
38
+ continuing?: boolean;
39
+ }
40
+ interface CFSNode {
41
+ type: string;
42
+ prepare(context: ExecutionContext): Promise<void>;
43
+ evaluate(context: ExecutionContext): any;
44
+ }
45
+ declare abstract class BaseNode implements CFSNode {
46
+ type: string;
47
+ constructor(type: string);
48
+ prepare(_context: ExecutionContext): Promise<void>;
49
+ evaluate(_context: ExecutionContext): any;
50
+ }
51
+ declare class BlockNode extends BaseNode {
52
+ statements: CFSNode[];
53
+ constructor(statements: CFSNode[]);
54
+ evaluate(context: ExecutionContext): any;
55
+ }
56
+ declare class AssignmentNode extends BaseNode {
57
+ target: AssignmentTarget;
58
+ value: ExpressionNode;
59
+ operator: "=" | "+=" | "-=" | "*=" | "/=" | "++" | "--";
60
+ prefix: boolean;
61
+ constructor(target: AssignmentTarget, value: ExpressionNode, operator?: "=" | "+=" | "-=" | "*=" | "/=" | "++" | "--", prefix?: boolean);
62
+ evaluate(context: ExecutionContext): any;
63
+ private applyCompoundAssignment;
64
+ private applyIncrement;
65
+ private resolveAssignmentTarget;
66
+ private resolveIndexPath;
67
+ private resolveTargetPath;
68
+ private assignTarget;
69
+ private assignDirectiveTarget;
70
+ }
71
+ declare class FunctionExpression extends BaseNode {
72
+ params: FunctionParam[];
73
+ body: BlockNode;
74
+ isAsync: boolean;
75
+ constructor(params: FunctionParam[], body: BlockNode, isAsync?: boolean);
76
+ evaluate(context: ExecutionContext): any;
77
+ private applyParams;
78
+ private restoreParams;
79
+ }
80
+ interface DeclarationFlags {
81
+ important?: boolean;
82
+ trusted?: boolean;
83
+ debounce?: boolean;
84
+ [key: string]: boolean | undefined;
85
+ }
86
+ interface DeclarationFlagArgs {
87
+ debounce?: number;
88
+ [key: string]: any;
89
+ }
90
+ interface BehaviorFlags {
91
+ [key: string]: boolean | undefined;
92
+ }
93
+ interface BehaviorFlagArgs {
94
+ [key: string]: any;
95
+ }
96
+ declare class DeclarationNode extends BaseNode {
97
+ target: DeclarationTarget;
98
+ operator: ":" | ":=" | ":<" | ":>";
99
+ value: ExpressionNode;
100
+ flags: DeclarationFlags;
101
+ flagArgs: DeclarationFlagArgs;
102
+ constructor(target: DeclarationTarget, operator: ":" | ":=" | ":<" | ":>", value: ExpressionNode, flags: DeclarationFlags, flagArgs: DeclarationFlagArgs);
103
+ }
104
+ type ExpressionNode = AssignmentNode | IdentifierExpression | LiteralExpression | TemplateExpression | UnaryExpression | BinaryExpression | MemberExpression | CallExpression | ArrayExpression | ObjectExpression | IndexExpression | FunctionExpression | AwaitExpression | TernaryExpression | DirectiveExpression | QueryExpression;
105
+ type DeclarationTarget = IdentifierExpression | DirectiveExpression;
106
+ type AssignmentTarget = IdentifierExpression | MemberExpression | IndexExpression | DirectiveExpression | ArrayPattern | ObjectPattern;
107
+ type FunctionParam = {
108
+ name: string;
109
+ defaultValue?: ExpressionNode;
110
+ rest?: boolean;
111
+ };
112
+ type PatternNode = IdentifierExpression | ArrayPattern | ObjectPattern;
113
+ declare class IdentifierExpression extends BaseNode {
114
+ name: string;
115
+ constructor(name: string);
116
+ evaluate(context: ExecutionContext): any;
117
+ }
118
+ declare class SpreadElement extends BaseNode {
119
+ value: ExpressionNode;
120
+ constructor(value: ExpressionNode);
121
+ }
122
+ declare class RestElement extends BaseNode {
123
+ target: IdentifierExpression;
124
+ constructor(target: IdentifierExpression);
125
+ }
126
+ type ArrayPatternElement = PatternNode | RestElement | null;
127
+ declare class ArrayPattern extends BaseNode {
128
+ elements: ArrayPatternElement[];
129
+ constructor(elements: ArrayPatternElement[]);
130
+ }
131
+ type ObjectPatternEntry = {
132
+ key: string;
133
+ target: PatternNode;
134
+ } | {
135
+ rest: IdentifierExpression;
136
+ };
137
+ declare class ObjectPattern extends BaseNode {
138
+ entries: ObjectPatternEntry[];
139
+ constructor(entries: ObjectPatternEntry[]);
140
+ }
141
+ declare class LiteralExpression extends BaseNode {
142
+ value: string | number | boolean | null;
143
+ constructor(value: string | number | boolean | null);
144
+ evaluate(): any;
145
+ }
146
+ declare class TemplateExpression extends BaseNode {
147
+ parts: ExpressionNode[];
148
+ constructor(parts: ExpressionNode[]);
149
+ evaluate(context: ExecutionContext): any;
150
+ }
151
+ declare class UnaryExpression extends BaseNode {
152
+ operator: string;
153
+ argument: ExpressionNode;
154
+ constructor(operator: string, argument: ExpressionNode);
155
+ evaluate(context: ExecutionContext): any;
156
+ }
157
+ declare class BinaryExpression extends BaseNode {
158
+ operator: string;
159
+ left: ExpressionNode;
160
+ right: ExpressionNode;
161
+ constructor(operator: string, left: ExpressionNode, right: ExpressionNode);
162
+ evaluate(context: ExecutionContext): any;
163
+ }
164
+ declare class TernaryExpression extends BaseNode {
165
+ test: ExpressionNode;
166
+ consequent: ExpressionNode;
167
+ alternate: ExpressionNode;
168
+ constructor(test: ExpressionNode, consequent: ExpressionNode, alternate: ExpressionNode);
169
+ evaluate(context: ExecutionContext): any;
170
+ }
171
+ declare class MemberExpression extends BaseNode {
172
+ target: ExpressionNode;
173
+ property: string;
174
+ optional: boolean;
175
+ constructor(target: ExpressionNode, property: string, optional?: boolean);
176
+ evaluate(context: ExecutionContext): any;
177
+ resolve(context: ExecutionContext): {
178
+ value: any;
179
+ target?: any;
180
+ optional?: boolean;
181
+ } | undefined | Promise<{
182
+ value: any;
183
+ target?: any;
184
+ optional?: boolean;
185
+ } | undefined>;
186
+ getIdentifierPath(): {
187
+ path: string;
188
+ root: string;
189
+ } | undefined;
190
+ private getTargetIdentifierPath;
191
+ private resolveFromScope;
192
+ private resolveFromGlobals;
193
+ private getTargetPath;
194
+ }
195
+ declare class CallExpression extends BaseNode {
196
+ callee: ExpressionNode;
197
+ args: ExpressionNode[];
198
+ constructor(callee: ExpressionNode, args: ExpressionNode[]);
199
+ evaluate(context: ExecutionContext): any;
200
+ private resolveCallee;
201
+ }
202
+ type ArrayElement = ExpressionNode | SpreadElement;
203
+ declare class ArrayExpression extends BaseNode {
204
+ elements: ArrayElement[];
205
+ constructor(elements: ArrayElement[]);
206
+ evaluate(context: ExecutionContext): any;
207
+ }
208
+ type ObjectEntry = {
209
+ key: string;
210
+ value: ExpressionNode;
211
+ computed?: false;
212
+ } | {
213
+ keyExpr: ExpressionNode;
214
+ value: ExpressionNode;
215
+ computed: true;
216
+ } | {
217
+ spread: ExpressionNode;
218
+ };
219
+ declare class ObjectExpression extends BaseNode {
220
+ entries: ObjectEntry[];
221
+ constructor(entries: ObjectEntry[]);
222
+ evaluate(context: ExecutionContext): any;
223
+ }
224
+ declare class IndexExpression extends BaseNode {
225
+ target: ExpressionNode;
226
+ index: ExpressionNode;
227
+ constructor(target: ExpressionNode, index: ExpressionNode);
228
+ evaluate(context: ExecutionContext): any;
229
+ private normalizeIndexKey;
230
+ }
231
+ declare class DirectiveExpression extends BaseNode {
232
+ kind: "attr" | "style";
233
+ name: string;
234
+ constructor(kind: "attr" | "style", name: string);
235
+ evaluate(context: ExecutionContext): any;
236
+ }
237
+ declare class AwaitExpression extends BaseNode {
238
+ argument: ExpressionNode;
239
+ constructor(argument: ExpressionNode);
240
+ evaluate(context: ExecutionContext): any;
241
+ }
242
+ declare class QueryExpression extends BaseNode {
243
+ direction: "self" | "descendant" | "ancestor";
244
+ selector: string;
245
+ constructor(direction: "self" | "descendant" | "ancestor", selector: string);
246
+ evaluate(context: ExecutionContext): any;
247
+ }
248
+
249
+ interface RegisteredBehavior {
250
+ id: number;
251
+ hash: string;
252
+ selector: string;
253
+ rootSelector: string;
254
+ parentSelector?: string;
255
+ specificity: number;
256
+ order: number;
257
+ construct?: BlockNode;
258
+ destruct?: BlockNode;
259
+ onBlocks: {
260
+ event: string;
261
+ body: BlockNode;
262
+ flags: DeclarationFlags;
263
+ flagArgs: DeclarationFlagArgs;
264
+ args: string[];
265
+ }[];
266
+ declarations: DeclarationNode[];
267
+ functions: FunctionBinding[];
268
+ flags: BehaviorFlags;
269
+ flagArgs: BehaviorFlagArgs;
270
+ }
271
+ type FunctionBinding = {
272
+ name: string;
273
+ params: FunctionParam[];
274
+ body: BlockNode;
275
+ };
276
+ type AttributeHandler = {
277
+ id: string;
278
+ match: (name: string) => boolean;
279
+ handle: (element: Element, name: string, value: string, scope: Scope) => boolean | void;
280
+ };
281
+ type FlagApplyContext = {
282
+ name: string;
283
+ args: any;
284
+ element: Element;
285
+ scope: Scope;
286
+ declaration: DeclarationNode;
287
+ };
288
+ type FlagHandler = {
289
+ onApply?: (context: FlagApplyContext) => void;
290
+ transformValue?: (context: FlagApplyContext, value: any) => any;
291
+ onEventBind?: (context: EventFlagContext) => EventBindPatch | void;
292
+ onEventBefore?: (context: EventFlagContext) => boolean | void;
293
+ onEventAfter?: (context: EventFlagContext) => void;
294
+ transformEventArgs?: (context: EventFlagContext, args: any[]) => any[];
295
+ };
296
+ type BehaviorModifierHandler = {
297
+ onBind?: (context: BehaviorModifierContext) => void | Promise<void>;
298
+ onConstruct?: (context: BehaviorModifierContext) => void | Promise<void>;
299
+ onDestruct?: (context: BehaviorModifierContext) => void | Promise<void>;
300
+ onUnbind?: (context: BehaviorModifierContext) => void | Promise<void>;
301
+ };
302
+ type BehaviorModifierContext = {
303
+ name: string;
304
+ args: any;
305
+ element: Element;
306
+ scope: Scope;
307
+ rootScope: Scope | undefined;
308
+ behavior: RegisteredBehavior;
309
+ engine: Engine;
310
+ };
311
+ type EventBindPatch = {
312
+ listenerTarget?: EventTarget;
313
+ options?: AddEventListenerOptions;
314
+ debounceMs?: number;
315
+ };
316
+ type EventFlagContext = {
317
+ name: string;
318
+ args: any;
319
+ element: Element;
320
+ scope: Scope;
321
+ rootScope: Scope | undefined;
322
+ event: Event | undefined;
323
+ engine: Engine;
324
+ };
325
+ type EngineOptions = {
326
+ diagnostics?: boolean;
327
+ logger?: Partial<Pick<Console, "info" | "warn">>;
328
+ };
329
+ declare class Engine {
330
+ private static activeEngines;
331
+ private scopes;
332
+ private bindBindings;
333
+ private ifBindings;
334
+ private showBindings;
335
+ private htmlBindings;
336
+ private getBindings;
337
+ private eachBindings;
338
+ private lifecycleBindings;
339
+ private behaviorRegistry;
340
+ private behaviorRegistryHashes;
341
+ private behaviorBindings;
342
+ private behaviorListeners;
343
+ private behaviorId;
344
+ private codeCache;
345
+ private behaviorCache;
346
+ private observer;
347
+ private attributeHandlers;
348
+ private globals;
349
+ private importantFlags;
350
+ private inlineDeclarations;
351
+ private flagHandlers;
352
+ private behaviorModifiers;
353
+ private pendingAdded;
354
+ private pendingRemoved;
355
+ private pendingUpdated;
356
+ private observerFlush?;
357
+ private ignoredAdded;
358
+ private diagnostics;
359
+ private logger;
360
+ private pendingUses;
361
+ private pendingAutoBindToScope;
362
+ private scopeWatchers;
363
+ private executionStack;
364
+ private groupProxyCache;
365
+ constructor(options?: EngineOptions);
366
+ private getGroupTargetScope;
367
+ private getGroupProxy;
368
+ mount(root: HTMLElement): Promise<void>;
369
+ unmount(element: Element): void;
370
+ registerBehaviors(source: string): void;
371
+ registerGlobal(name: string, value: any): void;
372
+ registerGlobals(values: Record<string, any>): void;
373
+ registerFlag(name: string, handler?: FlagHandler): void;
374
+ registerBehaviorModifier(name: string, handler?: BehaviorModifierHandler): void;
375
+ getRegistryStats(): {
376
+ behaviorCount: number;
377
+ behaviorCacheSize: number;
378
+ };
379
+ registerAttributeHandler(handler: AttributeHandler): void;
380
+ private resolveGlobalPath;
381
+ private waitForUses;
382
+ private waitForUseGlobal;
383
+ getScope(element: Element, parentScope?: Scope): Scope;
384
+ evaluate(element: Element): void;
385
+ private attachObserver;
386
+ private disconnectObserver;
387
+ private flushObserverQueue;
388
+ private handleRemovedNode;
389
+ private handleAddedNode;
390
+ private handleUpdatedNode;
391
+ private applyBehaviors;
392
+ private reapplyBehaviorsForElement;
393
+ private applyBehaviorForElement;
394
+ private unbindBehaviorForElement;
395
+ private runBehaviorDestruct;
396
+ private attachAttributes;
397
+ private setLifecycle;
398
+ private runConstruct;
399
+ private runDestruct;
400
+ private parseEachExpression;
401
+ private renderEach;
402
+ private attachBindInputHandler;
403
+ private parseBindDirection;
404
+ private resolveBindConfig;
405
+ private isFormControl;
406
+ private hasScopeValue;
407
+ private hasElementValue;
408
+ private coerceInt;
409
+ private coerceFloat;
410
+ private isInEachScope;
411
+ private flushAutoBindQueue;
412
+ private hasVsnAttributes;
413
+ private markInlineDeclaration;
414
+ private isInlineDeclaration;
415
+ private findParentScope;
416
+ private watch;
417
+ private watchWithDebounce;
418
+ private watchAllScopes;
419
+ private trackScopeWatcher;
420
+ private cleanupScopeWatchers;
421
+ private cleanupBehaviorListeners;
422
+ private parseOnAttribute;
423
+ private parseInlineFlags;
424
+ private parseInlineFlagArg;
425
+ private describeElement;
426
+ private logDiagnostic;
427
+ private emitError;
428
+ private emitUseError;
429
+ private attachOnHandler;
430
+ private attachBehaviorOnHandler;
431
+ private attachGetHandler;
432
+ private getEventBindingConfig;
433
+ private applyEventFlagBefore;
434
+ private applyEventFlagAfter;
435
+ private applyEventFlagArgTransforms;
436
+ private matchesKeyFlag;
437
+ private withExecutionElement;
438
+ getCurrentElement(): Element | undefined;
439
+ private execute;
440
+ private executeBlock;
441
+ private safeExecute;
442
+ private safeExecuteBlock;
443
+ private collectBehavior;
444
+ private collectNestedBehaviors;
445
+ private computeSpecificity;
446
+ private getBehaviorRootScope;
447
+ private getImportantKey;
448
+ private isImportant;
449
+ private markImportant;
450
+ private extractLifecycle;
451
+ private extractOnBlocks;
452
+ private extractDeclarations;
453
+ private extractFunctionDeclarations;
454
+ private getCachedBehavior;
455
+ private hashBehavior;
456
+ private normalizeNode;
457
+ private hashString;
458
+ private applyBehaviorFunctions;
459
+ private applyBehaviorFunction;
460
+ private applyFunctionParams;
461
+ private restoreFunctionParams;
462
+ private applyBehaviorDeclarations;
463
+ private applyBehaviorDeclaration;
464
+ private applyCustomFlags;
465
+ private applyCustomFlagTransforms;
466
+ private applyBehaviorModifierHook;
467
+ private behaviorHasModifierHooks;
468
+ private applyDirectiveFromScope;
469
+ private applyDirectiveFromExpression;
470
+ private applyDirectiveToScope;
471
+ private applyCheckedBindingToScope;
472
+ private applyValueBindingToScope;
473
+ private setDirectiveValue;
474
+ private getDirectiveValue;
475
+ private handleTrustedHtml;
476
+ private registerDefaultAttributeHandlers;
477
+ }
478
+
479
+ declare function registerMicrodata(engine: Engine): void;
480
+
481
+ export { registerMicrodata as default, registerMicrodata };
@@ -0,0 +1,178 @@
1
+ // src/plugins/microdata.ts
2
+ var META_TYPE = "@type";
3
+ var META_ID = "@id";
4
+ function registerMicrodata(engine) {
5
+ engine.registerBehaviorModifier("microdata", {
6
+ onBind: ({ element, scope, args }) => {
7
+ const options = normalizeOptions(args);
8
+ const root = resolveItemscopeRoot(element);
9
+ if (!root) {
10
+ return;
11
+ }
12
+ const data = extractMicrodata(root, options);
13
+ applyMicrodataToScope(scope, data, options);
14
+ }
15
+ });
16
+ engine.registerGlobal("microdata", (target, maybeOptions) => {
17
+ const options = normalizeOptions(
18
+ isPlainObject(target) ? target : maybeOptions
19
+ );
20
+ const root = resolveTargetElement(engine, target);
21
+ if (!root) {
22
+ return void 0;
23
+ }
24
+ const data = extractMicrodata(resolveItemscopeRoot(root) ?? root, options);
25
+ if (typeof target === "string" && !isPlainObject(maybeOptions)) {
26
+ return data[target];
27
+ }
28
+ return data;
29
+ });
30
+ }
31
+ var microdata_default = registerMicrodata;
32
+ var globals = globalThis;
33
+ var plugins = globals.VSNPlugins ?? {};
34
+ plugins.microdata = (instance) => registerMicrodata(instance);
35
+ globals.VSNPlugins = plugins;
36
+ var autoEngine = globals.VSNEngine;
37
+ if (autoEngine && typeof autoEngine.registerBehaviorModifier === "function") {
38
+ registerMicrodata(autoEngine);
39
+ }
40
+ function normalizeOptions(value) {
41
+ if (!value) {
42
+ return {};
43
+ }
44
+ if (typeof value === "string") {
45
+ return { key: value };
46
+ }
47
+ if (isPlainObject(value)) {
48
+ const options = {};
49
+ if (typeof value.key === "string") {
50
+ options.key = value.key;
51
+ }
52
+ if (typeof value.flatten === "boolean") {
53
+ options.flatten = value.flatten;
54
+ }
55
+ return options;
56
+ }
57
+ return {};
58
+ }
59
+ function isPlainObject(value) {
60
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
61
+ }
62
+ function resolveTargetElement(engine, target) {
63
+ if (!target) {
64
+ return engine.getCurrentElement();
65
+ }
66
+ if (target instanceof Element) {
67
+ return target;
68
+ }
69
+ if (Array.isArray(target) && target[0] instanceof Element) {
70
+ return target[0];
71
+ }
72
+ return engine.getCurrentElement();
73
+ }
74
+ function resolveItemscopeRoot(element) {
75
+ if (element.hasAttribute("itemscope")) {
76
+ return element;
77
+ }
78
+ return element.querySelector("[itemscope]") ?? void 0;
79
+ }
80
+ function extractMicrodata(root, options) {
81
+ const result = {};
82
+ const itemType = root.getAttribute("itemtype");
83
+ const itemId = root.getAttribute("itemid");
84
+ if (itemType) {
85
+ result[META_TYPE] = itemType;
86
+ }
87
+ if (itemId) {
88
+ result[META_ID] = itemId;
89
+ }
90
+ collectItemProps(root, result, options);
91
+ return result;
92
+ }
93
+ function collectItemProps(root, result, options) {
94
+ const children = Array.from(root.children);
95
+ for (const child of children) {
96
+ const hasItemprop = child.hasAttribute("itemprop");
97
+ const hasItemscope = child.hasAttribute("itemscope");
98
+ if (hasItemscope && !hasItemprop) {
99
+ continue;
100
+ }
101
+ if (hasItemprop) {
102
+ const props = (child.getAttribute("itemprop") ?? "").split(/\s+/).map((prop) => prop.trim()).filter(Boolean);
103
+ const value = hasItemscope ? extractMicrodata(child, options) : readItemValue(child);
104
+ for (const prop of props) {
105
+ addValue(result, prop, value);
106
+ }
107
+ if (options.flatten && value && typeof value === "object" && !Array.isArray(value)) {
108
+ for (const [key, nestedValue] of Object.entries(value)) {
109
+ if (key.startsWith("@")) {
110
+ continue;
111
+ }
112
+ addValue(result, key, nestedValue);
113
+ }
114
+ }
115
+ if (hasItemscope) {
116
+ continue;
117
+ }
118
+ }
119
+ collectItemProps(child, result, options);
120
+ }
121
+ }
122
+ function readItemValue(element) {
123
+ if (element instanceof HTMLMetaElement) {
124
+ return element.content ?? "";
125
+ }
126
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
127
+ return element.value ?? "";
128
+ }
129
+ if (element instanceof HTMLSelectElement) {
130
+ return element.value ?? "";
131
+ }
132
+ if (element instanceof HTMLTimeElement) {
133
+ return element.dateTime || element.getAttribute("datetime") || "";
134
+ }
135
+ if (element instanceof HTMLAnchorElement || element instanceof HTMLLinkElement) {
136
+ return element.getAttribute("href") ?? "";
137
+ }
138
+ if (element instanceof HTMLImageElement) {
139
+ return element.getAttribute("src") ?? "";
140
+ }
141
+ if (element.hasAttribute("content")) {
142
+ return element.getAttribute("content") ?? "";
143
+ }
144
+ return (element.textContent ?? "").trim();
145
+ }
146
+ function addValue(result, key, value) {
147
+ if (result[key] === void 0) {
148
+ result[key] = value;
149
+ return;
150
+ }
151
+ if (Array.isArray(result[key])) {
152
+ result[key].push(value);
153
+ return;
154
+ }
155
+ result[key] = [result[key], value];
156
+ }
157
+ function applyMicrodataToScope(scope, data, options) {
158
+ if (options.key) {
159
+ scope.setPath?.(options.key, data);
160
+ return;
161
+ }
162
+ for (const [key, value] of Object.entries(data)) {
163
+ if (key === META_TYPE) {
164
+ scope.setPath?.("itemtype", value);
165
+ continue;
166
+ }
167
+ if (key === META_ID) {
168
+ scope.setPath?.("itemid", value);
169
+ continue;
170
+ }
171
+ scope.setPath?.(key, value);
172
+ }
173
+ }
174
+ export {
175
+ microdata_default as default,
176
+ registerMicrodata
177
+ };
178
+ //# sourceMappingURL=microdata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/microdata.ts"],"sourcesContent":["import type { Engine } from \"../runtime/engine\";\n\ntype MicrodataOptions = {\n key?: string;\n flatten?: boolean;\n};\n\ntype ExtractResult = Record<string, any>;\n\nconst META_TYPE = \"@type\";\nconst META_ID = \"@id\";\n\nexport function registerMicrodata(engine: Engine): void {\n engine.registerBehaviorModifier(\"microdata\", {\n onBind: ({ element, scope, args }) => {\n const options = normalizeOptions(args);\n const root = resolveItemscopeRoot(element);\n if (!root) {\n return;\n }\n const data = extractMicrodata(root, options);\n applyMicrodataToScope(scope, data, options);\n }\n });\n\n engine.registerGlobal(\"microdata\", (target?: any, maybeOptions?: any) => {\n const options = normalizeOptions(\n isPlainObject(target) ? target : maybeOptions\n );\n const root = resolveTargetElement(engine, target);\n if (!root) {\n return undefined;\n }\n const data = extractMicrodata(resolveItemscopeRoot(root) ?? root, options);\n if (typeof target === \"string\" && !isPlainObject(maybeOptions)) {\n return data[target];\n }\n return data;\n });\n}\n\nexport default registerMicrodata;\n\nconst globals = (globalThis as Record<string, any>);\nconst plugins = globals.VSNPlugins ?? {};\nplugins.microdata = (instance: Engine) => registerMicrodata(instance);\nglobals.VSNPlugins = plugins;\n\nconst autoEngine = globals.VSNEngine;\nif (autoEngine && typeof autoEngine.registerBehaviorModifier === \"function\") {\n registerMicrodata(autoEngine as Engine);\n}\n\nfunction normalizeOptions(value: any): MicrodataOptions {\n if (!value) {\n return {};\n }\n if (typeof value === \"string\") {\n return { key: value };\n }\n if (isPlainObject(value)) {\n const options: MicrodataOptions = {};\n if (typeof value.key === \"string\") {\n options.key = value.key;\n }\n if (typeof value.flatten === \"boolean\") {\n options.flatten = value.flatten;\n }\n return options;\n }\n return {};\n}\n\nfunction isPlainObject(value: any): value is Record<string, any> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction resolveTargetElement(engine: Engine, target?: any): Element | undefined {\n if (!target) {\n return engine.getCurrentElement();\n }\n if (target instanceof Element) {\n return target;\n }\n if (Array.isArray(target) && target[0] instanceof Element) {\n return target[0];\n }\n return engine.getCurrentElement();\n}\n\nfunction resolveItemscopeRoot(element: Element): Element | undefined {\n if (element.hasAttribute(\"itemscope\")) {\n return element;\n }\n return element.querySelector(\"[itemscope]\") ?? undefined;\n}\n\nfunction extractMicrodata(root: Element, options: MicrodataOptions): ExtractResult {\n const result: ExtractResult = {};\n const itemType = root.getAttribute(\"itemtype\");\n const itemId = root.getAttribute(\"itemid\");\n if (itemType) {\n result[META_TYPE] = itemType;\n }\n if (itemId) {\n result[META_ID] = itemId;\n }\n\n collectItemProps(root, result, options);\n return result;\n}\n\nfunction collectItemProps(root: Element, result: ExtractResult, options: MicrodataOptions): void {\n const children = Array.from(root.children);\n for (const child of children) {\n const hasItemprop = child.hasAttribute(\"itemprop\");\n const hasItemscope = child.hasAttribute(\"itemscope\");\n\n if (hasItemscope && !hasItemprop) {\n continue;\n }\n\n if (hasItemprop) {\n const props = (child.getAttribute(\"itemprop\") ?? \"\")\n .split(/\\s+/)\n .map((prop) => prop.trim())\n .filter(Boolean);\n const value = hasItemscope ? extractMicrodata(child, options) : readItemValue(child);\n for (const prop of props) {\n addValue(result, prop, value);\n }\n if (options.flatten && value && typeof value === \"object\" && !Array.isArray(value)) {\n for (const [key, nestedValue] of Object.entries(value)) {\n if (key.startsWith(\"@\")) {\n continue;\n }\n addValue(result, key, nestedValue);\n }\n }\n if (hasItemscope) {\n continue;\n }\n }\n\n collectItemProps(child, result, options);\n }\n}\n\nfunction readItemValue(element: Element): string {\n if (element instanceof HTMLMetaElement) {\n return element.content ?? \"\";\n }\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n return element.value ?? \"\";\n }\n if (element instanceof HTMLSelectElement) {\n return element.value ?? \"\";\n }\n if (element instanceof HTMLTimeElement) {\n return element.dateTime || element.getAttribute(\"datetime\") || \"\";\n }\n if (element instanceof HTMLAnchorElement || element instanceof HTMLLinkElement) {\n return element.getAttribute(\"href\") ?? \"\";\n }\n if (element instanceof HTMLImageElement) {\n return element.getAttribute(\"src\") ?? \"\";\n }\n if (element.hasAttribute(\"content\")) {\n return element.getAttribute(\"content\") ?? \"\";\n }\n return (element.textContent ?? \"\").trim();\n}\n\nfunction addValue(result: ExtractResult, key: string, value: any): void {\n if (result[key] === undefined) {\n result[key] = value;\n return;\n }\n if (Array.isArray(result[key])) {\n result[key].push(value);\n return;\n }\n result[key] = [result[key], value];\n}\n\nfunction applyMicrodataToScope(scope: any, data: ExtractResult, options: MicrodataOptions): void {\n if (options.key) {\n scope.setPath?.(options.key, data);\n return;\n }\n for (const [key, value] of Object.entries(data)) {\n if (key === META_TYPE) {\n scope.setPath?.(\"itemtype\", value);\n continue;\n }\n if (key === META_ID) {\n scope.setPath?.(\"itemid\", value);\n continue;\n }\n scope.setPath?.(key, value);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,2 @@
1
+ var A="@type";function p(t){t.registerBehaviorModifier("microdata",{onBind:({element:n,scope:i,args:r})=>{let e=E(r),o=l(n);if(!o)return;let s=d(o,e);I(i,s,e)}}),t.registerGlobal("microdata",(n,i)=>{let r=E(u(n)?n:i),e=T(t,n);if(!e)return;let o=d(l(e)??e,r);return typeof n=="string"&&!u(i)?o[n]:o})}var R=p,y=globalThis,g=y.VSNPlugins??{};g.microdata=t=>p(t);y.VSNPlugins=g;var f=y.VSNEngine;f&&typeof f.registerBehaviorModifier=="function"&&p(f);function E(t){if(!t)return{};if(typeof t=="string")return{key:t};if(u(t)){let n={};return typeof t.key=="string"&&(n.key=t.key),typeof t.flatten=="boolean"&&(n.flatten=t.flatten),n}return{}}function u(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function T(t,n){return n?n instanceof Element?n:Array.isArray(n)&&n[0]instanceof Element?n[0]:t.getCurrentElement():t.getCurrentElement()}function l(t){return t.hasAttribute("itemscope")?t:t.querySelector("[itemscope]")??void 0}function d(t,n){let i={},r=t.getAttribute("itemtype"),e=t.getAttribute("itemid");return r&&(i[A]=r),e&&(i["@id"]=e),M(t,i,n),i}function M(t,n,i){let r=Array.from(t.children);for(let e of r){let o=e.hasAttribute("itemprop"),s=e.hasAttribute("itemscope");if(!(s&&!o)){if(o){let b=(e.getAttribute("itemprop")??"").split(/\s+/).map(c=>c.trim()).filter(Boolean),a=s?d(e,i):x(e);for(let c of b)m(n,c,a);if(i.flatten&&a&&typeof a=="object"&&!Array.isArray(a))for(let[c,h]of Object.entries(a))c.startsWith("@")||m(n,c,h);if(s)continue}M(e,n,i)}}}function x(t){return t instanceof HTMLMetaElement?t.content??"":t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement?t.value??"":t instanceof HTMLTimeElement?t.dateTime||t.getAttribute("datetime")||"":t instanceof HTMLAnchorElement||t instanceof HTMLLinkElement?t.getAttribute("href")??"":t instanceof HTMLImageElement?t.getAttribute("src")??"":t.hasAttribute("content")?t.getAttribute("content")??"":(t.textContent??"").trim()}function m(t,n,i){if(t[n]===void 0){t[n]=i;return}if(Array.isArray(t[n])){t[n].push(i);return}t[n]=[t[n],i]}function I(t,n,i){if(i.key){t.setPath?.(i.key,n);return}for(let[r,e]of Object.entries(n)){if(r===A){t.setPath?.("itemtype",e);continue}if(r==="@id"){t.setPath?.("itemid",e);continue}t.setPath?.(r,e)}}export{R as default,p as registerMicrodata};
2
+ //# sourceMappingURL=microdata.min.js.map