Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate JsTrimmer summaries. #1481

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export function toClosureJS(
externs: {},
emitSkipped: true,
emittedFiles: [],
fileSummaries: new Map(),
};
}
return tsickle.emit(program, transformerHost, writeFile);
Expand Down
22 changes: 18 additions & 4 deletions src/googmodule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@ export function jsPathToNamespace(
host: GoogModuleProcessorHost, context: ts.Node,
diagnostics: ts.Diagnostic[], importPath: string,
getModuleSymbol: () => ts.Symbol | undefined): string|undefined {
const namespace = localJsPathToNamespace(host, importPath);
if (namespace) return namespace;

const moduleSymbol = getModuleSymbol();
if (!moduleSymbol) return;
return getGoogNamespaceFromClutzComments(
context, diagnostics, importPath, moduleSymbol);
}

/**
* Resolves an import path to its goog namespace, if it points to an original
* closure JavaScript file, using only local information.
*
* Forwards to `jsPathToModuleName` on the host if present.
*/
export function localJsPathToNamespace(
host: GoogModuleProcessorHost, importPath: string): string|undefined {
if (importPath.match(/^goog:/)) {
// This is a namespace import, of the form "goog:foo.bar".
// Fix it to just "foo.bar".
Expand All @@ -99,10 +116,7 @@ export function jsPathToNamespace(
return host.jsPathToModuleName(importPath);
}

const moduleSymbol = getModuleSymbol();
if (!moduleSymbol) return;
return getGoogNamespaceFromClutzComments(
context, diagnostics, importPath, moduleSymbol);
return undefined;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ export function relative(base: string, rel: string): string {
export function normalize(path: string): string {
return ts.resolvePath(path);
}

/** Wrapper around ts.resolvePath. */
export function resolve(path: string, ...paths: string[]): string {
return ts.resolvePath(path, ...paths);
}
125 changes: 125 additions & 0 deletions src/summary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/** The Type of an import, as used in JsTrimmer. */
export enum Type {
UNKNOWN = 0,
/** The symbol type for Closure namespace. */
CLOSURE,
/** The symbol type for a GSS namespace. */
GSS,
/** The symbol type for a Soy namespace. */
SOY,
/** The symbol type for an extensionless google3-relative CSS/GSS path. */
CSSPATH,
/** The symbol type for a google3-relative ES module path. */
ESPATH,
}

/** The module system used by a file. */
export enum ModuleType {
UNKNOWN = 0,
GOOG_PROVIDE,
GOOG_MODULE,
ES_MODULE,
}

/** A single imported symbol. */
export interface Symbol {
type: Type;
name: string;
}

/**
* The JsTrimmer file summary for a single file. Contains imported and
* exported symbols, as well as some other information required for sorting and
* pruning files.
*/
export class FileSummary {
// These sets are implemented as Maps of jsonified Symbol to Symbol because
// JavaScript Sets use object address, not object contents. Similarly, we use
// getters and setters for these to hide this implementation detail.
private readonly provideSet = new Map<string, Symbol>();
private readonly strongRequireSet = new Map<string, Symbol>();
private readonly weakRequireSet = new Map<string, Symbol>();
private readonly dynamicRequireSet = new Map<string, Symbol>();
private readonly modSet = new Map<string, Symbol>();
private readonly enhancedSet = new Map<string, Symbol>();
toggles: string[] = [];
modName: string|undefined;
autochunk = false;
enhanceable = false;
moduleType = ModuleType.UNKNOWN;

private stringify(symbol: Symbol): string {
return JSON.stringify(symbol);
}

addProvide(provide: Symbol) {
this.provideSet.set(this.stringify(provide), provide);
}

get provides(): Symbol[] {
return [...this.provideSet.values()];
}

addStrongRequire(strongRequire: Symbol) {
this.strongRequireSet.set(this.stringify(strongRequire), strongRequire);
}

get strongRequires(): Symbol[] {
return [...this.strongRequireSet.values()];
}

addWeakRequire(weakRequire: Symbol) {
this.weakRequireSet.set(this.stringify(weakRequire), weakRequire);
}

get weakRequires(): Symbol[] {
return [...this.weakRequireSet.values()];
}

addDynamicRequire(dynamicRequire: Symbol) {
this.dynamicRequireSet.set(this.stringify(dynamicRequire), dynamicRequire);
}

get dynamicRequires(): Symbol[] {
return [...this.dynamicRequireSet.values()];
}

addMods(mods: Symbol) {
this.modSet.set(this.stringify(mods), mods);
}

get mods(): Symbol[] {
return [...this.modSet.values()];
}

addEnhanced(enhanced: Symbol) {
this.enhancedSet.set(this.stringify(enhanced), enhanced);
}

get enhanced(): Symbol[] {
return [...this.enhancedSet.values()];
}
}

/** Provides dependencies for file generation. */
export interface SummaryGenerationProcessorHost {
/** @deprecated use unknownTypesPaths instead */
typeBlackListPaths?: Set<string>;

Check failure on line 115 in src/summary.ts

View check run for this annotation

In Solidarity / Inclusive Language

Match Found

Please consider an alternative to `BlackList`. Possibilities include: `exclude list`, `deny list`
Raw output
/black[_-]*list/gi
/** If provided, a set of paths whose types should always generate as {?}. */
unknownTypesPaths?: Set<string>;
/** See compiler_host.ts */
rootDirsRelative(fileName: string): string;
/**
* Whether to convert CommonJS require() imports to goog.module() and
* goog.require() calls.
*/
googmodule: boolean;
}
31 changes: 25 additions & 6 deletions src/ts_migration_exports_shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import * as ts from 'typescript';

import {ModulesManifest} from './modules_manifest';
import {FileSummary, ModuleType, Type} from './summary';
import {getGoogFunctionName, isAnyTsmesCall, isGoogCallExpressionOf, isTsmesDeclareLegacyNamespaceCall, isTsmesShorthandCall, reportDiagnostic} from './transformer_util';

/** Provides dependencies for file generation. */
Expand Down Expand Up @@ -46,7 +47,8 @@ export type TsMigrationExportsShimFileMap = Map<string, string>;
export function createTsMigrationExportsShimTransformerFactory(
typeChecker: ts.TypeChecker, host: TsMigrationExportsShimProcessorHost,
manifest: ModulesManifest, tsickleDiagnostics: ts.Diagnostic[],
outputFileMap: TsMigrationExportsShimFileMap):
outputFileMap: TsMigrationExportsShimFileMap,
fileSummaries: Map<string, FileSummary>):
ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
return (src: ts.SourceFile): ts.SourceFile => {
Expand All @@ -70,13 +72,17 @@ export function createTsMigrationExportsShimTransformerFactory(
// TODO(martinprobst): the empty files might cause issues with code
// that should be in mods or modules.
outputFileMap.set(tsmesFile, '');
const fileSummary = new FileSummary();
fileSummary.moduleType = ModuleType.UNKNOWN;
fileSummaries.set(tsmesFile, fileSummary);
if (context.getCompilerOptions().declaration) {
outputFileMap.set(dtsFile, '');
}
return src;
}
const result = generator.generateExportShimJavaScript();
outputFileMap.set(tsmesFile, result);
const [content, fileSummary] = generator.generateExportShimJavaScript();
outputFileMap.set(tsmesFile, content);
fileSummaries.set(tsmesFile, fileSummary);
if (context.getCompilerOptions().declaration) {
const dtsResult = generator.generateExportShimDeclarations();
outputFileMap.set(dtsFile, dtsResult);
Expand Down Expand Up @@ -396,7 +402,7 @@ class Generator {
*
* NOTE: This code must be written to be compatible as-is with IE11.
*/
generateExportShimJavaScript(): string {
generateExportShimJavaScript(): [string, FileSummary] {
if (!this.outputIds || !this.tsmesBreakdown) {
throw new Error('tsmes call must be extracted first');
}
Expand Down Expand Up @@ -427,11 +433,12 @@ class Generator {
this.manifest.addReferencedModule(
this.outputIds.google3Path, this.srcIds.googModuleId);

const pintoModuleAnnotation = containsAtPintoModule(this.src) ?
const isAutoChunk = containsAtPintoModule(this.src);
const pintoModuleAnnotation = isAutoChunk ?
'@pintomodule found in original_file' :
'pintomodule absent in original_file';

return lines(
const content = lines(
'/**',
' * @fileoverview generator:ts_migration_exports_shim.ts',
' * original_file:' + this.srcIds.google3Path,
Expand All @@ -443,6 +450,18 @@ class Generator {
exportsAssignment,
'',
);

const fileSummary = new FileSummary();
fileSummary.addProvide(
{type: Type.CLOSURE, name: this.outputIds.googModuleId});
fileSummary.addStrongRequire({type: Type.CLOSURE, name: 'goog'});
fileSummary.addStrongRequire(
{type: Type.CLOSURE, name: this.srcIds.googModuleId});

fileSummary.autochunk = isAutoChunk;
fileSummary.moduleType = ModuleType.GOOG_MODULE;

return [content, fileSummary];
}

/**
Expand Down
22 changes: 20 additions & 2 deletions src/tsickle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as googmodule from './googmodule';
import {jsdocTransformer, removeTypeAssertions} from './jsdoc_transformer';
import {ModulesManifest} from './modules_manifest';
import {namespaceTransformer} from './ns_transformer';
import {FileSummary, SummaryGenerationProcessorHost} from './summary';
import {isDtsFileName} from './transformer_util';
import * as tsmes from './ts_migration_exports_shim';
import {makeTsickleDeclarationMarkerTransformerFactory} from './tsickle_declaration_marker';
Expand All @@ -29,10 +30,12 @@ export {pathToModuleName} from './cli_support';
// Retained here for API compatibility.
export {getGeneratedExterns} from './externs';
export {FileMap, ModulesManifest} from './modules_manifest';
export {FileSummary, ModuleType, Symbol, Type} from './summary';

export interface TsickleHost extends googmodule.GoogModuleProcessorHost,
tsmes.TsMigrationExportsShimProcessorHost,
AnnotatorHost {
AnnotatorHost,
SummaryGenerationProcessorHost {
/**
* Whether to downlevel decorators
*/
Expand Down Expand Up @@ -79,6 +82,11 @@ export interface TsickleHost extends googmodule.GoogModuleProcessorHost,
* Whether to add suppressions by default.
*/
generateExtraSuppressions: boolean;

/**
* Whether to generate summaries.
*/
generateSummary?: boolean;
}


Expand All @@ -90,6 +98,7 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
{[fileName: string]: {output: string, moduleNamespace: string}} = {};
const modulesManifest = new ModulesManifest();
const tsMigrationExportsShimFiles = new Map<string, string>();
const fileSummaries = new Map<string, FileSummary>();
for (const er of emitResults) {
diagnostics.push(...er.diagnostics);
emitSkipped = emitSkipped || er.emitSkipped;
Expand All @@ -101,6 +110,9 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
for (const [k, v] of er.tsMigrationExportsShimFiles) {
tsMigrationExportsShimFiles.set(k, v);
}
for (const [k, v] of er.fileSummaries) {
fileSummaries.set(k, v);
}
}

return {
Expand All @@ -110,6 +122,7 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
externs,
tsMigrationExportsShimFiles,
modulesManifest,
fileSummaries,
};
}

Expand All @@ -127,6 +140,8 @@ export interface EmitResult extends ts.EmitResult {
* Filenames are google3 relative.
*/
tsMigrationExportsShimFiles: tsmes.TsMigrationExportsShimFileMap;

fileSummaries: Map<string, FileSummary>;
}

export interface EmitTransformers {
Expand Down Expand Up @@ -182,17 +197,19 @@ export function emit(
modulesManifest: new ModulesManifest(),
externs: {},
tsMigrationExportsShimFiles: new Map(),
fileSummaries: new Map(),
};
}

const modulesManifest = new ModulesManifest();
const tsMigrationExportsShimFiles = new Map<string, string>();
const tsickleSourceTransformers: Array<ts.TransformerFactory<ts.SourceFile>> =
[];
const fileSummaries = new Map<string, FileSummary>();
tsickleSourceTransformers.push(
tsmes.createTsMigrationExportsShimTransformerFactory(
typeChecker, host, modulesManifest, tsickleDiagnostics,
tsMigrationExportsShimFiles));
tsMigrationExportsShimFiles, fileSummaries));

if (host.transformTypesToClosure) {
// Only add @suppress {checkTypes} comments when also adding type
Expand Down Expand Up @@ -282,6 +299,7 @@ export function emit(
diagnostics: [...tsDiagnostics, ...tsickleDiagnostics],
externs,
tsMigrationExportsShimFiles,
fileSummaries,
};
}

Expand Down
Loading