@whenessel/seql-js 1.4.0 → 1.6.0

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 CHANGED
@@ -146,6 +146,30 @@ Manage the LRU cache to improve performance for frequent generations/resolutions
146
146
  - `src/resolver/`: Logic for resolving EID JSON back to DOM elements.
147
147
  - `src/types/`: Core type definitions for EIDs, Semantics, and Constraints.
148
148
  - `src/utils/`: Shared utilities, constants, and scoring algorithms.
149
+ - `extensions/chrome/`: Chrome DevTools extension for visual SEQL inspection.
150
+
151
+ ## Developer Tools
152
+
153
+ ### Chrome DevTools Extension
154
+
155
+ The SEQL Inspector extension provides visual tooling for working with SEQL selectors directly in Chrome DevTools.
156
+
157
+ **Features:**
158
+
159
+ - Generate SEQL selectors for all elements or pick individual elements
160
+ - Full iframe support with automatic detection and context switching
161
+ - Live search and resolution testing
162
+ - Interactive element highlighting and inspection
163
+ - Tree view with grouping and filtering
164
+
165
+ **Installation:**
166
+
167
+ ```bash
168
+ yarn extension:prepare
169
+ # Then load extensions/chrome/ as unpacked extension in Chrome
170
+ ```
171
+
172
+ See [Chrome Extension README](extensions/chrome/README.md) for detailed documentation.
149
173
 
150
174
  ## Scripts
151
175
 
@@ -154,6 +178,7 @@ Manage the LRU cache to improve performance for frequent generations/resolutions
154
178
  - `yarn test:watch`: Run tests in watch mode.
155
179
  - `yarn test:coverage`: Run tests with coverage report.
156
180
  - `yarn types:check`: Run TypeScript type checking.
181
+ - `yarn extension:prepare`: Build library and prepare Chrome extension.
157
182
  - `npx vitest <path>`: Run a specific test file.
158
183
 
159
184
  ## Documentation
package/dist/seql-js.d.ts CHANGED
@@ -452,12 +452,12 @@ export declare class CssGenerator {
452
452
  * div with utility classes) can still be identified using positional information
453
453
  * (nthChild).
454
454
  */
455
- export declare const DEFAULT_GENERATOR_OPTIONS: Omit<Required<GeneratorOptions>, 'cache'> & Pick<GeneratorOptions, 'cache'>;
455
+ export declare const DEFAULT_GENERATOR_OPTIONS: Omit<Required<GeneratorOptions>, 'cache' | 'root'> & Pick<GeneratorOptions, 'cache' | 'root'>;
456
456
 
457
457
  /**
458
458
  * Default resolver options
459
459
  */
460
- export declare const DEFAULT_RESOLVER_OPTIONS: Required<ResolverOptions>;
460
+ export declare const DEFAULT_RESOLVER_OPTIONS: Omit<Required<ResolverOptions>, 'root' | 'documentUrl'> & Pick<ResolverOptions, 'root' | 'documentUrl'>;
461
461
 
462
462
  /**
463
463
  * EID specification version
@@ -744,6 +744,21 @@ export declare interface GeneratorOptions {
744
744
  source?: string;
745
745
  /** Optional cache instance for performance optimization */
746
746
  cache?: EIDCache;
747
+ /**
748
+ * Root element or document for validation (optional).
749
+ *
750
+ * ⚠️ IMPORTANT: When working with iframes, pass iframe.contentDocument
751
+ * to ensure cross-document validation works correctly.
752
+ *
753
+ * @example
754
+ * // Main document
755
+ * generateEID(element, { root: document });
756
+ *
757
+ * // Iframe content
758
+ * const iframe = document.querySelector('iframe');
759
+ * generateEID(iframeElement, { root: iframe.contentDocument });
760
+ */
761
+ root?: Document | Element;
747
762
  }
748
763
 
749
764
  /**
@@ -948,7 +963,7 @@ export declare interface ResolveResult {
948
963
  /** Metadata about resolution */
949
964
  meta: {
950
965
  degraded: boolean;
951
- degradationReason?: string;
966
+ degradationReason?: 'not-found' | 'strict-not-found' | 'ambiguous' | 'anchor-fallback' | 'anchor-not-found' | 'first-of-multiple' | 'best-of-multiple' | 'multiple-matches' | 'over-constrained' | 'relaxed-text-matching' | 'invalid-context' | 'invalid-selector' | 'invalid-anchor-selector';
952
967
  };
953
968
  }
954
969
 
