assign-gingerly 0.0.75 → 0.0.77
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/DX/installForwarding.js +1 -1
- package/DX/installForwarding.ts +1 -1
- package/README.md +2 -0
- package/assignFeatures.js +10 -31
- package/assignFeatures.ts +15 -39
- package/assignFrom.js +18 -17
- package/assignFrom.ts +23 -23
- package/assignFromAsync.js +14 -13
- package/assignFromAsync.ts +15 -15
- package/assignGingerly.js +87 -48
- package/assignGingerly.ts +177 -131
- package/assignPermissions/PermissionProcessor.js +166 -0
- package/assignPermissions/PermissionProcessor.ts +210 -0
- package/assignPermissions/isAllowedImportPath.js +2 -6
- package/assignPermissions/isAllowedImportPath.ts +3 -5
- package/assignPermissions/isAllowedUrl.js +18 -0
- package/assignPermissions/isAllowedUrl.ts +15 -0
- package/assignTentatively.js +9 -11
- package/assignTentatively.ts +11 -13
- package/beVigilant.js +1 -1
- package/beVigilant.ts +1 -1
- package/buildCSSQuery.js +1 -1
- package/buildCSSQuery.ts +1 -1
- package/eachTime.js +5 -6
- package/eachTime.ts +12 -15
- package/enhanceAll.js +3 -3
- package/enhanceAll.ts +4 -4
- package/evaluatePathWithAsyncMethods.js +12 -8
- package/evaluatePathWithAsyncMethods.ts +129 -117
- package/handlers/addEventListener.js +11 -11
- package/handlers/addEventListener.ts +12 -13
- package/handlers/lazyLoad.ts +7 -7
- package/handlers/lazyLoadSwitch.ts +3 -3
- package/handlers/manageTemplateList.js +10 -10
- package/handlers/manageTemplateList.ts +12 -12
- package/handlers/rangeSelector.ts +3 -3
- package/index.js +2 -3
- package/index.ts +2 -3
- package/inferencer/types/assign-gingerly/types.d.ts +40 -9
- package/inferencer/types/el-maker/types.d.ts +33 -0
- package/inferencer/types/scratch-box/types.d.ts +3 -0
- package/inferencer/types/truth-sourcer/types.d.ts +4 -0
- package/inferencer/types/wc-info/SimpleWCInfo.d.ts +15 -0
- package/package.json +24 -23
- package/parseWithAttrs.js +1 -1
- package/parseWithAttrs.ts +1 -1
- package/processHandlerCommands.js +5 -7
- package/processHandlerCommands.ts +12 -15
- package/{getValues.js → resolve/getValues.js} +19 -8
- package/{getValues.ts → resolve/getValues.ts} +331 -314
- package/{resolveIdRef.js → resolve/resolveIdRef.js} +1 -1
- package/{resolveIdRef.ts → resolve/resolveIdRef.ts} +1 -1
- package/{resolveValues.ts → resolve/resolveValues.ts} +1 -1
- package/types/assign-gingerly/types.d.ts +40 -9
- package/assignPermissions/restrictedProps.js +0 -43
- package/assignPermissions/restrictedProps.ts +0 -53
- package/resolveAndAssignFeatures.js +0 -36
- package/resolveAndAssignFeatures.ts +0 -43
- /package/{resolveTemplate.js → resolve/resolveTemplate.js} +0 -0
- /package/{resolveTemplate.ts → resolve/resolveTemplate.ts} +0 -0
- /package/{resolveValues.js → resolve/resolveValues.js} +0 -0
package/DX/installForwarding.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* installForwarding(ClubMember);
|
|
21
21
|
* // Now el.command delegates to el.behaviors.commandBehavior.command
|
|
22
22
|
*/
|
|
23
|
-
import { resolveValue } from '../resolveValues.js';
|
|
23
|
+
import { resolveValue } from '../resolve/resolveValues.js';
|
|
24
24
|
import assignGingerly from '../assignGingerly.js';
|
|
25
25
|
/**
|
|
26
26
|
* Installs property forwarding on a class prototype based on `static propLinks`.
|
package/DX/installForwarding.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* // Now el.command delegates to el.behaviors.commandBehavior.command
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { resolveValue} from '../resolveValues.js';
|
|
24
|
+
import { resolveValue} from '../resolve/resolveValues.js';
|
|
25
25
|
import {ResolveValuesOptions, IAssignGingerlyOptions} from '../types/assign-gingerly/types.js';
|
|
26
26
|
import assignGingerly, { } from '../assignGingerly.js';
|
|
27
27
|
|
package/README.md
CHANGED
|
@@ -54,6 +54,8 @@ So in our view this package helps fill the void left by not supporting the "is"
|
|
|
54
54
|
|
|
55
55
|
Anyway, let's start out detailing the more innocent features of this package / polyfill.
|
|
56
56
|
|
|
57
|
+
Because the same declarative input can come from sources that aren't fully trusted — HTML attributes, user JSON, remote config — the package also provides an **opt-in permission layer** to block or redirect dangerous property assignments. See [docs/assign-permissions.md](docs/assign-permissions.md) for how to construct and pass a `PermissionProcessor`.
|
|
58
|
+
|
|
57
59
|
The three utility functions are:
|
|
58
60
|
|
|
59
61
|
## assignGingerly
|
package/assignFeatures.js
CHANGED
|
@@ -84,10 +84,8 @@ function isAsyncResolution(spawnish) {
|
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Resolves all configured spawns for the target constructor and caches them.
|
|
87
|
-
* Returns a Promise if any resolution is async, otherwise undefined.
|
|
88
87
|
*/
|
|
89
|
-
function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
|
|
90
|
-
let hasAsync = false;
|
|
88
|
+
async function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
|
|
91
89
|
const asyncResolutions = [];
|
|
92
90
|
for (const key of Object.keys(features)) {
|
|
93
91
|
const classCache = getOrCreateClassCache(ctr);
|
|
@@ -104,7 +102,6 @@ function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
|
|
|
104
102
|
continue;
|
|
105
103
|
}
|
|
106
104
|
if (isAsyncResolution(spawnish)) {
|
|
107
|
-
hasAsync = true;
|
|
108
105
|
asyncResolutions.push((async () => {
|
|
109
106
|
const resolved = await resolveSpawn(spawnish);
|
|
110
107
|
classCache.set(key, resolved);
|
|
@@ -114,10 +111,9 @@ function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
|
|
|
114
111
|
classCache.set(key, spawnish);
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
|
-
if (
|
|
118
|
-
|
|
114
|
+
if (asyncResolutions.length > 0) {
|
|
115
|
+
await Promise.all(asyncResolutions);
|
|
119
116
|
}
|
|
120
|
-
return undefined;
|
|
121
117
|
}
|
|
122
118
|
/**
|
|
123
119
|
* Installs a getter/setter pair on the constructor's prototype for the given feature key.
|
|
@@ -288,7 +284,7 @@ function installCallbackForwarding(ctr, key, callbacks) {
|
|
|
288
284
|
featureKeys.add(key);
|
|
289
285
|
}
|
|
290
286
|
}
|
|
291
|
-
function installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry) {
|
|
287
|
+
async function installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry) {
|
|
292
288
|
// 1. Confirm the key is opted-in via supportedFeatures
|
|
293
289
|
if (!(key in supportedFeatures)) {
|
|
294
290
|
throw new Error(`assignFeatures: "${key}" is not declared in ${ctr.name || 'constructor'}.supportedFeatures`);
|
|
@@ -322,27 +318,13 @@ function installOneFeature(ctr, key, features, supportedFeatures, featuresRegist
|
|
|
322
318
|
if (resolvedSpawn && !isAsyncSpawn(resolvedSpawn) &&
|
|
323
319
|
Object.hasOwn(resolvedSpawn, 'onAssigned') &&
|
|
324
320
|
typeof resolvedSpawn.onAssigned === 'function') {
|
|
325
|
-
|
|
326
|
-
if (result && typeof result.then === 'function') {
|
|
327
|
-
return result;
|
|
328
|
-
}
|
|
321
|
+
await resolvedSpawn.onAssigned(ctr, featureConfig, key);
|
|
329
322
|
}
|
|
330
|
-
return undefined;
|
|
331
323
|
}
|
|
332
|
-
function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry) {
|
|
333
|
-
let asyncResult;
|
|
324
|
+
async function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry) {
|
|
334
325
|
for (const key of Object.keys(features)) {
|
|
335
|
-
|
|
336
|
-
if (result) {
|
|
337
|
-
if (!asyncResult) {
|
|
338
|
-
asyncResult = result.then(() => undefined);
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
asyncResult = asyncResult.then(() => result.then(() => undefined));
|
|
342
|
-
}
|
|
343
|
-
}
|
|
326
|
+
await installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
|
|
344
327
|
}
|
|
345
|
-
return asyncResult;
|
|
346
328
|
}
|
|
347
329
|
/**
|
|
348
330
|
* Core assignFeatures implementation.
|
|
@@ -357,7 +339,7 @@ function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry)
|
|
|
357
339
|
* @param features - Map of feature keys to their injection configs
|
|
358
340
|
* @param featuresRegistry - The registry to store injections in
|
|
359
341
|
*/
|
|
360
|
-
export function assignFeatures(ctr, features, featuresRegistry) {
|
|
342
|
+
export async function assignFeatures(ctr, features, featuresRegistry) {
|
|
361
343
|
// Validate that the constructor has static supportedFeatures
|
|
362
344
|
const supportedFeatures = ctr.supportedFeatures;
|
|
363
345
|
if (!supportedFeatures) {
|
|
@@ -366,11 +348,8 @@ export function assignFeatures(ctr, features, featuresRegistry) {
|
|
|
366
348
|
// Resolve all configured spawns before installing getters. This is the single
|
|
367
349
|
// source of truth for spawn resolution; other callers (defineWithFeatures, etc.)
|
|
368
350
|
// delegate to assignFeatures.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return spawnResolution.then(() => installAllFeatures(ctr, features, supportedFeatures, featuresRegistry));
|
|
372
|
-
}
|
|
373
|
-
return installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
|
|
351
|
+
await resolveAndCacheSpawns(ctr, features, supportedFeatures);
|
|
352
|
+
await installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
|
|
374
353
|
}
|
|
375
354
|
/**
|
|
376
355
|
* Captures own-properties that shadow feature getters and stores them as initVals.
|
package/assignFeatures.ts
CHANGED
|
@@ -96,14 +96,12 @@ function isAsyncResolution(spawnish: any): boolean {
|
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* Resolves all configured spawns for the target constructor and caches them.
|
|
99
|
-
* Returns a Promise if any resolution is async, otherwise undefined.
|
|
100
99
|
*/
|
|
101
|
-
function resolveAndCacheSpawns(
|
|
100
|
+
async function resolveAndCacheSpawns(
|
|
102
101
|
ctr: Function,
|
|
103
102
|
features: FeatureConfigsMap,
|
|
104
103
|
supportedFeatures: SupportedFeaturesMap
|
|
105
|
-
): Promise<void>
|
|
106
|
-
let hasAsync = false;
|
|
104
|
+
): Promise<void> {
|
|
107
105
|
const asyncResolutions: Promise<void>[] = [];
|
|
108
106
|
|
|
109
107
|
for (const key of Object.keys(features)) {
|
|
@@ -123,7 +121,6 @@ function resolveAndCacheSpawns(
|
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
if (isAsyncResolution(spawnish)) {
|
|
126
|
-
hasAsync = true;
|
|
127
124
|
asyncResolutions.push((async () => {
|
|
128
125
|
const resolved = await resolveSpawn(spawnish);
|
|
129
126
|
classCache.set(key, resolved);
|
|
@@ -133,10 +130,9 @@ function resolveAndCacheSpawns(
|
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
|
|
136
|
-
if (
|
|
137
|
-
|
|
133
|
+
if (asyncResolutions.length > 0) {
|
|
134
|
+
await Promise.all(asyncResolutions);
|
|
138
135
|
}
|
|
139
|
-
return undefined;
|
|
140
136
|
}
|
|
141
137
|
|
|
142
138
|
/**
|
|
@@ -349,13 +345,13 @@ function installCallbackForwarding(
|
|
|
349
345
|
}
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
function installOneFeature(
|
|
348
|
+
async function installOneFeature(
|
|
353
349
|
ctr: Function,
|
|
354
350
|
key: string,
|
|
355
351
|
features: FeatureConfigsMap,
|
|
356
352
|
supportedFeatures: SupportedFeaturesMap,
|
|
357
353
|
featuresRegistry: FeaturesRegistry
|
|
358
|
-
): Promise<void>
|
|
354
|
+
): Promise<void> {
|
|
359
355
|
// 1. Confirm the key is opted-in via supportedFeatures
|
|
360
356
|
if (!(key in supportedFeatures)) {
|
|
361
357
|
throw new Error(
|
|
@@ -401,32 +397,19 @@ function installOneFeature(
|
|
|
401
397
|
if (resolvedSpawn && !isAsyncSpawn(resolvedSpawn) &&
|
|
402
398
|
Object.hasOwn(resolvedSpawn, 'onAssigned') &&
|
|
403
399
|
typeof (resolvedSpawn as any).onAssigned === 'function') {
|
|
404
|
-
|
|
405
|
-
if (result && typeof result.then === 'function') {
|
|
406
|
-
return result;
|
|
407
|
-
}
|
|
400
|
+
await (resolvedSpawn as any).onAssigned(ctr, featureConfig, key);
|
|
408
401
|
}
|
|
409
|
-
return undefined;
|
|
410
402
|
}
|
|
411
403
|
|
|
412
|
-
function installAllFeatures(
|
|
404
|
+
async function installAllFeatures(
|
|
413
405
|
ctr: Function,
|
|
414
406
|
features: FeatureConfigsMap,
|
|
415
407
|
supportedFeatures: SupportedFeaturesMap,
|
|
416
408
|
featuresRegistry: FeaturesRegistry
|
|
417
|
-
): Promise<void>
|
|
418
|
-
let asyncResult: Promise<void> | undefined;
|
|
409
|
+
): Promise<void> {
|
|
419
410
|
for (const key of Object.keys(features)) {
|
|
420
|
-
|
|
421
|
-
if (result) {
|
|
422
|
-
if (!asyncResult) {
|
|
423
|
-
asyncResult = result.then(() => undefined);
|
|
424
|
-
} else {
|
|
425
|
-
asyncResult = asyncResult.then(() => result.then(() => undefined));
|
|
426
|
-
}
|
|
427
|
-
}
|
|
411
|
+
await installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
|
|
428
412
|
}
|
|
429
|
-
return asyncResult;
|
|
430
413
|
}
|
|
431
414
|
|
|
432
415
|
/**
|
|
@@ -442,11 +425,11 @@ function installAllFeatures(
|
|
|
442
425
|
* @param features - Map of feature keys to their injection configs
|
|
443
426
|
* @param featuresRegistry - The registry to store injections in
|
|
444
427
|
*/
|
|
445
|
-
export function assignFeatures(
|
|
428
|
+
export async function assignFeatures(
|
|
446
429
|
ctr: Function,
|
|
447
430
|
features: FeatureConfigsMap,
|
|
448
431
|
featuresRegistry: FeaturesRegistry
|
|
449
|
-
): Promise<void>
|
|
432
|
+
): Promise<void> {
|
|
450
433
|
// Validate that the constructor has static supportedFeatures
|
|
451
434
|
const supportedFeatures: SupportedFeaturesMap | undefined = (ctr as any).supportedFeatures;
|
|
452
435
|
|
|
@@ -459,15 +442,8 @@ export function assignFeatures(
|
|
|
459
442
|
// Resolve all configured spawns before installing getters. This is the single
|
|
460
443
|
// source of truth for spawn resolution; other callers (defineWithFeatures, etc.)
|
|
461
444
|
// delegate to assignFeatures.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (spawnResolution) {
|
|
465
|
-
return spawnResolution.then(() =>
|
|
466
|
-
installAllFeatures(ctr, features, supportedFeatures, featuresRegistry)
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
|
|
445
|
+
await resolveAndCacheSpawns(ctr, features, supportedFeatures);
|
|
446
|
+
await installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
|
|
471
447
|
}
|
|
472
448
|
|
|
473
449
|
/**
|
|
@@ -682,7 +658,7 @@ export class PropertyBag {
|
|
|
682
658
|
declare global {
|
|
683
659
|
interface CustomElementRegistry {
|
|
684
660
|
featuresRegistry: FeaturesRegistry;
|
|
685
|
-
assignFeatures(ctr: Function, features: FeatureConfigsMap): Promise<void
|
|
661
|
+
assignFeatures(ctr: Function, features: FeatureConfigsMap): Promise<void>;
|
|
686
662
|
}
|
|
687
663
|
}
|
|
688
664
|
|
package/assignFrom.js
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Handler commands (` =>`) are fire-and-forget (kicked off asynchronously, not awaited).
|
|
10
10
|
*/
|
|
11
|
-
import { getValues, getValue } from './getValues.js';
|
|
11
|
+
import { getValues, getValue } from './resolve/getValues.js';
|
|
12
12
|
import assignGingerly from './assignGingerly.js';
|
|
13
|
-
import { resolveIdVariable, parseIdRef } from './resolveIdRef.js';
|
|
13
|
+
import { resolveIdVariable, parseIdRef } from './resolve/resolveIdRef.js';
|
|
14
14
|
import { processInferredAssignments } from './inferredAssignments.js';
|
|
15
15
|
/**
|
|
16
16
|
* Supported substitution variables and their option keys.
|
|
@@ -377,7 +377,7 @@ function getEffectiveIds(options) {
|
|
|
377
377
|
/**
|
|
378
378
|
* Process #[x] normal keys synchronously.
|
|
379
379
|
*/
|
|
380
|
-
function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options,
|
|
380
|
+
function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options, permissionProcessor) {
|
|
381
381
|
const ids = getEffectiveIds(options);
|
|
382
382
|
if (!ids)
|
|
383
383
|
return;
|
|
@@ -391,13 +391,13 @@ function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, option
|
|
|
391
391
|
continue;
|
|
392
392
|
const value = expandedPattern[key];
|
|
393
393
|
if (parsed.remainingPath) {
|
|
394
|
-
const resolvedValue = getValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target });
|
|
395
|
-
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options,
|
|
394
|
+
const resolvedValue = getValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target, permissionProcessor });
|
|
395
|
+
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options, permissionProcessor);
|
|
396
396
|
}
|
|
397
397
|
else {
|
|
398
|
-
const resolvedValue = getValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target });
|
|
398
|
+
const resolvedValue = getValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target, permissionProcessor });
|
|
399
399
|
if (!('__v' in resolvedValue)) {
|
|
400
|
-
assignGingerly(el, resolvedValue, options,
|
|
400
|
+
assignGingerly(el, resolvedValue, options, permissionProcessor);
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
}
|
|
@@ -411,15 +411,15 @@ function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, option
|
|
|
411
411
|
* @param target - Object to merge resolved values into
|
|
412
412
|
* @param pattern - Object whose RHS values may contain `?.` path strings
|
|
413
413
|
* @param options - Options including `from` (source object)
|
|
414
|
-
* @param
|
|
414
|
+
* @param permissionProcessor - Optional security permissionProcessor
|
|
415
415
|
* @returns The target object after merging
|
|
416
416
|
*/
|
|
417
|
-
export function assignFrom(target, pattern, options,
|
|
417
|
+
export function assignFrom(target, pattern, options, permissionProcessor) {
|
|
418
418
|
// Expand looped substitution variables
|
|
419
419
|
const expandedPattern = expandSubstitutions(pattern, options);
|
|
420
420
|
// Categorize keys
|
|
421
421
|
const { handlerKeys, normalPattern, idRefNormalKeys, idRefHandlerKeys, ternaryKeys } = categorizeKeys(expandedPattern);
|
|
422
|
-
const resolveOptions = { ...options, root: target };
|
|
422
|
+
const resolveOptions = { ...options, root: target, permissionProcessor };
|
|
423
423
|
// Process ?= ternary keys (sync)
|
|
424
424
|
if (ternaryKeys.length > 0) {
|
|
425
425
|
const ternaryResolved = {};
|
|
@@ -436,7 +436,7 @@ export function assignFrom(target, pattern, options, permissions) {
|
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
438
|
if (Object.keys(ternaryResolved).length > 0) {
|
|
439
|
-
assignGingerly(target, ternaryResolved, options,
|
|
439
|
+
assignGingerly(target, ternaryResolved, options, permissionProcessor);
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
// Process normal keys via getValues (sync) + assignGingerly
|
|
@@ -459,7 +459,8 @@ export function assignFrom(target, pattern, options, permissions) {
|
|
|
459
459
|
aka: options.aka,
|
|
460
460
|
akaMethods: options.akaMethods,
|
|
461
461
|
protocols: options.protocols,
|
|
462
|
-
root: target
|
|
462
|
+
root: target,
|
|
463
|
+
permissionProcessor
|
|
463
464
|
});
|
|
464
465
|
}
|
|
465
466
|
else {
|
|
@@ -472,16 +473,16 @@ export function assignFrom(target, pattern, options, permissions) {
|
|
|
472
473
|
}
|
|
473
474
|
const resolved = getValues(normalPattern, options.from, resolveOptions);
|
|
474
475
|
handleSpreads(resolved);
|
|
475
|
-
assignGingerly(target, resolved, options,
|
|
476
|
+
assignGingerly(target, resolved, options, permissionProcessor);
|
|
476
477
|
}
|
|
477
478
|
// Process #[x] normal keys (sync)
|
|
478
479
|
if (idRefNormalKeys.length > 0) {
|
|
479
|
-
processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options,
|
|
480
|
+
processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options, permissionProcessor);
|
|
480
481
|
}
|
|
481
482
|
// Process handler commands — fire-and-forget (async)
|
|
482
483
|
if (handlerKeys.length > 0) {
|
|
483
484
|
import('./processHandlerCommands.js').then(({ processHandlerCommands }) => {
|
|
484
|
-
processHandlerCommands(target, handlerKeys, expandedPattern, options,
|
|
485
|
+
processHandlerCommands(target, handlerKeys, expandedPattern, options, permissionProcessor);
|
|
485
486
|
});
|
|
486
487
|
}
|
|
487
488
|
// Process #[x] handler keys — fire-and-forget (async)
|
|
@@ -497,7 +498,7 @@ export function assignFrom(target, pattern, options, permissions) {
|
|
|
497
498
|
continue;
|
|
498
499
|
const syntheticKey = parsed.remainingPath ? `${parsed.remainingPath} =>` : ' =>';
|
|
499
500
|
const syntheticPattern = { [syntheticKey]: expandedPattern[key] };
|
|
500
|
-
processHandlerCommands(el, [syntheticKey], syntheticPattern, options,
|
|
501
|
+
processHandlerCommands(el, [syntheticKey], syntheticPattern, options, permissionProcessor);
|
|
501
502
|
}
|
|
502
503
|
});
|
|
503
504
|
}
|
|
@@ -517,7 +518,7 @@ export function assignFrom(target, pattern, options, permissions) {
|
|
|
517
518
|
// Process bulk enhancements — fire-and-forget (async)
|
|
518
519
|
if (options.enhance && options.enhance.length > 0) {
|
|
519
520
|
import('./enhanceAll.js').then(({ enhanceAll }) => {
|
|
520
|
-
enhanceAll(target, options.enhance,
|
|
521
|
+
enhanceAll(target, options.enhance, permissionProcessor);
|
|
521
522
|
});
|
|
522
523
|
}
|
|
523
524
|
return target;
|
package/assignFrom.ts
CHANGED
|
@@ -9,12 +9,11 @@
|
|
|
9
9
|
* Handler commands (` =>`) are fire-and-forget (kicked off asynchronously, not awaited).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { getValues, getValue } from './getValues.js';
|
|
12
|
+
import { getValues, getValue } from './resolve/getValues.js';
|
|
13
13
|
import assignGingerly from './assignGingerly.js';
|
|
14
|
-
import { resolveIdVariable, parseIdRef } from './resolveIdRef.js';
|
|
14
|
+
import { resolveIdVariable, parseIdRef } from './resolve/resolveIdRef.js';
|
|
15
15
|
import { processInferredAssignments } from './inferredAssignments.js';
|
|
16
|
-
import type {
|
|
17
|
-
import type { AssignFromOptions, AssignFromHandler, AssignFromHandlerConstructor } from './types/assign-gingerly/types.js';
|
|
16
|
+
import type { PermissionProcessor, AssignFromOptions, AssignFromHandler, AssignFromHandlerConstructor } from './types/assign-gingerly/types.js';
|
|
18
17
|
|
|
19
18
|
// Re-export types for consumers
|
|
20
19
|
export type { AssignFromOptions, AssignFromHandler, AssignFromHandlerConstructor };
|
|
@@ -387,11 +386,11 @@ function getEffectiveIds(options: AssignFromOptions): Record<string, any> | unde
|
|
|
387
386
|
* Process #[x] normal keys synchronously.
|
|
388
387
|
*/
|
|
389
388
|
function processIdRefNormalKeys(
|
|
390
|
-
idRefNormalKeys: string[],
|
|
391
|
-
expandedPattern: Record<string, any>,
|
|
392
|
-
target: any,
|
|
393
|
-
options: AssignFromOptions,
|
|
394
|
-
|
|
389
|
+
idRefNormalKeys: string[],
|
|
390
|
+
expandedPattern: Record<string, any>,
|
|
391
|
+
target: any,
|
|
392
|
+
options: AssignFromOptions,
|
|
393
|
+
permissionProcessor?: PermissionProcessor
|
|
395
394
|
): void {
|
|
396
395
|
const ids = getEffectiveIds(options);
|
|
397
396
|
if (!ids) return;
|
|
@@ -408,17 +407,17 @@ function processIdRefNormalKeys(
|
|
|
408
407
|
if (parsed.remainingPath) {
|
|
409
408
|
const resolvedValue = getValues(
|
|
410
409
|
{ __v: value }, from,
|
|
411
|
-
{ withMethods, aka, akaMethods, protocols, root: target }
|
|
410
|
+
{ withMethods, aka, akaMethods, protocols, root: target, permissionProcessor }
|
|
412
411
|
);
|
|
413
|
-
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options,
|
|
412
|
+
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options, permissionProcessor);
|
|
414
413
|
} else {
|
|
415
414
|
const resolvedValue = getValues(
|
|
416
415
|
typeof value === 'object' && value !== null ? value : { __v: value },
|
|
417
416
|
from,
|
|
418
|
-
{ withMethods, aka, akaMethods, protocols, root: target }
|
|
417
|
+
{ withMethods, aka, akaMethods, protocols, root: target, permissionProcessor }
|
|
419
418
|
);
|
|
420
419
|
if (!('__v' in resolvedValue)) {
|
|
421
|
-
assignGingerly(el, resolvedValue, options,
|
|
420
|
+
assignGingerly(el, resolvedValue, options, permissionProcessor);
|
|
422
421
|
}
|
|
423
422
|
}
|
|
424
423
|
}
|
|
@@ -433,14 +432,14 @@ function processIdRefNormalKeys(
|
|
|
433
432
|
* @param target - Object to merge resolved values into
|
|
434
433
|
* @param pattern - Object whose RHS values may contain `?.` path strings
|
|
435
434
|
* @param options - Options including `from` (source object)
|
|
436
|
-
* @param
|
|
435
|
+
* @param permissionProcessor - Optional security permissionProcessor
|
|
437
436
|
* @returns The target object after merging
|
|
438
437
|
*/
|
|
439
438
|
export function assignFrom(
|
|
440
439
|
target: any,
|
|
441
440
|
pattern: Record<string, any>,
|
|
442
441
|
options: AssignFromOptions,
|
|
443
|
-
|
|
442
|
+
permissionProcessor?: PermissionProcessor
|
|
444
443
|
): any {
|
|
445
444
|
// Expand looped substitution variables
|
|
446
445
|
const expandedPattern = expandSubstitutions(pattern, options);
|
|
@@ -448,7 +447,7 @@ export function assignFrom(
|
|
|
448
447
|
// Categorize keys
|
|
449
448
|
const { handlerKeys, normalPattern, idRefNormalKeys, idRefHandlerKeys, ternaryKeys } = categorizeKeys(expandedPattern);
|
|
450
449
|
|
|
451
|
-
const resolveOptions = { ...options, root: target } as any;
|
|
450
|
+
const resolveOptions = { ...options, root: target, permissionProcessor } as any;
|
|
452
451
|
|
|
453
452
|
// Process ?= ternary keys (sync)
|
|
454
453
|
if (ternaryKeys.length > 0) {
|
|
@@ -464,7 +463,7 @@ export function assignFrom(
|
|
|
464
463
|
}
|
|
465
464
|
}
|
|
466
465
|
if (Object.keys(ternaryResolved).length > 0) {
|
|
467
|
-
assignGingerly(target, ternaryResolved, options,
|
|
466
|
+
assignGingerly(target, ternaryResolved, options, permissionProcessor);
|
|
468
467
|
}
|
|
469
468
|
}
|
|
470
469
|
|
|
@@ -488,7 +487,8 @@ export function assignFrom(
|
|
|
488
487
|
aka: options.aka,
|
|
489
488
|
akaMethods: options.akaMethods,
|
|
490
489
|
protocols: options.protocols,
|
|
491
|
-
root: target
|
|
490
|
+
root: target,
|
|
491
|
+
permissionProcessor
|
|
492
492
|
});
|
|
493
493
|
} else {
|
|
494
494
|
normalPattern[key] = el.id; // bare #[x] → ID string
|
|
@@ -502,18 +502,18 @@ export function assignFrom(
|
|
|
502
502
|
const resolved = getValues(normalPattern, options.from, resolveOptions);
|
|
503
503
|
|
|
504
504
|
handleSpreads(resolved);
|
|
505
|
-
assignGingerly(target, resolved, options,
|
|
505
|
+
assignGingerly(target, resolved, options, permissionProcessor);
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
// Process #[x] normal keys (sync)
|
|
509
509
|
if (idRefNormalKeys.length > 0) {
|
|
510
|
-
processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options,
|
|
510
|
+
processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, options, permissionProcessor);
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
// Process handler commands — fire-and-forget (async)
|
|
514
514
|
if (handlerKeys.length > 0) {
|
|
515
515
|
import('./processHandlerCommands.js').then(({ processHandlerCommands }) => {
|
|
516
|
-
processHandlerCommands(target, handlerKeys, expandedPattern, options,
|
|
516
|
+
processHandlerCommands(target, handlerKeys, expandedPattern, options, permissionProcessor);
|
|
517
517
|
});
|
|
518
518
|
}
|
|
519
519
|
|
|
@@ -528,7 +528,7 @@ export function assignFrom(
|
|
|
528
528
|
if (!el) continue;
|
|
529
529
|
const syntheticKey = parsed.remainingPath ? `${parsed.remainingPath} =>` : ' =>';
|
|
530
530
|
const syntheticPattern = { [syntheticKey]: expandedPattern[key] };
|
|
531
|
-
processHandlerCommands(el, [syntheticKey], syntheticPattern, options,
|
|
531
|
+
processHandlerCommands(el, [syntheticKey], syntheticPattern, options, permissionProcessor);
|
|
532
532
|
}
|
|
533
533
|
});
|
|
534
534
|
}
|
|
@@ -551,7 +551,7 @@ export function assignFrom(
|
|
|
551
551
|
// Process bulk enhancements — fire-and-forget (async)
|
|
552
552
|
if (options.enhance && options.enhance.length > 0) {
|
|
553
553
|
import('./enhanceAll.js').then(({ enhanceAll }) => {
|
|
554
|
-
enhanceAll(target, options.enhance!,
|
|
554
|
+
enhanceAll(target, options.enhance!, permissionProcessor);
|
|
555
555
|
});
|
|
556
556
|
}
|
|
557
557
|
|
package/assignFromAsync.js
CHANGED
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
* }, { from: source });
|
|
20
20
|
* // target is now { color: 'red', text: 'Hello' }
|
|
21
21
|
*/
|
|
22
|
-
import { resolveValues } from './resolveValues.js';
|
|
22
|
+
import { resolveValues } from './resolve/resolveValues.js';
|
|
23
23
|
import assignGingerly from './assignGingerly.js';
|
|
24
24
|
import { expandSubstitutions, categorizeKeys, handleSpreads } from './assignFrom.js';
|
|
25
25
|
// Module cache for processHandlerCommands — avoids await on dynamic import after first call
|
|
26
26
|
let _processHandlerCommands;
|
|
27
|
-
export async function assignFromAsync(target, pattern, options,
|
|
27
|
+
export async function assignFromAsync(target, pattern, options, permissionProcessor) {
|
|
28
28
|
// First: expand looped substitution variables (${x}, ${y}, ${z})
|
|
29
29
|
const expandedPattern = expandSubstitutions(pattern, options);
|
|
30
30
|
// Categorize keys
|
|
@@ -36,16 +36,17 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
36
36
|
aka: options.aka,
|
|
37
37
|
akaMethods: options.akaMethods,
|
|
38
38
|
protocols: options.protocols,
|
|
39
|
-
root: target
|
|
39
|
+
root: target,
|
|
40
|
+
permissionProcessor
|
|
40
41
|
});
|
|
41
42
|
// Recursively handle "..." spread keys at all nesting levels
|
|
42
43
|
handleSpreads(resolved);
|
|
43
|
-
assignGingerly(target, resolved, options,
|
|
44
|
+
assignGingerly(target, resolved, options, permissionProcessor);
|
|
44
45
|
}
|
|
45
46
|
// Process #[x] normal keys — resolve element, then apply remaining path + value
|
|
46
47
|
if (idRefNormalKeys.length > 0 && (options.pin || options.at)) {
|
|
47
48
|
const ids = { ...options.pin, ...options.at };
|
|
48
|
-
const { resolveIdVariable, parseIdRef } = await import('./resolveIdRef.js');
|
|
49
|
+
const { resolveIdVariable, parseIdRef } = await import('./resolve/resolveIdRef.js');
|
|
49
50
|
const { withMethods, aka, akaMethods, protocols, from } = options;
|
|
50
51
|
for (const key of idRefNormalKeys) {
|
|
51
52
|
const parsed = parseIdRef(key);
|
|
@@ -57,18 +58,18 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
57
58
|
const value = expandedPattern[key];
|
|
58
59
|
if (parsed.remainingPath) {
|
|
59
60
|
// Resolve the RHS value
|
|
60
|
-
const resolvedValue = await resolveValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el });
|
|
61
|
+
const resolvedValue = await resolveValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el, permissionProcessor });
|
|
61
62
|
// Apply remaining path on the resolved element
|
|
62
|
-
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options,
|
|
63
|
+
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options, permissionProcessor);
|
|
63
64
|
}
|
|
64
65
|
else {
|
|
65
66
|
// No remaining path — resolve and assign directly to the element
|
|
66
|
-
const resolvedValue = await resolveValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el });
|
|
67
|
+
const resolvedValue = await resolveValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el, permissionProcessor });
|
|
67
68
|
if ('__v' in resolvedValue) {
|
|
68
69
|
// Single value — can't assign to element root without a path
|
|
69
70
|
}
|
|
70
71
|
else {
|
|
71
|
-
assignGingerly(el, resolvedValue, options,
|
|
72
|
+
assignGingerly(el, resolvedValue, options, permissionProcessor);
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -76,12 +77,12 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
76
77
|
// Process handler commands ( =>) — cached after first load to avoid await overhead
|
|
77
78
|
if (handlerKeys.length > 0) {
|
|
78
79
|
_processHandlerCommands ??= (await import('./processHandlerCommands.js')).processHandlerCommands;
|
|
79
|
-
await _processHandlerCommands(target, handlerKeys, expandedPattern, options,
|
|
80
|
+
await _processHandlerCommands(target, handlerKeys, expandedPattern, options, permissionProcessor);
|
|
80
81
|
}
|
|
81
82
|
// Process #[x] handler keys — resolve element, then pass to handler processing
|
|
82
83
|
if (idRefHandlerKeys.length > 0 && (options.pin || options.at)) {
|
|
83
84
|
const ids = { ...options.pin, ...options.at };
|
|
84
|
-
const { resolveIdVariable, parseIdRef } = await import('./resolveIdRef.js');
|
|
85
|
+
const { resolveIdVariable, parseIdRef } = await import('./resolve/resolveIdRef.js');
|
|
85
86
|
_processHandlerCommands ??= (await import('./processHandlerCommands.js')).processHandlerCommands;
|
|
86
87
|
for (const key of idRefHandlerKeys) {
|
|
87
88
|
const parsed = parseIdRef(key);
|
|
@@ -98,7 +99,7 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
98
99
|
const syntheticPattern = {
|
|
99
100
|
[syntheticKey]: expandedPattern[key]
|
|
100
101
|
};
|
|
101
|
-
await _processHandlerCommands(el, [syntheticKey], syntheticPattern, options,
|
|
102
|
+
await _processHandlerCommands(el, [syntheticKey], syntheticPattern, options, permissionProcessor);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
// Process inferred assignments — dynamically imported only when option is present
|
|
@@ -117,7 +118,7 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
117
118
|
// Process bulk enhancements — dynamically imported only when option is present
|
|
118
119
|
if (options.enhance && options.enhance.length > 0) {
|
|
119
120
|
const { enhanceAll } = await import('./enhanceAll.js');
|
|
120
|
-
await enhanceAll(target, options.enhance,
|
|
121
|
+
await enhanceAll(target, options.enhance, permissionProcessor);
|
|
121
122
|
}
|
|
122
123
|
return target;
|
|
123
124
|
}
|