diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6b900302c96df..43f542270d9d8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1324,7 +1324,10 @@ function setExternalModuleIndicator(sourceFile: SourceFile) { sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); } -export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { +export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile; +/** @internal */ +export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes?: boolean, scriptKind?: ScriptKind, skipNonSemanticJSDoc?: boolean): SourceFile; +export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, skipNonSemanticJSDoc?: boolean): SourceFile { tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); performance.mark("beforeParse"); let result: SourceFile; @@ -1336,14 +1339,14 @@ export function createSourceFile(fileName: string, sourceText: string, languageV impliedNodeFormat: format, } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); if (languageVersion === ScriptTarget.JSON) { - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); + result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop, skipNonSemanticJSDoc); } else { const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { file.impliedNodeFormat = format; return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); }; - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); + result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator, skipNonSemanticJSDoc); } perfLogger?.logStopParseSourceFile(); @@ -1575,7 +1578,16 @@ namespace Parser { var parseErrorBeforeNextFinishedNode = false; /* eslint-enable no-var */ - export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { + export function parseSourceFile( + fileName: string, + sourceText: string, + languageVersion: ScriptTarget, + syntaxCursor: IncrementalParser.SyntaxCursor | undefined, + setParentNodes = false, + scriptKind?: ScriptKind, + setExternalModuleIndicatorOverride?: (file: SourceFile) => void, + skipNonSemanticJSDoc?: boolean, + ): SourceFile { scriptKind = ensureScriptKind(fileName, scriptKind); if (scriptKind === ScriptKind.JSON) { const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); @@ -1589,9 +1601,10 @@ namespace Parser { return result; } - initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); + skipNonSemanticJSDoc = !!skipNonSemanticJSDoc && scriptKind !== ScriptKind.JS && scriptKind !== ScriptKind.JSX; + initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind, skipNonSemanticJSDoc); - const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); + const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator, skipNonSemanticJSDoc); clearState(); @@ -1600,7 +1613,7 @@ namespace Parser { export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { // Choice of `isDeclarationFile` should be arbitrary - initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); + initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS, /*skipNonSemanticJSDoc*/ false); // Prime the scanner. nextToken(); const entityName = parseEntityName(/*allowReservedWords*/ true); @@ -1610,7 +1623,7 @@ namespace Parser { } export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { - initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); + initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON, /*skipNonSemanticJSDoc*/ false); sourceFlags = contextFlags; // Prime the scanner. @@ -1698,7 +1711,7 @@ namespace Parser { return result; } - function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { + function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind, _skipNonSemanticJSDoc: boolean) { NodeConstructor = objectAllocator.getNodeConstructor(); TokenConstructor = objectAllocator.getTokenConstructor(); IdentifierConstructor = objectAllocator.getIdentifierConstructor(); @@ -1739,6 +1752,7 @@ namespace Parser { scanner.setOnError(scanError); scanner.setScriptTarget(languageVersion); scanner.setLanguageVariant(languageVariant); + scanner.setSkipNonSemanticJSDoc(_skipNonSemanticJSDoc); } function clearState() { @@ -1746,6 +1760,7 @@ namespace Parser { scanner.clearCommentDirectives(); scanner.setText(""); scanner.setOnError(undefined); + scanner.setSkipNonSemanticJSDoc(false); // Clear any data. We don't want to accidentally hold onto it for too long. sourceText = undefined!; @@ -1762,7 +1777,7 @@ namespace Parser { topLevel = true; } - function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { + function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void, skipNonSemanticJSDoc: boolean): SourceFile { const isDeclarationFile = isDeclarationFileName(fileName); if (isDeclarationFile) { contextFlags |= NodeFlags.Ambient; @@ -1789,6 +1804,7 @@ namespace Parser { sourceFile.identifierCount = identifierCount; sourceFile.identifiers = identifiers; sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); + sourceFile.skipNonSemanticJSDoc = skipNonSemanticJSDoc; if (jsDocDiagnostics) { sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); } @@ -8670,7 +8686,7 @@ namespace Parser { export namespace JSDocParser { export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined { - initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS); + initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, /*skipNonSemanticJSDoc*/ false); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); @@ -8720,7 +8736,7 @@ namespace Parser { } export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined { - initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS); + initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, /*skipNonSemanticJSDoc*/ false); const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile; @@ -9788,7 +9804,7 @@ namespace IncrementalParser { if (sourceFile.statements.length === 0) { // If we don't have any statements in the current source file, then there's no real // way to incrementally parse. So just do a full parse instead. - return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.skipNonSemanticJSDoc); } // Make sure we're not trying to incrementally update a source file more than once. Once @@ -9851,7 +9867,7 @@ namespace IncrementalParser { // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.skipNonSemanticJSDoc); result.commentDirectives = getNewCommentDirectives( sourceFile.commentDirectives, result.commentDirectives, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 13a3c37bc4126..113c956179188 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -402,6 +402,7 @@ export function createGetSourceFile( readFile: ProgramHost["readFile"], getCompilerOptions: () => CompilerOptions, setParentNodes: boolean | undefined, + skipNonSemanticJSDocParsing: boolean | undefined, ): CompilerHost["getSourceFile"] { return (fileName, languageVersionOrOptions, onError) => { let text: string | undefined; @@ -417,7 +418,7 @@ export function createGetSourceFile( } text = ""; } - return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes) : undefined; + return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes, /*scriptKind*/ undefined, skipNonSemanticJSDocParsing) : undefined; }; } @@ -455,7 +456,12 @@ export function createWriteFileMeasuringIO( } /** @internal */ -export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system: System = sys): CompilerHost { +export function createCompilerHostWorker( + options: CompilerOptions, + setParentNodes?: boolean, + skipNonSemanticJSDocParsing?: boolean, + system: System = sys, +): CompilerHost { const existingDirectories = new Map(); const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames); function directoryExists(directoryPath: string): boolean { @@ -476,7 +482,7 @@ export function createCompilerHostWorker(options: CompilerOptions, setParentNode const newLine = getNewLineCharacter(options); const realpath = system.realpath && ((path: string) => system.realpath!(path)); const compilerHost: CompilerHost = { - getSourceFile: createGetSourceFile(fileName => compilerHost.readFile(fileName), () => options, setParentNodes), + getSourceFile: createGetSourceFile(fileName => compilerHost.readFile(fileName), () => options, setParentNodes, skipNonSemanticJSDocParsing), getDefaultLibLocation, getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)), writeFile: createWriteFileMeasuringIO( diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 5a519dc79dcfb..e5cd8e6e5a5a2 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -114,6 +114,8 @@ export interface Scanner { // callback returns something truthy, then the scanner state is not rolled back. The result // of invoking the callback is returned from this function. tryScan(callback: () => T): T; + /** @internal */ + setSkipNonSemanticJSDoc(skip: boolean): void; } /** @internal */ @@ -343,6 +345,11 @@ const commentDirectiveRegExSingleLine = /^\/\/\/?\s*@(ts-expect-error|ts-ignore) */ const commentDirectiveRegExMultiLine = /^(?:\/|\*)*\s*@(ts-expect-error|ts-ignore)/; +/** + * Test for whether a comment contains a JSDoc tag needed by the checker when run in tsc. + */ +const semanticJSDocTagRegEx = /@(?:see|link)/i; + function lookupInUnicodeMap(code: number, map: readonly number[]): boolean { // Bail out quickly if it couldn't possibly be in the map. if (code < map[0]) { @@ -1001,6 +1008,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean var commentDirectives: CommentDirective[] | undefined; var inJSDocType = 0; + var skipNonSemanticJSDoc = false; + setText(text, start, length); var scanner: Scanner = { @@ -1052,6 +1061,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean tryScan, lookAhead, scanRange, + setSkipNonSemanticJSDoc, }; /* eslint-enable no-var */ @@ -1971,9 +1981,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean // Multi-line comment if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash) { - tokenFlags |= TokenFlags.PrecedingJSDocComment; - } + const isJSDoc = text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash; let commentClosed = false; let lastLineStart = tokenStart; @@ -1994,6 +2002,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean } } + if (isJSDoc && (!skipNonSemanticJSDoc || semanticJSDocTagRegEx.test(text.slice(fullStartPos, pos)))) { + tokenFlags |= TokenFlags.PrecedingJSDocComment; + } + commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart); if (!commentClosed) { @@ -2775,6 +2787,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean languageVariant = variant; } + function setSkipNonSemanticJSDoc(skip: boolean) { + skipNonSemanticJSDoc = skip; + } + function resetTokenState(position: number) { Debug.assert(position >= 0); pos = position; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 85d8c8720c2bf..1b3d4c2a7cbef 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4297,6 +4297,8 @@ export interface SourceFile extends Declaration, LocalsContainer { /** @internal */ exportedModulesFromDeclarationEmit?: ExportedModulesFromDeclarationEmit; /** @internal */ endFlowNode?: FlowNode; + + /** @internal */ skipNonSemanticJSDoc?: boolean; } /** @internal */ diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index fd4d4a8b6ca28..9d7991a2984fb 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -746,6 +746,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost, getCom (fileName, encoding) => !encoding ? compilerHost.readFile(fileName) : host.readFile(fileName, encoding), getCompilerOptions, /*setParentNodes*/ undefined, + host.skipNonSemanticJSDocParsing, ), getDefaultLibLocation: maybeBind(host, host.getDefaultLibLocation), getDefaultLibFileName: options => host.getDefaultLibFileName(options), diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index e963067868d66..6f432177ac8d5 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -118,8 +118,11 @@ export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadB return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host); } -export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost { - const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, system); +export function createIncrementalCompilerHost(options: CompilerOptions, system?: System): CompilerHost; +/** @internal */ +export function createIncrementalCompilerHost(options: CompilerOptions, system?: System, skipNonSemanticJSDocParsing?: boolean): CompilerHost; +export function createIncrementalCompilerHost(options: CompilerOptions, system = sys, skipNonSemanticJSDocParsing?: boolean): CompilerHost { + const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, skipNonSemanticJSDocParsing, system); host.createHash = maybeBind(system, system.createHash); host.storeFilesChangingSignatureDuringEmit = system.storeFilesChangingSignatureDuringEmit; setGetSourceFileAsHashVersioned(host); @@ -254,6 +257,13 @@ export interface ProgramHost { * Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it */ getModuleResolutionCache?(): ModuleResolutionCache | undefined; + + /** + * True if it's safe for the parser to skip parsing non-semantic JSDoc tags. + * + * @internal + */ + skipNonSemanticJSDocParsing?: boolean; } /** * Internal interface used to wire emit through same host diff --git a/src/executeCommandLine/executeCommandLine.ts b/src/executeCommandLine/executeCommandLine.ts index e7b2a1167a19d..99aa3b345ba45 100644 --- a/src/executeCommandLine/executeCommandLine.ts +++ b/src/executeCommandLine/executeCommandLine.ts @@ -789,6 +789,9 @@ function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: Diagnos return false; } +// This could be inlined everywhere, but this is convenient for debugging and patching. +const skipNonSemanticJSDocParsing = true; + function performBuild( sys: System, cb: ExecuteCommandLineCallbacks, @@ -839,6 +842,7 @@ function performBuild( createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), createWatchStatusReporter(sys, buildOptions), ); + buildHost.skipNonSemanticJSDocParsing = skipNonSemanticJSDocParsing; const solutionPerformance = enableSolutionPerformance(sys, buildOptions); updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance); const onWatchStatusChange = buildHost.onWatchStatusChange; @@ -868,6 +872,7 @@ function performBuild( createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), createReportErrorSummary(sys, buildOptions), ); + buildHost.skipNonSemanticJSDocParsing = skipNonSemanticJSDocParsing; const solutionPerformance = enableSolutionPerformance(sys, buildOptions); updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance); const builder = createSolutionBuilder(buildHost, projects, buildOptions); @@ -890,7 +895,7 @@ function performCompilation( config: ParsedCommandLine, ) { const { fileNames, options, projectReferences } = config; - const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, sys); + const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, skipNonSemanticJSDocParsing, sys); const currentDirectory = host.getCurrentDirectory(); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName)); @@ -923,7 +928,7 @@ function performIncrementalCompilation( ) { const { options, fileNames, projectReferences } = config; enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false); - const host = createIncrementalCompilerHost(options, sys); + const host = createIncrementalCompilerHost(options, sys, skipNonSemanticJSDocParsing); const exitStatus = ts_performIncrementalCompilation({ host, system: sys, @@ -975,6 +980,7 @@ function updateWatchCompilationHost( cb: ExecuteCommandLineCallbacks, watchCompilerHost: WatchCompilerHost, ) { + watchCompilerHost.skipNonSemanticJSDocParsing = skipNonSemanticJSDocParsing; updateCreateProgram(sys, watchCompilerHost, /*isBuildMode*/ false); const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217 watchCompilerHost.afterProgramCreate = builderProgram => { diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index 1a3da111540f4..0d646f714d750 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -211,3 +211,4 @@ import "./unittests/tsserver/watchEnvironment"; import "./unittests/debugDeprecation"; import "./unittests/tsserver/inconsistentErrorInEditor"; import "./unittests/tsserver/getMoveToRefactoringFileSuggestions"; +import "./unittests/skipNonSemanticJSDocParsing"; diff --git a/src/testRunner/unittests/skipNonSemanticJSDocParsing.ts b/src/testRunner/unittests/skipNonSemanticJSDocParsing.ts new file mode 100644 index 0000000000000..94948e36e5855 --- /dev/null +++ b/src/testRunner/unittests/skipNonSemanticJSDocParsing.ts @@ -0,0 +1,60 @@ +import * as Harness from "../_namespaces/Harness"; +import * as ts from "../_namespaces/ts"; +import * as Utils from "../_namespaces/Utils"; + +describe("unittests:: skipNonSemanticJSDocParsing", () => { + const Diff = require("diff"); + + function diffSourceFiles(name: string, content: string) { + it(name, () => { + const sourceFile = ts.createSourceFile("file.ts", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ undefined, /*scriptKind*/ undefined); + assert.isTrue(sourceFile && sourceFile.parseDiagnostics.length === 0, "no errors issued"); + const sourceFileSkipped = ts.createSourceFile("file.ts", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ undefined, /*scriptKind*/ undefined, /*skipNonSemanticJSDoc*/ true); + assert.isTrue(sourceFileSkipped && sourceFileSkipped.parseDiagnostics.length === 0, "no errors issued"); + + const patch = Diff.createTwoFilesPatch("withJSDoc", "withoutJSDoc", Utils.sourceFileToJSON(sourceFile), Utils.sourceFileToJSON(sourceFileSkipped), "With JSDoc", "Without JSDoc"); + Harness.Baseline.runBaseline("skipNonSemanticJSDocParsing/" + name + ".diff", patch); + }); + } + + diffSourceFiles( + "deprecated", + ` +/** @deprecated */ +function imDeprecated() {} +imDeprecated() +/** + * {@see imDeprecated} + * @deprecated + */ +function imDeprecated2() {} +imDeprecated2() + `, + ); + + diffSourceFiles( + "see", + ` +/** + * @typedef {any} A + */ + +/** + * @see {@link A} + * @see {@linkcode A} + * @see {@linkplain A} + */ +let foo; + `, + ); + + diffSourceFiles( + "link", + ` +import type { A } from "./a"; + +/** {@link A} */ +export interface B {} + `, + ); +}); diff --git a/tests/baselines/reference/arrowFunctionJSDocAnnotation.symbols b/tests/baselines/reference/arrowFunctionJSDocAnnotation.symbols new file mode 100644 index 0000000000000..436532de7fbc0 --- /dev/null +++ b/tests/baselines/reference/arrowFunctionJSDocAnnotation.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/arrowFunctionJSDocAnnotation.ts] //// + +=== index.js === +/** + * @param {any} v + */ +function identity(v) { +>identity : Symbol(identity, Decl(index.js, 0, 0)) +>v : Symbol(v, Decl(index.js, 3, 18)) + + return v; +>v : Symbol(v, Decl(index.js, 3, 18)) +} + +const x = identity( +>x : Symbol(x, Decl(index.js, 7, 5)) +>identity : Symbol(identity, Decl(index.js, 0, 0)) + + /** + * @param {number} param + * @returns {number=} + */ + param => param +>param : Symbol(param, Decl(index.js, 7, 19)) +>param : Symbol(param, Decl(index.js, 7, 19)) + +); + diff --git a/tests/baselines/reference/arrowFunctionJSDocAnnotation.types b/tests/baselines/reference/arrowFunctionJSDocAnnotation.types new file mode 100644 index 0000000000000..962a6582b5bb6 --- /dev/null +++ b/tests/baselines/reference/arrowFunctionJSDocAnnotation.types @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/arrowFunctionJSDocAnnotation.ts] //// + +=== index.js === +/** + * @param {any} v + */ +function identity(v) { +>identity : (v: any) => any +>v : any + + return v; +>v : any +} + +const x = identity( +>x : any +>identity( /** * @param {number} param * @returns {number=} */ param => param) : any +>identity : (v: any) => any + + /** + * @param {number} param + * @returns {number=} + */ + param => param +>param => param : (param: number) => number | undefined +>param : number +>param : number + +); + diff --git a/tests/baselines/reference/skipNonSemanticJSDocParsing/deprecated.diff b/tests/baselines/reference/skipNonSemanticJSDocParsing/deprecated.diff new file mode 100644 index 0000000000000..12a169292e64b --- /dev/null +++ b/tests/baselines/reference/skipNonSemanticJSDocParsing/deprecated.diff @@ -0,0 +1,67 @@ +=================================================================== +--- withJSDoc With JSDoc ++++ withoutJSDoc Without JSDoc +@@ -8,9 +8,8 @@ + "0": { + "kind": "FunctionDeclaration", + "pos": 0, + "end": 46, +- "flags": "Deprecated", + "modifierFlagsCache": 0, + "transformFlags": 4194304, + "name": { + "kind": "Identifier", +@@ -40,43 +39,9 @@ + "hasTrailingComma": false, + "transformFlags": 0 + }, + "multiLine": false +- }, +- "jsDoc": [ +- { +- "kind": "JSDoc", +- "pos": 1, +- "end": 19, +- "flags": "JSDoc", +- "modifierFlagsCache": 0, +- "transformFlags": 0, +- "tags": { +- "0": { +- "kind": "JSDocDeprecatedTag", +- "pos": 5, +- "end": 17, +- "flags": "JSDoc", +- "modifierFlagsCache": 0, +- "transformFlags": 0, +- "tagName": { +- "kind": "Identifier", +- "pos": 6, +- "end": 16, +- "flags": "JSDoc", +- "modifierFlagsCache": 0, +- "transformFlags": 0, +- "escapedText": "deprecated" +- } +- }, +- "length": 1, +- "pos": 5, +- "end": 17, +- "hasTrailingComma": false, +- "transformFlags": 0 +- } +- } +- ] ++ } + }, + "1": { + "kind": "ExpressionStatement", + "pos": 46, +@@ -237,6 +202,6 @@ + "typeReferenceDirectives": [], + "libReferenceDirectives": [], + "amdDependencies": [], + "identifiers": {}, +- "skipNonSemanticJSDoc": false ++ "skipNonSemanticJSDoc": true + } +\ No newline at end of file diff --git a/tests/baselines/reference/skipNonSemanticJSDocParsing/link.diff b/tests/baselines/reference/skipNonSemanticJSDocParsing/link.diff new file mode 100644 index 0000000000000..e7b3e2a532791 --- /dev/null +++ b/tests/baselines/reference/skipNonSemanticJSDocParsing/link.diff @@ -0,0 +1,12 @@ +=================================================================== +--- withJSDoc With JSDoc ++++ withoutJSDoc Without JSDoc +@@ -220,6 +220,6 @@ + "typeReferenceDirectives": [], + "libReferenceDirectives": [], + "amdDependencies": [], + "identifiers": {}, +- "skipNonSemanticJSDoc": false ++ "skipNonSemanticJSDoc": true + } +\ No newline at end of file diff --git a/tests/baselines/reference/skipNonSemanticJSDocParsing/see.diff b/tests/baselines/reference/skipNonSemanticJSDocParsing/see.diff new file mode 100644 index 0000000000000..cbad93fc6bd33 --- /dev/null +++ b/tests/baselines/reference/skipNonSemanticJSDocParsing/see.diff @@ -0,0 +1,12 @@ +=================================================================== +--- withJSDoc With JSDoc ++++ withoutJSDoc Without JSDoc +@@ -307,6 +307,6 @@ + "typeReferenceDirectives": [], + "libReferenceDirectives": [], + "amdDependencies": [], + "identifiers": {}, +- "skipNonSemanticJSDoc": false ++ "skipNonSemanticJSDoc": true + } +\ No newline at end of file diff --git a/tests/cases/compiler/arrowFunctionJSDocAnnotation.ts b/tests/cases/compiler/arrowFunctionJSDocAnnotation.ts new file mode 100644 index 0000000000000..47f6c2b56574b --- /dev/null +++ b/tests/cases/compiler/arrowFunctionJSDocAnnotation.ts @@ -0,0 +1,21 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true +// @strict: true + +// @filename: index.js + +/** + * @param {any} v + */ +function identity(v) { + return v; +} + +const x = identity( + /** + * @param {number} param + * @returns {number=} + */ + param => param +);