assign-gingerly 0.0.53 → 0.0.55
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/README.md +847 -5
- package/assignFrom.js +229 -9
- package/assignFrom.ts +338 -9
- package/assignGingerly.js +34 -1
- package/assignGingerly.ts +54 -1
- package/beVigilant.js +73 -0
- package/beVigilant.ts +85 -0
- package/enhanceAll.js +106 -0
- package/enhanceAll.ts +138 -0
- package/handlers/join.js +74 -0
- package/handlers/join.ts +80 -0
- package/handlers/lazyLoad.js +212 -0
- package/handlers/lazyLoad.ts +307 -0
- package/handlers/lazyLoadSwitch.js +58 -0
- package/handlers/lazyLoadSwitch.ts +63 -0
- package/handlers/microDataJoin.js +184 -0
- package/handlers/microDataJoin.ts +270 -0
- package/inferencer/.gitmodules +3 -0
- package/inferencer/.vscode/settings.json +2 -0
- package/inferencer/InferencedPropagator.js +230 -0
- package/inferencer/InferencedPropagator.ts +269 -0
- package/inferencer/LICENSE +21 -0
- package/inferencer/README.md +524 -0
- package/inferencer/Requirements/SupportForPropagator.md +368 -0
- package/inferencer/imports.html +7 -0
- package/inferencer/inferencer.js +254 -0
- package/inferencer/inferencer.ts +292 -0
- package/inferencer/package-lock.json +129 -0
- package/inferencer/package.json +60 -0
- package/inferencer/playwright-report/data/507ad515125e13390ea07de92f22331c913fa068.md +55 -0
- package/inferencer/playwright-report/index.html +90 -0
- package/inferencer/playwright.config.ts +54 -0
- package/inferencer/test-results/.last-run.json +6 -0
- package/inferencer/test-results/inferencer-Inferencer-Enha-535bc-inferencer-tests-in-browser-chromium/error-context.md +55 -0
- package/inferencer/tests/inferencedPropagator.html +428 -0
- package/inferencer/tests/inferencedPropagator.spec.ts +18 -0
- package/inferencer/tests/inferencer.html +355 -0
- package/inferencer/tests/inferencer.spec.ts +19 -0
- package/inferencer/tsconfig.json +19 -0
- package/inferencer/types/.kiro/specs/conversion-template/README.md +128 -0
- package/inferencer/types/.kiro/specs/conversion-template/design.md +360 -0
- package/inferencer/types/.kiro/specs/conversion-template/requirements.md +191 -0
- package/inferencer/types/.kiro/specs/conversion-template/tasks.md +174 -0
- package/inferencer/types/.kiro/steering/coding-standards.md +53 -0
- package/inferencer/types/.kiro/steering/conversion-guide.md +108 -0
- package/inferencer/types/.kiro/steering/declarative-configuration.md +108 -0
- package/inferencer/types/.kiro/steering/emc-json-serializability.md +306 -0
- package/inferencer/types/EnhancementConversionInstructions.md +1854 -0
- package/inferencer/types/LICENSE +21 -0
- package/inferencer/types/NewCustomElement.md +388 -0
- package/inferencer/types/NewCustomElementFeature.md +683 -0
- package/inferencer/types/NewEnhancementInstructions.md +705 -0
- package/inferencer/types/README.md +2 -0
- package/inferencer/types/agrace/types.d.ts +11 -0
- package/inferencer/types/assign-gingerly/types.d.ts +572 -0
- package/inferencer/types/be-a-beacon/types.d.ts +17 -0
- package/inferencer/types/be-bound/types.d.ts +66 -0
- package/inferencer/types/be-buttoned-up/types.d.ts +19 -0
- package/inferencer/types/be-calculating/types.d.ts +54 -0
- package/inferencer/types/be-clonable/types.d.ts +38 -0
- package/inferencer/types/be-committed/types.d.ts +22 -0
- package/inferencer/types/be-consoling/types.d.ts +24 -0
- package/inferencer/types/be-decked-with/types.d.ts +26 -0
- package/inferencer/types/be-delible/types.d.ts +27 -0
- package/inferencer/types/be-dispatching/types.d.ts +34 -0
- package/inferencer/types/be-evanescent/types.d.ts +20 -0
- package/inferencer/types/be-flashy/types.d.ts +21 -0
- package/inferencer/types/be-gone/types.d.ts +25 -0
- package/inferencer/types/be-observing/types.d.ts +55 -0
- package/inferencer/types/be-reflective/types.d.ts +78 -0
- package/inferencer/types/be-reformable/types.d.ts +49 -0
- package/inferencer/types/be-render-neutral/types.d.ts +32 -0
- package/inferencer/types/be-switched/types.d.ts +146 -0
- package/inferencer/types/be-typed/types.d.ts +32 -0
- package/inferencer/types/be-valued/types.d.ts +22 -0
- package/inferencer/types/data-props/types.d.ts +34 -0
- package/inferencer/types/do-inc/types.d.ts +56 -0
- package/inferencer/types/do-invoke/types.d.ts +38 -0
- package/inferencer/types/do-merge/types.d.ts +28 -0
- package/inferencer/types/do-toggle/types.d.ts +31 -0
- package/inferencer/types/face-up/types.d.ts +100 -0
- package/inferencer/types/fetch-for/types.d.ts +36 -0
- package/inferencer/types/folder-picker/types.d.ts +21 -0
- package/inferencer/types/global.d.ts +29 -0
- package/inferencer/types/id-generation/types.d.ts +26 -0
- package/inferencer/types/inferencer/types.d.ts +46 -0
- package/inferencer/types/mount-observer/types.d.ts +363 -0
- package/inferencer/types/nested-regex-groups/types.d.ts +107 -0
- package/inferencer/types/pipe-in/types.d.ts +52 -0
- package/inferencer/types/roundabout/types.d.ts +268 -0
- package/inferencer/types/soak-up/types.d.ts +40 -0
- package/inferencer/types/templ-maker/types.d.ts +43 -0
- package/inferencer/types/time-ticker/types.d.ts +62 -0
- package/inferencer/types/truth-sourcer/types.d.ts +44 -0
- package/inferencer/upSearch.js +27 -0
- package/inferencer/upSearch.ts +26 -0
- package/inferencer/withScopePerimeter.js +27 -0
- package/inferencer/withScopePerimeter.ts +33 -0
- package/inferredAssignments.js +38 -0
- package/inferredAssignments.ts +65 -0
- package/isAllowedImportPath.js +42 -0
- package/isAllowedImportPath.ts +53 -0
- package/package.json +57 -3
- package/paths.js +231 -0
- package/paths.ts +413 -0
- package/processHandlerCommands.js +188 -0
- package/processHandlerCommands.ts +217 -0
- package/resolveIdRef.js +144 -0
- package/resolveIdRef.ts +170 -0
- package/resolveValues.js +41 -2
- package/resolveValues.ts +41 -1
- package/transitionHelper.js +109 -0
- package/transitionHelper.ts +132 -0
- package/types/assign-gingerly/types.d.ts +89 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* isAllowedImportPath.ts — Security utility for validating import paths.
|
|
3
|
+
*
|
|
4
|
+
* Checks that a path is local (relative, absolute, or bare specifier) and
|
|
5
|
+
* not a cross-domain URL. Used to prevent untrusted HTML attributes from
|
|
6
|
+
* triggering imports to arbitrary external domains.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { isAllowedImportPath } from 'assign-gingerly/isAllowedImportPath.js';
|
|
10
|
+
*
|
|
11
|
+
* isAllowedImportPath('./local.js'); // true
|
|
12
|
+
* isAllowedImportPath('../parent/file.js'); // true
|
|
13
|
+
* isAllowedImportPath('/absolute/path.js'); // true
|
|
14
|
+
* isAllowedImportPath('bare-specifier/mod.js'); // true
|
|
15
|
+
* isAllowedImportPath('https://evil.com/x.js'); // false
|
|
16
|
+
* isAllowedImportPath('//cdn.example.com/x.js'); // false
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Check if an import path is allowed (non-cross-domain).
|
|
20
|
+
*
|
|
21
|
+
* Allowed:
|
|
22
|
+
* - Relative paths: ./foo.js, ../bar.js
|
|
23
|
+
* - Absolute paths: /path/to/file.js
|
|
24
|
+
* - Bare specifiers: package-name/file.js, @scope/package/file.js
|
|
25
|
+
*
|
|
26
|
+
* Blocked:
|
|
27
|
+
* - Protocol URLs: https://..., http://..., data:..., etc.
|
|
28
|
+
* - Protocol-relative: //cdn.example.com/...
|
|
29
|
+
*
|
|
30
|
+
* @param path - The import path to validate
|
|
31
|
+
* @returns true if the path is local/safe, false if cross-domain
|
|
32
|
+
*/
|
|
33
|
+
export function isAllowedImportPath(path) {
|
|
34
|
+
if (path.startsWith('./') || path.startsWith('../') || path.startsWith('/')) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (path.includes('://') || path.startsWith('//')) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
// Bare specifier (no protocol, no //) — allowed
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* isAllowedImportPath.ts — Security utility for validating import paths.
|
|
3
|
+
*
|
|
4
|
+
* Checks that a path is local (relative, absolute, or bare specifier) and
|
|
5
|
+
* not a cross-domain URL. Used to prevent untrusted HTML attributes from
|
|
6
|
+
* triggering imports to arbitrary external domains.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { isAllowedImportPath } from 'assign-gingerly/isAllowedImportPath.js';
|
|
10
|
+
*
|
|
11
|
+
* isAllowedImportPath('./local.js'); // true
|
|
12
|
+
* isAllowedImportPath('../parent/file.js'); // true
|
|
13
|
+
* isAllowedImportPath('/absolute/path.js'); // true
|
|
14
|
+
* isAllowedImportPath('bare-specifier/mod.js'); // true
|
|
15
|
+
* isAllowedImportPath('https://evil.com/x.js'); // false
|
|
16
|
+
* isAllowedImportPath('//cdn.example.com/x.js'); // false
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Permissions interface for controlling security-sensitive operations.
|
|
21
|
+
* Passed as the last parameter to assignGingerly, assignFrom, and enhanceAll.
|
|
22
|
+
* Only trusted script can set these — they are never parsed from HTML attributes.
|
|
23
|
+
*/
|
|
24
|
+
export interface AssignPermissions {
|
|
25
|
+
/** Allow imports from cross-domain URLs (default: false) */
|
|
26
|
+
crossDomainImports?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if an import path is allowed (non-cross-domain).
|
|
31
|
+
*
|
|
32
|
+
* Allowed:
|
|
33
|
+
* - Relative paths: ./foo.js, ../bar.js
|
|
34
|
+
* - Absolute paths: /path/to/file.js
|
|
35
|
+
* - Bare specifiers: package-name/file.js, @scope/package/file.js
|
|
36
|
+
*
|
|
37
|
+
* Blocked:
|
|
38
|
+
* - Protocol URLs: https://..., http://..., data:..., etc.
|
|
39
|
+
* - Protocol-relative: //cdn.example.com/...
|
|
40
|
+
*
|
|
41
|
+
* @param path - The import path to validate
|
|
42
|
+
* @returns true if the path is local/safe, false if cross-domain
|
|
43
|
+
*/
|
|
44
|
+
export function isAllowedImportPath(path: string): boolean {
|
|
45
|
+
if (path.startsWith('./') || path.startsWith('../') || path.startsWith('/')) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (path.includes('://') || path.startsWith('//')) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// Bare specifier (no protocol, no //) — allowed
|
|
52
|
+
return true;
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assign-gingerly",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.55",
|
|
4
4
|
"description": "This package provides a utility function for carefully merging one object into another.",
|
|
5
5
|
"homepage": "https://github.com/bahrus/assign-gingerly#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"*.js",
|
|
19
19
|
"*.ts",
|
|
20
|
+
"handlers/**",
|
|
21
|
+
"inferencer/**",
|
|
20
22
|
"README.md",
|
|
21
23
|
"LICENSE",
|
|
22
24
|
"types/assign-gingerly/types.d.ts"
|
|
@@ -60,6 +62,14 @@
|
|
|
60
62
|
"default": "./resolveValues.js",
|
|
61
63
|
"types": "./resolveValues.ts"
|
|
62
64
|
},
|
|
65
|
+
"./resolveIdRef.js": {
|
|
66
|
+
"default": "./resolveIdRef.js",
|
|
67
|
+
"types": "./resolveIdRef.ts"
|
|
68
|
+
},
|
|
69
|
+
"./transitionHelper.js": {
|
|
70
|
+
"default": "./transitionHelper.js",
|
|
71
|
+
"types": "./transitionHelper.ts"
|
|
72
|
+
},
|
|
63
73
|
"./installForwarding.js": {
|
|
64
74
|
"default": "./installForwarding.js",
|
|
65
75
|
"types": "./installForwarding.ts"
|
|
@@ -72,6 +82,50 @@
|
|
|
72
82
|
"default": "./resolveAndAssignFeatures.js",
|
|
73
83
|
"types": "./resolveAndAssignFeatures.ts"
|
|
74
84
|
},
|
|
85
|
+
"./handlers/lazyLoad.js": {
|
|
86
|
+
"default": "./handlers/lazyLoad.js",
|
|
87
|
+
"types": "./handlers/lazyLoad.ts"
|
|
88
|
+
},
|
|
89
|
+
"./handlers/lazyLoadSwitch.js": {
|
|
90
|
+
"default": "./handlers/lazyLoadSwitch.js",
|
|
91
|
+
"types": "./handlers/lazyLoadSwitch.ts"
|
|
92
|
+
},
|
|
93
|
+
"./handlers/join.js": {
|
|
94
|
+
"default": "./handlers/join.js",
|
|
95
|
+
"types": "./handlers/join.ts"
|
|
96
|
+
},
|
|
97
|
+
"./handlers/microDataJoin.js": {
|
|
98
|
+
"default": "./handlers/microDataJoin.js",
|
|
99
|
+
"types": "./handlers/microDataJoin.ts"
|
|
100
|
+
},
|
|
101
|
+
"./paths.js": {
|
|
102
|
+
"default": "./paths.js",
|
|
103
|
+
"types": "./paths.ts"
|
|
104
|
+
},
|
|
105
|
+
"./enhanceAll.js": {
|
|
106
|
+
"default": "./enhanceAll.js",
|
|
107
|
+
"types": "./enhanceAll.ts"
|
|
108
|
+
},
|
|
109
|
+
"./isAllowedImportPath.js": {
|
|
110
|
+
"default": "./isAllowedImportPath.js",
|
|
111
|
+
"types": "./isAllowedImportPath.ts"
|
|
112
|
+
},
|
|
113
|
+
"./inferredAssignments.js": {
|
|
114
|
+
"default": "./inferredAssignments.js",
|
|
115
|
+
"types": "./inferredAssignments.ts"
|
|
116
|
+
},
|
|
117
|
+
"./beVigilant.js": {
|
|
118
|
+
"default": "./beVigilant.js",
|
|
119
|
+
"types": "./beVigilant.ts"
|
|
120
|
+
},
|
|
121
|
+
"./inferencer/inferencer.js": {
|
|
122
|
+
"default": "./inferencer/inferencer.js",
|
|
123
|
+
"types": "./inferencer/inferencer.ts"
|
|
124
|
+
},
|
|
125
|
+
"./inferencer/withScopePerimeter.js": {
|
|
126
|
+
"default": "./inferencer/withScopePerimeter.js",
|
|
127
|
+
"types": "./inferencer/withScopePerimeter.ts"
|
|
128
|
+
},
|
|
75
129
|
"./assignFrom.js": {
|
|
76
130
|
"default": "./assignFrom.js",
|
|
77
131
|
"types": "./assignFrom.ts"
|
|
@@ -95,9 +149,9 @@
|
|
|
95
149
|
"chrome": "npx playwright cr http://localhost:8000"
|
|
96
150
|
},
|
|
97
151
|
"devDependencies": {
|
|
98
|
-
"@playwright/test": "1.
|
|
152
|
+
"@playwright/test": "1.61.1",
|
|
99
153
|
"spa-ssi": "0.0.27",
|
|
100
|
-
"@types/node": "
|
|
154
|
+
"@types/node": "26.1.0",
|
|
101
155
|
"typescript": "6.0.3"
|
|
102
156
|
}
|
|
103
157
|
}
|
package/paths.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* paths.js — Typed path proxy and template tags for assignFrom authoring.
|
|
3
|
+
*
|
|
4
|
+
* Provides compile-time autocomplete and type safety for `?.`-prefixed path strings.
|
|
5
|
+
* Supports method call syntax, alias reversal, and batch proxy extraction.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Symbol used internally to detect path proxy objects.
|
|
10
|
+
*/
|
|
11
|
+
const PATH_SYMBOL = Symbol('assign-gingerly-path');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a proxy for id-ref paths (#[varName]).
|
|
15
|
+
*/
|
|
16
|
+
function createIdRefProxy(idRef, options) {
|
|
17
|
+
function handler() {}
|
|
18
|
+
return new Proxy(handler, {
|
|
19
|
+
get(_, prop) {
|
|
20
|
+
if (prop === 'path' || prop === PATH_SYMBOL) {
|
|
21
|
+
return idRef;
|
|
22
|
+
}
|
|
23
|
+
if (typeof prop === 'symbol') return undefined;
|
|
24
|
+
const chained = `${idRef}?.${String(prop)}`;
|
|
25
|
+
return createIdRefProxy(chained, options);
|
|
26
|
+
},
|
|
27
|
+
apply(_, __, args) {
|
|
28
|
+
if (args.length > 0) {
|
|
29
|
+
const arg = args[0];
|
|
30
|
+
let argStr;
|
|
31
|
+
if (arg === true) argStr = 'true';
|
|
32
|
+
else if (arg === false) argStr = 'false';
|
|
33
|
+
else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
|
|
34
|
+
const fullPath = arg[PATH_SYMBOL];
|
|
35
|
+
argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
|
|
36
|
+
}
|
|
37
|
+
else argStr = String(arg);
|
|
38
|
+
const chained = `${idRef}?.${argStr}`;
|
|
39
|
+
return createIdRefProxy(chained, options);
|
|
40
|
+
}
|
|
41
|
+
return createIdRefProxy(idRef, options);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a recursive proxy that records property access paths.
|
|
48
|
+
*/
|
|
49
|
+
function createPathProxy(prefix, options) {
|
|
50
|
+
const aliasMap = options?.aka;
|
|
51
|
+
|
|
52
|
+
function handler() {}
|
|
53
|
+
|
|
54
|
+
return new Proxy(handler, {
|
|
55
|
+
get(_, prop) {
|
|
56
|
+
if (prop === 'path' || prop === PATH_SYMBOL) {
|
|
57
|
+
return prefix.length > 0 ? `?.${prefix}` : '?.';
|
|
58
|
+
}
|
|
59
|
+
if (typeof prop === 'symbol') return undefined;
|
|
60
|
+
|
|
61
|
+
let segment = String(prop);
|
|
62
|
+
|
|
63
|
+
// #-prefix: $['#firstName'] → '#[firstName]' (cached element ref)
|
|
64
|
+
if (segment.startsWith('#')) {
|
|
65
|
+
const varName = segment.substring(1);
|
|
66
|
+
const idRef = `#[${varName}]`;
|
|
67
|
+
return createIdRefProxy(idRef, options);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (aliasMap) {
|
|
71
|
+
for (const [alias, target] of Object.entries(aliasMap)) {
|
|
72
|
+
if (target === segment) { segment = alias; break; }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const newPath = prefix ? `${prefix}?.${segment}` : segment;
|
|
77
|
+
return createPathProxy(newPath, options);
|
|
78
|
+
},
|
|
79
|
+
apply(_, __, args) {
|
|
80
|
+
if (args.length > 0) {
|
|
81
|
+
const arg = args[0];
|
|
82
|
+
let argStr;
|
|
83
|
+
if (arg === true) argStr = 'true';
|
|
84
|
+
else if (arg === false) argStr = 'false';
|
|
85
|
+
else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
|
|
86
|
+
const fullPath = arg[PATH_SYMBOL];
|
|
87
|
+
argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
|
|
88
|
+
}
|
|
89
|
+
else argStr = String(arg);
|
|
90
|
+
|
|
91
|
+
const newPath = prefix ? `${prefix}?.${argStr}` : argStr;
|
|
92
|
+
return createPathProxy(newPath, options);
|
|
93
|
+
}
|
|
94
|
+
return createPathProxy(prefix, options);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a typed path proxy.
|
|
101
|
+
*/
|
|
102
|
+
export function paths(options) {
|
|
103
|
+
return createPathProxy('', options);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create an assignment pair: { [lhs.path]: rhs.path }.
|
|
108
|
+
*/
|
|
109
|
+
export function set(lhs) {
|
|
110
|
+
const lhsStr = lhs && typeof lhs === 'object' && PATH_SYMBOL in lhs
|
|
111
|
+
? lhs[PATH_SYMBOL]
|
|
112
|
+
: String(lhs);
|
|
113
|
+
return {
|
|
114
|
+
to(rhs) {
|
|
115
|
+
const rhsStr = rhs && typeof rhs === 'object' && PATH_SYMBOL in rhs
|
|
116
|
+
? rhs[PATH_SYMBOL]
|
|
117
|
+
: rhs;
|
|
118
|
+
return { [lhsStr]: rhsStr };
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Recursively walk a value and convert any path proxy objects to path strings.
|
|
125
|
+
*/
|
|
126
|
+
export function smoothOver(value) {
|
|
127
|
+
if (value && typeof value === 'object' && PATH_SYMBOL in value) {
|
|
128
|
+
return value[PATH_SYMBOL];
|
|
129
|
+
}
|
|
130
|
+
if (Array.isArray(value)) {
|
|
131
|
+
return value.map(smoothOver);
|
|
132
|
+
}
|
|
133
|
+
if (value && typeof value === 'object') {
|
|
134
|
+
const proto = Object.getPrototypeOf(value);
|
|
135
|
+
if (proto === Object.prototype || proto === null) {
|
|
136
|
+
const result = {};
|
|
137
|
+
for (const [k, v] of Object.entries(value)) {
|
|
138
|
+
result[k] = smoothOver(v);
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Merge multiple set(...).to(...) pairs into an { assign: {...} } object.
|
|
148
|
+
* Spread the result into a merge config.
|
|
149
|
+
*/
|
|
150
|
+
export function doAssign(...pairs) {
|
|
151
|
+
return { assign: Object.assign({}, ...pairs) };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Compile-time loop expansion: generates one entry per key from a factory function.
|
|
156
|
+
*/
|
|
157
|
+
export function forEachKeyIn(keys, factory, options) {
|
|
158
|
+
const $ = paths(options);
|
|
159
|
+
return keys.map(key => factory(key, $));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Tagged template literal that splits a template into an array of parts.
|
|
164
|
+
* Path proxy objects are auto-detected and converted to path strings.
|
|
165
|
+
*/
|
|
166
|
+
export function sp(strings, ...values) {
|
|
167
|
+
const result = [];
|
|
168
|
+
for (let i = 0; i < strings.length; i++) {
|
|
169
|
+
if (strings[i]) result.push(strings[i]);
|
|
170
|
+
if (i < values.length) {
|
|
171
|
+
const v = values[i];
|
|
172
|
+
if (v && typeof v === 'object' && PATH_SYMBOL in v) {
|
|
173
|
+
result.push(v[PATH_SYMBOL]);
|
|
174
|
+
}
|
|
175
|
+
else if (Array.isArray(v)) {
|
|
176
|
+
result.push(v.map(el =>
|
|
177
|
+
el && typeof el === 'object' && PATH_SYMBOL in el ? el[PATH_SYMBOL] : el
|
|
178
|
+
));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
result.push(v);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Extract the last segment from a `?.`-prefixed path string.
|
|
190
|
+
*/
|
|
191
|
+
function extractPropName(pathStr) {
|
|
192
|
+
const parts = pathStr.split('?.');
|
|
193
|
+
return parts[parts.length - 1];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Tagged template literal that produces {prop, val} objects for microDataJoin.
|
|
198
|
+
*/
|
|
199
|
+
export function md(strings, ...values) {
|
|
200
|
+
const result = [];
|
|
201
|
+
for (let i = 0; i < strings.length; i++) {
|
|
202
|
+
if (strings[i]) result.push(strings[i]);
|
|
203
|
+
if (i < values.length) {
|
|
204
|
+
const v = values[i];
|
|
205
|
+
if (v && typeof v === 'object' && PATH_SYMBOL in v) {
|
|
206
|
+
const pathStr = v[PATH_SYMBOL];
|
|
207
|
+
result.push({ prop: extractPropName(pathStr), val: pathStr });
|
|
208
|
+
}
|
|
209
|
+
else if (Array.isArray(v)) {
|
|
210
|
+
result.push(v.map(el => {
|
|
211
|
+
if (el && typeof el === 'object' && PATH_SYMBOL in el) {
|
|
212
|
+
const pathStr = el[PATH_SYMBOL];
|
|
213
|
+
return { prop: extractPropName(pathStr), val: pathStr };
|
|
214
|
+
}
|
|
215
|
+
return el;
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
else if (v && typeof v === 'object' && 'prop' in v) {
|
|
219
|
+
const processed = { ...v };
|
|
220
|
+
if (processed.val && typeof processed.val === 'object' && PATH_SYMBOL in processed.val) {
|
|
221
|
+
processed.val = processed.val[PATH_SYMBOL];
|
|
222
|
+
}
|
|
223
|
+
result.push(processed);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
result.push(v);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return result;
|
|
231
|
+
}
|