From 5fd239f0dcea60a689b50bf1e19e0541e856293f Mon Sep 17 00:00:00 2001 From: David Date: Tue, 23 Jan 2018 12:53:34 +0100 Subject: [PATCH] feat(typescript): resolve typescript module paths derived by compilerOptions --- typescript/src/api-doc-types/ModuleDoc.ts | 1 + .../processors/readTypeScriptModules/index.ts | 3 ++- typescript/src/services/TsParser/index.ts | 1 + .../TsParser/resolveModulePath.spec.ts | 23 ++++++++++++++++ .../services/TsParser/resolveModulePath.ts | 27 +++++++++++++++++++ 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 typescript/src/services/TsParser/resolveModulePath.spec.ts create mode 100644 typescript/src/services/TsParser/resolveModulePath.ts diff --git a/typescript/src/api-doc-types/ModuleDoc.ts b/typescript/src/api-doc-types/ModuleDoc.ts index 1808ff75..1618269d 100644 --- a/typescript/src/api-doc-types/ModuleDoc.ts +++ b/typescript/src/api-doc-types/ModuleDoc.ts @@ -22,6 +22,7 @@ export class ModuleDoc implements ApiDoc { path: string; outputPath: string; content: string; + importFrom?: string; constructor(public symbol: ModuleSymbol, public basePath: string, public namespacesToInclude: string[], public hidePrivateMembers: boolean, public typeChecker: TypeChecker) {} } diff --git a/typescript/src/processors/readTypeScriptModules/index.ts b/typescript/src/processors/readTypeScriptModules/index.ts index 0dbc0899..d01533a5 100644 --- a/typescript/src/processors/readTypeScriptModules/index.ts +++ b/typescript/src/processors/readTypeScriptModules/index.ts @@ -2,7 +2,7 @@ const path = require('canonical-path'); import { DocCollection, Processor } from 'dgeni'; import { getCombinedModifierFlags, getLineAndCharacterOfPosition, ModifierFlags, Node, SourceFile, Symbol, SymbolFlags, TypeChecker } from 'typescript'; -import { getContent, getExportDocType, ModuleSymbols, TsParser } from '../../services/TsParser'; +import { getContent, getExportDocType, ModuleSymbols, resolveModulePath, TsParser } from '../../services/TsParser'; import { Location } from '../../services/TsParser/Location'; import { ApiDoc } from '../../api-doc-types/ApiDoc'; @@ -80,6 +80,7 @@ export class ReadTypeScriptModules implements Processor { moduleSymbols.forEach(moduleSymbol => { // Create a doc for this module and add it to the module lookup collection and the docs collection const moduleDoc = new ModuleDoc(moduleSymbol, basePath, this.namespacesToInclude, this.hidePrivateMembers, moduleSymbols.typeChecker!); + moduleDoc.importFrom = resolveModulePath(moduleSymbol, this.tsParser.options); this.modules[moduleDoc.id] = moduleDoc; docs.push(moduleDoc); this.addExportDocs(docs, moduleDoc); diff --git a/typescript/src/services/TsParser/index.ts b/typescript/src/services/TsParser/index.ts index b89632a7..498af8b9 100644 --- a/typescript/src/services/TsParser/index.ts +++ b/typescript/src/services/TsParser/index.ts @@ -7,6 +7,7 @@ const path = require('canonical-path'); export { getExportDocType } from './getExportDocType'; export { getContent } from './getContent'; export { getAccessibility } from './getAccessibility'; +export { resolveModulePath } from './resolveModulePath'; export interface ModuleSymbols extends Array { typeChecker?: TypeChecker; diff --git a/typescript/src/services/TsParser/resolveModulePath.spec.ts b/typescript/src/services/TsParser/resolveModulePath.spec.ts new file mode 100644 index 00000000..64b6de21 --- /dev/null +++ b/typescript/src/services/TsParser/resolveModulePath.spec.ts @@ -0,0 +1,23 @@ +import { TsParser } from '.'; +import { resolveModulePath } from './resolveModulePath'; +const path = require('canonical-path'); + +describe('resolveModulePath', () => { + let parser: TsParser; + let basePath: string; + beforeEach(() => { + parser = new TsParser(require('dgeni/lib/mocks/log')(false)); + basePath = path.resolve(__dirname, '../../mocks'); + }); + + it('should return the resolved module path derived by compilerOptions.paths', () => { + parser.options.paths = { + '@foo/bar': ['./tsParser/getExportDocType.test.ts'] + }; + + const parseInfo = parser.parse(['tsParser/getExportDocType.test.ts'], basePath); + const moduleSymbol = parseInfo.moduleSymbols[0]; + + expect(resolveModulePath(moduleSymbol, parser.options)).toEqual('@foo/bar'); + }); +}); diff --git a/typescript/src/services/TsParser/resolveModulePath.ts b/typescript/src/services/TsParser/resolveModulePath.ts new file mode 100644 index 00000000..d24469f9 --- /dev/null +++ b/typescript/src/services/TsParser/resolveModulePath.ts @@ -0,0 +1,27 @@ +import * as path from 'path'; +import { CompilerOptions, Symbol } from 'typescript'; + +/** + * Resolves the TypeScript module import path derived by the `paths` in `TypeScriptPackagesDef`. + * + * Implements a reverse lookup of the TypeScript `compilerOptions.paths` mapping. + * + * Example: `'@my/foo: ['./src/index.ts']` is the paths mapping. + * TODO: add test spec + */ +export function resolveModulePath(symbol: Symbol, options: CompilerOptions): string | undefined { + if (!options.paths) { + return; + } + const paths = options.paths || []; + const tsModules = Object.keys(paths); + + // Relative file path of this document, e.g. 'a/b/public_api.ts' + const fileName = symbol.valueDeclaration!.getSourceFile().fileName; + + // Find the TypeScript module path, e.g. '@my/foo' + const typeScriptModule = tsModules.find(tsModule => paths[tsModule] + .some(p => path.normalize(p) === fileName)); + + return typeScriptModule; +}