@decantr/verifier 2.5.1 → 3.0.0-next.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/dist/index.js CHANGED
@@ -1,15 +1,353 @@
1
1
  // src/index.ts
2
2
  import { createHash } from "crypto";
3
- import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync3, realpathSync, statSync as statSync3 } from "fs";
3
+ import { existsSync as existsSync4, readdirSync as readdirSync4, readFileSync as readFileSync5, realpathSync, statSync as statSync3 } from "fs";
4
4
  import { readFile } from "fs/promises";
5
- import { basename, dirname, extname as extname3, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve } from "path";
5
+ import { basename as basename2, dirname, extname as extname4, isAbsolute as isAbsolute2, join as join4, relative as relative4, resolve } from "path";
6
6
  import { evaluateGuard, isV4, validateEssence } from "@decantr/essence-spec";
7
+ import * as ts3 from "typescript";
8
+
9
+ // src/component-reuse.ts
10
+ import { readFileSync } from "fs";
11
+ import { basename, extname, relative } from "path";
7
12
  import * as ts from "typescript";
13
+ var COMPONENT_REUSE_RULE_ID = "component-reuse-primitive-reimplemented";
14
+ var RAW_CONTROL_REUSE_RULE_ID = "component-reuse-raw-control";
15
+ var PRIMITIVE_COMPONENT_NAMES = /* @__PURE__ */ new Set([
16
+ "Accordion",
17
+ "Alert",
18
+ "Avatar",
19
+ "Badge",
20
+ "Breadcrumb",
21
+ "Button",
22
+ "Calendar",
23
+ "Card",
24
+ "Chart",
25
+ "Checkbox",
26
+ "Combobox",
27
+ "Command",
28
+ "DataTable",
29
+ "DatePicker",
30
+ "Dialog",
31
+ "Drawer",
32
+ "DropdownMenu",
33
+ "EmptyState",
34
+ "ErrorState",
35
+ "Field",
36
+ "Footer",
37
+ "Form",
38
+ "Header",
39
+ "Heading",
40
+ "Icon",
41
+ "Input",
42
+ "Kpi",
43
+ "Label",
44
+ "Link",
45
+ "Metric",
46
+ "Modal",
47
+ "Nav",
48
+ "Popover",
49
+ "Radio",
50
+ "Search",
51
+ "Select",
52
+ "Sheet",
53
+ "Sidebar",
54
+ "Skeleton",
55
+ "Spinner",
56
+ "Switch",
57
+ "Table",
58
+ "Tabs",
59
+ "Textarea",
60
+ "Toast",
61
+ "Toggle",
62
+ "Tooltip"
63
+ ]);
64
+ var RAW_CONTROL_COMPONENT_BY_ELEMENT = {
65
+ button: "Button",
66
+ dialog: "Dialog",
67
+ input: "Input",
68
+ select: "Select",
69
+ table: "Table",
70
+ textarea: "Textarea"
71
+ };
72
+ function normalizePath(path) {
73
+ return path.replace(/\\/g, "/");
74
+ }
75
+ function isPrimitiveComponentName(name) {
76
+ return PRIMITIVE_COMPONENT_NAMES.has(name);
77
+ }
78
+ function isComponentName(name) {
79
+ return /^[A-Z][A-Za-z0-9]*$/.test(name);
80
+ }
81
+ function hasExportModifier(node) {
82
+ return Boolean(
83
+ ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)
84
+ );
85
+ }
86
+ function containsJsx(node) {
87
+ let found = false;
88
+ const visit = (child) => {
89
+ if (found) return;
90
+ if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child) || ts.isJsxFragment(child) || ts.isJsxOpeningElement(child)) {
91
+ found = true;
92
+ return;
93
+ }
94
+ ts.forEachChild(child, visit);
95
+ };
96
+ ts.forEachChild(node, visit);
97
+ return found;
98
+ }
99
+ function classExtendsReactComponent(node) {
100
+ return node.heritageClauses?.some(
101
+ (clause) => clause.types.some((type) => {
102
+ const text = type.expression.getText();
103
+ return /(?:^|\.)(?:Component|PureComponent)$/.test(text);
104
+ })
105
+ ) ?? false;
106
+ }
107
+ function lineForNode(sourceFile, node) {
108
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
109
+ }
110
+ function jsxIdentifierName(name) {
111
+ return ts.isIdentifier(name) ? name.text : null;
112
+ }
113
+ function jsxAttributeStringValue(node, attributeName) {
114
+ for (const property of node.attributes.properties) {
115
+ if (!ts.isJsxAttribute(property) || !ts.isIdentifier(property.name) || property.name.text !== attributeName) {
116
+ continue;
117
+ }
118
+ if (!property.initializer) return "";
119
+ if (ts.isStringLiteral(property.initializer)) return property.initializer.text;
120
+ }
121
+ return null;
122
+ }
123
+ function isHiddenInput(node) {
124
+ const tagName = jsxIdentifierName(node.tagName);
125
+ if (tagName !== "input") return false;
126
+ return jsxAttributeStringValue(node, "type")?.toLowerCase() === "hidden";
127
+ }
128
+ function isReusableComponentPath(file, name) {
129
+ const normalized = normalizePath(file);
130
+ const extension = extname(normalized);
131
+ const base = basename(normalized, extension).toLowerCase();
132
+ const componentName = name.toLowerCase();
133
+ return /(?:^|\/)(?:components|ui|shared|primitives|design-system|common)(?:\/|$)/i.test(normalized) || base === componentName && !/(?:^|\/)(?:app|pages|routes)(?:\/|$)/i.test(normalized) && !/(?:^|\/)(?:page|layout|route|loading|error|not-found)\.[cm]?[jt]sx?$/i.test(normalized);
134
+ }
135
+ function collectImports(sourceFile, file) {
136
+ const imports = /* @__PURE__ */ new Set();
137
+ const references = [];
138
+ for (const statement of sourceFile.statements) {
139
+ if (!ts.isImportDeclaration(statement)) continue;
140
+ const clause = statement.importClause;
141
+ const moduleSpecifier = statement.moduleSpecifier;
142
+ if (!ts.isStringLiteral(moduleSpecifier)) continue;
143
+ const defaultImport = clause?.name?.text;
144
+ const imported = [];
145
+ const localNames = [];
146
+ let namespaceImport;
147
+ if (!clause) continue;
148
+ if (clause.name) {
149
+ imports.add(clause.name.text);
150
+ localNames.push(clause.name.text);
151
+ }
152
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
153
+ for (const element of clause.namedBindings.elements) {
154
+ imports.add(element.name.text);
155
+ localNames.push(element.name.text);
156
+ imported.push((element.propertyName ?? element.name).text);
157
+ }
158
+ } else if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
159
+ namespaceImport = clause.namedBindings.name.text;
160
+ imports.add(namespaceImport);
161
+ localNames.push(namespaceImport);
162
+ }
163
+ references.push({
164
+ file,
165
+ source: moduleSpecifier.text,
166
+ line: lineForNode(sourceFile, statement),
167
+ ...defaultImport ? { defaultImport } : {},
168
+ ...namespaceImport ? { namespaceImport } : {},
169
+ imported,
170
+ localNames
171
+ });
172
+ }
173
+ return { names: imports, references };
174
+ }
175
+ function collectDeclarations(sourceFile, file) {
176
+ const declarations = [];
177
+ const addDeclaration = (node, name, exported, kind) => {
178
+ if (!isComponentName(name) || !containsJsx(node)) return;
179
+ declarations.push({
180
+ id: `cmp:${file}:${name}`,
181
+ name,
182
+ file,
183
+ line: lineForNode(sourceFile, node),
184
+ exported,
185
+ reusable: exported && isReusableComponentPath(file, name),
186
+ kind
187
+ });
188
+ };
189
+ const visit = (node) => {
190
+ if (ts.isFunctionDeclaration(node) && node.name) {
191
+ addDeclaration(node, node.name.text, hasExportModifier(node), "function");
192
+ } else if (ts.isClassDeclaration(node) && node.name && classExtendsReactComponent(node)) {
193
+ addDeclaration(node, node.name.text, hasExportModifier(node), "class");
194
+ } else if (ts.isVariableStatement(node)) {
195
+ const exported = hasExportModifier(node);
196
+ for (const declaration of node.declarationList.declarations) {
197
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
198
+ addDeclaration(declaration, declaration.name.text, exported, "variable");
199
+ }
200
+ }
201
+ ts.forEachChild(node, visit);
202
+ };
203
+ ts.forEachChild(sourceFile, visit);
204
+ return declarations;
205
+ }
206
+ function componentDeclarationName(node) {
207
+ if (ts.isFunctionDeclaration(node) && node.name && isComponentName(node.name.text)) {
208
+ return containsJsx(node) ? node.name.text : null;
209
+ }
210
+ if (ts.isClassDeclaration(node) && node.name && isComponentName(node.name.text) && classExtendsReactComponent(node)) {
211
+ return node.name.text;
212
+ }
213
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && isComponentName(node.name.text)) {
214
+ return node.initializer && containsJsx(node) ? node.name.text : null;
215
+ }
216
+ return null;
217
+ }
218
+ function collectRawControls(sourceFile, file) {
219
+ const rawControls = [];
220
+ const visit = (node, containingComponent) => {
221
+ const nextComponent = componentDeclarationName(node) ?? containingComponent;
222
+ if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
223
+ const tagName = jsxIdentifierName(node.tagName);
224
+ const component = tagName && Object.hasOwn(RAW_CONTROL_COMPONENT_BY_ELEMENT, tagName) ? RAW_CONTROL_COMPONENT_BY_ELEMENT[tagName] : null;
225
+ if (component && !isHiddenInput(node)) {
226
+ rawControls.push({
227
+ element: tagName,
228
+ component,
229
+ file,
230
+ line: lineForNode(sourceFile, node),
231
+ ...nextComponent ? { containingComponent: nextComponent } : {}
232
+ });
233
+ }
234
+ }
235
+ ts.forEachChild(node, (child) => visit(child, nextComponent));
236
+ };
237
+ ts.forEachChild(sourceFile, (node) => visit(node));
238
+ return rawControls;
239
+ }
240
+ function parseComponentFile(projectRoot, absolutePath) {
241
+ const file = normalizePath(relative(projectRoot, absolutePath) || absolutePath);
242
+ if (isNonProductionComponentAuditFile(file)) {
243
+ return null;
244
+ }
245
+ let code = "";
246
+ try {
247
+ code = readFileSync(absolutePath, "utf-8");
248
+ } catch {
249
+ return null;
250
+ }
251
+ const sourceFile = ts.createSourceFile(
252
+ file,
253
+ code,
254
+ ts.ScriptTarget.Latest,
255
+ true,
256
+ /\.[cm]?[jt]sx$/i.test(file) ? ts.ScriptKind.TSX : ts.ScriptKind.TS
257
+ );
258
+ const imports = collectImports(sourceFile, file);
259
+ return {
260
+ file,
261
+ imports: imports.names,
262
+ importReferences: imports.references,
263
+ declarations: collectDeclarations(sourceFile, file),
264
+ rawControls: collectRawControls(sourceFile, file)
265
+ };
266
+ }
267
+ function canonicalSort(a, b) {
268
+ return a.file.localeCompare(b.file) || a.line - b.line || a.name.localeCompare(b.name);
269
+ }
270
+ function isNonProductionComponentAuditFile(file) {
271
+ const normalized = normalizePath(file);
272
+ return /(?:^|\/)(?:__tests__|__mocks__|tests?|specs?|fixtures?|mocks?|stories?)(?:\/|$)/i.test(
273
+ normalized
274
+ ) || /\.(?:test|spec|stories|story|fixture|mock)\.[cm]?[jt]sx?$/i.test(normalized);
275
+ }
276
+ function auditComponentReuse(projectRoot, sourceFiles) {
277
+ const parsedFiles = sourceFiles.map((file) => parseComponentFile(projectRoot, file)).filter((file) => Boolean(file));
278
+ const declarations = parsedFiles.flatMap((file) => file.declarations);
279
+ const reusableByName = /* @__PURE__ */ new Map();
280
+ for (const declaration of declarations) {
281
+ if (!declaration.reusable || !isPrimitiveComponentName(declaration.name)) continue;
282
+ const existing = reusableByName.get(declaration.name) ?? [];
283
+ existing.push(declaration);
284
+ reusableByName.set(declaration.name, existing.sort(canonicalSort));
285
+ }
286
+ const findings = [];
287
+ const rawControlFindings = [];
288
+ for (const parsedFile of parsedFiles) {
289
+ for (const declaration of parsedFile.declarations) {
290
+ if (!isPrimitiveComponentName(declaration.name) || declaration.reusable) continue;
291
+ if (parsedFile.imports.has(declaration.name)) continue;
292
+ const canonical = reusableByName.get(declaration.name)?.filter((entry) => entry.file !== declaration.file).sort(canonicalSort)[0];
293
+ if (!canonical) continue;
294
+ findings.push({
295
+ id: `${COMPONENT_REUSE_RULE_ID}:${declaration.file}:${declaration.name}`,
296
+ name: declaration.name,
297
+ file: declaration.file,
298
+ line: declaration.line,
299
+ canonicalFile: canonical.file,
300
+ canonicalLine: canonical.line,
301
+ evidence: [
302
+ `${declaration.file}:${declaration.line} declares local ${declaration.name}`,
303
+ `${canonical.file}:${canonical.line} already exports reusable ${canonical.name}`
304
+ ]
305
+ });
306
+ }
307
+ const seenRawControls = /* @__PURE__ */ new Set();
308
+ for (const rawControl of parsedFile.rawControls) {
309
+ if (parsedFile.imports.has(rawControl.component)) continue;
310
+ if (rawControl.containingComponent === rawControl.component) continue;
311
+ const canonical = reusableByName.get(rawControl.component)?.filter((entry) => entry.file !== rawControl.file).sort(canonicalSort)[0];
312
+ if (!canonical) continue;
313
+ const key = `${rawControl.file}:${rawControl.component}`;
314
+ if (seenRawControls.has(key)) continue;
315
+ seenRawControls.add(key);
316
+ rawControlFindings.push({
317
+ id: `${RAW_CONTROL_REUSE_RULE_ID}:${rawControl.file}:${rawControl.element}`,
318
+ element: rawControl.element,
319
+ component: rawControl.component,
320
+ file: rawControl.file,
321
+ line: rawControl.line,
322
+ canonicalFile: canonical.file,
323
+ canonicalLine: canonical.line,
324
+ ...rawControl.containingComponent ? { containingComponent: rawControl.containingComponent } : {},
325
+ evidence: [
326
+ `${rawControl.file}:${rawControl.line} renders raw <${rawControl.element}>`,
327
+ `${canonical.file}:${canonical.line} already exports reusable ${canonical.name}`
328
+ ]
329
+ });
330
+ }
331
+ }
332
+ return {
333
+ filesChecked: parsedFiles.length,
334
+ declarations,
335
+ imports: parsedFiles.flatMap((file) => file.importReferences),
336
+ reusableComponentCount: [...reusableByName.values()].reduce(
337
+ (count, entries) => count + entries.length,
338
+ 0
339
+ ),
340
+ localRedeclarationCount: findings.length,
341
+ rawControlCount: rawControlFindings.length,
342
+ findings,
343
+ rawControlFindings
344
+ };
345
+ }
8
346
 
9
347
  // src/runtime.ts
10
- import { existsSync, readdirSync, readFileSync, statSync } from "fs";
348
+ import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
11
349
  import { createServer } from "http";
12
- import { extname, join, normalize } from "path";
350
+ import { extname as extname2, join, normalize } from "path";
13
351
  var CONTENT_TYPES = {
14
352
  ".css": "text/css; charset=utf-8",
15
353
  ".html": "text/html; charset=utf-8",
@@ -69,7 +407,7 @@ function emptyRuntimeAudit(failures = []) {
69
407
  };
70
408
  }
71
409
  function getContentType(pathname) {
72
- return CONTENT_TYPES[extname(pathname)] ?? "application/octet-stream";
410
+ return CONTENT_TYPES[extname2(pathname)] ?? "application/octet-stream";
73
411
  }
74
412
  function extractAssetPaths(indexHtml) {
75
413
  const assetPaths = /* @__PURE__ */ new Set();
@@ -252,7 +590,7 @@ function auditNextBuildOutput(projectRoot) {
252
590
  const relativePath = filePath.slice(appServerDir.length + 1).replace(/\\/g, "/");
253
591
  return filePath.endsWith(".html") && !relativePath.startsWith("_");
254
592
  });
