@c4a/extract-ts 0.7.4 → 0.7.8
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/index.js +1260 -788
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -12532,6 +12532,753 @@ var detectEntries = async (manifest, fs) => {
|
|
|
12532
12532
|
};
|
|
12533
12533
|
};
|
|
12534
12534
|
|
|
12535
|
+
// src/componentContract.ts
|
|
12536
|
+
import ts from "typescript";
|
|
12537
|
+
function componentPropsNode(node2) {
|
|
12538
|
+
if (node2 === undefined || !ts.isTypeReferenceNode(node2))
|
|
12539
|
+
return;
|
|
12540
|
+
if (!["FC", "React.FC", "FunctionComponent", "React.FunctionComponent"].includes(node2.typeName.getText()))
|
|
12541
|
+
return;
|
|
12542
|
+
return node2.typeArguments?.length === 1 ? node2.typeArguments[0] : undefined;
|
|
12543
|
+
}
|
|
12544
|
+
function componentLocalPropsNode(node2, checker) {
|
|
12545
|
+
if (ts.isParenthesizedTypeNode(node2))
|
|
12546
|
+
return componentLocalPropsNode(node2.type, checker);
|
|
12547
|
+
if (!ts.isTypeReferenceNode(node2) || node2.typeArguments?.length !== 1)
|
|
12548
|
+
return;
|
|
12549
|
+
const name = node2.typeName;
|
|
12550
|
+
const identifier = ts.isIdentifier(name) ? name : ts.isIdentifier(name.left) ? name.left : undefined;
|
|
12551
|
+
if (identifier === undefined)
|
|
12552
|
+
return;
|
|
12553
|
+
const imported = checker.getSymbolAtLocation(identifier)?.declarations?.find((declaration) => ts.isImportSpecifier(declaration) || ts.isNamespaceImport(declaration) || ts.isImportClause(declaration));
|
|
12554
|
+
if (imported === undefined)
|
|
12555
|
+
return;
|
|
12556
|
+
let owner = imported;
|
|
12557
|
+
while (!ts.isImportDeclaration(owner) && owner.parent !== undefined)
|
|
12558
|
+
owner = owner.parent;
|
|
12559
|
+
if (!ts.isImportDeclaration(owner) || !ts.isStringLiteral(owner.moduleSpecifier) || owner.moduleSpecifier.text !== "react")
|
|
12560
|
+
return;
|
|
12561
|
+
const wrapper = ts.isIdentifier(name) ? ts.isImportSpecifier(imported) ? (imported.propertyName ?? imported.name).text : undefined : ts.isNamespaceImport(imported) || ts.isImportClause(imported) ? name.right.text : undefined;
|
|
12562
|
+
return wrapper === "PropsWithChildren" ? node2.typeArguments[0] : undefined;
|
|
12563
|
+
}
|
|
12564
|
+
function componentPropsName(annotation) {
|
|
12565
|
+
const source = ts.createSourceFile("contract.ts", `type Contract = ${annotation};`, ts.ScriptTarget.Latest, true);
|
|
12566
|
+
const declaration = source.statements[0];
|
|
12567
|
+
if (declaration === undefined || !ts.isTypeAliasDeclaration(declaration))
|
|
12568
|
+
return;
|
|
12569
|
+
const props = componentPropsNode(declaration.type);
|
|
12570
|
+
return props !== undefined && ts.isTypeReferenceNode(props) && ts.isIdentifier(props.typeName) && !props.typeArguments?.length ? props.typeName.text : undefined;
|
|
12571
|
+
}
|
|
12572
|
+
function componentBindingDefaults(pattern) {
|
|
12573
|
+
const source = ts.createSourceFile("contract.ts", `function input(${pattern}) {}`, ts.ScriptTarget.Latest, true);
|
|
12574
|
+
const diagnostics = source.parseDiagnostics;
|
|
12575
|
+
const fn = source.statements[0];
|
|
12576
|
+
if (diagnostics.length || source.statements.length !== 1 || fn === undefined || !ts.isFunctionDeclaration(fn) || fn.parameters.length !== 1 || fn.body?.statements.length)
|
|
12577
|
+
return {};
|
|
12578
|
+
const name = fn.parameters[0].name;
|
|
12579
|
+
return componentDefaultsFromBinding(name, source);
|
|
12580
|
+
}
|
|
12581
|
+
function componentDefaultsFromBinding(name, source) {
|
|
12582
|
+
if (!ts.isObjectBindingPattern(name))
|
|
12583
|
+
return {};
|
|
12584
|
+
const defaults = Object.create(null);
|
|
12585
|
+
for (const element of name.elements) {
|
|
12586
|
+
const key = element.propertyName ?? element.name;
|
|
12587
|
+
if (element.initializer === undefined || element.dotDotDotToken !== undefined || !ts.isIdentifier(key) && !ts.isStringLiteral(key) && !ts.isNumericLiteral(key))
|
|
12588
|
+
continue;
|
|
12589
|
+
defaults[key.text] = element.initializer.getText(source);
|
|
12590
|
+
}
|
|
12591
|
+
return defaults;
|
|
12592
|
+
}
|
|
12593
|
+
|
|
12594
|
+
// src/federationContracts.ts
|
|
12595
|
+
import ts2 from "typescript";
|
|
12596
|
+
function federationContracts(source) {
|
|
12597
|
+
const factories = new Set;
|
|
12598
|
+
for (const statement of source.statements) {
|
|
12599
|
+
if (!ts2.isImportDeclaration(statement) || !ts2.isStringLiteral(statement.moduleSpecifier))
|
|
12600
|
+
continue;
|
|
12601
|
+
const module = statement.moduleSpecifier.text;
|
|
12602
|
+
const clause = statement.importClause;
|
|
12603
|
+
if (module === "webpack" && clause?.name !== undefined)
|
|
12604
|
+
factories.add(`${clause.name.text}.container.ModuleFederationPlugin`);
|
|
12605
|
+
if (!["webpack", "@module-federation/enhanced/webpack", "@module-federation/enhanced/rspack", "@module-federation/vite"].includes(module))
|
|
12606
|
+
continue;
|
|
12607
|
+
if (clause?.namedBindings !== undefined && ts2.isNamedImports(clause.namedBindings)) {
|
|
12608
|
+
for (const item of clause.namedBindings.elements) {
|
|
12609
|
+
if (["ModuleFederationPlugin", "federation"].includes((item.propertyName ?? item.name).text))
|
|
12610
|
+
factories.add(item.name.text);
|
|
12611
|
+
if (module === "webpack" && (item.propertyName ?? item.name).text === "container")
|
|
12612
|
+
factories.add(`${item.name.text}.ModuleFederationPlugin`);
|
|
12613
|
+
}
|
|
12614
|
+
}
|
|
12615
|
+
}
|
|
12616
|
+
const results = [];
|
|
12617
|
+
const visit = (node2) => {
|
|
12618
|
+
if ((ts2.isCallExpression(node2) || ts2.isNewExpression(node2)) && factories.has(node2.expression.getText(source))) {
|
|
12619
|
+
const config = node2.arguments?.[0];
|
|
12620
|
+
if (config !== undefined && ts2.isObjectLiteralExpression(config)) {
|
|
12621
|
+
const members = [];
|
|
12622
|
+
for (const property of config.properties) {
|
|
12623
|
+
if (!ts2.isPropertyAssignment(property))
|
|
12624
|
+
continue;
|
|
12625
|
+
const key = property.name.getText(source).replace(/^['"]|['"]$/gu, "");
|
|
12626
|
+
if (!["name", "filename", "exposes", "remotes", "shared"].includes(key))
|
|
12627
|
+
continue;
|
|
12628
|
+
const properties = ts2.isObjectLiteralExpression(property.initializer) ? property.initializer.properties.filter(ts2.isPropertyAssignment) : [property];
|
|
12629
|
+
for (const value of properties)
|
|
12630
|
+
members.push({
|
|
12631
|
+
name: value === property ? key : `${key}.${value.name.getText(source).replace(/^['"]|['"]$/gu, "")}`,
|
|
12632
|
+
kind: "config" /* Config */,
|
|
12633
|
+
visibility: "exported" /* Exported */,
|
|
12634
|
+
file: source.fileName.replace(/^\//u, ""),
|
|
12635
|
+
line: source.getLineAndCharacterOfPosition(value.getStart()).line + 1,
|
|
12636
|
+
endLine: source.getLineAndCharacterOfPosition(value.end).line + 1,
|
|
12637
|
+
typeAnnotation: value.initializer.getText(source)
|
|
12638
|
+
});
|
|
12639
|
+
}
|
|
12640
|
+
results.push({
|
|
12641
|
+
name: "Module federation configuration",
|
|
12642
|
+
kind: "config" /* Config */,
|
|
12643
|
+
visibility: "exported" /* Exported */,
|
|
12644
|
+
file: source.fileName.replace(/^\//u, ""),
|
|
12645
|
+
line: source.getLineAndCharacterOfPosition(node2.getStart()).line + 1,
|
|
12646
|
+
endLine: source.getLineAndCharacterOfPosition(node2.end).line + 1,
|
|
12647
|
+
signature: node2.expression.getText(source),
|
|
12648
|
+
members
|
|
12649
|
+
});
|
|
12650
|
+
}
|
|
12651
|
+
}
|
|
12652
|
+
ts2.forEachChild(node2, visit);
|
|
12653
|
+
};
|
|
12654
|
+
visit(source);
|
|
12655
|
+
return results;
|
|
12656
|
+
}
|
|
12657
|
+
|
|
12658
|
+
// src/publicContracts.ts
|
|
12659
|
+
import { posix as posix3 } from "node:path";
|
|
12660
|
+
import ts5 from "typescript";
|
|
12661
|
+
|
|
12662
|
+
// src/typeReferences.ts
|
|
12663
|
+
import ts3 from "typescript";
|
|
12664
|
+
var BUILTIN_TYPES = new Set([
|
|
12665
|
+
"Array",
|
|
12666
|
+
"Boolean",
|
|
12667
|
+
"Date",
|
|
12668
|
+
"Error",
|
|
12669
|
+
"Map",
|
|
12670
|
+
"Number",
|
|
12671
|
+
"Object",
|
|
12672
|
+
"Promise",
|
|
12673
|
+
"ReadonlyArray",
|
|
12674
|
+
"Record",
|
|
12675
|
+
"Set",
|
|
12676
|
+
"String"
|
|
12677
|
+
]);
|
|
12678
|
+
function referencedTypeNames(text) {
|
|
12679
|
+
if (!text)
|
|
12680
|
+
return [];
|
|
12681
|
+
const file = ts3.createSourceFile("type.ts", `type __Value = ${text};`, ts3.ScriptTarget.Latest, true);
|
|
12682
|
+
const declaration = file.statements[0];
|
|
12683
|
+
if (!declaration || !ts3.isTypeAliasDeclaration(declaration))
|
|
12684
|
+
return [];
|
|
12685
|
+
const result = new Set;
|
|
12686
|
+
const visit = (node2, bound) => {
|
|
12687
|
+
const scope = new Set(bound);
|
|
12688
|
+
if ("typeParameters" in node2) {
|
|
12689
|
+
for (const parameter of node2.typeParameters ?? []) {
|
|
12690
|
+
scope.add(parameter.name.text);
|
|
12691
|
+
}
|
|
12692
|
+
}
|
|
12693
|
+
if (ts3.isMappedTypeNode(node2)) {
|
|
12694
|
+
if (node2.typeParameter.constraint)
|
|
12695
|
+
visit(node2.typeParameter.constraint, bound);
|
|
12696
|
+
scope.add(node2.typeParameter.name.text);
|
|
12697
|
+
if (node2.nameType)
|
|
12698
|
+
visit(node2.nameType, scope);
|
|
12699
|
+
if (node2.type)
|
|
12700
|
+
visit(node2.type, scope);
|
|
12701
|
+
return;
|
|
12702
|
+
}
|
|
12703
|
+
if (ts3.isConditionalTypeNode(node2)) {
|
|
12704
|
+
visit(node2.checkType, scope);
|
|
12705
|
+
visit(node2.extendsType, scope);
|
|
12706
|
+
const inferred = new Set(scope);
|
|
12707
|
+
const collect = (child) => {
|
|
12708
|
+
if (ts3.isInferTypeNode(child))
|
|
12709
|
+
inferred.add(child.typeParameter.name.text);
|
|
12710
|
+
else if (!ts3.isConditionalTypeNode(child))
|
|
12711
|
+
ts3.forEachChild(child, collect);
|
|
12712
|
+
};
|
|
12713
|
+
collect(node2.extendsType);
|
|
12714
|
+
visit(node2.trueType, inferred);
|
|
12715
|
+
visit(node2.falseType, scope);
|
|
12716
|
+
return;
|
|
12717
|
+
}
|
|
12718
|
+
if (ts3.isTypeReferenceNode(node2)) {
|
|
12719
|
+
const name = node2.typeName.getText(file);
|
|
12720
|
+
if (!scope.has(name.split(".")[0]) && !BUILTIN_TYPES.has(name))
|
|
12721
|
+
result.add(name);
|
|
12722
|
+
}
|
|
12723
|
+
ts3.forEachChild(node2, (child) => visit(child, scope));
|
|
12724
|
+
};
|
|
12725
|
+
visit(declaration.type, new Set);
|
|
12726
|
+
return [...result];
|
|
12727
|
+
}
|
|
12728
|
+
|
|
12729
|
+
// src/symbolExtractorAst.ts
|
|
12730
|
+
var DECLARATION_TYPES = new Set([
|
|
12731
|
+
"function_declaration",
|
|
12732
|
+
"class_declaration",
|
|
12733
|
+
"interface_declaration",
|
|
12734
|
+
"type_alias_declaration",
|
|
12735
|
+
"enum_declaration",
|
|
12736
|
+
"lexical_declaration"
|
|
12737
|
+
]);
|
|
12738
|
+
var countLines = (source) => {
|
|
12739
|
+
if (!source)
|
|
12740
|
+
return 0;
|
|
12741
|
+
return source.split(/\r\n|\r|\n/).filter((line) => line.trim().length > 0).length;
|
|
12742
|
+
};
|
|
12743
|
+
var createRelation = (type, from, to, isExternal, line) => ({
|
|
12744
|
+
type,
|
|
12745
|
+
from,
|
|
12746
|
+
to,
|
|
12747
|
+
isExternal,
|
|
12748
|
+
grounding: "code" /* Code */,
|
|
12749
|
+
confidence: 1,
|
|
12750
|
+
source: "ast" /* Ast */,
|
|
12751
|
+
...line ? { line } : {}
|
|
12752
|
+
});
|
|
12753
|
+
var getLine = (node2) => node2.startPosition.row + 1;
|
|
12754
|
+
var getEndLine = (node2) => node2.endPosition.row + 1;
|
|
12755
|
+
var extractJSDoc = (node2) => {
|
|
12756
|
+
const prev = node2.previousNamedSibling ?? node2.parent?.previousNamedSibling;
|
|
12757
|
+
if (!prev || prev.type !== "comment")
|
|
12758
|
+
return;
|
|
12759
|
+
const text = prev.text;
|
|
12760
|
+
if (!text.startsWith("/**"))
|
|
12761
|
+
return;
|
|
12762
|
+
const cleaned = text.replace(/^\/\*\*\s*/, "").replace(/\s*\*\/$/, "").replace(/^\s*\* ?/gm, "").trim();
|
|
12763
|
+
return cleaned || undefined;
|
|
12764
|
+
};
|
|
12765
|
+
var extractTypeAnnotation = (node2) => {
|
|
12766
|
+
if (!node2)
|
|
12767
|
+
return null;
|
|
12768
|
+
return node2.text.replace(/^:\s*/, "").trim() || null;
|
|
12769
|
+
};
|
|
12770
|
+
var getNameNodeText = (node2) => node2?.text?.trim() ? node2.text.trim() : null;
|
|
12771
|
+
var getReturnType = (node2) => {
|
|
12772
|
+
const returnNode = node2.childForFieldName("return_type") ?? node2.namedChildren.find((child) => child.type === "type_annotation") ?? null;
|
|
12773
|
+
return extractTypeAnnotation(returnNode);
|
|
12774
|
+
};
|
|
12775
|
+
var getInitializer = (node2) => node2.childForFieldName("value") ?? node2.namedChildren.find((child) => child.type === "arrow_function" || child.type === "function" || child.type === "call_expression") ?? null;
|
|
12776
|
+
var getCallableFromInitializer = (node2) => {
|
|
12777
|
+
if (!node2)
|
|
12778
|
+
return null;
|
|
12779
|
+
if (node2.type === "arrow_function" || node2.type === "function")
|
|
12780
|
+
return node2;
|
|
12781
|
+
if (node2.type === "call_expression") {
|
|
12782
|
+
return node2.namedChildren.find((child) => child.type === "arrow_function" || child.type === "function") ?? null;
|
|
12783
|
+
}
|
|
12784
|
+
return null;
|
|
12785
|
+
};
|
|
12786
|
+
var getInitializerTypeAnnotation = (node2, options = {}) => {
|
|
12787
|
+
if (!node2 || node2.type !== "call_expression")
|
|
12788
|
+
return null;
|
|
12789
|
+
const typeArguments = node2.namedChildren.find((child) => child.type === "type_arguments") ?? null;
|
|
12790
|
+
if (!typeArguments)
|
|
12791
|
+
return null;
|
|
12792
|
+
if (options.referencesOnly) {
|
|
12793
|
+
return `[${typeArguments.namedChildren.filter((child) => child.type !== "comment").map((child) => child.text).join(", ")}]`;
|
|
12794
|
+
}
|
|
12795
|
+
const callee = node2.namedChildren.find((child) => child.type !== "type_arguments" && child.type !== "arguments") ?? null;
|
|
12796
|
+
const calleeText = callee?.text?.trim();
|
|
12797
|
+
return calleeText ? `${calleeText}${typeArguments.text}` : typeArguments.text;
|
|
12798
|
+
};
|
|
12799
|
+
var getInitializerText = (node2, options = {}) => {
|
|
12800
|
+
if (!node2)
|
|
12801
|
+
return null;
|
|
12802
|
+
if ((node2.type === "arrow_function" || node2.type === "function") && !options.includeCallable)
|
|
12803
|
+
return null;
|
|
12804
|
+
const text = node2.text.trim();
|
|
12805
|
+
if ((node2.type === "arrow_function" || node2.type === "function") && text.length > 600)
|
|
12806
|
+
return null;
|
|
12807
|
+
return text.length > 0 ? text : null;
|
|
12808
|
+
};
|
|
12809
|
+
var inferReturnType = (node2) => {
|
|
12810
|
+
if (!node2)
|
|
12811
|
+
return null;
|
|
12812
|
+
return containsJsx(node2) ? "JSX.Element" : null;
|
|
12813
|
+
};
|
|
12814
|
+
var containsJsx = (node2) => {
|
|
12815
|
+
if (node2.type.startsWith("jsx_"))
|
|
12816
|
+
return true;
|
|
12817
|
+
return node2.namedChildren.some(containsJsx);
|
|
12818
|
+
};
|
|
12819
|
+
var resolveTypeBinding = (typeName, importBindings, declarations) => {
|
|
12820
|
+
const localName = typeName.split(".")[0] ?? typeName;
|
|
12821
|
+
const importBinding = importBindings.get(localName);
|
|
12822
|
+
if (importBinding)
|
|
12823
|
+
return importBinding.isExternal;
|
|
12824
|
+
if (declarations.has(localName))
|
|
12825
|
+
return false;
|
|
12826
|
+
return false;
|
|
12827
|
+
};
|
|
12828
|
+
var appendTypeRelations = (relations, relationType, from, typeText, importBindings, declarations, line) => {
|
|
12829
|
+
for (const typeName of referencedTypeNames(typeText)) {
|
|
12830
|
+
relations.push(createRelation(relationType, from, typeName, resolveTypeBinding(typeName, importBindings, declarations), line));
|
|
12831
|
+
}
|
|
12832
|
+
};
|
|
12833
|
+
var classifyVariable = (name, filePath) => {
|
|
12834
|
+
if ((filePath.endsWith(".tsx") || filePath.endsWith(".jsx")) && /^[A-Z]/.test(name)) {
|
|
12835
|
+
return "component" /* Component */;
|
|
12836
|
+
}
|
|
12837
|
+
return "variable" /* Variable */;
|
|
12838
|
+
};
|
|
12839
|
+
var collectParams = (node2) => {
|
|
12840
|
+
if (!node2)
|
|
12841
|
+
return [];
|
|
12842
|
+
return node2.namedChildren.map((child) => {
|
|
12843
|
+
const wrapper = child;
|
|
12844
|
+
const target = child.type === "required_parameter" || child.type === "optional_parameter" ? child.namedChildren[0] ?? child : child;
|
|
12845
|
+
const nameNode = target.childForFieldName("name") ?? target.namedChildren.find((candidate) => candidate.type === "identifier" || candidate.type === "property_identifier") ?? target.namedChildren[0] ?? target;
|
|
12846
|
+
const typeNode = wrapper.childForFieldName("type") ?? wrapper.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? target.childForFieldName("type") ?? target.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? null;
|
|
12847
|
+
return {
|
|
12848
|
+
name: nameNode.text,
|
|
12849
|
+
type: extractTypeAnnotation(typeNode),
|
|
12850
|
+
optional: wrapper.type === "optional_parameter" || wrapper.children.some((child2) => child2.text === "?"),
|
|
12851
|
+
rest: wrapper.text.trimStart().startsWith("..."),
|
|
12852
|
+
...wrapper.childForFieldName("value") === null ? {} : { defaultValue: wrapper.childForFieldName("value").text }
|
|
12853
|
+
};
|
|
12854
|
+
});
|
|
12855
|
+
};
|
|
12856
|
+
var collectMembers = (node2, declarations, importBindings, ownerName, relations) => {
|
|
12857
|
+
if (!node2)
|
|
12858
|
+
return;
|
|
12859
|
+
const members = [];
|
|
12860
|
+
for (const child of node2.namedChildren) {
|
|
12861
|
+
if (child.type === "public_field_definition" || child.type === "property_signature") {
|
|
12862
|
+
const nameNode = child.childForFieldName("name") ?? child.namedChildren.find((candidate) => candidate.type === "property_identifier" || candidate.type === "identifier");
|
|
12863
|
+
if (!nameNode)
|
|
12864
|
+
continue;
|
|
12865
|
+
const typeNode = child.childForFieldName("type") ?? child.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? null;
|
|
12866
|
+
const typeAnnotation = extractTypeAnnotation(typeNode);
|
|
12867
|
+
const propDoc = extractJSDoc(child);
|
|
12868
|
+
members.push({
|
|
12869
|
+
name: nameNode.text,
|
|
12870
|
+
kind: "prop" /* Prop */,
|
|
12871
|
+
visibility: "internal" /* Internal */,
|
|
12872
|
+
file: "",
|
|
12873
|
+
line: getLine(child),
|
|
12874
|
+
endLine: getEndLine(child),
|
|
12875
|
+
optional: child.children.some((token) => token.text === "?"),
|
|
12876
|
+
readonly: child.children.some((token) => token.text === "readonly"),
|
|
12877
|
+
...typeAnnotation ? { typeAnnotation } : {},
|
|
12878
|
+
...propDoc ? { doc: propDoc } : {}
|
|
12879
|
+
});
|
|
12880
|
+
appendTypeRelations(relations, "of_type" /* OfType */, ownerName, typeAnnotation, importBindings, declarations, getLine(child));
|
|
12881
|
+
continue;
|
|
12882
|
+
}
|
|
12883
|
+
const indexMember = indexSignatureMember(child);
|
|
12884
|
+
if (indexMember) {
|
|
12885
|
+
members.push(indexMember.info);
|
|
12886
|
+
appendTypeRelations(relations, "of_type" /* OfType */, ownerName, indexMember.typeAnnotation, importBindings, declarations, getLine(child));
|
|
12887
|
+
continue;
|
|
12888
|
+
}
|
|
12889
|
+
if (child.type === "method_definition" || child.type === "method_signature") {
|
|
12890
|
+
const nameNode = child.childForFieldName("name") ?? child.namedChildren.find((candidate) => candidate.type === "property_identifier" || candidate.type === "identifier");
|
|
12891
|
+
if (!nameNode)
|
|
12892
|
+
continue;
|
|
12893
|
+
const paramsNode = child.childForFieldName("parameters") ?? child.namedChildren.find((candidate) => candidate.type === "formal_parameters") ?? null;
|
|
12894
|
+
const params = collectParams(paramsNode);
|
|
12895
|
+
const returnType = getReturnType(child);
|
|
12896
|
+
const methodDoc = extractJSDoc(child);
|
|
12897
|
+
members.push({
|
|
12898
|
+
name: nameNode.text,
|
|
12899
|
+
kind: "method" /* Method */,
|
|
12900
|
+
visibility: "internal" /* Internal */,
|
|
12901
|
+
file: "",
|
|
12902
|
+
line: getLine(child),
|
|
12903
|
+
endLine: getEndLine(child),
|
|
12904
|
+
...params.length > 0 ? { params } : {},
|
|
12905
|
+
...returnType ? { returnType } : {},
|
|
12906
|
+
...methodDoc ? { doc: methodDoc } : {}
|
|
12907
|
+
});
|
|
12908
|
+
for (const param of params) {
|
|
12909
|
+
appendTypeRelations(relations, "param_type" /* ParamType */, ownerName, param.type, importBindings, declarations, getLine(child));
|
|
12910
|
+
}
|
|
12911
|
+
appendTypeRelations(relations, "return_type" /* ReturnType */, ownerName, returnType, importBindings, declarations, getLine(child));
|
|
12912
|
+
}
|
|
12913
|
+
}
|
|
12914
|
+
return members.length > 0 ? members : undefined;
|
|
12915
|
+
};
|
|
12916
|
+
var indexSignatureMember = (node2) => {
|
|
12917
|
+
if (node2.type !== "index_signature")
|
|
12918
|
+
return null;
|
|
12919
|
+
const match = /^\s*(\[[^\]]+\])\s*:?\s*([^;]+)?;?\s*$/u.exec(node2.text);
|
|
12920
|
+
const name = match?.[1]?.trim();
|
|
12921
|
+
const typeAnnotation = match?.[2]?.trim();
|
|
12922
|
+
if (!name)
|
|
12923
|
+
return null;
|
|
12924
|
+
const propDoc = extractJSDoc(node2);
|
|
12925
|
+
return {
|
|
12926
|
+
info: {
|
|
12927
|
+
name,
|
|
12928
|
+
kind: "prop" /* Prop */,
|
|
12929
|
+
visibility: "internal" /* Internal */,
|
|
12930
|
+
file: "",
|
|
12931
|
+
line: getLine(node2),
|
|
12932
|
+
endLine: getEndLine(node2),
|
|
12933
|
+
...typeAnnotation ? { typeAnnotation } : {},
|
|
12934
|
+
...propDoc ? { doc: propDoc } : {}
|
|
12935
|
+
},
|
|
12936
|
+
typeAnnotation
|
|
12937
|
+
};
|
|
12938
|
+
};
|
|
12939
|
+
var collectEnumValues = (node2) => {
|
|
12940
|
+
const body = node2.namedChildren.find((child) => child.type === "enum_body") ?? null;
|
|
12941
|
+
if (!body)
|
|
12942
|
+
return;
|
|
12943
|
+
const values = [];
|
|
12944
|
+
for (const member of body.namedChildren.filter((child) => child.type === "enum_assignment" || child.type === "property_identifier")) {
|
|
12945
|
+
if (member.type === "property_identifier") {
|
|
12946
|
+
values.push(member.text);
|
|
12947
|
+
continue;
|
|
12948
|
+
}
|
|
12949
|
+
const name = member.childForFieldName("name")?.text ?? member.namedChildren[0]?.text;
|
|
12950
|
+
if (!name)
|
|
12951
|
+
continue;
|
|
12952
|
+
const valueNode = member.childForFieldName("value") ?? member.namedChildren.find((child) => child !== member.childForFieldName("name")) ?? null;
|
|
12953
|
+
const rawValue = valueNode?.text.replace(/^['"]|['"]$/gu, "");
|
|
12954
|
+
values.push(rawValue ? `${name} = ${rawValue}` : name);
|
|
12955
|
+
}
|
|
12956
|
+
return values.length > 0 ? values : undefined;
|
|
12957
|
+
};
|
|
12958
|
+
var extractUnionLiteralValues = (typeNode) => {
|
|
12959
|
+
if (!typeNode)
|
|
12960
|
+
return;
|
|
12961
|
+
if (typeNode.type === "literal_type") {
|
|
12962
|
+
const text = typeNode.text.replace(/^['"]|['"]$/g, "");
|
|
12963
|
+
return text ? [text] : undefined;
|
|
12964
|
+
}
|
|
12965
|
+
if (typeNode.type === "union_type") {
|
|
12966
|
+
const values = [];
|
|
12967
|
+
for (const child of typeNode.namedChildren) {
|
|
12968
|
+
if (child.type === "literal_type") {
|
|
12969
|
+
const text = child.text.replace(/^['"]|['"]$/g, "");
|
|
12970
|
+
if (text)
|
|
12971
|
+
values.push(text);
|
|
12972
|
+
} else if (child.type === "union_type") {
|
|
12973
|
+
const nested = extractUnionLiteralValues(child);
|
|
12974
|
+
if (!nested)
|
|
12975
|
+
return;
|
|
12976
|
+
values.push(...nested);
|
|
12977
|
+
} else {
|
|
12978
|
+
return;
|
|
12979
|
+
}
|
|
12980
|
+
}
|
|
12981
|
+
return values.length > 0 ? values : undefined;
|
|
12982
|
+
}
|
|
12983
|
+
return;
|
|
12984
|
+
};
|
|
12985
|
+
var findObjectTypeNodes = (node2) => {
|
|
12986
|
+
if (!node2)
|
|
12987
|
+
return [];
|
|
12988
|
+
if (node2.type === "object_type")
|
|
12989
|
+
return [node2];
|
|
12990
|
+
if (node2.type === "intersection_type" || node2.type === "union_type") {
|
|
12991
|
+
return node2.namedChildren.flatMap(findObjectTypeNodes);
|
|
12992
|
+
}
|
|
12993
|
+
if (node2.type === "parenthesized_type" && node2.namedChildCount > 0) {
|
|
12994
|
+
return findObjectTypeNodes(node2.namedChildren[0]);
|
|
12995
|
+
}
|
|
12996
|
+
return [];
|
|
12997
|
+
};
|
|
12998
|
+
|
|
12999
|
+
// src/runtimeRegistrations.ts
|
|
13000
|
+
import ts4 from "typescript";
|
|
13001
|
+
function runtimeRegistrations(source) {
|
|
13002
|
+
const imports = new Map;
|
|
13003
|
+
const receivers = new Map;
|
|
13004
|
+
const middleware = new Map;
|
|
13005
|
+
const result = [];
|
|
13006
|
+
const supported = new Set(["express", "fastify", "hono", "node-cron", "node:events", "events"]);
|
|
13007
|
+
for (const statement of source.statements) {
|
|
13008
|
+
if (!ts4.isImportDeclaration(statement) || !ts4.isStringLiteral(statement.moduleSpecifier))
|
|
13009
|
+
continue;
|
|
13010
|
+
const module = statement.moduleSpecifier.text;
|
|
13011
|
+
if (!supported.has(module))
|
|
13012
|
+
continue;
|
|
13013
|
+
const clause = statement.importClause;
|
|
13014
|
+
if (clause?.name !== undefined)
|
|
13015
|
+
imports.set(clause.name.text, module);
|
|
13016
|
+
if (clause?.namedBindings !== undefined) {
|
|
13017
|
+
if (ts4.isNamespaceImport(clause.namedBindings))
|
|
13018
|
+
imports.set(clause.namedBindings.name.text, module);
|
|
13019
|
+
else
|
|
13020
|
+
for (const item of clause.namedBindings.elements)
|
|
13021
|
+
imports.set(item.name.text, module);
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
const rootName = (node2) => ts4.isIdentifier(node2) ? node2.text : ts4.isPropertyAccessExpression(node2) ? rootName(node2.expression) : undefined;
|
|
13025
|
+
const visit = (node2) => {
|
|
13026
|
+
if (ts4.isVariableDeclaration(node2) && ts4.isIdentifier(node2.name) && node2.initializer !== undefined && (ts4.isCallExpression(node2.initializer) || ts4.isNewExpression(node2.initializer))) {
|
|
13027
|
+
const root = rootName(node2.initializer.expression);
|
|
13028
|
+
const module = root === undefined ? undefined : imports.get(root);
|
|
13029
|
+
if (module !== undefined)
|
|
13030
|
+
receivers.set(node2.name.text, module);
|
|
13031
|
+
}
|
|
13032
|
+
if (ts4.isCallExpression(node2) && ts4.isPropertyAccessExpression(node2.expression)) {
|
|
13033
|
+
const receiver = node2.expression.expression.getText(source);
|
|
13034
|
+
const module = receivers.get(receiver) ?? imports.get(receiver);
|
|
13035
|
+
const operation = node2.expression.name.text;
|
|
13036
|
+
if (module !== undefined) {
|
|
13037
|
+
const args = node2.arguments;
|
|
13038
|
+
const http = ["express", "fastify", "hono"].includes(module);
|
|
13039
|
+
if (http && operation === "use") {
|
|
13040
|
+
middleware.set(receiver, [...middleware.get(receiver) ?? [], ...args.map((arg) => arg.getText(source))]);
|
|
13041
|
+
}
|
|
13042
|
+
const kind = http && ["get", "post", "put", "patch", "delete", "head", "options", "all"].includes(operation) ? "http" : module === "node-cron" && operation === "schedule" ? "schedule" : ["events", "node:events"].includes(module) && ["on", "once"].includes(operation) ? "event" : undefined;
|
|
13043
|
+
const first = args[0];
|
|
13044
|
+
if (kind !== undefined && first !== undefined && ts4.isStringLiteralLike(first) && args.length >= 2) {
|
|
13045
|
+
const handler = args.at(-1).getText(source);
|
|
13046
|
+
const line = source.getLineAndCharacterOfPosition(node2.getStart()).line + 1;
|
|
13047
|
+
result.push({
|
|
13048
|
+
name: `${kind === "http" ? operation.toUpperCase() : kind} ${first.text}`,
|
|
13049
|
+
kind: kind === "http" ? "endpoint" /* Endpoint */ : "process" /* Process */,
|
|
13050
|
+
visibility: "exported" /* Exported */,
|
|
13051
|
+
file: source.fileName.replace(/^\//u, ""),
|
|
13052
|
+
line,
|
|
13053
|
+
endLine: source.getLineAndCharacterOfPosition(node2.end).line + 1,
|
|
13054
|
+
signature: `${operation} ${first.text} → ${handler}`,
|
|
13055
|
+
registration: {
|
|
13056
|
+
kind,
|
|
13057
|
+
key: first.text,
|
|
13058
|
+
handler,
|
|
13059
|
+
...kind === "http" ? { method: operation.toUpperCase() } : {},
|
|
13060
|
+
middleware: [...middleware.get(receiver) ?? [], ...args.slice(1, -1).map((arg) => arg.getText(source))]
|
|
13061
|
+
}
|
|
13062
|
+
});
|
|
13063
|
+
}
|
|
13064
|
+
}
|
|
13065
|
+
}
|
|
13066
|
+
ts4.forEachChild(node2, visit);
|
|
13067
|
+
};
|
|
13068
|
+
visit(source);
|
|
13069
|
+
return result;
|
|
13070
|
+
}
|
|
13071
|
+
|
|
13072
|
+
// src/publicContracts.ts
|
|
13073
|
+
var format = ts5.TypeFormatFlags.NoTruncation | ts5.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope;
|
|
13074
|
+
function declarationAt(source, symbol) {
|
|
13075
|
+
const candidates = [];
|
|
13076
|
+
const visit = (node2) => {
|
|
13077
|
+
const line = source.getLineAndCharacterOfPosition(node2.getStart(source)).line + 1;
|
|
13078
|
+
if (line > symbol.endLine)
|
|
13079
|
+
return;
|
|
13080
|
+
if (line === symbol.line && (ts5.isFunctionDeclaration(node2) || ts5.isVariableDeclaration(node2) || ts5.isInterfaceDeclaration(node2) || ts5.isTypeAliasDeclaration(node2) || ts5.isClassDeclaration(node2))) {
|
|
13081
|
+
candidates.push(node2);
|
|
13082
|
+
}
|
|
13083
|
+
ts5.forEachChild(node2, visit);
|
|
13084
|
+
};
|
|
13085
|
+
visit(source);
|
|
13086
|
+
return candidates.find((node2) => ("name" in node2) && node2.name?.getText(source) === symbol.name) ?? (candidates.length === 1 ? candidates[0] : undefined);
|
|
13087
|
+
}
|
|
13088
|
+
function declaredObjectTypes(node2, checker, seen = new Set) {
|
|
13089
|
+
if (seen.has(node2))
|
|
13090
|
+
return [];
|
|
13091
|
+
seen.add(node2);
|
|
13092
|
+
if (ts5.isTypeAliasDeclaration(node2))
|
|
13093
|
+
return declaredObjectTypes(node2.type, checker, seen);
|
|
13094
|
+
if (ts5.isParenthesizedTypeNode(node2))
|
|
13095
|
+
return declaredObjectTypes(node2.type, checker, seen);
|
|
13096
|
+
if (ts5.isIntersectionTypeNode(node2))
|
|
13097
|
+
return node2.types.flatMap((type) => declaredObjectTypes(type, checker, seen));
|
|
13098
|
+
if (ts5.isTypeReferenceNode(node2) && !node2.typeArguments?.length) {
|
|
13099
|
+
let symbol = checker.getSymbolAtLocation(node2.typeName);
|
|
13100
|
+
if (symbol !== undefined && (symbol.flags & ts5.SymbolFlags.Alias) !== 0)
|
|
13101
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
13102
|
+
return (symbol?.declarations ?? []).flatMap((declaration) => declaredObjectTypes(declaration, checker, seen));
|
|
13103
|
+
}
|
|
13104
|
+
return ts5.isTypeLiteralNode(node2) || ts5.isInterfaceDeclaration(node2) ? [node2] : [];
|
|
13105
|
+
}
|
|
13106
|
+
function memberTypeText(checker, type, member, annotation) {
|
|
13107
|
+
const text = checker.typeToString(type, member, format);
|
|
13108
|
+
if (annotation === undefined)
|
|
13109
|
+
return { text, complete: (type.flags & (ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) === 0 };
|
|
13110
|
+
if (annotation.kind === ts5.SyntaxKind.AnyKeyword || annotation.kind === ts5.SyntaxKind.UnknownKeyword) {
|
|
13111
|
+
return { text: annotation.getText(), complete: true };
|
|
13112
|
+
}
|
|
13113
|
+
let incomplete = (type.flags & (ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) !== 0 || text === "{}" && !ts5.isTypeLiteralNode(annotation);
|
|
13114
|
+
const visit = (node2) => {
|
|
13115
|
+
if (ts5.isArrayTypeNode(node2) || ts5.isTupleTypeNode(node2) || ts5.isTypeReferenceNode(node2)) {
|
|
13116
|
+
const resolved = checker.getTypeFromTypeNode(node2);
|
|
13117
|
+
const rendered = checker.typeToString(resolved, node2, format);
|
|
13118
|
+
if ((resolved.flags & (ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) !== 0 || ts5.isArrayTypeNode(node2) && rendered === "{}")
|
|
13119
|
+
incomplete = true;
|
|
13120
|
+
}
|
|
13121
|
+
ts5.forEachChild(node2, visit);
|
|
13122
|
+
};
|
|
13123
|
+
visit(annotation);
|
|
13124
|
+
return { text: incomplete ? annotation.getText() : text, complete: !incomplete };
|
|
13125
|
+
}
|
|
13126
|
+
function callable(node2) {
|
|
13127
|
+
if (ts5.isFunctionDeclaration(node2))
|
|
13128
|
+
return node2;
|
|
13129
|
+
if (!ts5.isVariableDeclaration(node2))
|
|
13130
|
+
return;
|
|
13131
|
+
let value = node2.initializer;
|
|
13132
|
+
if (value !== undefined && ts5.isCallExpression(value)) {
|
|
13133
|
+
value = value.arguments.find((argument) => ts5.isArrowFunction(argument) || ts5.isFunctionExpression(argument));
|
|
13134
|
+
}
|
|
13135
|
+
return value !== undefined && (ts5.isArrowFunction(value) || ts5.isFunctionExpression(value)) ? value : undefined;
|
|
13136
|
+
}
|
|
13137
|
+
async function enrichPublicContracts(input) {
|
|
13138
|
+
const sources = new Map;
|
|
13139
|
+
for (const path2 of input.paths) {
|
|
13140
|
+
const source = await input.fs.readFile(path2);
|
|
13141
|
+
const absolute = posix3.resolve("/", path2);
|
|
13142
|
+
sources.set(absolute, ts5.createSourceFile(absolute, source, ts5.ScriptTarget.Latest, true));
|
|
13143
|
+
}
|
|
13144
|
+
const options = {
|
|
13145
|
+
noLib: true,
|
|
13146
|
+
skipLibCheck: true,
|
|
13147
|
+
allowJs: true,
|
|
13148
|
+
jsx: ts5.JsxEmit.Preserve,
|
|
13149
|
+
moduleResolution: ts5.ModuleResolutionKind.Node10,
|
|
13150
|
+
baseUrl: "/",
|
|
13151
|
+
paths: Object.fromEntries((input.resolver?.mappings ?? []).map((mapping) => [mapping.pattern, mapping.targets.map((target) => posix3.resolve("/", target))]))
|
|
13152
|
+
};
|
|
13153
|
+
const host = {
|
|
13154
|
+
getSourceFile: (path2) => sources.get(posix3.resolve("/", path2)),
|
|
13155
|
+
getDefaultLibFileName: () => "",
|
|
13156
|
+
writeFile: () => {},
|
|
13157
|
+
getCurrentDirectory: () => "/",
|
|
13158
|
+
getDirectories: () => [],
|
|
13159
|
+
fileExists: (path2) => sources.has(posix3.resolve("/", path2)),
|
|
13160
|
+
readFile: (path2) => sources.get(posix3.resolve("/", path2))?.text,
|
|
13161
|
+
getCanonicalFileName: (path2) => posix3.resolve("/", path2),
|
|
13162
|
+
useCaseSensitiveFileNames: () => true,
|
|
13163
|
+
getNewLine: () => `
|
|
13164
|
+
`
|
|
13165
|
+
};
|
|
13166
|
+
const program = ts5.createProgram([...sources.keys()], options, host);
|
|
13167
|
+
for (const source of sources.values())
|
|
13168
|
+
input.symbols.push(...runtimeRegistrations(source), ...federationContracts(source));
|
|
13169
|
+
const checker = program.getTypeChecker();
|
|
13170
|
+
const diagnosticsByFile = new Map;
|
|
13171
|
+
for (const symbol of input.symbols) {
|
|
13172
|
+
if (symbol.visibility !== "exported" /* Exported */)
|
|
13173
|
+
continue;
|
|
13174
|
+
const source = sources.get(posix3.resolve("/", symbol.file));
|
|
13175
|
+
if (source === undefined)
|
|
13176
|
+
continue;
|
|
13177
|
+
const declaration = declarationAt(source, symbol);
|
|
13178
|
+
if (declaration === undefined)
|
|
13179
|
+
continue;
|
|
13180
|
+
symbol.contractResolution = "declaration-only";
|
|
13181
|
+
const fn = callable(declaration);
|
|
13182
|
+
if (fn !== undefined) {
|
|
13183
|
+
symbol.params = fn.parameters.map((parameter) => ({
|
|
13184
|
+
name: parameter.name.getText(source),
|
|
13185
|
+
type: parameter.type?.getText(source) ?? checker.typeToString(checker.getTypeAtLocation(parameter), parameter, format),
|
|
13186
|
+
optional: parameter.questionToken !== undefined || parameter.initializer !== undefined,
|
|
13187
|
+
rest: parameter.dotDotDotToken !== undefined,
|
|
13188
|
+
...parameter.initializer === undefined ? {} : { defaultValue: parameter.initializer.getText(source) }
|
|
13189
|
+
}));
|
|
13190
|
+
if (fn.typeParameters !== undefined)
|
|
13191
|
+
symbol.typeParameters = `<${fn.typeParameters.map((item) => item.getText(source)).join(", ")}>`;
|
|
13192
|
+
}
|
|
13193
|
+
const valueType = checker.getTypeAtLocation(declaration);
|
|
13194
|
+
const signatures = valueType.getCallSignatures();
|
|
13195
|
+
const declaredSignatures = signatures.flatMap((signature) => {
|
|
13196
|
+
const declared = signature.getDeclaration();
|
|
13197
|
+
if (declared === undefined || !sources.has(declared.getSourceFile().fileName))
|
|
13198
|
+
return [];
|
|
13199
|
+
const body = "body" in declared ? declared.body : undefined;
|
|
13200
|
+
return [declared.getSourceFile().text.slice(declared.getStart(), body?.pos ?? declared.getEnd()).trim().replace(/;$/u, "")];
|
|
13201
|
+
});
|
|
13202
|
+
if (declaredSignatures.length > 1)
|
|
13203
|
+
symbol.overloads = declaredSignatures;
|
|
13204
|
+
let contractType;
|
|
13205
|
+
let localProps;
|
|
13206
|
+
if (symbol.kind === "component" /* Component */) {
|
|
13207
|
+
const parameter = signatures[0]?.parameters[0];
|
|
13208
|
+
if (parameter !== undefined) {
|
|
13209
|
+
contractType = checker.getTypeOfSymbolAtLocation(parameter, declaration);
|
|
13210
|
+
symbol.propsType = checker.typeToString(contractType, declaration, format);
|
|
13211
|
+
}
|
|
13212
|
+
const annotation = fn?.parameters[0]?.type ?? (ts5.isVariableDeclaration(declaration) ? componentPropsNode(declaration.type) : undefined);
|
|
13213
|
+
if (annotation !== undefined) {
|
|
13214
|
+
contractType = checker.getTypeFromTypeNode(annotation);
|
|
13215
|
+
symbol.propsType = annotation.getText(source);
|
|
13216
|
+
localProps = componentLocalPropsNode(annotation, checker);
|
|
13217
|
+
}
|
|
13218
|
+
} else if (ts5.isInterfaceDeclaration(declaration) || ts5.isTypeAliasDeclaration(declaration)) {
|
|
13219
|
+
contractType = checker.getTypeAtLocation(declaration);
|
|
13220
|
+
}
|
|
13221
|
+
if (contractType === undefined)
|
|
13222
|
+
continue;
|
|
13223
|
+
const unresolved = (contractType.flags & (ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) !== 0;
|
|
13224
|
+
const localType = unresolved && localProps !== undefined ? checker.getTypeFromTypeNode(localProps) : undefined;
|
|
13225
|
+
const knownType = localType ?? contractType;
|
|
13226
|
+
const properties = (knownType.flags & (ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) !== 0 ? declaredObjectTypes(localProps ?? declaration, checker).flatMap((node2) => checker.getPropertiesOfType(checker.getTypeAtLocation(node2))) : checker.getPropertiesOfType(knownType);
|
|
13227
|
+
if (properties.length === 0)
|
|
13228
|
+
continue;
|
|
13229
|
+
if (symbol.kind === "component" /* Component */ && symbol.propsType !== undefined && input.relations !== undefined) {
|
|
13230
|
+
const typeSymbol = knownType.aliasSymbol ?? knownType.getSymbol();
|
|
13231
|
+
const declaration2 = typeSymbol?.declarations?.[0];
|
|
13232
|
+
if (typeSymbol !== undefined && declaration2 !== undefined)
|
|
13233
|
+
input.relations.push({ ...createRelation("of_type" /* OfType */, symbol.name, typeSymbol.name, !sources.has(declaration2.getSourceFile().fileName), symbol.line), file: symbol.file });
|
|
13234
|
+
}
|
|
13235
|
+
const pattern = fn?.parameters[0]?.name;
|
|
13236
|
+
const defaults = pattern === undefined ? {} : componentDefaultsFromBinding(pattern, source);
|
|
13237
|
+
const members = [];
|
|
13238
|
+
let completeMembers = true;
|
|
13239
|
+
for (const property of properties) {
|
|
13240
|
+
const member = property.valueDeclaration ?? property.declarations?.[0];
|
|
13241
|
+
if (member === undefined || !sources.has(member.getSourceFile().fileName))
|
|
13242
|
+
continue;
|
|
13243
|
+
const memberSource = member.getSourceFile();
|
|
13244
|
+
const modifiers = ts5.canHaveModifiers(member) ? ts5.getModifiers(member) : undefined;
|
|
13245
|
+
const propertyType = checker.getTypeOfSymbolAtLocation(property, member);
|
|
13246
|
+
const annotation = "type" in member ? member.type : undefined;
|
|
13247
|
+
const documentedDefault = ts5.getJSDocTags(member).find((tag) => tag.tagName.text === "default" || tag.tagName.text === "defaultValue");
|
|
13248
|
+
const defaultComment = documentedDefault?.comment;
|
|
13249
|
+
const defaultText = typeof defaultComment === "string" ? defaultComment.trim() : defaultComment === undefined ? undefined : defaultComment.map((part) => part.getText(memberSource)).join("").trim();
|
|
13250
|
+
const defaultValue = (Object.hasOwn(defaults, property.name) ? defaults[property.name] : undefined) ?? (defaultText || undefined);
|
|
13251
|
+
const hidden = ts5.getJSDocTags(member).some((tag) => ["internal", "private"].includes(tag.tagName.text)) || modifiers?.some((modifier) => modifier.kind === ts5.SyntaxKind.PrivateKeyword || modifier.kind === ts5.SyntaxKind.ProtectedKeyword);
|
|
13252
|
+
if (hidden)
|
|
13253
|
+
continue;
|
|
13254
|
+
const renderedType = memberTypeText(checker, propertyType, member, annotation);
|
|
13255
|
+
completeMembers &&= renderedType.complete;
|
|
13256
|
+
members.push({
|
|
13257
|
+
name: property.name,
|
|
13258
|
+
kind: "prop" /* Prop */,
|
|
13259
|
+
visibility: "exported" /* Exported */,
|
|
13260
|
+
file: posix3.relative("/", memberSource.fileName),
|
|
13261
|
+
line: memberSource.getLineAndCharacterOfPosition(member.getStart()).line + 1,
|
|
13262
|
+
endLine: memberSource.getLineAndCharacterOfPosition(member.getEnd()).line + 1,
|
|
13263
|
+
optional: (property.flags & ts5.SymbolFlags.Optional) !== 0,
|
|
13264
|
+
...defaultValue === undefined ? {} : { defaultValue },
|
|
13265
|
+
readonly: modifiers?.some((modifier) => modifier.kind === ts5.SyntaxKind.ReadonlyKeyword) ?? false,
|
|
13266
|
+
typeAnnotation: renderedType.text,
|
|
13267
|
+
doc: ts5.displayPartsToString(property.getDocumentationComment(checker))
|
|
13268
|
+
});
|
|
13269
|
+
}
|
|
13270
|
+
if (properties.length > 0) {
|
|
13271
|
+
symbol.members = members;
|
|
13272
|
+
let diagnostics = diagnosticsByFile.get(source.fileName);
|
|
13273
|
+
if (diagnostics === undefined) {
|
|
13274
|
+
diagnostics = program.getSemanticDiagnostics(source);
|
|
13275
|
+
diagnosticsByFile.set(source.fileName, diagnostics);
|
|
13276
|
+
}
|
|
13277
|
+
symbol.contractResolution = !unresolved && completeMembers && diagnostics.length === 0 ? "resolved" : "declaration-only";
|
|
13278
|
+
}
|
|
13279
|
+
}
|
|
13280
|
+
}
|
|
13281
|
+
|
|
12535
13282
|
// ../extract/src/types.ts
|
|
12536
13283
|
var symbolKindSchema2 = exports_external.enum(Object.values(SymbolKind));
|
|
12537
13284
|
var visibilitySchema2 = exports_external.enum(Object.values(Visibility));
|
|
@@ -12555,7 +13302,17 @@ var relationSourceSchema = exports_external.enum([
|
|
|
12555
13302
|
var packageKindSchema2 = exports_external.enum(Object.values(PackageKind));
|
|
12556
13303
|
var symbolParamSchema = exports_external.object({
|
|
12557
13304
|
name: exports_external.string().min(1),
|
|
12558
|
-
type: exports_external.string().min(1).nullable()
|
|
13305
|
+
type: exports_external.string().min(1).nullable(),
|
|
13306
|
+
optional: exports_external.boolean().optional(),
|
|
13307
|
+
rest: exports_external.boolean().optional(),
|
|
13308
|
+
defaultValue: exports_external.string().optional()
|
|
13309
|
+
});
|
|
13310
|
+
var registrationSchema = exports_external.object({
|
|
13311
|
+
kind: exports_external.enum(["http", "schedule", "event"]),
|
|
13312
|
+
key: exports_external.string(),
|
|
13313
|
+
handler: exports_external.string(),
|
|
13314
|
+
method: exports_external.string().optional(),
|
|
13315
|
+
middleware: exports_external.array(exports_external.string())
|
|
12559
13316
|
});
|
|
12560
13317
|
var symbolInfoSchema = exports_external.lazy(() => exports_external.object({
|
|
12561
13318
|
name: exports_external.string().min(1),
|
|
@@ -12566,6 +13323,14 @@ var symbolInfoSchema = exports_external.lazy(() => exports_external.object({
|
|
|
12566
13323
|
endLine: exports_external.number().int().positive(),
|
|
12567
13324
|
members: exports_external.array(symbolInfoSchema).optional(),
|
|
12568
13325
|
params: exports_external.array(symbolParamSchema).optional(),
|
|
13326
|
+
optional: exports_external.boolean().optional(),
|
|
13327
|
+
readonly: exports_external.boolean().optional(),
|
|
13328
|
+
defaultValue: exports_external.string().optional(),
|
|
13329
|
+
typeParameters: exports_external.string().optional(),
|
|
13330
|
+
overloads: exports_external.array(exports_external.string()).optional(),
|
|
13331
|
+
publicEntrypoints: exports_external.array(exports_external.string()).optional(),
|
|
13332
|
+
contractResolution: exports_external.enum(["resolved", "declaration-only"]).optional(),
|
|
13333
|
+
registration: registrationSchema.optional(),
|
|
12569
13334
|
returnType: exports_external.string().min(1).nullable().optional(),
|
|
12570
13335
|
typeAnnotation: exports_external.string().min(1).nullable().optional(),
|
|
12571
13336
|
extends: exports_external.string().min(1).nullable().optional(),
|
|
@@ -12580,6 +13345,7 @@ var relationInfoSchema = exports_external.object({
|
|
|
12580
13345
|
type: relationTypeSchema,
|
|
12581
13346
|
from: exports_external.string().min(1),
|
|
12582
13347
|
to: exports_external.string().min(1),
|
|
13348
|
+
file: exports_external.string().min(1).optional(),
|
|
12583
13349
|
isExternal: exports_external.boolean(),
|
|
12584
13350
|
grounding: groundingSchema,
|
|
12585
13351
|
confidence: exports_external.number().min(0).max(1),
|
|
@@ -12860,6 +13626,8 @@ function semanticExtractionPayload(extraction) {
|
|
|
12860
13626
|
};
|
|
12861
13627
|
}
|
|
12862
13628
|
function relationSourceFile(relation, symbols, filePaths) {
|
|
13629
|
+
if (relation.file !== undefined)
|
|
13630
|
+
return filePaths.has(relation.file) ? relation.file : null;
|
|
12863
13631
|
if (filePaths.has(relation.from))
|
|
12864
13632
|
return relation.from;
|
|
12865
13633
|
const candidates = symbols.filter((symbol) => symbol.name === relation.from);
|
|
@@ -12941,6 +13709,10 @@ function extractionResultToEvidenceAdapterResult(extraction, invocation) {
|
|
|
12941
13709
|
}
|
|
12942
13710
|
const facts = [];
|
|
12943
13711
|
if (coverageFile.disposition === "analyzed" && fileInfo) {
|
|
13712
|
+
const source = invocation.source_files?.[normalizedPath2];
|
|
13713
|
+
if (invocation.source_files !== undefined && source === undefined) {
|
|
13714
|
+
throw new TypeError(`Analyzed file ${normalizedPath2} has no scoped source text`);
|
|
13715
|
+
}
|
|
12944
13716
|
facts.push(fact2({
|
|
12945
13717
|
sourceRef: invocation.authorized_scope.source_ref,
|
|
12946
13718
|
moduleRef: invocation.module_ref,
|
|
@@ -12948,7 +13720,11 @@ function extractionResultToEvidenceAdapterResult(extraction, invocation) {
|
|
|
12948
13720
|
qualifiedItemPath: "file",
|
|
12949
13721
|
kind: "source-file",
|
|
12950
13722
|
signature: { path: normalizedPath2, language: fileInfo.language },
|
|
12951
|
-
payload: fileInfo
|
|
13723
|
+
payload: source === undefined ? fileInfo : {
|
|
13724
|
+
...fileInfo,
|
|
13725
|
+
line: 1,
|
|
13726
|
+
endLine: source.split(/\r\n|\r|\n/u).length
|
|
13727
|
+
},
|
|
12952
13728
|
denominator: ownsDenominators ? "eligible-file" : "none"
|
|
12953
13729
|
}));
|
|
12954
13730
|
facts.push(fact2({
|
|
@@ -13692,27 +14468,27 @@ var parseFile = async (source, isTsx) => {
|
|
|
13692
14468
|
}
|
|
13693
14469
|
};
|
|
13694
14470
|
// src/commonJsModule.ts
|
|
13695
|
-
import
|
|
14471
|
+
import ts7 from "typescript";
|
|
13696
14472
|
|
|
13697
14473
|
// src/typescriptAst.ts
|
|
13698
|
-
import
|
|
14474
|
+
import ts6 from "typescript";
|
|
13699
14475
|
var scriptKind = (filePath) => {
|
|
13700
14476
|
const lower = filePath.toLowerCase();
|
|
13701
14477
|
if (lower.endsWith(".tsx"))
|
|
13702
|
-
return
|
|
14478
|
+
return ts6.ScriptKind.TSX;
|
|
13703
14479
|
if (lower.endsWith(".jsx"))
|
|
13704
|
-
return
|
|
14480
|
+
return ts6.ScriptKind.JSX;
|
|
13705
14481
|
if (lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".cjs")) {
|
|
13706
|
-
return
|
|
14482
|
+
return ts6.ScriptKind.JS;
|
|
13707
14483
|
}
|
|
13708
|
-
return
|
|
14484
|
+
return ts6.ScriptKind.TS;
|
|
13709
14485
|
};
|
|
13710
|
-
var createEcmaScriptSourceFile = (source, filePath) =>
|
|
14486
|
+
var createEcmaScriptSourceFile = (source, filePath) => ts6.createSourceFile(filePath, source, ts6.ScriptTarget.Latest, true, scriptKind(filePath));
|
|
13711
14487
|
var treeSitterCompatibleJsxSource = (sourceFile, source) => {
|
|
13712
14488
|
const characters = source.split("");
|
|
13713
14489
|
let changed = false;
|
|
13714
14490
|
const visit2 = (node2) => {
|
|
13715
|
-
const jsxPresentationLiteral =
|
|
14491
|
+
const jsxPresentationLiteral = ts6.isJsxText(node2) || ts6.isStringLiteral(node2) && ts6.isJsxAttribute(node2.parent);
|
|
13716
14492
|
if (jsxPresentationLiteral) {
|
|
13717
14493
|
for (let index = node2.getStart(sourceFile);index < node2.getEnd(); index += 1) {
|
|
13718
14494
|
if (characters[index] === "&") {
|
|
@@ -13721,7 +14497,7 @@ var treeSitterCompatibleJsxSource = (sourceFile, source) => {
|
|
|
13721
14497
|
}
|
|
13722
14498
|
}
|
|
13723
14499
|
}
|
|
13724
|
-
|
|
14500
|
+
ts6.forEachChild(node2, visit2);
|
|
13725
14501
|
};
|
|
13726
14502
|
visit2(sourceFile);
|
|
13727
14503
|
return changed ? characters.join("") : source;
|
|
@@ -13752,25 +14528,25 @@ var nodeLocation = (sourceFile, node2) => {
|
|
|
13752
14528
|
var staticStringValue = (node2) => {
|
|
13753
14529
|
if (!node2)
|
|
13754
14530
|
return null;
|
|
13755
|
-
if (
|
|
14531
|
+
if (ts6.isStringLiteral(node2) || ts6.isNoSubstitutionTemplateLiteral(node2))
|
|
13756
14532
|
return node2.text;
|
|
13757
14533
|
return null;
|
|
13758
14534
|
};
|
|
13759
14535
|
|
|
13760
14536
|
// src/commonJsModule.ts
|
|
13761
|
-
var requireCall = (node2) =>
|
|
14537
|
+
var requireCall = (node2) => ts7.isCallExpression(node2) && ts7.isIdentifier(node2.expression) && node2.expression.text === "require" ? node2 : null;
|
|
13762
14538
|
var requireReference = (node2) => {
|
|
13763
14539
|
const direct = requireCall(node2);
|
|
13764
14540
|
if (direct) {
|
|
13765
14541
|
const source = staticStringValue(direct.arguments[0]);
|
|
13766
14542
|
return source ? { source, importedName: "*" } : null;
|
|
13767
14543
|
}
|
|
13768
|
-
if (
|
|
14544
|
+
if (ts7.isPropertyAccessExpression(node2)) {
|
|
13769
14545
|
const call = requireCall(node2.expression);
|
|
13770
14546
|
const source = call ? staticStringValue(call.arguments[0]) : null;
|
|
13771
14547
|
return source ? { source, importedName: node2.name.text } : null;
|
|
13772
14548
|
}
|
|
13773
|
-
if (
|
|
14549
|
+
if (ts7.isElementAccessExpression(node2)) {
|
|
13774
14550
|
const call = requireCall(node2.expression);
|
|
13775
14551
|
const source = call ? staticStringValue(call.arguments[0]) : null;
|
|
13776
14552
|
const importedName = staticStringValue(node2.argumentExpression);
|
|
@@ -13779,20 +14555,20 @@ var requireReference = (node2) => {
|
|
|
13779
14555
|
return null;
|
|
13780
14556
|
};
|
|
13781
14557
|
var isModuleExports = (node2) => {
|
|
13782
|
-
if (
|
|
14558
|
+
if (ts7.isPropertyAccessExpression(node2) && ts7.isIdentifier(node2.expression) && node2.expression.text === "module" && node2.name.text === "exports")
|
|
13783
14559
|
return true;
|
|
13784
|
-
return
|
|
14560
|
+
return ts7.isElementAccessExpression(node2) && ts7.isIdentifier(node2.expression) && node2.expression.text === "module" && staticStringValue(node2.argumentExpression) === "exports";
|
|
13785
14561
|
};
|
|
13786
|
-
var isExportsObject = (node2) =>
|
|
14562
|
+
var isExportsObject = (node2) => ts7.isIdentifier(node2) && node2.text === "exports" || isModuleExports(node2);
|
|
13787
14563
|
var isUnsupportedExportMutationCall = (node2) => {
|
|
13788
|
-
if (
|
|
14564
|
+
if (ts7.isPropertyAccessExpression(node2.expression) && ts7.isIdentifier(node2.expression.expression) && node2.expression.expression.text === "Object" && ["assign", "defineProperties", "defineProperty"].includes(node2.expression.name.text) && node2.arguments[0] && isExportsObject(node2.arguments[0])) {
|
|
13789
14565
|
return !(node2.expression.name.text === "defineProperty" && staticStringValue(node2.arguments[1]) === "__esModule");
|
|
13790
14566
|
}
|
|
13791
|
-
return
|
|
14567
|
+
return ts7.isIdentifier(node2.expression) && ["__createBinding", "__export", "__exportStar"].includes(node2.expression.text) && node2.arguments.some(isExportsObject);
|
|
13792
14568
|
};
|
|
13793
14569
|
var commonJsExportTarget = (node2) => {
|
|
13794
|
-
if (
|
|
13795
|
-
if (
|
|
14570
|
+
if (ts7.isPropertyAccessExpression(node2)) {
|
|
14571
|
+
if (ts7.isIdentifier(node2.expression) && node2.expression.text === "exports") {
|
|
13796
14572
|
return { kind: "named", exportedName: node2.name.text };
|
|
13797
14573
|
}
|
|
13798
14574
|
if (isModuleExports(node2.expression)) {
|
|
@@ -13801,9 +14577,9 @@ var commonJsExportTarget = (node2) => {
|
|
|
13801
14577
|
if (isModuleExports(node2))
|
|
13802
14578
|
return { kind: "whole" };
|
|
13803
14579
|
}
|
|
13804
|
-
if (
|
|
14580
|
+
if (ts7.isElementAccessExpression(node2)) {
|
|
13805
14581
|
const property = staticStringValue(node2.argumentExpression);
|
|
13806
|
-
if (
|
|
14582
|
+
if (ts7.isIdentifier(node2.expression) && node2.expression.text === "exports" && property) {
|
|
13807
14583
|
return { kind: "named", exportedName: property };
|
|
13808
14584
|
}
|
|
13809
14585
|
if (isModuleExports(node2.expression) && property) {
|
|
@@ -13815,7 +14591,7 @@ var commonJsExportTarget = (node2) => {
|
|
|
13815
14591
|
return null;
|
|
13816
14592
|
};
|
|
13817
14593
|
var localReference = (expression, bindings) => {
|
|
13818
|
-
if (
|
|
14594
|
+
if (ts7.isIdentifier(expression)) {
|
|
13819
14595
|
const binding = bindings.get(expression.text);
|
|
13820
14596
|
if (binding) {
|
|
13821
14597
|
return {
|
|
@@ -13825,7 +14601,7 @@ var localReference = (expression, bindings) => {
|
|
|
13825
14601
|
}
|
|
13826
14602
|
return { localName: expression.text };
|
|
13827
14603
|
}
|
|
13828
|
-
if (
|
|
14604
|
+
if (ts7.isPropertyAccessExpression(expression) && ts7.isIdentifier(expression.expression)) {
|
|
13829
14605
|
const binding = bindings.get(expression.expression.text);
|
|
13830
14606
|
if (binding)
|
|
13831
14607
|
return { source: binding.source, importedName: expression.name.text };
|
|
@@ -13835,7 +14611,7 @@ var localReference = (expression, bindings) => {
|
|
|
13835
14611
|
};
|
|
13836
14612
|
var syntheticDeclaration = (name, expression, sourceFile) => {
|
|
13837
14613
|
const location = nodeLocation(sourceFile, expression);
|
|
13838
|
-
if (
|
|
14614
|
+
if (ts7.isFunctionExpression(expression) || ts7.isArrowFunction(expression)) {
|
|
13839
14615
|
return {
|
|
13840
14616
|
name,
|
|
13841
14617
|
kind: "function",
|
|
@@ -13844,10 +14620,10 @@ var syntheticDeclaration = (name, expression, sourceFile) => {
|
|
|
13844
14620
|
params: expression.parameters.map((parameter) => parameter.name.getText(sourceFile))
|
|
13845
14621
|
};
|
|
13846
14622
|
}
|
|
13847
|
-
if (
|
|
14623
|
+
if (ts7.isClassExpression(expression)) {
|
|
13848
14624
|
return { name, kind: "class", line: location.line, endLine: location.endLine, params: [] };
|
|
13849
14625
|
}
|
|
13850
|
-
if (
|
|
14626
|
+
if (ts7.isObjectLiteralExpression(expression) || ts7.isArrayLiteralExpression(expression) || ts7.isLiteralExpression(expression)) {
|
|
13851
14627
|
return { name, kind: "variable", line: location.line, endLine: location.endLine, params: [] };
|
|
13852
14628
|
}
|
|
13853
14629
|
return null;
|
|
@@ -13881,430 +14657,192 @@ var appendUnsupportedExportDiagnostic = (result, sourceFile, node2) => {
|
|
|
13881
14657
|
var collectBindings = (sourceFile) => {
|
|
13882
14658
|
const bindings = [];
|
|
13883
14659
|
for (const statement of sourceFile.statements) {
|
|
13884
|
-
if (!
|
|
14660
|
+
if (!ts7.isVariableStatement(statement))
|
|
13885
14661
|
continue;
|
|
13886
14662
|
for (const declaration of statement.declarationList.declarations) {
|
|
13887
14663
|
if (!declaration.initializer)
|
|
13888
14664
|
continue;
|
|
13889
14665
|
const line = nodeLocation(sourceFile, declaration).line;
|
|
13890
|
-
if (
|
|
14666
|
+
if (ts7.isIdentifier(declaration.name)) {
|
|
13891
14667
|
const reference = requireReference(declaration.initializer);
|
|
13892
14668
|
if (reference)
|
|
13893
14669
|
bindings.push({ localName: declaration.name.text, ...reference, line });
|
|
13894
14670
|
continue;
|
|
13895
14671
|
}
|
|
13896
|
-
const direct = requireCall(declaration.initializer);
|
|
13897
|
-
const source = direct ? staticStringValue(direct.arguments[0]) : null;
|
|
13898
|
-
if (!source || !
|
|
13899
|
-
continue;
|
|
13900
|
-
for (const element of declaration.name.elements) {
|
|
13901
|
-
if (!ts2.isIdentifier(element.name))
|
|
13902
|
-
continue;
|
|
13903
|
-
const importedName = element.propertyName?.getText(sourceFile) ?? element.name.text;
|
|
13904
|
-
bindings.push({ localName: element.name.text, source, importedName, line });
|
|
13905
|
-
}
|
|
13906
|
-
}
|
|
13907
|
-
}
|
|
13908
|
-
return bindings;
|
|
13909
|
-
};
|
|
13910
|
-
var collectDynamicDiagnostics = (sourceFile) => {
|
|
13911
|
-
const diagnostics = [];
|
|
13912
|
-
const visit2 = (node2) => {
|
|
13913
|
-
if (ts2.isCallExpression(node2) && ts2.isIdentifier(node2.expression) && node2.expression.text === "require") {
|
|
13914
|
-
if (staticStringValue(node2.arguments[0]) === null) {
|
|
13915
|
-
const location = nodeLocation(sourceFile, node2);
|
|
13916
|
-
diagnostics.push({
|
|
13917
|
-
code: "dynamic-commonjs-require",
|
|
13918
|
-
severity: "error",
|
|
13919
|
-
file: sourceFile.fileName,
|
|
13920
|
-
line: location.line,
|
|
13921
|
-
column: location.column
|
|
13922
|
-
});
|
|
13923
|
-
}
|
|
13924
|
-
}
|
|
13925
|
-
if (ts2.isCallExpression(node2) && isUnsupportedExportMutationCall(node2)) {
|
|
13926
|
-
const location = nodeLocation(sourceFile, node2);
|
|
13927
|
-
diagnostics.push({
|
|
13928
|
-
code: "unsupported-commonjs-export-form",
|
|
13929
|
-
severity: "error",
|
|
13930
|
-
file: sourceFile.fileName,
|
|
13931
|
-
line: location.line,
|
|
13932
|
-
column: location.column
|
|
13933
|
-
});
|
|
13934
|
-
}
|
|
13935
|
-
if (ts2.isBinaryExpression(node2) && node2.operatorToken.kind === ts2.SyntaxKind.EqualsToken) {
|
|
13936
|
-
if (ts2.isElementAccessExpression(node2.left)) {
|
|
13937
|
-
const isCommonJsTarget = ts2.isIdentifier(node2.left.expression) && node2.left.expression.text === "exports" || isModuleExports(node2.left.expression) || isModuleExports(node2.left);
|
|
13938
|
-
if (isCommonJsTarget && commonJsExportTarget(node2.left) === null) {
|
|
13939
|
-
const location = nodeLocation(sourceFile, node2.left);
|
|
13940
|
-
diagnostics.push({
|
|
13941
|
-
code: "dynamic-commonjs-export",
|
|
13942
|
-
severity: "error",
|
|
13943
|
-
file: sourceFile.fileName,
|
|
13944
|
-
line: location.line,
|
|
13945
|
-
column: location.column
|
|
13946
|
-
});
|
|
13947
|
-
}
|
|
13948
|
-
}
|
|
13949
|
-
}
|
|
13950
|
-
ts2.forEachChild(node2, visit2);
|
|
13951
|
-
};
|
|
13952
|
-
visit2(sourceFile);
|
|
13953
|
-
return diagnostics;
|
|
13954
|
-
};
|
|
13955
|
-
var analyzeCommonJsModule = (source, filePath) => {
|
|
13956
|
-
const sourceFile = createEcmaScriptSourceFile(source, filePath);
|
|
13957
|
-
const bindings = collectBindings(sourceFile);
|
|
13958
|
-
const bindingMap = new Map(bindings.map((binding) => [binding.localName, binding]));
|
|
13959
|
-
const result = {
|
|
13960
|
-
bindings,
|
|
13961
|
-
exports: [],
|
|
13962
|
-
wildcardSources: [],
|
|
13963
|
-
syntheticDeclarations: [],
|
|
13964
|
-
diagnostics: collectDynamicDiagnostics(sourceFile)
|
|
13965
|
-
};
|
|
13966
|
-
for (const statement of sourceFile.statements) {
|
|
13967
|
-
if (!ts2.isExpressionStatement(statement) || !ts2.isBinaryExpression(statement.expression))
|
|
13968
|
-
continue;
|
|
13969
|
-
const assignment = statement.expression;
|
|
13970
|
-
if (assignment.operatorToken.kind !== ts2.SyntaxKind.EqualsToken)
|
|
13971
|
-
continue;
|
|
13972
|
-
const target = commonJsExportTarget(assignment.left);
|
|
13973
|
-
if (!target)
|
|
13974
|
-
continue;
|
|
13975
|
-
const line = nodeLocation(sourceFile, assignment).line;
|
|
13976
|
-
if (target.kind === "named") {
|
|
13977
|
-
if (!pushExport(result, target.exportedName, assignment.right, line, bindingMap, sourceFile)) {
|
|
13978
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
13979
|
-
}
|
|
13980
|
-
continue;
|
|
13981
|
-
}
|
|
13982
|
-
const directRequire = requireReference(assignment.right);
|
|
13983
|
-
if (directRequire?.importedName === "*") {
|
|
13984
|
-
result.wildcardSources.push(directRequire.source);
|
|
13985
|
-
continue;
|
|
13986
|
-
}
|
|
13987
|
-
if (ts2.isObjectLiteralExpression(assignment.right)) {
|
|
13988
|
-
for (const property of assignment.right.properties) {
|
|
13989
|
-
if (ts2.isShorthandPropertyAssignment(property)) {
|
|
13990
|
-
pushExport(result, property.name.text, property.name, line, bindingMap, sourceFile);
|
|
13991
|
-
continue;
|
|
13992
|
-
}
|
|
13993
|
-
if (ts2.isPropertyAssignment(property)) {
|
|
13994
|
-
const name = property.name && (ts2.isIdentifier(property.name) || ts2.isStringLiteral(property.name)) ? property.name.text : null;
|
|
13995
|
-
if (name) {
|
|
13996
|
-
if (!pushExport(result, name, property.initializer, line, bindingMap, sourceFile)) {
|
|
13997
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, property.initializer);
|
|
13998
|
-
}
|
|
13999
|
-
} else {
|
|
14000
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, property);
|
|
14001
|
-
}
|
|
14002
|
-
continue;
|
|
14003
|
-
}
|
|
14004
|
-
if (ts2.isMethodDeclaration(property) && property.name && ts2.isIdentifier(property.name)) {
|
|
14005
|
-
const location = nodeLocation(sourceFile, property);
|
|
14006
|
-
result.syntheticDeclarations.push({
|
|
14007
|
-
name: property.name.text,
|
|
14008
|
-
kind: "function",
|
|
14009
|
-
line: location.line,
|
|
14010
|
-
endLine: location.endLine,
|
|
14011
|
-
params: property.parameters.map((parameter) => parameter.name.getText(sourceFile))
|
|
14012
|
-
});
|
|
14013
|
-
result.exports.push({
|
|
14014
|
-
exportedName: property.name.text,
|
|
14015
|
-
localName: property.name.text,
|
|
14016
|
-
line
|
|
14017
|
-
});
|
|
14018
|
-
continue;
|
|
14019
|
-
}
|
|
14020
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, property);
|
|
14021
|
-
}
|
|
14022
|
-
continue;
|
|
14023
|
-
}
|
|
14024
|
-
if (ts2.isIdentifier(assignment.right)) {
|
|
14025
|
-
const binding = bindingMap.get(assignment.right.text);
|
|
14026
|
-
if (binding?.importedName === "*") {
|
|
14027
|
-
result.wildcardSources.push(binding.source);
|
|
14028
|
-
continue;
|
|
14029
|
-
}
|
|
14030
|
-
if (!pushExport(result, assignment.right.text, assignment.right, line, bindingMap, sourceFile)) {
|
|
14031
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
14032
|
-
}
|
|
14033
|
-
continue;
|
|
14034
|
-
}
|
|
14035
|
-
if (!pushExport(result, "default", assignment.right, line, bindingMap, sourceFile)) {
|
|
14036
|
-
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
14037
|
-
}
|
|
14038
|
-
}
|
|
14039
|
-
result.bindings.sort((left, right) => left.localName.localeCompare(right.localName));
|
|
14040
|
-
result.exports.sort((left, right) => left.exportedName.localeCompare(right.exportedName) || left.line - right.line);
|
|
14041
|
-
result.wildcardSources = [...new Set(result.wildcardSources)].sort();
|
|
14042
|
-
result.syntheticDeclarations.sort((left, right) => left.name.localeCompare(right.name));
|
|
14043
|
-
result.diagnostics.sort((left, right) => left.line - right.line || left.column - right.column);
|
|
14044
|
-
return result;
|
|
14045
|
-
};
|
|
14046
|
-
|
|
14047
|
-
// src/commonJsExportTrace.ts
|
|
14048
|
-
var traceCommonJsExports = async (input) => {
|
|
14049
|
-
const traced = [];
|
|
14050
|
-
for (const item of input.analysis.exports) {
|
|
14051
|
-
if (item.localName && input.localDeclarations.has(item.localName)) {
|
|
14052
|
-
traced.push({
|
|
14053
|
-
exportedName: item.exportedName,
|
|
14054
|
-
localName: item.localName,
|
|
14055
|
-
declarationFile: input.filePath
|
|
14056
|
-
});
|
|
14057
|
-
continue;
|
|
14058
|
-
}
|
|
14059
|
-
if (item.source && item.importedName) {
|
|
14060
|
-
traced.push(...await input.traceImported(item.source, item.importedName, item.exportedName));
|
|
14061
|
-
}
|
|
14062
|
-
}
|
|
14063
|
-
for (const source of input.analysis.wildcardSources) {
|
|
14064
|
-
traced.push(...await input.traceWildcard(source));
|
|
14065
|
-
}
|
|
14066
|
-
return traced;
|
|
14067
|
-
};
|
|
14068
|
-
|
|
14069
|
-
// src/exportTracer.ts
|
|
14070
|
-
var DECLARATION_TYPES = new Set([
|
|
14071
|
-
"function_declaration",
|
|
14072
|
-
"class_declaration",
|
|
14073
|
-
"interface_declaration",
|
|
14074
|
-
"type_alias_declaration",
|
|
14075
|
-
"enum_declaration",
|
|
14076
|
-
"lexical_declaration"
|
|
14077
|
-
]);
|
|
14078
|
-
var stripQuotes = (value) => value.replace(/^['"]/, "").replace(/['"]$/, "");
|
|
14079
|
-
var getDeclarationName = (node2) => {
|
|
14080
|
-
if (node2.type === "lexical_declaration") {
|
|
14081
|
-
return node2.namedChildren.filter((child) => child.type === "variable_declarator").map((child) => child.childForFieldName("name")?.text ?? child.namedChildren[0]?.text ?? "").filter(Boolean);
|
|
14082
|
-
}
|
|
14083
|
-
const nameNode = node2.childForFieldName("name") ?? node2.namedChildren.find((child) => child.type === "identifier" || child.type === "type_identifier");
|
|
14084
|
-
return nameNode?.text ? [nameNode.text] : [];
|
|
14085
|
-
};
|
|
14086
|
-
var collectLocalDeclarations = (root) => {
|
|
14087
|
-
const declarations = new Map;
|
|
14088
|
-
const register = (node2) => {
|
|
14089
|
-
for (const name of getDeclarationName(node2)) {
|
|
14090
|
-
if (!declarations.has(name)) {
|
|
14091
|
-
declarations.set(name, name);
|
|
14092
|
-
}
|
|
14093
|
-
}
|
|
14094
|
-
};
|
|
14095
|
-
for (const child of root.namedChildren) {
|
|
14096
|
-
if (DECLARATION_TYPES.has(child.type)) {
|
|
14097
|
-
register(child);
|
|
14098
|
-
continue;
|
|
14099
|
-
}
|
|
14100
|
-
if (child.type !== "export_statement")
|
|
14101
|
-
continue;
|
|
14102
|
-
const declaration = child.namedChildren.find((node2) => DECLARATION_TYPES.has(node2.type));
|
|
14103
|
-
if (declaration) {
|
|
14104
|
-
register(declaration);
|
|
14105
|
-
}
|
|
14106
|
-
}
|
|
14107
|
-
return declarations;
|
|
14108
|
-
};
|
|
14109
|
-
var parseExportSpecifier = (node2) => {
|
|
14110
|
-
const identifiers = node2.namedChildren.filter((child) => child.type === "identifier" || child.type === "type_identifier").map((child) => child.text);
|
|
14111
|
-
if (identifiers.length === 0)
|
|
14112
|
-
return null;
|
|
14113
|
-
const localName = identifiers[0];
|
|
14114
|
-
const exportedName = identifiers[1] ?? localName;
|
|
14115
|
-
return { localName, exportedName };
|
|
14116
|
-
};
|
|
14117
|
-
var parseImportSpecifier = (node2) => {
|
|
14118
|
-
const identifiers = node2.namedChildren.filter((child) => child.type === "identifier" || child.type === "type_identifier").map((child) => child.text);
|
|
14119
|
-
if (identifiers.length === 0)
|
|
14120
|
-
return null;
|
|
14121
|
-
const importedName = identifiers[0];
|
|
14122
|
-
const localName = identifiers[1] ?? importedName;
|
|
14123
|
-
return { importedName, localName };
|
|
14124
|
-
};
|
|
14125
|
-
var collectImportBindings = (root) => {
|
|
14126
|
-
const bindings = new Map;
|
|
14127
|
-
for (const node2 of root.namedChildren) {
|
|
14128
|
-
if (node2.type !== "import_statement")
|
|
14129
|
-
continue;
|
|
14130
|
-
const stringNode = node2.namedChildren.find((child) => child.type === "string");
|
|
14131
|
-
if (!stringNode)
|
|
14132
|
-
continue;
|
|
14133
|
-
const source = stripQuotes(stringNode.text);
|
|
14134
|
-
const clause = node2.namedChildren.find((child) => child.type === "import_clause");
|
|
14135
|
-
for (const part of clause?.namedChildren ?? []) {
|
|
14136
|
-
if (part.type === "identifier") {
|
|
14137
|
-
bindings.set(part.text, { source, importedName: "default" });
|
|
14138
|
-
continue;
|
|
14139
|
-
}
|
|
14140
|
-
if (part.type !== "named_imports")
|
|
14672
|
+
const direct = requireCall(declaration.initializer);
|
|
14673
|
+
const source = direct ? staticStringValue(direct.arguments[0]) : null;
|
|
14674
|
+
if (!source || !ts7.isObjectBindingPattern(declaration.name))
|
|
14141
14675
|
continue;
|
|
14142
|
-
for (const
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
}
|
|
14676
|
+
for (const element of declaration.name.elements) {
|
|
14677
|
+
if (!ts7.isIdentifier(element.name))
|
|
14678
|
+
continue;
|
|
14679
|
+
const importedName = element.propertyName?.getText(sourceFile) ?? element.name.text;
|
|
14680
|
+
bindings.push({ localName: element.name.text, source, importedName, line });
|
|
14147
14681
|
}
|
|
14148
14682
|
}
|
|
14149
14683
|
}
|
|
14150
14684
|
return bindings;
|
|
14151
14685
|
};
|
|
14152
|
-
var
|
|
14153
|
-
const
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
const traced = await traceFile(targetPath, fs, state);
|
|
14167
|
-
const match = traced.find((item) => item.exportedName === binding.importedName || binding.importedName === "default" && item.exportedName === item.localName);
|
|
14168
|
-
if (!match)
|
|
14169
|
-
return [];
|
|
14170
|
-
return [{
|
|
14171
|
-
exportedName,
|
|
14172
|
-
localName: match.localName,
|
|
14173
|
-
declarationFile: match.declarationFile
|
|
14174
|
-
}];
|
|
14175
|
-
};
|
|
14176
|
-
var traceFile = async (filePath, fs, state) => {
|
|
14177
|
-
const cached = state.cache.get(filePath);
|
|
14178
|
-
if (cached)
|
|
14179
|
-
return cached;
|
|
14180
|
-
if (state.inFlight.has(filePath))
|
|
14181
|
-
return [];
|
|
14182
|
-
const promise = (async () => {
|
|
14183
|
-
state.inFlight.add(filePath);
|
|
14184
|
-
state.files.add(filePath);
|
|
14185
|
-
const source = await fs.readFile(filePath);
|
|
14186
|
-
const commonJs = analyzeCommonJsModule(source, filePath);
|
|
14187
|
-
if (commonJs.diagnostics.length > 0)
|
|
14188
|
-
return [];
|
|
14189
|
-
const jsxLike = isJsxLikePath(filePath);
|
|
14190
|
-
const parserSource = jsxLike ? treeSitterCompatibleJsxSource(createEcmaScriptSourceFile(source, filePath), source) : source;
|
|
14191
|
-
const tree = await parseFile(parserSource, jsxLike);
|
|
14192
|
-
if (!tree)
|
|
14193
|
-
return [];
|
|
14194
|
-
const root = tree.rootNode;
|
|
14195
|
-
const localDeclarations = collectLocalDeclarations(root);
|
|
14196
|
-
const importBindings = collectImportBindings(root);
|
|
14197
|
-
for (const declaration of commonJs.syntheticDeclarations) {
|
|
14198
|
-
localDeclarations.set(declaration.name, declaration.name);
|
|
14686
|
+
var collectDynamicDiagnostics = (sourceFile) => {
|
|
14687
|
+
const diagnostics = [];
|
|
14688
|
+
const visit2 = (node2) => {
|
|
14689
|
+
if (ts7.isCallExpression(node2) && ts7.isIdentifier(node2.expression) && node2.expression.text === "require") {
|
|
14690
|
+
if (staticStringValue(node2.arguments[0]) === null) {
|
|
14691
|
+
const location = nodeLocation(sourceFile, node2);
|
|
14692
|
+
diagnostics.push({
|
|
14693
|
+
code: "dynamic-commonjs-require",
|
|
14694
|
+
severity: "error",
|
|
14695
|
+
file: sourceFile.fileName,
|
|
14696
|
+
line: location.line,
|
|
14697
|
+
column: location.column
|
|
14698
|
+
});
|
|
14699
|
+
}
|
|
14199
14700
|
}
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14701
|
+
if (ts7.isCallExpression(node2) && isUnsupportedExportMutationCall(node2)) {
|
|
14702
|
+
const location = nodeLocation(sourceFile, node2);
|
|
14703
|
+
diagnostics.push({
|
|
14704
|
+
code: "unsupported-commonjs-export-form",
|
|
14705
|
+
severity: "error",
|
|
14706
|
+
file: sourceFile.fileName,
|
|
14707
|
+
line: location.line,
|
|
14708
|
+
column: location.column
|
|
14204
14709
|
});
|
|
14205
14710
|
}
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
continue;
|
|
14218
|
-
}
|
|
14219
|
-
if (node2.text.startsWith("export default ")) {
|
|
14220
|
-
const identifier = node2.namedChildren.find((child) => child.type === "identifier" || child.type === "type_identifier");
|
|
14221
|
-
if (identifier && localDeclarations.has(identifier.text)) {
|
|
14222
|
-
exportsList.push({
|
|
14223
|
-
exportedName: identifier.text,
|
|
14224
|
-
localName: identifier.text,
|
|
14225
|
-
declarationFile: filePath
|
|
14711
|
+
if (ts7.isBinaryExpression(node2) && node2.operatorToken.kind === ts7.SyntaxKind.EqualsToken) {
|
|
14712
|
+
if (ts7.isElementAccessExpression(node2.left)) {
|
|
14713
|
+
const isCommonJsTarget = ts7.isIdentifier(node2.left.expression) && node2.left.expression.text === "exports" || isModuleExports(node2.left.expression) || isModuleExports(node2.left);
|
|
14714
|
+
if (isCommonJsTarget && commonJsExportTarget(node2.left) === null) {
|
|
14715
|
+
const location = nodeLocation(sourceFile, node2.left);
|
|
14716
|
+
diagnostics.push({
|
|
14717
|
+
code: "dynamic-commonjs-export",
|
|
14718
|
+
severity: "error",
|
|
14719
|
+
file: sourceFile.fileName,
|
|
14720
|
+
line: location.line,
|
|
14721
|
+
column: location.column
|
|
14226
14722
|
});
|
|
14227
14723
|
}
|
|
14228
|
-
continue;
|
|
14229
14724
|
}
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14725
|
+
}
|
|
14726
|
+
ts7.forEachChild(node2, visit2);
|
|
14727
|
+
};
|
|
14728
|
+
visit2(sourceFile);
|
|
14729
|
+
return diagnostics;
|
|
14730
|
+
};
|
|
14731
|
+
var analyzeCommonJsModule = (source, filePath) => {
|
|
14732
|
+
const sourceFile = createEcmaScriptSourceFile(source, filePath);
|
|
14733
|
+
const bindings = collectBindings(sourceFile);
|
|
14734
|
+
const bindingMap = new Map(bindings.map((binding) => [binding.localName, binding]));
|
|
14735
|
+
const result = {
|
|
14736
|
+
bindings,
|
|
14737
|
+
exports: [],
|
|
14738
|
+
wildcardSources: [],
|
|
14739
|
+
syntheticDeclarations: [],
|
|
14740
|
+
diagnostics: collectDynamicDiagnostics(sourceFile)
|
|
14741
|
+
};
|
|
14742
|
+
for (const statement of sourceFile.statements) {
|
|
14743
|
+
if (!ts7.isExpressionStatement(statement) || !ts7.isBinaryExpression(statement.expression))
|
|
14744
|
+
continue;
|
|
14745
|
+
const assignment = statement.expression;
|
|
14746
|
+
if (assignment.operatorToken.kind !== ts7.SyntaxKind.EqualsToken)
|
|
14747
|
+
continue;
|
|
14748
|
+
const target = commonJsExportTarget(assignment.left);
|
|
14749
|
+
if (!target)
|
|
14750
|
+
continue;
|
|
14751
|
+
const line = nodeLocation(sourceFile, assignment).line;
|
|
14752
|
+
if (target.kind === "named") {
|
|
14753
|
+
if (!pushExport(result, target.exportedName, assignment.right, line, bindingMap, sourceFile)) {
|
|
14754
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
14238
14755
|
}
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
}
|
|
14252
|
-
const importBinding = importBindings.get(parsed.localName);
|
|
14253
|
-
if (importBinding) {
|
|
14254
|
-
exportsList.push(...await traceImportedBinding(filePath, importBinding, parsed.exportedName, fs, state));
|
|
14255
|
-
}
|
|
14756
|
+
continue;
|
|
14757
|
+
}
|
|
14758
|
+
const directRequire = requireReference(assignment.right);
|
|
14759
|
+
if (directRequire?.importedName === "*") {
|
|
14760
|
+
result.wildcardSources.push(directRequire.source);
|
|
14761
|
+
continue;
|
|
14762
|
+
}
|
|
14763
|
+
if (ts7.isObjectLiteralExpression(assignment.right)) {
|
|
14764
|
+
for (const property of assignment.right.properties) {
|
|
14765
|
+
if (ts7.isShorthandPropertyAssignment(property)) {
|
|
14766
|
+
pushExport(result, property.name.text, property.name, line, bindingMap, sourceFile);
|
|
14767
|
+
continue;
|
|
14256
14768
|
}
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
|
|
14769
|
+
if (ts7.isPropertyAssignment(property)) {
|
|
14770
|
+
const name = property.name && (ts7.isIdentifier(property.name) || ts7.isStringLiteral(property.name)) ? property.name.text : null;
|
|
14771
|
+
if (name) {
|
|
14772
|
+
if (!pushExport(result, name, property.initializer, line, bindingMap, sourceFile)) {
|
|
14773
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, property.initializer);
|
|
14774
|
+
}
|
|
14775
|
+
} else {
|
|
14776
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, property);
|
|
14777
|
+
}
|
|
14266
14778
|
continue;
|
|
14267
|
-
|
|
14268
|
-
if (
|
|
14779
|
+
}
|
|
14780
|
+
if (ts7.isMethodDeclaration(property) && property.name && ts7.isIdentifier(property.name)) {
|
|
14781
|
+
const location = nodeLocation(sourceFile, property);
|
|
14782
|
+
result.syntheticDeclarations.push({
|
|
14783
|
+
name: property.name.text,
|
|
14784
|
+
kind: "function",
|
|
14785
|
+
line: location.line,
|
|
14786
|
+
endLine: location.endLine,
|
|
14787
|
+
params: property.parameters.map((parameter) => parameter.name.getText(sourceFile))
|
|
14788
|
+
});
|
|
14789
|
+
result.exports.push({
|
|
14790
|
+
exportedName: property.name.text,
|
|
14791
|
+
localName: property.name.text,
|
|
14792
|
+
line
|
|
14793
|
+
});
|
|
14269
14794
|
continue;
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
localName: match.localName,
|
|
14273
|
-
declarationFile: match.declarationFile
|
|
14274
|
-
});
|
|
14795
|
+
}
|
|
14796
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, property);
|
|
14275
14797
|
}
|
|
14798
|
+
continue;
|
|
14276
14799
|
}
|
|
14277
|
-
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
|
|
14281
|
-
|
|
14282
|
-
traceWildcard: async (source2) => {
|
|
14283
|
-
const targetPath = await resolveImportSourcePath(filePath, source2, fs, state.resolver);
|
|
14284
|
-
return targetPath ? traceFile(targetPath, fs, state) : [];
|
|
14800
|
+
if (ts7.isIdentifier(assignment.right)) {
|
|
14801
|
+
const binding = bindingMap.get(assignment.right.text);
|
|
14802
|
+
if (binding?.importedName === "*") {
|
|
14803
|
+
result.wildcardSources.push(binding.source);
|
|
14804
|
+
continue;
|
|
14285
14805
|
}
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
return {
|
|
14302
|
-
exports: uniqueExports(exportsList),
|
|
14303
|
-
files: [...state.files].sort()
|
|
14304
|
-
};
|
|
14806
|
+
if (!pushExport(result, assignment.right.text, assignment.right, line, bindingMap, sourceFile)) {
|
|
14807
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
14808
|
+
}
|
|
14809
|
+
continue;
|
|
14810
|
+
}
|
|
14811
|
+
if (!pushExport(result, "default", assignment.right, line, bindingMap, sourceFile)) {
|
|
14812
|
+
appendUnsupportedExportDiagnostic(result, sourceFile, assignment.right);
|
|
14813
|
+
}
|
|
14814
|
+
}
|
|
14815
|
+
result.bindings.sort((left, right) => left.localName.localeCompare(right.localName));
|
|
14816
|
+
result.exports.sort((left, right) => left.exportedName.localeCompare(right.exportedName) || left.line - right.line);
|
|
14817
|
+
result.wildcardSources = [...new Set(result.wildcardSources)].sort();
|
|
14818
|
+
result.syntheticDeclarations.sort((left, right) => left.name.localeCompare(right.name));
|
|
14819
|
+
result.diagnostics.sort((left, right) => left.line - right.line || left.column - right.column);
|
|
14820
|
+
return result;
|
|
14305
14821
|
};
|
|
14306
14822
|
|
|
14307
|
-
// src/
|
|
14823
|
+
// src/commonJsExportTrace.ts
|
|
14824
|
+
var traceCommonJsExports = async (input) => {
|
|
14825
|
+
const traced = [];
|
|
14826
|
+
for (const item of input.analysis.exports) {
|
|
14827
|
+
if (item.localName && input.localDeclarations.has(item.localName)) {
|
|
14828
|
+
traced.push({
|
|
14829
|
+
exportedName: item.exportedName,
|
|
14830
|
+
localName: item.localName,
|
|
14831
|
+
declarationFile: input.filePath
|
|
14832
|
+
});
|
|
14833
|
+
continue;
|
|
14834
|
+
}
|
|
14835
|
+
if (item.source && item.importedName) {
|
|
14836
|
+
traced.push(...await input.traceImported(item.source, item.importedName, item.exportedName));
|
|
14837
|
+
}
|
|
14838
|
+
}
|
|
14839
|
+
for (const source of input.analysis.wildcardSources) {
|
|
14840
|
+
traced.push(...await input.traceWildcard(source));
|
|
14841
|
+
}
|
|
14842
|
+
return traced;
|
|
14843
|
+
};
|
|
14844
|
+
|
|
14845
|
+
// src/exportTracer.ts
|
|
14308
14846
|
var DECLARATION_TYPES2 = new Set([
|
|
14309
14847
|
"function_declaration",
|
|
14310
14848
|
"class_declaration",
|
|
@@ -14313,296 +14851,243 @@ var DECLARATION_TYPES2 = new Set([
|
|
|
14313
14851
|
"enum_declaration",
|
|
14314
14852
|
"lexical_declaration"
|
|
14315
14853
|
]);
|
|
14316
|
-
var
|
|
14317
|
-
|
|
14318
|
-
"
|
|
14319
|
-
|
|
14320
|
-
"Error",
|
|
14321
|
-
"Map",
|
|
14322
|
-
"Number",
|
|
14323
|
-
"Object",
|
|
14324
|
-
"Promise",
|
|
14325
|
-
"ReadonlyArray",
|
|
14326
|
-
"Record",
|
|
14327
|
-
"Set",
|
|
14328
|
-
"String",
|
|
14329
|
-
"unknown",
|
|
14330
|
-
"void",
|
|
14331
|
-
"string",
|
|
14332
|
-
"number",
|
|
14333
|
-
"boolean",
|
|
14334
|
-
"null",
|
|
14335
|
-
"undefined",
|
|
14336
|
-
"never",
|
|
14337
|
-
"any"
|
|
14338
|
-
]);
|
|
14339
|
-
var countLines = (source) => {
|
|
14340
|
-
if (!source)
|
|
14341
|
-
return 0;
|
|
14342
|
-
return source.split(/\r\n|\r|\n/).filter((line) => line.trim().length > 0).length;
|
|
14343
|
-
};
|
|
14344
|
-
var createRelation = (type, from, to, isExternal, line) => ({
|
|
14345
|
-
type,
|
|
14346
|
-
from,
|
|
14347
|
-
to,
|
|
14348
|
-
isExternal,
|
|
14349
|
-
grounding: "code" /* Code */,
|
|
14350
|
-
confidence: 1,
|
|
14351
|
-
source: "ast" /* Ast */,
|
|
14352
|
-
...line ? { line } : {}
|
|
14353
|
-
});
|
|
14354
|
-
var getLine = (node2) => node2.startPosition.row + 1;
|
|
14355
|
-
var getEndLine = (node2) => node2.endPosition.row + 1;
|
|
14356
|
-
var extractJSDoc = (node2) => {
|
|
14357
|
-
const prev = node2.previousNamedSibling ?? node2.parent?.previousNamedSibling;
|
|
14358
|
-
if (!prev || prev.type !== "comment")
|
|
14359
|
-
return;
|
|
14360
|
-
const text = prev.text;
|
|
14361
|
-
if (!text.startsWith("/**"))
|
|
14362
|
-
return;
|
|
14363
|
-
const cleaned = text.replace(/^\/\*\*\s*/, "").replace(/\s*\*\/$/, "").replace(/^\s*\* ?/gm, "").trim();
|
|
14364
|
-
return cleaned || undefined;
|
|
14365
|
-
};
|
|
14366
|
-
var extractTypeAnnotation = (node2) => {
|
|
14367
|
-
if (!node2)
|
|
14368
|
-
return null;
|
|
14369
|
-
return node2.text.replace(/^:\s*/, "").trim() || null;
|
|
14370
|
-
};
|
|
14371
|
-
var getNameNodeText = (node2) => node2?.text?.trim() ? node2.text.trim() : null;
|
|
14372
|
-
var getReturnType = (node2) => {
|
|
14373
|
-
const returnNode = node2.childForFieldName("return_type") ?? node2.namedChildren.find((child) => child.type === "type_annotation") ?? null;
|
|
14374
|
-
return extractTypeAnnotation(returnNode);
|
|
14375
|
-
};
|
|
14376
|
-
var getInitializer = (node2) => node2.childForFieldName("value") ?? node2.namedChildren.find((child) => child.type === "arrow_function" || child.type === "function" || child.type === "call_expression") ?? null;
|
|
14377
|
-
var getCallableFromInitializer = (node2) => {
|
|
14378
|
-
if (!node2)
|
|
14379
|
-
return null;
|
|
14380
|
-
if (node2.type === "arrow_function" || node2.type === "function")
|
|
14381
|
-
return node2;
|
|
14382
|
-
if (node2.type === "call_expression") {
|
|
14383
|
-
return node2.namedChildren.find((child) => child.type === "arrow_function" || child.type === "function") ?? null;
|
|
14384
|
-
}
|
|
14385
|
-
return null;
|
|
14386
|
-
};
|
|
14387
|
-
var getInitializerTypeAnnotation = (node2) => {
|
|
14388
|
-
if (!node2 || node2.type !== "call_expression")
|
|
14389
|
-
return null;
|
|
14390
|
-
const typeArguments = node2.namedChildren.find((child) => child.type === "type_arguments") ?? null;
|
|
14391
|
-
if (!typeArguments)
|
|
14392
|
-
return null;
|
|
14393
|
-
const callee = node2.namedChildren.find((child) => child.type !== "type_arguments" && child.type !== "arguments") ?? null;
|
|
14394
|
-
const calleeText = callee?.text?.trim();
|
|
14395
|
-
return calleeText ? `${calleeText}${typeArguments.text}` : typeArguments.text;
|
|
14396
|
-
};
|
|
14397
|
-
var getInitializerText = (node2, options = {}) => {
|
|
14398
|
-
if (!node2)
|
|
14399
|
-
return null;
|
|
14400
|
-
if ((node2.type === "arrow_function" || node2.type === "function") && !options.includeCallable)
|
|
14401
|
-
return null;
|
|
14402
|
-
const text = node2.text.trim();
|
|
14403
|
-
if ((node2.type === "arrow_function" || node2.type === "function") && text.length > 600)
|
|
14404
|
-
return null;
|
|
14405
|
-
return text.length > 0 ? text : null;
|
|
14406
|
-
};
|
|
14407
|
-
var inferReturnType = (node2) => {
|
|
14408
|
-
if (!node2)
|
|
14409
|
-
return null;
|
|
14410
|
-
return containsJsx(node2) ? "JSX.Element" : null;
|
|
14411
|
-
};
|
|
14412
|
-
var containsJsx = (node2) => {
|
|
14413
|
-
if (node2.type.startsWith("jsx_"))
|
|
14414
|
-
return true;
|
|
14415
|
-
return node2.namedChildren.some(containsJsx);
|
|
14416
|
-
};
|
|
14417
|
-
var getTypeNames = (typeText) => {
|
|
14418
|
-
if (!typeText)
|
|
14419
|
-
return [];
|
|
14420
|
-
const matches = typeText.match(/\b[A-Z][A-Za-z0-9_]*(?:\.[A-Z][A-Za-z0-9_]*)*\b/g) ?? [];
|
|
14421
|
-
return [...new Set(matches)].filter((match) => !BUILTIN_TYPES.has(match));
|
|
14422
|
-
};
|
|
14423
|
-
var resolveTypeBinding = (typeName, importBindings, declarations) => {
|
|
14424
|
-
const localName = typeName.split(".")[0] ?? typeName;
|
|
14425
|
-
const importBinding = importBindings.get(localName);
|
|
14426
|
-
if (importBinding)
|
|
14427
|
-
return importBinding.isExternal;
|
|
14428
|
-
if (declarations.has(localName))
|
|
14429
|
-
return false;
|
|
14430
|
-
return false;
|
|
14431
|
-
};
|
|
14432
|
-
var appendTypeRelations = (relations, relationType, from, typeText, importBindings, declarations, line) => {
|
|
14433
|
-
for (const typeName of getTypeNames(typeText)) {
|
|
14434
|
-
relations.push(createRelation(relationType, from, typeName, resolveTypeBinding(typeName, importBindings, declarations), line));
|
|
14435
|
-
}
|
|
14436
|
-
};
|
|
14437
|
-
var classifyVariable = (name, filePath) => {
|
|
14438
|
-
if ((filePath.endsWith(".tsx") || filePath.endsWith(".jsx")) && /^[A-Z]/.test(name)) {
|
|
14439
|
-
return "component" /* Component */;
|
|
14854
|
+
var stripQuotes = (value) => value.replace(/^['"]/, "").replace(/['"]$/, "");
|
|
14855
|
+
var getDeclarationName = (node2) => {
|
|
14856
|
+
if (node2.type === "lexical_declaration") {
|
|
14857
|
+
return node2.namedChildren.filter((child) => child.type === "variable_declarator").map((child) => child.childForFieldName("name")?.text ?? child.namedChildren[0]?.text ?? "").filter(Boolean);
|
|
14440
14858
|
}
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
var collectParams = (node2) => {
|
|
14444
|
-
if (!node2)
|
|
14445
|
-
return [];
|
|
14446
|
-
return node2.namedChildren.map((child) => {
|
|
14447
|
-
const wrapper = child;
|
|
14448
|
-
const target = child.type === "required_parameter" || child.type === "optional_parameter" ? child.namedChildren[0] ?? child : child;
|
|
14449
|
-
const nameNode = target.childForFieldName("name") ?? target.namedChildren.find((candidate) => candidate.type === "identifier" || candidate.type === "property_identifier") ?? target.namedChildren[0] ?? target;
|
|
14450
|
-
const typeNode = wrapper.childForFieldName("type") ?? wrapper.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? target.childForFieldName("type") ?? target.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? null;
|
|
14451
|
-
return {
|
|
14452
|
-
name: nameNode.text,
|
|
14453
|
-
type: extractTypeAnnotation(typeNode)
|
|
14454
|
-
};
|
|
14455
|
-
});
|
|
14859
|
+
const nameNode = node2.childForFieldName("name") ?? node2.namedChildren.find((child) => child.type === "identifier" || child.type === "type_identifier");
|
|
14860
|
+
return nameNode?.text ? [nameNode.text] : [];
|
|
14456
14861
|
};
|
|
14457
|
-
var
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
14463
|
-
const nameNode = child.childForFieldName("name") ?? child.namedChildren.find((candidate) => candidate.type === "property_identifier" || candidate.type === "identifier");
|
|
14464
|
-
if (!nameNode)
|
|
14465
|
-
continue;
|
|
14466
|
-
const typeNode = child.childForFieldName("type") ?? child.namedChildren.find((candidate) => candidate.type === "type_annotation") ?? null;
|
|
14467
|
-
const typeAnnotation = extractTypeAnnotation(typeNode);
|
|
14468
|
-
const propDoc = extractJSDoc(child);
|
|
14469
|
-
members.push({
|
|
14470
|
-
name: nameNode.text,
|
|
14471
|
-
kind: "prop" /* Prop */,
|
|
14472
|
-
visibility: "internal" /* Internal */,
|
|
14473
|
-
file: "",
|
|
14474
|
-
line: getLine(child),
|
|
14475
|
-
endLine: getEndLine(child),
|
|
14476
|
-
...typeAnnotation ? { typeAnnotation } : {},
|
|
14477
|
-
...propDoc ? { doc: propDoc } : {}
|
|
14478
|
-
});
|
|
14479
|
-
appendTypeRelations(relations, "of_type" /* OfType */, ownerName, typeAnnotation, importBindings, declarations, getLine(child));
|
|
14480
|
-
continue;
|
|
14481
|
-
}
|
|
14482
|
-
const indexMember = indexSignatureMember(child);
|
|
14483
|
-
if (indexMember) {
|
|
14484
|
-
members.push(indexMember.info);
|
|
14485
|
-
appendTypeRelations(relations, "of_type" /* OfType */, ownerName, indexMember.typeAnnotation, importBindings, declarations, getLine(child));
|
|
14486
|
-
continue;
|
|
14487
|
-
}
|
|
14488
|
-
if (child.type === "method_definition" || child.type === "method_signature") {
|
|
14489
|
-
const nameNode = child.childForFieldName("name") ?? child.namedChildren.find((candidate) => candidate.type === "property_identifier" || candidate.type === "identifier");
|
|
14490
|
-
if (!nameNode)
|
|
14491
|
-
continue;
|
|
14492
|
-
const paramsNode = child.childForFieldName("parameters") ?? child.namedChildren.find((candidate) => candidate.type === "formal_parameters") ?? null;
|
|
14493
|
-
const params = collectParams(paramsNode);
|
|
14494
|
-
const returnType = getReturnType(child);
|
|
14495
|
-
const methodDoc = extractJSDoc(child);
|
|
14496
|
-
members.push({
|
|
14497
|
-
name: nameNode.text,
|
|
14498
|
-
kind: "method" /* Method */,
|
|
14499
|
-
visibility: "internal" /* Internal */,
|
|
14500
|
-
file: "",
|
|
14501
|
-
line: getLine(child),
|
|
14502
|
-
endLine: getEndLine(child),
|
|
14503
|
-
...params.length > 0 ? { params } : {},
|
|
14504
|
-
...returnType ? { returnType } : {},
|
|
14505
|
-
...methodDoc ? { doc: methodDoc } : {}
|
|
14506
|
-
});
|
|
14507
|
-
for (const param of params) {
|
|
14508
|
-
appendTypeRelations(relations, "param_type" /* ParamType */, ownerName, param.type, importBindings, declarations, getLine(child));
|
|
14862
|
+
var collectLocalDeclarations = (root) => {
|
|
14863
|
+
const declarations = new Map;
|
|
14864
|
+
const register = (node2) => {
|
|
14865
|
+
for (const name of getDeclarationName(node2)) {
|
|
14866
|
+
if (!declarations.has(name)) {
|
|
14867
|
+
declarations.set(name, name);
|
|
14509
14868
|
}
|
|
14510
|
-
appendTypeRelations(relations, "return_type" /* ReturnType */, ownerName, returnType, importBindings, declarations, getLine(child));
|
|
14511
14869
|
}
|
|
14512
|
-
}
|
|
14513
|
-
return members.length > 0 ? members : undefined;
|
|
14514
|
-
};
|
|
14515
|
-
var indexSignatureMember = (node2) => {
|
|
14516
|
-
if (node2.type !== "index_signature")
|
|
14517
|
-
return null;
|
|
14518
|
-
const match = /^\s*(\[[^\]]+\])\s*:?\s*([^;]+)?;?\s*$/u.exec(node2.text);
|
|
14519
|
-
const name = match?.[1]?.trim();
|
|
14520
|
-
const typeAnnotation = match?.[2]?.trim();
|
|
14521
|
-
if (!name)
|
|
14522
|
-
return null;
|
|
14523
|
-
const propDoc = extractJSDoc(node2);
|
|
14524
|
-
return {
|
|
14525
|
-
info: {
|
|
14526
|
-
name,
|
|
14527
|
-
kind: "prop" /* Prop */,
|
|
14528
|
-
visibility: "internal" /* Internal */,
|
|
14529
|
-
file: "",
|
|
14530
|
-
line: getLine(node2),
|
|
14531
|
-
endLine: getEndLine(node2),
|
|
14532
|
-
...typeAnnotation ? { typeAnnotation } : {},
|
|
14533
|
-
...propDoc ? { doc: propDoc } : {}
|
|
14534
|
-
},
|
|
14535
|
-
typeAnnotation
|
|
14536
14870
|
};
|
|
14537
|
-
|
|
14538
|
-
|
|
14539
|
-
|
|
14540
|
-
if (!body)
|
|
14541
|
-
return;
|
|
14542
|
-
const values = [];
|
|
14543
|
-
for (const member of body.namedChildren.filter((child) => child.type === "enum_assignment" || child.type === "property_identifier")) {
|
|
14544
|
-
if (member.type === "property_identifier") {
|
|
14545
|
-
values.push(member.text);
|
|
14871
|
+
for (const child of root.namedChildren) {
|
|
14872
|
+
if (DECLARATION_TYPES2.has(child.type)) {
|
|
14873
|
+
register(child);
|
|
14546
14874
|
continue;
|
|
14547
14875
|
}
|
|
14548
|
-
|
|
14549
|
-
if (!name)
|
|
14876
|
+
if (child.type !== "export_statement")
|
|
14550
14877
|
continue;
|
|
14551
|
-
const
|
|
14552
|
-
|
|
14553
|
-
|
|
14878
|
+
const declaration = child.namedChildren.find((node2) => DECLARATION_TYPES2.has(node2.type));
|
|
14879
|
+
if (declaration) {
|
|
14880
|
+
register(declaration);
|
|
14881
|
+
}
|
|
14554
14882
|
}
|
|
14555
|
-
return
|
|
14883
|
+
return declarations;
|
|
14556
14884
|
};
|
|
14557
|
-
var
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
}
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14885
|
+
var parseExportSpecifier = (node2) => {
|
|
14886
|
+
const identifiers = node2.namedChildren.filter((child) => child.type === "identifier" || child.type === "type_identifier").map((child) => child.text);
|
|
14887
|
+
if (identifiers.length === 0)
|
|
14888
|
+
return null;
|
|
14889
|
+
const localName = identifiers[0];
|
|
14890
|
+
const exportedName = identifiers[1] ?? localName;
|
|
14891
|
+
return { localName, exportedName };
|
|
14892
|
+
};
|
|
14893
|
+
var parseImportSpecifier = (node2) => {
|
|
14894
|
+
const identifiers = node2.namedChildren.filter((child) => child.type === "identifier" || child.type === "type_identifier").map((child) => child.text);
|
|
14895
|
+
if (identifiers.length === 0)
|
|
14896
|
+
return null;
|
|
14897
|
+
const importedName = identifiers[0];
|
|
14898
|
+
const localName = identifiers[1] ?? importedName;
|
|
14899
|
+
return { importedName, localName };
|
|
14900
|
+
};
|
|
14901
|
+
var collectImportBindings = (root) => {
|
|
14902
|
+
const bindings = new Map;
|
|
14903
|
+
for (const node2 of root.namedChildren) {
|
|
14904
|
+
if (node2.type !== "import_statement")
|
|
14905
|
+
continue;
|
|
14906
|
+
const stringNode = node2.namedChildren.find((child) => child.type === "string");
|
|
14907
|
+
if (!stringNode)
|
|
14908
|
+
continue;
|
|
14909
|
+
const source = stripQuotes(stringNode.text);
|
|
14910
|
+
const clause = node2.namedChildren.find((child) => child.type === "import_clause");
|
|
14911
|
+
for (const part of clause?.namedChildren ?? []) {
|
|
14912
|
+
if (part.type === "identifier") {
|
|
14913
|
+
bindings.set(part.text, { source, importedName: "default" });
|
|
14914
|
+
continue;
|
|
14915
|
+
}
|
|
14916
|
+
if (part.type !== "named_imports")
|
|
14917
|
+
continue;
|
|
14918
|
+
for (const specifier of part.namedChildren.filter((child) => child.type === "import_specifier")) {
|
|
14919
|
+
const parsed = parseImportSpecifier(specifier);
|
|
14920
|
+
if (parsed) {
|
|
14921
|
+
bindings.set(parsed.localName, { source, importedName: parsed.importedName });
|
|
14922
|
+
}
|
|
14578
14923
|
}
|
|
14579
14924
|
}
|
|
14580
|
-
return values.length > 0 ? values : undefined;
|
|
14581
14925
|
}
|
|
14582
|
-
return;
|
|
14926
|
+
return bindings;
|
|
14583
14927
|
};
|
|
14584
|
-
var
|
|
14585
|
-
|
|
14928
|
+
var uniqueExports = (exportsList) => {
|
|
14929
|
+
const seen = new Set;
|
|
14930
|
+
return exportsList.filter((item) => {
|
|
14931
|
+
const key = `${item.declarationFile}::${item.localName}::${item.exportedName}`;
|
|
14932
|
+
if (seen.has(key))
|
|
14933
|
+
return false;
|
|
14934
|
+
seen.add(key);
|
|
14935
|
+
return true;
|
|
14936
|
+
});
|
|
14937
|
+
};
|
|
14938
|
+
var traceImportedBinding = async (filePath, binding, exportedName, fs, state) => {
|
|
14939
|
+
const targetPath = await resolveImportSourcePath(filePath, binding.source, fs, state.resolver);
|
|
14940
|
+
if (!targetPath)
|
|
14586
14941
|
return [];
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
if (
|
|
14590
|
-
return
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14942
|
+
const traced = await traceFile(targetPath, fs, state);
|
|
14943
|
+
const match = traced.find((item) => item.exportedName === binding.importedName || binding.importedName === "default" && item.exportedName === item.localName);
|
|
14944
|
+
if (!match)
|
|
14945
|
+
return [];
|
|
14946
|
+
return [{
|
|
14947
|
+
exportedName,
|
|
14948
|
+
localName: match.localName,
|
|
14949
|
+
declarationFile: match.declarationFile
|
|
14950
|
+
}];
|
|
14951
|
+
};
|
|
14952
|
+
var traceFile = async (filePath, fs, state) => {
|
|
14953
|
+
const cached = state.cache.get(filePath);
|
|
14954
|
+
if (cached)
|
|
14955
|
+
return cached;
|
|
14956
|
+
if (state.inFlight.has(filePath))
|
|
14957
|
+
return [];
|
|
14958
|
+
const promise = (async () => {
|
|
14959
|
+
state.inFlight.add(filePath);
|
|
14960
|
+
state.files.add(filePath);
|
|
14961
|
+
const source = await fs.readFile(filePath);
|
|
14962
|
+
const commonJs = analyzeCommonJsModule(source, filePath);
|
|
14963
|
+
if (commonJs.diagnostics.length > 0)
|
|
14964
|
+
return [];
|
|
14965
|
+
const jsxLike = isJsxLikePath(filePath);
|
|
14966
|
+
const parserSource = jsxLike ? treeSitterCompatibleJsxSource(createEcmaScriptSourceFile(source, filePath), source) : source;
|
|
14967
|
+
const tree = await parseFile(parserSource, jsxLike);
|
|
14968
|
+
if (!tree)
|
|
14969
|
+
return [];
|
|
14970
|
+
const root = tree.rootNode;
|
|
14971
|
+
const localDeclarations = collectLocalDeclarations(root);
|
|
14972
|
+
const importBindings = collectImportBindings(root);
|
|
14973
|
+
for (const declaration of commonJs.syntheticDeclarations) {
|
|
14974
|
+
localDeclarations.set(declaration.name, declaration.name);
|
|
14975
|
+
}
|
|
14976
|
+
for (const binding of commonJs.bindings) {
|
|
14977
|
+
importBindings.set(binding.localName, {
|
|
14978
|
+
source: binding.source,
|
|
14979
|
+
importedName: binding.importedName
|
|
14980
|
+
});
|
|
14981
|
+
}
|
|
14982
|
+
const exportsList = [];
|
|
14983
|
+
for (const node2 of root.namedChildren) {
|
|
14984
|
+
if (node2.type !== "export_statement")
|
|
14985
|
+
continue;
|
|
14986
|
+
const stringNode = node2.namedChildren.find((child) => child.type === "string");
|
|
14987
|
+
const exportClause = node2.namedChildren.find((child) => child.type === "export_clause");
|
|
14988
|
+
const declaration = node2.namedChildren.find((child) => DECLARATION_TYPES2.has(child.type));
|
|
14989
|
+
if (declaration) {
|
|
14990
|
+
for (const name of getDeclarationName(declaration)) {
|
|
14991
|
+
exportsList.push({ exportedName: name, localName: name, declarationFile: filePath });
|
|
14992
|
+
}
|
|
14993
|
+
continue;
|
|
14994
|
+
}
|
|
14995
|
+
if (node2.text.startsWith("export default ")) {
|
|
14996
|
+
const identifier = node2.namedChildren.find((child) => child.type === "identifier" || child.type === "type_identifier");
|
|
14997
|
+
if (identifier && localDeclarations.has(identifier.text)) {
|
|
14998
|
+
exportsList.push({
|
|
14999
|
+
exportedName: identifier.text,
|
|
15000
|
+
localName: identifier.text,
|
|
15001
|
+
declarationFile: filePath
|
|
15002
|
+
});
|
|
15003
|
+
}
|
|
15004
|
+
continue;
|
|
15005
|
+
}
|
|
15006
|
+
if (!exportClause) {
|
|
15007
|
+
if (stringNode && node2.text.startsWith("export *")) {
|
|
15008
|
+
const targetPath2 = await resolveImportSourcePath(filePath, stripQuotes(stringNode.text), fs, state.resolver);
|
|
15009
|
+
if (targetPath2) {
|
|
15010
|
+
exportsList.push(...await traceFile(targetPath2, fs, state));
|
|
15011
|
+
}
|
|
15012
|
+
}
|
|
15013
|
+
continue;
|
|
15014
|
+
}
|
|
15015
|
+
if (!stringNode) {
|
|
15016
|
+
for (const specifier of exportClause.namedChildren.filter((child) => child.type === "export_specifier")) {
|
|
15017
|
+
const parsed = parseExportSpecifier(specifier);
|
|
15018
|
+
if (!parsed)
|
|
15019
|
+
continue;
|
|
15020
|
+
if (localDeclarations.has(parsed.localName)) {
|
|
15021
|
+
exportsList.push({
|
|
15022
|
+
exportedName: parsed.exportedName,
|
|
15023
|
+
localName: parsed.localName,
|
|
15024
|
+
declarationFile: filePath
|
|
15025
|
+
});
|
|
15026
|
+
continue;
|
|
15027
|
+
}
|
|
15028
|
+
const importBinding = importBindings.get(parsed.localName);
|
|
15029
|
+
if (importBinding) {
|
|
15030
|
+
exportsList.push(...await traceImportedBinding(filePath, importBinding, parsed.exportedName, fs, state));
|
|
15031
|
+
}
|
|
15032
|
+
}
|
|
15033
|
+
continue;
|
|
15034
|
+
}
|
|
15035
|
+
const targetPath = await resolveImportSourcePath(filePath, stripQuotes(stringNode.text), fs, state.resolver);
|
|
15036
|
+
if (!targetPath)
|
|
15037
|
+
continue;
|
|
15038
|
+
const traced = await traceFile(targetPath, fs, state);
|
|
15039
|
+
for (const specifier of exportClause.namedChildren.filter((child) => child.type === "export_specifier")) {
|
|
15040
|
+
const parsed = parseExportSpecifier(specifier);
|
|
15041
|
+
if (!parsed)
|
|
15042
|
+
continue;
|
|
15043
|
+
const match = traced.find((item) => item.exportedName === parsed.localName);
|
|
15044
|
+
if (!match)
|
|
15045
|
+
continue;
|
|
15046
|
+
exportsList.push({
|
|
15047
|
+
exportedName: parsed.exportedName,
|
|
15048
|
+
localName: match.localName,
|
|
15049
|
+
declarationFile: match.declarationFile
|
|
15050
|
+
});
|
|
15051
|
+
}
|
|
15052
|
+
}
|
|
15053
|
+
exportsList.push(...await traceCommonJsExports({
|
|
15054
|
+
analysis: commonJs,
|
|
15055
|
+
filePath,
|
|
15056
|
+
localDeclarations,
|
|
15057
|
+
traceImported: (source2, importedName, exportedName) => traceImportedBinding(filePath, { source: source2, importedName }, exportedName, fs, state),
|
|
15058
|
+
traceWildcard: async (source2) => {
|
|
15059
|
+
const targetPath = await resolveImportSourcePath(filePath, source2, fs, state.resolver);
|
|
15060
|
+
return targetPath ? traceFile(targetPath, fs, state) : [];
|
|
15061
|
+
}
|
|
15062
|
+
}));
|
|
15063
|
+
state.inFlight.delete(filePath);
|
|
15064
|
+
return uniqueExports(exportsList);
|
|
15065
|
+
})();
|
|
15066
|
+
state.cache.set(filePath, promise);
|
|
15067
|
+
return promise;
|
|
15068
|
+
};
|
|
15069
|
+
var traceExports = async (entryPath, fs, resolver = { mappings: [] }) => {
|
|
15070
|
+
const state = {
|
|
15071
|
+
files: new Set,
|
|
15072
|
+
cache: new Map,
|
|
15073
|
+
inFlight: new Set,
|
|
15074
|
+
resolver
|
|
15075
|
+
};
|
|
15076
|
+
const exportsList = await traceFile(entryPath, fs, state);
|
|
15077
|
+
return {
|
|
15078
|
+
exports: uniqueExports(exportsList),
|
|
15079
|
+
files: [...state.files].sort()
|
|
15080
|
+
};
|
|
14596
15081
|
};
|
|
14597
15082
|
|
|
14598
15083
|
// src/staticCallRelations.ts
|
|
14599
|
-
import
|
|
15084
|
+
import ts8 from "typescript";
|
|
14600
15085
|
var callTarget = (expression, sourceFile) => {
|
|
14601
|
-
if (
|
|
15086
|
+
if (ts8.isIdentifier(expression))
|
|
14602
15087
|
return expression.text === "require" ? null : expression.text;
|
|
14603
|
-
if (
|
|
15088
|
+
if (ts8.isPropertyAccessExpression(expression))
|
|
14604
15089
|
return expression.getText(sourceFile).replace(/\s+/gu, "");
|
|
14605
|
-
if (
|
|
15090
|
+
if (ts8.isElementAccessExpression(expression)) {
|
|
14606
15091
|
const property = staticStringValue(expression.argumentExpression);
|
|
14607
15092
|
return property ? `${expression.expression.getText(sourceFile).replace(/\s+/gu, "")}.${property}` : null;
|
|
14608
15093
|
}
|
|
@@ -14610,21 +15095,21 @@ var callTarget = (expression, sourceFile) => {
|
|
|
14610
15095
|
};
|
|
14611
15096
|
var rootIdentifier = (expression) => {
|
|
14612
15097
|
let current = expression;
|
|
14613
|
-
while (
|
|
15098
|
+
while (ts8.isPropertyAccessExpression(current) || ts8.isElementAccessExpression(current)) {
|
|
14614
15099
|
current = current.expression;
|
|
14615
15100
|
}
|
|
14616
|
-
return
|
|
15101
|
+
return ts8.isIdentifier(current) ? current.text : null;
|
|
14617
15102
|
};
|
|
14618
15103
|
var declarationName = (node2, sourceFile) => {
|
|
14619
|
-
if (
|
|
15104
|
+
if (ts8.isFunctionDeclaration(node2) && node2.name)
|
|
14620
15105
|
return node2.name.text;
|
|
14621
|
-
if (
|
|
15106
|
+
if (ts8.isClassDeclaration(node2) && node2.name)
|
|
14622
15107
|
return node2.name.text;
|
|
14623
|
-
if (
|
|
15108
|
+
if (ts8.isVariableDeclaration(node2) && ts8.isIdentifier(node2.name))
|
|
14624
15109
|
return node2.name.text;
|
|
14625
|
-
if (
|
|
15110
|
+
if (ts8.isMethodDeclaration(node2) || ts8.isGetAccessorDeclaration(node2) || ts8.isSetAccessorDeclaration(node2)) {
|
|
14626
15111
|
const parent = node2.parent;
|
|
14627
|
-
if (parent &&
|
|
15112
|
+
if (parent && ts8.isClassDeclaration(parent) && parent.name)
|
|
14628
15113
|
return parent.name.text;
|
|
14629
15114
|
return node2.name?.getText(sourceFile) ?? null;
|
|
14630
15115
|
}
|
|
@@ -14635,7 +15120,7 @@ var collectStaticCallRelations = (source, filePath, importBindings) => {
|
|
|
14635
15120
|
const relations = [];
|
|
14636
15121
|
const visit2 = (node2, owner) => {
|
|
14637
15122
|
const namedOwner = declarationName(node2, sourceFile) ?? owner;
|
|
14638
|
-
if (
|
|
15123
|
+
if (ts8.isCallExpression(node2) || ts8.isNewExpression(node2)) {
|
|
14639
15124
|
const target = callTarget(node2.expression, sourceFile);
|
|
14640
15125
|
if (target) {
|
|
14641
15126
|
const root = rootIdentifier(node2.expression);
|
|
@@ -14643,7 +15128,7 @@ var collectStaticCallRelations = (source, filePath, importBindings) => {
|
|
|
14643
15128
|
relations.push(createRelation("calls" /* Calls */, namedOwner, target, isExternal, nodeLocation(sourceFile, node2).line));
|
|
14644
15129
|
}
|
|
14645
15130
|
}
|
|
14646
|
-
|
|
15131
|
+
ts8.forEachChild(node2, (child) => visit2(child, namedOwner));
|
|
14647
15132
|
};
|
|
14648
15133
|
visit2(sourceFile, filePath);
|
|
14649
15134
|
const seen = new Set;
|
|
@@ -14778,10 +15263,10 @@ var analyzeLexicalDeclaration = (node2, filePath, declarations, importBindings,
|
|
|
14778
15263
|
continue;
|
|
14779
15264
|
const typeNode = declarator.childForFieldName("type") ?? declarator.namedChildren.find((child) => child.type === "type_annotation") ?? null;
|
|
14780
15265
|
const initializer = getInitializer(declarator);
|
|
14781
|
-
const
|
|
14782
|
-
const paramsNode =
|
|
15266
|
+
const callable2 = getCallableFromInitializer(initializer);
|
|
15267
|
+
const paramsNode = callable2?.childForFieldName("parameters") ?? callable2?.namedChildren.find((child) => child.type === "formal_parameters") ?? null;
|
|
14783
15268
|
const params = collectParams(paramsNode);
|
|
14784
|
-
const returnType =
|
|
15269
|
+
const returnType = callable2 ? getReturnType(callable2) ?? inferReturnType(callable2) : null;
|
|
14785
15270
|
const initializerTypeAnnotation = getInitializerTypeAnnotation(initializer);
|
|
14786
15271
|
const typeAnnotation = extractTypeAnnotation(typeNode) ?? initializerTypeAnnotation;
|
|
14787
15272
|
const initializerText = getInitializerText(initializer, {
|
|
@@ -14807,7 +15292,7 @@ var analyzeLexicalDeclaration = (node2, filePath, declarations, importBindings,
|
|
|
14807
15292
|
appendTypeRelations(relations, "param_type" /* ParamType */, nameNode.text, param.type, importBindings, declarations, getLine(declarator));
|
|
14808
15293
|
}
|
|
14809
15294
|
appendTypeRelations(relations, "return_type" /* ReturnType */, nameNode.text, returnType, importBindings, declarations, getLine(declarator));
|
|
14810
|
-
appendTypeRelations(relations, "of_type" /* OfType */, nameNode.text,
|
|
15295
|
+
appendTypeRelations(relations, "of_type" /* OfType */, nameNode.text, extractTypeAnnotation(typeNode) ?? getInitializerTypeAnnotation(initializer, { referencesOnly: true }), importBindings, declarations, getLine(declarator));
|
|
14811
15296
|
}
|
|
14812
15297
|
};
|
|
14813
15298
|
var analyzeFunctionDeclaration = (node2, name, filePath, declarations, importBindings, relations) => {
|
|
@@ -14815,7 +15300,8 @@ var analyzeFunctionDeclaration = (node2, name, filePath, declarations, importBin
|
|
|
14815
15300
|
const params = collectParams(paramsNode);
|
|
14816
15301
|
const returnType = getReturnType(node2);
|
|
14817
15302
|
const funcDoc = extractJSDoc(node2);
|
|
14818
|
-
const
|
|
15303
|
+
const body = node2.childForFieldName("body");
|
|
15304
|
+
const signature = body === null ? node2.text : node2.text.slice(0, body.startIndex - node2.startIndex).trimEnd();
|
|
14819
15305
|
declarations.set(name, {
|
|
14820
15306
|
info: {
|
|
14821
15307
|
name,
|
|
@@ -14990,13 +15476,13 @@ var analyzeFile = async (filePath, fs, resolver = { mappings: [] }) => {
|
|
|
14990
15476
|
}
|
|
14991
15477
|
}
|
|
14992
15478
|
for (const child of root.namedChildren) {
|
|
14993
|
-
if (
|
|
15479
|
+
if (DECLARATION_TYPES.has(child.type)) {
|
|
14994
15480
|
analyzeDeclaration(child, filePath, declarations, importBindings, relations);
|
|
14995
15481
|
continue;
|
|
14996
15482
|
}
|
|
14997
15483
|
if (child.type !== "export_statement")
|
|
14998
15484
|
continue;
|
|
14999
|
-
const declaration = child.namedChildren.find((node2) =>
|
|
15485
|
+
const declaration = child.namedChildren.find((node2) => DECLARATION_TYPES.has(node2.type));
|
|
15000
15486
|
if (declaration) {
|
|
15001
15487
|
analyzeDeclaration(declaration, filePath, declarations, importBindings, relations);
|
|
15002
15488
|
}
|
|
@@ -15006,7 +15492,7 @@ var analyzeFile = async (filePath, fs, resolver = { mappings: [] }) => {
|
|
|
15006
15492
|
return {
|
|
15007
15493
|
declarations,
|
|
15008
15494
|
importBindings,
|
|
15009
|
-
relations,
|
|
15495
|
+
relations: relations.map((relation) => ({ ...relation, file: filePath })),
|
|
15010
15496
|
lines: countLines(source),
|
|
15011
15497
|
disposition: "analyzed",
|
|
15012
15498
|
diagnostics: []
|
|
@@ -15022,6 +15508,7 @@ var relationIdentity = (relation) => JSON.stringify([
|
|
|
15022
15508
|
relation.grounding,
|
|
15023
15509
|
relation.confidence,
|
|
15024
15510
|
relation.source,
|
|
15511
|
+
relation.file ?? null,
|
|
15025
15512
|
relation.line ?? null
|
|
15026
15513
|
]);
|
|
15027
15514
|
var uniqueRelations = (relations) => {
|
|
@@ -15061,14 +15548,19 @@ var extractSymbols = async (entries, fs, options) => {
|
|
|
15061
15548
|
continue;
|
|
15062
15549
|
const declKey = `${tracedExport.declarationFile}::${tracedExport.localName}`;
|
|
15063
15550
|
const exportKey = `${declKey}::${tracedExport.exportedName}`;
|
|
15064
|
-
if (exportedDeclarationKeys.has(exportKey))
|
|
15551
|
+
if (exportedDeclarationKeys.has(exportKey)) {
|
|
15552
|
+
const existing = exportedSymbols.find((symbol) => symbol.file === tracedExport.declarationFile && symbol.name === tracedExport.exportedName);
|
|
15553
|
+
if (existing !== undefined)
|
|
15554
|
+
existing.publicEntrypoints = [...new Set([...existing.publicEntrypoints, entry.path])].sort();
|
|
15065
15555
|
continue;
|
|
15556
|
+
}
|
|
15066
15557
|
exportedDeclarationKeys.add(declKey);
|
|
15067
15558
|
exportedDeclarationKeys.add(exportKey);
|
|
15068
15559
|
exportedSymbols.push({
|
|
15069
15560
|
...declaration.info,
|
|
15070
15561
|
name: tracedExport.exportedName,
|
|
15071
|
-
visibility: "exported" /* Exported
|
|
15562
|
+
visibility: "exported" /* Exported */,
|
|
15563
|
+
publicEntrypoints: [entry.path]
|
|
15072
15564
|
});
|
|
15073
15565
|
}
|
|
15074
15566
|
}
|
|
@@ -15090,34 +15582,7 @@ var extractSymbols = async (entries, fs, options) => {
|
|
|
15090
15582
|
}
|
|
15091
15583
|
}
|
|
15092
15584
|
const symbols = [...exportedSymbols, ...internalSymbols];
|
|
15093
|
-
|
|
15094
|
-
for (const analysis of analyses.values()) {
|
|
15095
|
-
for (const [name, decl] of analysis.declarations) {
|
|
15096
|
-
if (decl.info.kind === "interface" || decl.info.kind === "type") {
|
|
15097
|
-
typeDeclarations.set(name, decl.info.file);
|
|
15098
|
-
}
|
|
15099
|
-
}
|
|
15100
|
-
}
|
|
15101
|
-
for (const sym of symbols) {
|
|
15102
|
-
if (sym.kind !== "component")
|
|
15103
|
-
continue;
|
|
15104
|
-
let propsTypeName;
|
|
15105
|
-
if (sym.typeAnnotation) {
|
|
15106
|
-
const genericBody = /<(.+)>/u.exec(sym.typeAnnotation)?.[1];
|
|
15107
|
-
const genericNames = genericBody?.match(/\b[A-Z][A-Za-z0-9_]*\b/gu) ?? [];
|
|
15108
|
-
propsTypeName = genericNames.filter((name) => typeDeclarations.has(name)).at(-1);
|
|
15109
|
-
}
|
|
15110
|
-
if (!propsTypeName) {
|
|
15111
|
-
const conventionName = `${sym.name}Props`;
|
|
15112
|
-
if (typeDeclarations.has(conventionName)) {
|
|
15113
|
-
propsTypeName = conventionName;
|
|
15114
|
-
}
|
|
15115
|
-
}
|
|
15116
|
-
if (propsTypeName) {
|
|
15117
|
-
sym.propsType = propsTypeName;
|
|
15118
|
-
relations.push(createRelation("of_type" /* OfType */, sym.name, propsTypeName, false, sym.line));
|
|
15119
|
-
}
|
|
15120
|
-
}
|
|
15585
|
+
await enrichPublicContracts({ symbols, paths: [...analyses.keys()], fs, resolver, relations });
|
|
15121
15586
|
const deduplicatedRelations = uniqueRelations(relations);
|
|
15122
15587
|
const files = [...filePaths].sort().map((filePath) => ({
|
|
15123
15588
|
path: filePath,
|
|
@@ -15195,10 +15660,15 @@ class TypeScriptPlugin {
|
|
|
15195
15660
|
}
|
|
15196
15661
|
}
|
|
15197
15662
|
async extractSymbolsInScope(entries, analysisPaths, fs) {
|
|
15198
|
-
const
|
|
15199
|
-
if (!
|
|
15200
|
-
throw new Error("TypeScriptPlugin.extractSymbolsInScope requires detectEntries
|
|
15201
|
-
}
|
|
15663
|
+
const detectedPackage = this.#lastDetection?.package;
|
|
15664
|
+
if (!detectedPackage && entries.length > 0) {
|
|
15665
|
+
throw new Error("TypeScriptPlugin.extractSymbolsInScope requires detectEntries before using package entries");
|
|
15666
|
+
}
|
|
15667
|
+
const packageInfo = detectedPackage ?? {
|
|
15668
|
+
name: "unknown-package",
|
|
15669
|
+
kind: "lib" /* Lib */,
|
|
15670
|
+
language: packageLanguage(analysisPaths)
|
|
15671
|
+
};
|
|
15202
15672
|
try {
|
|
15203
15673
|
return await extractSymbols(entries, fs, {
|
|
15204
15674
|
packageInfo,
|
|
@@ -15211,20 +15681,20 @@ class TypeScriptPlugin {
|
|
|
15211
15681
|
}
|
|
15212
15682
|
}
|
|
15213
15683
|
// src/reactRouter.ts
|
|
15214
|
-
import * as
|
|
15684
|
+
import * as ts9 from "typescript";
|
|
15215
15685
|
function compact(value) {
|
|
15216
15686
|
return value.replace(/\s+/gu, " ").trim();
|
|
15217
15687
|
}
|
|
15218
15688
|
function scalarValue(node2) {
|
|
15219
15689
|
if (!node2)
|
|
15220
15690
|
return;
|
|
15221
|
-
if (
|
|
15691
|
+
if (ts9.isStringLiteralLike(node2) || ts9.isNoSubstitutionTemplateLiteral(node2))
|
|
15222
15692
|
return node2.text;
|
|
15223
|
-
if (
|
|
15693
|
+
if (ts9.isNumericLiteral(node2))
|
|
15224
15694
|
return Number(node2.text);
|
|
15225
|
-
if (node2.kind ===
|
|
15695
|
+
if (node2.kind === ts9.SyntaxKind.TrueKeyword)
|
|
15226
15696
|
return true;
|
|
15227
|
-
if (node2.kind ===
|
|
15697
|
+
if (node2.kind === ts9.SyntaxKind.FalseKeyword)
|
|
15228
15698
|
return false;
|
|
15229
15699
|
return;
|
|
15230
15700
|
}
|
|
@@ -15233,37 +15703,37 @@ function findDynamicImport(node2) {
|
|
|
15233
15703
|
const visit2 = (child) => {
|
|
15234
15704
|
if (result)
|
|
15235
15705
|
return;
|
|
15236
|
-
if (
|
|
15706
|
+
if (ts9.isCallExpression(child) && child.expression.kind === ts9.SyntaxKind.ImportKeyword && child.arguments[0] && ts9.isStringLiteralLike(child.arguments[0])) {
|
|
15237
15707
|
result = child.arguments[0].text;
|
|
15238
15708
|
return;
|
|
15239
15709
|
}
|
|
15240
|
-
|
|
15710
|
+
ts9.forEachChild(child, visit2);
|
|
15241
15711
|
};
|
|
15242
15712
|
visit2(node2);
|
|
15243
15713
|
return result;
|
|
15244
15714
|
}
|
|
15245
15715
|
function parseSource(source, filePath) {
|
|
15246
|
-
const sourceFile =
|
|
15716
|
+
const sourceFile = ts9.createSourceFile(filePath, source, ts9.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts9.ScriptKind.TSX : ts9.ScriptKind.TS);
|
|
15247
15717
|
const imports = new Map;
|
|
15248
15718
|
const constants2 = new Map;
|
|
15249
15719
|
for (const statement of sourceFile.statements) {
|
|
15250
|
-
if (
|
|
15720
|
+
if (ts9.isImportDeclaration(statement) && ts9.isStringLiteral(statement.moduleSpecifier)) {
|
|
15251
15721
|
const moduleSource = statement.moduleSpecifier.text;
|
|
15252
15722
|
const clause = statement.importClause;
|
|
15253
15723
|
if (clause?.name)
|
|
15254
15724
|
imports.set(clause.name.text, moduleSource);
|
|
15255
15725
|
const bindings = clause?.namedBindings;
|
|
15256
|
-
if (bindings &&
|
|
15726
|
+
if (bindings && ts9.isNamedImports(bindings)) {
|
|
15257
15727
|
for (const element of bindings.elements)
|
|
15258
15728
|
imports.set(element.name.text, moduleSource);
|
|
15259
15729
|
}
|
|
15260
|
-
if (bindings &&
|
|
15730
|
+
if (bindings && ts9.isNamespaceImport(bindings))
|
|
15261
15731
|
imports.set(bindings.name.text, moduleSource);
|
|
15262
15732
|
}
|
|
15263
|
-
if (!
|
|
15733
|
+
if (!ts9.isVariableStatement(statement))
|
|
15264
15734
|
continue;
|
|
15265
15735
|
for (const declaration of statement.declarationList.declarations) {
|
|
15266
|
-
if (!
|
|
15736
|
+
if (!ts9.isIdentifier(declaration.name) || !declaration.initializer)
|
|
15267
15737
|
continue;
|
|
15268
15738
|
const scalar = scalarValue(declaration.initializer);
|
|
15269
15739
|
if (scalar !== undefined)
|
|
@@ -15292,13 +15762,13 @@ function routeConditions(node2, sourceFile) {
|
|
|
15292
15762
|
let current = node2;
|
|
15293
15763
|
while (current?.parent) {
|
|
15294
15764
|
const parent = current.parent;
|
|
15295
|
-
if (
|
|
15765
|
+
if (ts9.isConditionalExpression(parent)) {
|
|
15296
15766
|
const condition = compact(parent.condition.getText(sourceFile));
|
|
15297
15767
|
conditions.push(current === parent.whenTrue ? condition : `!(${condition})`);
|
|
15298
|
-
} else if (
|
|
15768
|
+
} else if (ts9.isBinaryExpression(parent) && parent.operatorToken.kind === ts9.SyntaxKind.AmpersandAmpersandToken && current === parent.right) {
|
|
15299
15769
|
conditions.push(compact(parent.left.getText(sourceFile)));
|
|
15300
15770
|
}
|
|
15301
|
-
if (
|
|
15771
|
+
if (ts9.isFunctionLike(parent))
|
|
15302
15772
|
break;
|
|
15303
15773
|
current = parent;
|
|
15304
15774
|
}
|
|
@@ -15307,36 +15777,36 @@ function routeConditions(node2, sourceFile) {
|
|
|
15307
15777
|
function jsxAttributes(node2) {
|
|
15308
15778
|
const result = new Map;
|
|
15309
15779
|
for (const property of node2.attributes.properties)
|
|
15310
|
-
if (
|
|
15780
|
+
if (ts9.isJsxAttribute(property))
|
|
15311
15781
|
result.set(property.name.getText(), property);
|
|
15312
15782
|
return result;
|
|
15313
15783
|
}
|
|
15314
15784
|
function jsxExpression(attribute) {
|
|
15315
15785
|
const initializer = attribute?.initializer;
|
|
15316
|
-
return initializer &&
|
|
15786
|
+
return initializer && ts9.isJsxExpression(initializer) ? initializer.expression : undefined;
|
|
15317
15787
|
}
|
|
15318
15788
|
function jsxScalar(attribute, constants2) {
|
|
15319
15789
|
if (!attribute)
|
|
15320
15790
|
return;
|
|
15321
15791
|
if (!attribute.initializer)
|
|
15322
15792
|
return true;
|
|
15323
|
-
if (
|
|
15793
|
+
if (ts9.isStringLiteral(attribute.initializer))
|
|
15324
15794
|
return attribute.initializer.text;
|
|
15325
15795
|
const expression = jsxExpression(attribute);
|
|
15326
|
-
return scalarValue(expression) ?? (expression &&
|
|
15796
|
+
return scalarValue(expression) ?? (expression && ts9.isIdentifier(expression) ? constants2.get(expression.text) : undefined);
|
|
15327
15797
|
}
|
|
15328
15798
|
function descendantTags(node2) {
|
|
15329
15799
|
const tags = new Set;
|
|
15330
15800
|
const visit2 = (child) => {
|
|
15331
|
-
if (
|
|
15332
|
-
const opening =
|
|
15801
|
+
if (ts9.isJsxElement(child) || ts9.isJsxSelfClosingElement(child)) {
|
|
15802
|
+
const opening = ts9.isJsxElement(child) ? child.openingElement : child;
|
|
15333
15803
|
const tag = opening.tagName.getText();
|
|
15334
15804
|
if (child !== node2 && tag === "Route")
|
|
15335
15805
|
return;
|
|
15336
15806
|
if (!["Route", "Routes", "Suspense", "Fragment", "React.Fragment", "Navigate"].includes(tag))
|
|
15337
15807
|
tags.add(tag);
|
|
15338
15808
|
}
|
|
15339
|
-
|
|
15809
|
+
ts9.forEachChild(child, visit2);
|
|
15340
15810
|
};
|
|
15341
15811
|
visit2(node2);
|
|
15342
15812
|
return [...tags];
|
|
@@ -15346,8 +15816,8 @@ function navigateTarget(node2, sourceFile) {
|
|
|
15346
15816
|
const visit2 = (child) => {
|
|
15347
15817
|
if (target)
|
|
15348
15818
|
return;
|
|
15349
|
-
if (
|
|
15350
|
-
const opening =
|
|
15819
|
+
if (ts9.isJsxElement(child) || ts9.isJsxSelfClosingElement(child)) {
|
|
15820
|
+
const opening = ts9.isJsxElement(child) ? child.openingElement : child;
|
|
15351
15821
|
if (child !== node2 && opening.tagName.getText() === "Route")
|
|
15352
15822
|
return;
|
|
15353
15823
|
if (opening.tagName.getText() === "Navigate") {
|
|
@@ -15362,7 +15832,7 @@ function navigateTarget(node2, sourceFile) {
|
|
|
15362
15832
|
}
|
|
15363
15833
|
}
|
|
15364
15834
|
}
|
|
15365
|
-
|
|
15835
|
+
ts9.forEachChild(child, visit2);
|
|
15366
15836
|
};
|
|
15367
15837
|
visit2(node2);
|
|
15368
15838
|
return target;
|
|
@@ -15379,12 +15849,12 @@ function componentSource(component, imports) {
|
|
|
15379
15849
|
}
|
|
15380
15850
|
function objectProperty(object2, name) {
|
|
15381
15851
|
for (const property of object2.properties) {
|
|
15382
|
-
if (!
|
|
15852
|
+
if (!ts9.isPropertyAssignment(property) && !ts9.isShorthandPropertyAssignment(property))
|
|
15383
15853
|
continue;
|
|
15384
|
-
const key = property.name && (
|
|
15854
|
+
const key = property.name && (ts9.isIdentifier(property.name) || ts9.isStringLiteralLike(property.name)) ? property.name.text : undefined;
|
|
15385
15855
|
if (key !== name)
|
|
15386
15856
|
continue;
|
|
15387
|
-
return
|
|
15857
|
+
return ts9.isPropertyAssignment(property) ? property.initializer : property.name;
|
|
15388
15858
|
}
|
|
15389
15859
|
return;
|
|
15390
15860
|
}
|
|
@@ -15426,7 +15896,7 @@ function extractReactRouterRoutes(source, filePath, options = {}) {
|
|
|
15426
15896
|
};
|
|
15427
15897
|
const visitRouteObjects = (array, parentPath) => {
|
|
15428
15898
|
for (const element of array.elements) {
|
|
15429
|
-
if (!
|
|
15899
|
+
if (!ts9.isObjectLiteralExpression(element))
|
|
15430
15900
|
continue;
|
|
15431
15901
|
const index = scalarValue(objectProperty(element, "index")) === true;
|
|
15432
15902
|
const pathValue = scalarValue(objectProperty(element, "path"));
|
|
@@ -15442,13 +15912,13 @@ function extractReactRouterRoutes(source, filePath, options = {}) {
|
|
|
15442
15912
|
index,
|
|
15443
15913
|
...component ? { component } : {},
|
|
15444
15914
|
...typeof redirect === "string" ? { redirectTo: redirect } : {},
|
|
15445
|
-
...children &&
|
|
15915
|
+
...children && ts9.isArrayLiteralExpression(children) ? { children } : {}
|
|
15446
15916
|
});
|
|
15447
15917
|
}
|
|
15448
15918
|
};
|
|
15449
15919
|
const visit2 = (node2, parentPath) => {
|
|
15450
|
-
if (
|
|
15451
|
-
const opening =
|
|
15920
|
+
if (ts9.isJsxElement(node2) || ts9.isJsxSelfClosingElement(node2)) {
|
|
15921
|
+
const opening = ts9.isJsxElement(node2) ? node2.openingElement : node2;
|
|
15452
15922
|
if (opening.tagName.getText() === "Route") {
|
|
15453
15923
|
const attributes = jsxAttributes(opening);
|
|
15454
15924
|
const index = jsxScalar(attributes.get("index"), parsed.constants) === true;
|
|
@@ -15461,30 +15931,30 @@ function extractReactRouterRoutes(source, filePath, options = {}) {
|
|
|
15461
15931
|
const fullPath = joinRoutePath(parentPath, typeof pathValue === "string" ? pathValue : "", index);
|
|
15462
15932
|
const redirectTo = navigateTarget(candidateNode, parsed.sourceFile);
|
|
15463
15933
|
pushRoute({ node: node2, parentPath, path: typeof pathValue === "string" ? pathValue : "", index, ...component ? { component } : {}, candidates, ...redirectTo ? { redirectTo } : {} });
|
|
15464
|
-
if (
|
|
15934
|
+
if (ts9.isJsxElement(node2))
|
|
15465
15935
|
for (const child of node2.children)
|
|
15466
15936
|
visit2(child, fullPath);
|
|
15467
15937
|
return;
|
|
15468
15938
|
}
|
|
15469
15939
|
}
|
|
15470
|
-
if (
|
|
15940
|
+
if (ts9.isCallExpression(node2)) {
|
|
15471
15941
|
const callee = node2.expression.getText(parsed.sourceFile);
|
|
15472
|
-
if ((callee === "createBrowserRouter" || callee === "createHashRouter" || callee === "useRoutes") && node2.arguments[0] &&
|
|
15942
|
+
if ((callee === "createBrowserRouter" || callee === "createHashRouter" || callee === "useRoutes") && node2.arguments[0] && ts9.isArrayLiteralExpression(node2.arguments[0])) {
|
|
15473
15943
|
visitRouteObjects(node2.arguments[0], mountPath);
|
|
15474
15944
|
}
|
|
15475
15945
|
}
|
|
15476
|
-
|
|
15946
|
+
ts9.forEachChild(node2, (child) => visit2(child, parentPath));
|
|
15477
15947
|
};
|
|
15478
15948
|
visit2(parsed.sourceFile, mountPath);
|
|
15479
15949
|
return routes.sort((left, right) => left.fullPath.localeCompare(right.fullPath) || left.location.startLine - right.location.startLine || left.location.startColumn - right.location.startColumn);
|
|
15480
15950
|
}
|
|
15481
15951
|
// src/moduleExports.ts
|
|
15482
|
-
import * as
|
|
15952
|
+
import * as ts10 from "typescript";
|
|
15483
15953
|
function exportedDeclarationName(statement) {
|
|
15484
|
-
const exported =
|
|
15954
|
+
const exported = ts10.canHaveModifiers(statement) && ts10.getModifiers(statement)?.some((modifier) => modifier.kind === ts10.SyntaxKind.ExportKeyword);
|
|
15485
15955
|
if (!exported)
|
|
15486
15956
|
return;
|
|
15487
|
-
if ((
|
|
15957
|
+
if ((ts10.isFunctionDeclaration(statement) || ts10.isClassDeclaration(statement) || ts10.isInterfaceDeclaration(statement) || ts10.isTypeAliasDeclaration(statement) || ts10.isEnumDeclaration(statement)) && statement.name) {
|
|
15488
15958
|
return statement.name.text;
|
|
15489
15959
|
}
|
|
15490
15960
|
return;
|
|
@@ -15495,17 +15965,17 @@ function extractTypeScriptModuleExports(source, filePath = "module.ts") {
|
|
|
15495
15965
|
const wildcard = new Set;
|
|
15496
15966
|
const targets = new Set;
|
|
15497
15967
|
for (const statement of sourceFile.statements) {
|
|
15498
|
-
if (
|
|
15499
|
-
const target = statement.moduleSpecifier &&
|
|
15968
|
+
if (ts10.isExportDeclaration(statement)) {
|
|
15969
|
+
const target = statement.moduleSpecifier && ts10.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : undefined;
|
|
15500
15970
|
if (target)
|
|
15501
15971
|
targets.add(target);
|
|
15502
15972
|
if (!statement.exportClause) {
|
|
15503
15973
|
if (target)
|
|
15504
15974
|
wildcard.add(target);
|
|
15505
|
-
} else if (
|
|
15975
|
+
} else if (ts10.isNamedExports(statement.exportClause)) {
|
|
15506
15976
|
for (const element of statement.exportClause.elements)
|
|
15507
15977
|
named.add(element.name.text);
|
|
15508
|
-
} else if (
|
|
15978
|
+
} else if (ts10.isNamespaceExport(statement.exportClause)) {
|
|
15509
15979
|
named.add(statement.exportClause.name.text);
|
|
15510
15980
|
}
|
|
15511
15981
|
continue;
|
|
@@ -15513,9 +15983,9 @@ function extractTypeScriptModuleExports(source, filePath = "module.ts") {
|
|
|
15513
15983
|
const declarationName2 = exportedDeclarationName(statement);
|
|
15514
15984
|
if (declarationName2)
|
|
15515
15985
|
named.add(declarationName2);
|
|
15516
|
-
if (
|
|
15986
|
+
if (ts10.isVariableStatement(statement) && ts10.getModifiers(statement)?.some((modifier) => modifier.kind === ts10.SyntaxKind.ExportKeyword)) {
|
|
15517
15987
|
for (const declaration of statement.declarationList.declarations) {
|
|
15518
|
-
if (
|
|
15988
|
+
if (ts10.isIdentifier(declaration.name))
|
|
15519
15989
|
named.add(declaration.name.text);
|
|
15520
15990
|
}
|
|
15521
15991
|
}
|
|
@@ -15580,6 +16050,8 @@ export {
|
|
|
15580
16050
|
extractReactRouterRoutes,
|
|
15581
16051
|
extractEcmaScriptModuleExports,
|
|
15582
16052
|
ecmaScriptLanguage,
|
|
16053
|
+
componentPropsName,
|
|
16054
|
+
componentBindingDefaults,
|
|
15583
16055
|
TypeScriptPlugin,
|
|
15584
16056
|
EXTRACT_TS_COVERAGE_TIER,
|
|
15585
16057
|
EXTRACT_TS_CAPABILITIES
|