react-doctor 0.9.13-dev.fd23edc → 0.9.13-dev.fd64d26

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.
Files changed (46) hide show
  1. package/dist/_react-doctor_require-typescript-DnwIzXJn.js +7 -0
  2. package/dist/{active-scan-abort-registry-DwG6tSPy.js → active-scan-abort-registry-B72ASBUh.js} +3 -3
  3. package/dist/build-section-divider-DqBNBmQx.js +80 -0
  4. package/dist/{ci-DjilJaw4.js → ci-C9VIuxer.js} +12 -12
  5. package/dist/cli.js +25 -26
  6. package/dist/constants-CKOk_Fa9.js +23 -0
  7. package/dist/{design-CXLKbARh.js → design-Bi2Vyiox.js} +4 -4
  8. package/dist/{devtools-CC2PAZ85.js → devtools-DOdrAPkZ.js} +3 -3
  9. package/dist/duplicate-jsx-worker.d.ts +1 -0
  10. package/dist/duplicate-jsx-worker.js +636 -0
  11. package/dist/{exit-gracefully-DTLgxZZ5.js → exit-gracefully-BECsBTnW.js} +7 -7
  12. package/dist/{get-east-asian-width-Bv2TD3Xj.js → get-east-asian-width-CM5BOEC-.js} +3 -3
  13. package/dist/{handle-error-BqaqFvmc.js → handle-error-Bpa6UIOi.js} +5 -5
  14. package/dist/index.js +2329 -1616
  15. package/dist/{inspect-BIfnzKGq.js → inspect-CIlLTl74.js} +25 -21
  16. package/dist/{install-nhJ65X-y.js → install-CWRhGRwA.js} +9 -9
  17. package/dist/{install-doctor-script-B1U08lUD.js → install-doctor-script-4bc7a9Xa.js} +5 -5
  18. package/dist/{install-github-workflow-CkOl0wCn.js → install-github-workflow-CApF2UUE.js} +5 -5
  19. package/dist/{install-react-doctor-Dm35Egex.js → install-react-doctor-5JVhuBwj.js} +8 -8
  20. package/dist/{jsx-runtime-C1t3eR6p.js → jsx-runtime-BiIKqx7W.js} +7 -7
  21. package/dist/oxlint-worker.d.ts +1 -0
  22. package/dist/oxlint-worker.js +135 -0
  23. package/dist/{print-branded-header-qOJiGkuW.js → print-branded-header-I68eir6S.js} +4 -4
  24. package/dist/project-analysis-worker.js +457 -470
  25. package/dist/{prompt-runtime-scan-url-m88LMtMP.js → prompt-runtime-scan-url-DTURCZJx.js} +5 -5
  26. package/dist/{read-object-file-Cv41FpZo.js → read-object-file-D_so7aRw.js} +4 -4
  27. package/dist/{record-metric-u8youmM2.js → record-metric-Cs3byi4j.js} +1823 -1059
  28. package/dist/{report-error-CkFgxJTQ.js → report-error-C6cwK5ek.js} +7 -7
  29. package/dist/{report-workflow-result-Wh1SQuOu.js → report-workflow-result-C__-WR2y.js} +5 -5
  30. package/dist/{resolve-scope-CHCpJtks.js → resolve-scope-Ded7Rst2.js} +6 -6
  31. package/dist/{rules-C30QFptP.js → rules-zE-OOAQv.js} +6 -6
  32. package/dist/{run-scan-app-yTBDucJ3.js → run-scan-app-vOe1geDj.js} +28 -22
  33. package/dist/{runtime-scan-VH25Yf8H.js → runtime-scan-BpV7bw6k.js} +14 -14
  34. package/dist/{sanitize-runtime-url-crVHbQlW.js → sanitize-runtime-url-Bz3numjM.js} +5 -5
  35. package/dist/{scan-CNSRWEtJ.js → scan-lvKKvrda.js} +9 -9
  36. package/dist/{semver-DFtnEmN-.js → semver-DlmXks31.js} +3 -3
  37. package/dist/{should-fail-scan-gate-Cw6KeoRT.js → should-fail-scan-gate-Chyg9-UY.js} +116 -72
  38. package/dist/{should-skip-prompts-B5zkkkKR.js → should-skip-prompts-DHnGjhIu.js} +4 -4
  39. package/dist/{should-use-tui-S9255AG_.js → should-use-tui-DXeiBj0r.js} +4 -4
  40. package/dist/{telemetry-runtime-B2rpGWMl.js → telemetry-runtime-C4xTDemQ.js} +153 -5
  41. package/dist/unwrap-typescript-expression-CbO_6kmC.js +14 -0
  42. package/dist/{version-KQbGQSGN.js → version-BEYXWT3R.js} +4 -4
  43. package/dist/{why-B-l2qTCV.js → why-Bd-soKyA.js} +4 -4
  44. package/dist/{with-run-span-Dk1M8cnH.js → with-run-span-B6t6uEzq.js} +5 -5
  45. package/package.json +4 -4
  46. package/dist/build-section-divider-CUtO-gXD.js +0 -216