255
- const htmlDocuments = htmlFiles.map((filePath) => readFileSync(filePath, "utf-8"));
593
+ const htmlDocuments = htmlFiles.map((filePath) => readFileSync2(filePath, "utf-8"));
256
594
  const staticAssetFiles = collectFiles(
257
595
  join(nextDir, "static"),
258
596
  (filePath) => /\.(?:js|css|json|svg|png|jpe?g|webp)$/i.test(filePath)
@@ -269,7 +607,7 @@ function auditNextBuildOutput(projectRoot) {
269
607
  totalAssetBytes += byteLength;
270
608
  if (assetFile.endsWith(".js")) {
271
609
  jsAssetBytes += byteLength;
272
- combinedJs += readFileSync(assetFile, "utf-8");
610
+ combinedJs += readFileSync2(assetFile, "utf-8");
273
611
  }
274
612
  if (assetFile.endsWith(".css")) {
275
613
  cssAssetBytes += byteLength;
@@ -354,7 +692,7 @@ function isNextProject(projectRoot) {
354
692
  return true;
355
693
  }
356
694
  try {
357
- const pkg = JSON.parse(readFileSync(join(projectRoot, "package.json"), "utf-8"));
695
+ const pkg = JSON.parse(readFileSync2(join(projectRoot, "package.json"), "utf-8"));
358
696
  return Boolean(pkg.dependencies?.next || pkg.devDependencies?.next);
359
697
  } catch {
360
698
  return false;
@@ -371,13 +709,13 @@ async function startStaticServer(rootDir) {
371
709
  if (existsSync(filePath)) {
372
710
  res.statusCode = 200;
373
711
  res.setHeader("Content-Type", getContentType(filePath));
374
- res.end(readFileSync(filePath));
712
+ res.end(readFileSync2(filePath));
375
713
  return;
376
714
  }
377
715
  if (existsSync(fallbackPath)) {
378
716
  res.statusCode = 200;
379
717
  res.setHeader("Content-Type", "text/html; charset=utf-8");
380
- res.end(readFileSync(fallbackPath));
718
+ res.end(readFileSync2(fallbackPath));
381
719
  return;
382
720
  }
383
721
  res.statusCode = 404;
@@ -422,7 +760,7 @@ async function auditBuiltDist(projectRoot, options = {}) {
422
760
  }
423
761
  const routeHints = Array.isArray(options.routeHints) && options.routeHints.length > 0 ? options.routeHints.map((route) => normalizeRouteHint(route)).filter(Boolean).slice(0, 8) : ["/"];
424
762
  const frameworkDocumentOutput = isNextProject(projectRoot);
425
- const indexHtml = readFileSync(indexPath, "utf-8");
763
+ const indexHtml = readFileSync2(indexPath, "utf-8");
426
764
  const assetPaths = extractAssetPaths(indexHtml);
427
765
  const server = await startStaticServer(distDir);
428
766
  try {
@@ -586,6 +924,862 @@ async function auditBuiltDist(projectRoot, options = {}) {
586
924
  }
587
925
  }
588
926
 
927
+ // src/style-bridge-drift.ts
928
+ import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
929
+ import { join as join2, relative as relative2 } from "path";
930
+ import * as ts2 from "typescript";
931
+ var STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID = "style-bridge-arbitrary-value";
932
+ var CLASS_HELPER_NAMES = /* @__PURE__ */ new Set(["cn", "clsx", "classnames", "cva", "tv"]);
933
+ var INLINE_STYLE_PROPERTIES = /* @__PURE__ */ new Set([
934
+ "accentColor",
935
+ "background",
936
+ "backgroundColor",
937
+ "border",
938
+ "borderColor",
939
+ "boxShadow",
940
+ "caretColor",
941
+ "color",
942
+ "fill",
943
+ "outline",
944
+ "outlineColor",
945
+ "stroke",
946
+ "textDecorationColor"
947
+ ]);
948
+ var STYLESHEET_EXTENSIONS = /\.(?:css|scss|sass|less)$/i;
949
+ var SCRIPT_EXTENSIONS = /\.[cm]?[jt]sx?$/i;
950
+ var STYLESHEET_VISUAL_PROPERTIES = /* @__PURE__ */ new Set([
951
+ "accent-color",
952
+ "background",
953
+ "background-color",
954
+ "border",
955
+ "border-color",
956
+ "box-shadow",
957
+ "caret-color",
958
+ "color",
959
+ "fill",
960
+ "outline",
961
+ "outline-color",
962
+ "stroke",
963
+ "text-decoration-color"
964
+ ]);
965
+ function normalizePath2(path) {
966
+ return path.replace(/\\/g, "/");
967
+ }
968
+ function stringArray(value) {
969
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
970
+ }
971
+ function isNonProductionStyleBridgeDriftFile(file) {
972
+ const normalized = normalizePath2(file);
973
+ return /(?:^|\/)(?:__tests__|__mocks__|tests?|specs?|fixtures?|mocks?|stories?)(?:\/|$)/i.test(
974
+ normalized
975
+ ) || /\.(?:test|spec|stories|story|fixture|mock)\.(?:[cm]?[jt]sx?|css|scss|sass|less)$/i.test(
976
+ normalized
977
+ );
978
+ }
979
+ function collectProjectStyleFiles(projectRoot) {
980
+ const candidates = ["src", "app", "pages", "components", "styles"].map((dir) => join2(projectRoot, dir)).filter((dir) => existsSync2(dir));
981
+ const ignoredDirNames = /* @__PURE__ */ new Set([
982
+ "node_modules",
983
+ ".git",
984
+ ".decantr",
985
+ "dist",
986
+ "build",
987
+ "coverage"
988
+ ]);
989
+ const files = /* @__PURE__ */ new Set();
990
+ const walk = (dir) => {
991
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
992
+ if (ignoredDirNames.has(entry.name)) continue;
993
+ const absolutePath = join2(dir, entry.name);
994
+ if (entry.isDirectory()) {
995
+ walk(absolutePath);
996
+ continue;
997
+ }
998
+ if (!entry.isFile() || !STYLESHEET_EXTENSIONS.test(absolutePath)) continue;
999
+ files.add(absolutePath);
1000
+ }
1001
+ };
1002
+ for (const candidate of candidates) {
1003
+ walk(candidate);
1004
+ }
1005
+ return [...files].sort();
1006
+ }
1007
+ function readAcceptedStyleBridge(projectRoot) {
1008
+ const path = join2(projectRoot, ".decantr", "style-bridge.json");
1009
+ if (!existsSync2(path)) return null;
1010
+ let bridge;
1011
+ try {
1012
+ bridge = JSON.parse(readFileSync3(path, "utf-8"));
1013
+ } catch {
1014
+ return null;
1015
+ }
1016
+ if (bridge.status !== "accepted" || !Array.isArray(bridge.mappings)) return null;
1017
+ const mappings = bridge.mappings.filter(
1018
+ (mapping) => Boolean(mapping) && typeof mapping === "object"
1019
+ );
1020
+ if (mappings.length === 0) return null;
1021
+ const mappingIds = mappings.map(
1022
+ (mapping, index) => typeof mapping.id === "string" && mapping.id.length > 0 ? mapping.id : typeof mapping.label === "string" && mapping.label.length > 0 ? mapping.label : `mapping-${index + 1}`
1023
+ ).slice(0, 12);
1024
+ const tokenHints = [
1025
+ ...new Set(mappings.flatMap((mapping) => stringArray(mapping.tokenHints)))
1026
+ ].slice(0, 16);
1027
+ const classHints = [
1028
+ ...new Set(mappings.flatMap((mapping) => stringArray(mapping.classHints)))
1029
+ ].slice(0, 16);
1030
+ return { mappingIds, tokenHints, classHints };
1031
+ }
1032
+ function lineForNode2(sourceFile, node) {
1033
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
1034
+ }
1035
+ function jsxAttributeName(name) {
1036
+ if (ts2.isIdentifier(name)) return name.text;
1037
+ if (ts2.isJsxNamespacedName(name)) return `${name.namespace.text}:${name.name.text}`;
1038
+ return null;
1039
+ }
1040
+ function jsxAttributeText(attribute) {
1041
+ const initializer = attribute.initializer;
1042
+ if (!initializer) return "";
1043
+ if (ts2.isStringLiteral(initializer)) return initializer.text;
1044
+ if (!ts2.isJsxExpression(initializer) || !initializer.expression) return null;
1045
+ const expression = initializer.expression;
1046
+ if (ts2.isStringLiteral(expression) || ts2.isNoSubstitutionTemplateLiteral(expression)) {
1047
+ return expression.text;
1048
+ }
1049
+ if (ts2.isTemplateExpression(expression)) {
1050
+ return [
1051
+ expression.head.text,
1052
+ ...expression.templateSpans.map((span) => span.literal.text)
1053
+ ].join(" ");
1054
+ }
1055
+ return null;
1056
+ }
1057
+ function classHelperName(expression) {
1058
+ if (ts2.isIdentifier(expression)) return expression.text;
1059
+ if (ts2.isPropertyAccessExpression(expression)) return expression.name.text;
1060
+ return null;
1061
+ }
1062
+ function isClassHelperCall(node) {
1063
+ const helperName = classHelperName(node.expression);
1064
+ return Boolean(helperName && CLASS_HELPER_NAMES.has(helperName));
1065
+ }
1066
+ function templateExpressionText(expression) {
1067
+ return [
1068
+ expression.head.text,
1069
+ ...expression.templateSpans.map((span) => span.literal.text)
1070
+ ].join(" ");
1071
+ }
1072
+ function collectClassTextsFromNode(node) {
1073
+ const entries = [];
1074
+ const visit = (child) => {
1075
+ if (ts2.isStringLiteral(child) || ts2.isNoSubstitutionTemplateLiteral(child)) {
1076
+ entries.push({ className: child.text, node: child });
1077
+ return;
1078
+ }
1079
+ if (ts2.isTemplateExpression(child)) {
1080
+ entries.push({ className: templateExpressionText(child), node: child });
1081
+ return;
1082
+ }
1083
+ ts2.forEachChild(child, visit);
1084
+ };
1085
+ ts2.forEachChild(node, visit);
1086
+ return entries;
1087
+ }
1088
+ function stripTailwindVariants(className) {
1089
+ let bracketDepth = 0;
1090
+ let segmentStart = 0;
1091
+ for (let index = 0; index < className.length; index += 1) {
1092
+ const char = className[index];
1093
+ if (char === "[") bracketDepth += 1;
1094
+ if (char === "]") bracketDepth = Math.max(0, bracketDepth - 1);
1095
+ if (char === ":" && bracketDepth === 0) segmentStart = index + 1;
1096
+ }
1097
+ return className.slice(segmentStart);
1098
+ }
1099
+ function arbitraryStyleClasses(className) {
1100
+ const classes = className.split(/\s+/).map((entry) => entry.trim()).filter(Boolean);
1101
+ return classes.filter((entry) => {
1102
+ const classWithoutVariant = stripTailwindVariants(entry);
1103
+ return /^(?:-)?(?:bg|text|border|ring|shadow|from|via|to|fill|stroke|outline|decoration|accent|caret|placeholder|divide)-\[[^\]]+\]$/i.test(
1104
+ classWithoutVariant
1105
+ ) || /^\[(?:color|background|background-color|border|border-color|box-shadow|outline|fill|stroke|--[A-Za-z0-9_-]+):[^\]]+\]$/i.test(
1106
+ classWithoutVariant
1107
+ );
1108
+ });
1109
+ }
1110
+ function propertyName(name) {
1111
+ if (ts2.isIdentifier(name) || ts2.isStringLiteral(name) || ts2.isNumericLiteral(name)) {
1112
+ return name.text;
1113
+ }
1114
+ return null;
1115
+ }
1116
+ function styleLiteralValue(expression) {
1117
+ if (ts2.isStringLiteral(expression) || ts2.isNoSubstitutionTemplateLiteral(expression)) {
1118
+ return expression.text;
1119
+ }
1120
+ if (ts2.isTemplateExpression(expression)) {
1121
+ return expression.templateSpans.length === 0 ? expression.head.text : null;
1122
+ }
1123
+ return null;
1124
+ }
1125
+ function isAcceptedTokenValue(value, tokenHints) {
1126
+ return tokenHints.some((hint) => {
1127
+ const normalizedHint = hint.trim();
1128
+ if (!normalizedHint) return false;
1129
+ return value.includes(normalizedHint) || value.includes(`var(${normalizedHint})`);
1130
+ });
1131
+ }
1132
+ function arbitraryInlineStyleValue(property, value, tokenHints) {
1133
+ const normalizedProperty = property.trim();
1134
+ const normalizedValue = value.trim();
1135
+ if (!normalizedProperty || !normalizedValue) return null;
1136
+ const isVisualProperty = INLINE_STYLE_PROPERTIES.has(normalizedProperty) || STYLESHEET_VISUAL_PROPERTIES.has(normalizedProperty) || normalizedProperty.startsWith("--");
1137
+ if (!isVisualProperty) return null;
1138
+ if (isAcceptedTokenValue(normalizedValue, tokenHints)) return null;
1139
+ if (/(?:^|[\s,(])#[0-9a-f]{3,8}\b|(?:rgba?|hsla?|oklch|oklab|lch|lab|color-mix)\(/i.test(
1140
+ normalizedValue
1141
+ ) || /var\(--[A-Za-z0-9_-]+\)/i.test(normalizedValue)) {
1142
+ return `${normalizedProperty}: ${normalizedValue}`;
1143
+ }
1144
+ return null;
1145
+ }
1146
+ function styleBridgeEvidenceText(file, line, source, value) {
1147
+ if (source === "inline-style") {
1148
+ return `${file}:${line} uses inline style value "${value}"`;
1149
+ }
1150
+ if (source === "stylesheet") {
1151
+ return `${file}:${line} uses stylesheet value "${value}"`;
1152
+ }
1153
+ return `${file}:${line} uses arbitrary Tailwind value "${value}"`;
1154
+ }
1155
+ function collectStyleBridgeDriftFindings(input) {
1156
+ const file = normalizePath2(relative2(input.projectRoot, input.absolutePath) || input.absolutePath);
1157
+ if (isNonProductionStyleBridgeDriftFile(file)) return [];
1158
+ if (!SCRIPT_EXTENSIONS.test(file)) return [];
1159
+ let code = "";
1160
+ try {
1161
+ code = readFileSync3(input.absolutePath, "utf-8");
1162
+ } catch {
1163
+ return [];
1164
+ }
1165
+ const sourceFile = ts2.createSourceFile(
1166
+ file,
1167
+ code,
1168
+ ts2.ScriptTarget.Latest,
1169
+ true,
1170
+ /\.[cm]?[jt]sx$/i.test(file) ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS
1171
+ );
1172
+ const findings = [];
1173
+ const seen = /* @__PURE__ */ new Set();
1174
+ const addFinding = (node, className, value, source, property) => {
1175
+ const line = lineForNode2(sourceFile, node);
1176
+ const key = `${file}:${line}:${value}`;
1177
+ if (seen.has(key)) return;
1178
+ seen.add(key);
1179
+ findings.push({
1180
+ id: `${STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID}:${file}:${line}:${value}`,
1181
+ file,
1182
+ line,
1183
+ className,
1184
+ value,
1185
+ source,
1186
+ ...property ? { property } : {},
1187
+ bridgeMappingIds: input.bridge.mappingIds,
1188
+ tokenHints: input.bridge.tokenHints,
1189
+ classHints: input.bridge.classHints,
1190
+ evidence: [
1191
+ styleBridgeEvidenceText(file, line, source, value),
1192
+ `.decantr/style-bridge.json is accepted with mappings: ${input.bridge.mappingIds.join(", ")}`,
1193
+ input.bridge.tokenHints.length > 0 ? `Accepted token hints: ${input.bridge.tokenHints.join(", ")}` : "Accepted style bridge has no token hints for this mapping set",
1194
+ input.bridge.classHints.length > 0 ? `Accepted class hints: ${input.bridge.classHints.join(", ")}` : "Accepted style bridge has no class hints for this mapping set"
1195
+ ]
1196
+ });
1197
+ };
1198
+ const visit = (node) => {
1199
+ if (ts2.isJsxAttribute(node) && jsxAttributeName(node.name) === "className") {
1200
+ const className = jsxAttributeText(node);
1201
+ if (className) {
1202
+ for (const value of arbitraryStyleClasses(className)) {
1203
+ addFinding(node, className, value, "className");
1204
+ }
1205
+ }
1206
+ }
1207
+ if (ts2.isJsxAttribute(node) && jsxAttributeName(node.name) === "style") {
1208
+ const initializer = node.initializer;
1209
+ const expression = initializer && ts2.isJsxExpression(initializer) ? initializer.expression : void 0;
1210
+ if (expression && ts2.isObjectLiteralExpression(expression)) {
1211
+ for (const property of expression.properties) {
1212
+ if (!ts2.isPropertyAssignment(property)) continue;
1213
+ const name = propertyName(property.name);
1214
+ const literal = styleLiteralValue(property.initializer);
1215
+ if (!name || literal === null) continue;
1216
+ const value = arbitraryInlineStyleValue(name, literal, input.bridge.tokenHints);
1217
+ if (value) {
1218
+ addFinding(property, `style.${name}`, value, "inline-style", name);
1219
+ }
1220
+ }
1221
+ }
1222
+ }
1223
+ if (ts2.isCallExpression(node) && isClassHelperCall(node)) {
1224
+ for (const entry of collectClassTextsFromNode(node)) {
1225
+ for (const value of arbitraryStyleClasses(entry.className)) {
1226
+ addFinding(entry.node, entry.className, value, "className");
1227
+ }
1228
+ }
1229
+ }
1230
+ ts2.forEachChild(node, visit);
1231
+ };
1232
+ ts2.forEachChild(sourceFile, visit);
1233
+ return findings;
1234
+ }
1235
+ function collectStylesheetBridgeDriftFindings(input) {
1236
+ const file = normalizePath2(relative2(input.projectRoot, input.absolutePath) || input.absolutePath);
1237
+ if (isNonProductionStyleBridgeDriftFile(file) || !STYLESHEET_EXTENSIONS.test(file)) return [];
1238
+ let code = "";
1239
+ try {
1240
+ code = readFileSync3(input.absolutePath, "utf-8");
1241
+ } catch {
1242
+ return [];
1243
+ }
1244
+ const findings = [];
1245
+ const seen = /* @__PURE__ */ new Set();
1246
+ const lines = code.split(/\r?\n/);
1247
+ const declarationPattern = /(^|[;{\s])(?<property>accent-color|background|background-color|border|border-color|box-shadow|caret-color|color|fill|outline|outline-color|stroke|text-decoration-color)\s*:\s*(?<value>[^;{}]+)\s*;?/gi;
1248
+ for (const [lineIndex, line] of lines.entries()) {
1249
+ if (/^\s*(?:\/\*|\*|\/\/)/.test(line)) continue;
1250
+ for (const match of line.matchAll(declarationPattern)) {
1251
+ const property = match.groups?.property;
1252
+ const rawValue = match.groups?.value;
1253
+ if (!property || !rawValue) continue;
1254
+ const value = arbitraryInlineStyleValue(property, rawValue, input.bridge.tokenHints);
1255
+ if (!value) continue;
1256
+ const lineNumber = lineIndex + 1;
1257
+ const key = `${file}:${lineNumber}:${value}`;
1258
+ if (seen.has(key)) continue;
1259
+ seen.add(key);
1260
+ findings.push({
1261
+ id: `${STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID}:${file}:${lineNumber}:${value}`,
1262
+ file,
1263
+ line: lineNumber,
1264
+ className: property,
1265
+ value,
1266
+ source: "stylesheet",
1267
+ property,
1268
+ bridgeMappingIds: input.bridge.mappingIds,
1269
+ tokenHints: input.bridge.tokenHints,
1270
+ classHints: input.bridge.classHints,
1271
+ evidence: [
1272
+ `${file}:${lineNumber} uses stylesheet value "${value}"`,
1273
+ `.decantr/style-bridge.json is accepted with mappings: ${input.bridge.mappingIds.join(", ")}`,
1274
+ input.bridge.tokenHints.length > 0 ? `Accepted token hints: ${input.bridge.tokenHints.join(", ")}` : "Accepted style bridge has no token hints for this mapping set",
1275
+ input.bridge.classHints.length > 0 ? `Accepted class hints: ${input.bridge.classHints.join(", ")}` : "Accepted style bridge has no class hints for this mapping set"
1276
+ ]
1277
+ });
1278
+ }
1279
+ }
1280
+ return findings;
1281
+ }
1282
+ function auditStyleBridgeDrift(projectRoot, sourceFiles) {
1283
+ const bridge = readAcceptedStyleBridge(projectRoot);
1284
+ if (!bridge) {
1285
+ return {
1286
+ filesChecked: 0,
1287
+ bridgeMappingCount: 0,
1288
+ arbitraryValueCount: 0,
1289
+ findings: []
1290
+ };
1291
+ }
1292
+ const filesToCheck = [
1293
+ .../* @__PURE__ */ new Set([...sourceFiles, ...collectProjectStyleFiles(projectRoot)])
1294
+ ].sort();
1295
+ const findings = filesToCheck.flatMap(
1296
+ (absolutePath) => SCRIPT_EXTENSIONS.test(absolutePath) ? collectStyleBridgeDriftFindings({ projectRoot, absolutePath, bridge }) : collectStylesheetBridgeDriftFindings({ projectRoot, absolutePath, bridge })
1297
+ );
1298
+ return {
1299
+ filesChecked: filesToCheck.filter(
1300
+ (file) => !isNonProductionStyleBridgeDriftFile(
1301
+ normalizePath2(relative2(projectRoot, file) || file)
1302
+ )
1303
+ ).length,
1304
+ bridgeMappingCount: bridge.mappingIds.length,
1305
+ arbitraryValueCount: findings.length,
1306
+ findings
1307
+ };
1308
+ }
1309
+
1310
+ // src/diagnostics.ts
1311
+ var KNOWN_VERIFICATION_DIAGNOSTICS = [
1312
+ {
1313
+ rule: "browser-base-url-missing",
1314
+ code: "VISUAL002",
1315
+ repairId: "provide-browser-base-url",
1316
+ family: "VISUAL"
1317
+ },
1318
+ {
1319
+ rule: "browser-playwright-missing",
1320
+ code: "VISUAL001",
1321
+ repairId: "install-browser-verifier",
1322
+ family: "VISUAL"
1323
+ },
1324
+ {
1325
+ rule: "browser-route-verification-failed",
1326
+ code: "VISUAL003",
1327
+ repairId: "fix-route-render",
1328
+ family: "VISUAL"
1329
+ },
1330
+ {
1331
+ rule: "visual-baseline-screenshot-drift",
1332
+ code: "VISUAL010",
1333
+ repairId: "review-visual-baseline-drift",
1334
+ family: "VISUAL"
1335
+ },
1336
+ {
1337
+ rule: "brownfield-route-drift",
1338
+ code: "ROUTE001",
1339
+ repairId: "reconcile-brownfield-routes",
1340
+ family: "ROUTE"
1341
+ },
1342
+ { rule: "check-failed", code: "CHECK001", repairId: "repair-contract-check", family: "CHECK" },
1343
+ {
1344
+ rule: "component-reuse-raw-control",
1345
+ code: "COMP010",
1346
+ repairId: "replace-raw-control-with-local-component",
1347
+ family: "COMP"
1348
+ },
1349
+ {
1350
+ rule: "component-reuse-primitive-reimplemented",
1351
+ code: "COMP001",
1352
+ repairId: "import-existing-component",
1353
+ family: "COMP"
1354
+ },
1355
+ {
1356
+ rule: "declared-route-resolves",
1357
+ code: "STRUCT002",
1358
+ repairId: "repair-route-binding",
1359
+ family: "STRUCT"
1360
+ },
1361
+ {
1362
+ rule: "design-token-coverage",
1363
+ code: "TOKEN002",
1364
+ repairId: "repair-design-token-coverage",
1365
+ family: "TOKEN"
1366
+ },
1367
+ {
1368
+ rule: "style-bridge-arbitrary-value",
1369
+ code: "TOKEN010",
1370
+ repairId: "replace-arbitrary-style-with-bridge-token",
1371
+ family: "TOKEN"
1372
+ },
1373
+ {
1374
+ rule: "essence-present",
1375
+ code: "CONTRACT001",
1376
+ repairId: "restore-essence-contract",
1377
+ family: "CONTRACT"
1378
+ },
1379
+ {
1380
+ rule: "essence-v4",
1381
+ code: "CONTRACT002",
1382
+ repairId: "migrate-essence-v4",
1383
+ family: "CONTRACT"
1384
+ },
1385
+ {
1386
+ rule: "focus-visible-enabled",
1387
+ code: "A11Y001",
1388
+ repairId: "enable-focus-visible",
1389
+ family: "A11Y"
1390
+ },
1391
+ {
1392
+ rule: "pack-manifest-present",
1393
+ code: "CTX002",
1394
+ repairId: "hydrate-execution-packs",
1395
+ family: "CTX"
1396
+ },
1397
+ {
1398
+ rule: "pack-manifest-missing",
1399
+ code: "CTX002",
1400
+ repairId: "hydrate-execution-packs",
1401
+ family: "CTX"
1402
+ },
1403
+ {
1404
+ rule: "page-pack-count-mismatch",
1405
+ code: "CTX001",
1406
+ repairId: "regenerate-context-packs",
1407
+ family: "CTX"
1408
+ },
1409
+ { rule: "page-route-required", code: "STRUCT001", repairId: "add-page-route", family: "STRUCT" },
1410
+ {
1411
+ rule: "project-audit-invalid",
1412
+ code: "AUDIT001",
1413
+ repairId: "repair-project-audit",
1414
+ family: "AUDIT"
1415
+ },
1416
+ {
1417
+ rule: "review-pack-present",
1418
+ code: "CTX003",
1419
+ repairId: "hydrate-review-pack",
1420
+ family: "CTX"
1421
+ },
1422
+ {
1423
+ rule: "review-pack-file-missing",
1424
+ code: "CTX003",
1425
+ repairId: "hydrate-review-pack",
1426
+ family: "CTX"
1427
+ },
1428
+ {
1429
+ rule: "section-shell-concrete",
1430
+ code: "STRUCT003",
1431
+ repairId: "assign-section-shell",
1432
+ family: "STRUCT"
1433
+ },
1434
+ {
1435
+ rule: "tokens-file-present",
1436
+ code: "TOKEN001",
1437
+ repairId: "restore-design-token-file",
1438
+ family: "TOKEN"
1439
+ },
1440
+ {
1441
+ rule: "typed-graph-current",
1442
+ code: "GRAPH001",
1443
+ repairId: "regenerate-typed-graph",
1444
+ family: "GRAPH"
1445
+ }
1446
+ ];
1447
+ var CODE_BY_RULE = Object.fromEntries(
1448
+ KNOWN_VERIFICATION_DIAGNOSTICS.map((entry) => [entry.rule, entry.code])
1449
+ );
1450
+ var REPAIR_BY_RULE = Object.fromEntries(
1451
+ KNOWN_VERIFICATION_DIAGNOSTICS.map((entry) => [entry.rule, entry.repairId])
1452
+ );
1453
+ var DEFAULT_REPAIR_BY_SOURCE = {
1454
+ assertion: "repair-contract-assertion",
1455
+ audit: "repair-audit-finding",
1456
+ browser: "repair-browser-evidence",
1457
+ brownfield: "repair-brownfield-drift",
1458
+ check: "repair-contract-check",
1459
+ "design-token": "repair-design-token-drift",
1460
+ "style-bridge": "repair-style-bridge-drift",
1461
+ graph: "regenerate-typed-graph",
1462
+ interaction: "repair-interaction-contract",
1463
+ pack: "regenerate-context-packs",
1464
+ runtime: "repair-runtime-output"
1465
+ };
1466
+ var DEFAULT_CODE_PREFIX_BY_SOURCE = {
1467
+ assertion: "CONTRACT",
1468
+ audit: "AUDIT",
1469
+ browser: "VISUAL",
1470
+ brownfield: "ROUTE",
1471
+ check: "CHECK",
1472
+ "design-token": "TOKEN",
1473
+ "style-bridge": "TOKEN",
1474
+ graph: "GRAPH",
1475
+ interaction: "INT",
1476
+ pack: "CTX",
1477
+ runtime: "RUNTIME"
1478
+ };
1479
+ function stableNumber(value) {
1480
+ let hash = 0;
1481
+ for (let i = 0; i < value.length; i += 1) {
1482
+ hash = hash * 31 + value.charCodeAt(i) >>> 0;
1483
+ }
1484
+ return String(hash % 900 + 100).padStart(3, "0");
1485
+ }
1486
+ function normalizedKey(value) {
1487
+ return (value ?? "").trim().toLowerCase();
1488
+ }
1489
+ function codePrefix(input) {
1490
+ const source = normalizedKey(input.source);
1491
+ if (source && DEFAULT_CODE_PREFIX_BY_SOURCE[source]) return DEFAULT_CODE_PREFIX_BY_SOURCE[source];
1492
+ const category = normalizedKey(input.category);
1493
+ if (category.includes("accessibility")) return "A11Y";
1494
+ if (category.includes("route")) return "ROUTE";
1495
+ if (category.includes("token")) return "TOKEN";
1496
+ if (category.includes("runtime")) return "RUNTIME";
1497
+ if (category.includes("pack") || category.includes("context")) return "CTX";
1498
+ if (category.includes("visual") || category.includes("browser")) return "VISUAL";
1499
+ if (category.includes("interaction")) return "INT";
1500
+ if (category.includes("contract")) return "CONTRACT";
1501
+ return "DCTR";
1502
+ }
1503
+ function lookupById(map, input) {
1504
+ const id = normalizedKey(input.id);
1505
+ if (!id) return void 0;
1506
+ if (map[id]) return map[id];
1507
+ const source = normalizedKey(input.source);
1508
+ const idWithoutSource = source && id.startsWith(`${source}-`) ? id.slice(source.length + 1) : id;
1509
+ if (map[idWithoutSource]) return map[idWithoutSource];
1510
+ const suffix = Object.keys(map).find((key) => id.endsWith(`-${key}`));
1511
+ return suffix ? map[suffix] : void 0;
1512
+ }
1513
+ function diagnosticCode(input) {
1514
+ const rule = normalizedKey(input.rule);
1515
+ if (rule && CODE_BY_RULE[rule]) return CODE_BY_RULE[rule];
1516
+ const idCode = lookupById(CODE_BY_RULE, input);
1517
+ if (idCode) return idCode;
1518
+ const seed = [input.source, input.rule, input.id, input.category, input.message].filter((entry) => typeof entry === "string" && entry.length > 0).join("|");
1519
+ return `${codePrefix(input)}${stableNumber(seed)}`;
1520
+ }
1521
+ function repairId(input) {
1522
+ const rule = normalizedKey(input.rule);
1523
+ if (rule && REPAIR_BY_RULE[rule]) return REPAIR_BY_RULE[rule];
1524
+ const idRepair = lookupById(REPAIR_BY_RULE, input);
1525
+ if (idRepair) return idRepair;
1526
+ const source = normalizedKey(input.source);
1527
+ return DEFAULT_REPAIR_BY_SOURCE[source] ?? "repair-project-health-finding";
1528
+ }
1529
+ function compactPayload(input) {
1530
+ return Object.fromEntries(
1531
+ Object.entries(input).filter(([, value]) => {
1532
+ if (value === void 0 || value === null) return false;
1533
+ if (Array.isArray(value)) return value.length > 0;
1534
+ if (typeof value === "string") return value.length > 0;
1535
+ return true;
1536
+ })
1537
+ );
1538
+ }
1539
+ function deriveVerificationDiagnostic(input) {
1540
+ const payload = compactPayload({
1541
+ source: input.source,
1542
+ rule: input.rule,
1543
+ target: input.target,
1544
+ file: input.file,
1545
+ suggested_fix: input.suggestedFix,
1546
+ evidence: input.evidence?.slice(0, 5)
1547
+ });
1548
+ const repair = { id: repairId(input) };
1549
+ if (Object.keys(payload).length > 0) repair.payload = payload;
1550
+ return {
1551
+ code: diagnosticCode(input),
1552
+ repair
1553
+ };
1554
+ }
1555
+
1556
+ // src/graph-anchors.ts
1557
+ function payloadRecord(payload) {
1558
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
1559
+ }
1560
+ function payloadString(payload, key) {
1561
+ const value = payloadRecord(payload)[key];
1562
+ return typeof value === "string" ? value : void 0;
1563
+ }
1564
+ function slug(value) {
1565
+ return value.trim().toLowerCase().replace(/[^a-z0-9_.:/-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1566
+ }
1567
+ function normalizedHaystack(finding) {
1568
+ return [
1569
+ finding.id,
1570
+ finding.category,
1571
+ finding.message,
1572
+ finding.target,
1573
+ finding.file,
1574
+ finding.rule,
1575
+ ...finding.evidence ?? []
1576
+ ].filter((entry) => typeof entry === "string" && entry.length > 0).join("\n").toLowerCase();
1577
+ }
1578
+ function graphAnchor(snapshot, node, confidence, reason, route) {
1579
+ const anchor = {
1580
+ snapshot_id: snapshot.id,
1581
+ source_hash: snapshot.source_hash,
1582
+ node_id: node.id,
1583
+ node_type: node.type,
1584
+ confidence,
1585
+ reason
1586
+ };
1587
+ if (route) anchor.route = route;
1588
+ return anchor;
1589
+ }
1590
+ function routeForNode(snapshot, nodeId, visited = /* @__PURE__ */ new Set()) {
1591
+ if (visited.has(nodeId)) return void 0;
1592
+ visited.add(nodeId);
1593
+ if (nodeId.startsWith("rt:")) {
1594
+ const route2 = snapshot.nodes.find((node) => node.id === nodeId);
1595
+ return payloadString(route2?.payload, "path") ?? nodeId.replace(/^rt:/, "");
1596
+ }
1597
+ const sourceNode = snapshot.nodes.find(
1598
+ (node) => node.id === nodeId && node.type === "SourceArtifact"
1599
+ );
1600
+ if (sourceNode) {
1601
+ const sourceEdges = snapshot.edges.filter(
1602
+ (edge) => edge.relation === "NODE_DERIVED_FROM_SOURCE" && edge.dst === nodeId
1603
+ );
1604
+ const sortedSourceEdges = [
1605
+ ...sourceEdges.filter((edge) => edge.src.startsWith("rt:")),
1606
+ ...sourceEdges.filter((edge) => !edge.src.startsWith("rt:"))
1607
+ ];
1608
+ for (const edge of sortedSourceEdges) {
1609
+ const route2 = routeForNode(snapshot, edge.src, visited);
1610
+ if (route2) return route2;
1611
+ }
1612
+ return void 0;
1613
+ }
1614
+ const pageId = snapshot.nodes.find((node) => node.id === nodeId && node.type === "Page")?.id ?? snapshot.edges.find((edge) => edge.relation === "PAGE_COMPOSES_PATTERN" && edge.dst === nodeId)?.src ?? snapshot.edges.find((edge) => edge.relation === "PAGE_USES_SHELL" && edge.dst === nodeId)?.src;
1615
+ if (!pageId) return void 0;
1616
+ const routeEdge = snapshot.edges.find(
1617
+ (edge) => edge.relation === "PAGE_ROUTED_AT_ROUTE" && edge.src === pageId
1618
+ );
1619
+ if (!routeEdge) return void 0;
1620
+ const route = snapshot.nodes.find((node) => node.id === routeEdge.dst);
1621
+ return payloadString(route?.payload, "path") ?? routeEdge.dst.replace(/^rt:/, "");
1622
+ }
1623
+ function findProjectNode(snapshot) {
1624
+ return snapshot.nodes.find((node) => node.id === snapshot.project_id) ?? snapshot.nodes.find((node) => node.type === "Project");
1625
+ }
1626
+ function findLocalRuleNode(snapshot, finding) {
1627
+ const candidates = [finding.rule, finding.target, finding.id].filter((entry) => typeof entry === "string" && entry.length > 0).map(slug);
1628
+ if (candidates.length === 0) return null;
1629
+ return snapshot.nodes.find((node) => {
1630
+ if (node.type !== "LocalRule") return false;
1631
+ const payloadId = payloadString(node.payload, "id");
1632
+ const ids = [node.id.replace(/^rule:/, ""), payloadId ? slug(payloadId) : null].filter(
1633
+ (entry) => Boolean(entry)
1634
+ );
1635
+ return ids.some((id) => candidates.some((candidate) => id === candidate));
1636
+ }) ?? null;
1637
+ }
1638
+ function findStyleBridgeNode(snapshot, finding) {
1639
+ const haystack = normalizedHaystack(finding);
1640
+ const candidates = [finding.rule, finding.target, finding.id, ...finding.evidence ?? []].filter((entry) => typeof entry === "string" && entry.length > 0).map(slug);
1641
+ const styleBridgeNodes = snapshot.nodes.filter((node) => node.type === "StyleBridge");
1642
+ if (styleBridgeNodes.length === 0) return null;
1643
+ return styleBridgeNodes.find((node) => {
1644
+ const payloadId = payloadString(node.payload, "id");
1645
+ const payloadLabel = payloadString(node.payload, "label");
1646
+ const ids = [
1647
+ node.id.replace(/^bridge:/, ""),
1648
+ payloadId ? slug(payloadId) : null,
1649
+ payloadLabel ? slug(payloadLabel) : null
1650
+ ].filter((entry) => Boolean(entry));
1651
+ return ids.some(
1652
+ (id) => candidates.some((candidate) => id === candidate || candidate.includes(id)) || haystack.includes(id.toLowerCase())
1653
+ );
1654
+ }) ?? (haystack.includes("style-bridge") || haystack.includes("style bridge") ? styleBridgeNodes[0] ?? null : null);
1655
+ }
1656
+ function findRouteNode(snapshot, finding) {
1657
+ const haystack = normalizedHaystack(finding);
1658
+ const exactTarget = finding.target?.startsWith("/") ? finding.target : null;
1659
+ const routes = snapshot.nodes.filter((node) => node.type === "Route").map((node) => ({
1660
+ node,
1661
+ path: payloadString(node.payload, "path") ?? node.id.replace(/^rt:/, "")
1662
+ })).sort((a, b) => b.path.length - a.path.length);
1663
+ return routes.find((route) => route.path === exactTarget)?.node ?? routes.find((route) => route.path !== "/" && haystack.includes(route.path.toLowerCase()))?.node ?? null;
1664
+ }
1665
+ function findPageNode(snapshot, finding) {
1666
+ const candidates = [finding.target, finding.id].filter((entry) => typeof entry === "string" && entry.length > 0).map(slug);
1667
+ if (candidates.length === 0) return null;
1668
+ return snapshot.nodes.find((node) => {
1669
+ if (node.type !== "Page") return false;
1670
+ const payloadId = payloadString(node.payload, "id");
1671
+ const payloadSection = payloadString(node.payload, "section");
1672
+ const ids = [
1673
+ node.id.replace(/^pg:/, ""),
1674
+ payloadId ? slug(payloadId) : null,
1675
+ payloadId && payloadSection ? slug(`${payloadSection}:${payloadId}`) : null
1676
+ ].filter((entry) => Boolean(entry));
1677
+ return ids.some((id) => candidates.some((candidate) => id === candidate));
1678
+ }) ?? null;
1679
+ }
1680
+ function findPatternNode(snapshot, finding) {
1681
+ const haystack = normalizedHaystack(finding);
1682
+ return snapshot.nodes.find((node) => {
1683
+ if (node.type !== "Pattern") return false;
1684
+ const payloadId = payloadString(node.payload, "id");
1685
+ return [node.id.replace(/^pat:/, ""), payloadId].filter((entry) => Boolean(entry)).some((id) => haystack.includes(id.toLowerCase()));
1686
+ }) ?? null;
1687
+ }
1688
+ function findSourceArtifactNode(snapshot, finding) {
1689
+ const haystack = normalizedHaystack(finding);
1690
+ return snapshot.nodes.find((node) => {
1691
+ if (node.type !== "SourceArtifact") return false;
1692
+ const path = payloadString(node.payload, "path");
1693
+ return path ? haystack.includes(path.toLowerCase()) : false;
1694
+ }) ?? null;
1695
+ }
1696
+ function normalizePath3(value) {
1697
+ return value ? value.replace(/\\/g, "/").toLowerCase() : null;
1698
+ }
1699
+ function findExactSourceArtifactNode(snapshot, finding) {
1700
+ const findingFile = normalizePath3(finding.file);
1701
+ if (!findingFile) return null;
1702
+ return snapshot.nodes.find((node) => {
1703
+ if (node.type !== "SourceArtifact") return false;
1704
+ return normalizePath3(payloadString(node.payload, "path")) === findingFile;
1705
+ }) ?? null;
1706
+ }
1707
+ function resolveGraphAnchorForFinding(snapshot, finding) {
1708
+ if (!snapshot) return void 0;
1709
+ const localRule = findLocalRuleNode(snapshot, finding);
1710
+ if (localRule) {
1711
+ return graphAnchor(snapshot, localRule, "exact", "finding rule matched a LocalRule node");
1712
+ }
1713
+ const exactSourceArtifact = findExactSourceArtifactNode(snapshot, finding);
1714
+ if (exactSourceArtifact) {
1715
+ return graphAnchor(
1716
+ snapshot,
1717
+ exactSourceArtifact,
1718
+ "exact",
1719
+ "finding file matched a SourceArtifact node",
1720
+ routeForNode(snapshot, exactSourceArtifact.id)
1721
+ );
1722
+ }
1723
+ const styleBridge = findStyleBridgeNode(snapshot, finding);
1724
+ if (styleBridge) {
1725
+ return graphAnchor(snapshot, styleBridge, "exact", "finding matched a StyleBridge node");
1726
+ }
1727
+ const route = findRouteNode(snapshot, finding);
1728
+ if (route) {
1729
+ return graphAnchor(
1730
+ snapshot,
1731
+ route,
1732
+ finding.target === payloadString(route.payload, "path") ? "exact" : "inferred",
1733
+ "finding text matched a Route node",
1734
+ payloadString(route.payload, "path") ?? route.id.replace(/^rt:/, "")
1735
+ );
1736
+ }
1737
+ const page = findPageNode(snapshot, finding);
1738
+ if (page) {
1739
+ return graphAnchor(
1740
+ snapshot,
1741
+ page,
1742
+ "exact",
1743
+ "finding target matched a Page node",
1744
+ routeForNode(snapshot, page.id)
1745
+ );
1746
+ }
1747
+ const pattern = findPatternNode(snapshot, finding);
1748
+ if (pattern) {
1749
+ return graphAnchor(
1750
+ snapshot,
1751
+ pattern,
1752
+ "inferred",
1753
+ "finding text matched a Pattern node",
1754
+ routeForNode(snapshot, pattern.id)
1755
+ );
1756
+ }
1757
+ const sourceArtifact = findSourceArtifactNode(snapshot, finding);
1758
+ if (sourceArtifact) {
1759
+ return graphAnchor(
1760
+ snapshot,
1761
+ sourceArtifact,
1762
+ "inferred",
1763
+ "finding evidence matched a SourceArtifact node",
1764
+ routeForNode(snapshot, sourceArtifact.id)
1765
+ );
1766
+ }
1767
+ const project = findProjectNode(snapshot);
1768
+ return project ? graphAnchor(
1769
+ snapshot,
1770
+ project,
1771
+ "fallback",
1772
+ "finding is project-level or no specific graph node matched"
1773
+ ) : void 0;
1774
+ }
1775
+ function anchorFindingsToGraph(snapshot, findings) {
1776
+ if (!snapshot) return findings;
1777
+ return findings.map((finding) => {
1778
+ const graph = resolveGraphAnchorForFinding(snapshot, finding);
1779
+ return graph ? { ...finding, graph } : finding;
1780
+ });
1781
+ }
1782
+
589
1783
  // src/interactions.ts
590
1784
  var INTERACTION_SIGNALS = {
591
1785
  "animate-on-mount": {
@@ -755,8 +1949,9 @@ function listKnownInteractions() {
755
1949
  }
756
1950
 
757
1951
  // src/scan.ts
758
- import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
759
- import { extname as extname2, isAbsolute, join as join2, relative } from "path";
1952
+ import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
1953
+ import { extname as extname3, isAbsolute, join as join3, relative as relative3 } from "path";
1954
+ import { decodeHTML, decodeHTMLAttribute } from "entities";
760
1955
  var SCAN_REPORT_SCHEMA_URL = "https://decantr.ai/schemas/scan-report.v1.json";
761
1956
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".vue", ".svelte"]);
762
1957
  var STYLE_EXTENSIONS = /* @__PURE__ */ new Set([".css", ".scss", ".sass", ".less"]);
@@ -788,6 +1983,27 @@ var RULE_FILES = [
788
1983
  "copilot-instructions.md",
789
1984
  ".windsurfrules"
790
1985
  ];
1986
+ var GITHUB_OWNER_RE = /^[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?$/i;
1987
+ var GITHUB_REPO_RE = /^[a-z0-9._-]{1,100}$/i;
1988
+ function parseHttpUrl(value) {
1989
+ try {
1990
+ const url = new URL(value.trim());
1991
+ return url.protocol === "https:" || url.protocol === "http:" ? url : null;
1992
+ } catch {
1993
+ return null;
1994
+ }
1995
+ }
1996
+ function githubPagesOwnerFromHostname(hostname) {
1997
+ const [owner, domain, tld, ...extra] = hostname.toLowerCase().split(".");
1998
+ if (extra.length > 0 || domain !== "github" || tld !== "io" || !owner) return null;
1999
+ return GITHUB_OWNER_RE.test(owner) ? owner : null;
2000
+ }
2001
+ function normalizeGitHubPathSegment(segment, kind) {
2002
+ if (!segment) return null;
2003
+ const normalized = kind === "repo" ? segment.replace(/\.git$/i, "") : segment;
2004
+ const pattern = kind === "owner" ? GITHUB_OWNER_RE : GITHUB_REPO_RE;
2005
+ return pattern.test(normalized) ? normalized : null;
2006
+ }
791
2007
  var WEB_FRAMEWORKS = /* @__PURE__ */ new Set([
792
2008
  "angular",
793
2009
  "astro",
@@ -806,14 +2022,14 @@ function readTextFile(path, maxBytes = MAX_FILE_READ_BYTES) {
806
2022
  try {
807
2023
  const stat = statSync2(path);
808
2024
  if (!stat.isFile() || stat.size > maxBytes) return null;
809
- return readFileSync2(path, "utf-8");
2025
+ return readFileSync4(path, "utf-8");
810
2026
  } catch {
811
2027
  return null;
812
2028
  }
813
2029
  }
814
2030
  function readPackageJson(projectRoot) {
815
- const path = join2(projectRoot, "package.json");
816
- if (!existsSync2(path)) return { value: null, present: false, valid: false };
2031
+ const path = join3(projectRoot, "package.json");
2032
+ if (!existsSync3(path)) return { value: null, present: false, valid: false };
817
2033
  const content = readTextFile(path);
818
2034
  if (!content) return { value: null, present: true, valid: false };
819
2035
  try {
@@ -831,17 +2047,17 @@ function dependencyVersion(dependencies, names) {
831
2047
  return null;
832
2048
  }
833
2049
  function hasAnyFile(projectRoot, paths) {
834
- return paths.some((path) => existsSync2(join2(projectRoot, path)));
2050
+ return paths.some((path) => existsSync3(join3(projectRoot, path)));
835
2051
  }
836
2052
  function detectPackageManager(projectRoot, pkg) {
837
2053
  const declared = pkg?.packageManager?.split("@")[0];
838
2054
  if (declared === "npm" || declared === "pnpm" || declared === "yarn" || declared === "bun") {
839
2055
  return declared;
840
2056
  }
841
- if (existsSync2(join2(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
842
- if (existsSync2(join2(projectRoot, "yarn.lock"))) return "yarn";
843
- if (existsSync2(join2(projectRoot, "bun.lockb"))) return "bun";
844
- if (existsSync2(join2(projectRoot, "package-lock.json"))) return "npm";
2057
+ if (existsSync3(join3(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
2058
+ if (existsSync3(join3(projectRoot, "yarn.lock"))) return "yarn";
2059
+ if (existsSync3(join3(projectRoot, "bun.lockb"))) return "bun";
2060
+ if (existsSync3(join3(projectRoot, "package-lock.json"))) return "npm";
845
2061
  return "unknown";
846
2062
  }
847
2063
  function detectPrimaryLanguage(projectRoot, packageJsonPresent) {
@@ -897,7 +2113,7 @@ function detectProject(projectRoot) {
897
2113
  "tailwind.config.mjs",
898
2114
  "tailwind.config.cjs"
899
2115
  ]),
900
- hasDecantr: existsSync2(join2(projectRoot, "decantr.essence.json")) || existsSync2(join2(projectRoot, ".decantr")) || Boolean(dependencies["@decantr/cli"] || dependencies["@decantr/css"]),
2116
+ hasDecantr: existsSync3(join3(projectRoot, "decantr.essence.json")) || existsSync3(join3(projectRoot, ".decantr")) || Boolean(dependencies["@decantr/cli"] || dependencies["@decantr/css"]),
901
2117
  packageName: typeof pkg?.name === "string" ? pkg.name : null,
902
2118
  packageJsonValid: packageRead.valid,
903
2119
  packageJsonPresent: packageRead.present,
@@ -913,13 +2129,13 @@ function walkFiles(projectRoot, options = {}) {
913
2129
  if (files.length >= MAX_WALK_FILES) return;
914
2130
  let entries;
915
2131
  try {
916
- entries = readdirSync2(dir);
2132
+ entries = readdirSync3(dir);
917
2133
  } catch {
918
2134
  return;
919
2135
  }
920
2136
  for (const entry of entries) {
921
2137
  if (files.length >= MAX_WALK_FILES) return;
922
- const fullPath = join2(dir, entry);
2138
+ const fullPath = join3(dir, entry);
923
2139
  let stat;
924
2140
  try {
925
2141
  stat = statSync2(fullPath);
@@ -932,8 +2148,8 @@ function walkFiles(projectRoot, options = {}) {
932
2148
  continue;
933
2149
  }
934
2150
  if (!stat.isFile()) continue;
935
- const rel = relative(projectRoot, fullPath).replace(/\\/g, "/");
936
- const ext = extname2(entry).toLowerCase();
2151
+ const rel = relative3(projectRoot, fullPath).replace(/\\/g, "/");
2152
+ const ext = extname3(entry).toLowerCase();
937
2153
  if (!options.extensions || options.extensions.has(ext)) {
938
2154
  files.push(rel);
939
2155
  }
@@ -955,7 +2171,7 @@ function segmentToRoute(segment) {
955
2171
  function walkNextAppRoutes(dir, projectRoot, segments) {
956
2172
  let entries;
957
2173
  try {
958
- entries = readdirSync2(dir);
2174
+ entries = readdirSync3(dir);
959
2175
  } catch {
960
2176
  return [];
961
2177
  }
@@ -965,13 +2181,13 @@ function walkNextAppRoutes(dir, projectRoot, segments) {
965
2181
  if (pageFile) {
966
2182
  routes.push({
967
2183
  path: `/${segments.filter(Boolean).join("/")}` || "/",
968
- file: relative(projectRoot, join2(dir, pageFile)).replace(/\\/g, "/"),
2184
+ file: relative3(projectRoot, join3(dir, pageFile)).replace(/\\/g, "/"),
969
2185
  hasLayout
970
2186
  });
971
2187
  }
972
2188
  for (const entry of entries) {
973
2189
  if (shouldSkipDir(entry)) continue;
974
- const fullPath = join2(dir, entry);
2190
+ const fullPath = join3(dir, entry);
975
2191
  try {
976
2192
  if (!statSync2(fullPath).isDirectory()) continue;
977
2193
  } catch {
@@ -983,17 +2199,17 @@ function walkNextAppRoutes(dir, projectRoot, segments) {
983
2199
  return routes;
984
2200
  }
985
2201
  function fileRouteFromPath(file, baseDir) {
986
- let withoutExt = file.slice(0, -extname2(file).length);
2202
+ let withoutExt = file.slice(0, -extname3(file).length);
987
2203
  if (withoutExt.endsWith("/index")) withoutExt = withoutExt.slice(0, -"/index".length);
988
2204
  withoutExt = withoutExt.replace(new RegExp(`^${baseDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "");
989
2205
  const parts = withoutExt.split("/").filter(Boolean).map((part) => segmentToRoute(part)).filter(Boolean);
990
2206
  return `/${parts.join("/")}` || "/";
991
2207
  }
992
2208
  function scanFileRoutes(projectRoot, baseDir, extensions = PAGE_EXTENSIONS) {
993
- const fullBase = join2(projectRoot, baseDir);
994
- if (!existsSync2(fullBase)) return [];
2209
+ const fullBase = join3(projectRoot, baseDir);
2210
+ if (!existsSync3(fullBase)) return [];
995
2211
  return walkFiles(fullBase, { extensions }).map((file) => {
996
- const rel = relative(projectRoot, join2(fullBase, file)).replace(/\\/g, "/");
2212
+ const rel = relative3(projectRoot, join3(fullBase, file)).replace(/\\/g, "/");
997
2213
  return { path: fileRouteFromPath(rel, baseDir), file: rel, hasLayout: false };
998
2214
  });
999
2215
  }
@@ -1002,7 +2218,7 @@ function scanReactRouter(projectRoot) {
1002
2218
  const routes = /* @__PURE__ */ new Map();
1003
2219
  let hashRouting = false;
1004
2220
  for (const file of files) {
1005
- const content = readTextFile(join2(projectRoot, file));
2221
+ const content = readTextFile(join3(projectRoot, file));
1006
2222
  if (!content) continue;
1007
2223
  if (content.includes("HashRouter") || content.includes("createHashRouter")) hashRouting = true;
1008
2224
  const jsxRouteRegex = /<Route\b[^>]*\bpath\s*=\s*["']([^"']+)["']/g;
@@ -1021,7 +2237,7 @@ function scanReactRouter(projectRoot) {
1021
2237
  }
1022
2238
  function scanRoutes(projectRoot, detection) {
1023
2239
  const appRoutes = ["src/app", "app"].flatMap(
1024
- (dir) => existsSync2(join2(projectRoot, dir)) ? walkNextAppRoutes(join2(projectRoot, dir), projectRoot, []) : []
2240
+ (dir) => existsSync3(join3(projectRoot, dir)) ? walkNextAppRoutes(join3(projectRoot, dir), projectRoot, []) : []
1025
2241
  );
1026
2242
  const pagesRoutes = ["src/pages", "pages"].flatMap((dir) => scanFileRoutes(projectRoot, dir));
1027
2243
  if (detection.framework === "nextjs") {
@@ -1044,10 +2260,10 @@ function scanRoutes(projectRoot, detection) {
1044
2260
  const reactRouter = scanReactRouter(projectRoot);
1045
2261
  if (reactRouter.routes.length > 0) return { strategy: "react-router", routes: reactRouter.routes };
1046
2262
  if (pagesRoutes.length > 0) return { strategy: "pages-router", routes: pagesRoutes };
1047
- if (existsSync2(join2(projectRoot, "index.html"))) {
2263
+ if (existsSync3(join3(projectRoot, "index.html"))) {
1048
2264
  return { strategy: "static-html", routes: [{ path: "/", file: "index.html", hasLayout: false }] };
1049
2265
  }
1050
- if (existsSync2(join2(projectRoot, "docs", "index.html"))) {
2266
+ if (existsSync3(join3(projectRoot, "docs", "index.html"))) {
1051
2267
  return { strategy: "static-html", routes: [{ path: "/", file: "docs/index.html", hasLayout: false }] };
1052
2268
  }
1053
2269
  return { strategy: "none", routes: [] };
@@ -1089,12 +2305,12 @@ function scanStyling(projectRoot, detection) {
1089
2305
  let configFile = null;
1090
2306
  let approach = "unknown";
1091
2307
  const tailwindConfig = ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs", "tailwind.config.cjs"].find(
1092
- (file) => existsSync2(join2(projectRoot, file))
2308
+ (file) => existsSync3(join3(projectRoot, file))
1093
2309
  );
1094
2310
  if (tailwindConfig || deps.tailwindcss) {
1095
2311
  approach = "tailwind";
1096
2312
  configFile = tailwindConfig ?? "package.json";
1097
- } else if (deps["@decantr/css"] || existsSync2(join2(projectRoot, "src/styles/tokens.css")) && existsSync2(join2(projectRoot, "src/styles/treatments.css"))) {
2313
+ } else if (deps["@decantr/css"] || existsSync3(join3(projectRoot, "src/styles/tokens.css")) && existsSync3(join3(projectRoot, "src/styles/treatments.css"))) {
1098
2314
  approach = "decantr-css";
1099
2315
  configFile = deps["@decantr/css"] ? "package.json" : "src/styles/tokens.css";
1100
2316
  } else if (deps.bootstrap) {
@@ -1112,7 +2328,7 @@ function scanStyling(projectRoot, detection) {
1112
2328
  approach = "css";
1113
2329
  }
1114
2330
  for (const file of cssFiles.slice(0, 80)) {
1115
- const content = readTextFile(join2(projectRoot, file), 256 * 1024);
2331
+ const content = readTextFile(join3(projectRoot, file), 256 * 1024);
1116
2332
  if (!content) continue;
1117
2333
  const evidence = extractCssEvidence(content);
1118
2334
  cssVariableCount += evidence.variables;
@@ -1130,7 +2346,7 @@ function scanStyling(projectRoot, detection) {
1130
2346
  };
1131
2347
  }
1132
2348
  function findAssistantRules(projectRoot) {
1133
- return RULE_FILES.filter((file) => existsSync2(join2(projectRoot, file)));
2349
+ return RULE_FILES.filter((file) => existsSync3(join3(projectRoot, file)));
1134
2350
  }
1135
2351
  function scanStaticHosting(projectRoot, detection) {
1136
2352
  const packageRead = readPackageJson(projectRoot);
@@ -1139,25 +2355,22 @@ function scanStaticHosting(projectRoot, detection) {
1139
2355
  const homepageUrl = typeof pkg?.homepage === "string" ? pkg.homepage : null;
1140
2356
  let basePath = null;
1141
2357
  let hashRouting = false;
1142
- if (homepageUrl?.includes("github.io")) {
2358
+ const homepage = homepageUrl ? parseHttpUrl(homepageUrl) : null;
2359
+ if (homepage && githubPagesOwnerFromHostname(homepage.hostname)) {
1143
2360
  evidence.push("package.json homepage points at GitHub Pages");
1144
- try {
1145
- const url = new URL(homepageUrl);
1146
- basePath = url.pathname && url.pathname !== "/" ? url.pathname : null;
1147
- } catch {
1148
- }
2361
+ basePath = homepage.pathname && homepage.pathname !== "/" ? homepage.pathname : null;
1149
2362
  }
1150
2363
  if (detection.dependencies["gh-pages"] || pkg?.scripts?.deploy?.includes("gh-pages")) {
1151
2364
  evidence.push("package scripts or dependencies reference gh-pages");
1152
2365
  }
1153
- if (existsSync2(join2(projectRoot, "docs", "index.html"))) evidence.push("docs/index.html can serve GitHub Pages");
1154
- if (existsSync2(join2(projectRoot, "404.html")) || existsSync2(join2(projectRoot, "docs", "404.html"))) {
2366
+ if (existsSync3(join3(projectRoot, "docs", "index.html"))) evidence.push("docs/index.html can serve GitHub Pages");
2367
+ if (existsSync3(join3(projectRoot, "404.html")) || existsSync3(join3(projectRoot, "docs", "404.html"))) {
1155
2368
  evidence.push("404.html fallback is present");
1156
2369
  }
1157
- const workflowDir = join2(projectRoot, ".github", "workflows");
1158
- if (existsSync2(workflowDir)) {
2370
+ const workflowDir = join3(projectRoot, ".github", "workflows");
2371
+ if (existsSync3(workflowDir)) {
1159
2372
  for (const file of walkFiles(workflowDir, { extensions: /* @__PURE__ */ new Set([".yml", ".yaml"]) }).slice(0, 20)) {
1160
- const content = readTextFile(join2(workflowDir, file));
2373
+ const content = readTextFile(join3(workflowDir, file));
1161
2374
  if (content && /pages|gh-pages|upload-pages-artifact|deploy-pages/i.test(content)) {
1162
2375
  evidence.push(`GitHub Pages workflow hint: .github/workflows/${file}`);
1163
2376
  break;
@@ -1166,7 +2379,7 @@ function scanStaticHosting(projectRoot, detection) {
1166
2379
  }
1167
2380
  const sourceFiles = walkFiles(projectRoot, { extensions: SOURCE_EXTENSIONS });
1168
2381
  for (const file of sourceFiles.slice(0, 200)) {
1169
- const content = readTextFile(join2(projectRoot, file), 128 * 1024);
2382
+ const content = readTextFile(join3(projectRoot, file), 128 * 1024);
1170
2383
  if (!content) continue;
1171
2384
  if (content.includes("HashRouter") || content.includes("createHashRouter")) {
1172
2385
  hashRouting = true;
@@ -1175,7 +2388,7 @@ function scanStaticHosting(projectRoot, detection) {
1175
2388
  }
1176
2389
  }
1177
2390
  for (const config of ["vite.config.ts", "vite.config.js", "vite.config.mjs"]) {
1178
- const content = readTextFile(join2(projectRoot, config), 128 * 1024);
2391
+ const content = readTextFile(join3(projectRoot, config), 128 * 1024);
1179
2392
  const baseMatch = content?.match(/\bbase\s*:\s*['"]([^'"]+)['"]/);
1180
2393
  if (baseMatch?.[1]) {
1181
2394
  basePath = baseMatch[1];
@@ -1482,12 +2695,15 @@ function createUnavailableScanReport(input) {
1482
2695
  }
1483
2696
  };
1484
2697
  }
1485
- function decodeHtml(value) {
1486
- return value.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
2698
+ function decodeHtmlText(value) {
2699
+ return decodeHTML(value).replace(/\s+/g, " ").trim();
2700
+ }
2701
+ function decodeHtmlAttributeValue(value) {
2702
+ return decodeHTMLAttribute(value).trim();
1487
2703
  }
1488
2704
  function extractHtmlAttribute(tag, attr) {
1489
2705
  const match = tag.match(new RegExp(`${attr}\\s*=\\s*["']([^"']+)["']`, "i"));
1490
- return match?.[1] ? decodeHtml(match[1]) : null;
2706
+ return match?.[1] ? decodeHtmlAttributeValue(match[1]) : null;
1491
2707
  }
1492
2708
  async function probePublishedSite(url, options = {}) {
1493
2709
  const fetchImpl = options.fetchImpl ?? fetch;
@@ -1519,7 +2735,7 @@ async function probePublishedSite(url, options = {}) {
1519
2735
  checked: true,
1520
2736
  reachable: response.ok,
1521
2737
  status: response.status,
1522
- title: titleMatch?.[1] ? decodeHtml(titleMatch[1].replace(/\s+/g, " ")) : null,
2738
+ title: titleMatch?.[1] ? decodeHtmlText(titleMatch[1]) : null,
1523
2739
  description: descriptionTag ? extractHtmlAttribute(descriptionTag, "content") : null,
1524
2740
  canonicalUrl: canonicalTag ? extractHtmlAttribute(canonicalTag, "href") : null,
1525
2741
  assetHints: {
@@ -1550,22 +2766,21 @@ async function probePublishedSite(url, options = {}) {
1550
2766
  }
1551
2767
  }
1552
2768
  function resolveGitHubScanInput(input) {
1553
- let url;
1554
- try {
1555
- url = new URL(input.trim());
1556
- } catch {
2769
+ const url = parseHttpUrl(input);
2770
+ if (!url) {
1557
2771
  throw new Error("Enter a valid GitHub repository URL or GitHub Pages URL.");
1558
2772
  }
1559
- if (url.protocol !== "https:" && url.protocol !== "http:") {
1560
- throw new Error("Scan URLs must use http or https.");
1561
- }
1562
2773
  const host = url.hostname.toLowerCase();
1563
2774
  if (host === "github.com" || host === "www.github.com") {
1564
- const [owner, repoSegment] = url.pathname.split("/").filter(Boolean);
2775
+ const [ownerSegment, repoSegment] = url.pathname.split("/").filter(Boolean);
2776
+ const owner = normalizeGitHubPathSegment(ownerSegment, "owner");
2777
+ const repo = normalizeGitHubPathSegment(repoSegment, "repo");
1565
2778
  if (!owner || !repoSegment) {
1566
2779
  throw new Error("GitHub repository URLs must include owner and repository.");
1567
2780
  }
1568
- const repo = repoSegment.replace(/\.git$/, "");
2781
+ if (!repo) {
2782
+ throw new Error("GitHub repository URLs must include a valid owner and repository.");
2783
+ }
1569
2784
  return {
1570
2785
  inputKind: "github-repo",
1571
2786
  normalizedInput: `https://github.com/${owner}/${repo}`,
@@ -1578,18 +2793,21 @@ function resolveGitHubScanInput(input) {
1578
2793
  warnings: url.pathname.split("/").filter(Boolean).length > 2 ? ["Extra GitHub URL path segments were ignored."] : []
1579
2794
  };
1580
2795
  }
1581
- if (host.endsWith(".github.io")) {
1582
- const owner = host.slice(0, -".github.io".length);
2796
+ const pagesOwner = githubPagesOwnerFromHostname(host);
2797
+ if (pagesOwner) {
1583
2798
  const segments = url.pathname.split("/").filter(Boolean);
1584
- const repo = segments[0] ?? `${owner}.github.io`;
1585
- const publishedSiteUrl = segments[0] ? `https://${owner}.github.io/${repo}/` : `https://${owner}.github.io/`;
2799
+ const repo = segments[0] ? normalizeGitHubPathSegment(segments[0], "repo") : `${pagesOwner}.github.io`;
2800
+ if (!repo) {
2801
+ throw new Error("GitHub Pages URLs must include a valid owner and repository path.");
2802
+ }
2803
+ const publishedSiteUrl = segments[0] ? `https://${pagesOwner}.github.io/${repo}/` : `https://${pagesOwner}.github.io/`;
1586
2804
  return {
1587
2805
  inputKind: "github-pages",
1588
2806
  normalizedInput: publishedSiteUrl,
1589
2807
  repository: {
1590
- owner,
2808
+ owner: pagesOwner,
1591
2809
  repo,
1592
- url: `https://github.com/${owner}/${repo}`
2810
+ url: `https://github.com/${pagesOwner}/${repo}`
1593
2811
  },
1594
2812
  publishedSiteUrl,
1595
2813
  warnings: segments.length > 1 ? ["Only the first GitHub Pages path segment was used to infer the repository."] : []
@@ -1615,16 +2833,16 @@ function hashString(value) {
1615
2833
  return createHash("sha256").update(value).digest("hex").slice(0, 16);
1616
2834
  }
1617
2835
  function hashFile(path) {
1618
- if (!existsSync3(path)) return null;
2836
+ if (!existsSync4(path)) return null;
1619
2837
  try {
1620
- return createHash("sha256").update(readFileSync3(path)).digest("hex");
2838
+ return createHash("sha256").update(readFileSync5(path)).digest("hex");
1621
2839
  } catch {
1622
2840
  return null;
1623
2841
  }
1624
2842
  }
1625
2843
  function provenanceEntry(projectRoot, relativePath) {
1626
- const path = join3(projectRoot, relativePath);
1627
- if (!existsSync3(path)) {
2844
+ const path = join4(projectRoot, relativePath);
2845
+ if (!existsSync4(path)) {
1628
2846
  return {
1629
2847
  path: relativePath,
1630
2848
  present: false,
@@ -1646,8 +2864,8 @@ function provenanceEntry(projectRoot, relativePath) {
1646
2864
  };
1647
2865
  }
1648
2866
  function provenanceForPath(projectRoot, path) {
1649
- const rel = isAbsolute2(path) ? relative2(projectRoot, path).replace(/\\/g, "/") : path;
1650
- return provenanceEntry(projectRoot, rel && !rel.startsWith("..") ? rel : basename(path));
2867
+ const rel = isAbsolute2(path) ? relative4(projectRoot, path).replace(/\\/g, "/") : path;
2868
+ return provenanceEntry(projectRoot, rel && !rel.startsWith("..") ? rel : basename2(path));
1651
2869
  }
1652
2870
  function redactEvidenceText(projectRoot, value) {
1653
2871
  const normalizedRoot = projectRoot.replace(/\\/g, "/");
@@ -1660,6 +2878,116 @@ function redactEvidenceText(projectRoot, value) {
1660
2878
  function redactEvidenceList(projectRoot, evidence) {
1661
2879
  return evidence.map((entry) => redactEvidenceText(projectRoot, entry));
1662
2880
  }
2881
+ function redactEvidenceValue(projectRoot, value) {
2882
+ if (typeof value === "string") return redactEvidenceText(projectRoot, value);
2883
+ if (Array.isArray(value)) return value.map((entry) => redactEvidenceValue(projectRoot, entry));
2884
+ if (value && typeof value === "object") {
2885
+ return Object.fromEntries(
2886
+ Object.entries(value).map(([key, entry]) => [
2887
+ key,
2888
+ redactEvidenceValue(projectRoot, entry)
2889
+ ])
2890
+ );
2891
+ }
2892
+ return value;
2893
+ }
2894
+ function redactRepairAction(projectRoot, repair) {
2895
+ if (!repair) return void 0;
2896
+ return {
2897
+ id: repair.id,
2898
+ ...repair.payload ? { payload: redactEvidenceValue(projectRoot, repair.payload) } : {}
2899
+ };
2900
+ }
2901
+ function evidenceRepairPlanAction(projectRoot, finding) {
2902
+ const repair = redactRepairAction(projectRoot, finding.repair);
2903
+ const repairId2 = repair?.id ?? "manual-repair";
2904
+ if (repairId2 === "regenerate-typed-graph" || finding.source === "graph") {
2905
+ return {
2906
+ id: repairId2,
2907
+ kind: "regenerate_artifact",
2908
+ target: ".decantr/graph",
2909
+ description: "Regenerate typed Contract graph artifacts from current project sources.",
2910
+ ...repair?.payload ? { payload: repair.payload } : {}
2911
+ };
2912
+ }
2913
+ if (repairId2 === "import-existing-component") {
2914
+ return {
2915
+ id: repairId2,
2916
+ kind: "replace_duplicate_with_import",
2917
+ target: finding.file ? redactEvidenceText(projectRoot, finding.file) : finding.target ? redactEvidenceText(projectRoot, finding.target) : null,
2918
+ description: "Remove the locally redeclared UI primitive and import the existing project-owned component.",
2919
+ ...repair?.payload ? { payload: repair.payload } : {}
2920
+ };
2921
+ }
2922
+ if (repairId2 === "replace-raw-control-with-local-component") {
2923
+ return {
2924
+ id: repairId2,
2925
+ kind: "replace_raw_control_with_component",
2926
+ target: finding.file ? redactEvidenceText(projectRoot, finding.file) : finding.target ? redactEvidenceText(projectRoot, finding.target) : null,
2927
+ description: "Replace the raw JSX control with the existing project-owned primitive component.",
2928
+ ...repair?.payload ? { payload: repair.payload } : {}
2929
+ };
2930
+ }
2931
+ return {
2932
+ id: repairId2,
2933
+ kind: "manual_repair",
2934
+ target: finding.file ? redactEvidenceText(projectRoot, finding.file) : finding.target ? redactEvidenceText(projectRoot, finding.target) : null,
2935
+ description: finding.suggestedFix ?? finding.remediation.summary,
2936
+ ...repair?.payload ? { payload: repair.payload } : {}
2937
+ };
2938
+ }
2939
+ function evidenceRepairReadTargets(projectRoot, finding) {
2940
+ const targets = /* @__PURE__ */ new Set(["DECANTR.md", "decantr.essence.json"]);
2941
+ if (finding.source === "graph") {
2942
+ targets.add(".decantr/graph/graph.manifest.json");
2943
+ targets.add(".decantr/graph/graph.snapshot.json");
2944
+ targets.add(".decantr/graph/graph.diff.json");
2945
+ targets.add(".decantr/graph/snapshots/");
2946
+ }
2947
+ if (finding.source === "style-bridge") {
2948
+ targets.add(".decantr/style-bridge.json");
2949
+ }
2950
+ if (finding.source === "pack" || finding.source === "assertion") {
2951
+ targets.add(".decantr/context/pack-manifest.json");
2952
+ }
2953
+ if (finding.graph?.node_id) {
2954
+ targets.add(".decantr/graph/contract-capsule.json");
2955
+ }
2956
+ if (finding.file) targets.add(redactEvidenceText(projectRoot, finding.file));
2957
+ if (finding.target && !finding.target.startsWith("http")) {
2958
+ targets.add(redactEvidenceText(projectRoot, finding.target));
2959
+ }
2960
+ return [...targets];
2961
+ }
2962
+ function buildProjectHealthRepairPlan(projectRoot, finding) {
2963
+ return {
2964
+ id: `repair-plan:${finding.id}`,
2965
+ findingId: finding.id,
2966
+ diagnosticCode: finding.code ?? null,
2967
+ repairId: finding.repair?.id ?? null,
2968
+ severity: finding.severity,
2969
+ source: finding.source,
2970
+ category: finding.category,
2971
+ graphAnchor: finding.graph ?? null,
2972
+ actions: [evidenceRepairPlanAction(projectRoot, finding)],
2973
+ evidence: redactEvidenceList(projectRoot, finding.evidence).map((entry, index) => ({
2974
+ id: `evidence:${finding.id}:${index + 1}`,
2975
+ text: entry
2976
+ })),
2977
+ readTargets: evidenceRepairReadTargets(projectRoot, finding),
2978
+ preserve: [
2979
+ "existing framework, routing, and styling system",
2980
+ "existing production behavior unrelated to this finding",
2981
+ "accepted local law, style bridge mappings, and graph anchors"
2982
+ ],
2983
+ avoid: [
2984
+ "rewriting unrelated routes",
2985
+ "replacing the app styling system",
2986
+ "regenerating Decantr artifacts unless the finding is about generated context or graph freshness"
2987
+ ],
2988
+ commands: finding.remediation.commands
2989
+ };
2990
+ }
1663
2991
  function assertion(input) {
1664
2992
  return {
1665
2993
  status: "passed",
@@ -1670,7 +2998,7 @@ function createContractAssertions(projectRoot, audit) {
1670
2998
  const assertions = [];
1671
2999
  const essence = audit?.essence;
1672
3000
  const v4 = essence && isV4(essence) ? essence : null;
1673
- const contextDir = join3(projectRoot, ".decantr", "context");
3001
+ const contextDir = join4(projectRoot, ".decantr", "context");
1674
3002
  const packManifest = audit?.packManifest ?? null;
1675
3003
  assertions.push(
1676
3004
  assertion({
@@ -1680,7 +3008,7 @@ function createContractAssertions(projectRoot, audit) {
1680
3008
  rule: "essence-present",
1681
3009
  status: essence ? "passed" : "failed",
1682
3010
  message: essence ? "Decantr Essence contract is present." : "No Decantr Essence contract was found.",
1683
- evidence: [redactEvidenceText(projectRoot, join3(projectRoot, "decantr.essence.json"))],
3011
+ evidence: [redactEvidenceText(projectRoot, join4(projectRoot, "decantr.essence.json"))],
1684
3012
  suggestedFix: essence ? void 0 : "Run `decantr init` or restore decantr.essence.json."
1685
3013
  })
1686
3014
  );
@@ -1752,7 +3080,7 @@ function createContractAssertions(projectRoot, audit) {
1752
3080
  rule: "pack-manifest-present",
1753
3081
  status: packManifest ? "passed" : "failed",
1754
3082
  message: packManifest ? "Compiled execution pack manifest is present." : "Compiled execution pack manifest is missing.",
1755
- evidence: [redactEvidenceText(projectRoot, join3(contextDir, "pack-manifest.json"))],
3083
+ evidence: [redactEvidenceText(projectRoot, join4(contextDir, "pack-manifest.json"))],
1756
3084
  suggestedFix: packManifest ? void 0 : "Run `decantr registry compile-packs decantr.essence.json --write-context` to hydrate the full context pack bundle."
1757
3085
  })
1758
3086
  );
@@ -1764,21 +3092,21 @@ function createContractAssertions(projectRoot, audit) {
1764
3092
  rule: "review-pack-present",
1765
3093
  status: audit?.reviewPack ? "passed" : "failed",
1766
3094
  message: audit?.reviewPack ? "Compiled review pack is present." : "Compiled review pack is missing.",
1767
- evidence: [redactEvidenceText(projectRoot, join3(contextDir, "review-pack.json"))],
3095
+ evidence: [redactEvidenceText(projectRoot, join4(contextDir, "review-pack.json"))],
1768
3096
  suggestedFix: audit?.reviewPack ? void 0 : "Run `decantr registry compile-packs decantr.essence.json --write-context` so critique has the compiled review contract."
1769
3097
  })
1770
3098
  );
1771
- const tokensPath = join3(projectRoot, "src", "styles", "tokens.css");
3099
+ const tokensPath = join4(projectRoot, "src", "styles", "tokens.css");
1772
3100
  assertions.push(
1773
3101
  assertion({
1774
3102
  id: "contract.design-token.tokens-file",
1775
3103
  category: "design-token",
1776
- severity: existsSync3(tokensPath) ? "info" : "warn",
3104
+ severity: existsSync4(tokensPath) ? "info" : "warn",
1777
3105
  rule: "tokens-file-present",
1778
- status: existsSync3(tokensPath) ? "passed" : "failed",
1779
- message: existsSync3(tokensPath) ? "Decantr token CSS file is present." : "Decantr token CSS file was not found.",
3106
+ status: existsSync4(tokensPath) ? "passed" : "failed",
3107
+ message: existsSync4(tokensPath) ? "Decantr token CSS file is present." : "Decantr token CSS file was not found.",
1780
3108
  evidence: [redactEvidenceText(projectRoot, tokensPath)],
1781
- suggestedFix: existsSync3(tokensPath) ? void 0 : "Run `decantr refresh` or map Decantr tokens into the existing styling system."
3109
+ suggestedFix: existsSync4(tokensPath) ? void 0 : "Run `decantr refresh` or map Decantr tokens into the existing styling system."
1782
3110
  })
1783
3111
  );
1784
3112
  return assertions;
@@ -1797,7 +3125,7 @@ function createEvidenceBundle(input) {
1797
3125
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1798
3126
  project: {
1799
3127
  id: projectId,
1800
- rootLabel: basename(input.projectRoot) || "project"
3128
+ rootLabel: basename2(input.projectRoot) || "project"
1801
3129
  },
1802
3130
  toolchain: {
1803
3131
  verifierVersion: input.verifierVersion ?? null
@@ -1826,12 +3154,17 @@ function createEvidenceBundle(input) {
1826
3154
  essence: provenanceEntry(input.projectRoot, "decantr.essence.json"),
1827
3155
  packManifest: provenanceEntry(input.projectRoot, ".decantr/context/pack-manifest.json"),
1828
3156
  reviewPack: provenanceEntry(input.projectRoot, ".decantr/context/review-pack.json"),
3157
+ graphSnapshot: provenanceEntry(input.projectRoot, ".decantr/graph/graph.snapshot.json"),
3158
+ graphManifest: provenanceEntry(input.projectRoot, ".decantr/graph/graph.manifest.json"),
3159
+ graphDiff: provenanceEntry(input.projectRoot, ".decantr/graph/graph.diff.json"),
3160
+ contractCapsule: provenanceEntry(input.projectRoot, ".decantr/graph/contract-capsule.json"),
1829
3161
  ...input.workspaceConfigPath ? { workspaceConfig: provenanceForPath(input.projectRoot, input.workspaceConfigPath) } : {},
1830
3162
  ...input.designTokensPath ? { designTokens: provenanceForPath(input.projectRoot, input.designTokensPath) } : {}
1831
3163
  },
1832
3164
  assertions,
1833
3165
  findings: input.report.findings.map((finding) => ({
1834
3166
  id: finding.id,
3167
+ code: finding.code,
1835
3168
  source: finding.source,
1836
3169
  category: finding.category,
1837
3170
  severity: finding.severity,
@@ -1840,6 +3173,9 @@ function createEvidenceBundle(input) {
1840
3173
  target: finding.target ? redactEvidenceText(input.projectRoot, finding.target) : void 0,
1841
3174
  rule: finding.rule,
1842
3175
  suggestedFix: finding.suggestedFix,
3176
+ graph: finding.graph,
3177
+ repair: redactRepairAction(input.projectRoot, finding.repair),
3178
+ repairPlan: buildProjectHealthRepairPlan(input.projectRoot, finding),
1843
3179
  remediationSummary: finding.remediation.summary,
1844
3180
  commands: finding.remediation.commands,
1845
3181
  promptCommand: `decantr health --prompt ${finding.id}`
@@ -1883,21 +3219,21 @@ function scoreRatio(numerator, denominator) {
1883
3219
  return Math.min(5, Math.max(1, Math.round(numerator / denominator * 5)));
1884
3220
  }
1885
3221
  function readJsonIfExists(path) {
1886
- if (!existsSync3(path)) return null;
3222
+ if (!existsSync4(path)) return null;
1887
3223
  try {
1888
- return JSON.parse(readFileSync3(path, "utf-8"));
3224
+ return JSON.parse(readFileSync5(path, "utf-8"));
1889
3225
  } catch {
1890
3226
  return null;
1891
3227
  }
1892
3228
  }
1893
3229
  function loadReviewPack(projectRoot) {
1894
3230
  return readJsonIfExists(
1895
- join3(projectRoot, ".decantr", "context", "review-pack.json")
3231
+ join4(projectRoot, ".decantr", "context", "review-pack.json")
1896
3232
  );
1897
3233
  }
1898
3234
  function loadPackManifest(projectRoot) {
1899
3235
  return readJsonIfExists(
1900
- join3(projectRoot, ".decantr", "context", "pack-manifest.json")
3236
+ join4(projectRoot, ".decantr", "context", "pack-manifest.json")
1901
3237
  );
1902
3238
  }
1903
3239
  function collectPackManifestReferences(packManifest) {
@@ -1946,14 +3282,14 @@ function collectPackManifestReferences(packManifest) {
1946
3282
  }
1947
3283
  function collectMissingPackManifestFiles(projectRoot, packManifest = loadPackManifest(projectRoot)) {
1948
3284
  if (!packManifest) return [];
1949
- const contextDir = join3(projectRoot, ".decantr", "context");
3285
+ const contextDir = join4(projectRoot, ".decantr", "context");
1950
3286
  const missing = [];
1951
3287
  for (const reference of collectPackManifestReferences(packManifest)) {
1952
3288
  for (const field of ["markdown", "json"]) {
1953
3289
  const fileName = reference[field];
1954
3290
  if (!fileName) continue;
1955
- const absolutePath = join3(contextDir, fileName);
1956
- if (existsSync3(absolutePath)) continue;
3291
+ const absolutePath = join4(contextDir, fileName);
3292
+ if (existsSync4(absolutePath)) continue;
1957
3293
  missing.push({
1958
3294
  entryId: reference.entryId,
1959
3295
  kind: reference.kind,
@@ -1967,13 +3303,13 @@ function collectMissingPackManifestFiles(projectRoot, packManifest = loadPackMan
1967
3303
  }
1968
3304
  function readTextIfExists(path) {
1969
3305
  try {
1970
- return existsSync3(path) ? readFileSync3(path, "utf-8") : "";
3306
+ return existsSync4(path) ? readFileSync5(path, "utf-8") : "";
1971
3307
  } catch {
1972
3308
  return "";
1973
3309
  }
1974
3310
  }
1975
3311
  function readProjectAdoptionMode(projectRoot) {
1976
- const projectJson = readJsonIfExists(join3(projectRoot, ".decantr", "project.json"));
3312
+ const projectJson = readJsonIfExists(join4(projectRoot, ".decantr", "project.json"));
1977
3313
  const adoptionMode = projectJson?.initialized?.adoptionMode;
1978
3314
  return typeof adoptionMode === "string" ? adoptionMode : null;
1979
3315
  }
@@ -2059,7 +3395,7 @@ function collectProjectSourceFiles(projectRoot) {
2059
3395
  "hooks",
2060
3396
  "providers",
2061
3397
  "server"
2062
- ].map((dir) => join3(projectRoot, dir)).filter((dir) => existsSync3(dir));
3398
+ ].map((dir) => join4(projectRoot, dir)).filter((dir) => existsSync4(dir));
2063
3399
  const rootFileCandidates = [
2064
3400
  "middleware.ts",
2065
3401
  "middleware.tsx",
@@ -2073,7 +3409,7 @@ function collectProjectSourceFiles(projectRoot) {
2073
3409
  "proxy.jsx",
2074
3410
  "proxy.mts",
2075
3411
  "proxy.cts"
2076
- ].map((file) => join3(projectRoot, file)).filter((file) => existsSync3(file));
3412
+ ].map((file) => join4(projectRoot, file)).filter((file) => existsSync4(file));
2077
3413
  const files = /* @__PURE__ */ new Set();
2078
3414
  const ignoredDirNames = /* @__PURE__ */ new Set([
2079
3415
  "node_modules",
@@ -2084,9 +3420,9 @@ function collectProjectSourceFiles(projectRoot) {
2084
3420
  "coverage"
2085
3421
  ]);
2086
3422
  const walk = (dir) => {
2087
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
3423
+ for (const entry of readdirSync4(dir, { withFileTypes: true })) {
2088
3424
  if (ignoredDirNames.has(entry.name)) continue;
2089
- const absolutePath = join3(dir, entry.name);
3425
+ const absolutePath = join4(dir, entry.name);
2090
3426
  if (entry.isDirectory()) {
2091
3427
  walk(absolutePath);
2092
3428
  continue;
@@ -2116,8 +3452,8 @@ function buildSourceAuditEvidence(summary, bucket, label) {
2116
3452
  function isAuditableStyleFile(filePath) {
2117
3453
  return /\.css$/i.test(filePath);
2118
3454
  }
2119
- function collectProjectStyleFiles(projectRoot) {
2120
- const candidates = ["src", "app", "styles"].map((dir) => join3(projectRoot, dir)).filter((dir) => existsSync3(dir));
3455
+ function collectProjectStyleFiles2(projectRoot) {
3456
+ const candidates = ["src", "app", "styles"].map((dir) => join4(projectRoot, dir)).filter((dir) => existsSync4(dir));
2121
3457
  const files = /* @__PURE__ */ new Set();
2122
3458
  const ignoredDirNames = /* @__PURE__ */ new Set([
2123
3459
  "node_modules",
@@ -2128,9 +3464,9 @@ function collectProjectStyleFiles(projectRoot) {
2128
3464
  "coverage"
2129
3465
  ]);
2130
3466
  const walk = (dir) => {
2131
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
3467
+ for (const entry of readdirSync4(dir, { withFileTypes: true })) {
2132
3468
  if (ignoredDirNames.has(entry.name)) continue;
2133
- const absolutePath = join3(dir, entry.name);
3469
+ const absolutePath = join4(dir, entry.name);
2134
3470
  if (entry.isDirectory()) {
2135
3471
  walk(absolutePath);
2136
3472
  continue;
@@ -2158,15 +3494,15 @@ function countReducedMotionSignals(code) {
2158
3494
  return patterns.reduce((count, pattern) => count + (pattern.test(code) ? 1 : 0), 0);
2159
3495
  }
2160
3496
  function hasModuleDirective(filePath, code, directive) {
2161
- const sourceFile = ts.createSourceFile(
3497
+ const sourceFile = ts3.createSourceFile(
2162
3498
  filePath,
2163
3499
  code,
2164
- ts.ScriptTarget.Latest,
3500
+ ts3.ScriptTarget.Latest,
2165
3501
  true,
2166
3502
  getScriptKind(filePath)
2167
3503
  );
2168
3504
  for (const statement of sourceFile.statements) {
2169
- if (ts.isExpressionStatement(statement) && ts.isStringLiteralLike(statement.expression)) {
3505
+ if (ts3.isExpressionStatement(statement) && ts3.isStringLiteralLike(statement.expression)) {
2170
3506
  if (statement.expression.text === directive) {
2171
3507
  return true;
2172
3508
  }
@@ -2182,20 +3518,20 @@ function importDeclarationHasRuntimeBinding(statement) {
2182
3518
  if (clause.isTypeOnly) return false;
2183
3519
  if (clause.name) return true;
2184
3520
  if (!clause.namedBindings) return true;
2185
- if (ts.isNamespaceImport(clause.namedBindings)) return true;
3521
+ if (ts3.isNamespaceImport(clause.namedBindings)) return true;
2186
3522
  return clause.namedBindings.elements.some((element) => !element.isTypeOnly);
2187
3523
  }
2188
3524
  function collectRuntimeImportSpecifiers(entry) {
2189
- const sourceFile = ts.createSourceFile(
3525
+ const sourceFile = ts3.createSourceFile(
2190
3526
  entry.relativePath,
2191
3527
  entry.code,
2192
- ts.ScriptTarget.Latest,
3528
+ ts3.ScriptTarget.Latest,
2193
3529
  true,
2194
3530
  getScriptKind(entry.relativePath)
2195
3531
  );
2196
3532
  const specifiers = [];
2197
3533
  for (const statement of sourceFile.statements) {
2198
- if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier) && importDeclarationHasRuntimeBinding(statement)) {
3534
+ if (ts3.isImportDeclaration(statement) && ts3.isStringLiteralLike(statement.moduleSpecifier) && importDeclarationHasRuntimeBinding(statement)) {
2199
3535
  specifiers.push(statement.moduleSpecifier.text);
2200
3536
  }
2201
3537
  }
@@ -2204,7 +3540,7 @@ function collectRuntimeImportSpecifiers(entry) {
2204
3540
  function resolveSourceImportTarget(projectRoot, sourceAbsolutePath, specifier) {
2205
3541
  let basePath = null;
2206
3542
  if (specifier.startsWith("@/")) {
2207
- basePath = join3(projectRoot, "src", specifier.slice(2));
3543
+ basePath = join4(projectRoot, "src", specifier.slice(2));
2208
3544
  } else if (specifier.startsWith("./") || specifier.startsWith("../")) {
2209
3545
  basePath = resolve(dirname(sourceAbsolutePath), specifier);
2210
3546
  }
@@ -2217,14 +3553,14 @@ function resolveSourceImportTarget(projectRoot, sourceAbsolutePath, specifier) {
2217
3553
  `${basePath}.jsx`,
2218
3554
  `${basePath}.mts`,
2219
3555
  `${basePath}.cts`,
2220
- join3(basePath, "index.ts"),
2221
- join3(basePath, "index.tsx"),
2222
- join3(basePath, "index.js"),
2223
- join3(basePath, "index.jsx")
3556
+ join4(basePath, "index.ts"),
3557
+ join4(basePath, "index.tsx"),
3558
+ join4(basePath, "index.js"),
3559
+ join4(basePath, "index.jsx")
2224
3560
  ];
2225
3561
  for (const candidate of candidates) {
2226
- if (existsSync3(candidate) && isAuditableSourceFile(candidate)) {
2227
- return relative2(projectRoot, candidate) || candidate;
3562
+ if (existsSync4(candidate) && isAuditableSourceFile(candidate)) {
3563
+ return relative4(projectRoot, candidate) || candidate;
2228
3564
  }
2229
3565
  }
2230
3566
  return null;
@@ -2269,12 +3605,11 @@ function isClientAuthHeaderSource(relativePath, code, clientReachableFiles) {
2269
3605
  }
2270
3606
  return /(?:^|\/)(?:components|routes|pages|hooks|providers)\//i.test(normalized);
2271
3607
  }
2272
- function auditProjectSourceTree(projectRoot) {
2273
- const sourceFiles = collectProjectSourceFiles(projectRoot);
3608
+ function auditProjectSourceTree(projectRoot, sourceFiles = collectProjectSourceFiles(projectRoot)) {
2274
3609
  const sourceEntries = sourceFiles.map((sourceFile) => ({
2275
3610
  absolutePath: sourceFile,
2276
- relativePath: relative2(projectRoot, sourceFile) || sourceFile,
2277
- code: readFileSync3(sourceFile, "utf-8")
3611
+ relativePath: relative4(projectRoot, sourceFile) || sourceFile,
3612
+ code: readFileSync5(sourceFile, "utf-8")
2278
3613
  })).filter((entry) => !isNonProductionSourceAuditFile(entry.relativePath));
2279
3614
  const clientReachableFiles = collectClientReachableSourceFiles(projectRoot, sourceEntries);
2280
3615
  const summary = {
@@ -2580,15 +3915,15 @@ function auditProjectSourceTree(projectRoot) {
2580
3915
  return summary;
2581
3916
  }
2582
3917
  function auditProjectStyleContracts(projectRoot) {
2583
- const styleFiles = collectProjectStyleFiles(projectRoot);
3918
+ const styleFiles = collectProjectStyleFiles2(projectRoot);
2584
3919
  const summary = {
2585
3920
  filesChecked: styleFiles.length,
2586
3921
  focusVisibleSignals: createSourceAuditBucket(),
2587
3922
  reducedMotionSignals: createSourceAuditBucket()
2588
3923
  };
2589
3924
  for (const styleFile of styleFiles) {
2590
- const relativePath = relative2(projectRoot, styleFile) || styleFile;
2591
- const css = readFileSync3(styleFile, "utf-8");
3925
+ const relativePath = relative4(projectRoot, styleFile) || styleFile;
3926
+ const css = readFileSync5(styleFile, "utf-8");
2592
3927
  recordSourceAudit(summary.focusVisibleSignals, relativePath, countFocusVisibleSignals(css));
2593
3928
  recordSourceAudit(summary.reducedMotionSignals, relativePath, countReducedMotionSignals(css));
2594
3929
  }
@@ -2597,15 +3932,15 @@ function auditProjectStyleContracts(projectRoot) {
2597
3932
  function buildRegistryContext(projectRoot) {
2598
3933
  const themeRegistry = /* @__PURE__ */ new Map();
2599
3934
  const patternRegistry = /* @__PURE__ */ new Map();
2600
- const cacheDir = join3(projectRoot, ".decantr", "cache");
2601
- const customDir = join3(projectRoot, ".decantr", "custom");
2602
- const cachedThemesDir = join3(cacheDir, "@official", "themes");
3935
+ const cacheDir = join4(projectRoot, ".decantr", "cache");
3936
+ const customDir = join4(projectRoot, ".decantr", "custom");
3937
+ const cachedThemesDir = join4(cacheDir, "@official", "themes");
2603
3938
  try {
2604
- if (existsSync3(cachedThemesDir)) {
2605
- for (const file of readdirSync3(cachedThemesDir).filter(
3939
+ if (existsSync4(cachedThemesDir)) {
3940
+ for (const file of readdirSync4(cachedThemesDir).filter(
2606
3941
  (name) => name.endsWith(".json") && name !== "index.json"
2607
3942
  )) {
2608
- const data = JSON.parse(readFileSync3(join3(cachedThemesDir, file), "utf-8"));
3943
+ const data = JSON.parse(readFileSync5(join4(cachedThemesDir, file), "utf-8"));
2609
3944
  if (data.id && !themeRegistry.has(data.id)) {
2610
3945
  themeRegistry.set(data.id, { modes: data.modes || ["light", "dark"] });
2611
3946
  }
@@ -2613,11 +3948,11 @@ function buildRegistryContext(projectRoot) {
2613
3948
  }
2614
3949
  } catch {
2615
3950
  }
2616
- const customThemesDir = join3(customDir, "themes");
3951
+ const customThemesDir = join4(customDir, "themes");
2617
3952
  try {
2618
- if (existsSync3(customThemesDir)) {
2619
- for (const file of readdirSync3(customThemesDir).filter((name) => name.endsWith(".json"))) {
2620
- const data = JSON.parse(readFileSync3(join3(customThemesDir, file), "utf-8"));
3953
+ if (existsSync4(customThemesDir)) {
3954
+ for (const file of readdirSync4(customThemesDir).filter((name) => name.endsWith(".json"))) {
3955
+ const data = JSON.parse(readFileSync5(join4(customThemesDir, file), "utf-8"));
2621
3956
  if (data.id) {
2622
3957
  themeRegistry.set(`custom:${data.id}`, { modes: data.modes || ["light", "dark"] });
2623
3958
  }
@@ -2625,13 +3960,13 @@ function buildRegistryContext(projectRoot) {
2625
3960
  }
2626
3961
  } catch {
2627
3962
  }
2628
- const cachedPatternsDir = join3(cacheDir, "@official", "patterns");
3963
+ const cachedPatternsDir = join4(cacheDir, "@official", "patterns");
2629
3964
  try {
2630
- if (existsSync3(cachedPatternsDir)) {
2631
- for (const file of readdirSync3(cachedPatternsDir).filter(
3965
+ if (existsSync4(cachedPatternsDir)) {
3966
+ for (const file of readdirSync4(cachedPatternsDir).filter(
2632
3967
  (name) => name.endsWith(".json") && name !== "index.json"
2633
3968
  )) {
2634
- const data = JSON.parse(readFileSync3(join3(cachedPatternsDir, file), "utf-8"));
3969
+ const data = JSON.parse(readFileSync5(join4(cachedPatternsDir, file), "utf-8"));
2635
3970
  if (data.id && !patternRegistry.has(data.id)) {
2636
3971
  patternRegistry.set(data.id, data);
2637
3972
  }
@@ -2945,8 +4280,8 @@ function extractFailedRouteDocumentHardening(runtimeAudit) {
2945
4280
  return runtimeAudit.failures.filter((failure) => failure.startsWith("route-document-hardening-failed:")).map((failure) => normalizeRouteHint2(failure.slice("route-document-hardening-failed:".length))).filter(Boolean);
2946
4281
  }
2947
4282
  function appendRuntimeAuditFindings(findings, runtimeAudit, projectRoot, topology, sourceAudit) {
2948
- const distPath = join3(projectRoot, "dist");
2949
- const indexPath = join3(distPath, "index.html");
4283
+ const distPath = join4(projectRoot, "dist");
4284
+ const indexPath = join4(distPath, "index.html");
2950
4285
  const isFrameworkBuildOutput = runtimeAudit.failures.includes("next-build-output");
2951
4286
  if (!runtimeAudit.distPresent) {
2952
4287
  findings.push(
@@ -4590,6 +5925,88 @@ function appendSourceAuditFindings(findings, sourceAudit, essence, reviewPack, a
4590
5925
  );
4591
5926
  }
4592
5927
  }
5928
+ function appendComponentReuseFindings(findings, audit) {
5929
+ for (const finding of audit.findings.slice(0, 8)) {
5930
+ findings.push(
5931
+ makeFinding({
5932
+ id: COMPONENT_REUSE_RULE_ID,
5933
+ code: "COMP001",
5934
+ category: "Component Reuse",
5935
+ severity: "warn",
5936
+ message: `${finding.name} is reimplemented locally even though a reusable ${finding.name} component already exists.`,
5937
+ evidence: finding.evidence,
5938
+ target: finding.name,
5939
+ file: finding.file,
5940
+ rule: COMPONENT_REUSE_RULE_ID,
5941
+ suggestedFix: `Import ${finding.name} from ${finding.canonicalFile} instead of redefining it in ${finding.file}.`,
5942
+ repair: {
5943
+ id: "import-existing-component",
5944
+ payload: {
5945
+ component: finding.name,
5946
+ file: finding.file,
5947
+ canonical_file: finding.canonicalFile
5948
+ }
5949
+ }
5950
+ })
5951
+ );
5952
+ }
5953
+ for (const finding of audit.rawControlFindings.slice(0, 8)) {
5954
+ findings.push(
5955
+ makeFinding({
5956
+ id: RAW_CONTROL_REUSE_RULE_ID,
5957
+ code: "COMP010",
5958
+ category: "Component Reuse",
5959
+ severity: "warn",
5960
+ message: `${finding.file} renders raw <${finding.element}> even though the project has a reusable ${finding.component} component.`,
5961
+ evidence: finding.evidence,
5962
+ target: finding.component,
5963
+ file: finding.file,
5964
+ rule: RAW_CONTROL_REUSE_RULE_ID,
5965
+ suggestedFix: `Use ${finding.component} from ${finding.canonicalFile} instead of raw <${finding.element}> in ${finding.file}.`,
5966
+ repair: {
5967
+ id: "replace-raw-control-with-local-component",
5968
+ payload: {
5969
+ component: finding.component,
5970
+ element: finding.element,
5971
+ file: finding.file,
5972
+ canonical_file: finding.canonicalFile
5973
+ }
5974
+ }
5975
+ })
5976
+ );
5977
+ }
5978
+ }
5979
+ function appendStyleBridgeDriftFindings(findings, audit) {
5980
+ for (const finding of audit.findings.slice(0, 8)) {
5981
+ findings.push(
5982
+ makeFinding({
5983
+ id: STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID,
5984
+ code: "TOKEN010",
5985
+ category: "Style Bridge",
5986
+ severity: "warn",
5987
+ message: `${finding.file} uses arbitrary styling even though an accepted style bridge defines project-owned token/class authority.`,
5988
+ evidence: finding.evidence,
5989
+ target: finding.value,
5990
+ file: finding.file,
5991
+ rule: STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID,
5992
+ suggestedFix: "Replace the arbitrary Tailwind value with an accepted project token or class from .decantr/style-bridge.json, or update the style bridge if this value is now approved design authority.",
5993
+ repair: {
5994
+ id: "replace-arbitrary-style-with-bridge-token",
5995
+ payload: {
5996
+ file: finding.file,
5997
+ line: finding.line,
5998
+ value: finding.value,
5999
+ source: finding.source,
6000
+ property: finding.property,
6001
+ bridge_mappings: finding.bridgeMappingIds,
6002
+ token_hints: finding.tokenHints,
6003
+ class_hints: finding.classHints
6004
+ }
6005
+ }
6006
+ })
6007
+ );
6008
+ }
6009
+ }
4593
6010
  function appendStyleContractFindings(findings, styleAudit, essence) {
4594
6011
  if (essenceRequiresFocusVisible(essence) && styleAudit.focusVisibleSignals.count === 0) {
4595
6012
  findings.push(
@@ -4625,7 +6042,7 @@ function appendStyleContractFindings(findings, styleAudit, essence) {
4625
6042
  }
4626
6043
  }
4627
6044
  async function auditProject(projectRoot) {
4628
- const essencePath = join3(projectRoot, "decantr.essence.json");
6045
+ const essencePath = join4(projectRoot, "decantr.essence.json");
4629
6046
  const findings = [];
4630
6047
  const reviewPack = loadReviewPack(projectRoot);
4631
6048
  const packManifest = loadPackManifest(projectRoot);
@@ -4633,7 +6050,7 @@ async function auditProject(projectRoot) {
4633
6050
  const packHydrationOptional = adoptionMode === "contract-only" || adoptionMode === "style-bridge";
4634
6051
  const packHydrationSeverity = packHydrationOptional ? "info" : "warn";
4635
6052
  const runtimeAudit = emptyRuntimeAudit();
4636
- if (!existsSync3(essencePath)) {
6053
+ if (!existsSync4(essencePath)) {
4637
6054
  findings.push(
4638
6055
  makeFinding({
4639
6056
  id: "essence-missing",
@@ -4668,7 +6085,7 @@ async function auditProject(projectRoot) {
4668
6085
  }
4669
6086
  let essence = null;
4670
6087
  try {
4671
- essence = JSON.parse(readFileSync3(essencePath, "utf-8"));
6088
+ essence = JSON.parse(readFileSync5(essencePath, "utf-8"));
4672
6089
  } catch (error) {
4673
6090
  findings.push(
4674
6091
  makeFinding({
@@ -4711,7 +6128,7 @@ async function auditProject(projectRoot) {
4711
6128
  category: "Execution Packs",
4712
6129
  severity: packHydrationSeverity,
4713
6130
  message: packHydrationOptional ? "Compiled execution pack manifest is not hydrated yet; this is optional for contract-only/style-bridge Brownfield adoption." : "Compiled execution pack manifest is missing.",
4714
- evidence: [join3(projectRoot, ".decantr", "context", "pack-manifest.json")],
6131
+ evidence: [join4(projectRoot, ".decantr", "context", "pack-manifest.json")],
4715
6132
  suggestedFix: packHydrationOptional ? "Optional: run `decantr registry compile-packs decantr.essence.json --write-context` when you want hosted page packs and review packs for richer assistant context." : "Run `decantr registry compile-packs decantr.essence.json --write-context` to hydrate scaffold, review, mutation, section, and page packs."
4716
6133
  })
4717
6134
  );
@@ -4775,12 +6192,15 @@ async function auditProject(projectRoot) {
4775
6192
  category: "Review Contract",
4776
6193
  severity: packHydrationSeverity,
4777
6194
  message: packHydrationOptional ? "The compiled review pack file is not hydrated yet; contract-only/style-bridge Brownfield projects can continue without it." : "The compiled review pack file is missing.",
4778
- evidence: [join3(projectRoot, ".decantr", "context", "review-pack.json")],
6195
+ evidence: [join4(projectRoot, ".decantr", "context", "review-pack.json")],
4779
6196
  suggestedFix: packHydrationOptional ? "Optional: hydrate hosted packs later if you want critique consumers to anchor findings to the compiled review contract." : "Hydrate the full hosted context bundle with `decantr registry compile-packs decantr.essence.json --write-context` so critique consumers can anchor findings to the compiled review contract."
4780
6197
  })
4781
6198
  );
4782
6199
  }
4783
- const sourceAudit = auditProjectSourceTree(projectRoot);
6200
+ const projectSourceFiles = collectProjectSourceFiles(projectRoot);
6201
+ const sourceAudit = auditProjectSourceTree(projectRoot, projectSourceFiles);
6202
+ const componentReuseAudit = auditComponentReuse(projectRoot, projectSourceFiles);
6203
+ const styleBridgeDriftAudit = auditStyleBridgeDrift(projectRoot, projectSourceFiles);
4784
6204
  const styleAudit = auditProjectStyleContracts(projectRoot);
4785
6205
  const checkedRuntimeAudit = await runRuntimeAudit(projectRoot, essence);
4786
6206
  appendRuntimeAuditFindings(
@@ -4791,6 +6211,8 @@ async function auditProject(projectRoot) {
4791
6211
  sourceAudit
4792
6212
  );
4793
6213
  appendSourceAuditFindings(findings, sourceAudit, essence, reviewPack, adoptionMode);
6214
+ appendComponentReuseFindings(findings, componentReuseAudit);
6215
+ appendStyleBridgeDriftFindings(findings, styleBridgeDriftAudit);
4794
6216
  appendStyleContractFindings(findings, styleAudit, essence);
4795
6217
  const summary = {
4796
6218
  errorCount: findings.filter((finding) => finding.severity === "error").length,
@@ -4916,74 +6338,74 @@ function countKeyboardShortcutSignals(code) {
4916
6338
  return matches.length;
4917
6339
  }
4918
6340
  function getScriptKind(filePath) {
4919
- switch (extname3(filePath).toLowerCase()) {
6341
+ switch (extname4(filePath).toLowerCase()) {
4920
6342
  case ".tsx":
4921
- return ts.ScriptKind.TSX;
6343
+ return ts3.ScriptKind.TSX;
4922
6344
  case ".jsx":
4923
- return ts.ScriptKind.JSX;
6345
+ return ts3.ScriptKind.JSX;
4924
6346
  case ".ts":
4925
- return ts.ScriptKind.TS;
6347
+ return ts3.ScriptKind.TS;
4926
6348
  case ".js":
4927
- return ts.ScriptKind.JS;
6349
+ return ts3.ScriptKind.JS;
4928
6350
  default:
4929
- return ts.ScriptKind.TSX;
6351
+ return ts3.ScriptKind.TSX;
4930
6352
  }
4931
6353
  }
4932
6354
  function isPropertyNamed(node, ...names) {
4933
6355
  if (!node) return false;
4934
- if (ts.isIdentifier(node)) {
6356
+ if (ts3.isIdentifier(node)) {
4935
6357
  return names.includes(node.text);
4936
6358
  }
4937
- if (ts.isPrivateIdentifier(node)) {
6359
+ if (ts3.isPrivateIdentifier(node)) {
4938
6360
  return names.includes(node.text);
4939
6361
  }
4940
- if (ts.isStringLiteral(node)) {
6362
+ if (ts3.isStringLiteral(node)) {
4941
6363
  return names.includes(node.text);
4942
6364
  }
4943
6365
  return false;
4944
6366
  }
4945
6367
  function getJsxAttribute(attributes, ...names) {
4946
6368
  return attributes.properties.find(
4947
- (property) => ts.isJsxAttribute(property) && isPropertyNamed(property.name, ...names)
6369
+ (property) => ts3.isJsxAttribute(property) && isPropertyNamed(property.name, ...names)
4948
6370
  );
4949
6371
  }
4950
6372
  function getJsxTagName(node) {
4951
- if (ts.isIdentifier(node.tagName)) {
6373
+ if (ts3.isIdentifier(node.tagName)) {
4952
6374
  return node.tagName.text;
4953
6375
  }
4954
- if (ts.isPropertyAccessExpression(node.tagName)) {
6376
+ if (ts3.isPropertyAccessExpression(node.tagName)) {
4955
6377
  return node.tagName.name.text;
4956
6378
  }
4957
6379
  return null;
4958
6380
  }
4959
6381
  function getJsxAttributeLiteralValue(attribute) {
4960
6382
  if (!attribute?.initializer) return null;
4961
- if (ts.isStringLiteral(attribute.initializer)) {
6383
+ if (ts3.isStringLiteral(attribute.initializer)) {
4962
6384
  return attribute.initializer.text;
4963
6385
  }
4964
- if (ts.isJsxExpression(attribute.initializer)) {
6386
+ if (ts3.isJsxExpression(attribute.initializer)) {
4965
6387
  const expression = attribute.initializer.expression;
4966
6388
  if (!expression) return "";
4967
- if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {
6389
+ if (ts3.isStringLiteral(expression) || ts3.isNoSubstitutionTemplateLiteral(expression)) {
4968
6390
  return expression.text;
4969
6391
  }
4970
6392
  }
4971
6393
  return null;
4972
6394
  }
4973
6395
  function getJsxTextContent(node) {
4974
- if (ts.isJsxText(node)) {
6396
+ if (ts3.isJsxText(node)) {
4975
6397
  return node.getText();
4976
6398
  }
4977
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
6399
+ if (ts3.isStringLiteral(node) || ts3.isNoSubstitutionTemplateLiteral(node)) {
4978
6400
  return node.text;
4979
6401
  }
4980
- if (ts.isJsxExpression(node)) {
6402
+ if (ts3.isJsxExpression(node)) {
4981
6403
  return node.expression ? getJsxTextContent(node.expression) : "";
4982
6404
  }
4983
- if (ts.isJsxSelfClosingElement(node) || ts.isJsxOpeningElement(node)) {
6405
+ if (ts3.isJsxSelfClosingElement(node) || ts3.isJsxOpeningElement(node)) {
4984
6406
  return "";
4985
6407
  }
4986
- if (ts.isJsxElement(node) || ts.isJsxFragment(node)) {
6408
+ if (ts3.isJsxElement(node) || ts3.isJsxFragment(node)) {
4987
6409
  return node.children.map((child) => getJsxTextContent(child)).join("");
4988
6410
  }
4989
6411
  let text = "";
@@ -5003,7 +6425,7 @@ function isNonSemanticInteractiveTag(tagName) {
5003
6425
  function collectLabelForIds(root) {
5004
6426
  const ids = /* @__PURE__ */ new Set();
5005
6427
  const walk = (node) => {
5006
- if (ts.isJsxSelfClosingElement(node) || ts.isJsxOpeningElement(node)) {
6428
+ if (ts3.isJsxSelfClosingElement(node) || ts3.isJsxOpeningElement(node)) {
5007
6429
  const tagName = getJsxTagName(node);
5008
6430
  if (tagName === "label") {
5009
6431
  const htmlForValue = getJsxAttributeLiteralValue(
@@ -5014,7 +6436,7 @@ function collectLabelForIds(root) {
5014
6436
  }
5015
6437
  }
5016
6438
  }
5017
- ts.forEachChild(node, walk);
6439
+ ts3.forEachChild(node, walk);
5018
6440
  };
5019
6441
  walk(root);
5020
6442
  return ids;
@@ -5022,7 +6444,7 @@ function collectLabelForIds(root) {
5022
6444
  function isWrappedInJsxLabel(node) {
5023
6445
  let current = node.parent;
5024
6446
  while (current) {
5025
- if (ts.isJsxElement(current) && getJsxTagName(current.openingElement) === "label") {
6447
+ if (ts3.isJsxElement(current) && getJsxTagName(current.openingElement) === "label") {
5026
6448
  return true;
5027
6449
  }
5028
6450
  current = current.parent;
@@ -5032,7 +6454,7 @@ function isWrappedInJsxLabel(node) {
5032
6454
  function hasAncestorJsxTag(node, tagName) {
5033
6455
  let current = node.parent;
5034
6456
  while (current) {
5035
- if (ts.isJsxElement(current) && getJsxTagName(current.openingElement) === tagName) {
6457
+ if (ts3.isJsxElement(current) && getJsxTagName(current.openingElement) === tagName) {
5036
6458
  return true;
5037
6459
  }
5038
6460
  current = current.parent;
@@ -5110,9 +6532,9 @@ function hasNavigationLabel(attributes) {
5110
6532
  }
5111
6533
  function getJsxAttributeOwner(attribute) {
5112
6534
  const attributes = attribute.parent;
5113
- if (!attributes || !ts.isJsxAttributes(attributes)) return null;
6535
+ if (!attributes || !ts3.isJsxAttributes(attributes)) return null;
5114
6536
  const owner = attributes.parent;
5115
- if (ts.isJsxOpeningElement(owner) || ts.isJsxSelfClosingElement(owner)) {
6537
+ if (ts3.isJsxOpeningElement(owner) || ts3.isJsxSelfClosingElement(owner)) {
5116
6538
  return owner;
5117
6539
  }
5118
6540
  return null;
@@ -5199,14 +6621,14 @@ function jsxTreeContainsAuthInput(node) {
5199
6621
  let found = false;
5200
6622
  const visit = (current) => {
5201
6623
  if (found) return;
5202
- if (ts.isJsxSelfClosingElement(current)) {
6624
+ if (ts3.isJsxSelfClosingElement(current)) {
5203
6625
  const tagName = getJsxTagName(current);
5204
6626
  if (tagName === "input" && isAuthLikeInputAttributes(current.attributes)) {
5205
6627
  found = true;
5206
6628
  }
5207
6629
  return;
5208
6630
  }
5209
- if (ts.isJsxElement(current)) {
6631
+ if (ts3.isJsxElement(current)) {
5210
6632
  const tagName = getJsxTagName(current.openingElement);
5211
6633
  if (tagName === "input" && isAuthLikeInputAttributes(current.openingElement.attributes)) {
5212
6634
  found = true;
@@ -5218,7 +6640,7 @@ function jsxTreeContainsAuthInput(node) {
5218
6640
  }
5219
6641
  return;
5220
6642
  }
5221
- if (ts.isJsxFragment(current)) {
6643
+ if (ts3.isJsxFragment(current)) {
5222
6644
  for (const child of current.children) {
5223
6645
  visit(child);
5224
6646
  if (found) return;
@@ -5242,7 +6664,7 @@ function jsxTreeHasSubmitControl(node) {
5242
6664
  let found = false;
5243
6665
  const visit = (current) => {
5244
6666
  if (found) return;
5245
- if (ts.isJsxSelfClosingElement(current)) {
6667
+ if (ts3.isJsxSelfClosingElement(current)) {
5246
6668
  const tagName = getJsxTagName(current);
5247
6669
  if (tagName === "button") {
5248
6670
  const typeValue = getJsxAttributeLiteralValue(getJsxAttribute(current.attributes, "type"))?.trim().toLowerCase();
@@ -5258,7 +6680,7 @@ function jsxTreeHasSubmitControl(node) {
5258
6680
  }
5259
6681
  return;
5260
6682
  }
5261
- if (ts.isJsxElement(current)) {
6683
+ if (ts3.isJsxElement(current)) {
5262
6684
  const tagName = getJsxTagName(current.openingElement);
5263
6685
  if (tagName === "button") {
5264
6686
  const typeValue = getJsxAttributeLiteralValue(
@@ -5282,7 +6704,7 @@ function jsxTreeHasSubmitControl(node) {
5282
6704
  }
5283
6705
  return;
5284
6706
  }
5285
- if (ts.isJsxFragment(current)) {
6707
+ if (ts3.isJsxFragment(current)) {
5286
6708
  for (const child of current.children) {
5287
6709
  visit(child);
5288
6710
  if (found) return;
@@ -5299,14 +6721,14 @@ function jsxTreeHasTag(node, tagNames) {
5299
6721
  const wanted = new Set(tagNames);
5300
6722
  const visit = (current) => {
5301
6723
  if (found) return;
5302
- if (ts.isJsxSelfClosingElement(current)) {
6724
+ if (ts3.isJsxSelfClosingElement(current)) {
5303
6725
  const tagName = getJsxTagName(current);
5304
6726
  if (tagName && wanted.has(tagName)) {
5305
6727
  found = true;
5306
6728
  }
5307
6729
  return;
5308
6730
  }
5309
- if (ts.isJsxElement(current)) {
6731
+ if (ts3.isJsxElement(current)) {
5310
6732
  const tagName = getJsxTagName(current.openingElement);
5311
6733
  if (tagName && wanted.has(tagName)) {
5312
6734
  found = true;
@@ -5318,7 +6740,7 @@ function jsxTreeHasTag(node, tagNames) {
5318
6740
  }
5319
6741
  return;
5320
6742
  }
5321
- if (ts.isJsxFragment(current)) {
6743
+ if (ts3.isJsxFragment(current)) {
5322
6744
  for (const child of current.children) {
5323
6745
  visit(child);
5324
6746
  if (found) return;
@@ -5335,47 +6757,47 @@ function hasAuthFormWithoutSubmitControl(node) {
5335
6757
  }
5336
6758
  function getExpressionLiteralValue(expression) {
5337
6759
  if (!expression) return null;
5338
- if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {
6760
+ if (ts3.isStringLiteral(expression) || ts3.isNoSubstitutionTemplateLiteral(expression)) {
5339
6761
  return expression.text;
5340
6762
  }
5341
- if (ts.isParenthesizedExpression(expression)) {
6763
+ if (ts3.isParenthesizedExpression(expression)) {
5342
6764
  return getExpressionLiteralValue(expression.expression);
5343
6765
  }
5344
- if (ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression)) {
6766
+ if (ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression)) {
5345
6767
  return getExpressionLiteralValue(expression.expression);
5346
6768
  }
5347
6769
  return null;
5348
6770
  }
5349
6771
  function getObjectLiteralStringPropertyValue(expression, ...propertyNames) {
5350
- if (!expression || !ts.isObjectLiteralExpression(expression)) return null;
6772
+ if (!expression || !ts3.isObjectLiteralExpression(expression)) return null;
5351
6773
  for (const property of expression.properties) {
5352
- if (!ts.isPropertyAssignment(property)) continue;
5353
- const propertyName = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) ? property.name.text : null;
5354
- if (!propertyName || !propertyNames.includes(propertyName)) continue;
6774
+ if (!ts3.isPropertyAssignment(property)) continue;
6775
+ const propertyName2 = ts3.isIdentifier(property.name) ? property.name.text : ts3.isStringLiteral(property.name) ? property.name.text : null;
6776
+ if (!propertyName2 || !propertyNames.includes(propertyName2)) continue;
5355
6777
  const value = getExpressionLiteralValue(property.initializer);
5356
6778
  if (value) return value;
5357
6779
  }
5358
6780
  return null;
5359
6781
  }
5360
6782
  function getObjectLiteralBooleanPropertyValue(expression, ...propertyNames) {
5361
- if (!expression || !ts.isObjectLiteralExpression(expression)) return null;
6783
+ if (!expression || !ts3.isObjectLiteralExpression(expression)) return null;
5362
6784
  for (const property of expression.properties) {
5363
- if (!ts.isPropertyAssignment(property)) continue;
5364
- const propertyName = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) ? property.name.text : null;
5365
- if (!propertyName || !propertyNames.includes(propertyName)) continue;
5366
- if (property.initializer.kind === ts.SyntaxKind.TrueKeyword) return true;
5367
- if (property.initializer.kind === ts.SyntaxKind.FalseKeyword) return false;
6785
+ if (!ts3.isPropertyAssignment(property)) continue;
6786
+ const propertyName2 = ts3.isIdentifier(property.name) ? property.name.text : ts3.isStringLiteral(property.name) ? property.name.text : null;
6787
+ if (!propertyName2 || !propertyNames.includes(propertyName2)) continue;
6788
+ if (property.initializer.kind === ts3.SyntaxKind.TrueKeyword) return true;
6789
+ if (property.initializer.kind === ts3.SyntaxKind.FalseKeyword) return false;
5368
6790
  }
5369
6791
  return null;
5370
6792
  }
5371
6793
  function collectNamedFunctionLikeDeclarations(root) {
5372
6794
  const declarations = /* @__PURE__ */ new Map();
5373
6795
  const visit = (node) => {
5374
- if (ts.isFunctionDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
6796
+ if (ts3.isFunctionDeclaration(node) && node.name && ts3.isIdentifier(node.name)) {
5375
6797
  declarations.set(node.name.text, node);
5376
6798
  }
5377
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
5378
- if (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) {
6799
+ if (ts3.isVariableDeclaration(node) && ts3.isIdentifier(node.name) && node.initializer) {
6800
+ if (ts3.isArrowFunction(node.initializer) || ts3.isFunctionExpression(node.initializer)) {
5379
6801
  declarations.set(node.name.text, node.initializer);
5380
6802
  }
5381
6803
  }
@@ -5395,12 +6817,12 @@ function getCachedNamedFunctionLikeDeclarations(sourceFile) {
5395
6817
  function collectNamedExpressionInitializers(root) {
5396
6818
  const initializers = /* @__PURE__ */ new Map();
5397
6819
  const visit = (node) => {
5398
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
6820
+ if (ts3.isVariableDeclaration(node) && ts3.isIdentifier(node.name) && node.initializer) {
5399
6821
  initializers.set(node.name.text, node.initializer);
5400
6822
  }
5401
- if (ts.isVariableDeclaration(node) && ts.isArrayBindingPattern(node.name) && node.initializer) {
6823
+ if (ts3.isVariableDeclaration(node) && ts3.isArrayBindingPattern(node.name) && node.initializer) {
5402
6824
  const firstElement = node.name.elements[0];
5403
- if (firstElement && !ts.isOmittedExpression(firstElement) && ts.isBindingElement(firstElement) && ts.isIdentifier(firstElement.name)) {
6825
+ if (firstElement && !ts3.isOmittedExpression(firstElement) && ts3.isBindingElement(firstElement) && ts3.isIdentifier(firstElement.name)) {
5404
6826
  initializers.set(firstElement.name.text, node.initializer);
5405
6827
  }
5406
6828
  }
@@ -5411,7 +6833,7 @@ function collectNamedExpressionInitializers(root) {
5411
6833
  }
5412
6834
  function getPropertyNameText(name) {
5413
6835
  if (!name) return null;
5414
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
6836
+ if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
5415
6837
  return name.text;
5416
6838
  }
5417
6839
  return null;
@@ -5421,23 +6843,23 @@ function collectNamedPropertyAliases(root) {
5421
6843
  const collectFromBindingPattern = (pattern, initializer, propertyPath) => {
5422
6844
  for (const element of pattern.elements) {
5423
6845
  if (element.dotDotDotToken) continue;
5424
- const propertyName = getPropertyNameText(element.propertyName) ?? getPropertyNameText(element.name);
5425
- if (!propertyName) continue;
5426
- const nextPath = [...propertyPath, propertyName];
5427
- if (ts.isIdentifier(element.name)) {
5428
- aliases.set(element.name.text, { initializer, propertyName, propertyPath: nextPath });
6846
+ const propertyName2 = getPropertyNameText(element.propertyName) ?? getPropertyNameText(element.name);
6847
+ if (!propertyName2) continue;
6848
+ const nextPath = [...propertyPath, propertyName2];
6849
+ if (ts3.isIdentifier(element.name)) {
6850
+ aliases.set(element.name.text, { initializer, propertyName: propertyName2, propertyPath: nextPath });
5429
6851
  continue;
5430
6852
  }
5431
- if (ts.isObjectBindingPattern(element.name)) {
6853
+ if (ts3.isObjectBindingPattern(element.name)) {
5432
6854
  collectFromBindingPattern(element.name, initializer, nextPath);
5433
6855
  }
5434
6856
  }
5435
6857
  };
5436
6858
  const visit = (node) => {
5437
- if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer) {
6859
+ if (ts3.isVariableDeclaration(node) && ts3.isObjectBindingPattern(node.name) && node.initializer) {
5438
6860
  collectFromBindingPattern(node.name, node.initializer, []);
5439
6861
  }
5440
- if (ts.isParameter(node) && ts.isObjectBindingPattern(node.name)) {
6862
+ if (ts3.isParameter(node) && ts3.isObjectBindingPattern(node.name)) {
5441
6863
  collectFromBindingPattern(node.name, void 0, []);
5442
6864
  }
5443
6865
  node.forEachChild(visit);
@@ -5447,28 +6869,28 @@ function collectNamedPropertyAliases(root) {
5447
6869
  }
5448
6870
  function resolveFunctionLikeHandler(expression, namedFunctions) {
5449
6871
  if (!expression) return null;
5450
- if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
6872
+ if (ts3.isArrowFunction(expression) || ts3.isFunctionExpression(expression)) {
5451
6873
  return expression;
5452
6874
  }
5453
- if (ts.isIdentifier(expression)) {
6875
+ if (ts3.isIdentifier(expression)) {
5454
6876
  return namedFunctions.get(expression.text) ?? null;
5455
6877
  }
5456
6878
  return null;
5457
6879
  }
5458
6880
  function getFunctionLikeReturnExpressions(node) {
5459
- if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
6881
+ if (ts3.isArrowFunction(node) && !ts3.isBlock(node.body)) {
5460
6882
  return [node.body];
5461
6883
  }
5462
6884
  const body = node.body;
5463
- if (!body || !ts.isBlock(body)) {
6885
+ if (!body || !ts3.isBlock(body)) {
5464
6886
  return [];
5465
6887
  }
5466
6888
  const expressions = [];
5467
6889
  const visit = (current) => {
5468
- if (current !== body && (ts.isFunctionDeclaration(current) || ts.isFunctionExpression(current) || ts.isArrowFunction(current) || ts.isMethodDeclaration(current) || ts.isGetAccessorDeclaration(current) || ts.isSetAccessorDeclaration(current) || ts.isConstructorDeclaration(current))) {
6890
+ if (current !== body && (ts3.isFunctionDeclaration(current) || ts3.isFunctionExpression(current) || ts3.isArrowFunction(current) || ts3.isMethodDeclaration(current) || ts3.isGetAccessorDeclaration(current) || ts3.isSetAccessorDeclaration(current) || ts3.isConstructorDeclaration(current))) {
5469
6891
  return;
5470
6892
  }
5471
- if (ts.isReturnStatement(current) && current.expression) {
6893
+ if (ts3.isReturnStatement(current) && current.expression) {
5472
6894
  expressions.push(current.expression);
5473
6895
  return;
5474
6896
  }
@@ -5484,7 +6906,7 @@ function bindFunctionLikeArguments(functionLike, args, namedExpressions) {
5484
6906
  const boundExpressions = new Map(namedExpressions);
5485
6907
  functionLike.parameters.forEach((parameter, index) => {
5486
6908
  const argument = args[index];
5487
- if (!argument || !ts.isIdentifier(parameter.name)) return;
6909
+ if (!argument || !ts3.isIdentifier(parameter.name)) return;
5488
6910
  boundExpressions.set(parameter.name.text, argument);
5489
6911
  });
5490
6912
  return boundExpressions;
@@ -5496,12 +6918,12 @@ function getMemberAccessPropertyName(expression) {
5496
6918
  }
5497
6919
  return getExpressionLiteralValue(expression.argumentExpression);
5498
6920
  }
5499
- function getObjectLiteralPropertyExpression(objectLiteral, propertyName, namedExpressions) {
6921
+ function getObjectLiteralPropertyExpression(objectLiteral, propertyName2, namedExpressions) {
5500
6922
  for (const property of objectLiteral.properties) {
5501
- if (ts.isPropertyAssignment(property) && getPropertyNameText(property.name) === propertyName) {
6923
+ if (ts3.isPropertyAssignment(property) && getPropertyNameText(property.name) === propertyName2) {
5502
6924
  return property.initializer;
5503
6925
  }
5504
- if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) {
6926
+ if (ts3.isShorthandPropertyAssignment(property) && property.name.text === propertyName2) {
5505
6927
  return namedExpressions.get(property.name.text) ?? null;
5506
6928
  }
5507
6929
  }
@@ -5520,10 +6942,10 @@ function resolveObjectLiteralExpressionAtPropertyPath(expression, sourceFile, pr
5520
6942
  depth + 1
5521
6943
  );
5522
6944
  if (!resolvedObjectLiteral) return null;
5523
- for (const propertyName of propertyPath) {
6945
+ for (const propertyName2 of propertyPath) {
5524
6946
  const propertyExpression = getObjectLiteralPropertyExpression(
5525
6947
  resolvedObjectLiteral.objectLiteral,
5526
- propertyName,
6948
+ propertyName2,
5527
6949
  resolvedObjectLiteral.namedExpressions
5528
6950
  );
5529
6951
  if (!propertyExpression) return null;
@@ -5567,7 +6989,7 @@ function resolveReturnedObjectLiteralExpression(functionLike, args, sourceFile,
5567
6989
  function resolveObjectLiteralExpression(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers, seenFunctions = /* @__PURE__ */ new Set(), depth = 0) {
5568
6990
  if (!expression) return null;
5569
6991
  if (depth > MAX_OPEN_REDIRECT_RESOLUTION_DEPTH) return null;
5570
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
6992
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
5571
6993
  return resolveObjectLiteralExpression(
5572
6994
  expression.expression,
5573
6995
  sourceFile,
@@ -5578,10 +7000,10 @@ function resolveObjectLiteralExpression(expression, sourceFile, namedExpressions
5578
7000
  depth + 1
5579
7001
  );
5580
7002
  }
5581
- if (ts.isObjectLiteralExpression(expression)) {
7003
+ if (ts3.isObjectLiteralExpression(expression)) {
5582
7004
  return { objectLiteral: expression, namedExpressions };
5583
7005
  }
5584
- if (ts.isIdentifier(expression)) {
7006
+ if (ts3.isIdentifier(expression)) {
5585
7007
  if (seenIdentifiers.has(expression.text)) return null;
5586
7008
  const initializer = namedExpressions.get(expression.text);
5587
7009
  if (initializer) {
@@ -5637,12 +7059,12 @@ function resolveObjectLiteralExpression(expression, sourceFile, namedExpressions
5637
7059
  );
5638
7060
  }
5639
7061
  if (isMemberAccessExpression(expression)) {
5640
- const propertyName = getMemberAccessPropertyName(expression);
5641
- if (!propertyName) return null;
7062
+ const propertyName2 = getMemberAccessPropertyName(expression);
7063
+ if (!propertyName2) return null;
5642
7064
  return resolveObjectLiteralExpressionAtPropertyPath(
5643
7065
  expression.expression,
5644
7066
  sourceFile,
5645
- [propertyName],
7067
+ [propertyName2],
5646
7068
  namedExpressions,
5647
7069
  namedPropertyAliases,
5648
7070
  seenIdentifiers,
@@ -5652,15 +7074,15 @@ function resolveObjectLiteralExpression(expression, sourceFile, namedExpressions
5652
7074
  }
5653
7075
  return null;
5654
7076
  }
5655
- function findFunctionLikeOnObjectLiteral(objectLiteral, propertyName, namedFunctions) {
7077
+ function findFunctionLikeOnObjectLiteral(objectLiteral, propertyName2, namedFunctions) {
5656
7078
  for (const property of objectLiteral.properties) {
5657
- if (ts.isMethodDeclaration(property) && getPropertyNameText(property.name) === propertyName) {
7079
+ if (ts3.isMethodDeclaration(property) && getPropertyNameText(property.name) === propertyName2) {
5658
7080
  return property;
5659
7081
  }
5660
- if (ts.isPropertyAssignment(property) && getPropertyNameText(property.name) === propertyName) {
7082
+ if (ts3.isPropertyAssignment(property) && getPropertyNameText(property.name) === propertyName2) {
5661
7083
  return resolveFunctionLikeHandler(property.initializer, namedFunctions);
5662
7084
  }
5663
- if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) {
7085
+ if (ts3.isShorthandPropertyAssignment(property) && property.name.text === propertyName2) {
5664
7086
  return namedFunctions.get(property.name.text) ?? null;
5665
7087
  }
5666
7088
  }
@@ -5695,7 +7117,7 @@ function resolveTrackedOpenRedirectFunctionLike(expression, sourceFile, namedExp
5695
7117
  if (directFunctionLike) {
5696
7118
  return { functionLike: directFunctionLike, namedExpressions };
5697
7119
  }
5698
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
7120
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
5699
7121
  return resolveTrackedOpenRedirectFunctionLike(
5700
7122
  expression.expression,
5701
7123
  sourceFile,
@@ -5728,7 +7150,7 @@ function resolveTrackedOpenRedirectFunctionLike(expression, sourceFile, namedExp
5728
7150
  depth + 1
5729
7151
  );
5730
7152
  }
5731
- if (ts.isIdentifier(expression)) {
7153
+ if (ts3.isIdentifier(expression)) {
5732
7154
  if (seenIdentifiers.has(expression.text)) return null;
5733
7155
  const initializer = namedExpressions.get(expression.text);
5734
7156
  if (initializer) {
@@ -5768,8 +7190,8 @@ function resolveTrackedOpenRedirectFunctionLike(expression, sourceFile, namedExp
5768
7190
  if (!isMemberAccessExpression(expression)) {
5769
7191
  return null;
5770
7192
  }
5771
- const propertyName = getMemberAccessPropertyName(expression);
5772
- if (!propertyName) return null;
7193
+ const propertyName2 = getMemberAccessPropertyName(expression);
7194
+ if (!propertyName2) return null;
5773
7195
  const resolvedObjectLiteral = resolveObjectLiteralExpression(
5774
7196
  expression.expression,
5775
7197
  sourceFile,
@@ -5782,7 +7204,7 @@ function resolveTrackedOpenRedirectFunctionLike(expression, sourceFile, namedExp
5782
7204
  if (!resolvedObjectLiteral) return null;
5783
7205
  const functionLike = findFunctionLikeOnObjectLiteral(
5784
7206
  resolvedObjectLiteral.objectLiteral,
5785
- propertyName,
7207
+ propertyName2,
5786
7208
  namedFunctions
5787
7209
  );
5788
7210
  return functionLike ? { functionLike, namedExpressions: resolvedObjectLiteral.namedExpressions } : null;
@@ -5791,16 +7213,16 @@ function functionLikeReferencesOrigin(node) {
5791
7213
  let found = false;
5792
7214
  const visit = (current) => {
5793
7215
  if (found) return;
5794
- if (ts.isPropertyAccessExpression(current) && isPropertyNamed(current.name, "origin")) {
7216
+ if (ts3.isPropertyAccessExpression(current) && isPropertyNamed(current.name, "origin")) {
5795
7217
  found = true;
5796
7218
  return;
5797
7219
  }
5798
- if (ts.isIdentifier(current) && current.text === "origin") {
7220
+ if (ts3.isIdentifier(current) && current.text === "origin") {
5799
7221
  found = true;
5800
7222
  return;
5801
7223
  }
5802
- if (ts.isBindingElement(current)) {
5803
- if (ts.isIdentifier(current.name) && current.name.text === "origin") {
7224
+ if (ts3.isBindingElement(current)) {
7225
+ if (ts3.isIdentifier(current.name) && current.name.text === "origin") {
5804
7226
  found = true;
5805
7227
  return;
5806
7228
  }
@@ -5815,13 +7237,13 @@ function functionLikeReferencesOrigin(node) {
5815
7237
  return found;
5816
7238
  }
5817
7239
  function isAddEventListenerCall(node) {
5818
- return ts.isIdentifier(node.expression) && node.expression.text === "addEventListener" || ts.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "addEventListener");
7240
+ return ts3.isIdentifier(node.expression) && node.expression.text === "addEventListener" || ts3.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "addEventListener");
5819
7241
  }
5820
7242
  function isCookieMutationSetCall(node) {
5821
- if (!ts.isPropertyAccessExpression(node.expression) || !isPropertyNamed(node.expression.name, "set")) {
7243
+ if (!ts3.isPropertyAccessExpression(node.expression) || !isPropertyNamed(node.expression.name, "set")) {
5822
7244
  return false;
5823
7245
  }
5824
- return ts.isIdentifier(node.expression.expression) && ["Cookies", "cookieStore", "cookies"].includes(node.expression.expression.text) || ts.isPropertyAccessExpression(node.expression.expression) && isPropertyNamed(node.expression.expression.name, "cookies", "cookieStore");
7246
+ return ts3.isIdentifier(node.expression.expression) && ["Cookies", "cookieStore", "cookies"].includes(node.expression.expression.text) || ts3.isPropertyAccessExpression(node.expression.expression) && isPropertyNamed(node.expression.expression.name, "cookies", "cookieStore");
5825
7247
  }
5826
7248
  function expressionLooksLikeAuthCookieName(node, sourceFile) {
5827
7249
  if (!node) return false;
@@ -5829,17 +7251,17 @@ function expressionLooksLikeAuthCookieName(node, sourceFile) {
5829
7251
  return hasAuthCredentialText(node, sourceFile);
5830
7252
  }
5831
7253
  function objectLiteralLooksLikeAuthCookieConfig(expression, sourceFile) {
5832
- if (!expression || !ts.isObjectLiteralExpression(expression)) return false;
7254
+ if (!expression || !ts3.isObjectLiteralExpression(expression)) return false;
5833
7255
  for (const property of expression.properties) {
5834
- if (!ts.isPropertyAssignment(property)) continue;
5835
- const propertyName = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) ? property.name.text : null;
5836
- if (!propertyName || !["name", "key", "cookie"].includes(propertyName)) continue;
7256
+ if (!ts3.isPropertyAssignment(property)) continue;
7257
+ const propertyName2 = ts3.isIdentifier(property.name) ? property.name.text : ts3.isStringLiteral(property.name) ? property.name.text : null;
7258
+ if (!propertyName2 || !["name", "key", "cookie"].includes(propertyName2)) continue;
5837
7259
  return expressionLooksLikeAuthCookieName(property.initializer, sourceFile);
5838
7260
  }
5839
7261
  return false;
5840
7262
  }
5841
7263
  function hasExplicitAuthCookieHardening(expression) {
5842
- if (!expression || !ts.isObjectLiteralExpression(expression)) return false;
7264
+ if (!expression || !ts3.isObjectLiteralExpression(expression)) return false;
5843
7265
  const httpOnly = getObjectLiteralBooleanPropertyValue(expression, "httpOnly", "http_only");
5844
7266
  const secure = getObjectLiteralBooleanPropertyValue(expression, "secure");
5845
7267
  const sameSite = getObjectLiteralStringPropertyValue(expression, "sameSite", "same_site");
@@ -5859,8 +7281,8 @@ function collectCookieHeaderStrings(expression) {
5859
7281
  if (!expression) return [];
5860
7282
  const literal = getExpressionLiteralValue(expression);
5861
7283
  if (literal !== null) return [literal];
5862
- if (ts.isArrayLiteralExpression(expression)) {
5863
- return expression.elements.map((element) => ts.isExpression(element) ? getExpressionLiteralValue(element) : null).filter((value) => value !== null);
7284
+ if (ts3.isArrayLiteralExpression(expression)) {
7285
+ return expression.elements.map((element) => ts3.isExpression(element) ? getExpressionLiteralValue(element) : null).filter((value) => value !== null);
5864
7286
  }
5865
7287
  return [];
5866
7288
  }
@@ -5868,16 +7290,16 @@ function isInsecureTransportUrl(value) {
5868
7290
  return typeof value === "string" && /^(?:http|ws):\/\//i.test(value.trim());
5869
7291
  }
5870
7292
  function isPropertyLikeAccessExpression(node) {
5871
- return Boolean(node && (ts.isPropertyAccessExpression(node) || ts.isPropertyAccessChain(node)));
7293
+ return Boolean(node && (ts3.isPropertyAccessExpression(node) || ts3.isPropertyAccessChain(node)));
5872
7294
  }
5873
7295
  function isElementLikeAccessExpression(node) {
5874
- return Boolean(node && (ts.isElementAccessExpression(node) || ts.isElementAccessChain(node)));
7296
+ return Boolean(node && (ts3.isElementAccessExpression(node) || ts3.isElementAccessChain(node)));
5875
7297
  }
5876
7298
  function isMemberAccessExpression(node) {
5877
7299
  return isPropertyLikeAccessExpression(node) || isElementLikeAccessExpression(node);
5878
7300
  }
5879
7301
  function isCallLikeExpression(node) {
5880
- return Boolean(node && (ts.isCallExpression(node) || ts.isCallChain(node)));
7302
+ return Boolean(node && (ts3.isCallExpression(node) || ts3.isCallChain(node)));
5881
7303
  }
5882
7304
  function isMemberAccessNamed(node, ...names) {
5883
7305
  if (!node) return false;
@@ -5890,19 +7312,19 @@ function isMemberAccessNamed(node, ...names) {
5890
7312
  return false;
5891
7313
  }
5892
7314
  function isLocationObjectExpression(expression) {
5893
- return ts.isIdentifier(expression) && expression.text === "location" || (ts.isPropertyAccessExpression(expression) || ts.isElementAccessExpression(expression)) && ts.isIdentifier(expression.expression) && ["window", "globalThis", "document", "self", "parent", "top"].includes(
7315
+ return ts3.isIdentifier(expression) && expression.text === "location" || (ts3.isPropertyAccessExpression(expression) || ts3.isElementAccessExpression(expression)) && ts3.isIdentifier(expression.expression) && ["window", "globalThis", "document", "self", "parent", "top"].includes(
5894
7316
  expression.expression.text
5895
7317
  ) && isMemberAccessNamed(expression, "location");
5896
7318
  }
5897
7319
  function isLocationAssignmentTarget(expression) {
5898
- return isLocationObjectExpression(expression) || (ts.isPropertyAccessExpression(expression) || ts.isElementAccessExpression(expression)) && isLocationObjectExpression(expression.expression) && isMemberAccessNamed(expression, "href");
7320
+ return isLocationObjectExpression(expression) || (ts3.isPropertyAccessExpression(expression) || ts3.isElementAccessExpression(expression)) && isLocationObjectExpression(expression.expression) && isMemberAccessNamed(expression, "href");
5899
7321
  }
5900
7322
  function isFetchLikeCall(node) {
5901
- return ts.isIdentifier(node.expression) && node.expression.text === "fetch" || ts.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "fetch");
7323
+ return ts3.isIdentifier(node.expression) && node.expression.text === "fetch" || ts3.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "fetch");
5902
7324
  }
5903
7325
  function isAxiosLikeCall(node) {
5904
- if (!ts.isPropertyAccessExpression(node.expression)) return false;
5905
- return ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "axios" && isPropertyNamed(
7326
+ if (!ts3.isPropertyAccessExpression(node.expression)) return false;
7327
+ return ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "axios" && isPropertyNamed(
5906
7328
  node.expression.name,
5907
7329
  "get",
5908
7330
  "post",
@@ -5915,10 +7337,10 @@ function isAxiosLikeCall(node) {
5915
7337
  );
5916
7338
  }
5917
7339
  function isAxiosConfigCall(node) {
5918
- return ts.isIdentifier(node.expression) && node.expression.text === "axios";
7340
+ return ts3.isIdentifier(node.expression) && node.expression.text === "axios";
5919
7341
  }
5920
7342
  function isRealtimeTransportConstructor(node) {
5921
- return ts.isIdentifier(node.expression) && (node.expression.text === "WebSocket" || node.expression.text === "EventSource");
7343
+ return ts3.isIdentifier(node.expression) && (node.expression.text === "WebSocket" || node.expression.text === "EventSource");
5922
7344
  }
5923
7345
  function hasPlaceholderNavigationTarget(attributes) {
5924
7346
  const targetValue = getJsxAttributeLiteralValue(getJsxAttribute(attributes, "href", "to"));
@@ -5985,40 +7407,40 @@ function getSkipNavTargetId(attributes, tagName) {
5985
7407
  }
5986
7408
  function isAuthStorageKeyLiteral(node) {
5987
7409
  if (!node) return false;
5988
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
7410
+ if (ts3.isStringLiteral(node) || ts3.isNoSubstitutionTemplateLiteral(node)) {
5989
7411
  if (node.text === "decantr_authenticated") return false;
5990
7412
  return /(?:token|auth|jwt|session|access_token|refresh_token)/i.test(node.text);
5991
7413
  }
5992
7414
  return false;
5993
7415
  }
5994
7416
  function isBrowserStorageObject(node) {
5995
- return ts.isIdentifier(node) && (node.text === "localStorage" || node.text === "sessionStorage");
7417
+ return ts3.isIdentifier(node) && (node.text === "localStorage" || node.text === "sessionStorage");
5996
7418
  }
5997
7419
  function isDocumentObject(node) {
5998
- return ts.isIdentifier(node) && node.text === "document";
7420
+ return ts3.isIdentifier(node) && node.text === "document";
5999
7421
  }
6000
7422
  function isCookiePropertyAccess(node) {
6001
- return ts.isPropertyAccessExpression(node) && isDocumentObject(node.expression) && isPropertyNamed(node.name, "cookie");
7423
+ return ts3.isPropertyAccessExpression(node) && isDocumentObject(node.expression) && isPropertyNamed(node.name, "cookie");
6002
7424
  }
6003
7425
  function hasAuthCredentialText(node, sourceFile) {
6004
7426
  return /(?:token|auth|jwt|session|access_token|refresh_token)/i.test(node.getText(sourceFile));
6005
7427
  }
6006
7428
  function isAuthorizationHeaderName(node) {
6007
7429
  if (!node) return false;
6008
- if (ts.isIdentifier(node)) {
7430
+ if (ts3.isIdentifier(node)) {
6009
7431
  return /^authorization$/i.test(node.text);
6010
7432
  }
6011
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
7433
+ if (ts3.isStringLiteral(node) || ts3.isNoSubstitutionTemplateLiteral(node)) {
6012
7434
  return /^authorization$/i.test(node.text);
6013
7435
  }
6014
- if (ts.isComputedPropertyName(node)) {
7436
+ if (ts3.isComputedPropertyName(node)) {
6015
7437
  return isAuthorizationHeaderName(node.expression);
6016
7438
  }
6017
7439
  return false;
6018
7440
  }
6019
7441
  function isAuthorizationHeaderAccess(node) {
6020
7442
  if (!node) return false;
6021
- return ts.isPropertyAccessExpression(node) && isAuthorizationHeaderName(node.name) || ts.isElementAccessExpression(node) && isAuthorizationHeaderName(node.argumentExpression);
7443
+ return ts3.isPropertyAccessExpression(node) && isAuthorizationHeaderName(node.name) || ts3.isElementAccessExpression(node) && isAuthorizationHeaderName(node.argumentExpression);
6022
7444
  }
6023
7445
  function isHeaderClearValue(node) {
6024
7446
  if (!node) return false;
@@ -6026,7 +7448,7 @@ function isHeaderClearValue(node) {
6026
7448
  if (literal !== null) {
6027
7449
  return literal.trim().length === 0;
6028
7450
  }
6029
- return node.kind === ts.SyntaxKind.NullKeyword || node.kind === ts.SyntaxKind.UndefinedKeyword || ts.isIdentifier(node) && node.text === "undefined";
7451
+ return node.kind === ts3.SyntaxKind.NullKeyword || node.kind === ts3.SyntaxKind.UndefinedKeyword || ts3.isIdentifier(node) && node.text === "undefined";
6030
7452
  }
6031
7453
  function countAuthGuardSignals(code) {
6032
7454
  const patterns = [
@@ -6775,7 +8197,7 @@ function propertyPathLooksLikeOpenRedirectQueryContainerBase(propertyPath) {
6775
8197
  }
6776
8198
  function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFile, namedExpressions = /* @__PURE__ */ new Map(), namedPropertyAliases = /* @__PURE__ */ new Map(), seenIdentifiers = /* @__PURE__ */ new Set(), seenFunctions = /* @__PURE__ */ new Set()) {
6777
8199
  if (!expression) return false;
6778
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
8200
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
6779
8201
  return expressionLooksLikeOpenRedirectQueryGetterFunction(
6780
8202
  expression.expression,
6781
8203
  sourceFile,
@@ -6802,7 +8224,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6802
8224
  )
6803
8225
  );
6804
8226
  }
6805
- if (ts.isBinaryExpression(expression) && (expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken || expression.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
8227
+ if (ts3.isBinaryExpression(expression) && (expression.operatorToken.kind === ts3.SyntaxKind.QuestionQuestionToken || expression.operatorToken.kind === ts3.SyntaxKind.BarBarToken)) {
6806
8228
  return expressionLooksLikeOpenRedirectQueryGetterFunction(
6807
8229
  expression.left,
6808
8230
  sourceFile,
@@ -6819,7 +8241,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6819
8241
  seenFunctions
6820
8242
  );
6821
8243
  }
6822
- if (ts.isConditionalExpression(expression)) {
8244
+ if (ts3.isConditionalExpression(expression)) {
6823
8245
  return expressionLooksLikeOpenRedirectQueryGetterFunction(
6824
8246
  expression.whenTrue,
6825
8247
  sourceFile,
@@ -6836,7 +8258,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6836
8258
  seenFunctions
6837
8259
  );
6838
8260
  }
6839
- if (ts.isTemplateExpression(expression)) {
8261
+ if (ts3.isTemplateExpression(expression)) {
6840
8262
  return expression.templateSpans.some(
6841
8263
  (span) => expressionLooksLikeOpenRedirectQueryGetterFunction(
6842
8264
  span.expression,
@@ -6848,7 +8270,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6848
8270
  )
6849
8271
  );
6850
8272
  }
6851
- if (ts.isTaggedTemplateExpression(expression)) {
8273
+ if (ts3.isTaggedTemplateExpression(expression)) {
6852
8274
  return expressionLooksLikeOpenRedirectQueryGetterFunction(
6853
8275
  expression.template,
6854
8276
  sourceFile,
@@ -6858,7 +8280,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6858
8280
  seenFunctions
6859
8281
  );
6860
8282
  }
6861
- if (ts.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalBooleanHelper(
8283
+ if (ts3.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalBooleanHelper(
6862
8284
  expression.expression,
6863
8285
  sourceFile,
6864
8286
  namedExpressions,
@@ -6874,7 +8296,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6874
8296
  )) {
6875
8297
  return true;
6876
8298
  }
6877
- if (ts.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalNumberHelper(
8299
+ if (ts3.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalNumberHelper(
6878
8300
  expression.expression,
6879
8301
  sourceFile,
6880
8302
  namedExpressions,
@@ -6890,7 +8312,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6890
8312
  )) {
6891
8313
  return true;
6892
8314
  }
6893
- if (ts.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalObjectHelper(
8315
+ if (ts3.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalObjectHelper(
6894
8316
  expression.expression,
6895
8317
  sourceFile,
6896
8318
  namedExpressions,
@@ -6906,7 +8328,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6906
8328
  )) {
6907
8329
  return true;
6908
8330
  }
6909
- if (ts.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalStringHelper(
8331
+ if (ts3.isNewExpression(expression) && expression.arguments && expression.arguments.length > 0 && expressionLooksLikeBrowserGlobalStringHelper(
6910
8332
  expression.expression,
6911
8333
  sourceFile,
6912
8334
  namedExpressions,
@@ -6938,7 +8360,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
6938
8360
  )) {
6939
8361
  return true;
6940
8362
  }
6941
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalSymbolHelper(
8363
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalSymbolHelper(
6942
8364
  expression.arguments[0],
6943
8365
  sourceFile,
6944
8366
  namedExpressions,
@@ -7002,7 +8424,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7002
8424
  )) {
7003
8425
  return true;
7004
8426
  }
7005
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBigIntHelper(
8427
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBigIntHelper(
7006
8428
  expression.arguments[0],
7007
8429
  sourceFile,
7008
8430
  namedExpressions,
@@ -7066,7 +8488,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7066
8488
  )) {
7067
8489
  return true;
7068
8490
  }
7069
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBooleanHelper(
8491
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBooleanHelper(
7070
8492
  expression.arguments[0],
7071
8493
  sourceFile,
7072
8494
  namedExpressions,
@@ -7130,7 +8552,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7130
8552
  )) {
7131
8553
  return true;
7132
8554
  }
7133
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalNumberHelper(
8555
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalNumberHelper(
7134
8556
  expression.arguments[0],
7135
8557
  sourceFile,
7136
8558
  namedExpressions,
@@ -7194,7 +8616,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7194
8616
  )) {
7195
8617
  return true;
7196
8618
  }
7197
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalObjectHelper(
8619
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalObjectHelper(
7198
8620
  expression.arguments[0],
7199
8621
  sourceFile,
7200
8622
  namedExpressions,
@@ -7242,7 +8664,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7242
8664
  )) {
7243
8665
  return true;
7244
8666
  }
7245
- if (isCallLikeExpression(expression) && ts.isIdentifier(expression.expression) && [
8667
+ if (isCallLikeExpression(expression) && ts3.isIdentifier(expression.expression) && [
7246
8668
  "String",
7247
8669
  "atob",
7248
8670
  "btoa",
@@ -7278,7 +8700,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7278
8700
  )) {
7279
8701
  return true;
7280
8702
  }
7281
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeJsonStringifyHelper(
8703
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeJsonStringifyHelper(
7282
8704
  expression.arguments[0],
7283
8705
  sourceFile,
7284
8706
  namedExpressions,
@@ -7342,7 +8764,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7342
8764
  )) {
7343
8765
  return true;
7344
8766
  }
7345
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeJsonParseHelper(
8767
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeJsonParseHelper(
7346
8768
  expression.arguments[0],
7347
8769
  sourceFile,
7348
8770
  namedExpressions,
@@ -7406,7 +8828,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7406
8828
  )) {
7407
8829
  return true;
7408
8830
  }
7409
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeStructuredCloneHelper(
8831
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeStructuredCloneHelper(
7410
8832
  expression.arguments[0],
7411
8833
  sourceFile,
7412
8834
  namedExpressions,
@@ -7470,7 +8892,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7470
8892
  )) {
7471
8893
  return true;
7472
8894
  }
7473
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalStringHelper(
8895
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalStringHelper(
7474
8896
  expression.arguments[0],
7475
8897
  sourceFile,
7476
8898
  namedExpressions,
@@ -7550,7 +8972,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7550
8972
  )) {
7551
8973
  return true;
7552
8974
  }
7553
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalUriCodecHelper(
8975
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalUriCodecHelper(
7554
8976
  expression.arguments[0],
7555
8977
  sourceFile,
7556
8978
  namedExpressions,
@@ -7598,7 +9020,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7598
9020
  )) {
7599
9021
  return true;
7600
9022
  }
7601
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBase64Helper(
9023
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBrowserGlobalBase64Helper(
7602
9024
  expression.arguments[0],
7603
9025
  sourceFile,
7604
9026
  namedExpressions,
@@ -7646,7 +9068,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7646
9068
  )) {
7647
9069
  return true;
7648
9070
  }
7649
- if (isCallLikeExpression(expression) && (ts.isIdentifier(expression.expression) || isMemberAccessExpression(expression.expression)) && expression.arguments.length > 0 && expressionLooksLikeBufferFromHelper(
9071
+ if (isCallLikeExpression(expression) && (ts3.isIdentifier(expression.expression) || isMemberAccessExpression(expression.expression)) && expression.arguments.length > 0 && expressionLooksLikeBufferFromHelper(
7650
9072
  expression.expression,
7651
9073
  sourceFile,
7652
9074
  namedExpressions,
@@ -7698,7 +9120,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7698
9120
  )) {
7699
9121
  return true;
7700
9122
  }
7701
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBufferFromHelper(
9123
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && expression.arguments.length > 2 && expressionLooksLikeBufferFromHelper(
7702
9124
  expression.arguments[0],
7703
9125
  sourceFile,
7704
9126
  namedExpressions,
@@ -7746,7 +9168,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7746
9168
  )) {
7747
9169
  return true;
7748
9170
  }
7749
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "from") && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Buffer" && expression.arguments.length > 0 && expressionLooksLikeOpenRedirectQueryGetterFunction(
9171
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "from") && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Buffer" && expression.arguments.length > 0 && expressionLooksLikeOpenRedirectQueryGetterFunction(
7750
9172
  expression.arguments[0],
7751
9173
  sourceFile,
7752
9174
  namedExpressions,
@@ -7925,7 +9347,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7925
9347
  )) {
7926
9348
  return true;
7927
9349
  }
7928
- if (isElementLikeAccessExpression(expression) && ts.isNumericLiteral(expression.argumentExpression) && expression.argumentExpression.text === "1" && isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "value") && isCallLikeExpression(expression.expression.expression) && isMemberAccessExpression(expression.expression.expression.expression) && isMemberAccessNamed(expression.expression.expression.expression, "next") && isCallLikeExpression(expression.expression.expression.expression.expression) && isMemberAccessExpression(expression.expression.expression.expression.expression.expression) && isMemberAccessNamed(
9350
+ if (isElementLikeAccessExpression(expression) && ts3.isNumericLiteral(expression.argumentExpression) && expression.argumentExpression.text === "1" && isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "value") && isCallLikeExpression(expression.expression.expression) && isMemberAccessExpression(expression.expression.expression.expression) && isMemberAccessNamed(expression.expression.expression.expression, "next") && isCallLikeExpression(expression.expression.expression.expression.expression) && isMemberAccessExpression(expression.expression.expression.expression.expression.expression) && isMemberAccessNamed(
7929
9351
  expression.expression.expression.expression.expression.expression,
7930
9352
  "entries"
7931
9353
  ) && expressionLooksLikeOpenRedirectQueryGetterFunction(
@@ -7958,7 +9380,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7958
9380
  )) {
7959
9381
  return true;
7960
9382
  }
7961
- if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Array" && isPropertyNamed(expression.expression.name, "from") && expression.arguments.length > 0 && expressionLooksLikeOpenRedirectQueryGetterFunction(
9383
+ if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Array" && isPropertyNamed(expression.expression.name, "from") && expression.arguments.length > 0 && expressionLooksLikeOpenRedirectQueryGetterFunction(
7962
9384
  expression.arguments[0],
7963
9385
  sourceFile,
7964
9386
  namedExpressions,
@@ -7968,8 +9390,8 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
7968
9390
  )) {
7969
9391
  return true;
7970
9392
  }
7971
- if (ts.isArrayLiteralExpression(expression) && expression.elements.some(
7972
- (element) => ts.isSpreadElement(element) && expressionLooksLikeOpenRedirectQueryGetterFunction(
9393
+ if (ts3.isArrayLiteralExpression(expression) && expression.elements.some(
9394
+ (element) => ts3.isSpreadElement(element) && expressionLooksLikeOpenRedirectQueryGetterFunction(
7973
9395
  element.expression,
7974
9396
  sourceFile,
7975
9397
  namedExpressions,
@@ -8020,7 +9442,7 @@ function expressionLooksLikeOpenRedirectQueryGetterFunction(expression, sourceFi
8020
9442
  )) {
8021
9443
  return true;
8022
9444
  }
8023
- if (ts.isIdentifier(expression)) {
9445
+ if (ts3.isIdentifier(expression)) {
8024
9446
  if (seenIdentifiers.has(expression.text)) return false;
8025
9447
  const initializer = namedExpressions.get(expression.text);
8026
9448
  if (initializer) {
@@ -8054,7 +9476,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8054
9476
  if (OPEN_REDIRECT_SOURCE_REGEX.test(expression.getText(sourceFile))) {
8055
9477
  return true;
8056
9478
  }
8057
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
9479
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8058
9480
  return expressionContainsOpenRedirectSource(
8059
9481
  expression.expression,
8060
9482
  sourceFile,
@@ -8064,7 +9486,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8064
9486
  seenFunctions
8065
9487
  );
8066
9488
  }
8067
- if (ts.isBinaryExpression(expression)) {
9489
+ if (ts3.isBinaryExpression(expression)) {
8068
9490
  return expressionContainsOpenRedirectSource(
8069
9491
  expression.left,
8070
9492
  sourceFile,
@@ -8081,7 +9503,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8081
9503
  seenFunctions
8082
9504
  );
8083
9505
  }
8084
- if (ts.isConditionalExpression(expression)) {
9506
+ if (ts3.isConditionalExpression(expression)) {
8085
9507
  return expressionContainsOpenRedirectSource(
8086
9508
  expression.condition,
8087
9509
  sourceFile,
@@ -8105,7 +9527,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8105
9527
  seenFunctions
8106
9528
  );
8107
9529
  }
8108
- if (ts.isTemplateExpression(expression)) {
9530
+ if (ts3.isTemplateExpression(expression)) {
8109
9531
  return expression.templateSpans.some(
8110
9532
  (span) => expressionContainsOpenRedirectSource(
8111
9533
  span.expression,
@@ -8117,7 +9539,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8117
9539
  )
8118
9540
  );
8119
9541
  }
8120
- if (ts.isTaggedTemplateExpression(expression)) {
9542
+ if (ts3.isTaggedTemplateExpression(expression)) {
8121
9543
  return expressionContainsOpenRedirectSource(
8122
9544
  expression.template,
8123
9545
  sourceFile,
@@ -8127,7 +9549,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8127
9549
  seenFunctions
8128
9550
  );
8129
9551
  }
8130
- if (ts.isNewExpression(expression)) {
9552
+ if (ts3.isNewExpression(expression)) {
8131
9553
  return (expression.arguments ?? []).some(
8132
9554
  (argument) => expressionContainsOpenRedirectSource(
8133
9555
  argument,
@@ -8139,9 +9561,9 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8139
9561
  )
8140
9562
  );
8141
9563
  }
8142
- if (ts.isArrayLiteralExpression(expression)) {
9564
+ if (ts3.isArrayLiteralExpression(expression)) {
8143
9565
  return expression.elements.some((element) => {
8144
- if (ts.isSpreadElement(element)) {
9566
+ if (ts3.isSpreadElement(element)) {
8145
9567
  return expressionContainsOpenRedirectSource(
8146
9568
  element.expression,
8147
9569
  sourceFile,
@@ -8151,7 +9573,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8151
9573
  seenFunctions
8152
9574
  );
8153
9575
  }
8154
- return ts.isExpression(element) && expressionContainsOpenRedirectSource(
9576
+ return ts3.isExpression(element) && expressionContainsOpenRedirectSource(
8155
9577
  element,
8156
9578
  sourceFile,
8157
9579
  namedExpressions,
@@ -8161,9 +9583,9 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8161
9583
  );
8162
9584
  });
8163
9585
  }
8164
- if (ts.isObjectLiteralExpression(expression)) {
9586
+ if (ts3.isObjectLiteralExpression(expression)) {
8165
9587
  return expression.properties.some((property) => {
8166
- if (ts.isPropertyAssignment(property)) {
9588
+ if (ts3.isPropertyAssignment(property)) {
8167
9589
  return expressionContainsOpenRedirectSource(
8168
9590
  property.initializer,
8169
9591
  sourceFile,
@@ -8173,7 +9595,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8173
9595
  seenFunctions
8174
9596
  );
8175
9597
  }
8176
- if (ts.isShorthandPropertyAssignment(property)) {
9598
+ if (ts3.isShorthandPropertyAssignment(property)) {
8177
9599
  return expressionContainsOpenRedirectSource(
8178
9600
  property.name,
8179
9601
  sourceFile,
@@ -8183,7 +9605,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8183
9605
  seenFunctions
8184
9606
  );
8185
9607
  }
8186
- if (ts.isSpreadAssignment(property)) {
9608
+ if (ts3.isSpreadAssignment(property)) {
8187
9609
  return expressionContainsOpenRedirectSource(
8188
9610
  property.expression,
8189
9611
  sourceFile,
@@ -8238,7 +9660,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8238
9660
  }
8239
9661
  }
8240
9662
  }
8241
- if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && isOpenRedirectQueryKeyExpression(
9663
+ if (isCallLikeExpression(expression) && isMemberAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Reflect" && isMemberAccessNamed(expression.expression, "apply") && isOpenRedirectQueryKeyExpression(
8242
9664
  getAliasedApplyArgumentExpression(expression.arguments[2], 0, namedExpressions, /* @__PURE__ */ new Set()),
8243
9665
  namedExpressions,
8244
9666
  seenIdentifiers
@@ -8354,7 +9776,7 @@ function expressionContainsOpenRedirectSource(expression, sourceFile, namedExpre
8354
9776
  )) {
8355
9777
  return true;
8356
9778
  }
8357
- if (ts.isIdentifier(expression)) {
9779
+ if (ts3.isIdentifier(expression)) {
8358
9780
  if (seenIdentifiers.has(expression.text)) {
8359
9781
  return false;
8360
9782
  }
@@ -8392,14 +9814,14 @@ function isOpenRedirectQueryKeyExpression(expression, namedExpressions = /* @__P
8392
9814
  return true;
8393
9815
  }
8394
9816
  if (!expression) return false;
8395
- if (ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression) || ts.isParenthesizedExpression(expression)) {
9817
+ if (ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression) || ts3.isParenthesizedExpression(expression)) {
8396
9818
  return isOpenRedirectQueryKeyExpression(
8397
9819
  expression.expression,
8398
9820
  namedExpressions,
8399
9821
  seenIdentifiers
8400
9822
  );
8401
9823
  }
8402
- if (ts.isIdentifier(expression)) {
9824
+ if (ts3.isIdentifier(expression)) {
8403
9825
  if (seenIdentifiers.has(expression.text)) return false;
8404
9826
  const initializer = namedExpressions.get(expression.text);
8405
9827
  if (!initializer) return false;
@@ -8415,7 +9837,7 @@ function expressionLooksLikeOpenRedirectQueryCarrier(expression, sourceFile, nam
8415
9837
  if (OPEN_REDIRECT_QUERY_CARRIER_REGEX.test(expression.getText(sourceFile))) {
8416
9838
  return true;
8417
9839
  }
8418
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
9840
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8419
9841
  return expressionLooksLikeOpenRedirectQueryCarrier(
8420
9842
  expression.expression,
8421
9843
  sourceFile,
@@ -8424,7 +9846,7 @@ function expressionLooksLikeOpenRedirectQueryCarrier(expression, sourceFile, nam
8424
9846
  seenIdentifiers
8425
9847
  );
8426
9848
  }
8427
- if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Object" && isPropertyNamed(expression.expression.name, "fromEntries") && expression.arguments.length > 0) {
9849
+ if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Object" && isPropertyNamed(expression.expression.name, "fromEntries") && expression.arguments.length > 0) {
8428
9850
  const entriesExpression = expression.arguments[0];
8429
9851
  if (expressionLooksLikeOpenRedirectSearchParamsCarrier(
8430
9852
  entriesExpression,
@@ -8454,7 +9876,7 @@ function expressionLooksLikeOpenRedirectQueryCarrier(expression, sourceFile, nam
8454
9876
  seenIdentifiers
8455
9877
  );
8456
9878
  }
8457
- if (ts.isIdentifier(expression)) {
9879
+ if (ts3.isIdentifier(expression)) {
8458
9880
  if (seenIdentifiers.has(expression.text)) return false;
8459
9881
  const initializer = namedExpressions.get(expression.text);
8460
9882
  if (initializer) {
@@ -8487,7 +9909,7 @@ function expressionLooksLikeOpenRedirectQueryCarrier(expression, sourceFile, nam
8487
9909
  }
8488
9910
  function expressionLooksLikeOpenRedirectEntriesCarrier(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
8489
9911
  if (!expression) return false;
8490
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
9912
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8491
9913
  return expressionLooksLikeOpenRedirectEntriesCarrier(
8492
9914
  expression.expression,
8493
9915
  sourceFile,
@@ -8496,7 +9918,7 @@ function expressionLooksLikeOpenRedirectEntriesCarrier(expression, sourceFile, n
8496
9918
  seenIdentifiers
8497
9919
  );
8498
9920
  }
8499
- if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Array" && isPropertyNamed(expression.expression.name, "from") && expression.arguments.length > 0 && (expressionLooksLikeOpenRedirectEntriesCarrier(
9921
+ if (isCallLikeExpression(expression) && isPropertyLikeAccessExpression(expression.expression) && ts3.isIdentifier(expression.expression.expression) && expression.expression.expression.text === "Array" && isPropertyNamed(expression.expression.name, "from") && expression.arguments.length > 0 && (expressionLooksLikeOpenRedirectEntriesCarrier(
8500
9922
  expression.arguments[0],
8501
9923
  sourceFile,
8502
9924
  namedExpressions,
@@ -8511,8 +9933,8 @@ function expressionLooksLikeOpenRedirectEntriesCarrier(expression, sourceFile, n
8511
9933
  ))) {
8512
9934
  return true;
8513
9935
  }
8514
- if (ts.isArrayLiteralExpression(expression) && expression.elements.some(
8515
- (element) => ts.isSpreadElement(element) && (expressionLooksLikeOpenRedirectEntriesCarrier(
9936
+ if (ts3.isArrayLiteralExpression(expression) && expression.elements.some(
9937
+ (element) => ts3.isSpreadElement(element) && (expressionLooksLikeOpenRedirectEntriesCarrier(
8516
9938
  element.expression,
8517
9939
  sourceFile,
8518
9940
  namedExpressions,
@@ -8537,7 +9959,7 @@ function expressionLooksLikeOpenRedirectEntriesCarrier(expression, sourceFile, n
8537
9959
  )) {
8538
9960
  return true;
8539
9961
  }
8540
- if (ts.isIdentifier(expression)) {
9962
+ if (ts3.isIdentifier(expression)) {
8541
9963
  if (seenIdentifiers.has(expression.text)) return false;
8542
9964
  const initializer = namedExpressions.get(expression.text);
8543
9965
  if (!initializer) return false;
@@ -8559,7 +9981,7 @@ function expressionLooksLikeOpenRedirectQueryContainerBase(expression, sourceFil
8559
9981
  if (OPEN_REDIRECT_QUERY_CONTAINER_BASE_REGEX.test(expression.getText(sourceFile))) {
8560
9982
  return true;
8561
9983
  }
8562
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
9984
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8563
9985
  return expressionLooksLikeOpenRedirectQueryContainerBase(
8564
9986
  expression.expression,
8565
9987
  sourceFile,
@@ -8568,10 +9990,10 @@ function expressionLooksLikeOpenRedirectQueryContainerBase(expression, sourceFil
8568
9990
  seenIdentifiers
8569
9991
  );
8570
9992
  }
8571
- if (isCallLikeExpression(expression) && (ts.isIdentifier(expression.expression) && expression.expression.text === "useRouter" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useRouter"))) {
9993
+ if (isCallLikeExpression(expression) && (ts3.isIdentifier(expression.expression) && expression.expression.text === "useRouter" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useRouter"))) {
8572
9994
  return true;
8573
9995
  }
8574
- if (ts.isIdentifier(expression)) {
9996
+ if (ts3.isIdentifier(expression)) {
8575
9997
  if (seenIdentifiers.has(expression.text)) return false;
8576
9998
  const initializer = namedExpressions.get(expression.text);
8577
9999
  if (initializer) {
@@ -8609,7 +10031,7 @@ function expressionLooksLikeLocationQuerySource(expression, sourceFile, namedExp
8609
10031
  if (LOCATION_QUERY_SOURCE_REGEX.test(expression.getText(sourceFile))) {
8610
10032
  return true;
8611
10033
  }
8612
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10034
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8613
10035
  return expressionLooksLikeLocationQuerySource(
8614
10036
  expression.expression,
8615
10037
  sourceFile,
@@ -8642,7 +10064,7 @@ function expressionLooksLikeLocationQuerySource(expression, sourceFile, namedExp
8642
10064
  ))) {
8643
10065
  return true;
8644
10066
  }
8645
- if (ts.isIdentifier(expression)) {
10067
+ if (ts3.isIdentifier(expression)) {
8646
10068
  if (seenIdentifiers.has(expression.text)) return false;
8647
10069
  const initializer = namedExpressions.get(expression.text);
8648
10070
  if (initializer) {
@@ -8678,10 +10100,10 @@ function expressionLooksLikeLocationQuerySource(expression, sourceFile, namedExp
8678
10100
  }
8679
10101
  function expressionLooksLikeWindowObjectSource(expression, sourceFile, namedExpressions, seenIdentifiers) {
8680
10102
  if (!expression) return false;
8681
- if (ts.isIdentifier(expression) && ["window", "globalThis", "document", "self", "parent", "top"].includes(expression.text)) {
10103
+ if (ts3.isIdentifier(expression) && ["window", "globalThis", "document", "self", "parent", "top"].includes(expression.text)) {
8682
10104
  return true;
8683
10105
  }
8684
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10106
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8685
10107
  return expressionLooksLikeWindowObjectSource(
8686
10108
  expression.expression,
8687
10109
  sourceFile,
@@ -8689,7 +10111,7 @@ function expressionLooksLikeWindowObjectSource(expression, sourceFile, namedExpr
8689
10111
  seenIdentifiers
8690
10112
  );
8691
10113
  }
8692
- if (ts.isIdentifier(expression)) {
10114
+ if (ts3.isIdentifier(expression)) {
8693
10115
  if (seenIdentifiers.has(expression.text)) return false;
8694
10116
  const initializer = namedExpressions.get(expression.text);
8695
10117
  if (!initializer) return false;
@@ -8710,7 +10132,7 @@ function expressionLooksLikeLocationObjectSource(expression, sourceFile, namedEx
8710
10132
  if (isLocationObjectExpression(expression)) {
8711
10133
  return true;
8712
10134
  }
8713
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10135
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8714
10136
  return expressionLooksLikeLocationObjectSource(
8715
10137
  expression.expression,
8716
10138
  sourceFile,
@@ -8719,7 +10141,7 @@ function expressionLooksLikeLocationObjectSource(expression, sourceFile, namedEx
8719
10141
  seenIdentifiers
8720
10142
  );
8721
10143
  }
8722
- if (isCallLikeExpression(expression) && (ts.isIdentifier(expression.expression) && expression.expression.text === "useLocation" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useLocation"))) {
10144
+ if (isCallLikeExpression(expression) && (ts3.isIdentifier(expression.expression) && expression.expression.text === "useLocation" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useLocation"))) {
8723
10145
  return true;
8724
10146
  }
8725
10147
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "location") && expressionLooksLikeWindowObjectSource(
@@ -8730,7 +10152,7 @@ function expressionLooksLikeLocationObjectSource(expression, sourceFile, namedEx
8730
10152
  )) {
8731
10153
  return true;
8732
10154
  }
8733
- if (ts.isIdentifier(expression)) {
10155
+ if (ts3.isIdentifier(expression)) {
8734
10156
  if (seenIdentifiers.has(expression.text)) return false;
8735
10157
  const initializer = namedExpressions.get(expression.text);
8736
10158
  if (initializer) {
@@ -8759,10 +10181,10 @@ function expressionLooksLikeLocationObjectSource(expression, sourceFile, namedEx
8759
10181
  }
8760
10182
  function expressionLooksLikeHistoryObjectSource(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
8761
10183
  if (!expression) return false;
8762
- if (ts.isIdentifier(expression) && expression.text === "history") {
10184
+ if (ts3.isIdentifier(expression) && expression.text === "history") {
8763
10185
  return true;
8764
10186
  }
8765
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10187
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8766
10188
  return expressionLooksLikeHistoryObjectSource(
8767
10189
  expression.expression,
8768
10190
  sourceFile,
@@ -8779,7 +10201,7 @@ function expressionLooksLikeHistoryObjectSource(expression, sourceFile, namedExp
8779
10201
  )) {
8780
10202
  return true;
8781
10203
  }
8782
- if (ts.isIdentifier(expression)) {
10204
+ if (ts3.isIdentifier(expression)) {
8783
10205
  if (seenIdentifiers.has(expression.text)) return false;
8784
10206
  const initializer = namedExpressions.get(expression.text);
8785
10207
  if (initializer) {
@@ -8808,10 +10230,10 @@ function expressionLooksLikeHistoryObjectSource(expression, sourceFile, namedExp
8808
10230
  }
8809
10231
  function expressionLooksLikeBufferObjectSource(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
8810
10232
  if (!expression) return false;
8811
- if (ts.isIdentifier(expression) && expression.text === "Buffer") {
10233
+ if (ts3.isIdentifier(expression) && expression.text === "Buffer") {
8812
10234
  return true;
8813
10235
  }
8814
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10236
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8815
10237
  return expressionLooksLikeBufferObjectSource(
8816
10238
  expression.expression,
8817
10239
  sourceFile,
@@ -8828,7 +10250,7 @@ function expressionLooksLikeBufferObjectSource(expression, sourceFile, namedExpr
8828
10250
  )) {
8829
10251
  return true;
8830
10252
  }
8831
- if (ts.isIdentifier(expression)) {
10253
+ if (ts3.isIdentifier(expression)) {
8832
10254
  if (seenIdentifiers.has(expression.text)) return false;
8833
10255
  const initializer = namedExpressions.get(expression.text);
8834
10256
  if (initializer) {
@@ -8875,7 +10297,7 @@ function expressionLooksLikeBufferFromHelper(expression, sourceFile, namedExpres
8875
10297
  )) {
8876
10298
  return true;
8877
10299
  }
8878
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10300
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8879
10301
  return expressionLooksLikeBufferFromHelper(
8880
10302
  expression.expression,
8881
10303
  sourceFile,
@@ -8884,7 +10306,7 @@ function expressionLooksLikeBufferFromHelper(expression, sourceFile, namedExpres
8884
10306
  seenIdentifiers
8885
10307
  );
8886
10308
  }
8887
- if (ts.isIdentifier(expression)) {
10309
+ if (ts3.isIdentifier(expression)) {
8888
10310
  if (seenIdentifiers.has(expression.text)) return false;
8889
10311
  const initializer = namedExpressions.get(expression.text);
8890
10312
  if (initializer) {
@@ -8914,10 +10336,10 @@ function expressionLooksLikeBufferFromHelper(expression, sourceFile, namedExpres
8914
10336
  }
8915
10337
  function expressionLooksLikeJsonObjectSource(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
8916
10338
  if (!expression) return false;
8917
- if (ts.isIdentifier(expression) && expression.text === "JSON") {
10339
+ if (ts3.isIdentifier(expression) && expression.text === "JSON") {
8918
10340
  return true;
8919
10341
  }
8920
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10342
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8921
10343
  return expressionLooksLikeJsonObjectSource(
8922
10344
  expression.expression,
8923
10345
  sourceFile,
@@ -8934,7 +10356,7 @@ function expressionLooksLikeJsonObjectSource(expression, sourceFile, namedExpres
8934
10356
  )) {
8935
10357
  return true;
8936
10358
  }
8937
- if (ts.isIdentifier(expression)) {
10359
+ if (ts3.isIdentifier(expression)) {
8938
10360
  if (seenIdentifiers.has(expression.text)) return false;
8939
10361
  const initializer = namedExpressions.get(expression.text);
8940
10362
  if (initializer) {
@@ -8981,7 +10403,7 @@ function expressionLooksLikeJsonStringifyHelper(expression, sourceFile, namedExp
8981
10403
  )) {
8982
10404
  return true;
8983
10405
  }
8984
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10406
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
8985
10407
  return expressionLooksLikeJsonStringifyHelper(
8986
10408
  expression.expression,
8987
10409
  sourceFile,
@@ -8990,7 +10412,7 @@ function expressionLooksLikeJsonStringifyHelper(expression, sourceFile, namedExp
8990
10412
  seenIdentifiers
8991
10413
  );
8992
10414
  }
8993
- if (ts.isIdentifier(expression)) {
10415
+ if (ts3.isIdentifier(expression)) {
8994
10416
  if (seenIdentifiers.has(expression.text)) return false;
8995
10417
  const initializer = namedExpressions.get(expression.text);
8996
10418
  if (initializer) {
@@ -9038,7 +10460,7 @@ function expressionLooksLikeJsonParseHelper(expression, sourceFile, namedExpress
9038
10460
  )) {
9039
10461
  return true;
9040
10462
  }
9041
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10463
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9042
10464
  return expressionLooksLikeJsonParseHelper(
9043
10465
  expression.expression,
9044
10466
  sourceFile,
@@ -9047,7 +10469,7 @@ function expressionLooksLikeJsonParseHelper(expression, sourceFile, namedExpress
9047
10469
  seenIdentifiers
9048
10470
  );
9049
10471
  }
9050
- if (ts.isIdentifier(expression)) {
10472
+ if (ts3.isIdentifier(expression)) {
9051
10473
  if (seenIdentifiers.has(expression.text)) return false;
9052
10474
  const initializer = namedExpressions.get(expression.text);
9053
10475
  if (initializer) {
@@ -9077,7 +10499,7 @@ function expressionLooksLikeJsonParseHelper(expression, sourceFile, namedExpress
9077
10499
  }
9078
10500
  function expressionLooksLikeStructuredCloneHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9079
10501
  if (!expression) return false;
9080
- if (ts.isIdentifier(expression) && expression.text === "structuredClone") {
10502
+ if (ts3.isIdentifier(expression) && expression.text === "structuredClone") {
9081
10503
  return true;
9082
10504
  }
9083
10505
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "structuredClone") && expressionLooksLikeWindowObjectSource(
@@ -9097,7 +10519,7 @@ function expressionLooksLikeStructuredCloneHelper(expression, sourceFile, namedE
9097
10519
  )) {
9098
10520
  return true;
9099
10521
  }
9100
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10522
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9101
10523
  return expressionLooksLikeStructuredCloneHelper(
9102
10524
  expression.expression,
9103
10525
  sourceFile,
@@ -9106,7 +10528,7 @@ function expressionLooksLikeStructuredCloneHelper(expression, sourceFile, namedE
9106
10528
  seenIdentifiers
9107
10529
  );
9108
10530
  }
9109
- if (ts.isIdentifier(expression)) {
10531
+ if (ts3.isIdentifier(expression)) {
9110
10532
  if (seenIdentifiers.has(expression.text)) return false;
9111
10533
  const initializer = namedExpressions.get(expression.text);
9112
10534
  if (initializer) {
@@ -9135,7 +10557,7 @@ function expressionLooksLikeStructuredCloneHelper(expression, sourceFile, namedE
9135
10557
  }
9136
10558
  function expressionLooksLikeBrowserGlobalSymbolHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9137
10559
  if (!expression) return false;
9138
- if (ts.isIdentifier(expression) && expression.text === "Symbol") {
10560
+ if (ts3.isIdentifier(expression) && expression.text === "Symbol") {
9139
10561
  return true;
9140
10562
  }
9141
10563
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "Symbol") && expressionLooksLikeWindowObjectSource(
@@ -9155,7 +10577,7 @@ function expressionLooksLikeBrowserGlobalSymbolHelper(expression, sourceFile, na
9155
10577
  )) {
9156
10578
  return true;
9157
10579
  }
9158
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10580
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9159
10581
  return expressionLooksLikeBrowserGlobalSymbolHelper(
9160
10582
  expression.expression,
9161
10583
  sourceFile,
@@ -9164,7 +10586,7 @@ function expressionLooksLikeBrowserGlobalSymbolHelper(expression, sourceFile, na
9164
10586
  seenIdentifiers
9165
10587
  );
9166
10588
  }
9167
- if (ts.isIdentifier(expression)) {
10589
+ if (ts3.isIdentifier(expression)) {
9168
10590
  if (seenIdentifiers.has(expression.text)) return false;
9169
10591
  const initializer = namedExpressions.get(expression.text);
9170
10592
  if (initializer) {
@@ -9193,7 +10615,7 @@ function expressionLooksLikeBrowserGlobalSymbolHelper(expression, sourceFile, na
9193
10615
  }
9194
10616
  function expressionLooksLikeBrowserGlobalBigIntHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9195
10617
  if (!expression) return false;
9196
- if (ts.isIdentifier(expression) && expression.text === "BigInt") {
10618
+ if (ts3.isIdentifier(expression) && expression.text === "BigInt") {
9197
10619
  return true;
9198
10620
  }
9199
10621
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "BigInt") && expressionLooksLikeWindowObjectSource(
@@ -9213,7 +10635,7 @@ function expressionLooksLikeBrowserGlobalBigIntHelper(expression, sourceFile, na
9213
10635
  )) {
9214
10636
  return true;
9215
10637
  }
9216
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10638
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9217
10639
  return expressionLooksLikeBrowserGlobalBigIntHelper(
9218
10640
  expression.expression,
9219
10641
  sourceFile,
@@ -9222,7 +10644,7 @@ function expressionLooksLikeBrowserGlobalBigIntHelper(expression, sourceFile, na
9222
10644
  seenIdentifiers
9223
10645
  );
9224
10646
  }
9225
- if (ts.isIdentifier(expression)) {
10647
+ if (ts3.isIdentifier(expression)) {
9226
10648
  if (seenIdentifiers.has(expression.text)) return false;
9227
10649
  const initializer = namedExpressions.get(expression.text);
9228
10650
  if (initializer) {
@@ -9251,7 +10673,7 @@ function expressionLooksLikeBrowserGlobalBigIntHelper(expression, sourceFile, na
9251
10673
  }
9252
10674
  function expressionLooksLikeBrowserGlobalBooleanHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9253
10675
  if (!expression) return false;
9254
- if (ts.isIdentifier(expression) && expression.text === "Boolean") {
10676
+ if (ts3.isIdentifier(expression) && expression.text === "Boolean") {
9255
10677
  return true;
9256
10678
  }
9257
10679
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "Boolean") && expressionLooksLikeWindowObjectSource(
@@ -9271,7 +10693,7 @@ function expressionLooksLikeBrowserGlobalBooleanHelper(expression, sourceFile, n
9271
10693
  )) {
9272
10694
  return true;
9273
10695
  }
9274
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10696
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9275
10697
  return expressionLooksLikeBrowserGlobalBooleanHelper(
9276
10698
  expression.expression,
9277
10699
  sourceFile,
@@ -9280,7 +10702,7 @@ function expressionLooksLikeBrowserGlobalBooleanHelper(expression, sourceFile, n
9280
10702
  seenIdentifiers
9281
10703
  );
9282
10704
  }
9283
- if (ts.isIdentifier(expression)) {
10705
+ if (ts3.isIdentifier(expression)) {
9284
10706
  if (seenIdentifiers.has(expression.text)) return false;
9285
10707
  const initializer = namedExpressions.get(expression.text);
9286
10708
  if (initializer) {
@@ -9309,7 +10731,7 @@ function expressionLooksLikeBrowserGlobalBooleanHelper(expression, sourceFile, n
9309
10731
  }
9310
10732
  function expressionLooksLikeBrowserGlobalNumberHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9311
10733
  if (!expression) return false;
9312
- if (ts.isIdentifier(expression) && expression.text === "Number") {
10734
+ if (ts3.isIdentifier(expression) && expression.text === "Number") {
9313
10735
  return true;
9314
10736
  }
9315
10737
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "Number") && expressionLooksLikeWindowObjectSource(
@@ -9329,7 +10751,7 @@ function expressionLooksLikeBrowserGlobalNumberHelper(expression, sourceFile, na
9329
10751
  )) {
9330
10752
  return true;
9331
10753
  }
9332
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10754
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9333
10755
  return expressionLooksLikeBrowserGlobalNumberHelper(
9334
10756
  expression.expression,
9335
10757
  sourceFile,
@@ -9338,7 +10760,7 @@ function expressionLooksLikeBrowserGlobalNumberHelper(expression, sourceFile, na
9338
10760
  seenIdentifiers
9339
10761
  );
9340
10762
  }
9341
- if (ts.isIdentifier(expression)) {
10763
+ if (ts3.isIdentifier(expression)) {
9342
10764
  if (seenIdentifiers.has(expression.text)) return false;
9343
10765
  const initializer = namedExpressions.get(expression.text);
9344
10766
  if (initializer) {
@@ -9367,7 +10789,7 @@ function expressionLooksLikeBrowserGlobalNumberHelper(expression, sourceFile, na
9367
10789
  }
9368
10790
  function expressionLooksLikeBrowserGlobalObjectHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9369
10791
  if (!expression) return false;
9370
- if (ts.isIdentifier(expression) && expression.text === "Object") {
10792
+ if (ts3.isIdentifier(expression) && expression.text === "Object") {
9371
10793
  return true;
9372
10794
  }
9373
10795
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "Object") && expressionLooksLikeWindowObjectSource(
@@ -9387,7 +10809,7 @@ function expressionLooksLikeBrowserGlobalObjectHelper(expression, sourceFile, na
9387
10809
  )) {
9388
10810
  return true;
9389
10811
  }
9390
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10812
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9391
10813
  return expressionLooksLikeBrowserGlobalObjectHelper(
9392
10814
  expression.expression,
9393
10815
  sourceFile,
@@ -9396,7 +10818,7 @@ function expressionLooksLikeBrowserGlobalObjectHelper(expression, sourceFile, na
9396
10818
  seenIdentifiers
9397
10819
  );
9398
10820
  }
9399
- if (ts.isIdentifier(expression)) {
10821
+ if (ts3.isIdentifier(expression)) {
9400
10822
  if (seenIdentifiers.has(expression.text)) return false;
9401
10823
  const initializer = namedExpressions.get(expression.text);
9402
10824
  if (initializer) {
@@ -9425,7 +10847,7 @@ function expressionLooksLikeBrowserGlobalObjectHelper(expression, sourceFile, na
9425
10847
  }
9426
10848
  function expressionLooksLikeBrowserGlobalStringHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9427
10849
  if (!expression) return false;
9428
- if (ts.isIdentifier(expression) && expression.text === "String") {
10850
+ if (ts3.isIdentifier(expression) && expression.text === "String") {
9429
10851
  return true;
9430
10852
  }
9431
10853
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "String") && expressionLooksLikeWindowObjectSource(
@@ -9445,7 +10867,7 @@ function expressionLooksLikeBrowserGlobalStringHelper(expression, sourceFile, na
9445
10867
  )) {
9446
10868
  return true;
9447
10869
  }
9448
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10870
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9449
10871
  return expressionLooksLikeBrowserGlobalStringHelper(
9450
10872
  expression.expression,
9451
10873
  sourceFile,
@@ -9454,7 +10876,7 @@ function expressionLooksLikeBrowserGlobalStringHelper(expression, sourceFile, na
9454
10876
  seenIdentifiers
9455
10877
  );
9456
10878
  }
9457
- if (ts.isIdentifier(expression)) {
10879
+ if (ts3.isIdentifier(expression)) {
9458
10880
  if (seenIdentifiers.has(expression.text)) return false;
9459
10881
  const initializer = namedExpressions.get(expression.text);
9460
10882
  if (initializer) {
@@ -9483,7 +10905,7 @@ function expressionLooksLikeBrowserGlobalStringHelper(expression, sourceFile, na
9483
10905
  }
9484
10906
  function expressionLooksLikeBrowserGlobalBase64Helper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9485
10907
  if (!expression) return false;
9486
- if (ts.isIdentifier(expression) && ["atob", "btoa"].includes(expression.text)) {
10908
+ if (ts3.isIdentifier(expression) && ["atob", "btoa"].includes(expression.text)) {
9487
10909
  return true;
9488
10910
  }
9489
10911
  if (isMemberAccessExpression(expression) && isMemberAccessNamed(expression, "atob", "btoa") && expressionLooksLikeWindowObjectSource(
@@ -9503,7 +10925,7 @@ function expressionLooksLikeBrowserGlobalBase64Helper(expression, sourceFile, na
9503
10925
  )) {
9504
10926
  return true;
9505
10927
  }
9506
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
10928
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9507
10929
  return expressionLooksLikeBrowserGlobalBase64Helper(
9508
10930
  expression.expression,
9509
10931
  sourceFile,
@@ -9512,7 +10934,7 @@ function expressionLooksLikeBrowserGlobalBase64Helper(expression, sourceFile, na
9512
10934
  seenIdentifiers
9513
10935
  );
9514
10936
  }
9515
- if (ts.isIdentifier(expression)) {
10937
+ if (ts3.isIdentifier(expression)) {
9516
10938
  if (seenIdentifiers.has(expression.text)) return false;
9517
10939
  const initializer = namedExpressions.get(expression.text);
9518
10940
  if (initializer) {
@@ -9541,7 +10963,7 @@ function expressionLooksLikeBrowserGlobalBase64Helper(expression, sourceFile, na
9541
10963
  }
9542
10964
  function expressionLooksLikeBrowserGlobalUriCodecHelper(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9543
10965
  if (!expression) return false;
9544
- if (ts.isIdentifier(expression) && [
10966
+ if (ts3.isIdentifier(expression) && [
9545
10967
  "decodeURI",
9546
10968
  "decodeURIComponent",
9547
10969
  "encodeURI",
@@ -9576,7 +10998,7 @@ function expressionLooksLikeBrowserGlobalUriCodecHelper(expression, sourceFile,
9576
10998
  )) {
9577
10999
  return true;
9578
11000
  }
9579
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11001
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9580
11002
  return expressionLooksLikeBrowserGlobalUriCodecHelper(
9581
11003
  expression.expression,
9582
11004
  sourceFile,
@@ -9585,7 +11007,7 @@ function expressionLooksLikeBrowserGlobalUriCodecHelper(expression, sourceFile,
9585
11007
  seenIdentifiers
9586
11008
  );
9587
11009
  }
9588
- if (ts.isIdentifier(expression)) {
11010
+ if (ts3.isIdentifier(expression)) {
9589
11011
  if (seenIdentifiers.has(expression.text)) return false;
9590
11012
  const initializer = namedExpressions.get(expression.text);
9591
11013
  if (initializer) {
@@ -9624,7 +11046,7 @@ function expressionLooksLikeLocationUrlSource(expression, sourceFile, namedExpre
9624
11046
  if (LOCATION_URL_SOURCE_REGEX.test(expression.getText(sourceFile))) {
9625
11047
  return true;
9626
11048
  }
9627
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11049
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9628
11050
  return expressionLooksLikeLocationUrlSource(
9629
11051
  expression.expression,
9630
11052
  sourceFile,
@@ -9633,7 +11055,7 @@ function expressionLooksLikeLocationUrlSource(expression, sourceFile, namedExpre
9633
11055
  seenIdentifiers
9634
11056
  );
9635
11057
  }
9636
- if (ts.isNewExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "URL") {
11058
+ if (ts3.isNewExpression(expression) && ts3.isIdentifier(expression.expression) && expression.expression.text === "URL") {
9637
11059
  return expressionLooksLikeLocationUrlInput(
9638
11060
  expression.arguments?.[0],
9639
11061
  sourceFile,
@@ -9642,7 +11064,7 @@ function expressionLooksLikeLocationUrlSource(expression, sourceFile, namedExpre
9642
11064
  seenIdentifiers
9643
11065
  );
9644
11066
  }
9645
- if (ts.isIdentifier(expression)) {
11067
+ if (ts3.isIdentifier(expression)) {
9646
11068
  if (seenIdentifiers.has(expression.text)) return false;
9647
11069
  const initializer = namedExpressions.get(expression.text);
9648
11070
  if (!initializer) return false;
@@ -9664,7 +11086,7 @@ function expressionLooksLikeLocationUrlInput(expression, sourceFile, namedExpres
9664
11086
  if (LOCATION_URL_INPUT_REGEX.test(expression.getText(sourceFile))) {
9665
11087
  return true;
9666
11088
  }
9667
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11089
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9668
11090
  return expressionLooksLikeLocationUrlInput(
9669
11091
  expression.expression,
9670
11092
  sourceFile,
@@ -9682,7 +11104,7 @@ function expressionLooksLikeLocationUrlInput(expression, sourceFile, namedExpres
9682
11104
  )) {
9683
11105
  return true;
9684
11106
  }
9685
- if (isCallLikeExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "String" && expression.arguments.length > 0 && (expressionLooksLikeLocationObjectSource(
11107
+ if (isCallLikeExpression(expression) && ts3.isIdentifier(expression.expression) && expression.expression.text === "String" && expression.arguments.length > 0 && (expressionLooksLikeLocationObjectSource(
9686
11108
  expression.arguments[0],
9687
11109
  sourceFile,
9688
11110
  namedExpressions,
@@ -9735,7 +11157,7 @@ function expressionLooksLikeLocationUrlInput(expression, sourceFile, namedExpres
9735
11157
  )) {
9736
11158
  return true;
9737
11159
  }
9738
- if (ts.isIdentifier(expression)) {
11160
+ if (ts3.isIdentifier(expression)) {
9739
11161
  if (seenIdentifiers.has(expression.text)) return false;
9740
11162
  const initializer = namedExpressions.get(expression.text);
9741
11163
  if (initializer) {
@@ -9782,7 +11204,7 @@ function expressionLooksLikeRequestObjectSource(expression, sourceFile, namedExp
9782
11204
  if (REQUEST_OBJECT_SOURCE_REGEX.test(expression.getText(sourceFile))) {
9783
11205
  return true;
9784
11206
  }
9785
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11207
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9786
11208
  return expressionLooksLikeRequestObjectSource(
9787
11209
  expression.expression,
9788
11210
  sourceFile,
@@ -9790,7 +11212,7 @@ function expressionLooksLikeRequestObjectSource(expression, sourceFile, namedExp
9790
11212
  seenIdentifiers
9791
11213
  );
9792
11214
  }
9793
- if (ts.isIdentifier(expression)) {
11215
+ if (ts3.isIdentifier(expression)) {
9794
11216
  if (seenIdentifiers.has(expression.text)) return false;
9795
11217
  const initializer = namedExpressions.get(expression.text);
9796
11218
  if (!initializer) return false;
@@ -9811,7 +11233,7 @@ function expressionLooksLikeNextUrlSource(expression, sourceFile, namedExpressio
9811
11233
  if (NEXT_URL_SOURCE_REGEX.test(expression.getText(sourceFile))) {
9812
11234
  return true;
9813
11235
  }
9814
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11236
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9815
11237
  return expressionLooksLikeNextUrlSource(
9816
11238
  expression.expression,
9817
11239
  sourceFile,
@@ -9837,7 +11259,7 @@ function expressionLooksLikeNextUrlSource(expression, sourceFile, namedExpressio
9837
11259
  seenIdentifiers
9838
11260
  );
9839
11261
  }
9840
- if (ts.isIdentifier(expression)) {
11262
+ if (ts3.isIdentifier(expression)) {
9841
11263
  if (seenIdentifiers.has(expression.text)) return false;
9842
11264
  const initializer = namedExpressions.get(expression.text);
9843
11265
  if (initializer) {
@@ -9871,7 +11293,7 @@ function expressionLooksLikeOpenRedirectSearchParamsCarrier(expression, sourceFi
9871
11293
  if (/\b(?:searchParams|(?:request|req)\.nextUrl\.searchParams|url\.searchParams)\b/i.test(text)) {
9872
11294
  return true;
9873
11295
  }
9874
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11296
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9875
11297
  return expressionLooksLikeOpenRedirectSearchParamsCarrier(
9876
11298
  expression.expression,
9877
11299
  sourceFile,
@@ -9880,7 +11302,7 @@ function expressionLooksLikeOpenRedirectSearchParamsCarrier(expression, sourceFi
9880
11302
  seenIdentifiers
9881
11303
  );
9882
11304
  }
9883
- if (ts.isNewExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "URLSearchParams") {
11305
+ if (ts3.isNewExpression(expression) && ts3.isIdentifier(expression.expression) && expression.expression.text === "URLSearchParams") {
9884
11306
  return expressionLooksLikeLocationQuerySource(
9885
11307
  expression.arguments?.[0],
9886
11308
  sourceFile,
@@ -9889,7 +11311,7 @@ function expressionLooksLikeOpenRedirectSearchParamsCarrier(expression, sourceFi
9889
11311
  seenIdentifiers
9890
11312
  );
9891
11313
  }
9892
- if (isCallLikeExpression(expression) && (ts.isIdentifier(expression.expression) && expression.expression.text === "useSearchParams" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useSearchParams"))) {
11314
+ if (isCallLikeExpression(expression) && (ts3.isIdentifier(expression.expression) && expression.expression.text === "useSearchParams" || isMemberAccessExpression(expression.expression) && isMemberAccessNamed(expression.expression, "useSearchParams"))) {
9893
11315
  return true;
9894
11316
  }
9895
11317
  if (isPropertyLikeAccessExpression(expression) && isPropertyNamed(expression.name, "searchParams")) {
@@ -9907,7 +11329,7 @@ function expressionLooksLikeOpenRedirectSearchParamsCarrier(expression, sourceFi
9907
11329
  seenIdentifiers
9908
11330
  );
9909
11331
  }
9910
- if (ts.isIdentifier(expression)) {
11332
+ if (ts3.isIdentifier(expression)) {
9911
11333
  if (seenIdentifiers.has(expression.text)) return false;
9912
11334
  const initializer = namedExpressions.get(expression.text);
9913
11335
  if (initializer) {
@@ -9947,7 +11369,7 @@ function expressionLooksLikeLocationAssignmentTarget(expression, sourceFile, nam
9947
11369
  if (isLocationAssignmentTarget(expression)) {
9948
11370
  return true;
9949
11371
  }
9950
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11372
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9951
11373
  return expressionLooksLikeLocationAssignmentTarget(
9952
11374
  expression.expression,
9953
11375
  sourceFile,
@@ -9969,7 +11391,7 @@ function expressionLooksLikeLocationAssignmentTarget(expression, sourceFile, nam
9969
11391
  }
9970
11392
  function expressionLooksLikeLocationMutationCall(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
9971
11393
  if (!expression) return false;
9972
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11394
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
9973
11395
  return expressionLooksLikeLocationMutationCall(
9974
11396
  expression.expression,
9975
11397
  sourceFile,
@@ -9996,7 +11418,7 @@ function expressionLooksLikeLocationMutationCall(expression, sourceFile, namedEx
9996
11418
  seenIdentifiers
9997
11419
  );
9998
11420
  }
9999
- if (ts.isIdentifier(expression)) {
11421
+ if (ts3.isIdentifier(expression)) {
10000
11422
  if (seenIdentifiers.has(expression.text)) return false;
10001
11423
  const initializer = namedExpressions.get(expression.text);
10002
11424
  if (initializer) {
@@ -10035,7 +11457,7 @@ function expressionLooksLikeLocationMutationCall(expression, sourceFile, namedEx
10035
11457
  }
10036
11458
  function expressionLooksLikeWindowOpenCall(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
10037
11459
  if (!expression) return false;
10038
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11460
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
10039
11461
  return expressionLooksLikeWindowOpenCall(
10040
11462
  expression.expression,
10041
11463
  sourceFile,
@@ -10053,10 +11475,10 @@ function expressionLooksLikeWindowOpenCall(expression, sourceFile, namedExpressi
10053
11475
  seenIdentifiers
10054
11476
  );
10055
11477
  }
10056
- if (ts.isIdentifier(expression) && expression.text === "open") {
11478
+ if (ts3.isIdentifier(expression) && expression.text === "open") {
10057
11479
  return true;
10058
11480
  }
10059
- if (ts.isIdentifier(expression)) {
11481
+ if (ts3.isIdentifier(expression)) {
10060
11482
  if (seenIdentifiers.has(expression.text)) return false;
10061
11483
  const initializer = namedExpressions.get(expression.text);
10062
11484
  if (initializer) {
@@ -10092,7 +11514,7 @@ function expressionLooksLikeWindowOpenCall(expression, sourceFile, namedExpressi
10092
11514
  }
10093
11515
  function expressionLooksLikeHistoryMutationCall(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
10094
11516
  if (!expression) return false;
10095
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11517
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
10096
11518
  return expressionLooksLikeHistoryMutationCall(
10097
11519
  expression.expression,
10098
11520
  sourceFile,
@@ -10119,7 +11541,7 @@ function expressionLooksLikeHistoryMutationCall(expression, sourceFile, namedExp
10119
11541
  seenIdentifiers
10120
11542
  );
10121
11543
  }
10122
- if (ts.isIdentifier(expression)) {
11544
+ if (ts3.isIdentifier(expression)) {
10123
11545
  if (seenIdentifiers.has(expression.text)) return false;
10124
11546
  const initializer = namedExpressions.get(expression.text);
10125
11547
  if (initializer) {
@@ -10158,7 +11580,7 @@ function expressionLooksLikeHistoryMutationCall(expression, sourceFile, namedExp
10158
11580
  }
10159
11581
  function expressionLooksLikeRouteTransitionCall(expression, sourceFile, namedExpressions, namedPropertyAliases, seenIdentifiers) {
10160
11582
  if (!expression) return false;
10161
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11583
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
10162
11584
  return expressionLooksLikeRouteTransitionCall(
10163
11585
  expression.expression,
10164
11586
  sourceFile,
@@ -10185,7 +11607,7 @@ function expressionLooksLikeRouteTransitionCall(expression, sourceFile, namedExp
10185
11607
  seenIdentifiers
10186
11608
  );
10187
11609
  }
10188
- if (ts.isIdentifier(expression)) {
11610
+ if (ts3.isIdentifier(expression)) {
10189
11611
  if (["redirect", "navigate"].includes(expression.text)) {
10190
11612
  return true;
10191
11613
  }
@@ -10231,7 +11653,7 @@ function expressionLooksLikeRouteTransitionCall(expression, sourceFile, namedExp
10231
11653
  );
10232
11654
  }
10233
11655
  function getRouteTransitionTargetExpression(node, sourceFile, namedExpressions, namedPropertyAliases) {
10234
- if (isMemberAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeRouteTransitionCall(
11656
+ if (isMemberAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeRouteTransitionCall(
10235
11657
  node.arguments[0],
10236
11658
  sourceFile,
10237
11659
  namedExpressions,
@@ -10276,7 +11698,7 @@ function getRouteTransitionTargetExpression(node, sourceFile, namedExpressions,
10276
11698
  )) {
10277
11699
  return getAliasedApplyArgumentExpression(node.arguments[1], 2, namedExpressions, /* @__PURE__ */ new Set());
10278
11700
  }
10279
- if (isMemberAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeHistoryMutationCall(
11701
+ if (isMemberAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeHistoryMutationCall(
10280
11702
  node.arguments[0],
10281
11703
  sourceFile,
10282
11704
  namedExpressions,
@@ -10307,7 +11729,7 @@ function getRouteTransitionTargetExpression(node, sourceFile, namedExpressions,
10307
11729
  }
10308
11730
  function getAliasedApplyArgumentExpression(expression, index, namedExpressions, seenIdentifiers) {
10309
11731
  if (!expression) return void 0;
10310
- if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression)) {
11732
+ if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
10311
11733
  return getAliasedApplyArgumentExpression(
10312
11734
  expression.expression,
10313
11735
  index,
@@ -10315,7 +11737,7 @@ function getAliasedApplyArgumentExpression(expression, index, namedExpressions,
10315
11737
  seenIdentifiers
10316
11738
  );
10317
11739
  }
10318
- if (ts.isIdentifier(expression)) {
11740
+ if (ts3.isIdentifier(expression)) {
10319
11741
  if (seenIdentifiers.has(expression.text)) return void 0;
10320
11742
  const initializer = namedExpressions.get(expression.text);
10321
11743
  if (!initializer) return void 0;
@@ -10329,12 +11751,12 @@ function getAliasedApplyArgumentExpression(expression, index, namedExpressions,
10329
11751
  seenIdentifiers.delete(expression.text);
10330
11752
  return result;
10331
11753
  }
10332
- if (!ts.isArrayLiteralExpression(expression)) return void 0;
11754
+ if (!ts3.isArrayLiteralExpression(expression)) return void 0;
10333
11755
  const argument = expression.elements[index];
10334
- return ts.isExpression(argument) ? argument : void 0;
11756
+ return ts3.isExpression(argument) ? argument : void 0;
10335
11757
  }
10336
11758
  function getLocationMutationTargetExpression(node, sourceFile, namedExpressions, namedPropertyAliases) {
10337
- if (isMemberAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeLocationMutationCall(
11759
+ if (isMemberAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeLocationMutationCall(
10338
11760
  node.arguments[0],
10339
11761
  sourceFile,
10340
11762
  namedExpressions,
@@ -10373,7 +11795,7 @@ function getLocationMutationTargetExpression(node, sourceFile, namedExpressions,
10373
11795
  return void 0;
10374
11796
  }
10375
11797
  function getWindowOpenTargetExpression(node, sourceFile, namedExpressions, namedPropertyAliases) {
10376
- if (isMemberAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeWindowOpenCall(
11798
+ if (isMemberAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "Reflect" && isMemberAccessNamed(node.expression, "apply") && expressionLooksLikeWindowOpenCall(
10377
11799
  node.arguments[0],
10378
11800
  sourceFile,
10379
11801
  namedExpressions,
@@ -10512,28 +11934,28 @@ var DYNAMIC_GEOMETRY_STYLE_PROPS = /* @__PURE__ */ new Set([
10512
11934
  "y"
10513
11935
  ]);
10514
11936
  function getJsxAttributeExpression(initializer) {
10515
- if (!initializer || !ts.isJsxExpression(initializer)) return null;
11937
+ if (!initializer || !ts3.isJsxExpression(initializer)) return null;
10516
11938
  return initializer.expression ?? null;
10517
11939
  }
10518
11940
  function getStylePropertyName(name) {
10519
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
11941
+ if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
10520
11942
  return name.text;
10521
11943
  }
10522
- if (ts.isComputedPropertyName(name)) {
11944
+ if (ts3.isComputedPropertyName(name)) {
10523
11945
  return getExpressionLiteralValue(name.expression);
10524
11946
  }
10525
11947
  return null;
10526
11948
  }
10527
11949
  function unwrapStyleExpression(expression) {
10528
11950
  let current = expression;
10529
- while (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current) || ts.isSatisfiesExpression(current)) {
11951
+ while (ts3.isParenthesizedExpression(current) || ts3.isAsExpression(current) || ts3.isTypeAssertionExpression(current) || ts3.isNonNullExpression(current) || ts3.isSatisfiesExpression(current)) {
10530
11952
  current = current.expression;
10531
11953
  }
10532
11954
  return current;
10533
11955
  }
10534
11956
  function isDynamicStyleValue(expression) {
10535
11957
  const unwrapped = unwrapStyleExpression(expression);
10536
- if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped) || ts.isNumericLiteral(unwrapped) || unwrapped.kind === ts.SyntaxKind.TrueKeyword || unwrapped.kind === ts.SyntaxKind.FalseKeyword || unwrapped.kind === ts.SyntaxKind.NullKeyword) {
11958
+ if (ts3.isStringLiteral(unwrapped) || ts3.isNoSubstitutionTemplateLiteral(unwrapped) || ts3.isNumericLiteral(unwrapped) || unwrapped.kind === ts3.SyntaxKind.TrueKeyword || unwrapped.kind === ts3.SyntaxKind.FalseKeyword || unwrapped.kind === ts3.SyntaxKind.NullKeyword) {
10537
11959
  return false;
10538
11960
  }
10539
11961
  return true;
@@ -10542,13 +11964,13 @@ function isAllowedInlineStyleObject(objectLiteral) {
10542
11964
  let sawGeometryProperty = false;
10543
11965
  let sawDynamicGeometryValue = false;
10544
11966
  for (const property of objectLiteral.properties) {
10545
- if (!ts.isPropertyAssignment(property)) return false;
10546
- const propertyName = getStylePropertyName(property.name);
10547
- if (!propertyName) return false;
10548
- if (propertyName.startsWith("--d-")) {
11967
+ if (!ts3.isPropertyAssignment(property)) return false;
11968
+ const propertyName2 = getStylePropertyName(property.name);
11969
+ if (!propertyName2) return false;
11970
+ if (propertyName2.startsWith("--d-")) {
10549
11971
  continue;
10550
11972
  }
10551
- if (!DYNAMIC_GEOMETRY_STYLE_PROPS.has(propertyName)) {
11973
+ if (!DYNAMIC_GEOMETRY_STYLE_PROPS.has(propertyName2)) {
10552
11974
  return false;
10553
11975
  }
10554
11976
  sawGeometryProperty = true;
@@ -10571,10 +11993,10 @@ function isAllowedInlineStyleAttribute(attribute, sourceFile, namedExpressions,
10571
11993
  return resolved ? isAllowedInlineStyleObject(resolved.objectLiteral) : false;
10572
11994
  }
10573
11995
  function analyzeAstSignals(filePath, code) {
10574
- const sourceFile = ts.createSourceFile(
11996
+ const sourceFile = ts3.createSourceFile(
10575
11997
  filePath,
10576
11998
  code,
10577
- ts.ScriptTarget.Latest,
11999
+ ts3.ScriptTarget.Latest,
10578
12000
  true,
10579
12001
  getScriptKind(filePath)
10580
12002
  );
@@ -10659,7 +12081,7 @@ function analyzeAstSignals(filePath, code) {
10659
12081
  let navigationLandmarkCount = 0;
10660
12082
  let unlabeledNavigationLandmarkCount = 0;
10661
12083
  const walk = (node) => {
10662
- if (ts.isJsxAttribute(node)) {
12084
+ if (ts3.isJsxAttribute(node)) {
10663
12085
  if (isPropertyNamed(node.name, "style") && node.initializer) {
10664
12086
  if (!isAllowedInlineStyleAttribute(
10665
12087
  node,
@@ -10673,7 +12095,7 @@ function analyzeAstSignals(filePath, code) {
10673
12095
  if (isPropertyNamed(node.name, "dangerouslySetInnerHTML") && !isSafeJsonLdDangerouslySetInnerHtml(node)) {
10674
12096
  signals.dangerousHtmlCount += 1;
10675
12097
  }
10676
- if (isPropertyNamed(node.name, "href", "to") && node.initializer && ts.isJsxExpression(node.initializer) && expressionContainsOpenRedirectSource(
12098
+ if (isPropertyNamed(node.name, "href", "to") && node.initializer && ts3.isJsxExpression(node.initializer) && expressionContainsOpenRedirectSource(
10677
12099
  node.initializer.expression,
10678
12100
  sourceFile,
10679
12101
  namedExpressionInitializers,
@@ -10691,10 +12113,10 @@ function analyzeAstSignals(filePath, code) {
10691
12113
  signals.authProviderNonceMissingCount += 1;
10692
12114
  }
10693
12115
  }
10694
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && isPropertyNamed(node.left.name, "innerHTML", "outerHTML")) {
12116
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && ts3.isPropertyAccessExpression(node.left) && isPropertyNamed(node.left.name, "innerHTML", "outerHTML")) {
10695
12117
  signals.rawHtmlInjectionCount += 1;
10696
12118
  }
10697
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
12119
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
10698
12120
  node.left,
10699
12121
  sourceFile,
10700
12122
  namedExpressionInitializers,
@@ -10708,7 +12130,7 @@ function analyzeAstSignals(filePath, code) {
10708
12130
  )) {
10709
12131
  signals.authOpenRedirectSignalCount += 1;
10710
12132
  }
10711
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
12133
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
10712
12134
  node.left,
10713
12135
  sourceFile,
10714
12136
  namedExpressionInitializers,
@@ -10717,7 +12139,7 @@ function analyzeAstSignals(filePath, code) {
10717
12139
  ) && isInsecureTransportUrl(getExpressionLiteralValue(node.right))) {
10718
12140
  signals.insecureTransportEndpointCount += 1;
10719
12141
  }
10720
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
12142
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
10721
12143
  node.left,
10722
12144
  sourceFile,
10723
12145
  namedExpressionInitializers,
@@ -10735,7 +12157,7 @@ function analyzeAstSignals(filePath, code) {
10735
12157
  signals.authProviderNonceMissingCount += 1;
10736
12158
  }
10737
12159
  }
10738
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
12160
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && expressionLooksLikeLocationAssignmentTarget(
10739
12161
  node.left,
10740
12162
  sourceFile,
10741
12163
  namedExpressionInitializers,
@@ -10749,36 +12171,36 @@ function analyzeAstSignals(filePath, code) {
10749
12171
  )) {
10750
12172
  signals.authOpenRedirectSignalCount += 1;
10751
12173
  }
10752
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && isPropertyNamed(node.left.name, "onmessage")) {
12174
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && ts3.isPropertyAccessExpression(node.left) && isPropertyNamed(node.left.name, "onmessage")) {
10753
12175
  const handler = resolveFunctionLikeHandler(node.right, namedFunctionDeclarations);
10754
12176
  if (handler && !functionLikeReferencesOrigin(handler)) {
10755
12177
  signals.messageListenerWithoutOriginCheckCount += 1;
10756
12178
  }
10757
12179
  }
10758
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && isBrowserStorageObject(node.left.expression) && /(?:token|auth|jwt|session)/i.test(node.left.name.text)) {
12180
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && ts3.isPropertyAccessExpression(node.left) && isBrowserStorageObject(node.left.expression) && /(?:token|auth|jwt|session)/i.test(node.left.name.text)) {
10759
12181
  signals.authStorageWriteCount += 1;
10760
12182
  }
10761
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isElementAccessExpression(node.left) && isBrowserStorageObject(node.left.expression) && isAuthStorageKeyLiteral(node.left.argumentExpression)) {
12183
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && ts3.isElementAccessExpression(node.left) && isBrowserStorageObject(node.left.expression) && isAuthStorageKeyLiteral(node.left.argumentExpression)) {
10762
12184
  signals.authStorageWriteCount += 1;
10763
12185
  }
10764
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && isCookiePropertyAccess(node.left) && hasAuthCredentialText(node.right, sourceFile)) {
12186
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && isCookiePropertyAccess(node.left) && hasAuthCredentialText(node.right, sourceFile)) {
10765
12187
  signals.authCookieWriteCount += 1;
10766
12188
  }
10767
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && isAuthorizationHeaderAccess(node.left)) {
12189
+ if (ts3.isBinaryExpression(node) && node.operatorToken.kind === ts3.SyntaxKind.EqualsToken && isAuthorizationHeaderAccess(node.left)) {
10768
12190
  if (isHeaderClearValue(node.right)) {
10769
12191
  signals.authHeaderClearCount += 1;
10770
12192
  } else {
10771
12193
  signals.authHeaderWriteCount += 1;
10772
12194
  }
10773
12195
  }
10774
- if (ts.isPropertyAssignment(node) && isAuthorizationHeaderName(node.name)) {
12196
+ if (ts3.isPropertyAssignment(node) && isAuthorizationHeaderName(node.name)) {
10775
12197
  if (isHeaderClearValue(node.initializer)) {
10776
12198
  signals.authHeaderClearCount += 1;
10777
12199
  } else {
10778
12200
  signals.authHeaderWriteCount += 1;
10779
12201
  }
10780
12202
  }
10781
- if (ts.isDeleteExpression(node) && isAuthorizationHeaderAccess(node.expression)) {
12203
+ if (ts3.isDeleteExpression(node) && isAuthorizationHeaderAccess(node.expression)) {
10782
12204
  signals.authHeaderClearCount += 1;
10783
12205
  }
10784
12206
  if (isCallLikeExpression(node)) {
@@ -10809,10 +12231,10 @@ function analyzeAstSignals(filePath, code) {
10809
12231
  namedPropertyAliases
10810
12232
  );
10811
12233
  const windowOpenTargetLiteral = getExpressionLiteralValue(windowOpenTargetExpression);
10812
- if (ts.isIdentifier(node.expression) && node.expression.text === "eval") {
12234
+ if (ts3.isIdentifier(node.expression) && node.expression.text === "eval") {
10813
12235
  signals.dynamicEvalCount += 1;
10814
12236
  }
10815
- if ((ts.isIdentifier(node.expression) && ["setTimeout", "setInterval"].includes(node.expression.text) || ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "window" && isPropertyNamed(node.expression.name, "setTimeout", "setInterval")) && typeof firstArgumentLiteral === "string") {
12237
+ if ((ts3.isIdentifier(node.expression) && ["setTimeout", "setInterval"].includes(node.expression.text) || ts3.isPropertyAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "window" && isPropertyNamed(node.expression.name, "setTimeout", "setInterval")) && typeof firstArgumentLiteral === "string") {
10816
12238
  signals.dynamicEvalCount += 1;
10817
12239
  }
10818
12240
  if ((isFetchLikeCall(node) || isAxiosLikeCall(node)) && isInsecureTransportUrl(firstArgumentLiteral)) {
@@ -10894,7 +12316,7 @@ function analyzeAstSignals(filePath, code) {
10894
12316
  signals.authProviderNonceMissingCount += 1;
10895
12317
  }
10896
12318
  }
10897
- if (ts.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "postMessage") && secondArgumentLiteral === "*") {
12319
+ if (ts3.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "postMessage") && secondArgumentLiteral === "*") {
10898
12320
  signals.wildcardPostMessageCount += 1;
10899
12321
  }
10900
12322
  if (isAddEventListenerCall(node) && firstArgumentLiteral === "message") {
@@ -10903,7 +12325,7 @@ function analyzeAstSignals(filePath, code) {
10903
12325
  signals.messageListenerWithoutOriginCheckCount += 1;
10904
12326
  }
10905
12327
  }
10906
- if (ts.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "setHeader", "append", "set") && isSetCookieHeaderName(node.arguments[0])) {
12328
+ if (ts3.isPropertyAccessExpression(node.expression) && isPropertyNamed(node.expression.name, "setHeader", "append", "set") && isSetCookieHeaderName(node.arguments[0])) {
10907
12329
  const cookieStrings = collectCookieHeaderStrings(node.arguments[1]);
10908
12330
  const authCookieStrings = cookieStrings.filter(cookieHeaderStringLooksAuthLike);
10909
12331
  if (authCookieStrings.length > 0) {
@@ -10921,13 +12343,13 @@ function analyzeAstSignals(filePath, code) {
10921
12343
  }
10922
12344
  }
10923
12345
  }
10924
- if ((ts.isIdentifier(node.expression) && node.expression.text === "open" || ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "window" && isPropertyNamed(node.expression.name, "open")) && secondArgumentLiteral === "_blank") {
12346
+ if ((ts3.isIdentifier(node.expression) && node.expression.text === "open" || ts3.isPropertyAccessExpression(node.expression) && ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "window" && isPropertyNamed(node.expression.name, "open")) && secondArgumentLiteral === "_blank") {
10925
12347
  const featureLiteral = getExpressionLiteralValue(node.arguments[2])?.toLowerCase() ?? "";
10926
12348
  if (!featureLiteral.includes("noopener") || !featureLiteral.includes("noreferrer")) {
10927
12349
  signals.windowOpenWithoutNoopenerCount += 1;
10928
12350
  }
10929
12351
  }
10930
- if (ts.isPropertyAccessExpression(node.expression)) {
12352
+ if (ts3.isPropertyAccessExpression(node.expression)) {
10931
12353
  if (isPropertyNamed(node.expression.name, "insertAdjacentHTML")) {
10932
12354
  signals.rawHtmlInjectionCount += 1;
10933
12355
  }
@@ -10936,7 +12358,7 @@ function analyzeAstSignals(filePath, code) {
10936
12358
  }
10937
12359
  if (isCookieMutationSetCall(node)) {
10938
12360
  const firstArgument = node.arguments[0];
10939
- const isObjectConfigCall = ts.isObjectLiteralExpression(firstArgument);
12361
+ const isObjectConfigCall = ts3.isObjectLiteralExpression(firstArgument);
10940
12362
  const isAuthCookieWrite = isObjectConfigCall ? objectLiteralLooksLikeAuthCookieConfig(firstArgument, sourceFile) : expressionLooksLikeAuthCookieName(firstArgument, sourceFile);
10941
12363
  if (isAuthCookieWrite) {
10942
12364
  signals.authCookieWriteCount += 1;
@@ -10956,7 +12378,7 @@ function analyzeAstSignals(filePath, code) {
10956
12378
  signals.authHeaderWriteCount += 1;
10957
12379
  }
10958
12380
  }
10959
- if (ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "document" && isPropertyNamed(node.expression.name, "write")) {
12381
+ if (ts3.isIdentifier(node.expression.expression) && node.expression.expression.text === "document" && isPropertyNamed(node.expression.name, "write")) {
10960
12382
  signals.rawHtmlInjectionCount += 1;
10961
12383
  }
10962
12384
  if (isPropertyNamed(node.expression.name, "eval")) {
@@ -10964,16 +12386,16 @@ function analyzeAstSignals(filePath, code) {
10964
12386
  }
10965
12387
  }
10966
12388
  }
10967
- if (ts.isNewExpression(node) && isRealtimeTransportConstructor(node) && isInsecureTransportUrl(getExpressionLiteralValue(node.arguments?.[0]))) {
12389
+ if (ts3.isNewExpression(node) && isRealtimeTransportConstructor(node) && isInsecureTransportUrl(getExpressionLiteralValue(node.arguments?.[0]))) {
10968
12390
  signals.insecureTransportEndpointCount += 1;
10969
12391
  }
10970
- if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "Function") {
12392
+ if (ts3.isNewExpression(node) && ts3.isIdentifier(node.expression) && node.expression.text === "Function") {
10971
12393
  signals.dynamicEvalCount += 1;
10972
12394
  }
10973
- if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && ["WebSocket", "EventSource"].includes(node.expression.text) && isInsecureTransportUrl(getExpressionLiteralValue(node.arguments?.[0]))) {
12395
+ if (ts3.isNewExpression(node) && ts3.isIdentifier(node.expression) && ["WebSocket", "EventSource"].includes(node.expression.text) && isInsecureTransportUrl(getExpressionLiteralValue(node.arguments?.[0]))) {
10974
12396
  signals.insecureTransportEndpointCount += 1;
10975
12397
  }
10976
- if (ts.isJsxSelfClosingElement(node)) {
12398
+ if (ts3.isJsxSelfClosingElement(node)) {
10977
12399
  const tagName = getJsxTagName(node);
10978
12400
  if (hasMainLandmarkSignal(node.attributes, tagName)) {
10979
12401
  signals.mainLandmarkCount += 1;
@@ -11066,7 +12488,7 @@ function analyzeAstSignals(filePath, code) {
11066
12488
  signals.formControlWithoutLabelCount += 1;
11067
12489
  }
11068
12490
  }
11069
- if (ts.isJsxElement(node)) {
12491
+ if (ts3.isJsxElement(node)) {
11070
12492
  const tagName = getJsxTagName(node.openingElement);
11071
12493
  const textContent = getJsxTextContent(node).replace(/\s+/g, " ").trim();
11072
12494
  if (hasMainLandmarkSignal(node.openingElement.attributes, tagName)) {
@@ -11182,7 +12604,7 @@ function analyzeAstSignals(filePath, code) {
11182
12604
  signals.formControlWithoutLabelCount += 1;
11183
12605
  }
11184
12606
  }
11185
- ts.forEachChild(node, walk);
12607
+ ts3.forEachChild(node, walk);
11186
12608
  };
11187
12609
  walk(sourceFile);
11188
12610
  signals.unlabeledNavigationLandmarkCount = navigationLandmarkCount > 1 ? unlabeledNavigationLandmarkCount : 0;
@@ -12936,10 +14358,10 @@ function critiqueSource({
12936
14358
  };
12937
14359
  }
12938
14360
  function resolveProjectFilePath(projectRoot, filePath) {
12939
- const root = existsSync3(projectRoot) ? realpathSync.native(projectRoot) : resolve(projectRoot);
14361
+ const root = existsSync4(projectRoot) ? realpathSync.native(projectRoot) : resolve(projectRoot);
12940
14362
  const candidatePath = isAbsolute2(filePath) ? resolve(filePath) : resolve(root, filePath);
12941
- const resolvedPath = existsSync3(candidatePath) ? realpathSync.native(candidatePath) : candidatePath;
12942
- const relativePath = relative2(root, resolvedPath);
14363
+ const resolvedPath = existsSync4(candidatePath) ? realpathSync.native(candidatePath) : candidatePath;
14364
+ const relativePath = relative4(root, resolvedPath);
12943
14365
  if (relativePath.startsWith("..") || isAbsolute2(relativePath)) {
12944
14366
  throw new Error(`Path escapes the project root: ${filePath}`);
12945
14367
  }
@@ -12948,7 +14370,7 @@ function resolveProjectFilePath(projectRoot, filePath) {
12948
14370
  async function critiqueFile(filePath, projectRoot) {
12949
14371
  const resolvedPath = resolveProjectFilePath(projectRoot, filePath);
12950
14372
  const code = await readFile(resolvedPath, "utf-8");
12951
- const treatmentsCss = readTextIfExists(join3(projectRoot, "src", "styles", "treatments.css"));
14373
+ const treatmentsCss = readTextIfExists(join4(projectRoot, "src", "styles", "treatments.css"));
12952
14374
  const reviewPack = loadReviewPack(projectRoot);
12953
14375
  const packManifest = loadPackManifest(projectRoot);
12954
14376
  const adoptionMode = readProjectAdoptionMode(projectRoot);
@@ -12962,23 +14384,34 @@ async function critiqueFile(filePath, projectRoot) {
12962
14384
  });
12963
14385
  }
12964
14386
  export {
14387
+ COMPONENT_REUSE_RULE_ID,
12965
14388
  EVIDENCE_BUNDLE_SCHEMA_URL,
12966
14389
  INTERACTION_SIGNALS,
14390
+ KNOWN_VERIFICATION_DIAGNOSTICS,
14391
+ RAW_CONTROL_REUSE_RULE_ID,
12967
14392
  SCAN_REPORT_SCHEMA_URL,
14393
+ STYLE_BRIDGE_ARBITRARY_VALUE_RULE_ID,
12968
14394
  VERIFICATION_SCHEMA_URLS,
14395
+ anchorFindingsToGraph,
12969
14396
  auditBuiltDist,
14397
+ auditComponentReuse,
12970
14398
  auditProject,
14399
+ auditStyleBridgeDrift,
14400
+ buildProjectHealthRepairPlan,
12971
14401
  collectMissingPackManifestFiles,
14402
+ collectProjectSourceFiles,
12972
14403
  createContractAssertions,
12973
14404
  createEvidenceBundle,
12974
14405
  createUnavailableScanReport,
12975
14406
  critiqueFile,
12976
14407
  critiqueSource,
14408
+ deriveVerificationDiagnostic,
12977
14409
  emptyRuntimeAudit,
12978
14410
  extractRouteHintsFromEssence,
12979
14411
  listKnownInteractions,
12980
14412
  probePublishedSite,
12981
14413
  resolveGitHubScanInput,
14414
+ resolveGraphAnchorForFinding,
12982
14415
  scanProject,
12983
14416
  verifyInteractionsInSource
12984
14417
  };