Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 0d47bd4

Browse files
tsjs-language-engcopybara-github
authored andcommitted
Generate JsTrimmer summaries.
PiperOrigin-RevId: 574242891
1 parent 8b9daeb commit 0d47bd4

File tree

6 files changed

+194
-12
lines changed

6 files changed

+194
-12
lines changed

demo/demo.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ export function toClosureJS(
184184
externs: {},
185185
emitSkipped: true,
186186
emittedFiles: [],
187+
fileSummaries: new Map(),
187188
};
188189
}
189190
return tsickle.emit(program, transformerHost, writeFile);

src/googmodule.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,23 @@ export function jsPathToNamespace(
8989
host: GoogModuleProcessorHost, context: ts.Node,
9090
diagnostics: ts.Diagnostic[], importPath: string,
9191
getModuleSymbol: () => ts.Symbol | undefined): string|undefined {
92+
const namespace = localJsPathToNamespace(host, importPath);
93+
if (namespace) return namespace;
94+
95+
const moduleSymbol = getModuleSymbol();
96+
if (!moduleSymbol) return;
97+
return getGoogNamespaceFromClutzComments(
98+
context, diagnostics, importPath, moduleSymbol);
99+
}
100+
101+
/**
102+
* Resolves an import path to its goog namespace, if it points to an original
103+
* closure JavaScript file, using only local information.
104+
*
105+
* Forwards to `jsPathToModuleName` on the host if present.
106+
*/
107+
export function localJsPathToNamespace(
108+
host: GoogModuleProcessorHost, importPath: string): string|undefined {
92109
if (importPath.match(/^goog:/)) {
93110
// This is a namespace import, of the form "goog:foo.bar".
94111
// Fix it to just "foo.bar".
@@ -99,10 +116,7 @@ export function jsPathToNamespace(
99116
return host.jsPathToModuleName(importPath);
100117
}
101118

102-
const moduleSymbol = getModuleSymbol();
103-
if (!moduleSymbol) return;
104-
return getGoogNamespaceFromClutzComments(
105-
context, diagnostics, importPath, moduleSymbol);
119+
return undefined;
106120
}
107121

108122
/**

src/path.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ export function relative(base: string, rel: string): string {
4747
export function normalize(path: string): string {
4848
return ts.resolvePath(path);
4949
}
50+
51+
/** Wrapper around ts.resolvePath. */
52+
export function resolve(path: string, ...paths: string[]): string {
53+
return ts.resolvePath(path, ...paths);
54+
}

src/summary.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/** The Type of an import, as used in JsTrimmer. */
10+
export enum Type {
11+
UNKNOWN = 0,
12+
/** The symbol type for Closure namespace. */
13+
CLOSURE,
14+
/** The symbol type for a GSS namespace. */
15+
GSS,
16+
/** The symbol type for a Soy namespace. */
17+
SOY,
18+
/** The symbol type for an extensionless google3-relative CSS/GSS path. */
19+
CSSPATH,
20+
/** The symbol type for a google3-relative ES module path. */
21+
ESPATH,
22+
}
23+
24+
/** The module system used by a file. */
25+
export enum ModuleType {
26+
UNKNOWN = 0,
27+
GOOG_PROVIDE,
28+
GOOG_MODULE,
29+
ES_MODULE,
30+
}
31+
32+
/** A single imported symbol. */
33+
export interface Symbol {
34+
type: Type;
35+
name: string;
36+
}
37+
38+
/**
39+
* The JsTrimmer file summary for a single file. Contains imported and
40+
* exported symbols, as well as some other information required for sorting and
41+
* pruning files.
42+
*/
43+
export class FileSummary {
44+
// These sets are implemented as Maps of jsonified Symbol to Symbol because
45+
// JavaScript Sets use object address, not object contents. Similarly, we use
46+
// getters and setters for these to hide this implementation detail.
47+
private readonly provideSet = new Map<string, Symbol>();
48+
private readonly strongRequireSet = new Map<string, Symbol>();
49+
private readonly weakRequireSet = new Map<string, Symbol>();
50+
private readonly dynamicRequireSet = new Map<string, Symbol>();
51+
private readonly modSet = new Map<string, Symbol>();
52+
private readonly enhancedSet = new Map<string, Symbol>();
53+
toggles: string[] = [];
54+
modName: string|undefined;
55+
autochunk = false;
56+
enhanceable = false;
57+
moduleType = ModuleType.UNKNOWN;
58+
59+
private stringify(symbol: Symbol): string {
60+
return JSON.stringify(symbol);
61+
}
62+
63+
addProvide(provide: Symbol) {
64+
this.provideSet.set(this.stringify(provide), provide);
65+
}
66+
67+
get provides(): Symbol[] {
68+
return [...this.provideSet.values()];
69+
}
70+
71+
addStrongRequire(strongRequire: Symbol) {
72+
this.strongRequireSet.set(this.stringify(strongRequire), strongRequire);
73+
}
74+
75+
get strongRequires(): Symbol[] {
76+
return [...this.strongRequireSet.values()];
77+
}
78+
79+
addWeakRequire(weakRequire: Symbol) {
80+
this.weakRequireSet.set(this.stringify(weakRequire), weakRequire);
81+
}
82+
83+
get weakRequires(): Symbol[] {
84+
return [...this.weakRequireSet.values()];
85+
}
86+
87+
addDynamicRequire(dynamicRequire: Symbol) {
88+
this.dynamicRequireSet.set(this.stringify(dynamicRequire), dynamicRequire);
89+
}
90+
91+
get dynamicRequires(): Symbol[] {
92+
return [...this.dynamicRequireSet.values()];
93+
}
94+
95+
addMods(mods: Symbol) {
96+
this.modSet.set(this.stringify(mods), mods);
97+
}
98+
99+
get mods(): Symbol[] {
100+
return [...this.modSet.values()];
101+
}
102+
103+
addEnhanced(enhanced: Symbol) {
104+
this.enhancedSet.set(this.stringify(enhanced), enhanced);
105+
}
106+
107+
get enhanced(): Symbol[] {
108+
return [...this.enhancedSet.values()];
109+
}
110+
}
111+
112+
/** Provides dependencies for file generation. */
113+
export interface SummaryGenerationProcessorHost {
114+
/** @deprecated use unknownTypesPaths instead */
115+
typeBlackListPaths?: Set<string>;
116+
/** If provided, a set of paths whose types should always generate as {?}. */
117+
unknownTypesPaths?: Set<string>;
118+
/** See compiler_host.ts */
119+
rootDirsRelative(fileName: string): string;
120+
/**
121+
* Whether to convert CommonJS require() imports to goog.module() and
122+
* goog.require() calls.
123+
*/
124+
googmodule: boolean;
125+
}

src/ts_migration_exports_shim.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import * as ts from 'typescript';
1212

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

1617
/** Provides dependencies for file generation. */
@@ -46,7 +47,8 @@ export type TsMigrationExportsShimFileMap = Map<string, string>;
4647
export function createTsMigrationExportsShimTransformerFactory(
4748
typeChecker: ts.TypeChecker, host: TsMigrationExportsShimProcessorHost,
4849
manifest: ModulesManifest, tsickleDiagnostics: ts.Diagnostic[],
49-
outputFileMap: TsMigrationExportsShimFileMap):
50+
outputFileMap: TsMigrationExportsShimFileMap,
51+
fileSummaries: Map<string, FileSummary>):
5052
ts.TransformerFactory<ts.SourceFile> {
5153
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
5254
return (src: ts.SourceFile): ts.SourceFile => {
@@ -70,13 +72,17 @@ export function createTsMigrationExportsShimTransformerFactory(
7072
// TODO(martinprobst): the empty files might cause issues with code
7173
// that should be in mods or modules.
7274
outputFileMap.set(tsmesFile, '');
75+
const fileSummary = new FileSummary();
76+
fileSummary.moduleType = ModuleType.UNKNOWN;
77+
fileSummaries.set(tsmesFile, fileSummary);
7378
if (context.getCompilerOptions().declaration) {
7479
outputFileMap.set(dtsFile, '');
7580
}
7681
return src;
7782
}
78-
const result = generator.generateExportShimJavaScript();
79-
outputFileMap.set(tsmesFile, result);
83+
const [content, fileSummary] = generator.generateExportShimJavaScript();
84+
outputFileMap.set(tsmesFile, content);
85+
fileSummaries.set(tsmesFile, fileSummary);
8086
if (context.getCompilerOptions().declaration) {
8187
const dtsResult = generator.generateExportShimDeclarations();
8288
outputFileMap.set(dtsFile, dtsResult);
@@ -396,7 +402,7 @@ class Generator {
396402
*
397403
* NOTE: This code must be written to be compatible as-is with IE11.
398404
*/
399-
generateExportShimJavaScript(): string {
405+
generateExportShimJavaScript(): [string, FileSummary] {
400406
if (!this.outputIds || !this.tsmesBreakdown) {
401407
throw new Error('tsmes call must be extracted first');
402408
}
@@ -427,11 +433,12 @@ class Generator {
427433
this.manifest.addReferencedModule(
428434
this.outputIds.google3Path, this.srcIds.googModuleId);
429435

430-
const pintoModuleAnnotation = containsAtPintoModule(this.src) ?
436+
const isAutoChunk = containsAtPintoModule(this.src);
437+
const pintoModuleAnnotation = isAutoChunk ?
431438
'@pintomodule found in original_file' :
432439
'pintomodule absent in original_file';
433440

434-
return lines(
441+
const content = lines(
435442
'/**',
436443
' * @fileoverview generator:ts_migration_exports_shim.ts',
437444
' * original_file:' + this.srcIds.google3Path,
@@ -443,6 +450,18 @@ class Generator {
443450
exportsAssignment,
444451
'',
445452
);
453+
454+
const fileSummary = new FileSummary();
455+
fileSummary.addProvide(
456+
{type: Type.CLOSURE, name: this.outputIds.googModuleId});
457+
fileSummary.addStrongRequire({type: Type.CLOSURE, name: 'goog'});
458+
fileSummary.addStrongRequire(
459+
{type: Type.CLOSURE, name: this.srcIds.googModuleId});
460+
461+
fileSummary.autochunk = isAutoChunk;
462+
fileSummary.moduleType = ModuleType.GOOG_MODULE;
463+
464+
return [content, fileSummary];
446465
}
447466

448467
/**

src/tsickle.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import * as googmodule from './googmodule';
2020
import {jsdocTransformer, removeTypeAssertions} from './jsdoc_transformer';
2121
import {ModulesManifest} from './modules_manifest';
2222
import {namespaceTransformer} from './ns_transformer';
23+
import {FileSummary, SummaryGenerationProcessorHost} from './summary';
2324
import {isDtsFileName} from './transformer_util';
2425
import * as tsmes from './ts_migration_exports_shim';
2526
import {makeTsickleDeclarationMarkerTransformerFactory} from './tsickle_declaration_marker';
@@ -29,10 +30,12 @@ export {pathToModuleName} from './cli_support';
2930
// Retained here for API compatibility.
3031
export {getGeneratedExterns} from './externs';
3132
export {FileMap, ModulesManifest} from './modules_manifest';
33+
export {FileSummary, ModuleType, Symbol, Type} from './summary';
3234

3335
export interface TsickleHost extends googmodule.GoogModuleProcessorHost,
3436
tsmes.TsMigrationExportsShimProcessorHost,
35-
AnnotatorHost {
37+
AnnotatorHost,
38+
SummaryGenerationProcessorHost {
3639
/**
3740
* Whether to downlevel decorators
3841
*/
@@ -79,6 +82,11 @@ export interface TsickleHost extends googmodule.GoogModuleProcessorHost,
7982
* Whether to add suppressions by default.
8083
*/
8184
generateExtraSuppressions: boolean;
85+
86+
/**
87+
* Whether to generate summaries.
88+
*/
89+
generateSummary?: boolean;
8290
}
8391

8492

@@ -90,6 +98,7 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
9098
{[fileName: string]: {output: string, moduleNamespace: string}} = {};
9199
const modulesManifest = new ModulesManifest();
92100
const tsMigrationExportsShimFiles = new Map<string, string>();
101+
const fileSummaries = new Map<string, FileSummary>();
93102
for (const er of emitResults) {
94103
diagnostics.push(...er.diagnostics);
95104
emitSkipped = emitSkipped || er.emitSkipped;
@@ -101,6 +110,9 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
101110
for (const [k, v] of er.tsMigrationExportsShimFiles) {
102111
tsMigrationExportsShimFiles.set(k, v);
103112
}
113+
for (const [k, v] of er.fileSummaries) {
114+
fileSummaries.set(k, v);
115+
}
104116
}
105117

106118
return {
@@ -110,6 +122,7 @@ export function mergeEmitResults(emitResults: EmitResult[]): EmitResult {
110122
externs,
111123
tsMigrationExportsShimFiles,
112124
modulesManifest,
125+
fileSummaries,
113126
};
114127
}
115128

@@ -127,6 +140,8 @@ export interface EmitResult extends ts.EmitResult {
127140
* Filenames are google3 relative.
128141
*/
129142
tsMigrationExportsShimFiles: tsmes.TsMigrationExportsShimFileMap;
143+
144+
fileSummaries: Map<string, FileSummary>;
130145
}
131146

132147
export interface EmitTransformers {
@@ -182,17 +197,19 @@ export function emit(
182197
modulesManifest: new ModulesManifest(),
183198
externs: {},
184199
tsMigrationExportsShimFiles: new Map(),
200+
fileSummaries: new Map(),
185201
};
186202
}
187203

188204
const modulesManifest = new ModulesManifest();
189205
const tsMigrationExportsShimFiles = new Map<string, string>();
190206
const tsickleSourceTransformers: Array<ts.TransformerFactory<ts.SourceFile>> =
191207
[];
208+
const fileSummaries = new Map<string, FileSummary>();
192209
tsickleSourceTransformers.push(
193210
tsmes.createTsMigrationExportsShimTransformerFactory(
194211
typeChecker, host, modulesManifest, tsickleDiagnostics,
195-
tsMigrationExportsShimFiles));
212+
tsMigrationExportsShimFiles, fileSummaries));
196213

197214
if (host.transformTypesToClosure) {
198215
// Only add @suppress {checkTypes} comments when also adding type
@@ -282,6 +299,7 @@ export function emit(
282299
diagnostics: [...tsDiagnostics, ...tsickleDiagnostics],
283300
externs,
284301
tsMigrationExportsShimFiles,
302+
fileSummaries,
285303
};
286304
}
287305

0 commit comments

Comments
 (0)