From d9ead78e8cc4cf3a87f26b7044a0f8b8beb0a8eb Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 1 Feb 2019 20:10:31 -0800 Subject: [PATCH] Map dts file to sections to write and fix from --- src/compiler/emitter.ts | 77 ++++++++++++++++++----- src/compiler/factory.ts | 63 +++++++++++++++++++ src/compiler/transformers/declarations.ts | 1 + src/compiler/types.ts | 11 +++- src/compiler/utilities.ts | 3 +- 5 files changed, 138 insertions(+), 17 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a318b374e1f..5c54d883483 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -51,7 +51,7 @@ namespace ts { const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options); const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined; const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; - const buildInfoPath = jsFilePath && (options.composite || hasPrependReference(projectReferences)) ? combinePaths(getDirectoryPath(jsFilePath), infoFile) : undefined; + const buildInfoPath = outPath && (options.composite || hasPrependReference(projectReferences)) ? combinePaths(getDirectoryPath(outPath), infoFile) : undefined; return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }; } @@ -132,7 +132,7 @@ namespace ts { }; function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) { - if (buildInfoPath && !emitOnlyDtsFiles) buildInfo = { js: [], dts: [], commonSourceDirectory: host.getCommonSourceDirectory(), sources: {} }; + if (buildInfoPath) buildInfo = { js: [], dts: [], commonSourceDirectory: host.getCommonSourceDirectory(), sources: {} }; emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, buildInfo && { sections: buildInfo.js, sources: buildInfo.sources }); emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, buildInfo && { sections: buildInfo.dts, sources: buildInfo.sources }); // Write bundled offset information if applicable @@ -498,13 +498,19 @@ namespace ts { buildInfo, /*onlyOwnText*/ true ); + const optionsWithoutDeclaration = clone(config.options); + optionsWithoutDeclaration.declaration = false; + optionsWithoutDeclaration.composite = false; const outputFiles: OutputFile[] = []; + const newBuildInfo: BuildInfo = clone(buildInfo); + let writeByteOrderMarkBuildInfo = false; + const prependNodes = createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f)); const emitHost: EmitHost = { - getPrependNodes: () => createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f)). concat(ownPrependInput), + getPrependNodes: () => prependNodes.concat(ownPrependInput), getProjectReferences: () => config.projectReferences, getCanonicalFileName: host.getCanonicalFileName, getCommonSourceDirectory: () => buildInfo.commonSourceDirectory, - getCompilerOptions: () => config.options, + getCompilerOptions: () => optionsWithoutDeclaration, getCurrentDirectory: () => host.getCurrentDirectory(), getNewLine: () => host.getNewLine(), getSourceFile: notImplemented, @@ -513,30 +519,56 @@ namespace ts { getLibFileFromReference: notImplemented, isSourceFileFromExternalLibrary: notImplemented, writeFile: (name, text, writeByteOrderMark) => { - // no need to write dts file - if (fileExtensionIs(name, Extension.Dts)) return; - if (name === buildInfoPath) { + if (name !== buildInfoPath) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + else { // Add dts and sources build info since we are not touching that file - const newBuildInfo = JSON.parse(text) as BuildInfo; - newBuildInfo.dts = buildInfo.dts; - newBuildInfo.sources = buildInfo.sources; - text = getBuildInfoText(newBuildInfo); + const buildInfo = JSON.parse(text) as BuildInfo; + newBuildInfo.js = buildInfo.js; + writeByteOrderMarkBuildInfo = writeByteOrderMarkBuildInfo || writeByteOrderMark; } - outputFiles.push({ name, text, writeByteOrderMark }); }, isEmitBlocked: returnFalse, readFile: f => host.readFile(f), fileExists: f => host.fileExists(f), - ...(host.directoryExists ? { directoryExists: f => host.directoryExists!(f) } : {}), + directoryExists: host.directoryExists && (f => host.directoryExists!(f)), useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(), }; + // Emit js emitFiles( notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, /*emitOnlyDtsFiles*/ false, - getTransformers(config.options) + getTransformers(optionsWithoutDeclaration) ); + // Emit d.ts map + if (declarationMapText) { + emitHost.getPrependNodes = () => [createUnparsedDtsSourceFileWithPrepend(ownPrependInput, prependNodes)]; + emitHost.getCompilerOptions = () => config.options; + emitHost.writeFile = (name, text, writeByteOrderMark) => { + // Same dts ignore + if (fileExtensionIs(name, Extension.Dts)) return; + if (name !== buildInfoPath) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + else { + // Add dts and sources build info since we are not touching that file + const buildInfo = JSON.parse(text) as BuildInfo; + newBuildInfo.dts = buildInfo.dts; + writeByteOrderMarkBuildInfo = writeByteOrderMarkBuildInfo || writeByteOrderMark; + } + }; + emitFiles( + notImplementedResolver, + emitHost, + /*targetSourceFile*/ undefined, + /*emitOnlyDtsFiles*/ true + ); + } + outputFiles.push({ name: buildInfoPath!, text: getBuildInfoText(newBuildInfo), writeByteOrderMark: writeByteOrderMarkBuildInfo }); + console.log(JSON.stringify(outputFiles, undefined, 2)); return outputFiles; } @@ -882,6 +914,10 @@ namespace ts { case SyntaxKind.UnparsedSourceMapUrl: return emitUnparsedNode(node); + case SyntaxKind.UnparsedSectionText: + return emitUnparsedSectionText(node); + + // Identifiers case SyntaxKind.Identifier: return emitIdentifier(node); @@ -1391,6 +1427,7 @@ namespace ts { // SyntaxKind.UnparsedSource function emitUnparsedSource(unparsed: UnparsedSource) { for (const text of unparsed.texts) { + writeLine(); emit(text); } } @@ -1402,6 +1439,18 @@ namespace ts { writer.rawWrite(unparsed.parent.text.substring(unparsed.pos, unparsed.end)); } + // SyntaxKind.UnparsedSectionText + function emitUnparsedSectionText(unparsed: UnparsedSectionText) { + const pos = getTextPosWithWriteLine(); + emitUnparsedNode(unparsed); + if (bundleFileInfo) { + const section = clone(unparsed.section); + section.pos = pos; + section.end = writer.getTextPos(); + bundleFileInfo.sections.push(section); + } + } + // // Identifiers // diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d2180c18f9f..e7d69a46b0b 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2728,6 +2728,61 @@ namespace ts { return node; } + /*@internal*/ + export function createUnparsedDtsSourceFileWithPrepend(input: InputFiles, prepends: ReadonlyArray): UnparsedSource { + Debug.assert(!!input.oldFileOfCurrentEmit); + const node = createNode(SyntaxKind.UnparsedSource); + node.oldFileOfCurrentEmit = true; + node.fileName = Debug.assertDefined(input.declarationPath); + node.sourceMapPath = Debug.assertDefined(input.declarationMapPath); + node.text = input.declarationText; + node.sourceMapText = input.declarationMapText; + const mapOfPrepend = arrayToMap(prepends, prepend => prepend.declarationPath!, prepend => createUnparsedSourceFile(prepend, "dts")); + const texts: UnparsedSourceText[] = []; + const sections = input.buildInfo!.dts; + for (const section of sections) { + switch (section.kind) { + case BundleFileSectionKind.NoDefaultLib: + case BundleFileSectionKind.Reference: + case BundleFileSectionKind.Type: + case BundleFileSectionKind.Lib: + texts.push(createUnparsedSectionText(section, node)); + break; + + case BundleFileSectionKind.Prepend: + const parent = mapOfPrepend.get(section.data)!; + const sectionNode = createUnparsedSectionText(section, parent); + sectionNode.pos = parent.texts[0].pos; + sectionNode.end = last(parent.texts).end; + texts.push(sectionNode); + break; + + case BundleFileSectionKind.Text: + texts.push(createUnparsedNode(section, node) as UnparsedSourceText); + break; + + // Ignore + case BundleFileSectionKind.SourceMapUrl: + break; + + // Should never have + case BundleFileSectionKind.Prologue: + case BundleFileSectionKind.EmitHelpers: + Debug.fail(`Dts shouldnt have section: ${JSON.stringify(section)}`); + break; + + default: + Debug.assertNever(section); + } + } + node.prologues = emptyArray; + node.referencedFiles = emptyArray; + node.libReferenceDirectives = emptyArray; + node.texts = texts; + node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos); + return node; + } + function mapBundleFileSectionKindToSyntaxKind(kind: BundleFileSectionKind): SyntaxKind { switch (kind) { case BundleFileSectionKind.Prologue: return SyntaxKind.UnparsedPrologue; @@ -2754,6 +2809,14 @@ namespace ts { return node; } + function createUnparsedSectionText(section: BundleFileSection, parent: UnparsedSource) { + const node = createNode(SyntaxKind.UnparsedSectionText, section.pos, section.end) as UnparsedSectionText; + node.parent = parent; + node.data = section.data; + node.section = section; + return node; + } + export function createInputFiles( javascriptText: string, declarationText: string diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index a3139ffc37c..a4361e17248 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -214,6 +214,7 @@ namespace ts { collectLibs(sourceFile, libs); return sourceFile; } + return prepend; })); bundle.syntheticFileReferences = []; bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 33cda79bf4a..7778897b09f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -433,6 +433,7 @@ namespace ts { UnparsedPrependText, UnparsedText, UnparsedSourceMapUrl, + UnparsedSectionText, // Top-level nodes SourceFile, @@ -2803,7 +2804,7 @@ namespace ts { getLineAndCharacterOfPosition(pos: number): LineAndCharacter; } - export type UnparsedSourceText = UnparsedPrependText | UnparsedText | UnparsedSourceMapUrl; + export type UnparsedSourceText = UnparsedPrependText | UnparsedText | UnparsedSourceMapUrl | UnparsedSectionText; export type UnparsedNode = UnparsedPrologue | UnparsedSourceText; export interface UnparsedSection extends Node { @@ -2834,6 +2835,12 @@ namespace ts { parent: UnparsedSource; } + export interface UnparsedSectionText extends UnparsedSection { + kind: SyntaxKind.UnparsedSectionText; + parent: UnparsedSource; + section: BundleFileSection; + } + export interface JsonSourceFile extends SourceFile { statements: NodeArray; } @@ -5311,7 +5318,7 @@ namespace ts { isEmitBlocked(emitFileName: string): boolean; - getPrependNodes(): ReadonlyArray; + getPrependNodes(): ReadonlyArray; getProjectReferences(): ReadonlyArray | undefined; writeFile: WriteFileCallback; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0970ec22490..28e78e9e236 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5994,7 +5994,8 @@ namespace ts { return node.kind === SyntaxKind.UnparsedPrologue || node.kind === SyntaxKind.UnparsedPrependText || node.kind === SyntaxKind.UnparsedText || - node.kind === SyntaxKind.UnparsedSourceMapUrl; + node.kind === SyntaxKind.UnparsedSourceMapUrl || + node.kind === SyntaxKind.UnparsedSectionText; } // JSDoc