@@ -1583,6 +1583,9 @@ namespace Parser {
15831583 // attached to the EOF token.
15841584 let parseErrorBeforeNextFinishedNode = false;
15851585
1586+ const tsPlusExternalTypeCache = new Map<string, Record<string, TsPlusTypeDefinition[]>>()
1587+ const tsPlusResolvedPathsCache = new Map<string, string[]>()
1588+ const tsPlusResolvedModuleCache = new Map<string, any>()
15861589 let currentTsPlusTypes: TsPlusTypeDefinition[] | null = null;
15871590 let currentTsPlusFile: string | null = null;
15881591
@@ -1821,16 +1824,20 @@ namespace Parser {
18211824 }
18221825 }
18231826
1824- function parseTsPlusExternalTypes (fileName: string, options: CompilerOptions) {
1827+ function getTsPlusExternalTypesPaths (fileName: string, options: CompilerOptions) {
18251828 if (options.configFilePath) {
1829+ if (tsPlusResolvedPathsCache.has(options.configFilePath)) {
1830+ return tsPlusResolvedPathsCache.get(options.configFilePath)!;
1831+ }
1832+
18261833 let resolvedPaths: string[] = [];
18271834 if (options.tsPlusTypes) {
18281835 for (const path of options.tsPlusTypes) {
18291836 if (pathIsRelative(path)) {
18301837 resolvedPaths.push(resolvePath(options.configFilePath.split("/").slice(0, -1).join('/'), path));
18311838 }
18321839 else {
1833- const { resolvedModule } = resolveModuleName(path, options.configFilePath, options, sys);
1840+ const resolvedModule = resolveModuleName(path, options.configFilePath, options, sys).resolvedModule ?? resolveModuleName(path, fileName, options, sys).resolvedModule ;
18341841 if (resolvedModule) {
18351842 resolvedPaths.push(resolvedModule.resolvedFileName);
18361843 break
@@ -1872,22 +1879,37 @@ namespace Parser {
18721879 }
18731880 }
18741881
1875- if (resolvedPaths.length === 0) {
1876- return;
1877- }
1882+ tsPlusResolvedPathsCache.set(options.configFilePath, resolvedPaths);
1883+ return resolvedPaths;
1884+ }
1885+ return [];
1886+ }
18781887
1879- for (const resolvedPath of resolvedPaths) {
1888+ function parseTsPlusExternalTypes(fileName: string, options: CompilerOptions) {
1889+ const resolvedPaths = getTsPlusExternalTypesPaths(fileName, options);
1890+ if (!resolvedPaths || resolvedPaths.length === 0) {
1891+ return
1892+ }
1893+ for (const resolvedPath of resolvedPaths) {
1894+ let json = tsPlusExternalTypeCache.get(resolvedPath);
1895+ if (!json) {
18801896 const text = sys.readFile(resolvedPath);
18811897 if (text) {
1882- const json = JSON.parse(text);
1883- for (const moduleName in json) {
1884- const { resolvedModule } = resolveModuleName(moduleName, resolvedPath, options, sys);
1885- if (resolvedModule && resolvedModule.resolvedFileName === fileName) {
1886- currentTsPlusTypes = json[moduleName];
1887- currentTsPlusFile = moduleName;
1888- return;
1889- }
1890- }
1898+ json = JSON.parse(text);
1899+ }
1900+ }
1901+ if (!json) return;
1902+ for (const moduleName in json) {
1903+ const key = `${options.configFilePath ?? fileName}+${moduleName}`;
1904+ let resolvedModule = tsPlusResolvedModuleCache.get(key);
1905+ if (!resolvedModule) {
1906+ resolvedModule = resolveModuleName(moduleName, resolvedPath, options, sys).resolvedModule ?? resolveModuleName(moduleName, fileName, options, sys).resolvedModule;
1907+ tsPlusResolvedModuleCache.set(key, resolvedModule);
1908+ }
1909+ if (resolvedModule && resolvedModule.resolvedFileName === fileName) {
1910+ currentTsPlusTypes = json[moduleName];
1911+ currentTsPlusFile = moduleName;
1912+ return;
18911913 }
18921914 }
18931915 }
@@ -1896,6 +1918,15 @@ namespace Parser {
18961918 function addTsPlusTagsFromExternalTypes(declaration: VariableDeclaration | FunctionDeclaration | InterfaceDeclaration | ClassDeclaration | TypeAliasDeclaration, jsDocNode?: HasJSDoc): void {
18971919 if (currentTsPlusTypes !== null) {
18981920 if (declaration.name && declaration.name.kind === SyntaxKind.Identifier) {
1921+ if (!jsDocNode) {
1922+ jsDocNode = declaration;
1923+ }
1924+ if (jsDocNode.jsDoc &&
1925+ jsDocNode.jsDoc[0] &&
1926+ jsDocNode.jsDoc[0].tags &&
1927+ jsDocNode.jsDoc[0].tags.find((tag) => tag.tagName.escapedText === 'tsplus')) {
1928+ return;
1929+ }
18991930 const extensions = currentTsPlusTypes.filter(
19001931 (type) =>
19011932 (declaration.kind === SyntaxKind.VariableDeclaration ? (type.definitionKind === "const")
@@ -1916,15 +1947,15 @@ namespace Parser {
19161947 newTags.push(factory.createJSDocUnknownTag(factory.createIdentifier("tsplus"), comment));
19171948 }
19181949 newTags.push(factory.createJSDocUnknownTag(factory.createIdentifier("tsplus"), `location "${currentTsPlusFile}"`))
1919- if (!jsDocNode) {
1920- jsDocNode = declaration;
1921- }
19221950 if (jsDocNode.jsDoc && jsDocNode.jsDoc[0]) {
1923- const jsDocTags = factory.createNodeArray( Array.from(jsDocNode.jsDoc[0].tags ?? []).concat(newTags))
1951+ const jsDocTags = Array.from(jsDocNode.jsDoc[0].tags ?? []).concat(newTags);
19241952 // @ts-expect-error
1925- jsDocNode.jsDoc[0].tags = jsDocTags;
1926- } else {
1927- jsDocNode.jsDoc = [factory.createJSDocComment(undefined, newTags)]
1953+ jsDocNode.jsDoc[0].tags = factory.createNodeArray(jsDocTags);
1954+ jsDocNode.jsDocCache = jsDocTags;
1955+ }
1956+ else {
1957+ jsDocNode.jsDoc = [factory.createJSDocComment(undefined, newTags)];
1958+ jsDocNode.jsDocCache = newTags;
19281959 }
19291960 }
19301961 }
@@ -7797,8 +7828,6 @@ namespace Parser {
77977828 const pipeableIndexTags: string[] = [];
77987829 let isImplicit = false;
77997830
7800- addTsPlusTagsFromExternalTypes(declaration)
7801-
78027831 for (const doc of jsDoc ?? []) {
78037832 if (doc.tags) {
78047833 for (const tag of doc.tags) {
@@ -7940,6 +7969,7 @@ namespace Parser {
79407969 const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body);
79417970 (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators;
79427971 const finished = withJSDoc(finishNode(node, pos), hasJSDoc);
7972+ addTsPlusTagsFromExternalTypes(finished);
79437973 addTsPlusValueTags(finished, finished.jsDoc);
79447974 return finished;
79457975 }
0 commit comments