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.
Files changed (114) hide show
  1. package/README.md +847 -5
  2. package/assignFrom.js +229 -9
  3. package/assignFrom.ts +338 -9
  4. package/assignGingerly.js +34 -1
  5. package/assignGingerly.ts +54 -1
  6. package/beVigilant.js +73 -0
  7. package/beVigilant.ts +85 -0
  8. package/enhanceAll.js +106 -0
  9. package/enhanceAll.ts +138 -0
  10. package/handlers/join.js +74 -0
  11. package/handlers/join.ts +80 -0
  12. package/handlers/lazyLoad.js +212 -0
  13. package/handlers/lazyLoad.ts +307 -0
  14. package/handlers/lazyLoadSwitch.js +58 -0
  15. package/handlers/lazyLoadSwitch.ts +63 -0
  16. package/handlers/microDataJoin.js +184 -0
  17. package/handlers/microDataJoin.ts +270 -0
  18. package/inferencer/.gitmodules +3 -0
  19. package/inferencer/.vscode/settings.json +2 -0
  20. package/inferencer/InferencedPropagator.js +230 -0
  21. package/inferencer/InferencedPropagator.ts +269 -0
  22. package/inferencer/LICENSE +21 -0
  23. package/inferencer/README.md +524 -0
  24. package/inferencer/Requirements/SupportForPropagator.md +368 -0
  25. package/inferencer/imports.html +7 -0
  26. package/inferencer/inferencer.js +254 -0
  27. package/inferencer/inferencer.ts +292 -0
  28. package/inferencer/package-lock.json +129 -0
  29. package/inferencer/package.json +60 -0
  30. package/inferencer/playwright-report/data/507ad515125e13390ea07de92f22331c913fa068.md +55 -0
  31. package/inferencer/playwright-report/index.html +90 -0
  32. package/inferencer/playwright.config.ts +54 -0
  33. package/inferencer/test-results/.last-run.json +6 -0
  34. package/inferencer/test-results/inferencer-Inferencer-Enha-535bc-inferencer-tests-in-browser-chromium/error-context.md +55 -0
  35. package/inferencer/tests/inferencedPropagator.html +428 -0
  36. package/inferencer/tests/inferencedPropagator.spec.ts +18 -0
  37. package/inferencer/tests/inferencer.html +355 -0
  38. package/inferencer/tests/inferencer.spec.ts +19 -0
  39. package/inferencer/tsconfig.json +19 -0
  40. package/inferencer/types/.kiro/specs/conversion-template/README.md +128 -0
  41. package/inferencer/types/.kiro/specs/conversion-template/design.md +360 -0
  42. package/inferencer/types/.kiro/specs/conversion-template/requirements.md +191 -0
  43. package/inferencer/types/.kiro/specs/conversion-template/tasks.md +174 -0
  44. package/inferencer/types/.kiro/steering/coding-standards.md +53 -0
  45. package/inferencer/types/.kiro/steering/conversion-guide.md +108 -0
  46. package/inferencer/types/.kiro/steering/declarative-configuration.md +108 -0
  47. package/inferencer/types/.kiro/steering/emc-json-serializability.md +306 -0
  48. package/inferencer/types/EnhancementConversionInstructions.md +1854 -0
  49. package/inferencer/types/LICENSE +21 -0
  50. package/inferencer/types/NewCustomElement.md +388 -0
  51. package/inferencer/types/NewCustomElementFeature.md +683 -0
  52. package/inferencer/types/NewEnhancementInstructions.md +705 -0
  53. package/inferencer/types/README.md +2 -0
  54. package/inferencer/types/agrace/types.d.ts +11 -0
  55. package/inferencer/types/assign-gingerly/types.d.ts +572 -0
  56. package/inferencer/types/be-a-beacon/types.d.ts +17 -0
  57. package/inferencer/types/be-bound/types.d.ts +66 -0
  58. package/inferencer/types/be-buttoned-up/types.d.ts +19 -0
  59. package/inferencer/types/be-calculating/types.d.ts +54 -0
  60. package/inferencer/types/be-clonable/types.d.ts +38 -0
  61. package/inferencer/types/be-committed/types.d.ts +22 -0
  62. package/inferencer/types/be-consoling/types.d.ts +24 -0
  63. package/inferencer/types/be-decked-with/types.d.ts +26 -0
  64. package/inferencer/types/be-delible/types.d.ts +27 -0
  65. package/inferencer/types/be-dispatching/types.d.ts +34 -0
  66. package/inferencer/types/be-evanescent/types.d.ts +20 -0
  67. package/inferencer/types/be-flashy/types.d.ts +21 -0
  68. package/inferencer/types/be-gone/types.d.ts +25 -0
  69. package/inferencer/types/be-observing/types.d.ts +55 -0
  70. package/inferencer/types/be-reflective/types.d.ts +78 -0
  71. package/inferencer/types/be-reformable/types.d.ts +49 -0
  72. package/inferencer/types/be-render-neutral/types.d.ts +32 -0
  73. package/inferencer/types/be-switched/types.d.ts +146 -0
  74. package/inferencer/types/be-typed/types.d.ts +32 -0
  75. package/inferencer/types/be-valued/types.d.ts +22 -0
  76. package/inferencer/types/data-props/types.d.ts +34 -0
  77. package/inferencer/types/do-inc/types.d.ts +56 -0
  78. package/inferencer/types/do-invoke/types.d.ts +38 -0
  79. package/inferencer/types/do-merge/types.d.ts +28 -0
  80. package/inferencer/types/do-toggle/types.d.ts +31 -0
  81. package/inferencer/types/face-up/types.d.ts +100 -0
  82. package/inferencer/types/fetch-for/types.d.ts +36 -0
  83. package/inferencer/types/folder-picker/types.d.ts +21 -0
  84. package/inferencer/types/global.d.ts +29 -0
  85. package/inferencer/types/id-generation/types.d.ts +26 -0
  86. package/inferencer/types/inferencer/types.d.ts +46 -0
  87. package/inferencer/types/mount-observer/types.d.ts +363 -0
  88. package/inferencer/types/nested-regex-groups/types.d.ts +107 -0
  89. package/inferencer/types/pipe-in/types.d.ts +52 -0
  90. package/inferencer/types/roundabout/types.d.ts +268 -0
  91. package/inferencer/types/soak-up/types.d.ts +40 -0
  92. package/inferencer/types/templ-maker/types.d.ts +43 -0
  93. package/inferencer/types/time-ticker/types.d.ts +62 -0
  94. package/inferencer/types/truth-sourcer/types.d.ts +44 -0
  95. package/inferencer/upSearch.js +27 -0
  96. package/inferencer/upSearch.ts +26 -0
  97. package/inferencer/withScopePerimeter.js +27 -0
  98. package/inferencer/withScopePerimeter.ts +33 -0
  99. package/inferredAssignments.js +38 -0
  100. package/inferredAssignments.ts +65 -0
  101. package/isAllowedImportPath.js +42 -0
  102. package/isAllowedImportPath.ts +53 -0
  103. package/package.json +57 -3
  104. package/paths.js +231 -0
  105. package/paths.ts +413 -0
  106. package/processHandlerCommands.js +188 -0
  107. package/processHandlerCommands.ts +217 -0
  108. package/resolveIdRef.js +144 -0
  109. package/resolveIdRef.ts +170 -0
  110. package/resolveValues.js +41 -2
  111. package/resolveValues.ts +41 -1
  112. package/transitionHelper.js +109 -0
  113. package/transitionHelper.ts +132 -0
  114. 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.53",
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.60.0",
152
+ "@playwright/test": "1.61.1",
99
153
  "spa-ssi": "0.0.27",
100
- "@types/node": "25.9.3",
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
+ }