assign-gingerly 0.0.72 → 0.0.74
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 +29 -92
- package/assignFeatures.js +145 -254
- package/assignFeatures.ts +713 -837
- package/assignFrom.ts +1 -1
- package/assignFromAsync.ts +1 -1
- package/assignGingerly.js +1 -1
- package/assignGingerly.ts +3 -2
- package/assignPermissions/isAllowedImportPath.js +41 -0
- package/assignPermissions/isAllowedImportPath.ts +38 -0
- package/assignPermissions/restrictedProps.js +43 -0
- package/assignPermissions/restrictedProps.ts +53 -0
- package/assignTentatively.js +1 -1
- package/assignTentatively.ts +2 -2
- package/defineWithFeatures.js +12 -72
- package/defineWithFeatures.ts +92 -167
- package/eachTime.js +1 -1
- package/eachTime.ts +3 -2
- package/enhanceAll.js +10 -6
- package/enhanceAll.ts +11 -10
- package/handlers/addEventListener.ts +1 -1
- package/handlers/lazyLoad.ts +1 -1
- package/handlers/lazyLoadSwitch.ts +1 -1
- package/handlers/manageTemplateList.ts +1 -1
- package/handlers/rangeSelector.ts +1 -1
- package/inferencer/types/assign-gingerly/types.d.ts +5 -2
- package/inferencer/types/font-face-feature/types.d.ts +9 -0
- package/inferencer/types/nested-regex-groups/types.d.ts +12 -0
- package/package.json +13 -4
- package/processHandlerCommands.js +12 -34
- package/processHandlerCommands.ts +15 -41
- package/resolveAndAssignFeatures.js +9 -40
- package/resolveAndAssignFeatures.ts +43 -79
- package/types/assign-gingerly/types.d.ts +13 -25
- package/isAllowedImportPath.js +0 -104
- package/isAllowedImportPath.ts +0 -118
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {ParserOptions} from '../nested-regex-groups/types.js';
|
|
2
|
+
|
|
1
3
|
export type EnhKey = string | symbol;
|
|
2
4
|
|
|
3
5
|
// type NoUnderscore<T extends string> = T extends `_${string}` ? never : T;
|
|
@@ -196,7 +198,7 @@ export interface AttrConfig<T = unknown, TParserConfig = unknown> {
|
|
|
196
198
|
* For named parsers like 'parse-pattern-statements', this is forwarded
|
|
197
199
|
* as the options argument to the underlying parse function.
|
|
198
200
|
*/
|
|
199
|
-
parserOptions?:
|
|
201
|
+
parserOptions?: ParserOptions;
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
export type AttrPatterns<T = any> = {
|
|
@@ -589,21 +591,6 @@ export interface SupportedFeatureConfig {
|
|
|
589
591
|
callbackForwarding?: string[];
|
|
590
592
|
}
|
|
591
593
|
|
|
592
|
-
/**
|
|
593
|
-
* Class-level configuration for the features system.
|
|
594
|
-
* Declared as `static featuresConfig` on the class.
|
|
595
|
-
*/
|
|
596
|
-
export interface FeaturesClassConfig {
|
|
597
|
-
/**
|
|
598
|
-
* Lifecycle method configuration.
|
|
599
|
-
* true = install 'whenFeatureReady' method.
|
|
600
|
-
* Object = custom method name.
|
|
601
|
-
*/
|
|
602
|
-
lifecycleKeys?: true | {
|
|
603
|
-
whenFeatureReady?: string;
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
|
|
607
594
|
/**
|
|
608
595
|
* Configuration for a feature passed to assignFeatures.
|
|
609
596
|
*/
|
|
@@ -613,7 +600,8 @@ export interface FeatureConfig {
|
|
|
613
600
|
*/
|
|
614
601
|
spawn?:
|
|
615
602
|
| { new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }
|
|
616
|
-
| (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>)
|
|
603
|
+
| (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>)
|
|
604
|
+
| string // import path or builtIns.* alias
|
|
617
605
|
|
|
618
606
|
/** Attribute patterns for parsing element attributes into initVals. */
|
|
619
607
|
withAttrs?: AttrPatterns<any>;
|
|
@@ -706,8 +694,8 @@ export interface HandlerConfig {
|
|
|
706
694
|
* Interface for assignFrom handler classes.
|
|
707
695
|
* Handlers are invoked when a LHS key ends with ' =>'.
|
|
708
696
|
*/
|
|
709
|
-
export interface AssignFromHandler {
|
|
710
|
-
assign(lhsTarget: any, resolvedParams: Record<string, any>, options: any, permissions?: AssignPermissions): Promise<void> | void;
|
|
697
|
+
export interface AssignFromHandler {
|
|
698
|
+
assign(lhsTarget: any, resolvedParams: Record<string, any>, options: any, permissions?: AssignPermissions): Promise<void> | void;
|
|
711
699
|
}
|
|
712
700
|
|
|
713
701
|
/**
|
|
@@ -885,7 +873,7 @@ export interface LazyLoadInstantiatedContext {
|
|
|
885
873
|
export declare class LazyLoadHandler implements AssignFromHandler {
|
|
886
874
|
config: any;
|
|
887
875
|
constructor(config: any);
|
|
888
|
-
assign(lhsTarget: any, resolvedParams: Record<string, any>, options?: any, permissions?: AssignPermissions): Promise<void>;
|
|
876
|
+
assign(lhsTarget: any, resolvedParams: Record<string, any>, options?: any, permissions?: AssignPermissions): Promise<void>;
|
|
889
877
|
protected onCloneInserted(nodes: Node[], lhsTarget: Element, resolvedParams: Record<string, any>): Promise<void>;
|
|
890
878
|
}
|
|
891
879
|
|
|
@@ -969,12 +957,12 @@ export interface AssignPermissions {
|
|
|
969
957
|
/**
|
|
970
958
|
* Restricted property settings.
|
|
971
959
|
* Phase I: string entries are property names that cannot be assigned.
|
|
972
|
-
* Phase II: an object with useMethod redirects ordinary assignment to that
|
|
973
|
-
* method; command operations remain blocked. Phase III+ adds attr support.
|
|
960
|
+
* Phase II: an object with useMethod redirects ordinary assignment to that
|
|
961
|
+
* method; command operations remain blocked. Phase III+ adds attr support.
|
|
974
962
|
*
|
|
975
|
-
* NOTE: This is a property-assignment guard only. Method calls (setAttribute, etc.)
|
|
976
|
-
* are not blocked — see Phase III+. Event listeners can still be registered, but
|
|
977
|
-
* assignments performed by their vectors inherit these permissions.
|
|
963
|
+
* NOTE: This is a property-assignment guard only. Method calls (setAttribute, etc.)
|
|
964
|
+
* are not blocked — see Phase III+. Event listeners can still be registered, but
|
|
965
|
+
* assignments performed by their vectors inherit these permissions.
|
|
978
966
|
*/
|
|
979
967
|
restrictedPropSettings?: Array<string | RestrictedPropSetting>;
|
|
980
968
|
|
package/isAllowedImportPath.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
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
|
-
* Module-level warn dedup — one warning per property key per process lifetime.
|
|
20
|
-
*/
|
|
21
|
-
const warnedOnce = new Set();
|
|
22
|
-
/**
|
|
23
|
-
* Warn once per key that a restricted property assignment was skipped.
|
|
24
|
-
*/
|
|
25
|
-
function warnRestricted(key) {
|
|
26
|
-
if (!warnedOnce.has(key)) {
|
|
27
|
-
warnedOnce.add(key);
|
|
28
|
-
console.warn(`assignGingerly: property '${key}' is in restrictedPropSettings — assignment skipped.`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Normalize the restrictedPropSettings from permissions into a fast-lookup Set.
|
|
33
|
-
* Phase I: extracts string entries only (object entries are Phase II+).
|
|
34
|
-
* Returns undefined when nothing is restricted (fast-bail in callers).
|
|
35
|
-
*/
|
|
36
|
-
export function buildRestrictedPropSet(permissions) {
|
|
37
|
-
const settings = permissions?.restrictedPropSettings;
|
|
38
|
-
if (!settings || settings.length === 0)
|
|
39
|
-
return undefined;
|
|
40
|
-
const restrictedPropSet = new Map();
|
|
41
|
-
for (const setting of settings) {
|
|
42
|
-
const prop = typeof setting === 'string' ? setting : setting.prop;
|
|
43
|
-
if (restrictedPropSet.has(prop)) {
|
|
44
|
-
throw new Error(`assignGingerly: duplicate restrictedPropSettings entry for '${prop}'.`);
|
|
45
|
-
}
|
|
46
|
-
restrictedPropSet.set(prop, typeof setting === 'string' ? undefined : setting);
|
|
47
|
-
}
|
|
48
|
-
return restrictedPropSet;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Check if a property key is restricted. If so, warn (once) and return true.
|
|
52
|
-
* Call sites should `continue` or skip the assignment when this returns true.
|
|
53
|
-
*/
|
|
54
|
-
export function checkRestrictedProp(restrictedPropSet, key) {
|
|
55
|
-
if (!restrictedPropSet || !restrictedPropSet.has(key))
|
|
56
|
-
return false;
|
|
57
|
-
warnRestricted(key);
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Redirect an ordinary assignment through its configured safe method.
|
|
62
|
-
* Returns true when the property is restricted, whether redirected or skipped.
|
|
63
|
-
*/
|
|
64
|
-
export function redirectRestrictedProp(restrictedPropSet, target, key, value) {
|
|
65
|
-
if (!restrictedPropSet || !restrictedPropSet.has(key))
|
|
66
|
-
return false;
|
|
67
|
-
const setting = restrictedPropSet.get(key);
|
|
68
|
-
if (!setting?.useMethod) {
|
|
69
|
-
warnRestricted(key);
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
const method = target?.[setting.useMethod];
|
|
73
|
-
if (typeof method !== 'function') {
|
|
74
|
-
warnRestricted(key);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
method.call(target, value);
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Check if an import path is allowed (non-cross-domain).
|
|
82
|
-
*
|
|
83
|
-
* Allowed:
|
|
84
|
-
* - Relative paths: ./foo.js, ../bar.js
|
|
85
|
-
* - Absolute paths: /path/to/file.js
|
|
86
|
-
* - Bare specifiers: package-name/file.js, @scope/package/file.js
|
|
87
|
-
*
|
|
88
|
-
* Blocked:
|
|
89
|
-
* - Protocol URLs: https://..., http://..., data:..., etc.
|
|
90
|
-
* - Protocol-relative: //cdn.example.com/...
|
|
91
|
-
*
|
|
92
|
-
* @param path - The import path to validate
|
|
93
|
-
* @returns true if the path is local/safe, false if cross-domain
|
|
94
|
-
*/
|
|
95
|
-
export function isAllowedImportPath(path) {
|
|
96
|
-
if (path.startsWith('./') || path.startsWith('../') || path.startsWith('/')) {
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
if (path.includes('://') || path.startsWith('//')) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
// Bare specifier (no protocol, no //) — allowed
|
|
103
|
-
return true;
|
|
104
|
-
}
|
package/isAllowedImportPath.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
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
|
-
// Re-export AssignPermissions from canonical location for backwards compatibility
|
|
20
|
-
export type { AssignPermissions } from './types/assign-gingerly/types.js';
|
|
21
|
-
import type { AssignPermissions, RestrictedPropSetting } from './types/assign-gingerly/types.js';
|
|
22
|
-
|
|
23
|
-
export type RestrictedPropSettingsMap = Map<string, RestrictedPropSetting | undefined>;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Module-level warn dedup — one warning per property key per process lifetime.
|
|
27
|
-
*/
|
|
28
|
-
const warnedOnce = new Set<string>();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Warn once per key that a restricted property assignment was skipped.
|
|
32
|
-
*/
|
|
33
|
-
function warnRestricted(key: string): void {
|
|
34
|
-
if (!warnedOnce.has(key)) {
|
|
35
|
-
warnedOnce.add(key);
|
|
36
|
-
console.warn(`assignGingerly: property '${key}' is in restrictedPropSettings — assignment skipped.`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Normalize the restrictedPropSettings from permissions into a fast-lookup Set.
|
|
42
|
-
* Phase I: extracts string entries only (object entries are Phase II+).
|
|
43
|
-
* Returns undefined when nothing is restricted (fast-bail in callers).
|
|
44
|
-
*/
|
|
45
|
-
export function buildRestrictedPropSet(permissions: AssignPermissions | undefined): RestrictedPropSettingsMap | undefined {
|
|
46
|
-
const settings = permissions?.restrictedPropSettings;
|
|
47
|
-
if (!settings || settings.length === 0) return undefined;
|
|
48
|
-
const restrictedPropSet: RestrictedPropSettingsMap = new Map();
|
|
49
|
-
for (const setting of settings) {
|
|
50
|
-
const prop = typeof setting === 'string' ? setting : setting.prop;
|
|
51
|
-
if (restrictedPropSet.has(prop)) {
|
|
52
|
-
throw new Error(`assignGingerly: duplicate restrictedPropSettings entry for '${prop}'.`);
|
|
53
|
-
}
|
|
54
|
-
restrictedPropSet.set(prop, typeof setting === 'string' ? undefined : setting);
|
|
55
|
-
}
|
|
56
|
-
return restrictedPropSet;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Check if a property key is restricted. If so, warn (once) and return true.
|
|
61
|
-
* Call sites should `continue` or skip the assignment when this returns true.
|
|
62
|
-
*/
|
|
63
|
-
export function checkRestrictedProp(restrictedPropSet: RestrictedPropSettingsMap | undefined, key: string): boolean {
|
|
64
|
-
if (!restrictedPropSet || !restrictedPropSet.has(key)) return false;
|
|
65
|
-
warnRestricted(key);
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Redirect an ordinary assignment through its configured safe method.
|
|
71
|
-
* Returns true when the property is restricted, whether redirected or skipped.
|
|
72
|
-
*/
|
|
73
|
-
export function redirectRestrictedProp(
|
|
74
|
-
restrictedPropSet: RestrictedPropSettingsMap | undefined,
|
|
75
|
-
target: any,
|
|
76
|
-
key: string,
|
|
77
|
-
value: any
|
|
78
|
-
): boolean {
|
|
79
|
-
if (!restrictedPropSet || !restrictedPropSet.has(key)) return false;
|
|
80
|
-
const setting = restrictedPropSet.get(key);
|
|
81
|
-
if (!setting?.useMethod) {
|
|
82
|
-
warnRestricted(key);
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
const method = target?.[setting.useMethod];
|
|
86
|
-
if (typeof method !== 'function') {
|
|
87
|
-
warnRestricted(key);
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
method.call(target, value);
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Check if an import path is allowed (non-cross-domain).
|
|
96
|
-
*
|
|
97
|
-
* Allowed:
|
|
98
|
-
* - Relative paths: ./foo.js, ../bar.js
|
|
99
|
-
* - Absolute paths: /path/to/file.js
|
|
100
|
-
* - Bare specifiers: package-name/file.js, @scope/package/file.js
|
|
101
|
-
*
|
|
102
|
-
* Blocked:
|
|
103
|
-
* - Protocol URLs: https://..., http://..., data:..., etc.
|
|
104
|
-
* - Protocol-relative: //cdn.example.com/...
|
|
105
|
-
*
|
|
106
|
-
* @param path - The import path to validate
|
|
107
|
-
* @returns true if the path is local/safe, false if cross-domain
|
|
108
|
-
*/
|
|
109
|
-
export function isAllowedImportPath(path: string): boolean {
|
|
110
|
-
if (path.startsWith('./') || path.startsWith('../') || path.startsWith('/')) {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
if (path.includes('://') || path.startsWith('//')) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
// Bare specifier (no protocol, no //) — allowed
|
|
117
|
-
return true;
|
|
118
|
-
}
|