@@ -0,0 +1,636 @@
1
+
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="72ed940b-b5b5-59ad-965d-28f386d128c5")}catch(e){}}();
3
+ import { t as _react_doctor_require_typescript_default } from "./_react-doctor_require-typescript-DnwIzXJn.js";
4
+ import { t as unwrapTypescriptExpression } from "./unwrap-typescript-expression-CbO_6kmC.js";
5
+ import { i as JSX_DUPLICATION_SOURCE_FILE_PATTERN } from "./constants-CKOk_Fa9.js";
6
+ import * as path$1 from "node:path";
7
+ import * as fs$2 from "node:fs";
8
+ import crypto from "node:crypto";
9
+ import * as fs$1 from "node:fs/promises";
10
+ import { parentPort } from "node:worker_threads";
11
+ //#region ../core/src/utils/resolve-bounded-source-read-bytes.ts
12
+ const resolveBoundedSourceReadBytes = (maximumLengthChars, sizeBytes) => Math.min(sizeBytes, maximumLengthChars * 3 + 1);
13
+ //#endregion
14
+ //#region ../core/src/utils/read-text-file-up-to-character-limit-sync.ts
15
+ const readTextFileUpToCharacterLimitSync = (input) => {
16
+ const buffer = Buffer.allocUnsafe(resolveBoundedSourceReadBytes(input.maximumLengthChars, input.sizeBytes));
17
+ const fileDescriptor = fs$2.openSync(input.filePath, "r");
18
+ let readOffset = 0;
19
+ try {
20
+ while (readOffset < buffer.length) {
21
+ const bytesRead = fs$2.readSync(fileDescriptor, buffer, readOffset, buffer.length - readOffset, readOffset);
22
+ if (bytesRead === 0) break;
23
+ readOffset += bytesRead;
24
+ }
25
+ } finally {
26
+ fs$2.closeSync(fileDescriptor);
27
+ }
28
+ return buffer.subarray(0, readOffset).toString("utf-8");
29
+ };
30
+ //#endregion
31
+ //#region ../core/src/utils/read-text-file-up-to-character-limit.ts
32
+ const readTextFileUpToCharacterLimit = async (input) => {
33
+ const buffer = Buffer.allocUnsafe(resolveBoundedSourceReadBytes(input.maximumLengthChars, input.sizeBytes));
34
+ const fileHandle = await fs$1.open(input.filePath, "r");
35
+ let readOffset = 0;
36
+ try {
37
+ while (readOffset < buffer.length) {
38
+ input.signal?.throwIfAborted();
39
+ const { bytesRead } = await fileHandle.read(buffer, readOffset, buffer.length - readOffset, readOffset);
40
+ if (bytesRead === 0) break;
41
+ readOffset += bytesRead;
42
+ }
43
+ } finally {
44
+ await fileHandle.close();
45
+ }
46
+ input.signal?.throwIfAborted();
47
+ return buffer.subarray(0, readOffset).toString("utf-8");
48
+ };
49
+ //#endregion
50
+ //#region ../core/src/react-cleanup/create-jsx-source-reader.ts
51
+ const readBlocking = (absolutePath, maximumLengthChars, sizeBytes) => new Promise((resolve) => {
52
+ resolve(sizeBytes <= maximumLengthChars ? fs$2.readFileSync(absolutePath, "utf-8") : readTextFileUpToCharacterLimitSync({
53
+ filePath: absolutePath,
54
+ maximumLengthChars,
55
+ sizeBytes
56
+ }));
57
+ });
58
+ const createJsxSourceReader = (input) => {
59
+ const sourceSizeByPath = new Map(input.sourceFiles.map((sourceFile) => [sourceFile.path, sourceFile.sizeBytes]));
60
+ return {
61
+ paths: [...sourceSizeByPath.keys()],
62
+ read: (filePath, maximumLengthChars) => {
63
+ const absolutePath = path$1.resolve(input.rootDirectory, filePath);
64
+ const sourceSizeBytes = sourceSizeByPath.get(filePath) ?? 0;
65
+ if (input.useBlockingReads === true) return readBlocking(absolutePath, maximumLengthChars, sourceSizeBytes);
66
+ return sourceSizeBytes <= maximumLengthChars ? fs$1.readFile(absolutePath, {
67
+ encoding: "utf-8",
68
+ signal: input.signal
69
+ }) : readTextFileUpToCharacterLimit({
70
+ filePath: absolutePath,
71
+ maximumLengthChars,
72
+ sizeBytes: sourceSizeBytes,
73
+ signal: input.signal
74
+ });
75
+ }
76
+ };
77
+ };
78
+ //#endregion
79
+ //#region ../core/src/utils/get-typescript-script-kind.ts
80
+ const getTypescriptScriptKind = (fileName) => {
81
+ if (fileName.endsWith(".tsx")) return _react_doctor_require_typescript_default.ScriptKind.TSX;
82
+ if (fileName.endsWith(".jsx")) return _react_doctor_require_typescript_default.ScriptKind.JSX;
83
+ if (fileName.endsWith(".ts")) return _react_doctor_require_typescript_default.ScriptKind.TS;
84
+ return _react_doctor_require_typescript_default.ScriptKind.JS;
85
+ };
86
+ //#endregion
87
+ //#region ../core/src/utils/yield-to-event-loop.ts
88
+ const yieldToEventLoop = () => new Promise((resolve) => {
89
+ setImmediate(resolve);
90
+ });
91
+ //#endregion
92
+ //#region ../core/src/react-cleanup/utils/is-non-react-jsx-source.ts
93
+ const NON_REACT_JSX_RUNTIME_PREFIXES = ["solid-js", "@builder.io/qwik"];
94
+ const NON_REACT_JSX_RUNTIME_PACKAGES = new Set(["voby", "vidode"]);
95
+ const REACT_JSX_RUNTIME_PREFIXES = [
96
+ "react",
97
+ "react-dom",
98
+ "preact"
99
+ ];
100
+ const matchesPackagePrefix = (source, prefixes) => prefixes.some((prefix) => source === prefix || source.startsWith(`${prefix}/`));
101
+ const importDeclarationHasRuntimeValue = (declaration) => {
102
+ const importClause = declaration.importClause;
103
+ if (!importClause) return true;
104
+ if (importClause.isTypeOnly) return false;
105
+ if (importClause.name || !importClause.namedBindings) return true;
106
+ if (_react_doctor_require_typescript_default.isNamespaceImport(importClause.namedBindings)) return true;
107
+ return importClause.namedBindings.elements.some((element) => !element.isTypeOnly);
108
+ };
109
+ const openingElementHasNonReactMarker = (openingElement) => openingElement.attributes.properties.some((attribute) => {
110
+ if (!_react_doctor_require_typescript_default.isJsxAttribute(attribute)) return false;
111
+ if (_react_doctor_require_typescript_default.isJsxNamespacedName(attribute.name)) return attribute.name.namespace.text === "class" || attribute.name.namespace.text === "bind";
112
+ if (attribute.name.text !== "classList" || !attribute.initializer) return false;
113
+ return _react_doctor_require_typescript_default.isJsxExpression(attribute.initializer) && attribute.initializer.expression !== void 0 && _react_doctor_require_typescript_default.isObjectLiteralExpression(attribute.initializer.expression);
114
+ });
115
+ const NON_REACT_RUNTIME_SOURCE_TEXT_MARKERS = [
116
+ ...NON_REACT_JSX_RUNTIME_PREFIXES,
117
+ ...NON_REACT_JSX_RUNTIME_PACKAGES,
118
+ "classList"
119
+ ];
120
+ const NAMESPACED_ATTRIBUTE_MARKER_PATTERN = /\b(?:class|bind)\s*:/;
121
+ const ESCAPED_MODULE_SPECIFIER_PATTERN = /(?:import|from)\s*["'][^"'\n]*\\/;
122
+ const mayContainNonReactMarker = (sourceText) => NON_REACT_RUNTIME_SOURCE_TEXT_MARKERS.some((marker) => sourceText.includes(marker)) || NAMESPACED_ATTRIBUTE_MARKER_PATTERN.test(sourceText) || ESCAPED_MODULE_SPECIFIER_PATTERN.test(sourceText);
123
+ const isNonReactJsxSource = (sourceFile) => {
124
+ if (!mayContainNonReactMarker(sourceFile.text)) return false;
125
+ let hasNonReactRuntime = false;
126
+ let hasReactRuntime = false;
127
+ let hasNonReactMarker = false;
128
+ const visitNode = (node) => {
129
+ if (_react_doctor_require_typescript_default.isImportDeclaration(node) && importDeclarationHasRuntimeValue(node)) {
130
+ const source = _react_doctor_require_typescript_default.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : "";
131
+ if (NON_REACT_JSX_RUNTIME_PACKAGES.has(source) || matchesPackagePrefix(source, NON_REACT_JSX_RUNTIME_PREFIXES)) hasNonReactRuntime = true;
132
+ if (matchesPackagePrefix(source, REACT_JSX_RUNTIME_PREFIXES)) hasReactRuntime = true;
133
+ }
134
+ if ((_react_doctor_require_typescript_default.isJsxOpeningElement(node) || _react_doctor_require_typescript_default.isJsxSelfClosingElement(node)) && openingElementHasNonReactMarker(node)) hasNonReactMarker = true;
135
+ _react_doctor_require_typescript_default.forEachChild(node, visitNode);
136
+ };
137
+ visitNode(sourceFile);
138
+ return !hasReactRuntime && (hasNonReactRuntime || hasNonReactMarker);
139
+ };
140
+ //#endregion
141
+ //#region ../core/src/react-cleanup/detect-duplicate-jsx-subtrees.ts
142
+ const isJsxSubtreeNode = (node) => _react_doctor_require_typescript_default.isJsxElement(node) || _react_doctor_require_typescript_default.isJsxSelfClosingElement(node) || _react_doctor_require_typescript_default.isJsxFragment(node);
143
+ const resolveOptions = (options) => ({
144
+ minimumNodeCount: options.minimumNodeCount ?? 6,
145
+ minimumDepth: options.minimumDepth ?? 3,
146
+ minimumOccurrences: options.minimumOccurrences ?? 2,
147
+ minimumDistinctFiles: options.minimumDistinctFiles ?? 1,
148
+ maxSourceFiles: options.budget?.maxSourceFiles ?? 5e3,
149
+ maxSourceLengthChars: options.budget?.maxSourceLengthChars ?? 1e6,
150
+ maxJsxNodes: options.budget?.maxJsxNodes ?? 5e4,
151
+ maxFamilies: options.budget?.maxFamilies ?? 20
152
+ });
153
+ const hashParts = (parts) => {
154
+ let framedParts = "";
155
+ for (const part of parts) framedParts += `${part.length}:${part}`;
156
+ return crypto.hash("sha256", framedParts, "hex");
157
+ };
158
+ const collectDirectJsxDescendants = (node) => {
159
+ const descendants = [];
160
+ const pendingNodes = [];
161
+ _react_doctor_require_typescript_default.forEachChild(node, (child) => {
162
+ pendingNodes.push(child);
163
+ });
164
+ while (pendingNodes.length > 0) {
165
+ const currentNode = pendingNodes.pop();
166
+ if (currentNode === void 0) continue;
167
+ if (isJsxSubtreeNode(currentNode)) {
168
+ descendants.push(currentNode);
169
+ continue;
170
+ }
171
+ _react_doctor_require_typescript_default.forEachChild(currentNode, (child) => {
172
+ pendingNodes.push(child);
173
+ });
174
+ }
175
+ return descendants;
176
+ };
177
+ const buildStructuralHash = (node, metadataByNode) => {
178
+ if (isJsxSubtreeNode(node)) return buildJsxSubtreeMetadata(node, metadataByNode).fingerprint;
179
+ if (_react_doctor_require_typescript_default.isJsxText(node)) return node.getText().trim().length === 0 ? "jsx-whitespace" : "jsx-text";
180
+ if (_react_doctor_require_typescript_default.isPropertyAccessExpression(node)) return hashParts([
181
+ "property-access",
182
+ node.questionDotToken === void 0 ? "required" : "optional",
183
+ buildStructuralHash(node.expression, metadataByNode),
184
+ node.name.text
185
+ ]);
186
+ if (_react_doctor_require_typescript_default.isElementAccessExpression(node)) {
187
+ const argumentHash = _react_doctor_require_typescript_default.isStringLiteral(node.argumentExpression) || _react_doctor_require_typescript_default.isNumericLiteral(node.argumentExpression) ? `${_react_doctor_require_typescript_default.SyntaxKind[node.argumentExpression.kind]}:${node.argumentExpression.text}` : buildStructuralHash(node.argumentExpression, metadataByNode);
188
+ return hashParts([
189
+ "element-access",
190
+ node.questionDotToken === void 0 ? "required" : "optional",
191
+ buildStructuralHash(node.expression, metadataByNode),
192
+ argumentHash
193
+ ]);
194
+ }
195
+ if (_react_doctor_require_typescript_default.isBinaryExpression(node)) return hashParts([
196
+ "binary-expression",
197
+ _react_doctor_require_typescript_default.SyntaxKind[node.operatorToken.kind],
198
+ buildStructuralHash(node.left, metadataByNode),
199
+ buildStructuralHash(node.right, metadataByNode)
200
+ ]);
201
+ if (_react_doctor_require_typescript_default.isPrefixUnaryExpression(node) || _react_doctor_require_typescript_default.isPostfixUnaryExpression(node)) return hashParts([
202
+ _react_doctor_require_typescript_default.SyntaxKind[node.kind],
203
+ _react_doctor_require_typescript_default.SyntaxKind[node.operator],
204
+ buildStructuralHash(node.operand, metadataByNode)
205
+ ]);
206
+ if (_react_doctor_require_typescript_default.isIdentifier(node)) return "identifier";
207
+ if (_react_doctor_require_typescript_default.isStringLiteral(node) || _react_doctor_require_typescript_default.isNumericLiteral(node) || _react_doctor_require_typescript_default.isNoSubstitutionTemplateLiteral(node) || _react_doctor_require_typescript_default.isRegularExpressionLiteral(node)) return _react_doctor_require_typescript_default.SyntaxKind[node.kind];
208
+ if (_react_doctor_require_typescript_default.isJsxAttribute(node)) {
209
+ let initializerHash = "present";
210
+ if (node.initializer !== void 0) if (_react_doctor_require_typescript_default.isStringLiteral(node.initializer)) initializerHash = `string:${node.initializer.text}`;
211
+ else if (_react_doctor_require_typescript_default.isJsxExpression(node.initializer) && node.initializer.expression !== void 0 && (_react_doctor_require_typescript_default.isStringLiteral(node.initializer.expression) || _react_doctor_require_typescript_default.isNumericLiteral(node.initializer.expression) || node.initializer.expression.kind === _react_doctor_require_typescript_default.SyntaxKind.TrueKeyword || node.initializer.expression.kind === _react_doctor_require_typescript_default.SyntaxKind.FalseKeyword || node.initializer.expression.kind === _react_doctor_require_typescript_default.SyntaxKind.NullKeyword)) initializerHash = `static:${node.initializer.expression.getText()}`;
212
+ else initializerHash = buildStructuralHash(node.initializer, metadataByNode);
213
+ return hashParts([
214
+ "attribute",
215
+ node.name.getText(),
216
+ initializerHash
217
+ ]);
218
+ }
219
+ if (_react_doctor_require_typescript_default.isPropertyAssignment(node)) return hashParts([
220
+ "property-assignment",
221
+ node.name.getText(),
222
+ buildStructuralHash(node.initializer, metadataByNode)
223
+ ]);
224
+ if (_react_doctor_require_typescript_default.isShorthandPropertyAssignment(node)) return hashParts(["shorthand-property", node.name.text]);
225
+ if (_react_doctor_require_typescript_default.isJsxSpreadAttribute(node)) return hashParts(["spread", buildStructuralHash(node.expression, metadataByNode)]);
226
+ const childHashes = [];
227
+ _react_doctor_require_typescript_default.forEachChild(node, (child) => {
228
+ childHashes.push(buildStructuralHash(child, metadataByNode));
229
+ });
230
+ return hashParts([_react_doctor_require_typescript_default.SyntaxKind[node.kind], ...childHashes]);
231
+ };
232
+ const buildJsxSubtreeMetadata = (node, metadataByNode) => {
233
+ const existingMetadata = metadataByNode.get(node);
234
+ if (existingMetadata) return existingMetadata;
235
+ const descendantMetadata = collectDirectJsxDescendants(node).map((descendant) => buildJsxSubtreeMetadata(descendant, metadataByNode));
236
+ const nodeParts = [_react_doctor_require_typescript_default.SyntaxKind[node.kind]];
237
+ if (_react_doctor_require_typescript_default.isJsxElement(node)) nodeParts.push(node.openingElement.tagName.getText());
238
+ else if (_react_doctor_require_typescript_default.isJsxSelfClosingElement(node)) nodeParts.push(node.tagName.getText());
239
+ else nodeParts.push("fragment");
240
+ _react_doctor_require_typescript_default.forEachChild(node, (child) => {
241
+ if (_react_doctor_require_typescript_default.isJsxClosingElement(child) || _react_doctor_require_typescript_default.isJsxClosingFragment(child)) return;
242
+ if (_react_doctor_require_typescript_default.isJsxText(child) && child.getText().trim().length === 0) return;
243
+ if (_react_doctor_require_typescript_default.isJsxExpression(child) && child.expression === void 0) return;
244
+ nodeParts.push(buildStructuralHash(child, metadataByNode));
245
+ });
246
+ const metadata = {
247
+ fingerprint: `jsx:${hashParts(nodeParts)}`,
248
+ nodeCount: 1 + descendantMetadata.reduce((total, descendant) => total + descendant.nodeCount, 0),
249
+ depth: 1 + descendantMetadata.reduce((maximum, descendant) => Math.max(maximum, descendant.depth), 0)
250
+ };
251
+ metadataByNode.set(node, metadata);
252
+ return metadata;
253
+ };
254
+ const getRootName = (node) => {
255
+ if (_react_doctor_require_typescript_default.isJsxElement(node)) return node.openingElement.tagName.getText();
256
+ if (_react_doctor_require_typescript_default.isJsxSelfClosingElement(node)) return node.tagName.getText();
257
+ return "Fragment";
258
+ };
259
+ const getFunctionIdentity = (node, identityByNode) => {
260
+ if (identityByNode.has(node)) return identityByNode.get(node) ?? null;
261
+ const traversedNodes = [node];
262
+ let currentNode = node.parent;
263
+ let functionIdentity = null;
264
+ while (currentNode !== void 0) {
265
+ if (identityByNode.has(currentNode)) {
266
+ functionIdentity = identityByNode.get(currentNode) ?? null;
267
+ break;
268
+ }
269
+ traversedNodes.push(currentNode);
270
+ if (_react_doctor_require_typescript_default.isFunctionDeclaration(currentNode)) {
271
+ if (currentNode.name !== void 0) {
272
+ functionIdentity = {
273
+ name: currentNode.name.text,
274
+ startOffset: currentNode.getStart()
275
+ };
276
+ break;
277
+ }
278
+ if (_react_doctor_require_typescript_default.getModifiers(currentNode)?.some((modifier) => modifier.kind === _react_doctor_require_typescript_default.SyntaxKind.DefaultKeyword)) {
279
+ functionIdentity = {
280
+ name: "default export",
281
+ startOffset: currentNode.getStart()
282
+ };
283
+ break;
284
+ }
285
+ }
286
+ if (_react_doctor_require_typescript_default.isMethodDeclaration(currentNode)) {
287
+ const classDeclaration = currentNode.parent;
288
+ if (_react_doctor_require_typescript_default.isClassDeclaration(classDeclaration) && classDeclaration.name !== void 0) {
289
+ functionIdentity = {
290
+ name: classDeclaration.name.text,
291
+ startOffset: classDeclaration.getStart()
292
+ };
293
+ break;
294
+ }
295
+ functionIdentity = {
296
+ name: currentNode.name.getText(),
297
+ startOffset: currentNode.getStart()
298
+ };
299
+ break;
300
+ }
301
+ if (_react_doctor_require_typescript_default.isFunctionExpression(currentNode) && currentNode.name !== void 0) {
302
+ functionIdentity = {
303
+ name: currentNode.name.text,
304
+ startOffset: currentNode.getStart()
305
+ };
306
+ break;
307
+ }
308
+ if (_react_doctor_require_typescript_default.isArrowFunction(currentNode) || _react_doctor_require_typescript_default.isFunctionExpression(currentNode)) {
309
+ let assignmentNode = currentNode.parent;
310
+ while (assignmentNode !== void 0 && (_react_doctor_require_typescript_default.isCallExpression(assignmentNode) || _react_doctor_require_typescript_default.isExpressionWithTypeArguments(assignmentNode) || _react_doctor_require_typescript_default.isExpression(assignmentNode) && unwrapTypescriptExpression(assignmentNode) !== assignmentNode)) assignmentNode = assignmentNode.parent;
311
+ if (assignmentNode !== void 0 && _react_doctor_require_typescript_default.isVariableDeclaration(assignmentNode)) {
312
+ functionIdentity = {
313
+ name: assignmentNode.name.getText(),
314
+ startOffset: assignmentNode.getStart()
315
+ };
316
+ break;
317
+ }
318
+ if (assignmentNode !== void 0 && _react_doctor_require_typescript_default.isPropertyAssignment(assignmentNode)) {
319
+ functionIdentity = {
320
+ name: assignmentNode.name.getText(),
321
+ startOffset: assignmentNode.getStart()
322
+ };
323
+ break;
324
+ }
325
+ if (assignmentNode !== void 0 && _react_doctor_require_typescript_default.isExportAssignment(assignmentNode) && !assignmentNode.isExportEquals) {
326
+ functionIdentity = {
327
+ name: "default export",
328
+ startOffset: assignmentNode.getStart()
329
+ };
330
+ break;
331
+ }
332
+ }
333
+ currentNode = currentNode.parent;
334
+ }
335
+ for (const traversedNode of traversedNodes) identityByNode.set(traversedNode, functionIdentity);
336
+ return functionIdentity;
337
+ };
338
+ const buildOccurrence = (path, sourceFile, node, ancestorRootNames, functionIdentityByNode) => {
339
+ const startOffset = node.getStart(sourceFile);
340
+ const endOffset = node.getEnd();
341
+ const start = sourceFile.getLineAndCharacterOfPosition(startOffset);
342
+ const end = sourceFile.getLineAndCharacterOfPosition(endOffset);
343
+ const functionIdentity = getFunctionIdentity(node, functionIdentityByNode);
344
+ const compositionPath = [...ancestorRootNames, getRootName(node)];
345
+ if (functionIdentity !== null) compositionPath.unshift(functionIdentity.name);
346
+ return {
347
+ path,
348
+ startOffset,
349
+ endOffset,
350
+ startLine: start.line + 1,
351
+ startColumn: start.character + 1,
352
+ endLine: end.line + 1,
353
+ endColumn: end.character + 1,
354
+ rootName: getRootName(node),
355
+ parentRootName: ancestorRootNames.at(-1) ?? null,
356
+ compositionPath,
357
+ compositionRootStartOffset: functionIdentity?.startOffset ?? null
358
+ };
359
+ };
360
+ const collectCandidates = (source, sourceFile, signal, maximumCandidateCount) => {
361
+ const jsxNodes = [];
362
+ const pendingNodes = [sourceFile];
363
+ let limitExceeded = false;
364
+ while (pendingNodes.length > 0 && !limitExceeded && !signal?.aborted) {
365
+ const currentNode = pendingNodes.pop();
366
+ if (currentNode === void 0) continue;
367
+ if (isJsxSubtreeNode(currentNode)) {
368
+ if (jsxNodes.length >= maximumCandidateCount) {
369
+ limitExceeded = true;
370
+ continue;
371
+ }
372
+ jsxNodes.push(currentNode);
373
+ }
374
+ const childNodes = [];
375
+ _react_doctor_require_typescript_default.forEachChild(currentNode, (child) => {
376
+ childNodes.push(child);
377
+ });
378
+ for (let childIndex = childNodes.length - 1; childIndex >= 0; childIndex -= 1) pendingNodes.push(childNodes[childIndex]);
379
+ }
380
+ if (limitExceeded || signal?.aborted) return {
381
+ candidates: [],
382
+ aborted: signal?.aborted ?? false,
383
+ limitExceeded
384
+ };
385
+ const metadataByNode = /* @__PURE__ */ new Map();
386
+ const functionIdentityByNode = /* @__PURE__ */ new Map();
387
+ for (let nodeIndex = jsxNodes.length - 1; nodeIndex >= 0; nodeIndex -= 1) {
388
+ if (signal?.aborted) return {
389
+ candidates: [],
390
+ aborted: true,
391
+ limitExceeded: false
392
+ };
393
+ buildJsxSubtreeMetadata(jsxNodes[nodeIndex], metadataByNode);
394
+ }
395
+ return {
396
+ candidates: jsxNodes.map((node) => {
397
+ const ancestorRootNames = [];
398
+ let ancestorNode = node.parent;
399
+ while (ancestorNode !== void 0 && ancestorRootNames.length < 19) {
400
+ if (isJsxSubtreeNode(ancestorNode)) ancestorRootNames.unshift(getRootName(ancestorNode));
401
+ ancestorNode = ancestorNode.parent;
402
+ }
403
+ return {
404
+ metadata: buildJsxSubtreeMetadata(node, metadataByNode),
405
+ occurrence: buildOccurrence(source.path, sourceFile, node, ancestorRootNames, functionIdentityByNode)
406
+ };
407
+ }),
408
+ aborted: false,
409
+ limitExceeded: false
410
+ };
411
+ };
412
+ const scanSource = (input) => {
413
+ if (input.source.sourceText.length > input.options.maxSourceLengthChars) return {
414
+ candidates: [],
415
+ incompleteReason: {
416
+ kind: "source-length-limit",
417
+ limit: input.options.maxSourceLengthChars,
418
+ observed: input.source.sourceText.length,
419
+ path: input.source.path
420
+ },
421
+ didAbort: false,
422
+ didScan: false
423
+ };
424
+ const sourceFile = _react_doctor_require_typescript_default.createSourceFile(input.source.path, input.source.sourceText, _react_doctor_require_typescript_default.ScriptTarget.Latest, true, getTypescriptScriptKind(input.source.path));
425
+ if (isNonReactJsxSource(sourceFile)) return {
426
+ candidates: [],
427
+ incompleteReason: null,
428
+ didAbort: false,
429
+ didScan: true
430
+ };
431
+ const collectedCandidates = collectCandidates(input.source, sourceFile, input.signal, input.options.maxJsxNodes - input.scannedJsxNodeCount);
432
+ if (collectedCandidates.aborted) return {
433
+ candidates: [],
434
+ incompleteReason: {
435
+ kind: "aborted",
436
+ observed: input.scannedSourceFileCount
437
+ },
438
+ didAbort: true,
439
+ didScan: false
440
+ };
441
+ if (collectedCandidates.limitExceeded) return {
442
+ candidates: [],
443
+ incompleteReason: {
444
+ kind: "jsx-node-limit",
445
+ limit: input.options.maxJsxNodes,
446
+ observed: input.options.maxJsxNodes + 1,
447
+ path: input.source.path
448
+ },
449
+ didAbort: false,
450
+ didScan: false
451
+ };
452
+ return {
453
+ candidates: collectedCandidates.candidates,
454
+ incompleteReason: null,
455
+ didAbort: false,
456
+ didScan: true
457
+ };
458
+ };
459
+ const occurrenceIsContained = (inner, outer) => inner.path === outer.path && inner.startOffset >= outer.startOffset && inner.endOffset <= outer.endOffset;
460
+ const familyIsNestedWithin = (candidate, outer) => {
461
+ const outerOccurrences = [outer.primaryOccurrence, ...outer.relatedOccurrences];
462
+ return [candidate.primaryOccurrence, ...candidate.relatedOccurrences].every((occurrence) => outerOccurrences.some((outerOccurrence) => occurrenceIsContained(occurrence, outerOccurrence)));
463
+ };
464
+ const suppressNestedFamilies = (families) => {
465
+ const familiesBySize = [...families].sort((left, right) => right.nodeCount - left.nodeCount || right.depth - left.depth);
466
+ const maximalFamilies = [];
467
+ for (const family of familiesBySize) {
468
+ if (maximalFamilies.some((outer) => familyIsNestedWithin(family, outer))) continue;
469
+ maximalFamilies.push(family);
470
+ }
471
+ return maximalFamilies;
472
+ };
473
+ const compareOccurrences = (left, right) => left.path.localeCompare(right.path) || left.startOffset - right.startOffset || left.endOffset - right.endOffset;
474
+ const compareFamilies = (left, right) => right.estimatedRemovableNodeCount - left.estimatedRemovableNodeCount || right.estimatedRemovableLineCount - left.estimatedRemovableLineCount || right.occurrenceCount - left.occurrenceCount || right.distinctFileCount - left.distinctFileCount || right.nodeCount - left.nodeCount || compareOccurrences(left.primaryOccurrence, right.primaryOccurrence) || left.fingerprint.localeCompare(right.fingerprint);
475
+ const buildFamilies = (candidates, options) => {
476
+ const bucketsByFingerprint = /* @__PURE__ */ new Map();
477
+ for (const candidate of candidates) {
478
+ if (candidate.metadata.nodeCount < options.minimumNodeCount) continue;
479
+ if (candidate.metadata.depth < options.minimumDepth) continue;
480
+ const existingBucket = bucketsByFingerprint.get(candidate.metadata.fingerprint);
481
+ if (existingBucket) existingBucket.occurrences.push(candidate.occurrence);
482
+ else bucketsByFingerprint.set(candidate.metadata.fingerprint, {
483
+ metadata: candidate.metadata,
484
+ occurrences: [candidate.occurrence]
485
+ });
486
+ }
487
+ const families = [];
488
+ const familyProcessingLimit = Math.max(options.maxFamilies * 10, options.maxFamilies + 1);
489
+ for (const bucket of bucketsByFingerprint.values()) {
490
+ if (bucket.occurrences.length < options.minimumOccurrences) continue;
491
+ bucket.occurrences.sort(compareOccurrences);
492
+ const distinctFileCount = new Set(bucket.occurrences.map((occurrence) => occurrence.path)).size;
493
+ if (distinctFileCount < options.minimumDistinctFiles) continue;
494
+ if (distinctFileCount === 1) {
495
+ const compositionRootOffsets = /* @__PURE__ */ new Set();
496
+ for (const occurrence of bucket.occurrences) if (occurrence.compositionRootStartOffset !== null) compositionRootOffsets.add(occurrence.compositionRootStartOffset);
497
+ if (compositionRootOffsets.size < 2) continue;
498
+ }
499
+ families.push({
500
+ fingerprint: bucket.metadata.fingerprint,
501
+ nodeCount: bucket.metadata.nodeCount,
502
+ depth: bucket.metadata.depth,
503
+ occurrenceCount: bucket.occurrences.length,
504
+ distinctFileCount,
505
+ estimatedRemovableNodeCount: bucket.metadata.nodeCount * (bucket.occurrences.length - 1),
506
+ estimatedRemovableLineCount: bucket.occurrences.reduce((total, occurrence) => total + occurrence.endLine - occurrence.startLine + 1, 0) - Math.max(...bucket.occurrences.map((occurrence) => occurrence.endLine - occurrence.startLine + 1)),
507
+ primaryOccurrence: bucket.occurrences[0],
508
+ relatedOccurrences: bucket.occurrences.slice(1)
509
+ });
510
+ if (families.length > familyProcessingLimit) break;
511
+ }
512
+ return { families: suppressNestedFamilies(families).sort(compareFamilies) };
513
+ };
514
+ const buildResult = (input) => {
515
+ return {
516
+ families: buildFamilies(input.candidates, input.options).families.slice(0, input.options.maxFamilies),
517
+ scannedSourceFileCount: input.scannedSourceFileCount,
518
+ scannedJsxNodeCount: input.scannedJsxNodeCount,
519
+ incomplete: input.incompleteReasons.length > 0,
520
+ incompleteReasons: input.incompleteReasons
521
+ };
522
+ };
523
+ const detectDuplicateJsxSubtreesCooperative = async (sourceReader, options = {}) => {
524
+ const resolvedOptions = resolveOptions(options);
525
+ const incompleteReasons = [];
526
+ const sortedPaths = sourceReader.paths.filter((sourcePath) => JSX_DUPLICATION_SOURCE_FILE_PATTERN.test(sourcePath)).sort((left, right) => left.localeCompare(right));
527
+ if (sortedPaths.length > resolvedOptions.maxSourceFiles) incompleteReasons.push({
528
+ kind: "source-file-limit",
529
+ limit: resolvedOptions.maxSourceFiles,
530
+ observed: sortedPaths.length
531
+ });
532
+ const candidates = [];
533
+ let scannedSourceFileCount = 0;
534
+ let scannedJsxNodeCount = 0;
535
+ const scannedPaths = sortedPaths.slice(0, resolvedOptions.maxSourceFiles);
536
+ const readAhead = (pathIndex) => {
537
+ if (pathIndex >= scannedPaths.length) return null;
538
+ const pendingRead = sourceReader.read(scannedPaths[pathIndex], resolvedOptions.maxSourceLengthChars);
539
+ pendingRead.catch(() => void 0);
540
+ return pendingRead;
541
+ };
542
+ let pendingRead = readAhead(0);
543
+ for (const [pathIndex, sourcePath] of scannedPaths.entries()) {
544
+ if (options.signal?.aborted) {
545
+ incompleteReasons.push({
546
+ kind: "aborted",
547
+ observed: scannedSourceFileCount
548
+ });
549
+ break;
550
+ }
551
+ const sourceText = await pendingRead;
552
+ pendingRead = readAhead(pathIndex + 1);
553
+ if (sourceText === null) continue;
554
+ const scannedSource = scanSource({
555
+ source: {
556
+ path: sourcePath,
557
+ sourceText
558
+ },
559
+ options: resolvedOptions,
560
+ signal: options.signal,
561
+ scannedSourceFileCount,
562
+ scannedJsxNodeCount
563
+ });
564
+ if (scannedSource.incompleteReason !== null) incompleteReasons.push(scannedSource.incompleteReason);
565
+ if (scannedSource.didScan) {
566
+ candidates.push(...scannedSource.candidates);
567
+ scannedJsxNodeCount += scannedSource.candidates.length;
568
+ scannedSourceFileCount += 1;
569
+ }
570
+ if (scannedSource.didAbort) break;
571
+ await yieldToEventLoop();
572
+ }
573
+ return buildResult({
574
+ candidates,
575
+ options: resolvedOptions,
576
+ incompleteReasons,
577
+ scannedSourceFileCount,
578
+ scannedJsxNodeCount
579
+ });
580
+ };
581
+ //#endregion
582
+ //#region ../core/src/start-duplicate-jsx-worker.ts
583
+ const serializeError = (error) => error instanceof Error ? {
584
+ name: error.name,
585
+ message: error.message,
586
+ stack: error.stack
587
+ } : { message: String(error) };
588
+ const isWorkerCommand = (value) => typeof value === "object" && value !== null && "type" in value && (value.type === "detect" || value.type === "abort") && "id" in value && typeof value.id === "number";
589
+ const startDuplicateJsxWorker = () => {
590
+ if (parentPort === null) throw new Error("Duplicate JSX worker must run as a worker thread.");
591
+ const port = parentPort;
592
+ const abortControllersById = /* @__PURE__ */ new Map();
593
+ let queue = Promise.resolve();
594
+ const reply = (message) => port.postMessage(message);
595
+ const detect = async (request) => {
596
+ const abortController = abortControllersById.get(request.id);
597
+ if (abortController === void 0) return;
598
+ try {
599
+ const result = await detectDuplicateJsxSubtreesCooperative(createJsxSourceReader({
600
+ rootDirectory: request.rootDirectory,
601
+ sourceFiles: request.sourceFiles,
602
+ useBlockingReads: true
603
+ }), { signal: abortController.signal });
604
+ reply({
605
+ id: request.id,
606
+ ok: true,
607
+ result
608
+ });
609
+ } catch (error) {
610
+ reply({
611
+ id: request.id,
612
+ ok: false,
613
+ error: serializeError(error)
614
+ });
615
+ } finally {
616
+ abortControllersById.delete(request.id);
617
+ }
618
+ };
619
+ port.on("message", (message) => {
620
+ if (!isWorkerCommand(message)) return;
621
+ if (message.type === "abort") {
622
+ abortControllersById.get(message.id)?.abort();
623
+ return;
624
+ }
625
+ abortControllersById.set(message.id, new AbortController());
626
+ queue = queue.then(() => detect(message));
627
+ });
628
+ };
629
+ //#endregion
630
+ //#region src/duplicate-jsx-worker.ts
631
+ startDuplicateJsxWorker();
632
+ //#endregion
633
+ export {};
634
+
635
+ //# sourceMappingURL=duplicate-jsx-worker.js.map
636
+ //# debugId=72ed940b-b5b5-59ad-965d-28f386d128c5
@@ -1,9 +1,9 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ac280e3d-f449-54c6-95f5-93b1fbe35579")}catch(e){}}();
3
- import { d as isJsonModeActive, m as writeJsonCancellationReport } from "./record-metric-u8youmM2.js";
4
- import { n as shutdownTelemetry } from "./telemetry-runtime-B2rpGWMl.js";
5
- import { n as buildFooterLinkLines, r as flushSentry, t as buildSectionDivider } from "./build-section-divider-CUtO-gXD.js";
6
- import { t as activeScanAbortRegistry } from "./active-scan-abort-registry-DwG6tSPy.js";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6229593e-026e-5210-a4c1-aba9d907bbd2")}catch(e){}}();
3
+ import { d as isJsonModeActive, m as writeJsonCancellationReport } from "./record-metric-Cs3byi4j.js";
4
+ import { n as shutdownTelemetry, r as flushSentry } from "./telemetry-runtime-C4xTDemQ.js";
5
+ import { t as activeScanAbortRegistry } from "./active-scan-abort-registry-B72ASBUh.js";
6
+ import { n as buildFooterLinkLines, t as buildSectionDivider } from "./build-section-divider-DqBNBmQx.js";
7
7
  //#region src/cli/utils/active-tui-renderer.ts
8
8
  let activeTuiRenderer = null;
9
9
  const registerActiveTuiRenderer = (renderer) => {
@@ -50,5 +50,5 @@ const exitGracefully = () => {
50
50
  //#endregion
51
51
  export { registerActiveTuiRenderer as n, exitGracefully as t };
52
52
 
53
- //# sourceMappingURL=exit-gracefully-DTLgxZZ5.js.map
54
- //# debugId=ac280e3d-f449-54c6-95f5-93b1fbe35579
53
+ //# sourceMappingURL=exit-gracefully-BECsBTnW.js.map
54
+ //# debugId=6229593e-026e-5210-a4c1-aba9d907bbd2
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="db817079-8f8f-50ee-bae1-5d0182c74255")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="016750e6-1bf9-5924-8091-055917eeb9e5")}catch(e){}}();
3
3
  import process from "node:process";
4
4
  import os from "node:os";
5
5
  import tty from "node:tty";
@@ -440,5 +440,5 @@ function eastAsianWidth(codePoint, { ambiguousAsWide = false } = {}) {
440
440
  //#endregion
441
441
  export { chalk as a, stripAnsi as i, isFullWidth as n, isWide as r, eastAsianWidth as t };
442
442
 
443
- //# sourceMappingURL=get-east-asian-width-Bv2TD3Xj.js.map
444
- //# debugId=db817079-8f8f-50ee-bae1-5d0182c74255
443
+ //# sourceMappingURL=get-east-asian-width-CM5BOEC-.js.map
444
+ //# debugId=016750e6-1bf9-5924-8091-055917eeb9e5