diff --git a/apps/api-extractor/src/collector/SourceMapper.ts b/apps/api-extractor/src/collector/SourceMapper.ts index d044f9f1e6b..c0cefc12081 100644 --- a/apps/api-extractor/src/collector/SourceMapper.ts +++ b/apps/api-extractor/src/collector/SourceMapper.ts @@ -113,7 +113,9 @@ export class SourceMapper { column: sourceFileColumn }); - if (!nearestMappingItem) return; + // A segment with only a generated column marks code that has no original source. The "source-map" + // package reports it with a null originalLine, despite the MappingItem typings. + if (!nearestMappingItem || nearestMappingItem.originalLine === null) return; const mappedFilePath: string = path.resolve(path.dirname(sourceFilePath), nearestMappingItem.source); diff --git a/build-tests/api-extractor-scenarios/config/heft.json b/build-tests/api-extractor-scenarios/config/heft.json index df9febe88cb..1449eadc234 100644 --- a/build-tests/api-extractor-scenarios/config/heft.json +++ b/build-tests/api-extractor-scenarios/config/heft.json @@ -27,7 +27,7 @@ { "sourcePath": "src", "destinationFolders": ["lib-dts"], - "fileExtensions": [".d.ts"] + "fileExtensions": [".d.ts", ".d.ts.map"] } ] } diff --git a/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..c5b5f66e60e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.json @@ -0,0 +1,217 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!foo:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "foo: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "lib-dts/sourceMapWithoutSource/index.d.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "foo", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..8637b619d6e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/api-extractor-scenarios.api.md @@ -0,0 +1,12 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export const foo: string; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/rollup.d.ts new file mode 100644 index 00000000000..f53b70cfb3e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/sourceMapWithoutSource/rollup.d.ts @@ -0,0 +1,4 @@ +/** @public */ +export declare const foo: string; + +export { } diff --git a/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts b/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts new file mode 100644 index 00000000000..a48dcb5410b --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts @@ -0,0 +1,2 @@ +/** @public */ +export declare const foo: string; diff --git a/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts.map b/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts.map new file mode 100644 index 00000000000..4141439a3e5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/sourceMapWithoutSource/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","names":[],"sources":["index.ts"],"mappings":"A;A"} diff --git a/common/changes/@microsoft/api-extractor/fix-api-extractor-sourceless-mapping_2026-10-20-12-00.json b/common/changes/@microsoft/api-extractor/fix-api-extractor-sourceless-mapping_2026-10-20-12-00.json new file mode 100644 index 00000000000..18212536da1 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/fix-api-extractor-sourceless-mapping_2026-10-20-12-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "Fix a crash (\"Target is a folder, not a file\") when a .d.ts.map contains a mapping segment with no source, such as those emitted by rolldown.", + "type": "patch", + "packageName": "@microsoft/api-extractor" + } + ], + "packageName": "@microsoft/api-extractor" +}