react-doctor 0.7.7-dev.fbc804e → 0.7.8-dev.4829841
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/cli.js +451 -78
- package/dist/index.js +436 -75
- package/dist/lsp.js +437 -76
- package/package.json +6 -6
package/dist/lsp.js
CHANGED
|
@@ -6,6 +6,8 @@ import os from "node:os";
|
|
|
6
6
|
import * as Path from "node:path";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
9
|
+
import * as Crypto from "node:crypto";
|
|
10
|
+
import crypto, { createHash } from "node:crypto";
|
|
9
11
|
import * as NodeChildProcess from "node:child_process";
|
|
10
12
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
11
13
|
import ts from "typescript";
|
|
@@ -13,8 +15,6 @@ import { parseJSON5 } from "confbox";
|
|
|
13
15
|
import * as NodeUrl from "node:url";
|
|
14
16
|
import { fileURLToPath } from "node:url";
|
|
15
17
|
import { createJiti } from "jiti";
|
|
16
|
-
import * as Crypto from "node:crypto";
|
|
17
|
-
import crypto, { createHash } from "node:crypto";
|
|
18
18
|
import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
|
|
19
19
|
import { gzipSync } from "node:zlib";
|
|
20
20
|
import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
|
|
@@ -19365,12 +19365,13 @@ var JsonReportDiagnosticV3 = class extends Class("JsonReportDiagnosticV3")({
|
|
|
19365
19365
|
fixGroupId: optional(String$1)
|
|
19366
19366
|
}) {};
|
|
19367
19367
|
/**
|
|
19368
|
-
* Deterministic identity string for a diagnostic.
|
|
19369
|
-
*
|
|
19370
|
-
* suppression files, content-hash caches, and IDE "ignore this"
|
|
19371
|
-
* actions all key off one shared shape.
|
|
19368
|
+
* Deterministic identity string for a retained diagnostic occurrence.
|
|
19369
|
+
* Severity and message distinguish content variants at one normalized site.
|
|
19372
19370
|
*/
|
|
19373
|
-
const buildDiagnosticIdentity = (input) =>
|
|
19371
|
+
const buildDiagnosticIdentity = (input) => {
|
|
19372
|
+
const occurrenceDigest = createHash("sha256").update(JSON.stringify([input.severity, input.message])).digest("hex");
|
|
19373
|
+
return `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}::${occurrenceDigest}`;
|
|
19374
|
+
};
|
|
19374
19375
|
const JsonReportMode = Literals([
|
|
19375
19376
|
"full",
|
|
19376
19377
|
"diff",
|
|
@@ -33091,7 +33092,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
33091
33092
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
33092
33093
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
33093
33094
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
33094
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
33095
|
+
const CORE_PACKAGE_VERSION = "0.7.8";
|
|
33095
33096
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
33096
33097
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
33097
33098
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -37160,18 +37161,45 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
|
|
|
37160
37161
|
}
|
|
37161
37162
|
return diagnostics;
|
|
37162
37163
|
};
|
|
37163
|
-
const
|
|
37164
|
-
|
|
37165
|
-
|
|
37164
|
+
const getTypescriptScriptKind = (fileName) => {
|
|
37165
|
+
if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
37166
|
+
if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
37167
|
+
if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
37168
|
+
return ts.ScriptKind.JS;
|
|
37169
|
+
};
|
|
37170
|
+
const unwrapTypescriptExpression = (expression) => {
|
|
37171
|
+
let currentExpression = expression;
|
|
37172
|
+
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
37173
|
+
return currentExpression;
|
|
37174
|
+
};
|
|
37175
|
+
const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
|
|
37176
|
+
isAnimationFunction: false,
|
|
37177
|
+
isMotionComponent: false,
|
|
37178
|
+
isMotionComponentFactory: false,
|
|
37179
|
+
isMotionComponentNamespace: false,
|
|
37180
|
+
isMotionConfig: false,
|
|
37181
|
+
isMotionNamespace: false,
|
|
37182
|
+
isReducedMotionHook: false
|
|
37183
|
+
};
|
|
37184
|
+
const MOTION_COMPONENT_FACTORY_EXPORT_NAMES = new Set(["m", "motion"]);
|
|
37185
|
+
const MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES = new Set(["Reorder"]);
|
|
37186
|
+
const MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES = new Set(["Item"]);
|
|
37187
|
+
const MOTION_ANIMATION_FUNCTION_EXPORT_NAMES = new Set(["animate"]);
|
|
37188
|
+
const REDUCED_MOTION_HOOK_EXPORT_NAME = "useReducedMotion";
|
|
37189
|
+
const MOTION_CONFIG_EXPORT_NAME = "MotionConfig";
|
|
37190
|
+
const REDUCED_MOTION_PROP_NAME = "reducedMotion";
|
|
37191
|
+
const REDUCED_MOTION_CONFIG_VALUES = new Set(["always", "user"]);
|
|
37192
|
+
const SCRIPT_MODULE_EXTENSIONS = [
|
|
37166
37193
|
".ts",
|
|
37167
37194
|
".tsx",
|
|
37168
37195
|
".js",
|
|
37169
|
-
".jsx"
|
|
37170
|
-
|
|
37171
|
-
|
|
37172
|
-
]);
|
|
37173
|
-
const
|
|
37174
|
-
const
|
|
37196
|
+
".jsx"
|
|
37197
|
+
];
|
|
37198
|
+
const SCRIPT_FILE_EXTENSIONS = new Set(SCRIPT_MODULE_EXTENSIONS);
|
|
37199
|
+
const STYLE_FILE_EXTENSIONS = new Set([".css", ".scss"]);
|
|
37200
|
+
const MOTION_SOURCE_PREFILTER = /framer-motion|["']motion(?:\/[A-Za-z0-9_./-]+)?["']|MotionConfig|useReducedMotion/;
|
|
37201
|
+
const REDUCED_MOTION_MEDIA_QUERY_PATTERN = /@media\s+([^{}]*\(\s*prefers-reduced-motion\s*:\s*reduce\s*\)[^{}]*)\{/gi;
|
|
37202
|
+
const CSS_DECLARATION_PATTERN = /(?:^|[;{])\s*[-_A-Za-z][-_A-Za-z0-9]*\s*:/;
|
|
37175
37203
|
const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
|
|
37176
37204
|
filePath: "package.json",
|
|
37177
37205
|
plugin: "react-doctor",
|
|
@@ -37183,52 +37211,406 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
|
|
|
37183
37211
|
column: 0,
|
|
37184
37212
|
category: "Accessibility"
|
|
37185
37213
|
};
|
|
37186
|
-
const
|
|
37214
|
+
const isMotionModuleSource = (moduleSource) => {
|
|
37215
|
+
for (const packageName of MOTION_LIBRARY_PACKAGES) if (moduleSource === packageName || moduleSource.startsWith(`${packageName}/`)) return true;
|
|
37216
|
+
return false;
|
|
37217
|
+
};
|
|
37218
|
+
const classifyMotionExport = (exportName) => ({
|
|
37219
|
+
isAnimationFunction: MOTION_ANIMATION_FUNCTION_EXPORT_NAMES.has(exportName),
|
|
37220
|
+
isMotionComponent: false,
|
|
37221
|
+
isMotionComponentFactory: MOTION_COMPONENT_FACTORY_EXPORT_NAMES.has(exportName),
|
|
37222
|
+
isMotionComponentNamespace: MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES.has(exportName),
|
|
37223
|
+
isMotionConfig: exportName === MOTION_CONFIG_EXPORT_NAME,
|
|
37224
|
+
isMotionNamespace: false,
|
|
37225
|
+
isReducedMotionHook: exportName === REDUCED_MOTION_HOOK_EXPORT_NAME
|
|
37226
|
+
});
|
|
37227
|
+
const getImportModuleSource = (node) => {
|
|
37228
|
+
let currentNode = node;
|
|
37229
|
+
while (currentNode) {
|
|
37230
|
+
if (ts.isImportDeclaration(currentNode) && ts.isStringLiteral(currentNode.moduleSpecifier)) return currentNode.moduleSpecifier.text;
|
|
37231
|
+
currentNode = currentNode.parent;
|
|
37232
|
+
}
|
|
37233
|
+
return null;
|
|
37234
|
+
};
|
|
37235
|
+
const getImportedBindingEvidence = (declaration, typeChecker, program, visitedSymbols) => {
|
|
37236
|
+
const moduleSource = getImportModuleSource(declaration);
|
|
37237
|
+
if (!moduleSource) return null;
|
|
37238
|
+
if (isMotionModuleSource(moduleSource) && ts.isNamespaceImport(declaration)) return {
|
|
37239
|
+
...EMPTY_MOTION_EXPRESSION_EVIDENCE,
|
|
37240
|
+
isMotionNamespace: true
|
|
37241
|
+
};
|
|
37242
|
+
if (isMotionModuleSource(moduleSource) && ts.isImportSpecifier(declaration)) {
|
|
37243
|
+
if (declaration.isTypeOnly) return null;
|
|
37244
|
+
return classifyMotionExport(declaration.propertyName?.text ?? declaration.name.text);
|
|
37245
|
+
}
|
|
37246
|
+
if (isMotionModuleSource(moduleSource) && ts.isImportClause(declaration)) {
|
|
37247
|
+
if (declaration.isTypeOnly) return null;
|
|
37248
|
+
return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37249
|
+
}
|
|
37250
|
+
if (ts.isImportSpecifier(declaration) && !declaration.isTypeOnly || ts.isImportClause(declaration) && !declaration.isTypeOnly && declaration.name) {
|
|
37251
|
+
const importedName = ts.isImportSpecifier(declaration) ? declaration.propertyName?.text ?? declaration.name.text : "default";
|
|
37252
|
+
const moduleSourceFile = getLocalModuleSourceFile(moduleSource, declaration.getSourceFile().fileName, program);
|
|
37253
|
+
if (!moduleSourceFile) return null;
|
|
37254
|
+
return resolveModuleExportEvidence(moduleSourceFile, importedName, typeChecker, program, visitedSymbols);
|
|
37255
|
+
}
|
|
37256
|
+
return null;
|
|
37257
|
+
};
|
|
37258
|
+
const getLocalModuleSourceFile = (moduleSource, importingFileName, program) => {
|
|
37259
|
+
if (!moduleSource.startsWith(".")) return null;
|
|
37260
|
+
const moduleBasePath = Path.resolve(Path.dirname(importingFileName), moduleSource);
|
|
37261
|
+
const moduleBaseExtension = Path.extname(moduleBasePath);
|
|
37262
|
+
const typescriptModuleBasePath = moduleBaseExtension === ".js" || moduleBaseExtension === ".jsx" ? moduleBasePath.slice(0, -moduleBaseExtension.length) : null;
|
|
37263
|
+
const candidates = [
|
|
37264
|
+
moduleBasePath,
|
|
37265
|
+
...typescriptModuleBasePath ? [
|
|
37266
|
+
`${typescriptModuleBasePath}.ts`,
|
|
37267
|
+
`${typescriptModuleBasePath}.tsx`,
|
|
37268
|
+
Path.join(typescriptModuleBasePath, "index.ts"),
|
|
37269
|
+
Path.join(typescriptModuleBasePath, "index.tsx")
|
|
37270
|
+
] : [],
|
|
37271
|
+
...SCRIPT_MODULE_EXTENSIONS.map((extension) => `${moduleBasePath}${extension}`),
|
|
37272
|
+
...SCRIPT_MODULE_EXTENSIONS.map((extension) => Path.join(moduleBasePath, `index${extension}`))
|
|
37273
|
+
];
|
|
37274
|
+
for (const candidate of candidates) {
|
|
37275
|
+
const sourceFile = program.getSourceFile(candidate);
|
|
37276
|
+
if (sourceFile) return sourceFile;
|
|
37277
|
+
}
|
|
37278
|
+
return null;
|
|
37279
|
+
};
|
|
37280
|
+
const resolveModuleExportEvidence = (sourceFile, exportName, typeChecker, program, visitedSymbols) => {
|
|
37281
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
37282
|
+
if (moduleSymbol && visitedSymbols.has(moduleSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37283
|
+
const nextVisitedSymbols = new Set(visitedSymbols);
|
|
37284
|
+
if (moduleSymbol) nextVisitedSymbols.add(moduleSymbol);
|
|
37285
|
+
for (const statement of sourceFile.statements) {
|
|
37286
|
+
if (exportName === "default" && ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
37287
|
+
const evidence = resolveMotionExpressionEvidence(statement.expression, typeChecker, program, nextVisitedSymbols);
|
|
37288
|
+
if (hasMotionExpressionEvidence(evidence)) return evidence;
|
|
37289
|
+
continue;
|
|
37290
|
+
}
|
|
37291
|
+
if (!ts.isExportDeclaration(statement) || !statement.moduleSpecifier) continue;
|
|
37292
|
+
if (statement.isTypeOnly) continue;
|
|
37293
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
37294
|
+
const moduleSource = statement.moduleSpecifier.text;
|
|
37295
|
+
if (!statement.exportClause) {
|
|
37296
|
+
if (isMotionModuleSource(moduleSource)) {
|
|
37297
|
+
const evidence = classifyMotionExport(exportName);
|
|
37298
|
+
if (hasMotionExpressionEvidence(evidence)) return evidence;
|
|
37299
|
+
continue;
|
|
37300
|
+
}
|
|
37301
|
+
const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
|
|
37302
|
+
if (moduleSourceFile) {
|
|
37303
|
+
const evidence = resolveModuleExportEvidence(moduleSourceFile, exportName, typeChecker, program, nextVisitedSymbols);
|
|
37304
|
+
if (hasMotionExpressionEvidence(evidence)) return evidence;
|
|
37305
|
+
}
|
|
37306
|
+
continue;
|
|
37307
|
+
}
|
|
37308
|
+
if (!ts.isNamedExports(statement.exportClause)) continue;
|
|
37309
|
+
for (const exportSpecifier of statement.exportClause.elements) {
|
|
37310
|
+
if (exportSpecifier.name.text !== exportName || exportSpecifier.isTypeOnly) continue;
|
|
37311
|
+
const sourceExportName = exportSpecifier.propertyName?.text ?? exportSpecifier.name.text;
|
|
37312
|
+
if (isMotionModuleSource(moduleSource)) return classifyMotionExport(sourceExportName);
|
|
37313
|
+
const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
|
|
37314
|
+
if (!moduleSourceFile) continue;
|
|
37315
|
+
return resolveModuleExportEvidence(moduleSourceFile, sourceExportName, typeChecker, program, nextVisitedSymbols);
|
|
37316
|
+
}
|
|
37317
|
+
}
|
|
37318
|
+
if (!moduleSymbol) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37319
|
+
const exportedSymbol = typeChecker.getExportsOfModule(moduleSymbol).find((candidateSymbol) => candidateSymbol.name === exportName);
|
|
37320
|
+
if (!exportedSymbol || nextVisitedSymbols.has(exportedSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37321
|
+
nextVisitedSymbols.add(exportedSymbol);
|
|
37322
|
+
let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37323
|
+
for (const declaration of exportedSymbol.declarations ?? []) {
|
|
37324
|
+
if (ts.isExportSpecifier(declaration)) {
|
|
37325
|
+
const targetSymbol = typeChecker.getExportSpecifierLocalTargetSymbol(declaration);
|
|
37326
|
+
for (const targetDeclaration of targetSymbol?.declarations ?? []) {
|
|
37327
|
+
const importedEvidence = getImportedBindingEvidence(targetDeclaration, typeChecker, program, nextVisitedSymbols);
|
|
37328
|
+
if (importedEvidence) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
|
|
37329
|
+
if (ts.isVariableDeclaration(targetDeclaration) && targetDeclaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(targetDeclaration.initializer, typeChecker, program, nextVisitedSymbols));
|
|
37330
|
+
}
|
|
37331
|
+
}
|
|
37332
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
|
|
37333
|
+
}
|
|
37334
|
+
return resolvedEvidence;
|
|
37335
|
+
};
|
|
37336
|
+
const mergeMotionExpressionEvidence = (leftEvidence, rightEvidence) => ({
|
|
37337
|
+
isAnimationFunction: leftEvidence.isAnimationFunction || rightEvidence.isAnimationFunction,
|
|
37338
|
+
isMotionComponent: leftEvidence.isMotionComponent || rightEvidence.isMotionComponent,
|
|
37339
|
+
isMotionComponentFactory: leftEvidence.isMotionComponentFactory || rightEvidence.isMotionComponentFactory,
|
|
37340
|
+
isMotionComponentNamespace: leftEvidence.isMotionComponentNamespace || rightEvidence.isMotionComponentNamespace,
|
|
37341
|
+
isMotionConfig: leftEvidence.isMotionConfig || rightEvidence.isMotionConfig,
|
|
37342
|
+
isMotionNamespace: leftEvidence.isMotionNamespace || rightEvidence.isMotionNamespace,
|
|
37343
|
+
isReducedMotionHook: leftEvidence.isReducedMotionHook || rightEvidence.isReducedMotionHook
|
|
37344
|
+
});
|
|
37345
|
+
const hasMotionExpressionEvidence = (evidence) => evidence.isAnimationFunction || evidence.isMotionComponent || evidence.isMotionComponentFactory || evidence.isMotionComponentNamespace || evidence.isMotionConfig || evidence.isMotionNamespace || evidence.isReducedMotionHook;
|
|
37346
|
+
const classifyMotionMember = (receiverEvidence, memberName) => {
|
|
37347
|
+
if (receiverEvidence.isMotionNamespace) return classifyMotionExport(memberName);
|
|
37348
|
+
if (receiverEvidence.isMotionComponentFactory) return {
|
|
37349
|
+
...EMPTY_MOTION_EXPRESSION_EVIDENCE,
|
|
37350
|
+
isMotionComponent: true
|
|
37351
|
+
};
|
|
37352
|
+
if (receiverEvidence.isMotionComponentNamespace && MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES.has(memberName)) return {
|
|
37353
|
+
...EMPTY_MOTION_EXPRESSION_EVIDENCE,
|
|
37354
|
+
isMotionComponent: true
|
|
37355
|
+
};
|
|
37356
|
+
return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37357
|
+
};
|
|
37358
|
+
const resolveMotionExpressionEvidence = (expression, typeChecker, program, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
37359
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
37360
|
+
if (ts.isIdentifier(unwrappedExpression)) {
|
|
37361
|
+
const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
|
|
37362
|
+
if (!symbol || visitedSymbols.has(symbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37363
|
+
const nextVisitedSymbols = new Set(visitedSymbols);
|
|
37364
|
+
nextVisitedSymbols.add(symbol);
|
|
37365
|
+
let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37366
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
37367
|
+
const importedEvidence = getImportedBindingEvidence(declaration, typeChecker, program, nextVisitedSymbols);
|
|
37368
|
+
if (importedEvidence) {
|
|
37369
|
+
resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
|
|
37370
|
+
continue;
|
|
37371
|
+
}
|
|
37372
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
|
|
37373
|
+
if (ts.isBindingElement(declaration) && ts.isObjectBindingPattern(declaration.parent) && ts.isVariableDeclaration(declaration.parent.parent) && declaration.parent.parent.initializer) {
|
|
37374
|
+
const propertyName = declaration.propertyName ?? declaration.name;
|
|
37375
|
+
if (ts.isIdentifier(propertyName) || ts.isStringLiteral(propertyName)) {
|
|
37376
|
+
const receiverEvidence = resolveMotionExpressionEvidence(declaration.parent.parent.initializer, typeChecker, program, nextVisitedSymbols);
|
|
37377
|
+
resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, classifyMotionMember(receiverEvidence, propertyName.text));
|
|
37378
|
+
}
|
|
37379
|
+
}
|
|
37380
|
+
}
|
|
37381
|
+
return resolvedEvidence;
|
|
37382
|
+
}
|
|
37383
|
+
if (ts.isPropertyAccessExpression(unwrappedExpression)) return classifyMotionMember(resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols), unwrappedExpression.name.text);
|
|
37384
|
+
if (ts.isElementAccessExpression(unwrappedExpression) && unwrappedExpression.argumentExpression && (ts.isStringLiteral(unwrappedExpression.argumentExpression) || ts.isNoSubstitutionTemplateLiteral(unwrappedExpression.argumentExpression))) return classifyMotionMember(resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols), unwrappedExpression.argumentExpression.text);
|
|
37385
|
+
if (ts.isCallExpression(unwrappedExpression)) {
|
|
37386
|
+
if (ts.isIdentifier(unwrappedExpression.expression) && unwrappedExpression.expression.text === "require" && !typeChecker.getSymbolAtLocation(unwrappedExpression.expression) && unwrappedExpression.arguments.length === 1 && ts.isStringLiteral(unwrappedExpression.arguments[0]) && isMotionModuleSource(unwrappedExpression.arguments[0].text)) return {
|
|
37387
|
+
...EMPTY_MOTION_EXPRESSION_EVIDENCE,
|
|
37388
|
+
isMotionNamespace: true
|
|
37389
|
+
};
|
|
37390
|
+
if (ts.isPropertyAccessExpression(unwrappedExpression.expression) && unwrappedExpression.expression.name.text === "bind") {
|
|
37391
|
+
const boundReceiverEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression.expression, typeChecker, program, visitedSymbols);
|
|
37392
|
+
if (boundReceiverEvidence.isAnimationFunction) return boundReceiverEvidence;
|
|
37393
|
+
}
|
|
37394
|
+
const calleeEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols);
|
|
37395
|
+
if (calleeEvidence.isMotionComponentFactory) return {
|
|
37396
|
+
...EMPTY_MOTION_EXPRESSION_EVIDENCE,
|
|
37397
|
+
isMotionComponent: true
|
|
37398
|
+
};
|
|
37399
|
+
return calleeEvidence;
|
|
37400
|
+
}
|
|
37401
|
+
return EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
37402
|
+
};
|
|
37403
|
+
const getStaticStringExpressionValue = (expression, typeChecker, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
37404
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
37405
|
+
if (ts.isStringLiteral(unwrappedExpression) || ts.isNoSubstitutionTemplateLiteral(unwrappedExpression)) return unwrappedExpression.text;
|
|
37406
|
+
if (!ts.isIdentifier(unwrappedExpression)) return null;
|
|
37407
|
+
const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
|
|
37408
|
+
if (!symbol || visitedSymbols.has(symbol)) return null;
|
|
37409
|
+
const nextVisitedSymbols = new Set(visitedSymbols);
|
|
37410
|
+
nextVisitedSymbols.add(symbol);
|
|
37411
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
37412
|
+
if (!ts.isVariableDeclaration(declaration) || !declaration.initializer) continue;
|
|
37413
|
+
if (!ts.isVariableDeclarationList(declaration.parent)) continue;
|
|
37414
|
+
if (!(declaration.parent.flags & ts.NodeFlags.Const)) continue;
|
|
37415
|
+
const value = getStaticStringExpressionValue(declaration.initializer, typeChecker, nextVisitedSymbols);
|
|
37416
|
+
if (value !== null) return value;
|
|
37417
|
+
}
|
|
37418
|
+
return null;
|
|
37419
|
+
};
|
|
37420
|
+
const getStaticJsxAttributeValue = (attribute, typeChecker) => {
|
|
37421
|
+
if (!attribute.initializer) return null;
|
|
37422
|
+
if (ts.isStringLiteral(attribute.initializer)) return attribute.initializer.text;
|
|
37423
|
+
if (!ts.isJsxExpression(attribute.initializer) || !attribute.initializer.expression) return null;
|
|
37424
|
+
return getStaticStringExpressionValue(attribute.initializer.expression, typeChecker);
|
|
37425
|
+
};
|
|
37426
|
+
const isExpressionValueConsumed = (expression) => {
|
|
37427
|
+
let currentExpression = expression;
|
|
37428
|
+
while (ts.isParenthesizedExpression(currentExpression.parent) || ts.isAsExpression(currentExpression.parent) || ts.isSatisfiesExpression(currentExpression.parent) || ts.isNonNullExpression(currentExpression.parent) || ts.isTypeAssertionExpression(currentExpression.parent)) currentExpression = currentExpression.parent;
|
|
37429
|
+
return !ts.isExpressionStatement(currentExpression.parent) && !ts.isVoidExpression(currentExpression.parent);
|
|
37430
|
+
};
|
|
37431
|
+
const jsxElementHasReducedMotionConfiguration = (attributes, typeChecker) => attributes.properties.some((attribute) => ts.isJsxAttribute(attribute) && ts.isIdentifier(attribute.name) && attribute.name.text === REDUCED_MOTION_PROP_NAME && REDUCED_MOTION_CONFIG_VALUES.has(getStaticJsxAttributeValue(attribute, typeChecker) ?? ""));
|
|
37432
|
+
const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
|
|
37433
|
+
const evidence = {
|
|
37434
|
+
hasMotionUse: false,
|
|
37435
|
+
hasReducedMotionHandling: false
|
|
37436
|
+
};
|
|
37437
|
+
const visitNode = (node) => {
|
|
37438
|
+
if (ts.isCallExpression(node)) {
|
|
37439
|
+
const calleeEvidence = resolveMotionExpressionEvidence(node.expression, typeChecker, program);
|
|
37440
|
+
const isAnimationFunctionCallViaCallOrApply = (ts.isPropertyAccessExpression(node.expression) && (node.expression.name.text === "call" || node.expression.name.text === "apply") || ts.isElementAccessExpression(node.expression) && node.expression.argumentExpression && (ts.isStringLiteral(node.expression.argumentExpression) || ts.isNoSubstitutionTemplateLiteral(node.expression.argumentExpression)) && (node.expression.argumentExpression.text === "call" || node.expression.argumentExpression.text === "apply")) && resolveMotionExpressionEvidence(node.expression.expression, typeChecker, program).isAnimationFunction;
|
|
37441
|
+
if (calleeEvidence.isAnimationFunction || isAnimationFunctionCallViaCallOrApply) evidence.hasMotionUse = true;
|
|
37442
|
+
if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
|
|
37443
|
+
}
|
|
37444
|
+
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
37445
|
+
const tagEvidence = ts.isJsxNamespacedName(node.tagName) ? EMPTY_MOTION_EXPRESSION_EVIDENCE : resolveMotionExpressionEvidence(node.tagName, typeChecker, program);
|
|
37446
|
+
if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
|
|
37447
|
+
if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
|
|
37448
|
+
}
|
|
37449
|
+
ts.forEachChild(node, visitNode);
|
|
37450
|
+
};
|
|
37451
|
+
visitNode(sourceFile);
|
|
37452
|
+
return evidence;
|
|
37453
|
+
};
|
|
37454
|
+
const analyzeReducedMotionSources = (sources) => {
|
|
37455
|
+
if (!sources.some(({ sourceText }) => MOTION_SOURCE_PREFILTER.test(sourceText))) return {
|
|
37456
|
+
hasMotionUse: false,
|
|
37457
|
+
hasReducedMotionHandling: false
|
|
37458
|
+
};
|
|
37459
|
+
const compilerOptions = {
|
|
37460
|
+
allowJs: true,
|
|
37461
|
+
checkJs: false,
|
|
37462
|
+
jsx: ts.JsxEmit.Preserve,
|
|
37463
|
+
module: ts.ModuleKind.ESNext,
|
|
37464
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
37465
|
+
noEmit: true,
|
|
37466
|
+
noLib: true,
|
|
37467
|
+
noResolve: true,
|
|
37468
|
+
skipLibCheck: true,
|
|
37469
|
+
target: ts.ScriptTarget.Latest
|
|
37470
|
+
};
|
|
37471
|
+
const sourceTextByFileName = new Map(sources.map(({ fileName: sourceFileName, sourceText: content }) => [Path.resolve(sourceFileName), content]));
|
|
37472
|
+
const compilerHost = ts.createCompilerHost(compilerOptions);
|
|
37473
|
+
const getDefaultSourceFile = compilerHost.getSourceFile.bind(compilerHost);
|
|
37474
|
+
compilerHost.getSourceFile = (requestedFileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => sourceTextByFileName.has(Path.resolve(requestedFileName)) ? ts.createSourceFile(Path.resolve(requestedFileName), sourceTextByFileName.get(Path.resolve(requestedFileName)) ?? "", languageVersionOrOptions, true, getTypescriptScriptKind(requestedFileName)) : getDefaultSourceFile(requestedFileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
|
|
37475
|
+
const program = ts.createProgram([...sourceTextByFileName.keys()], compilerOptions, compilerHost);
|
|
37476
|
+
const typeChecker = program.getTypeChecker();
|
|
37477
|
+
const evidence = {
|
|
37478
|
+
hasMotionUse: false,
|
|
37479
|
+
hasReducedMotionHandling: false
|
|
37480
|
+
};
|
|
37481
|
+
for (const sourceFileName of sourceTextByFileName.keys()) {
|
|
37482
|
+
const sourceFile = program.getSourceFile(sourceFileName);
|
|
37483
|
+
if (!sourceFile) continue;
|
|
37484
|
+
const fileEvidence = collectScriptMotionEvidence(sourceFile, typeChecker, program);
|
|
37485
|
+
evidence.hasMotionUse ||= fileEvidence.hasMotionUse;
|
|
37486
|
+
evidence.hasReducedMotionHandling ||= fileEvidence.hasReducedMotionHandling;
|
|
37487
|
+
}
|
|
37488
|
+
return evidence;
|
|
37489
|
+
};
|
|
37490
|
+
const removeCssCommentsAndStrings = (content) => {
|
|
37491
|
+
let sanitizedContent = "";
|
|
37492
|
+
let quote = null;
|
|
37493
|
+
let isInsideComment = false;
|
|
37494
|
+
let isInsideLineComment = false;
|
|
37495
|
+
for (let characterIndex = 0; characterIndex < content.length; characterIndex += 1) {
|
|
37496
|
+
const character = content[characterIndex];
|
|
37497
|
+
const nextCharacter = content[characterIndex + 1];
|
|
37498
|
+
if (isInsideLineComment) {
|
|
37499
|
+
sanitizedContent += character === "\n" ? "\n" : " ";
|
|
37500
|
+
if (character === "\n") isInsideLineComment = false;
|
|
37501
|
+
continue;
|
|
37502
|
+
}
|
|
37503
|
+
if (isInsideComment) {
|
|
37504
|
+
if (character === "*" && nextCharacter === "/") {
|
|
37505
|
+
sanitizedContent += " ";
|
|
37506
|
+
characterIndex += 1;
|
|
37507
|
+
isInsideComment = false;
|
|
37508
|
+
} else sanitizedContent += character === "\n" ? "\n" : " ";
|
|
37509
|
+
continue;
|
|
37510
|
+
}
|
|
37511
|
+
if (quote) {
|
|
37512
|
+
if (character === "\\") {
|
|
37513
|
+
sanitizedContent += " ";
|
|
37514
|
+
characterIndex += 1;
|
|
37515
|
+
continue;
|
|
37516
|
+
}
|
|
37517
|
+
if (character === quote) quote = null;
|
|
37518
|
+
sanitizedContent += character === "\n" ? "\n" : " ";
|
|
37519
|
+
continue;
|
|
37520
|
+
}
|
|
37521
|
+
if (character === "/" && nextCharacter === "*") {
|
|
37522
|
+
sanitizedContent += " ";
|
|
37523
|
+
characterIndex += 1;
|
|
37524
|
+
isInsideComment = true;
|
|
37525
|
+
continue;
|
|
37526
|
+
}
|
|
37527
|
+
if (character === "/" && nextCharacter === "/") {
|
|
37528
|
+
sanitizedContent += " ";
|
|
37529
|
+
characterIndex += 1;
|
|
37530
|
+
isInsideLineComment = true;
|
|
37531
|
+
continue;
|
|
37532
|
+
}
|
|
37533
|
+
if (character === "\"" || character === "'") {
|
|
37534
|
+
sanitizedContent += " ";
|
|
37535
|
+
quote = character;
|
|
37536
|
+
continue;
|
|
37537
|
+
}
|
|
37538
|
+
sanitizedContent += character;
|
|
37539
|
+
}
|
|
37540
|
+
return sanitizedContent;
|
|
37541
|
+
};
|
|
37542
|
+
const findMatchingClosingBrace = (content, openingBraceIndex) => {
|
|
37543
|
+
let depth = 0;
|
|
37544
|
+
for (let characterIndex = openingBraceIndex; characterIndex < content.length; characterIndex += 1) {
|
|
37545
|
+
if (content[characterIndex] === "{") depth += 1;
|
|
37546
|
+
if (content[characterIndex] !== "}") continue;
|
|
37547
|
+
depth -= 1;
|
|
37548
|
+
if (depth === 0) return characterIndex;
|
|
37549
|
+
}
|
|
37550
|
+
return -1;
|
|
37551
|
+
};
|
|
37552
|
+
const hasReducedMotionMediaQuery = (content) => {
|
|
37553
|
+
const sanitizedContent = removeCssCommentsAndStrings(content);
|
|
37554
|
+
REDUCED_MOTION_MEDIA_QUERY_PATTERN.lastIndex = 0;
|
|
37555
|
+
for (const match of sanitizedContent.matchAll(REDUCED_MOTION_MEDIA_QUERY_PATTERN)) {
|
|
37556
|
+
const mediaPrelude = match[1];
|
|
37557
|
+
if (/\bnot\b/i.test(mediaPrelude)) continue;
|
|
37558
|
+
const openingBraceIndex = (match.index ?? 0) + match[0].lastIndexOf("{");
|
|
37559
|
+
const closingBraceIndex = findMatchingClosingBrace(sanitizedContent, openingBraceIndex);
|
|
37560
|
+
if (closingBraceIndex === -1) continue;
|
|
37561
|
+
const body = sanitizedContent.slice(openingBraceIndex + 1, closingBraceIndex);
|
|
37562
|
+
if (CSS_DECLARATION_PATTERN.test(body)) return true;
|
|
37563
|
+
}
|
|
37564
|
+
return false;
|
|
37565
|
+
};
|
|
37566
|
+
const collectProjectMotionEvidence = (rootDirectory) => {
|
|
37567
|
+
const scriptSources = [];
|
|
37568
|
+
let hasReducedMotionHandling = false;
|
|
37187
37569
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
37188
|
-
|
|
37570
|
+
const extension = Path.extname(name);
|
|
37571
|
+
if (!SCRIPT_FILE_EXTENSIONS.has(extension) && !STYLE_FILE_EXTENSIONS.has(extension)) continue;
|
|
37189
37572
|
let content;
|
|
37190
37573
|
try {
|
|
37191
37574
|
content = NFS.readFileSync(absolutePath, "utf-8");
|
|
37192
37575
|
} catch {
|
|
37193
37576
|
continue;
|
|
37194
37577
|
}
|
|
37195
|
-
if (
|
|
37578
|
+
if (STYLE_FILE_EXTENSIONS.has(extension)) {
|
|
37579
|
+
if (hasReducedMotionMediaQuery(content)) hasReducedMotionHandling = true;
|
|
37580
|
+
continue;
|
|
37581
|
+
}
|
|
37582
|
+
scriptSources.push({
|
|
37583
|
+
fileName: absolutePath,
|
|
37584
|
+
sourceText: content
|
|
37585
|
+
});
|
|
37196
37586
|
}
|
|
37197
|
-
return
|
|
37587
|
+
if (scriptSources.length === 0) return {
|
|
37588
|
+
hasMotionUse: false,
|
|
37589
|
+
hasReducedMotionHandling
|
|
37590
|
+
};
|
|
37591
|
+
const scriptEvidence = analyzeReducedMotionSources(scriptSources);
|
|
37592
|
+
const hasMotionUse = scriptEvidence.hasMotionUse;
|
|
37593
|
+
hasReducedMotionHandling ||= scriptEvidence.hasReducedMotionHandling;
|
|
37594
|
+
return {
|
|
37595
|
+
hasMotionUse,
|
|
37596
|
+
hasReducedMotionHandling
|
|
37597
|
+
};
|
|
37198
37598
|
};
|
|
37199
37599
|
const checkReducedMotion = (rootDirectory) => {
|
|
37200
37600
|
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
37201
37601
|
if (!isFile(packageJsonPath)) return [];
|
|
37202
|
-
let hasMotionLibrary = false;
|
|
37203
37602
|
try {
|
|
37204
37603
|
const packageJson = readPackageJson(packageJsonPath);
|
|
37205
37604
|
const allDependencies = {
|
|
37206
37605
|
...packageJson.dependencies,
|
|
37207
37606
|
...packageJson.devDependencies
|
|
37208
37607
|
};
|
|
37209
|
-
|
|
37608
|
+
if (!Object.keys(allDependencies).some((packageName) => MOTION_LIBRARY_PACKAGES.has(packageName))) return [];
|
|
37210
37609
|
} catch {
|
|
37211
37610
|
return [];
|
|
37212
37611
|
}
|
|
37213
|
-
|
|
37214
|
-
|
|
37215
|
-
"grep",
|
|
37216
|
-
"--untracked",
|
|
37217
|
-
"-lE",
|
|
37218
|
-
REDUCED_MOTION_GREP_PATTERN,
|
|
37219
|
-
"--",
|
|
37220
|
-
...REDUCED_MOTION_FILE_GLOBS
|
|
37221
|
-
], {
|
|
37222
|
-
cwd: rootDirectory,
|
|
37223
|
-
encoding: "utf-8",
|
|
37224
|
-
stdio: [
|
|
37225
|
-
"ignore",
|
|
37226
|
-
"pipe",
|
|
37227
|
-
"pipe"
|
|
37228
|
-
]
|
|
37229
|
-
});
|
|
37230
|
-
if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
37231
|
-
return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
37612
|
+
const evidence = collectProjectMotionEvidence(rootDirectory);
|
|
37613
|
+
return evidence.hasMotionUse && !evidence.hasReducedMotionHandling ? [MISSING_REDUCED_MOTION_DIAGNOSTIC] : [];
|
|
37232
37614
|
};
|
|
37233
37615
|
const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
|
|
37234
37616
|
filePath: relativePath,
|
|
@@ -39831,23 +40213,12 @@ const REACT_USE_BINDING_RESOLUTION = {
|
|
|
39831
40213
|
isReactUseBinding: true,
|
|
39832
40214
|
isReactNamespaceBinding: false
|
|
39833
40215
|
};
|
|
39834
|
-
const getScriptKind$2 = (filename) => {
|
|
39835
|
-
if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
39836
|
-
if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
39837
|
-
if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
39838
|
-
return ts.ScriptKind.JS;
|
|
39839
|
-
};
|
|
39840
40216
|
const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
|
|
39841
|
-
const unwrapExpression = (expression) => {
|
|
39842
|
-
let currentExpression = expression;
|
|
39843
|
-
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
39844
|
-
return currentExpression;
|
|
39845
|
-
};
|
|
39846
40217
|
const getStaticPropertyName = (node) => {
|
|
39847
40218
|
if (!node) return null;
|
|
39848
40219
|
if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) return node.text;
|
|
39849
40220
|
if (ts.isComputedPropertyName(node)) {
|
|
39850
|
-
const expression =
|
|
40221
|
+
const expression = unwrapTypescriptExpression(node.expression);
|
|
39851
40222
|
if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) return expression.text;
|
|
39852
40223
|
}
|
|
39853
40224
|
return null;
|
|
@@ -39876,7 +40247,7 @@ const isReactUseObjectBindingElement = (bindingElement) => {
|
|
|
39876
40247
|
return getStaticPropertyName(bindingElement.propertyName) === USE_IDENTIFIER;
|
|
39877
40248
|
};
|
|
39878
40249
|
const isReactRequireCall = (expression) => {
|
|
39879
|
-
const unwrappedExpression =
|
|
40250
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
39880
40251
|
return ts.isCallExpression(unwrappedExpression) && ts.isIdentifier(unwrappedExpression.expression) && unwrappedExpression.expression.text === REQUIRE_IDENTIFIER && unwrappedExpression.arguments.length === 1 && ts.isStringLiteral(unwrappedExpression.arguments[0]) && unwrappedExpression.arguments[0].text === REACT_MODULE_SOURCE;
|
|
39881
40252
|
};
|
|
39882
40253
|
const getModuleSource = (node) => {
|
|
@@ -39978,7 +40349,7 @@ const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
|
39978
40349
|
return false;
|
|
39979
40350
|
};
|
|
39980
40351
|
const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
|
|
39981
|
-
const unwrappedExpression =
|
|
40352
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
39982
40353
|
if (isReactRequireCall(unwrappedExpression)) return true;
|
|
39983
40354
|
if (!ts.isIdentifier(unwrappedExpression)) return false;
|
|
39984
40355
|
if (reactImportBindings.namespaceNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
|
|
@@ -39986,7 +40357,7 @@ const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile,
|
|
|
39986
40357
|
};
|
|
39987
40358
|
const isReactUseExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
|
|
39988
40359
|
if (!expression) return false;
|
|
39989
|
-
const unwrappedExpression =
|
|
40360
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
39990
40361
|
if (ts.isIdentifier(unwrappedExpression)) {
|
|
39991
40362
|
if (reactImportBindings.useImportNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
|
|
39992
40363
|
if (unwrappedExpression.text === USE_IDENTIFIER) return false;
|
|
@@ -40086,7 +40457,7 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
|
|
|
40086
40457
|
return matchedIdentifier;
|
|
40087
40458
|
};
|
|
40088
40459
|
const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
|
|
40089
|
-
const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true,
|
|
40460
|
+
const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filename));
|
|
40090
40461
|
const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
|
|
40091
40462
|
if (!useIdentifier) return null;
|
|
40092
40463
|
return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
|
|
@@ -40122,12 +40493,6 @@ const WORKLET_ACCEPTING_CALLEES = new Set([
|
|
|
40122
40493
|
"executeOnUIRuntimeSync"
|
|
40123
40494
|
]);
|
|
40124
40495
|
const GESTURE_ROOT_IDENTIFIER = "Gesture";
|
|
40125
|
-
const getScriptKind$1 = (filename) => {
|
|
40126
|
-
if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
40127
|
-
if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
40128
|
-
if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
40129
|
-
return ts.ScriptKind.JS;
|
|
40130
|
-
};
|
|
40131
40496
|
const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
|
|
40132
40497
|
const hasWorkletDirective = (node) => {
|
|
40133
40498
|
if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
|
|
@@ -40199,17 +40564,11 @@ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirecto
|
|
|
40199
40564
|
} catch {
|
|
40200
40565
|
return false;
|
|
40201
40566
|
}
|
|
40202
|
-
return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true,
|
|
40567
|
+
return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
|
|
40203
40568
|
};
|
|
40204
40569
|
const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
|
|
40205
40570
|
const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
|
|
40206
40571
|
const REACT_COMPILER_PLUGIN = "react-hooks-js";
|
|
40207
|
-
const getScriptKind = (filename) => {
|
|
40208
|
-
if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
40209
|
-
if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
40210
|
-
if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
40211
|
-
return ts.ScriptKind.JS;
|
|
40212
|
-
};
|
|
40213
40572
|
const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
|
|
40214
40573
|
const nodeLineRange = (sourceFile, node) => ({
|
|
40215
40574
|
startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
|
|
@@ -40271,7 +40630,7 @@ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) =>
|
|
|
40271
40630
|
try {
|
|
40272
40631
|
const buffer = NFS.readFileSync(absolutePath);
|
|
40273
40632
|
parsed = {
|
|
40274
|
-
sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true,
|
|
40633
|
+
sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)),
|
|
40275
40634
|
buffer
|
|
40276
40635
|
};
|
|
40277
40636
|
} catch {
|
|
@@ -42870,7 +43229,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
42870
43229
|
/** Display name used in client-facing messages and progress titles. */
|
|
42871
43230
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
42872
43231
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
42873
|
-
const SERVER_VERSION = "0.7.
|
|
43232
|
+
const SERVER_VERSION = "0.7.8";
|
|
42874
43233
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
42875
43234
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
42876
43235
|
/**
|
|
@@ -43073,7 +43432,9 @@ const toLspDiagnostic = (input) => {
|
|
|
43073
43432
|
line: diagnostic.line,
|
|
43074
43433
|
column: diagnostic.column,
|
|
43075
43434
|
plugin: diagnostic.plugin,
|
|
43076
|
-
rule: diagnostic.rule
|
|
43435
|
+
rule: diagnostic.rule,
|
|
43436
|
+
severity: diagnostic.severity,
|
|
43437
|
+
message: diagnostic.message
|
|
43077
43438
|
}),
|
|
43078
43439
|
plugin: diagnostic.plugin,
|
|
43079
43440
|
rule: diagnostic.rule,
|
|
@@ -44915,5 +45276,5 @@ const startLanguageServer = () => {
|
|
|
44915
45276
|
};
|
|
44916
45277
|
//#endregion
|
|
44917
45278
|
export { startLanguageServer };
|
|
44918
|
-
!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]="
|
|
44919
|
-
//# debugId=
|
|
45279
|
+
!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]="6f5aad14-63ee-530d-a972-9d9330e3a155")}catch(e){}}();
|
|
45280
|
+
//# debugId=6f5aad14-63ee-530d-a972-9d9330e3a155
|