@@ -963,6 +978,63 @@ export declare interface ResolverOptions {
963
978
  enableFallback?: boolean;
964
979
  /** Maximum candidates to consider (default: 20) */
965
980
  maxCandidates?: number;
981
+ /**
982
+ * Root element or document for CSS queries.
983
+ *
984
+ * ⚠️ IMPORTANT: When working with iframes, you MUST pass iframe.contentDocument
985
+ * as the root parameter. Otherwise, resolution will fail or return incorrect elements.
986
+ *
987
+ * @example
988
+ * // Main document
989
+ * resolve(eid, document, { root: document });
990
+ *
991
+ * // Iframe content
992
+ * const iframe = document.querySelector('iframe');
993
+ * resolve(eid, iframe.contentDocument, { root: iframe.contentDocument });
994
+ */
995
+ root?: Document | Element;
996
+ /**
997
+ * Document base URL for URL normalization.
998
+ * Used when comparing href/src attributes to provide correct origin context.
999
+ *
1000
+ * ⚠️ IMPORTANT: When working with iframes, this should match iframe.contentWindow.location.href
1001
+ * to ensure correct same-origin detection.
1002
+ *
1003
+ * If not provided, falls back to root.defaultView?.location?.href or window.location.href.
1004
+ *
1005
+ * @example
1006
+ * // Iframe context
1007
+ * const iframe = document.querySelector('iframe');
1008
+ * resolve(eid, iframe.contentDocument, {
1009
+ * root: iframe.contentDocument,
1010
+ * documentUrl: iframe.contentWindow.location.href
1011
+ * });
1012
+ *
1013
+ * @example
1014
+ * // Manual override for testing
1015
+ * resolve(eid, document, {
1016
+ * documentUrl: 'https://example.com'
1017
+ * });
1018
+ */
1019
+ documentUrl?: string;
1020
+ /**
1021
+ * Match URLs by pathname only, ignoring origin differences.
1022
+ * Useful for cross-origin rrweb replay scenarios (e.g., localhost dev with production links).
1023
+ *
1024
+ * When enabled (default):
1025
+ * - /booking matches https://any-origin.com/booking
1026
+ * - Ignores protocol and domain differences
1027
+ * - Compares only pathname (+ search + hash if present)
1028
+ * - Recommended for rrweb replay and development environments
1029
+ *
1030
+ * When disabled:
1031
+ * - Full URL normalization with same-origin detection
1032
+ * - Cross-origin URLs preserved as absolute
1033
+ * - More strict origin validation
1034
+ *
1035
+ * @default true
1036
+ */
1037
+ matchUrlsByPathOnly?: boolean;
966
1038
  }
967
1039
 
968
1040
  /**
@@ -985,6 +1057,21 @@ export declare interface ResolverOptions {
985
1057
  * highlightElement(elements[0]);
986
1058
  * }
987
1059
  * ```
1060
+ *
1061
+ * @example
1062
+ * ```typescript
1063
+ * // Working with iframes - pass iframe.contentDocument as both root and in options
1064
+ * const iframe = document.querySelector('iframe');
1065
+ * const iframeDoc = iframe.contentDocument;
1066
+ * const selector = "v1: form#payment :: input[name=cardnumber]";
1067
+ *
1068
+ * // IMPORTANT: Pass contentDocument as root in options for correct resolution
1069
+ * const elements = resolveSEQL(selector, iframeDoc, { root: iframeDoc });
1070
+ *
1071
+ * if (elements.length > 0) {
1072
+ * console.log('Found payment input in iframe:', elements[0]);
1073
+ * }
1074
+ * ```
988
1075
  */
989
1076
  export declare function resolveSEQL(selector: string, root: Document | Element, options?: ResolverOptions): Element[];
990
1077
 
@@ -1083,11 +1170,15 @@ export declare class SemanticsMatcher {
1083
1170
  * Filters elements that match the semantics
1084
1171
  * @param elements - Candidate elements
1085
1172
  * @param semantics - Target semantics to match
1173
+ * @param documentUrl - Optional document base URL for URL normalization (iframe context)
1174
+ * @param matchUrlsByPathOnly - Optional flag to match URLs by pathname only (ignoring origin)
1086
1175
  * @returns Filtered elements that match
1087
1176
  */
1088
- match(elements: Element[], semantics: ElementSemantics): Element[];
1177
+ match(elements: Element[], semantics: ElementSemantics, documentUrl?: string, matchUrlsByPathOnly?: boolean): Element[];
1089
1178
  /**
1090
1179
  * Checks if a single element matches the semantics
1180
+ * @param documentUrl - Optional document base URL for URL normalization (iframe context)
1181
+ * @param matchUrlsByPathOnly - Optional flag to match URLs by pathname only (ignoring origin)
1091
1182
  */
1092
1183
  private matchElement;
1093
1184
  /**
@@ -1096,9 +1187,28 @@ export declare class SemanticsMatcher {
1096
1187
  */
1097
1188
  matchText(element: Element, text: TextContent): boolean;
1098
1189
  /**
1099
- * Matches attributes
1190
+ * Lenient text matching - uses partial matching instead of exact
1191
+ * Used as fallback when exact matching fails
1192
+ */
1193
+ private matchTextLenient;
1194
+ /**
1195
+ * Checks if a single element matches the semantics with lenient text matching
1196
+ * @param documentUrl - Optional document base URL for URL normalization (iframe context)
1197
+ * @param matchUrlsByPathOnly - Optional flag to match URLs by pathname only (ignoring origin)
1198
+ */
1199
+ private matchElementLenient;
1200
+ /**
1201
+ * Filters elements with lenient matching (exported for use in resolver)
1202
+ * @param documentUrl - Optional document base URL for URL normalization (iframe context)
1203
+ * @param matchUrlsByPathOnly - Optional flag to match URLs by pathname only (ignoring origin)
1204
+ */
1205
+ matchLenient(elements: Element[], semantics: ElementSemantics, documentUrl?: string, matchUrlsByPathOnly?: boolean): Element[];
1206
+ /**
1207
+ * Matches attributes with URL normalization for href/src
1208
+ * @param documentUrl - Optional document base URL for URL normalization (iframe context)
1209
+ * @param matchUrlsByPathOnly - Optional flag to match URLs by pathname only (ignoring origin, default: true)
1100
1210
  */
1101
- matchAttributes(element: Element, attrs: Record<string, string>): boolean;
1211
+ matchAttributes(element: Element, attrs: Record<string, string>, documentUrl?: string, matchUrlsByPathOnly?: boolean): boolean;
1102
1212
  /**
1103
1213
  * Matches SVG fingerprint
1104
1214
  */