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.
@@ -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?: any;
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
 
@@ -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
- }
@@ -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
- }