fix(ivy): use globally unique names for i18n constants (#25689)

Closure compiler requires that the i18n message constants of the form

const MSG_XYZ = goog.getMessage('...');

have names that are unique across an entire compilation, even if the
variables themselves are local to a given module. This means that in
practice these names must be unique in a codebase.

The best way to guarantee this requirement is met is to encode the
relative file name of the file into which the constant is being written
into the constant name itself. This commit implements that solution.

PR Close #25689
This commit is contained in:
Alex Rickabaugh
2018-08-27 11:11:02 -07:00
committed by Misko Hevery
parent bd0eb0d1d4
commit cc29b9cf93
14 changed files with 95 additions and 28 deletions

View File

@ -29,7 +29,7 @@ export class ComponentDecoratorHandler implements DecoratorHandler<R3ComponentMe
constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean,
private resourceLoader: ResourceLoader) {}
private resourceLoader: ResourceLoader, private rootDirs: string[]) {}
private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
@ -111,9 +111,21 @@ export class ComponentDecoratorHandler implements DecoratorHandler<R3ComponentMe
preserveWhitespaces = value;
}
// Go through the root directories for this project, and select the one with the smallest
// relative path representation.
const filePath = node.getSourceFile().fileName;
const relativeFilePath = this.rootDirs.reduce<string|undefined>((previous, rootDir) => {
const candidate = path.posix.relative(rootDir, filePath);
if (previous === undefined || candidate.length < previous.length) {
return candidate;
} else {
return previous;
}
}, undefined) !;
const template = parseTemplate(
templateStr, `${node.getSourceFile().fileName}#${node.name!.text}/template.html`,
{preserveWhitespaces});
{preserveWhitespaces}, relativeFilePath);
if (template.errors !== undefined) {
throw new Error(
`Errors parsing template: ${template.errors.map(e => e.toString()).join(', ')}`);

View File

@ -39,7 +39,8 @@ describe('ComponentDecoratorHandler', () => {
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const handler = new ComponentDecoratorHandler(
checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader());
checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
['']);
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp));
if (detected === undefined) {

View File

@ -29,11 +29,20 @@ export class NgtscProgram implements api.Program {
private _coreImportsFrom: ts.SourceFile|null|undefined = undefined;
private _reflector: TypeScriptReflectionHost|undefined = undefined;
private _isCore: boolean|undefined = undefined;
private rootDirs: string[];
constructor(
rootNames: ReadonlyArray<string>, private options: api.CompilerOptions,
host: api.CompilerHost, oldProgram?: api.Program) {
this.rootDirs = [];
if (options.rootDirs !== undefined) {
this.rootDirs.push(...options.rootDirs);
} else if (options.rootDir !== undefined) {
this.rootDirs.push(options.rootDir);
} else {
this.rootDirs.push(host.getCurrentDirectory());
}
this.resourceLoader = host.readResource !== undefined ?
new HostResourceLoader(host.readResource.bind(host)) :
new FileResourceLoader();
@ -177,7 +186,7 @@ export class NgtscProgram implements api.Program {
const handlers = [
new BaseDefDecoratorHandler(checker, this.reflector),
new ComponentDecoratorHandler(
checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader),
checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs),
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.reflector, this.isCore),
new NgModuleDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),