style(compiler): reformat of codebase with new clang-format version (#36520)
This commit reformats the packages/compiler tree using the new version of clang-format. PR Close #36520
This commit is contained in:
parent
0a69a2832b
commit
83a9159063
@ -11,7 +11,7 @@ import {CompilerConfig} from '../config';
|
|||||||
import {ConstantPool} from '../constant_pool';
|
import {ConstantPool} from '../constant_pool';
|
||||||
import {ViewEncapsulation} from '../core';
|
import {ViewEncapsulation} from '../core';
|
||||||
import {MessageBundle} from '../i18n/message_bundle';
|
import {MessageBundle} from '../i18n/message_bundle';
|
||||||
import {Identifiers, createTokenForExternalReference} from '../identifiers';
|
import {createTokenForExternalReference, Identifiers} from '../identifiers';
|
||||||
import {InjectableCompiler} from '../injectable_compiler';
|
import {InjectableCompiler} from '../injectable_compiler';
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
import {CompileMetadataResolver} from '../metadata_resolver';
|
||||||
import {HtmlParser} from '../ml_parser/html_parser';
|
import {HtmlParser} from '../ml_parser/html_parser';
|
||||||
@ -31,9 +31,9 @@ import {SummaryResolver} from '../summary_resolver';
|
|||||||
import {BindingParser} from '../template_parser/binding_parser';
|
import {BindingParser} from '../template_parser/binding_parser';
|
||||||
import {TemplateAst} from '../template_parser/template_ast';
|
import {TemplateAst} from '../template_parser/template_ast';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from '../template_parser/template_parser';
|
||||||
import {OutputContext, ValueVisitor, error, newArray, syntaxError, visitValue} from '../util';
|
import {error, newArray, OutputContext, syntaxError, ValueVisitor, visitValue} from '../util';
|
||||||
import {TypeCheckCompiler} from '../view_compiler/type_check_compiler';
|
import {TypeCheckCompiler} from '../view_compiler/type_check_compiler';
|
||||||
import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
import {ViewCompiler, ViewCompileResult} from '../view_compiler/view_compiler';
|
||||||
|
|
||||||
import {AotCompilerHost} from './compiler_host';
|
import {AotCompilerHost} from './compiler_host';
|
||||||
import {AotCompilerOptions} from './compiler_options';
|
import {AotCompilerOptions} from './compiler_options';
|
||||||
@ -46,7 +46,11 @@ import {StaticSymbolResolver} from './static_symbol_resolver';
|
|||||||
import {createForJitStub, serializeSummaries} from './summary_serializer';
|
import {createForJitStub, serializeSummaries} from './summary_serializer';
|
||||||
import {ngfactoryFilePath, normalizeGenFileSuffix, splitTypescriptSuffix, summaryFileName, summaryForJitFileName} from './util';
|
import {ngfactoryFilePath, normalizeGenFileSuffix, splitTypescriptSuffix, summaryFileName, summaryForJitFileName} from './util';
|
||||||
|
|
||||||
const enum StubEmitFlags { Basic = 1 << 0, TypeCheck = 1 << 1, All = TypeCheck | Basic }
|
const enum StubEmitFlags {
|
||||||
|
Basic = 1 << 0,
|
||||||
|
TypeCheck = 1 << 1,
|
||||||
|
All = TypeCheck | Basic
|
||||||
|
}
|
||||||
|
|
||||||
export class AotCompiler {
|
export class AotCompiler {
|
||||||
private _templateAstCache =
|
private _templateAstCache =
|
||||||
@ -64,7 +68,9 @@ export class AotCompiler {
|
|||||||
private _summaryResolver: SummaryResolver<StaticSymbol>,
|
private _summaryResolver: SummaryResolver<StaticSymbol>,
|
||||||
private _symbolResolver: StaticSymbolResolver) {}
|
private _symbolResolver: StaticSymbolResolver) {}
|
||||||
|
|
||||||
clearCache() { this._metadataResolver.clearCache(); }
|
clearCache() {
|
||||||
|
this._metadataResolver.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
analyzeModulesSync(rootFiles: string[]): NgAnalyzedModules {
|
analyzeModulesSync(rootFiles: string[]): NgAnalyzedModules {
|
||||||
const analyzeResult = analyzeAndValidateNgModules(
|
const analyzeResult = analyzeAndValidateNgModules(
|
||||||
@ -123,7 +129,7 @@ export class AotCompiler {
|
|||||||
const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]);
|
const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]);
|
||||||
file.directives.forEach((dirSymbol) => {
|
file.directives.forEach((dirSymbol) => {
|
||||||
const compMeta =
|
const compMeta =
|
||||||
this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol) !.metadata;
|
this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol)!.metadata;
|
||||||
if (!compMeta.isComponent) {
|
if (!compMeta.isComponent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -149,7 +155,8 @@ export class AotCompiler {
|
|||||||
if (genFileName.endsWith('.ngfactory.ts')) {
|
if (genFileName.endsWith('.ngfactory.ts')) {
|
||||||
if (!originalFileName) {
|
if (!originalFileName) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Assertion error: require the original file for .ngfactory.ts stubs. File: ${genFileName}`);
|
`Assertion error: require the original file for .ngfactory.ts stubs. File: ${
|
||||||
|
genFileName}`);
|
||||||
}
|
}
|
||||||
const originalFile = this._analyzeFile(originalFileName);
|
const originalFile = this._analyzeFile(originalFileName);
|
||||||
this._createNgFactoryStub(outputCtx, originalFile, StubEmitFlags.Basic);
|
this._createNgFactoryStub(outputCtx, originalFile, StubEmitFlags.Basic);
|
||||||
@ -157,7 +164,8 @@ export class AotCompiler {
|
|||||||
if (this._options.enableSummariesForJit) {
|
if (this._options.enableSummariesForJit) {
|
||||||
if (!originalFileName) {
|
if (!originalFileName) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Assertion error: require the original file for .ngsummary.ts stubs. File: ${genFileName}`);
|
`Assertion error: require the original file for .ngsummary.ts stubs. File: ${
|
||||||
|
genFileName}`);
|
||||||
}
|
}
|
||||||
const originalFile = this._analyzeFile(originalFileName);
|
const originalFile = this._analyzeFile(originalFileName);
|
||||||
_createEmptyStub(outputCtx);
|
_createEmptyStub(outputCtx);
|
||||||
@ -319,10 +327,10 @@ export class AotCompiler {
|
|||||||
const html = compMeta.template !.template !;
|
const html = compMeta.template !.template !;
|
||||||
// Template URL points to either an HTML or TS file depending on whether
|
// Template URL points to either an HTML or TS file depending on whether
|
||||||
// the file is used with `templateUrl:` or `template:`, respectively.
|
// the file is used with `templateUrl:` or `template:`, respectively.
|
||||||
const templateUrl = compMeta.template !.templateUrl !;
|
const templateUrl = compMeta.template !.templateUrl!;
|
||||||
const interpolationConfig =
|
const interpolationConfig =
|
||||||
InterpolationConfig.fromArray(compMeta.template !.interpolation);
|
InterpolationConfig.fromArray(compMeta.template !.interpolation);
|
||||||
errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig) !);
|
errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig)!);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -342,7 +350,7 @@ export class AotCompiler {
|
|||||||
if (!contextMap.has(fileName)) {
|
if (!contextMap.has(fileName)) {
|
||||||
contextMap.set(fileName, this._createOutputContext(fileName));
|
contextMap.set(fileName, this._createOutputContext(fileName));
|
||||||
}
|
}
|
||||||
return contextMap.get(fileName) !;
|
return contextMap.get(fileName)!;
|
||||||
};
|
};
|
||||||
|
|
||||||
files.forEach(
|
files.forEach(
|
||||||
@ -381,13 +389,13 @@ export class AotCompiler {
|
|||||||
directives.forEach(directiveType => {
|
directives.forEach(directiveType => {
|
||||||
const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType);
|
const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
if (directiveMetadata.isComponent) {
|
if (directiveMetadata.isComponent) {
|
||||||
const module = ngModuleByPipeOrDirective.get(directiveType) !;
|
const module = ngModuleByPipeOrDirective.get(directiveType)!;
|
||||||
module ||
|
module ||
|
||||||
error(
|
error(`Cannot determine the module for component '${
|
||||||
`Cannot determine the module for component '${identifierName(directiveMetadata.type)}'`);
|
identifierName(directiveMetadata.type)}'`);
|
||||||
|
|
||||||
let htmlAst = directiveMetadata.template !.htmlAst !;
|
let htmlAst = directiveMetadata.template !.htmlAst!;
|
||||||
const preserveWhitespaces = directiveMetadata !.template !.preserveWhitespaces;
|
const preserveWhitespaces = directiveMetadata!.template !.preserveWhitespaces;
|
||||||
|
|
||||||
if (!preserveWhitespaces) {
|
if (!preserveWhitespaces) {
|
||||||
htmlAst = removeWhitespaces(htmlAst);
|
htmlAst = removeWhitespaces(htmlAst);
|
||||||
@ -412,7 +420,9 @@ export class AotCompiler {
|
|||||||
const pipes = module.transitiveModule.pipes.map(
|
const pipes = module.transitiveModule.pipes.map(
|
||||||
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
||||||
|
|
||||||
pipes.forEach(pipe => { pipeTypeByName.set(pipe.name, pipe.type.reference); });
|
pipes.forEach(pipe => {
|
||||||
|
pipeTypeByName.set(pipe.name, pipe.type.reference);
|
||||||
|
});
|
||||||
|
|
||||||
compileR3Component(
|
compileR3Component(
|
||||||
context, directiveMetadata, render3Ast, this.reflector, hostBindingParser,
|
context, directiveMetadata, render3Ast, this.reflector, hostBindingParser,
|
||||||
@ -484,8 +494,8 @@ export class AotCompiler {
|
|||||||
}
|
}
|
||||||
const ngModule = ngModuleByPipeOrDirective.get(dirType);
|
const ngModule = ngModuleByPipeOrDirective.get(dirType);
|
||||||
if (!ngModule) {
|
if (!ngModule) {
|
||||||
throw new Error(
|
throw new Error(`Internal Error: cannot determine the module for component ${
|
||||||
`Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`);
|
identifierName(compMeta.type)}!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile styles
|
// compile styles
|
||||||
@ -524,27 +534,27 @@ export class AotCompiler {
|
|||||||
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
|
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
|
||||||
const typeData: {
|
const typeData: {
|
||||||
summary: CompileTypeSummary,
|
summary: CompileTypeSummary,
|
||||||
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
|
metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata|
|
||||||
CompileTypeMetadata
|
CompileTypeMetadata
|
||||||
}[] =
|
}[] =
|
||||||
[
|
[
|
||||||
...ngModules.map(
|
...ngModules.map(
|
||||||
meta => ({
|
meta => ({
|
||||||
summary: this._metadataResolver.getNgModuleSummary(meta.type.reference) !,
|
summary: this._metadataResolver.getNgModuleSummary(meta.type.reference)!,
|
||||||
metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference) !
|
metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference)!
|
||||||
})),
|
})),
|
||||||
...directives.map(ref => ({
|
...directives.map(ref => ({
|
||||||
summary: this._metadataResolver.getDirectiveSummary(ref) !,
|
summary: this._metadataResolver.getDirectiveSummary(ref)!,
|
||||||
metadata: this._metadataResolver.getDirectiveMetadata(ref) !
|
metadata: this._metadataResolver.getDirectiveMetadata(ref)!
|
||||||
})),
|
})),
|
||||||
...pipes.map(ref => ({
|
...pipes.map(ref => ({
|
||||||
summary: this._metadataResolver.getPipeSummary(ref) !,
|
summary: this._metadataResolver.getPipeSummary(ref)!,
|
||||||
metadata: this._metadataResolver.getPipeMetadata(ref) !
|
metadata: this._metadataResolver.getPipeMetadata(ref)!
|
||||||
})),
|
})),
|
||||||
...injectables.map(
|
...injectables.map(
|
||||||
ref => ({
|
ref => ({
|
||||||
summary: this._metadataResolver.getInjectableSummary(ref.symbol) !,
|
summary: this._metadataResolver.getInjectableSummary(ref.symbol)!,
|
||||||
metadata: this._metadataResolver.getInjectableSummary(ref.symbol) !.type
|
metadata: this._metadataResolver.getInjectableSummary(ref.symbol)!.type
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
const forJitOutputCtx = this._options.enableSummariesForJit ?
|
const forJitOutputCtx = this._options.enableSummariesForJit ?
|
||||||
@ -621,7 +631,7 @@ export class AotCompiler {
|
|||||||
.toDeclStmt(
|
.toDeclStmt(
|
||||||
o.importType(
|
o.importType(
|
||||||
Identifiers.ComponentFactory,
|
Identifiers.ComponentFactory,
|
||||||
[o.expressionType(outputCtx.importExpr(compMeta.type.reference)) !],
|
[o.expressionType(outputCtx.importExpr(compMeta.type.reference))!],
|
||||||
[o.TypeModifier.Const]),
|
[o.TypeModifier.Const]),
|
||||||
[o.StmtModifier.Final, o.StmtModifier.Exported]));
|
[o.StmtModifier.Final, o.StmtModifier.Exported]));
|
||||||
}
|
}
|
||||||
@ -648,15 +658,15 @@ export class AotCompiler {
|
|||||||
directiveIdentifiers: CompileIdentifierMetadata[]):
|
directiveIdentifiers: CompileIdentifierMetadata[]):
|
||||||
{template: TemplateAst[], pipes: CompilePipeSummary[]} {
|
{template: TemplateAst[], pipes: CompilePipeSummary[]} {
|
||||||
if (this._templateAstCache.has(compMeta.type.reference)) {
|
if (this._templateAstCache.has(compMeta.type.reference)) {
|
||||||
return this._templateAstCache.get(compMeta.type.reference) !;
|
return this._templateAstCache.get(compMeta.type.reference)!;
|
||||||
}
|
}
|
||||||
const preserveWhitespaces = compMeta !.template !.preserveWhitespaces;
|
const preserveWhitespaces = compMeta!.template !.preserveWhitespaces;
|
||||||
const directives =
|
const directives =
|
||||||
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
|
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
|
||||||
const pipes = ngModule.transitiveModule.pipes.map(
|
const pipes = ngModule.transitiveModule.pipes.map(
|
||||||
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
||||||
const result = this._templateParser.parse(
|
const result = this._templateParser.parse(
|
||||||
compMeta, compMeta.template !.htmlAst !, directives, pipes, ngModule.schemas,
|
compMeta, compMeta.template !.htmlAst!, directives, pipes, ngModule.schemas,
|
||||||
templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces);
|
templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces);
|
||||||
this._templateAstCache.set(compMeta.type.reference, result);
|
this._templateAstCache.set(compMeta.type.reference, result);
|
||||||
return result;
|
return result;
|
||||||
@ -664,8 +674,7 @@ export class AotCompiler {
|
|||||||
|
|
||||||
private _createOutputContext(genFilePath: string): OutputContext {
|
private _createOutputContext(genFilePath: string): OutputContext {
|
||||||
const importExpr =
|
const importExpr =
|
||||||
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
|
(symbol: StaticSymbol, typeParams: o.Type[]|null = null, useSummaries: boolean = true) => {
|
||||||
useSummaries: boolean = true) => {
|
|
||||||
if (!(symbol instanceof StaticSymbol)) {
|
if (!(symbol instanceof StaticSymbol)) {
|
||||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
||||||
}
|
}
|
||||||
@ -710,7 +719,7 @@ export class AotCompiler {
|
|||||||
stylesheetMetadata: CompileStylesheetMetadata, isShimmed: boolean,
|
stylesheetMetadata: CompileStylesheetMetadata, isShimmed: boolean,
|
||||||
fileSuffix: string): GeneratedFile {
|
fileSuffix: string): GeneratedFile {
|
||||||
const outputCtx = this._createOutputContext(
|
const outputCtx = this._createOutputContext(
|
||||||
_stylesModuleUrl(stylesheetMetadata.moduleUrl !, isShimmed, fileSuffix));
|
_stylesModuleUrl(stylesheetMetadata.moduleUrl!, isShimmed, fileSuffix));
|
||||||
const compiledStylesheet =
|
const compiledStylesheet =
|
||||||
this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed);
|
this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed);
|
||||||
_resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix);
|
_resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix);
|
||||||
@ -748,8 +757,8 @@ export class AotCompiler {
|
|||||||
return allLazyRoutes;
|
return allLazyRoutes;
|
||||||
}
|
}
|
||||||
seenRoutes.add(symbol);
|
seenRoutes.add(symbol);
|
||||||
const lazyRoutes = listLazyRoutes(
|
const lazyRoutes =
|
||||||
self._metadataResolver.getNgModuleMetadata(symbol, true) !, self.reflector);
|
listLazyRoutes(self._metadataResolver.getNgModuleMetadata(symbol, true)!, self.reflector);
|
||||||
for (const lazyRoute of lazyRoutes) {
|
for (const lazyRoute of lazyRoutes) {
|
||||||
allLazyRoutes.push(lazyRoute);
|
allLazyRoutes.push(lazyRoute);
|
||||||
visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes);
|
visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes);
|
||||||
@ -803,7 +812,9 @@ export interface NgAnalyzedFile {
|
|||||||
exportsNonSourceFiles: boolean;
|
exportsNonSourceFiles: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NgAnalyzeModulesHost { isSourceFile(filePath: string): boolean; }
|
export interface NgAnalyzeModulesHost {
|
||||||
|
isSourceFile(filePath: string): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function analyzeNgModules(
|
export function analyzeNgModules(
|
||||||
fileNames: string[], host: NgAnalyzeModulesHost, staticSymbolResolver: StaticSymbolResolver,
|
fileNames: string[], host: NgAnalyzeModulesHost, staticSymbolResolver: StaticSymbolResolver,
|
||||||
@ -823,8 +834,8 @@ export function analyzeAndValidateNgModules(
|
|||||||
function validateAnalyzedModules(analyzedModules: NgAnalyzedModules): NgAnalyzedModules {
|
function validateAnalyzedModules(analyzedModules: NgAnalyzedModules): NgAnalyzedModules {
|
||||||
if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) {
|
if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) {
|
||||||
const messages = analyzedModules.symbolsMissingModule.map(
|
const messages = analyzedModules.symbolsMissingModule.map(
|
||||||
s =>
|
s => `Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${
|
||||||
`Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${s.name} to the NgModule to fix it.`);
|
s.name} to the NgModule to fix it.`);
|
||||||
throw syntaxError(messages.join('\n'));
|
throw syntaxError(messages.join('\n'));
|
||||||
}
|
}
|
||||||
return analyzedModules;
|
return analyzedModules;
|
||||||
@ -918,8 +929,13 @@ export function analyzeFile(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
fileName, directives, abstractDirectives, pipes,
|
fileName,
|
||||||
ngModules, injectables, exportsNonSourceFiles,
|
directives,
|
||||||
|
abstractDirectives,
|
||||||
|
pipes,
|
||||||
|
ngModules,
|
||||||
|
injectables,
|
||||||
|
exportsNonSourceFiles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -957,7 +973,9 @@ function isValueExportingNonSourceFile(host: NgAnalyzeModulesHost, metadata: any
|
|||||||
let exportsNonSourceFiles = false;
|
let exportsNonSourceFiles = false;
|
||||||
|
|
||||||
class Visitor implements ValueVisitor {
|
class Visitor implements ValueVisitor {
|
||||||
visitArray(arr: any[], context: any): any { arr.forEach(v => visitValue(v, this, context)); }
|
visitArray(arr: any[], context: any): any {
|
||||||
|
arr.forEach(v => visitValue(v, this, context));
|
||||||
|
}
|
||||||
visitStringMap(map: {[key: string]: any}, context: any): any {
|
visitStringMap(map: {[key: string]: any}, context: any): any {
|
||||||
Object.keys(map).forEach((key) => visitValue(map[key], this, context));
|
Object.keys(map).forEach((key) => visitValue(map[key], this, context));
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@ import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
|||||||
import {StaticSymbolResolver} from './static_symbol_resolver';
|
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
import {AotSummaryResolver} from './summary_resolver';
|
import {AotSummaryResolver} from './summary_resolver';
|
||||||
|
|
||||||
export function createAotUrlResolver(host: {
|
export function createAotUrlResolver(
|
||||||
resourceNameToFileName(resourceName: string, containingFileName: string): string | null;
|
host: {resourceNameToFileName(resourceName: string, containingFileName: string): string|null;}):
|
||||||
}): UrlResolver {
|
UrlResolver {
|
||||||
return {
|
return {
|
||||||
resolve: (basePath: string, url: string) => {
|
resolve: (basePath: string, url: string) => {
|
||||||
const filePath = host.resourceNameToFileName(url, basePath);
|
const filePath = host.resourceNameToFileName(url, basePath);
|
||||||
|
@ -20,7 +20,7 @@ export interface FormattedMessageChain {
|
|||||||
next?: FormattedMessageChain[];
|
next?: FormattedMessageChain[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormattedError = Error & {
|
export type FormattedError = Error&{
|
||||||
chain: FormattedMessageChain;
|
chain: FormattedMessageChain;
|
||||||
position?: Position;
|
position?: Position;
|
||||||
};
|
};
|
||||||
@ -34,10 +34,10 @@ function indentStr(level: number): string {
|
|||||||
return half + half + (level % 2 === 1 ? ' ' : '');
|
return half + half + (level % 2 === 1 ? ' ' : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatChain(chain: FormattedMessageChain | undefined, indent: number = 0): string {
|
function formatChain(chain: FormattedMessageChain|undefined, indent: number = 0): string {
|
||||||
if (!chain) return '';
|
if (!chain) return '';
|
||||||
const position = chain.position ?
|
const position = chain.position ?
|
||||||
`${chain.position.fileName}(${chain.position.line+1},${chain.position.column+1})` :
|
`${chain.position.fileName}(${chain.position.line + 1},${chain.position.column + 1})` :
|
||||||
'';
|
'';
|
||||||
const prefix = position && indent === 0 ? `${position}: ` : '';
|
const prefix = position && indent === 0 ? `${position}: ` : '';
|
||||||
const postfix = position && indent !== 0 ? ` at ${position}` : '';
|
const postfix = position && indent !== 0 ? ` at ${position}` : '';
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Statement, areAllEquivalent} from '../output/output_ast';
|
import {areAllEquivalent, Statement} from '../output/output_ast';
|
||||||
import {TypeScriptEmitter} from '../output/ts_emitter';
|
import {TypeScriptEmitter} from '../output/ts_emitter';
|
||||||
|
|
||||||
export class GeneratedFile {
|
export class GeneratedFile {
|
||||||
@ -36,7 +36,7 @@ export class GeneratedFile {
|
|||||||
}
|
}
|
||||||
// Note: the constructor guarantees that if this.source is not filled,
|
// Note: the constructor guarantees that if this.source is not filled,
|
||||||
// then this.stmts is.
|
// then this.stmts is.
|
||||||
return areAllEquivalent(this.stmts !, other.stmts !);
|
return areAllEquivalent(this.stmts!, other.stmts!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export function listLazyRoutes(
|
|||||||
return allLazyRoutes;
|
return allLazyRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _collectLoadChildren(routes: string | Route | Route[], target: string[] = []): string[] {
|
function _collectLoadChildren(routes: string|Route|Route[], target: string[] = []): string[] {
|
||||||
if (typeof routes === 'string') {
|
if (typeof routes === 'string') {
|
||||||
target.push(routes);
|
target.push(routes);
|
||||||
} else if (Array.isArray(routes)) {
|
} else if (Array.isArray(routes)) {
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
import {CompileSummaryKind} from '../compile_metadata';
|
import {CompileSummaryKind} from '../compile_metadata';
|
||||||
import {CompileReflector} from '../compile_reflector';
|
import {CompileReflector} from '../compile_reflector';
|
||||||
import {MetadataFactory, createAttribute, createComponent, createContentChild, createContentChildren, createDirective, createHost, createHostBinding, createHostListener, createInject, createInjectable, createInput, createNgModule, createOptional, createOutput, createPipe, createSelf, createSkipSelf, createViewChild, createViewChildren} from '../core';
|
import {createAttribute, createComponent, createContentChild, createContentChildren, createDirective, createHost, createHostBinding, createHostListener, createInject, createInjectable, createInput, createNgModule, createOptional, createOutput, createPipe, createSelf, createSkipSelf, createViewChild, createViewChildren, MetadataFactory} from '../core';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {SummaryResolver} from '../summary_resolver';
|
import {SummaryResolver} from '../summary_resolver';
|
||||||
import {syntaxError} from '../util';
|
import {syntaxError} from '../util';
|
||||||
|
|
||||||
import {FormattedMessageChain, formattedError} from './formatted_error';
|
import {formattedError, FormattedMessageChain} from './formatted_error';
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {StaticSymbolResolver} from './static_symbol_resolver';
|
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
|
|
||||||
@ -50,13 +50,13 @@ export class StaticReflector implements CompileReflector {
|
|||||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||||
private resolvedExternalReferences = new Map<string, StaticSymbol>();
|
private resolvedExternalReferences = new Map<string, StaticSymbol>();
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private injectionToken !: StaticSymbol;
|
private injectionToken!: StaticSymbol;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private opaqueToken !: StaticSymbol;
|
private opaqueToken!: StaticSymbol;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
ROUTES !: StaticSymbol;
|
ROUTES!: StaticSymbol;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private ANALYZE_FOR_ENTRY_COMPONENTS !: StaticSymbol;
|
private ANALYZE_FOR_ENTRY_COMPONENTS!: StaticSymbol;
|
||||||
private annotationForParentClassWithSummaryKind =
|
private annotationForParentClassWithSummaryKind =
|
||||||
new Map<CompileSummaryKind, MetadataFactory<any>[]>();
|
new Map<CompileSummaryKind, MetadataFactory<any>[]>();
|
||||||
|
|
||||||
@ -110,10 +110,10 @@ export class StaticReflector implements CompileReflector {
|
|||||||
if (declarationSymbol) return declarationSymbol;
|
if (declarationSymbol) return declarationSymbol;
|
||||||
}
|
}
|
||||||
const refSymbol =
|
const refSymbol =
|
||||||
this.symbolResolver.getSymbolByModule(ref.moduleName !, ref.name !, containingFile);
|
this.symbolResolver.getSymbolByModule(ref.moduleName!, ref.name!, containingFile);
|
||||||
const declarationSymbol = this.findSymbolDeclaration(refSymbol);
|
const declarationSymbol = this.findSymbolDeclaration(refSymbol);
|
||||||
if (!containingFile) {
|
if (!containingFile) {
|
||||||
this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName !);
|
this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName!);
|
||||||
this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
|
this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
|
||||||
}
|
}
|
||||||
if (key) {
|
if (key) {
|
||||||
@ -192,16 +192,20 @@ export class StaticReflector implements CompileReflector {
|
|||||||
const summary = this.summaryResolver.resolveSummary(parentType);
|
const summary = this.summaryResolver.resolveSummary(parentType);
|
||||||
if (summary && summary.type) {
|
if (summary && summary.type) {
|
||||||
const requiredAnnotationTypes =
|
const requiredAnnotationTypes =
|
||||||
this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind !) !;
|
this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind!)!;
|
||||||
const typeHasRequiredAnnotation = requiredAnnotationTypes.some(
|
const typeHasRequiredAnnotation = requiredAnnotationTypes.some(
|
||||||
(requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
|
(requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
|
||||||
if (!typeHasRequiredAnnotation) {
|
if (!typeHasRequiredAnnotation) {
|
||||||
this.reportError(
|
this.reportError(
|
||||||
formatMetadataError(
|
formatMetadataError(
|
||||||
metadataError(
|
metadataError(
|
||||||
`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator`,
|
`Class ${type.name} in ${type.filePath} extends from a ${
|
||||||
|
CompileSummaryKind[summary.type.summaryKind!
|
||||||
|
]} in another compilation unit without duplicating the decorator`,
|
||||||
/* summary */ undefined,
|
/* summary */ undefined,
|
||||||
`Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class`),
|
`Please add a ${
|
||||||
|
requiredAnnotationTypes.map((type) => type.ngMetadataName)
|
||||||
|
.join(' or ')} decorator to the class`),
|
||||||
type),
|
type),
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
@ -221,7 +225,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
if (parentType) {
|
if (parentType) {
|
||||||
const parentPropMetadata = this.propMetadata(parentType);
|
const parentPropMetadata = this.propMetadata(parentType);
|
||||||
Object.keys(parentPropMetadata).forEach((parentProp) => {
|
Object.keys(parentPropMetadata).forEach((parentProp) => {
|
||||||
propMetadata ![parentProp] = parentPropMetadata[parentProp];
|
propMetadata![parentProp] = parentPropMetadata[parentProp];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +235,10 @@ export class StaticReflector implements CompileReflector {
|
|||||||
const prop = (<any[]>propData)
|
const prop = (<any[]>propData)
|
||||||
.find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
|
.find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
|
||||||
const decorators: any[] = [];
|
const decorators: any[] = [];
|
||||||
if (propMetadata ![propName]) {
|
if (propMetadata![propName]) {
|
||||||
decorators.push(...propMetadata ![propName]);
|
decorators.push(...propMetadata![propName]);
|
||||||
}
|
}
|
||||||
propMetadata ![propName] = decorators;
|
propMetadata![propName] = decorators;
|
||||||
if (prop && prop['decorators']) {
|
if (prop && prop['decorators']) {
|
||||||
decorators.push(...this.simplify(type, prop['decorators']));
|
decorators.push(...this.simplify(type, prop['decorators']));
|
||||||
}
|
}
|
||||||
@ -271,7 +275,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
if (decorators) {
|
if (decorators) {
|
||||||
nestedResult.push(...decorators);
|
nestedResult.push(...decorators);
|
||||||
}
|
}
|
||||||
parameters !.push(nestedResult);
|
parameters!.push(nestedResult);
|
||||||
});
|
});
|
||||||
} else if (parentType) {
|
} else if (parentType) {
|
||||||
parameters = this.parameters(parentType);
|
parameters = this.parameters(parentType);
|
||||||
@ -297,7 +301,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
if (parentType) {
|
if (parentType) {
|
||||||
const parentMethodNames = this._methodNames(parentType);
|
const parentMethodNames = this._methodNames(parentType);
|
||||||
Object.keys(parentMethodNames).forEach((parentProp) => {
|
Object.keys(parentMethodNames).forEach((parentProp) => {
|
||||||
methodNames ![parentProp] = parentMethodNames[parentProp];
|
methodNames![parentProp] = parentMethodNames[parentProp];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +309,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
Object.keys(members).forEach((propName) => {
|
Object.keys(members).forEach((propName) => {
|
||||||
const propData = members[propName];
|
const propData = members[propName];
|
||||||
const isMethod = (<any[]>propData).some(a => a['__symbolic'] == 'method');
|
const isMethod = (<any[]>propData).some(a => a['__symbolic'] == 'method');
|
||||||
methodNames ![propName] = methodNames ![propName] || isMethod;
|
methodNames![propName] = methodNames![propName] || isMethod;
|
||||||
});
|
});
|
||||||
this.methodCache.set(type, methodNames);
|
this.methodCache.set(type, methodNames);
|
||||||
}
|
}
|
||||||
@ -485,7 +489,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
// Propagate the message text up but add a message to the chain that explains how we got
|
// Propagate the message text up but add a message to the chain that explains how we got
|
||||||
// here.
|
// here.
|
||||||
// e.chain implies e.symbol
|
// e.chain implies e.symbol
|
||||||
const summaryMsg = e.chain ? 'references \'' + e.symbol !.name + '\'' : errorSummary(e);
|
const summaryMsg = e.chain ? 'references \'' + e.symbol!.name + '\'' : errorSummary(e);
|
||||||
const summary = `'${nestedContext.name}' ${summaryMsg}`;
|
const summary = `'${nestedContext.name}' ${summaryMsg}`;
|
||||||
const chain = {message: summary, position: e.position, next: e.chain};
|
const chain = {message: summary, position: e.position, next: e.chain};
|
||||||
// TODO(chuckj): retrieve the position information indirectly from the collectors node
|
// TODO(chuckj): retrieve the position information indirectly from the collectors node
|
||||||
@ -494,7 +498,8 @@ export class StaticReflector implements CompileReflector {
|
|||||||
{
|
{
|
||||||
message: e.message,
|
message: e.message,
|
||||||
advise: e.advise,
|
advise: e.advise,
|
||||||
context: e.context, chain,
|
context: e.context,
|
||||||
|
chain,
|
||||||
symbol: nestedContext
|
symbol: nestedContext
|
||||||
},
|
},
|
||||||
context);
|
context);
|
||||||
@ -566,7 +571,8 @@ export class StaticReflector implements CompileReflector {
|
|||||||
{
|
{
|
||||||
message: FUNCTION_CALL_NOT_SUPPORTED,
|
message: FUNCTION_CALL_NOT_SUPPORTED,
|
||||||
context: functionSymbol,
|
context: functionSymbol,
|
||||||
value: targetFunction, position
|
value: targetFunction,
|
||||||
|
position
|
||||||
},
|
},
|
||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
@ -875,7 +881,7 @@ interface MetadataMessageChain {
|
|||||||
next?: MetadataMessageChain;
|
next?: MetadataMessageChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
type MetadataError = Error & {
|
type MetadataError = Error&{
|
||||||
position?: Position;
|
position?: Position;
|
||||||
advise?: string;
|
advise?: string;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
@ -916,7 +922,8 @@ function expandedMessage(message: string, context: any): string {
|
|||||||
switch (message) {
|
switch (message) {
|
||||||
case REFERENCE_TO_NONEXPORTED_CLASS:
|
case REFERENCE_TO_NONEXPORTED_CLASS:
|
||||||
if (context && context.className) {
|
if (context && context.className) {
|
||||||
return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
|
return `References to a non-exported class are not supported in decorators but ${
|
||||||
|
context.className} was referenced.`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VARIABLE_NOT_INITIALIZED:
|
case VARIABLE_NOT_INITIALIZED:
|
||||||
@ -935,7 +942,8 @@ function expandedMessage(message: string, context: any): string {
|
|||||||
return 'Function calls are not supported in decorators';
|
return 'Function calls are not supported in decorators';
|
||||||
case REFERENCE_TO_LOCAL_SYMBOL:
|
case REFERENCE_TO_LOCAL_SYMBOL:
|
||||||
if (context && context.name) {
|
if (context && context.name) {
|
||||||
return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
|
return `Reference to a local (non-exported) symbols are not supported in decorators but '${
|
||||||
|
context.name}' was referenced`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LAMBDA_NOT_SUPPORTED:
|
case LAMBDA_NOT_SUPPORTED:
|
||||||
@ -1040,7 +1048,9 @@ abstract class BindingScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PopulatedScope extends BindingScope {
|
class PopulatedScope extends BindingScope {
|
||||||
constructor(private bindings: Map<string, any>) { super(); }
|
constructor(private bindings: Map<string, any>) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
resolve(name: string): any {
|
resolve(name: string): any {
|
||||||
return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing;
|
return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing;
|
||||||
@ -1048,7 +1058,7 @@ class PopulatedScope extends BindingScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatMetadataMessageChain(
|
function formatMetadataMessageChain(
|
||||||
chain: MetadataMessageChain, advise: string | undefined): FormattedMessageChain {
|
chain: MetadataMessageChain, advise: string|undefined): FormattedMessageChain {
|
||||||
const expanded = expandedMessage(chain.message, chain.context);
|
const expanded = expandedMessage(chain.message, chain.context);
|
||||||
const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
|
const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
|
||||||
const message = `${expanded}${nesting}`;
|
const message = `${expanded}${nesting}`;
|
||||||
|
@ -31,7 +31,7 @@ export class StaticSymbolCache {
|
|||||||
|
|
||||||
get(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
get(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
members = members || [];
|
members = members || [];
|
||||||
const memberSuffix = members.length ? `.${ members.join('.')}` : '';
|
const memberSuffix = members.length ? `.${members.join('.')}` : '';
|
||||||
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
||||||
let result = this.cache.get(key);
|
let result = this.cache.get(key);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
@ -76,12 +76,12 @@ export class StaticSymbolResolver {
|
|||||||
|
|
||||||
resolveSymbol(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
resolveSymbol(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||||
if (staticSymbol.members.length > 0) {
|
if (staticSymbol.members.length > 0) {
|
||||||
return this._resolveSymbolMembers(staticSymbol) !;
|
return this._resolveSymbolMembers(staticSymbol)!;
|
||||||
}
|
}
|
||||||
// Note: always ask for a summary first,
|
// Note: always ask for a summary first,
|
||||||
// as we might have read shallow metadata via a .d.ts file
|
// as we might have read shallow metadata via a .d.ts file
|
||||||
// for the symbol.
|
// for the symbol.
|
||||||
const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol) !;
|
const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol)!;
|
||||||
if (resultFromSummary) {
|
if (resultFromSummary) {
|
||||||
return resultFromSummary;
|
return resultFromSummary;
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ export class StaticSymbolResolver {
|
|||||||
// have summaries, only .d.ts files. So we always need to check both, the summary
|
// have summaries, only .d.ts files. So we always need to check both, the summary
|
||||||
// and metadata.
|
// and metadata.
|
||||||
this._createSymbolsOf(staticSymbol.filePath);
|
this._createSymbolsOf(staticSymbol.filePath);
|
||||||
return this.resolvedSymbols.get(staticSymbol) !;
|
return this.resolvedSymbols.get(staticSymbol)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,15 +119,14 @@ export class StaticSymbolResolver {
|
|||||||
const baseSymbol =
|
const baseSymbol =
|
||||||
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
||||||
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
||||||
return baseImportAs ?
|
return baseImportAs ? this.getStaticSymbol(
|
||||||
this.getStaticSymbol(
|
summaryForJitFileName(baseImportAs.filePath),
|
||||||
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
summaryForJitName(baseImportAs.name), baseSymbol.members) :
|
||||||
baseSymbol.members) :
|
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = this.importAs.get(staticSymbol) !;
|
result = this.importAs.get(staticSymbol)!;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -347,8 +346,8 @@ export class StaticSymbolResolver {
|
|||||||
// correctly.
|
// correctly.
|
||||||
const originFilePath = this.resolveModule(origin, filePath);
|
const originFilePath = this.resolveModule(origin, filePath);
|
||||||
if (!originFilePath) {
|
if (!originFilePath) {
|
||||||
this.reportError(new Error(
|
this.reportError(new Error(`Couldn't resolve original symbol for ${origin} from ${
|
||||||
`Couldn't resolve original symbol for ${origin} from ${this.host.getOutputName(filePath)}`));
|
this.host.getOutputName(filePath)}`));
|
||||||
} else {
|
} else {
|
||||||
this.symbolResourcePaths.set(symbol, originFilePath);
|
this.symbolResourcePaths.set(symbol, originFilePath);
|
||||||
}
|
}
|
||||||
@ -413,7 +412,7 @@ export class StaticSymbolResolver {
|
|||||||
}
|
}
|
||||||
let filePath: string;
|
let filePath: string;
|
||||||
if (module) {
|
if (module) {
|
||||||
filePath = self.resolveModule(module, sourceSymbol.filePath) !;
|
filePath = self.resolveModule(module, sourceSymbol.filePath)!;
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
return {
|
return {
|
||||||
__symbolic: 'error',
|
__symbolic: 'error',
|
||||||
@ -501,8 +500,11 @@ export class StaticSymbolResolver {
|
|||||||
}
|
}
|
||||||
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
||||||
const errorMessage = moduleMetadata['version'] == 2 ?
|
const errorMessage = moduleMetadata['version'] == 2 ?
|
||||||
`Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
|
`Unsupported metadata version ${moduleMetadata['version']} for module ${
|
||||||
`Metadata version mismatch for module ${this.host.getOutputName(module)}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
|
module}. This module should be compiled with a newer version of ngc` :
|
||||||
|
`Metadata version mismatch for module ${
|
||||||
|
this.host.getOutputName(module)}, found version ${
|
||||||
|
moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
|
||||||
this.reportError(new Error(errorMessage));
|
this.reportError(new Error(errorMessage));
|
||||||
}
|
}
|
||||||
this.metadataCache.set(module, moduleMetadata);
|
this.metadataCache.set(module, moduleMetadata);
|
||||||
@ -514,9 +516,8 @@ export class StaticSymbolResolver {
|
|||||||
getSymbolByModule(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
getSymbolByModule(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||||
const filePath = this.resolveModule(module, containingFile);
|
const filePath = this.resolveModule(module, containingFile);
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
this.reportError(
|
this.reportError(new Error(`Could not resolve module ${module}${
|
||||||
new Error(`Could not resolve module ${module}${containingFile ? ' relative to ' +
|
containingFile ? ' relative to ' + this.host.getOutputName(containingFile) : ''}`));
|
||||||
this.host.getOutputName(containingFile) : ''}`));
|
|
||||||
return this.getStaticSymbol(`ERROR:${module}`, symbolName);
|
return this.getStaticSymbol(`ERROR:${module}`, symbolName);
|
||||||
}
|
}
|
||||||
return this.getStaticSymbol(filePath, symbolName);
|
return this.getStaticSymbol(filePath, symbolName);
|
||||||
|
@ -71,7 +71,7 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
|||||||
let summary = this.summaryCache.get(rootSymbol);
|
let summary = this.summaryCache.get(rootSymbol);
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
this._loadSummaryFile(staticSymbol.filePath);
|
this._loadSummaryFile(staticSymbol.filePath);
|
||||||
summary = this.summaryCache.get(staticSymbol) !;
|
summary = this.summaryCache.get(staticSymbol)!;
|
||||||
}
|
}
|
||||||
return (rootSymbol === staticSymbol && summary) || null;
|
return (rootSymbol === staticSymbol && summary) || null;
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
|||||||
|
|
||||||
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
||||||
staticSymbol.assertNoMembers();
|
staticSymbol.assertNoMembers();
|
||||||
return this.importAs.get(staticSymbol) !;
|
return this.importAs.get(staticSymbol)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,7 +95,9 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
|||||||
return this.knownFileNameToModuleNames.get(importedFilePath) || null;
|
return this.knownFileNameToModuleNames.get(importedFilePath) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
addSummary(summary: Summary<StaticSymbol>) { this.summaryCache.set(summary.symbol, summary); }
|
addSummary(summary: Summary<StaticSymbol>) {
|
||||||
|
this.summaryCache.set(summary.symbol, summary);
|
||||||
|
}
|
||||||
|
|
||||||
private _loadSummaryFile(filePath: string): boolean {
|
private _loadSummaryFile(filePath: string): boolean {
|
||||||
let hasSummary = this.loadedFilePaths.get(filePath);
|
let hasSummary = this.loadedFilePaths.get(filePath);
|
||||||
@ -121,7 +123,9 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
|||||||
if (moduleName) {
|
if (moduleName) {
|
||||||
this.knownFileNameToModuleNames.set(filePath, moduleName);
|
this.knownFileNameToModuleNames.set(filePath, moduleName);
|
||||||
}
|
}
|
||||||
importAs.forEach((importAs) => { this.importAs.set(importAs.symbol, importAs.importAs); });
|
importAs.forEach((importAs) => {
|
||||||
|
this.importAs.set(importAs.symbol, importAs.importAs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return hasSummary;
|
return hasSummary;
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,11 @@ import {ResolvedStaticSymbol, StaticSymbolResolver, unwrapResolvedMetadata} from
|
|||||||
import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util';
|
import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util';
|
||||||
|
|
||||||
export function serializeSummaries(
|
export function serializeSummaries(
|
||||||
srcFileName: string, forJitCtx: OutputContext | null,
|
srcFileName: string, forJitCtx: OutputContext|null,
|
||||||
summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver,
|
summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver,
|
||||||
symbols: ResolvedStaticSymbol[], types: {
|
symbols: ResolvedStaticSymbol[], types: {
|
||||||
summary: CompileTypeSummary,
|
summary: CompileTypeSummary,
|
||||||
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
|
metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata|
|
||||||
CompileTypeMetadata
|
CompileTypeMetadata
|
||||||
}[],
|
}[],
|
||||||
createExternalSymbolReexports =
|
createExternalSymbolReexports =
|
||||||
@ -41,7 +41,9 @@ export function serializeSummaries(
|
|||||||
const {json, exportAs} = toJsonSerializer.serialize(createExternalSymbolReexports);
|
const {json, exportAs} = toJsonSerializer.serialize(createExternalSymbolReexports);
|
||||||
if (forJitCtx) {
|
if (forJitCtx) {
|
||||||
const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver);
|
const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver);
|
||||||
types.forEach(({summary, metadata}) => { forJitSerializer.addSourceType(summary, metadata); });
|
types.forEach(({summary, metadata}) => {
|
||||||
|
forJitSerializer.addSourceType(summary, metadata);
|
||||||
|
});
|
||||||
toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach((summary) => {
|
toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach((summary) => {
|
||||||
if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) {
|
if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) {
|
||||||
forJitSerializer.addLibType(summary.type);
|
forJitSerializer.addLibType(summary.type);
|
||||||
@ -55,7 +57,7 @@ export function serializeSummaries(
|
|||||||
export function deserializeSummaries(
|
export function deserializeSummaries(
|
||||||
symbolCache: StaticSymbolCache, summaryResolver: SummaryResolver<StaticSymbol>,
|
symbolCache: StaticSymbolCache, summaryResolver: SummaryResolver<StaticSymbol>,
|
||||||
libraryFileName: string, json: string): {
|
libraryFileName: string, json: string): {
|
||||||
moduleName: string | null,
|
moduleName: string|null,
|
||||||
summaries: Summary<StaticSymbol>[],
|
summaries: Summary<StaticSymbol>[],
|
||||||
importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[]
|
importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[]
|
||||||
} {
|
} {
|
||||||
@ -144,7 +146,7 @@ class ToJsonSerializer extends ValueTransformer {
|
|||||||
processedSummary.metadata = this.processValue(metadata, SerializationFlags.ResolveValue);
|
processedSummary.metadata = this.processValue(metadata, SerializationFlags.ResolveValue);
|
||||||
if (metadata instanceof StaticSymbol &&
|
if (metadata instanceof StaticSymbol &&
|
||||||
this.summaryResolver.isLibraryFile(metadata.filePath)) {
|
this.summaryResolver.isLibraryFile(metadata.filePath)) {
|
||||||
const declarationSymbol = this.symbols[this.indexBySymbol.get(metadata) !];
|
const declarationSymbol = this.symbols[this.indexBySymbol.get(metadata)!];
|
||||||
if (!isLoweredSymbol(declarationSymbol.name)) {
|
if (!isLoweredSymbol(declarationSymbol.name)) {
|
||||||
// Note: symbols that were introduced during codegen in the user file can have a reexport
|
// Note: symbols that were introduced during codegen in the user file can have a reexport
|
||||||
// if a user used `export *`. However, we can't rely on this as tsickle will change
|
// if a user used `export *`. However, we can't rely on this as tsickle will change
|
||||||
@ -194,7 +196,7 @@ class ToJsonSerializer extends ValueTransformer {
|
|||||||
summaries: this.processedSummaries,
|
summaries: this.processedSummaries,
|
||||||
symbols: this.symbols.map((symbol, index) => {
|
symbols: this.symbols.map((symbol, index) => {
|
||||||
symbol.assertNoMembers();
|
symbol.assertNoMembers();
|
||||||
let importAs: string|number = undefined !;
|
let importAs: string|number = undefined!;
|
||||||
if (this.summaryResolver.isLibraryFile(symbol.filePath)) {
|
if (this.summaryResolver.isLibraryFile(symbol.filePath)) {
|
||||||
const reexportSymbol = this.reexportedBy.get(symbol);
|
const reexportSymbol = this.reexportedBy.get(symbol);
|
||||||
if (reexportSymbol) {
|
if (reexportSymbol) {
|
||||||
@ -202,7 +204,7 @@ class ToJsonSerializer extends ValueTransformer {
|
|||||||
// user, we just proxy the external static symbol reference to the manual export.
|
// user, we just proxy the external static symbol reference to the manual export.
|
||||||
// This ensures that the AOT compiler imports the external symbol through the
|
// This ensures that the AOT compiler imports the external symbol through the
|
||||||
// user export and does not introduce another dependency which is not needed.
|
// user export and does not introduce another dependency which is not needed.
|
||||||
importAs = this.indexBySymbol.get(reexportSymbol) !;
|
importAs = this.indexBySymbol.get(reexportSymbol)!;
|
||||||
} else if (createExternalSymbolReexports) {
|
} else if (createExternalSymbolReexports) {
|
||||||
// In this case, the given external static symbol is *not* manually exported by
|
// In this case, the given external static symbol is *not* manually exported by
|
||||||
// the user, and we manually create a re-export in the factory file so that we
|
// the user, and we manually create a re-export in the factory file so that we
|
||||||
@ -270,7 +272,7 @@ class ToJsonSerializer extends ValueTransformer {
|
|||||||
if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) {
|
if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) {
|
||||||
// the summary for this symbol was already added
|
// the summary for this symbol was already added
|
||||||
// -> nothing to do.
|
// -> nothing to do.
|
||||||
return index !;
|
return index!;
|
||||||
}
|
}
|
||||||
summary = this.loadSummary(baseSymbol);
|
summary = this.loadSummary(baseSymbol);
|
||||||
if (summary && summary.metadata instanceof StaticSymbol) {
|
if (summary && summary.metadata instanceof StaticSymbol) {
|
||||||
@ -324,8 +326,9 @@ class ForJitSerializer {
|
|||||||
private summaryResolver: SummaryResolver<StaticSymbol>) {}
|
private summaryResolver: SummaryResolver<StaticSymbol>) {}
|
||||||
|
|
||||||
addSourceType(
|
addSourceType(
|
||||||
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
|
summary: CompileTypeSummary,
|
||||||
CompilePipeMetadata|CompileTypeMetadata) {
|
metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata|
|
||||||
|
CompileTypeMetadata) {
|
||||||
this.data.push({summary, metadata, isLibrary: false});
|
this.data.push({summary, metadata, isLibrary: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +359,7 @@ class ForJitSerializer {
|
|||||||
const fnName = summaryForJitName(summary.type.reference.name);
|
const fnName = summaryForJitName(summary.type.reference.name);
|
||||||
createSummaryForJitFunction(
|
createSummaryForJitFunction(
|
||||||
this.outputCtx, summary.type.reference,
|
this.outputCtx, summary.type.reference,
|
||||||
this.serializeSummaryWithDeps(summary, metadata !));
|
this.serializeSummaryWithDeps(summary, metadata!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,8 +375,9 @@ class ForJitSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private serializeSummaryWithDeps(
|
private serializeSummaryWithDeps(
|
||||||
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
|
summary: CompileTypeSummary,
|
||||||
CompilePipeMetadata|CompileTypeMetadata): o.Expression {
|
metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata|
|
||||||
|
CompileTypeMetadata): o.Expression {
|
||||||
const expressions: o.Expression[] = [this.serializeSummary(summary)];
|
const expressions: o.Expression[] = [this.serializeSummary(summary)];
|
||||||
let providers: CompileProviderMetadata[] = [];
|
let providers: CompileProviderMetadata[] = [];
|
||||||
if (metadata instanceof CompileNgModuleMetadata) {
|
if (metadata instanceof CompileNgModuleMetadata) {
|
||||||
@ -403,7 +407,8 @@ class ForJitSerializer {
|
|||||||
// i.e. we didn't generate .ngsummary.ts files for these.
|
// i.e. we didn't generate .ngsummary.ts files for these.
|
||||||
expressions.push(
|
expressions.push(
|
||||||
...providers.filter(provider => !!provider.useClass).map(provider => this.serializeSummary({
|
...providers.filter(provider => !!provider.useClass).map(provider => this.serializeSummary({
|
||||||
summaryKind: CompileSummaryKind.Injectable, type: provider.useClass
|
summaryKind: CompileSummaryKind.Injectable,
|
||||||
|
type: provider.useClass
|
||||||
} as CompileTypeSummary)));
|
} as CompileTypeSummary)));
|
||||||
return o.literalArr(expressions);
|
return o.literalArr(expressions);
|
||||||
}
|
}
|
||||||
@ -425,7 +430,9 @@ class ForJitSerializer {
|
|||||||
return new o.LiteralMapExpr(Object.keys(map).map(
|
return new o.LiteralMapExpr(Object.keys(map).map(
|
||||||
(key) => new o.LiteralMapEntry(key, visitValue(map[key], this, context), false)));
|
(key) => new o.LiteralMapEntry(key, visitValue(map[key], this, context), false)));
|
||||||
}
|
}
|
||||||
visitPrimitive(value: any, context: any): any { return o.literal(value); }
|
visitPrimitive(value: any, context: any): any {
|
||||||
|
return o.literal(value);
|
||||||
|
}
|
||||||
visitOther(value: any, context: any): any {
|
visitOther(value: any, context: any): any {
|
||||||
if (value instanceof StaticSymbol) {
|
if (value instanceof StaticSymbol) {
|
||||||
return outputCtx.importExpr(value);
|
return outputCtx.importExpr(value);
|
||||||
@ -441,7 +448,7 @@ class ForJitSerializer {
|
|||||||
|
|
||||||
class FromJsonDeserializer extends ValueTransformer {
|
class FromJsonDeserializer extends ValueTransformer {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private symbols !: StaticSymbol[];
|
private symbols!: StaticSymbol[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private symbolCache: StaticSymbolCache,
|
private symbolCache: StaticSymbolCache,
|
||||||
@ -450,11 +457,11 @@ class FromJsonDeserializer extends ValueTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deserialize(libraryFileName: string, json: string): {
|
deserialize(libraryFileName: string, json: string): {
|
||||||
moduleName: string | null,
|
moduleName: string|null,
|
||||||
summaries: Summary<StaticSymbol>[],
|
summaries: Summary<StaticSymbol>[],
|
||||||
importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[]
|
importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[]
|
||||||
} {
|
} {
|
||||||
const data: {moduleName: string | null, summaries: any[], symbols: any[]} = JSON.parse(json);
|
const data: {moduleName: string|null, summaries: any[], symbols: any[]} = JSON.parse(json);
|
||||||
const allImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = [];
|
const allImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = [];
|
||||||
this.symbols = data.symbols.map(
|
this.symbols = data.symbols.map(
|
||||||
(serializedSymbol) => this.symbolCache.get(
|
(serializedSymbol) => this.symbolCache.get(
|
||||||
|
@ -26,23 +26,35 @@
|
|||||||
export class AstPath<T> {
|
export class AstPath<T> {
|
||||||
constructor(private path: T[], public position: number = -1) {}
|
constructor(private path: T[], public position: number = -1) {}
|
||||||
|
|
||||||
get empty(): boolean { return !this.path || !this.path.length; }
|
get empty(): boolean {
|
||||||
get head(): T|undefined { return this.path[0]; }
|
return !this.path || !this.path.length;
|
||||||
get tail(): T|undefined { return this.path[this.path.length - 1]; }
|
}
|
||||||
|
get head(): T|undefined {
|
||||||
|
return this.path[0];
|
||||||
|
}
|
||||||
|
get tail(): T|undefined {
|
||||||
|
return this.path[this.path.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
parentOf(node: T|undefined): T|undefined {
|
parentOf(node: T|undefined): T|undefined {
|
||||||
return node && this.path[this.path.indexOf(node) - 1];
|
return node && this.path[this.path.indexOf(node) - 1];
|
||||||
}
|
}
|
||||||
childOf(node: T): T|undefined { return this.path[this.path.indexOf(node) + 1]; }
|
childOf(node: T): T|undefined {
|
||||||
|
return this.path[this.path.indexOf(node) + 1];
|
||||||
|
}
|
||||||
|
|
||||||
first<N extends T>(ctor: {new (...args: any[]): N}): N|undefined {
|
first<N extends T>(ctor: {new(...args: any[]): N}): N|undefined {
|
||||||
for (let i = this.path.length - 1; i >= 0; i--) {
|
for (let i = this.path.length - 1; i >= 0; i--) {
|
||||||
let item = this.path[i];
|
let item = this.path[i];
|
||||||
if (item instanceof ctor) return <N>item;
|
if (item instanceof ctor) return <N>item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
push(node: T) { this.path.push(node); }
|
push(node: T) {
|
||||||
|
this.path.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
pop(): T { return this.path.pop() !; }
|
pop(): T {
|
||||||
|
return this.path.pop()!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ export function sanitizeIdentifier(name: string): string {
|
|||||||
|
|
||||||
let _anonymousTypeIndex = 0;
|
let _anonymousTypeIndex = 0;
|
||||||
|
|
||||||
export function identifierName(compileIdentifier: CompileIdentifierMetadata | null | undefined):
|
export function identifierName(compileIdentifier: CompileIdentifierMetadata|null|undefined): string|
|
||||||
string|null {
|
null {
|
||||||
if (!compileIdentifier || !compileIdentifier.reference) {
|
if (!compileIdentifier || !compileIdentifier.reference) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -72,9 +72,13 @@ export function componentFactoryName(compType: any): string {
|
|||||||
return `${identifierName({reference: compType})}NgFactory`;
|
return `${identifierName({reference: compType})}NgFactory`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProxyClass { setDelegate(delegate: any): void; }
|
export interface ProxyClass {
|
||||||
|
setDelegate(delegate: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CompileIdentifierMetadata { reference: any; }
|
export interface CompileIdentifierMetadata {
|
||||||
|
reference: any;
|
||||||
|
}
|
||||||
|
|
||||||
export enum CompileSummaryKind {
|
export enum CompileSummaryKind {
|
||||||
Pipe,
|
Pipe,
|
||||||
@ -175,8 +179,8 @@ export class CompileStylesheetMetadata {
|
|||||||
styles: string[];
|
styles: string[];
|
||||||
styleUrls: string[];
|
styleUrls: string[];
|
||||||
constructor(
|
constructor(
|
||||||
{moduleUrl, styles,
|
{moduleUrl, styles, styleUrls}:
|
||||||
styleUrls}: {moduleUrl?: string, styles?: string[], styleUrls?: string[]} = {}) {
|
{moduleUrl?: string, styles?: string[], styleUrls?: string[]} = {}) {
|
||||||
this.moduleUrl = moduleUrl || null;
|
this.moduleUrl = moduleUrl || null;
|
||||||
this.styles = _normalizeArray(styles);
|
this.styles = _normalizeArray(styles);
|
||||||
this.styleUrls = _normalizeArray(styleUrls);
|
this.styleUrls = _normalizeArray(styleUrls);
|
||||||
@ -209,10 +213,21 @@ export class CompileTemplateMetadata {
|
|||||||
ngContentSelectors: string[];
|
ngContentSelectors: string[];
|
||||||
interpolation: [string, string]|null;
|
interpolation: [string, string]|null;
|
||||||
preserveWhitespaces: boolean;
|
preserveWhitespaces: boolean;
|
||||||
constructor({encapsulation, template, templateUrl, htmlAst, styles, styleUrls,
|
constructor({
|
||||||
externalStylesheets, animations, ngContentSelectors, interpolation, isInline,
|
encapsulation,
|
||||||
preserveWhitespaces}: {
|
template,
|
||||||
encapsulation: ViewEncapsulation | null,
|
templateUrl,
|
||||||
|
htmlAst,
|
||||||
|
styles,
|
||||||
|
styleUrls,
|
||||||
|
externalStylesheets,
|
||||||
|
animations,
|
||||||
|
ngContentSelectors,
|
||||||
|
interpolation,
|
||||||
|
isInline,
|
||||||
|
preserveWhitespaces
|
||||||
|
}: {
|
||||||
|
encapsulation: ViewEncapsulation|null,
|
||||||
template: string|null,
|
template: string|null,
|
||||||
templateUrl: string|null,
|
templateUrl: string|null,
|
||||||
htmlAst: HtmlParseTreeResult|null,
|
htmlAst: HtmlParseTreeResult|null,
|
||||||
@ -286,9 +301,27 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
|||||||
* Metadata regarding compilation of a directive.
|
* Metadata regarding compilation of a directive.
|
||||||
*/
|
*/
|
||||||
export class CompileDirectiveMetadata {
|
export class CompileDirectiveMetadata {
|
||||||
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
static create({
|
||||||
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
|
isHost,
|
||||||
template, componentViewType, rendererType, componentFactory}: {
|
type,
|
||||||
|
isComponent,
|
||||||
|
selector,
|
||||||
|
exportAs,
|
||||||
|
changeDetection,
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
host,
|
||||||
|
providers,
|
||||||
|
viewProviders,
|
||||||
|
queries,
|
||||||
|
guards,
|
||||||
|
viewQueries,
|
||||||
|
entryComponents,
|
||||||
|
template,
|
||||||
|
componentViewType,
|
||||||
|
rendererType,
|
||||||
|
componentFactory
|
||||||
|
}: {
|
||||||
isHost: boolean,
|
isHost: boolean,
|
||||||
type: CompileTypeMetadata,
|
type: CompileTypeMetadata,
|
||||||
isComponent: boolean,
|
isComponent: boolean,
|
||||||
@ -347,7 +380,10 @@ export class CompileDirectiveMetadata {
|
|||||||
return new CompileDirectiveMetadata({
|
return new CompileDirectiveMetadata({
|
||||||
isHost,
|
isHost,
|
||||||
type,
|
type,
|
||||||
isComponent: !!isComponent, selector, exportAs, changeDetection,
|
isComponent: !!isComponent,
|
||||||
|
selector,
|
||||||
|
exportAs,
|
||||||
|
changeDetection,
|
||||||
inputs: inputsMap,
|
inputs: inputsMap,
|
||||||
outputs: outputsMap,
|
outputs: outputsMap,
|
||||||
hostListeners,
|
hostListeners,
|
||||||
@ -389,7 +425,8 @@ export class CompileDirectiveMetadata {
|
|||||||
rendererType: StaticSymbol|object|null;
|
rendererType: StaticSymbol|object|null;
|
||||||
componentFactory: StaticSymbol|object|null;
|
componentFactory: StaticSymbol|object|null;
|
||||||
|
|
||||||
constructor({isHost,
|
constructor({
|
||||||
|
isHost,
|
||||||
type,
|
type,
|
||||||
isComponent,
|
isComponent,
|
||||||
selector,
|
selector,
|
||||||
@ -409,7 +446,8 @@ export class CompileDirectiveMetadata {
|
|||||||
template,
|
template,
|
||||||
componentViewType,
|
componentViewType,
|
||||||
rendererType,
|
rendererType,
|
||||||
componentFactory}: {
|
componentFactory
|
||||||
|
}: {
|
||||||
isHost: boolean,
|
isHost: boolean,
|
||||||
type: CompileTypeMetadata,
|
type: CompileTypeMetadata,
|
||||||
isComponent: boolean,
|
isComponent: boolean,
|
||||||
@ -534,7 +572,7 @@ export interface CompileNgModuleSummary extends CompileTypeSummary {
|
|||||||
|
|
||||||
export class CompileShallowModuleMetadata {
|
export class CompileShallowModuleMetadata {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
type !: CompileTypeMetadata;
|
type!: CompileTypeMetadata;
|
||||||
|
|
||||||
rawExports: any;
|
rawExports: any;
|
||||||
rawImports: any;
|
rawImports: any;
|
||||||
@ -562,9 +600,21 @@ export class CompileNgModuleMetadata {
|
|||||||
|
|
||||||
transitiveModule: TransitiveCompileNgModuleMetadata;
|
transitiveModule: TransitiveCompileNgModuleMetadata;
|
||||||
|
|
||||||
constructor({type, providers, declaredDirectives, exportedDirectives, declaredPipes,
|
constructor({
|
||||||
exportedPipes, entryComponents, bootstrapComponents, importedModules,
|
type,
|
||||||
exportedModules, schemas, transitiveModule, id}: {
|
providers,
|
||||||
|
declaredDirectives,
|
||||||
|
exportedDirectives,
|
||||||
|
declaredPipes,
|
||||||
|
exportedPipes,
|
||||||
|
entryComponents,
|
||||||
|
bootstrapComponents,
|
||||||
|
importedModules,
|
||||||
|
exportedModules,
|
||||||
|
schemas,
|
||||||
|
transitiveModule,
|
||||||
|
id
|
||||||
|
}: {
|
||||||
type: CompileTypeMetadata,
|
type: CompileTypeMetadata,
|
||||||
providers: CompileProviderMetadata[],
|
providers: CompileProviderMetadata[],
|
||||||
declaredDirectives: CompileIdentifierMetadata[],
|
declaredDirectives: CompileIdentifierMetadata[],
|
||||||
@ -595,7 +645,7 @@ export class CompileNgModuleMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toSummary(): CompileNgModuleSummary {
|
toSummary(): CompileNgModuleSummary {
|
||||||
const module = this.transitiveModule !;
|
const module = this.transitiveModule!;
|
||||||
return {
|
return {
|
||||||
summaryKind: CompileSummaryKind.NgModule,
|
summaryKind: CompileSummaryKind.NgModule,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
@ -666,7 +716,7 @@ export class TransitiveCompileNgModuleMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _normalizeArray(obj: any[] | undefined | null): any[] {
|
function _normalizeArray(obj: any[]|undefined|null): any[] {
|
||||||
return obj || [];
|
return obj || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +748,7 @@ export class ProviderMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function flatten<T>(list: Array<T|T[]>): T[] {
|
export function flatten<T>(list: Array<T|T[]>): T[] {
|
||||||
return list.reduce((flat: any[], item: T | T[]): T[] => {
|
return list.reduce((flat: any[], item: T|T[]): T[] => {
|
||||||
const flatItem = Array.isArray(item) ? flatten(item) : item;
|
const flatItem = Array.isArray(item) ? flatten(item) : item;
|
||||||
return (<T[]>flat).concat(flatItem);
|
return (<T[]>flat).concat(flatItem);
|
||||||
}, []);
|
}, []);
|
||||||
@ -712,7 +762,7 @@ function jitSourceUrl(url: string) {
|
|||||||
|
|
||||||
export function templateSourceUrl(
|
export function templateSourceUrl(
|
||||||
ngModuleType: CompileIdentifierMetadata, compMeta: {type: CompileIdentifierMetadata},
|
ngModuleType: CompileIdentifierMetadata, compMeta: {type: CompileIdentifierMetadata},
|
||||||
templateMeta: {isInline: boolean, templateUrl: string | null}) {
|
templateMeta: {isInline: boolean, templateUrl: string|null}) {
|
||||||
let url: string;
|
let url: string;
|
||||||
if (templateMeta.isInline) {
|
if (templateMeta.isInline) {
|
||||||
if (compMeta.type.reference instanceof StaticSymbol) {
|
if (compMeta.type.reference instanceof StaticSymbol) {
|
||||||
@ -723,13 +773,13 @@ export function templateSourceUrl(
|
|||||||
url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`;
|
url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
url = templateMeta.templateUrl !;
|
url = templateMeta.templateUrl!;
|
||||||
}
|
}
|
||||||
return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
|
return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sharedStylesheetJitUrl(meta: CompileStylesheetMetadata, id: number) {
|
export function sharedStylesheetJitUrl(meta: CompileStylesheetMetadata, id: number) {
|
||||||
const pathParts = meta.moduleUrl !.split(/\/\\/g);
|
const pathParts = meta.moduleUrl!.split(/\/\\/g);
|
||||||
const baseName = pathParts[pathParts.length - 1];
|
const baseName = pathParts[pathParts.length - 1];
|
||||||
return jitSourceUrl(`css/${id}${baseName}.ngstyle.js`);
|
return jitSourceUrl(`css/${id}${baseName}.ngstyle.js`);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; }
|
export interface ExportedCompilerFacade {
|
||||||
|
ɵcompilerFacade: CompilerFacade;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CompilerFacade {
|
export interface CompilerFacade {
|
||||||
compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade):
|
compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade):
|
||||||
@ -44,13 +46,15 @@ export interface CompilerFacade {
|
|||||||
|
|
||||||
R3ResolvedDependencyType: typeof R3ResolvedDependencyType;
|
R3ResolvedDependencyType: typeof R3ResolvedDependencyType;
|
||||||
R3FactoryTarget: typeof R3FactoryTarget;
|
R3FactoryTarget: typeof R3FactoryTarget;
|
||||||
ResourceLoader: {new (): ResourceLoader};
|
ResourceLoader: {new(): ResourceLoader};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreEnvironment { [name: string]: Function; }
|
export interface CoreEnvironment {
|
||||||
|
[name: string]: Function;
|
||||||
|
}
|
||||||
|
|
||||||
export type ResourceLoader = {
|
export type ResourceLoader = {
|
||||||
get(url: string): Promise<string>| string;
|
get(url: string): Promise<string>|string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StringMap = {
|
export type StringMap = {
|
||||||
@ -58,7 +62,7 @@ export type StringMap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type StringMapWithRename = {
|
export type StringMapWithRename = {
|
||||||
[key: string]: string | [string, string];
|
[key: string]: string|[string, string];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Provider = any;
|
export type Provider = any;
|
||||||
|
@ -11,7 +11,9 @@ import {Identifiers} from '../identifiers';
|
|||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {ParseSourceSpan} from '../parse_util';
|
import {ParseSourceSpan} from '../parse_util';
|
||||||
|
|
||||||
export class EventHandlerVars { static event = o.variable('$event'); }
|
export class EventHandlerVars {
|
||||||
|
static event = o.variable('$event');
|
||||||
|
}
|
||||||
|
|
||||||
export interface LocalResolver {
|
export interface LocalResolver {
|
||||||
getLocal(name: string): o.Expression|null;
|
getLocal(name: string): o.Expression|null;
|
||||||
@ -68,7 +70,7 @@ export type InterpolationFunction = (args: o.Expression[]) => o.Expression;
|
|||||||
* used in an action binding (e.g. an event handler).
|
* used in an action binding (e.g. an event handler).
|
||||||
*/
|
*/
|
||||||
export function convertActionBinding(
|
export function convertActionBinding(
|
||||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST,
|
localResolver: LocalResolver|null, implicitReceiver: o.Expression, action: cdAst.AST,
|
||||||
bindingId: string, interpolationFunction?: InterpolationFunction,
|
bindingId: string, interpolationFunction?: InterpolationFunction,
|
||||||
baseSourceSpan?: ParseSourceSpan,
|
baseSourceSpan?: ParseSourceSpan,
|
||||||
implicitReceiverAccesses?: Set<string>): ConvertActionBindingResult {
|
implicitReceiverAccesses?: Set<string>): ConvertActionBindingResult {
|
||||||
@ -110,7 +112,7 @@ export function convertActionBinding(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lastIndex = actionStmts.length - 1;
|
const lastIndex = actionStmts.length - 1;
|
||||||
let preventDefaultVar: o.ReadVarExpr = null !;
|
let preventDefaultVar: o.ReadVarExpr = null!;
|
||||||
if (lastIndex >= 0) {
|
if (lastIndex >= 0) {
|
||||||
const lastStatement = actionStmts[lastIndex];
|
const lastStatement = actionStmts[lastIndex];
|
||||||
const returnExpr = convertStmtIntoExpression(lastStatement);
|
const returnExpr = convertStmtIntoExpression(lastStatement);
|
||||||
@ -126,7 +128,9 @@ export function convertActionBinding(
|
|||||||
return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
|
return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BuiltinConverter { (args: o.Expression[]): o.Expression; }
|
export interface BuiltinConverter {
|
||||||
|
(args: o.Expression[]): o.Expression;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BuiltinConverterFactory {
|
export interface BuiltinConverterFactory {
|
||||||
createLiteralArrayConverter(argCount: number): BuiltinConverter;
|
createLiteralArrayConverter(argCount: number): BuiltinConverter;
|
||||||
@ -158,7 +162,7 @@ export enum BindingForm {
|
|||||||
* `convertPropertyBindingBuiltins`.
|
* `convertPropertyBindingBuiltins`.
|
||||||
*/
|
*/
|
||||||
export function convertPropertyBinding(
|
export function convertPropertyBinding(
|
||||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
|
localResolver: LocalResolver|null, implicitReceiver: o.Expression,
|
||||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string, form: BindingForm,
|
expressionWithoutBuiltins: cdAst.AST, bindingId: string, form: BindingForm,
|
||||||
interpolationFunction?: InterpolationFunction): ConvertPropertyBindingResult {
|
interpolationFunction?: InterpolationFunction): ConvertPropertyBindingResult {
|
||||||
if (!localResolver) {
|
if (!localResolver) {
|
||||||
@ -284,7 +288,9 @@ function convertToStatementIfNeeded(mode: _Mode, expr: o.Expression): o.Expressi
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _BuiltinAstConverter extends cdAst.AstTransformer {
|
class _BuiltinAstConverter extends cdAst.AstTransformer {
|
||||||
constructor(private _converterFactory: BuiltinConverterFactory) { super(); }
|
constructor(private _converterFactory: BuiltinConverterFactory) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
visitPipe(ast: cdAst.BindingPipe, context: any): any {
|
visitPipe(ast: cdAst.BindingPipe, context: any): any {
|
||||||
const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
|
const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
|
||||||
return new BuiltinFunctionCall(
|
return new BuiltinFunctionCall(
|
||||||
@ -384,9 +390,10 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
visitConditional(ast: cdAst.Conditional, mode: _Mode): any {
|
visitConditional(ast: cdAst.Conditional, mode: _Mode): any {
|
||||||
const value: o.Expression = this._visit(ast.condition, _Mode.Expression);
|
const value: o.Expression = this._visit(ast.condition, _Mode.Expression);
|
||||||
return convertToStatementIfNeeded(
|
return convertToStatementIfNeeded(
|
||||||
mode, value.conditional(
|
mode,
|
||||||
this._visit(ast.trueExp, _Mode.Expression),
|
value.conditional(
|
||||||
this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
|
this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression),
|
||||||
|
this.convertSourceSpan(ast.span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any {
|
visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any {
|
||||||
@ -400,7 +407,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
if (ast instanceof BuiltinFunctionCall) {
|
if (ast instanceof BuiltinFunctionCall) {
|
||||||
fnResult = ast.converter(convertedArgs);
|
fnResult = ast.converter(convertedArgs);
|
||||||
} else {
|
} else {
|
||||||
fnResult = this._visit(ast.target !, _Mode.Expression)
|
fnResult = this._visit(ast.target!, _Mode.Expression)
|
||||||
.callFn(convertedArgs, this.convertSourceSpan(ast.span));
|
.callFn(convertedArgs, this.convertSourceSpan(ast.span));
|
||||||
}
|
}
|
||||||
return convertToStatementIfNeeded(mode, fnResult);
|
return convertToStatementIfNeeded(mode, fnResult);
|
||||||
@ -467,7 +474,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
mode, o.literal(ast.value, type, this.convertSourceSpan(ast.span)));
|
mode, o.literal(ast.value, type, this.convertSourceSpan(ast.span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
private _getLocal(name: string): o.Expression|null {
|
||||||
|
return this._localResolver.getLocal(name);
|
||||||
|
}
|
||||||
|
|
||||||
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
||||||
if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') {
|
if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') {
|
||||||
@ -558,8 +567,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
// Otherwise it's an error.
|
// Otherwise it's an error.
|
||||||
const receiver = ast.name;
|
const receiver = ast.name;
|
||||||
const value = (ast.value instanceof cdAst.PropertyRead) ? ast.value.name : undefined;
|
const value = (ast.value instanceof cdAst.PropertyRead) ? ast.value.name : undefined;
|
||||||
throw new Error(
|
throw new Error(`Cannot assign value "${value}" to template variable "${
|
||||||
`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`);
|
receiver}". Template variables are read-only.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -579,7 +588,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
|
return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAll(asts: cdAst.AST[], mode: _Mode): any { return asts.map(ast => this._visit(ast, mode)); }
|
visitAll(asts: cdAst.AST[], mode: _Mode): any {
|
||||||
|
return asts.map(ast => this._visit(ast, mode));
|
||||||
|
}
|
||||||
|
|
||||||
visitQuote(ast: cdAst.Quote, mode: _Mode): any {
|
visitQuote(ast: cdAst.Quote, mode: _Mode): any {
|
||||||
throw new Error(`Quotes are not supported for evaluation!
|
throw new Error(`Quotes are not supported for evaluation!
|
||||||
@ -634,7 +645,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
// which comes in as leftMostSafe to this routine.
|
// which comes in as leftMostSafe to this routine.
|
||||||
|
|
||||||
let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
|
let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
|
||||||
let temporary: o.ReadVarExpr = undefined !;
|
let temporary: o.ReadVarExpr = undefined!;
|
||||||
if (this.needsTemporary(leftMostSafe.receiver)) {
|
if (this.needsTemporary(leftMostSafe.receiver)) {
|
||||||
// If the expression has method calls or pipes then we need to save the result into a
|
// If the expression has method calls or pipes then we need to save the result into a
|
||||||
// temporary variable to avoid calling stateful or impure code more than once.
|
// temporary variable to avoid calling stateful or impure code more than once.
|
||||||
@ -652,12 +663,14 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
// leftMostNode with its unguarded version in the call to `this.visit()`.
|
// leftMostNode with its unguarded version in the call to `this.visit()`.
|
||||||
if (leftMostSafe instanceof cdAst.SafeMethodCall) {
|
if (leftMostSafe instanceof cdAst.SafeMethodCall) {
|
||||||
this._nodeMap.set(
|
this._nodeMap.set(
|
||||||
leftMostSafe, new cdAst.MethodCall(
|
leftMostSafe,
|
||||||
leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver,
|
new cdAst.MethodCall(
|
||||||
leftMostSafe.name, leftMostSafe.args));
|
leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.name,
|
||||||
|
leftMostSafe.args));
|
||||||
} else {
|
} else {
|
||||||
this._nodeMap.set(
|
this._nodeMap.set(
|
||||||
leftMostSafe, new cdAst.PropertyRead(
|
leftMostSafe,
|
||||||
|
new cdAst.PropertyRead(
|
||||||
leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver,
|
leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver,
|
||||||
leftMostSafe.name));
|
leftMostSafe.name));
|
||||||
}
|
}
|
||||||
@ -690,25 +703,63 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
return (this._nodeMap.get(ast) || ast).visit(visitor);
|
return (this._nodeMap.get(ast) || ast).visit(visitor);
|
||||||
};
|
};
|
||||||
return ast.visit({
|
return ast.visit({
|
||||||
visitBinary(ast: cdAst.Binary) { return null; },
|
visitBinary(ast: cdAst.Binary) {
|
||||||
visitChain(ast: cdAst.Chain) { return null; },
|
return null;
|
||||||
visitConditional(ast: cdAst.Conditional) { return null; },
|
},
|
||||||
visitFunctionCall(ast: cdAst.FunctionCall) { return null; },
|
visitChain(ast: cdAst.Chain) {
|
||||||
visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { return null; },
|
return null;
|
||||||
visitInterpolation(ast: cdAst.Interpolation) { return null; },
|
},
|
||||||
visitKeyedRead(ast: cdAst.KeyedRead) { return visit(this, ast.obj); },
|
visitConditional(ast: cdAst.Conditional) {
|
||||||
visitKeyedWrite(ast: cdAst.KeyedWrite) { return null; },
|
return null;
|
||||||
visitLiteralArray(ast: cdAst.LiteralArray) { return null; },
|
},
|
||||||
visitLiteralMap(ast: cdAst.LiteralMap) { return null; },
|
visitFunctionCall(ast: cdAst.FunctionCall) {
|
||||||
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { return null; },
|
return null;
|
||||||
visitMethodCall(ast: cdAst.MethodCall) { return visit(this, ast.receiver); },
|
},
|
||||||
visitPipe(ast: cdAst.BindingPipe) { return null; },
|
visitImplicitReceiver(ast: cdAst.ImplicitReceiver) {
|
||||||
visitPrefixNot(ast: cdAst.PrefixNot) { return null; },
|
return null;
|
||||||
visitNonNullAssert(ast: cdAst.NonNullAssert) { return null; },
|
},
|
||||||
visitPropertyRead(ast: cdAst.PropertyRead) { return visit(this, ast.receiver); },
|
visitInterpolation(ast: cdAst.Interpolation) {
|
||||||
visitPropertyWrite(ast: cdAst.PropertyWrite) { return null; },
|
return null;
|
||||||
visitQuote(ast: cdAst.Quote) { return null; },
|
},
|
||||||
visitSafeMethodCall(ast: cdAst.SafeMethodCall) { return visit(this, ast.receiver) || ast; },
|
visitKeyedRead(ast: cdAst.KeyedRead) {
|
||||||
|
return visit(this, ast.obj);
|
||||||
|
},
|
||||||
|
visitKeyedWrite(ast: cdAst.KeyedWrite) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitLiteralArray(ast: cdAst.LiteralArray) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitLiteralMap(ast: cdAst.LiteralMap) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitMethodCall(ast: cdAst.MethodCall) {
|
||||||
|
return visit(this, ast.receiver);
|
||||||
|
},
|
||||||
|
visitPipe(ast: cdAst.BindingPipe) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitPrefixNot(ast: cdAst.PrefixNot) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitNonNullAssert(ast: cdAst.NonNullAssert) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitPropertyRead(ast: cdAst.PropertyRead) {
|
||||||
|
return visit(this, ast.receiver);
|
||||||
|
},
|
||||||
|
visitPropertyWrite(ast: cdAst.PropertyWrite) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitQuote(ast: cdAst.Quote) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
visitSafeMethodCall(ast: cdAst.SafeMethodCall) {
|
||||||
|
return visit(this, ast.receiver) || ast;
|
||||||
|
},
|
||||||
visitSafePropertyRead(ast: cdAst.SafePropertyRead) {
|
visitSafePropertyRead(ast: cdAst.SafePropertyRead) {
|
||||||
return visit(this, ast.receiver) || ast;
|
return visit(this, ast.receiver) || ast;
|
||||||
}
|
}
|
||||||
@ -726,29 +777,66 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
return ast.some(ast => visit(visitor, ast));
|
return ast.some(ast => visit(visitor, ast));
|
||||||
};
|
};
|
||||||
return ast.visit({
|
return ast.visit({
|
||||||
visitBinary(ast: cdAst.Binary):
|
visitBinary(ast: cdAst.Binary): boolean {
|
||||||
boolean{return visit(this, ast.left) || visit(this, ast.right);},
|
return visit(this, ast.left) || visit(this, ast.right);
|
||||||
visitChain(ast: cdAst.Chain) { return false; },
|
},
|
||||||
visitConditional(ast: cdAst.Conditional):
|
visitChain(ast: cdAst.Chain) {
|
||||||
boolean{return visit(this, ast.condition) || visit(this, ast.trueExp) ||
|
return false;
|
||||||
visit(this, ast.falseExp);},
|
},
|
||||||
visitFunctionCall(ast: cdAst.FunctionCall) { return true; },
|
visitConditional(ast: cdAst.Conditional): boolean {
|
||||||
visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { return false; },
|
return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
|
||||||
visitInterpolation(ast: cdAst.Interpolation) { return visitSome(this, ast.expressions); },
|
},
|
||||||
visitKeyedRead(ast: cdAst.KeyedRead) { return false; },
|
visitFunctionCall(ast: cdAst.FunctionCall) {
|
||||||
visitKeyedWrite(ast: cdAst.KeyedWrite) { return false; },
|
return true;
|
||||||
visitLiteralArray(ast: cdAst.LiteralArray) { return true; },
|
},
|
||||||
visitLiteralMap(ast: cdAst.LiteralMap) { return true; },
|
visitImplicitReceiver(ast: cdAst.ImplicitReceiver) {
|
||||||
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { return false; },
|
return false;
|
||||||
visitMethodCall(ast: cdAst.MethodCall) { return true; },
|
},
|
||||||
visitPipe(ast: cdAst.BindingPipe) { return true; },
|
visitInterpolation(ast: cdAst.Interpolation) {
|
||||||
visitPrefixNot(ast: cdAst.PrefixNot) { return visit(this, ast.expression); },
|
return visitSome(this, ast.expressions);
|
||||||
visitNonNullAssert(ast: cdAst.PrefixNot) { return visit(this, ast.expression); },
|
},
|
||||||
visitPropertyRead(ast: cdAst.PropertyRead) { return false; },
|
visitKeyedRead(ast: cdAst.KeyedRead) {
|
||||||
visitPropertyWrite(ast: cdAst.PropertyWrite) { return false; },
|
return false;
|
||||||
visitQuote(ast: cdAst.Quote) { return false; },
|
},
|
||||||
visitSafeMethodCall(ast: cdAst.SafeMethodCall) { return true; },
|
visitKeyedWrite(ast: cdAst.KeyedWrite) {
|
||||||
visitSafePropertyRead(ast: cdAst.SafePropertyRead) { return false; }
|
return false;
|
||||||
|
},
|
||||||
|
visitLiteralArray(ast: cdAst.LiteralArray) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
visitLiteralMap(ast: cdAst.LiteralMap) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
visitMethodCall(ast: cdAst.MethodCall) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
visitPipe(ast: cdAst.BindingPipe) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
visitPrefixNot(ast: cdAst.PrefixNot) {
|
||||||
|
return visit(this, ast.expression);
|
||||||
|
},
|
||||||
|
visitNonNullAssert(ast: cdAst.PrefixNot) {
|
||||||
|
return visit(this, ast.expression);
|
||||||
|
},
|
||||||
|
visitPropertyRead(ast: cdAst.PropertyRead) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
visitPropertyWrite(ast: cdAst.PropertyWrite) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
visitQuote(ast: cdAst.Quote) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
visitSafeMethodCall(ast: cdAst.SafeMethodCall) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
visitSafePropertyRead(ast: cdAst.SafePropertyRead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,14 @@ export class CompilerConfig {
|
|||||||
public preserveWhitespaces: boolean;
|
public preserveWhitespaces: boolean;
|
||||||
public strictInjectionParameters: boolean;
|
public strictInjectionParameters: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor({
|
||||||
{defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false,
|
defaultEncapsulation = ViewEncapsulation.Emulated,
|
||||||
missingTranslation = null, preserveWhitespaces, strictInjectionParameters}: {
|
useJit = true,
|
||||||
|
jitDevMode = false,
|
||||||
|
missingTranslation = null,
|
||||||
|
preserveWhitespaces,
|
||||||
|
strictInjectionParameters
|
||||||
|
}: {
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
useJit?: boolean,
|
useJit?: boolean,
|
||||||
jitDevMode?: boolean,
|
jitDevMode?: boolean,
|
||||||
@ -40,6 +45,6 @@ export class CompilerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function preserveWhitespacesDefault(
|
export function preserveWhitespacesDefault(
|
||||||
preserveWhitespacesOption: boolean | null, defaultSetting = false): boolean {
|
preserveWhitespacesOption: boolean|null, defaultSetting = false): boolean {
|
||||||
return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
|
return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
import {OutputContext, error} from './util';
|
import {error, OutputContext} from './util';
|
||||||
|
|
||||||
const CONSTANT_PREFIX = '_c';
|
const CONSTANT_PREFIX = '_c';
|
||||||
|
|
||||||
@ -21,7 +21,12 @@ const CONSTANT_PREFIX = '_c';
|
|||||||
*/
|
*/
|
||||||
const UNKNOWN_VALUE_KEY = o.variable('<unknown>');
|
const UNKNOWN_VALUE_KEY = o.variable('<unknown>');
|
||||||
|
|
||||||
export const enum DefinitionKind {Injector, Directive, Component, Pipe}
|
export const enum DefinitionKind {
|
||||||
|
Injector,
|
||||||
|
Directive,
|
||||||
|
Component,
|
||||||
|
Pipe
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context to use when producing a key.
|
* Context to use when producing a key.
|
||||||
@ -43,7 +48,7 @@ class FixupExpression extends o.Expression {
|
|||||||
private original: o.Expression;
|
private original: o.Expression;
|
||||||
|
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
shared !: boolean;
|
shared!: boolean;
|
||||||
|
|
||||||
constructor(public resolved: o.Expression) {
|
constructor(public resolved: o.Expression) {
|
||||||
super(resolved.type);
|
super(resolved.type);
|
||||||
@ -64,7 +69,9 @@ class FixupExpression extends o.Expression {
|
|||||||
return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
|
return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return true; }
|
isConstant() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
fixup(expression: o.Expression) {
|
fixup(expression: o.Expression) {
|
||||||
this.resolved = expression;
|
this.resolved = expression;
|
||||||
@ -169,7 +176,7 @@ export class ConstantPool {
|
|||||||
const resultExpressions = values.map(
|
const resultExpressions = values.map(
|
||||||
(e, index) => e.isConstant() ? this.getConstLiteral(e, true) : o.variable(`a${index}`));
|
(e, index) => e.isConstant() ? this.getConstLiteral(e, true) : o.variable(`a${index}`));
|
||||||
const parameters =
|
const parameters =
|
||||||
resultExpressions.filter(isVariable).map(e => new o.FnParam(e.name !, o.DYNAMIC_TYPE));
|
resultExpressions.filter(isVariable).map(e => new o.FnParam(e.name!, o.DYNAMIC_TYPE));
|
||||||
const pureFunctionDeclaration =
|
const pureFunctionDeclaration =
|
||||||
o.fn(parameters, [new o.ReturnStatement(resultMap(resultExpressions))], o.INFERRED_TYPE);
|
o.fn(parameters, [new o.ReturnStatement(resultMap(resultExpressions))], o.INFERRED_TYPE);
|
||||||
const name = this.freshName();
|
const name = this.freshName();
|
||||||
@ -190,7 +197,9 @@ export class ConstantPool {
|
|||||||
* a digit so the prefix should be a constant string (not based on user input) and
|
* a digit so the prefix should be a constant string (not based on user input) and
|
||||||
* must not end in a digit.
|
* must not end in a digit.
|
||||||
*/
|
*/
|
||||||
uniqueName(prefix: string): string { return `${prefix}${this.nextNameIndex++}`; }
|
uniqueName(prefix: string): string {
|
||||||
|
return `${prefix}${this.nextNameIndex++}`;
|
||||||
|
}
|
||||||
|
|
||||||
private definitionsOf(kind: DefinitionKind): Map<any, FixupExpression> {
|
private definitionsOf(kind: DefinitionKind): Map<any, FixupExpression> {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@ -222,7 +231,9 @@ export class ConstantPool {
|
|||||||
return '<unknown>';
|
return '<unknown>';
|
||||||
}
|
}
|
||||||
|
|
||||||
private freshName(): string { return this.uniqueName(CONSTANT_PREFIX); }
|
private freshName(): string {
|
||||||
|
return this.uniqueName(CONSTANT_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
private keyOf(expression: o.Expression) {
|
private keyOf(expression: o.Expression) {
|
||||||
return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
|
return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
|
||||||
@ -259,7 +270,9 @@ class KeyVisitor implements o.ExpressionVisitor {
|
|||||||
`EX:${ast.value.runtime.name}`;
|
`EX:${ast.value.runtime.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitReadVarExpr(node: o.ReadVarExpr) { return `VAR:${node.name}`; }
|
visitReadVarExpr(node: o.ReadVarExpr) {
|
||||||
|
return `VAR:${node.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
visitTypeofExpr(node: o.TypeofExpr, context: any): string {
|
visitTypeofExpr(node: o.TypeofExpr, context: any): string {
|
||||||
return `TYPEOF:${node.expr.visitExpression(this, context)}`;
|
return `TYPEOF:${node.expr.visitExpression(this, context)}`;
|
||||||
@ -284,7 +297,7 @@ class KeyVisitor implements o.ExpressionVisitor {
|
|||||||
visitLocalizedString = invalid;
|
visitLocalizedString = invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function invalid<T>(this: o.ExpressionVisitor, arg: o.Expression | o.Statement): never {
|
function invalid<T>(this: o.ExpressionVisitor, arg: o.Expression|o.Statement): never {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
|
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,16 @@
|
|||||||
|
|
||||||
import {CssSelector} from './selector';
|
import {CssSelector} from './selector';
|
||||||
|
|
||||||
export interface Inject { token: any; }
|
export interface Inject {
|
||||||
|
token: any;
|
||||||
|
}
|
||||||
export const createInject = makeMetadataFactory<Inject>('Inject', (token: any) => ({token}));
|
export const createInject = makeMetadataFactory<Inject>('Inject', (token: any) => ({token}));
|
||||||
export const createInjectionToken = makeMetadataFactory<object>(
|
export const createInjectionToken = makeMetadataFactory<object>(
|
||||||
'InjectionToken', (desc: string) => ({_desc: desc, ɵprov: undefined}));
|
'InjectionToken', (desc: string) => ({_desc: desc, ɵprov: undefined}));
|
||||||
|
|
||||||
export interface Attribute { attributeName?: string; }
|
export interface Attribute {
|
||||||
|
attributeName?: string;
|
||||||
|
}
|
||||||
export const createAttribute =
|
export const createAttribute =
|
||||||
makeMetadataFactory<Attribute>('Attribute', (attributeName?: string) => ({attributeName}));
|
makeMetadataFactory<Attribute>('Attribute', (attributeName?: string) => ({attributeName}));
|
||||||
|
|
||||||
@ -37,13 +41,16 @@ export const createContentChildren = makeMetadataFactory<Query>(
|
|||||||
(selector?: any, data: any = {}) =>
|
(selector?: any, data: any = {}) =>
|
||||||
({selector, first: false, isViewQuery: false, descendants: false, ...data}));
|
({selector, first: false, isViewQuery: false, descendants: false, ...data}));
|
||||||
export const createContentChild = makeMetadataFactory<Query>(
|
export const createContentChild = makeMetadataFactory<Query>(
|
||||||
'ContentChild', (selector?: any, data: any = {}) =>
|
'ContentChild',
|
||||||
|
(selector?: any, data: any = {}) =>
|
||||||
({selector, first: true, isViewQuery: false, descendants: true, ...data}));
|
({selector, first: true, isViewQuery: false, descendants: true, ...data}));
|
||||||
export const createViewChildren = makeMetadataFactory<Query>(
|
export const createViewChildren = makeMetadataFactory<Query>(
|
||||||
'ViewChildren', (selector?: any, data: any = {}) =>
|
'ViewChildren',
|
||||||
|
(selector?: any, data: any = {}) =>
|
||||||
({selector, first: false, isViewQuery: true, descendants: true, ...data}));
|
({selector, first: false, isViewQuery: true, descendants: true, ...data}));
|
||||||
export const createViewChild = makeMetadataFactory<Query>(
|
export const createViewChild = makeMetadataFactory<Query>(
|
||||||
'ViewChild', (selector: any, data: any) =>
|
'ViewChild',
|
||||||
|
(selector: any, data: any) =>
|
||||||
({selector, first: true, isViewQuery: true, descendants: true, ...data}));
|
({selector, first: true, isViewQuery: true, descendants: true, ...data}));
|
||||||
|
|
||||||
export interface Directive {
|
export interface Directive {
|
||||||
@ -94,15 +101,21 @@ export interface Pipe {
|
|||||||
}
|
}
|
||||||
export const createPipe = makeMetadataFactory<Pipe>('Pipe', (p: Pipe) => ({pure: true, ...p}));
|
export const createPipe = makeMetadataFactory<Pipe>('Pipe', (p: Pipe) => ({pure: true, ...p}));
|
||||||
|
|
||||||
export interface Input { bindingPropertyName?: string; }
|
export interface Input {
|
||||||
|
bindingPropertyName?: string;
|
||||||
|
}
|
||||||
export const createInput =
|
export const createInput =
|
||||||
makeMetadataFactory<Input>('Input', (bindingPropertyName?: string) => ({bindingPropertyName}));
|
makeMetadataFactory<Input>('Input', (bindingPropertyName?: string) => ({bindingPropertyName}));
|
||||||
|
|
||||||
export interface Output { bindingPropertyName?: string; }
|
export interface Output {
|
||||||
|
bindingPropertyName?: string;
|
||||||
|
}
|
||||||
export const createOutput = makeMetadataFactory<Output>(
|
export const createOutput = makeMetadataFactory<Output>(
|
||||||
'Output', (bindingPropertyName?: string) => ({bindingPropertyName}));
|
'Output', (bindingPropertyName?: string) => ({bindingPropertyName}));
|
||||||
|
|
||||||
export interface HostBinding { hostPropertyName?: string; }
|
export interface HostBinding {
|
||||||
|
hostPropertyName?: string;
|
||||||
|
}
|
||||||
export const createHostBinding = makeMetadataFactory<HostBinding>(
|
export const createHostBinding = makeMetadataFactory<HostBinding>(
|
||||||
'HostBinding', (hostPropertyName?: string) => ({hostPropertyName}));
|
'HostBinding', (hostPropertyName?: string) => ({hostPropertyName}));
|
||||||
|
|
||||||
@ -140,7 +153,9 @@ export interface Injectable {
|
|||||||
}
|
}
|
||||||
export const createInjectable =
|
export const createInjectable =
|
||||||
makeMetadataFactory('Injectable', (injectable: Injectable = {}) => injectable);
|
makeMetadataFactory('Injectable', (injectable: Injectable = {}) => injectable);
|
||||||
export interface SchemaMetadata { name: string; }
|
export interface SchemaMetadata {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata = {
|
export const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata = {
|
||||||
name: 'custom-elements'
|
name: 'custom-elements'
|
||||||
@ -155,7 +170,9 @@ export const createSelf = makeMetadataFactory('Self');
|
|||||||
export const createSkipSelf = makeMetadataFactory('SkipSelf');
|
export const createSkipSelf = makeMetadataFactory('SkipSelf');
|
||||||
export const createHost = makeMetadataFactory('Host');
|
export const createHost = makeMetadataFactory('Host');
|
||||||
|
|
||||||
export interface Type extends Function { new (...args: any[]): any; }
|
export interface Type extends Function {
|
||||||
|
new(...args: any[]): any;
|
||||||
|
}
|
||||||
export const Type = Function;
|
export const Type = Function;
|
||||||
|
|
||||||
export enum SecurityContext {
|
export enum SecurityContext {
|
||||||
@ -240,7 +257,10 @@ export const enum InjectFlags {
|
|||||||
Optional = 1 << 3,
|
Optional = 1 << 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum ArgumentType {Inline = 0, Dynamic = 1}
|
export const enum ArgumentType {
|
||||||
|
Inline = 0,
|
||||||
|
Dynamic = 1
|
||||||
|
}
|
||||||
|
|
||||||
export const enum BindingFlags {
|
export const enum BindingFlags {
|
||||||
TypeElementAttribute = 1 << 0,
|
TypeElementAttribute = 1 << 0,
|
||||||
@ -255,7 +275,10 @@ export const enum BindingFlags {
|
|||||||
Types = TypeElementAttribute | TypeElementClass | TypeElementStyle | TypeProperty
|
Types = TypeElementAttribute | TypeElementClass | TypeElementStyle | TypeProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum QueryBindingType {First = 0, All = 1}
|
export const enum QueryBindingType {
|
||||||
|
First = 0,
|
||||||
|
All = 1
|
||||||
|
}
|
||||||
|
|
||||||
export const enum QueryValueType {
|
export const enum QueryValueType {
|
||||||
ElementRef = 0,
|
ElementRef = 0,
|
||||||
@ -324,7 +347,7 @@ export const enum SelectorFlags {
|
|||||||
|
|
||||||
// These are a copy the CSS types from core/src/render3/interfaces/projection.ts
|
// These are a copy the CSS types from core/src/render3/interfaces/projection.ts
|
||||||
// They are duplicated here as they cannot be directly referenced from core.
|
// They are duplicated here as they cannot be directly referenced from core.
|
||||||
export type R3CssSelector = (string | SelectorFlags)[];
|
export type R3CssSelector = (string|SelectorFlags)[];
|
||||||
export type R3CssSelectorList = R3CssSelector[];
|
export type R3CssSelectorList = R3CssSelector[];
|
||||||
|
|
||||||
function parserSelectorToSimpleSelector(selector: CssSelector): R3CssSelector {
|
function parserSelectorToSimpleSelector(selector: CssSelector): R3CssSelector {
|
||||||
@ -363,7 +386,7 @@ function parserSelectorToR3Selector(selector: CssSelector): R3CssSelector {
|
|||||||
return positive.concat(...negative);
|
return positive.concat(...negative);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseSelectorToR3Selector(selector: string | null): R3CssSelectorList {
|
export function parseSelectorToR3Selector(selector: string|null): R3CssSelectorList {
|
||||||
return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
|
return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,12 @@ export interface CssAstVisitor {
|
|||||||
|
|
||||||
export abstract class CssAst {
|
export abstract class CssAst {
|
||||||
constructor(public location: ParseSourceSpan) {}
|
constructor(public location: ParseSourceSpan) {}
|
||||||
get start(): ParseLocation { return this.location.start; }
|
get start(): ParseLocation {
|
||||||
get end(): ParseLocation { return this.location.end; }
|
return this.location.start;
|
||||||
|
}
|
||||||
|
get end(): ParseLocation {
|
||||||
|
return this.location.end;
|
||||||
|
}
|
||||||
abstract visit(visitor: CssAstVisitor, context?: any): any;
|
abstract visit(visitor: CssAstVisitor, context?: any): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +59,15 @@ export class CssStyleValueAst extends CssAst {
|
|||||||
constructor(location: ParseSourceSpan, public tokens: CssToken[], public strValue: string) {
|
constructor(location: ParseSourceSpan, public tokens: CssToken[], public strValue: string) {
|
||||||
super(location);
|
super(location);
|
||||||
}
|
}
|
||||||
visit(visitor: CssAstVisitor, context?: any): any { return visitor.visitCssValue(this); }
|
visit(visitor: CssAstVisitor, context?: any): any {
|
||||||
|
return visitor.visitCssValue(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class CssRuleAst extends CssAst {
|
export abstract class CssRuleAst extends CssAst {
|
||||||
constructor(location: ParseSourceSpan) { super(location); }
|
constructor(location: ParseSourceSpan) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CssBlockRuleAst extends CssRuleAst {
|
export class CssBlockRuleAst extends CssRuleAst {
|
||||||
@ -158,7 +166,9 @@ export class CssDefinitionAst extends CssAst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export abstract class CssSelectorPartAst extends CssAst {
|
export abstract class CssSelectorPartAst extends CssAst {
|
||||||
constructor(location: ParseSourceSpan) { super(location); }
|
constructor(location: ParseSourceSpan) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CssSelectorAst extends CssSelectorPartAst {
|
export class CssSelectorAst extends CssSelectorPartAst {
|
||||||
@ -195,8 +205,12 @@ export class CssPseudoSelectorAst extends CssSelectorPartAst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CssBlockAst extends CssAst {
|
export class CssBlockAst extends CssAst {
|
||||||
constructor(location: ParseSourceSpan, public entries: CssAst[]) { super(location); }
|
constructor(location: ParseSourceSpan, public entries: CssAst[]) {
|
||||||
visit(visitor: CssAstVisitor, context?: any): any { return visitor.visitCssBlock(this, context); }
|
super(location);
|
||||||
|
}
|
||||||
|
visit(visitor: CssAstVisitor, context?: any): any {
|
||||||
|
return visitor.visitCssBlock(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,7 +227,9 @@ export class CssStylesBlockAst extends CssBlockAst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CssStyleSheetAst extends CssAst {
|
export class CssStyleSheetAst extends CssAst {
|
||||||
constructor(location: ParseSourceSpan, public rules: CssAst[]) { super(location); }
|
constructor(location: ParseSourceSpan, public rules: CssAst[]) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
visit(visitor: CssAstVisitor, context?: any): any {
|
visit(visitor: CssAstVisitor, context?: any): any {
|
||||||
return visitor.visitCssStyleSheet(this, context);
|
return visitor.visitCssStyleSheet(this, context);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ function _trackWhitespace(mode: CssLexerMode) {
|
|||||||
|
|
||||||
export class CssScanner {
|
export class CssScanner {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
peek !: number;
|
peek!: number;
|
||||||
peekPeek: number;
|
peekPeek: number;
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
index: number = -1;
|
index: number = -1;
|
||||||
@ -135,7 +135,9 @@ export class CssScanner {
|
|||||||
this.advance();
|
this.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
getMode(): CssLexerMode { return this._currentMode; }
|
getMode(): CssLexerMode {
|
||||||
|
return this._currentMode;
|
||||||
|
}
|
||||||
|
|
||||||
setMode(mode: CssLexerMode) {
|
setMode(mode: CssLexerMode) {
|
||||||
if (this._currentMode != mode) {
|
if (this._currentMode != mode) {
|
||||||
@ -198,7 +200,7 @@ export class CssScanner {
|
|||||||
const previousLine = this.line;
|
const previousLine = this.line;
|
||||||
const previousColumn = this.column;
|
const previousColumn = this.column;
|
||||||
|
|
||||||
let next: CssToken = undefined !;
|
let next: CssToken = undefined!;
|
||||||
const output = this.scan();
|
const output = this.scan();
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
// just incase the inner scan method returned an error
|
// just incase the inner scan method returned an error
|
||||||
@ -236,7 +238,8 @@ export class CssScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
error = cssScannerError(
|
error = cssScannerError(
|
||||||
next, generateErrorMessage(
|
next,
|
||||||
|
generateErrorMessage(
|
||||||
this.input, errorMessage, next.strValue, previousIndex, previousLine,
|
this.input, errorMessage, next.strValue, previousIndex, previousLine,
|
||||||
previousColumn));
|
previousColumn));
|
||||||
}
|
}
|
||||||
@ -254,7 +257,7 @@ export class CssScanner {
|
|||||||
const token = this._scan();
|
const token = this._scan();
|
||||||
if (token == null) return null;
|
if (token == null) return null;
|
||||||
|
|
||||||
const error = this._currentError !;
|
const error = this._currentError!;
|
||||||
this._currentError = null;
|
this._currentError = null;
|
||||||
|
|
||||||
if (!trackWS) {
|
if (!trackWS) {
|
||||||
@ -461,7 +464,7 @@ export class CssScanner {
|
|||||||
const startingColumn = this.column;
|
const startingColumn = this.column;
|
||||||
this.advance();
|
this.advance();
|
||||||
if (isIdentifierStart(this.peek, this.peekPeek)) {
|
if (isIdentifierStart(this.peek, this.peekPeek)) {
|
||||||
const ident = this.scanIdentifier() !;
|
const ident = this.scanIdentifier()!;
|
||||||
const strValue = '@' + ident.strValue;
|
const strValue = '@' + ident.strValue;
|
||||||
return new CssToken(start, startingColumn, this.line, CssTokenType.AtKeyword, strValue);
|
return new CssToken(start, startingColumn, this.line, CssTokenType.AtKeyword, strValue);
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import * as chars from '../chars';
|
import * as chars from '../chars';
|
||||||
import {ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan} from '../parse_util';
|
import {ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan} from '../parse_util';
|
||||||
|
|
||||||
import {BlockType, CssAst, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst, mergeTokens} from './css_ast';
|
import {BlockType, CssAst, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStylesBlockAst, CssStyleSheetAst, CssStyleValueAst, CssUnknownRuleAst, CssUnknownTokenListAst, mergeTokens} from './css_ast';
|
||||||
import {CssLexer, CssLexerMode, CssScanner, CssToken, CssTokenType, generateErrorMessage, getRawMessage, isNewline} from './css_lexer';
|
import {CssLexer, CssLexerMode, CssScanner, CssToken, CssTokenType, generateErrorMessage, getRawMessage, isNewline} from './css_lexer';
|
||||||
|
|
||||||
const SPACE_OPERATOR = ' ';
|
const SPACE_OPERATOR = ' ';
|
||||||
@ -84,11 +84,11 @@ export class ParsedCssResult {
|
|||||||
export class CssParser {
|
export class CssParser {
|
||||||
private _errors: CssParseError[] = [];
|
private _errors: CssParseError[] = [];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _file !: ParseSourceFile;
|
private _file!: ParseSourceFile;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _scanner !: CssScanner;
|
private _scanner!: CssScanner;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _lastToken !: CssToken;
|
private _lastToken!: CssToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param css the CSS code that will be parsed
|
* @param css the CSS code that will be parsed
|
||||||
@ -125,11 +125,13 @@ export class CssParser {
|
|||||||
// EOF token that was emitted sometime during the lexing
|
// EOF token that was emitted sometime during the lexing
|
||||||
span = this._generateSourceSpan(firstRule, this._lastToken);
|
span = this._generateSourceSpan(firstRule, this._lastToken);
|
||||||
}
|
}
|
||||||
return new CssStyleSheetAst(span !, results);
|
return new CssStyleSheetAst(span!, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_getSourceContent(): string { return this._scanner != null ? this._scanner.input : ''; }
|
_getSourceContent(): string {
|
||||||
|
return this._scanner != null ? this._scanner.input : '';
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_extractSourceContent(start: number, end: number): string {
|
_extractSourceContent(start: number, end: number): string {
|
||||||
@ -159,9 +161,9 @@ export class CssParser {
|
|||||||
let endColumn: number = -1;
|
let endColumn: number = -1;
|
||||||
let endIndex: number = -1;
|
let endIndex: number = -1;
|
||||||
if (end instanceof CssAst) {
|
if (end instanceof CssAst) {
|
||||||
endLine = end.location.end.line !;
|
endLine = end.location.end.line!;
|
||||||
endColumn = end.location.end.col !;
|
endColumn = end.location.end.col!;
|
||||||
endIndex = end.location.end.offset !;
|
endIndex = end.location.end.offset!;
|
||||||
} else if (end instanceof CssToken) {
|
} else if (end instanceof CssToken) {
|
||||||
endLine = end.line;
|
endLine = end.line;
|
||||||
endColumn = end.column;
|
endColumn = end.column;
|
||||||
@ -253,7 +255,7 @@ export class CssParser {
|
|||||||
|
|
||||||
case BlockType.Viewport:
|
case BlockType.Viewport:
|
||||||
case BlockType.FontFace:
|
case BlockType.FontFace:
|
||||||
block = this._parseStyleBlock(delimiters) !;
|
block = this._parseStyleBlock(delimiters)!;
|
||||||
span = this._generateSourceSpan(startToken, block);
|
span = this._generateSourceSpan(startToken, block);
|
||||||
return new CssBlockRuleAst(span, type, block);
|
return new CssBlockRuleAst(span, type, block);
|
||||||
|
|
||||||
@ -293,7 +295,7 @@ export class CssParser {
|
|||||||
span = this._generateSourceSpan(startToken, tokens[tokens.length - 1]);
|
span = this._generateSourceSpan(startToken, tokens[tokens.length - 1]);
|
||||||
query = new CssAtRulePredicateAst(span, strValue, tokens);
|
query = new CssAtRulePredicateAst(span, strValue, tokens);
|
||||||
block = this._parseBlock(delimiters);
|
block = this._parseBlock(delimiters);
|
||||||
strValue = this._extractSourceContent(start, block.end.offset !);
|
strValue = this._extractSourceContent(start, block.end.offset!);
|
||||||
span = this._generateSourceSpan(startToken, block);
|
span = this._generateSourceSpan(startToken, block);
|
||||||
return new CssBlockDefinitionRuleAst(span, strValue, type, query, block);
|
return new CssBlockDefinitionRuleAst(span, strValue, type, query, block);
|
||||||
|
|
||||||
@ -310,11 +312,15 @@ export class CssParser {
|
|||||||
token);
|
token);
|
||||||
|
|
||||||
this._collectUntilDelim(delimiters | LBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG)
|
this._collectUntilDelim(delimiters | LBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG)
|
||||||
.forEach((token) => { listOfTokens.push(token); });
|
.forEach((token) => {
|
||||||
|
listOfTokens.push(token);
|
||||||
|
});
|
||||||
if (this._scanner.peek == chars.$LBRACE) {
|
if (this._scanner.peek == chars.$LBRACE) {
|
||||||
listOfTokens.push(this._consume(CssTokenType.Character, '{'));
|
listOfTokens.push(this._consume(CssTokenType.Character, '{'));
|
||||||
this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG)
|
this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG)
|
||||||
.forEach((token) => { listOfTokens.push(token); });
|
.forEach((token) => {
|
||||||
|
listOfTokens.push(token);
|
||||||
|
});
|
||||||
listOfTokens.push(this._consume(CssTokenType.Character, '}'));
|
listOfTokens.push(this._consume(CssTokenType.Character, '}'));
|
||||||
}
|
}
|
||||||
endToken = listOfTokens[listOfTokens.length - 1];
|
endToken = listOfTokens[listOfTokens.length - 1];
|
||||||
@ -339,7 +345,9 @@ export class CssParser {
|
|||||||
const innerTokens: CssToken[] = [];
|
const innerTokens: CssToken[] = [];
|
||||||
selectors.forEach((selector: CssSelectorAst) => {
|
selectors.forEach((selector: CssSelectorAst) => {
|
||||||
selector.selectorParts.forEach((part: CssSimpleSelectorAst) => {
|
selector.selectorParts.forEach((part: CssSimpleSelectorAst) => {
|
||||||
part.tokens.forEach((token: CssToken) => { innerTokens.push(token); });
|
part.tokens.forEach((token: CssToken) => {
|
||||||
|
innerTokens.push(token);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const endToken = innerTokens[innerTokens.length - 1];
|
const endToken = innerTokens[innerTokens.length - 1];
|
||||||
@ -376,7 +384,7 @@ export class CssParser {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_scan(): CssToken {
|
_scan(): CssToken {
|
||||||
const output = this._scanner.scan() !;
|
const output = this._scanner.scan()!;
|
||||||
const token = output.token;
|
const token = output.token;
|
||||||
const error = output.error;
|
const error = output.error;
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
@ -387,7 +395,9 @@ export class CssParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_getScannerIndex(): number { return this._scanner.index; }
|
_getScannerIndex(): number {
|
||||||
|
return this._scanner.index;
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_consume(type: CssTokenType, value: string|null = null): CssToken {
|
_consume(type: CssTokenType, value: string|null = null): CssToken {
|
||||||
@ -432,7 +442,7 @@ export class CssParser {
|
|||||||
}
|
}
|
||||||
const stylesBlock = this._parseStyleBlock(delimiters | RBRACE_DELIM_FLAG);
|
const stylesBlock = this._parseStyleBlock(delimiters | RBRACE_DELIM_FLAG);
|
||||||
const span = this._generateSourceSpan(stepTokens[0], stylesBlock);
|
const span = this._generateSourceSpan(stepTokens[0], stylesBlock);
|
||||||
const ast = new CssKeyframeDefinitionAst(span, stepTokens, stylesBlock !);
|
const ast = new CssKeyframeDefinitionAst(span, stepTokens, stylesBlock!);
|
||||||
|
|
||||||
this._scanner.setMode(CssLexerMode.BLOCK);
|
this._scanner.setMode(CssLexerMode.BLOCK);
|
||||||
return ast;
|
return ast;
|
||||||
@ -523,7 +533,7 @@ export class CssParser {
|
|||||||
const selectorCssTokens: CssToken[] = [];
|
const selectorCssTokens: CssToken[] = [];
|
||||||
const pseudoSelectors: CssPseudoSelectorAst[] = [];
|
const pseudoSelectors: CssPseudoSelectorAst[] = [];
|
||||||
|
|
||||||
let previousToken: CssToken = undefined !;
|
let previousToken: CssToken = undefined!;
|
||||||
|
|
||||||
const selectorPartDelimiters = delimiters | SPACE_DELIM_FLAG;
|
const selectorPartDelimiters = delimiters | SPACE_DELIM_FLAG;
|
||||||
let loopOverSelector = !characterContainsDelimiter(this._scanner.peek, selectorPartDelimiters);
|
let loopOverSelector = !characterContainsDelimiter(this._scanner.peek, selectorPartDelimiters);
|
||||||
@ -576,7 +586,8 @@ export class CssParser {
|
|||||||
hasAttributeError || this._scanner.getMode() == CssLexerMode.ATTRIBUTE_SELECTOR;
|
hasAttributeError || this._scanner.getMode() == CssLexerMode.ATTRIBUTE_SELECTOR;
|
||||||
if (hasAttributeError) {
|
if (hasAttributeError) {
|
||||||
this._error(
|
this._error(
|
||||||
`Unbalanced CSS attribute selector at column ${previousToken.line}:${previousToken.column}`,
|
`Unbalanced CSS attribute selector at column ${previousToken.line}:${
|
||||||
|
previousToken.column}`,
|
||||||
previousToken);
|
previousToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,8 +682,8 @@ export class CssParser {
|
|||||||
endTokenOrAst = operator;
|
endTokenOrAst = operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
const span = this._generateSourceSpan(startTokenOrAst !, endTokenOrAst);
|
const span = this._generateSourceSpan(startTokenOrAst!, endTokenOrAst);
|
||||||
return new CssSimpleSelectorAst(span, selectorCssTokens, strValue, pseudoSelectors, operator !);
|
return new CssSimpleSelectorAst(span, selectorCssTokens, strValue, pseudoSelectors, operator!);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@ -701,7 +712,7 @@ export class CssParser {
|
|||||||
|
|
||||||
const tokens: CssToken[] = [];
|
const tokens: CssToken[] = [];
|
||||||
let wsStr = '';
|
let wsStr = '';
|
||||||
let previous: CssToken = undefined !;
|
let previous: CssToken = undefined!;
|
||||||
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
|
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
|
||||||
let token: CssToken;
|
let token: CssToken;
|
||||||
if (previous != null && previous.type == CssTokenType.Identifier &&
|
if (previous != null && previous.type == CssTokenType.Identifier &&
|
||||||
@ -841,7 +852,9 @@ export class CssParser {
|
|||||||
const remainingTokens = this._collectUntilDelim(
|
const remainingTokens = this._collectUntilDelim(
|
||||||
delimiters | COLON_DELIM_FLAG | SEMICOLON_DELIM_FLAG, CssTokenType.Identifier);
|
delimiters | COLON_DELIM_FLAG | SEMICOLON_DELIM_FLAG, CssTokenType.Identifier);
|
||||||
if (remainingTokens.length > 0) {
|
if (remainingTokens.length > 0) {
|
||||||
remainingTokens.forEach((token) => { propStr.push(token.strValue); });
|
remainingTokens.forEach((token) => {
|
||||||
|
propStr.push(token.strValue);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
endToken = prop =
|
endToken = prop =
|
||||||
@ -868,7 +881,7 @@ export class CssParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const span = this._generateSourceSpan(prop, endToken);
|
const span = this._generateSourceSpan(prop, endToken);
|
||||||
return new CssDefinitionAst(span, prop, value !);
|
return new CssDefinitionAst(span, prop, value!);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@ -899,5 +912,7 @@ export class CssParseError extends ParseError {
|
|||||||
return new CssParseError(span, 'CSS Parse Error: ' + errMsg);
|
return new CssParseError(span, 'CSS Parse Error: ' + errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(span: ParseSourceSpan, message: string) { super(span, message); }
|
constructor(span: ParseSourceSpan, message: string) {
|
||||||
|
super(span, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import {ResourceLoader} from './resource_loader';
|
|||||||
import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver';
|
import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver';
|
||||||
import {PreparsedElementType, preparseElement} from './template_parser/template_preparser';
|
import {PreparsedElementType, preparseElement} from './template_parser/template_preparser';
|
||||||
import {UrlResolver} from './url_resolver';
|
import {UrlResolver} from './url_resolver';
|
||||||
import {SyncAsync, isDefined, stringify, syntaxError} from './util';
|
import {isDefined, stringify, SyncAsync, syntaxError} from './util';
|
||||||
|
|
||||||
export interface PrenormalizedTemplateMetadata {
|
export interface PrenormalizedTemplateMetadata {
|
||||||
ngModuleType: any;
|
ngModuleType: any;
|
||||||
@ -40,16 +40,19 @@ export class DirectiveNormalizer {
|
|||||||
private _resourceLoader: ResourceLoader, private _urlResolver: UrlResolver,
|
private _resourceLoader: ResourceLoader, private _urlResolver: UrlResolver,
|
||||||
private _htmlParser: HtmlParser, private _config: CompilerConfig) {}
|
private _htmlParser: HtmlParser, private _config: CompilerConfig) {}
|
||||||
|
|
||||||
clearCache(): void { this._resourceLoaderCache.clear(); }
|
clearCache(): void {
|
||||||
|
this._resourceLoaderCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
clearCacheFor(normalizedDirective: CompileDirectiveMetadata): void {
|
clearCacheFor(normalizedDirective: CompileDirectiveMetadata): void {
|
||||||
if (!normalizedDirective.isComponent) {
|
if (!normalizedDirective.isComponent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const template = normalizedDirective.template !;
|
const template = normalizedDirective.template !;
|
||||||
this._resourceLoaderCache.delete(template.templateUrl !);
|
this._resourceLoaderCache.delete(template.templateUrl!);
|
||||||
template.externalStylesheets.forEach(
|
template.externalStylesheets.forEach((stylesheet) => {
|
||||||
(stylesheet) => { this._resourceLoaderCache.delete(stylesheet.moduleUrl !); });
|
this._resourceLoaderCache.delete(stylesheet.moduleUrl!);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _fetch(url: string): SyncAsync<string> {
|
private _fetch(url: string): SyncAsync<string> {
|
||||||
@ -65,17 +68,18 @@ export class DirectiveNormalizer {
|
|||||||
SyncAsync<CompileTemplateMetadata> {
|
SyncAsync<CompileTemplateMetadata> {
|
||||||
if (isDefined(prenormData.template)) {
|
if (isDefined(prenormData.template)) {
|
||||||
if (isDefined(prenormData.templateUrl)) {
|
if (isDefined(prenormData.templateUrl)) {
|
||||||
throw syntaxError(
|
throw syntaxError(`'${
|
||||||
`'${stringify(prenormData.componentType)}' component cannot define both template and templateUrl`);
|
stringify(prenormData
|
||||||
|
.componentType)}' component cannot define both template and templateUrl`);
|
||||||
}
|
}
|
||||||
if (typeof prenormData.template !== 'string') {
|
if (typeof prenormData.template !== 'string') {
|
||||||
throw syntaxError(
|
throw syntaxError(`The template specified for component ${
|
||||||
`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
|
stringify(prenormData.componentType)} is not a string`);
|
||||||
}
|
}
|
||||||
} else if (isDefined(prenormData.templateUrl)) {
|
} else if (isDefined(prenormData.templateUrl)) {
|
||||||
if (typeof prenormData.templateUrl !== 'string') {
|
if (typeof prenormData.templateUrl !== 'string') {
|
||||||
throw syntaxError(
|
throw syntaxError(`The templateUrl specified for component ${
|
||||||
`The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`);
|
stringify(prenormData.componentType)} is not a string`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw syntaxError(
|
throw syntaxError(
|
||||||
@ -84,8 +88,8 @@ export class DirectiveNormalizer {
|
|||||||
|
|
||||||
if (isDefined(prenormData.preserveWhitespaces) &&
|
if (isDefined(prenormData.preserveWhitespaces) &&
|
||||||
typeof prenormData.preserveWhitespaces !== 'boolean') {
|
typeof prenormData.preserveWhitespaces !== 'boolean') {
|
||||||
throw syntaxError(
|
throw syntaxError(`The preserveWhitespaces option for component ${
|
||||||
`The preserveWhitespaces option for component ${stringify(prenormData.componentType)} must be a boolean`);
|
stringify(prenormData.componentType)} must be a boolean`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SyncAsync.then(
|
return SyncAsync.then(
|
||||||
@ -101,7 +105,7 @@ export class DirectiveNormalizer {
|
|||||||
template = prenomData.template;
|
template = prenomData.template;
|
||||||
templateUrl = prenomData.moduleUrl;
|
templateUrl = prenomData.moduleUrl;
|
||||||
} else {
|
} else {
|
||||||
templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl !);
|
templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl!);
|
||||||
template = this._fetch(templateUrl);
|
template = this._fetch(templateUrl);
|
||||||
}
|
}
|
||||||
return SyncAsync.then(
|
return SyncAsync.then(
|
||||||
@ -112,7 +116,7 @@ export class DirectiveNormalizer {
|
|||||||
prenormData: PrenormalizedTemplateMetadata, template: string,
|
prenormData: PrenormalizedTemplateMetadata, template: string,
|
||||||
templateAbsUrl: string): PreparsedTemplate {
|
templateAbsUrl: string): PreparsedTemplate {
|
||||||
const isInline = !!prenormData.template;
|
const isInline = !!prenormData.template;
|
||||||
const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation !);
|
const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation!);
|
||||||
const templateUrl = templateSourceUrl(
|
const templateUrl = templateSourceUrl(
|
||||||
{reference: prenormData.ngModuleType}, {type: {reference: prenormData.componentType}},
|
{reference: prenormData.ngModuleType}, {type: {reference: prenormData.componentType}},
|
||||||
{isInline, templateUrl: templateAbsUrl});
|
{isInline, templateUrl: templateAbsUrl});
|
||||||
@ -140,8 +144,12 @@ export class DirectiveNormalizer {
|
|||||||
.styleUrls;
|
.styleUrls;
|
||||||
return {
|
return {
|
||||||
template,
|
template,
|
||||||
templateUrl: templateAbsUrl, isInline,
|
templateUrl: templateAbsUrl,
|
||||||
htmlAst: rootNodesAndErrors, styles, inlineStyleUrls, styleUrls,
|
isInline,
|
||||||
|
htmlAst: rootNodesAndErrors,
|
||||||
|
styles,
|
||||||
|
inlineStyleUrls,
|
||||||
|
styleUrls,
|
||||||
ngContentSelectors: visitor.ngContentSelectors,
|
ngContentSelectors: visitor.ngContentSelectors,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -172,7 +180,7 @@ export class DirectiveNormalizer {
|
|||||||
const styleUrls = preparsedTemplate.styleUrls;
|
const styleUrls = preparsedTemplate.styleUrls;
|
||||||
|
|
||||||
const externalStylesheets = styleUrls.map(styleUrl => {
|
const externalStylesheets = styleUrls.map(styleUrl => {
|
||||||
const stylesheet = stylesheets.get(styleUrl) !;
|
const stylesheet = stylesheets.get(styleUrl)!;
|
||||||
const styles = [...stylesheet.styles];
|
const styles = [...stylesheet.styles];
|
||||||
this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
|
this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
|
||||||
return new CompileStylesheetMetadata({moduleUrl: styleUrl, styles: styles});
|
return new CompileStylesheetMetadata({moduleUrl: styleUrl, styles: styles});
|
||||||
@ -190,11 +198,14 @@ export class DirectiveNormalizer {
|
|||||||
encapsulation,
|
encapsulation,
|
||||||
template: preparsedTemplate.template,
|
template: preparsedTemplate.template,
|
||||||
templateUrl: preparsedTemplate.templateUrl,
|
templateUrl: preparsedTemplate.templateUrl,
|
||||||
htmlAst: preparsedTemplate.htmlAst, styles, styleUrls,
|
htmlAst: preparsedTemplate.htmlAst,
|
||||||
|
styles,
|
||||||
|
styleUrls,
|
||||||
ngContentSelectors: preparsedTemplate.ngContentSelectors,
|
ngContentSelectors: preparsedTemplate.ngContentSelectors,
|
||||||
animations: prenormData.animations,
|
animations: prenormData.animations,
|
||||||
interpolation: prenormData.interpolation,
|
interpolation: prenormData.interpolation,
|
||||||
isInline: preparsedTemplate.isInline, externalStylesheets,
|
isInline: preparsedTemplate.isInline,
|
||||||
|
externalStylesheets,
|
||||||
preserveWhitespaces: preserveWhitespacesDefault(
|
preserveWhitespaces: preserveWhitespacesDefault(
|
||||||
prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
|
prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
|
||||||
});
|
});
|
||||||
@ -204,7 +215,7 @@ export class DirectiveNormalizer {
|
|||||||
styleUrls: string[], stylesheets: Map<string, CompileStylesheetMetadata>,
|
styleUrls: string[], stylesheets: Map<string, CompileStylesheetMetadata>,
|
||||||
targetStyles: string[]) {
|
targetStyles: string[]) {
|
||||||
styleUrls.forEach(styleUrl => {
|
styleUrls.forEach(styleUrl => {
|
||||||
const stylesheet = stylesheets.get(styleUrl) !;
|
const stylesheet = stylesheets.get(styleUrl)!;
|
||||||
stylesheet.styles.forEach(style => targetStyles.push(style));
|
stylesheet.styles.forEach(style => targetStyles.push(style));
|
||||||
this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
|
this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
|
||||||
});
|
});
|
||||||
@ -232,7 +243,7 @@ export class DirectiveNormalizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _normalizeStylesheet(stylesheet: CompileStylesheetMetadata): CompileStylesheetMetadata {
|
private _normalizeStylesheet(stylesheet: CompileStylesheetMetadata): CompileStylesheetMetadata {
|
||||||
const moduleUrl = stylesheet.moduleUrl !;
|
const moduleUrl = stylesheet.moduleUrl!;
|
||||||
const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
|
const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
|
||||||
.map(url => this._urlResolver.resolve(moduleUrl, url));
|
.map(url => this._urlResolver.resolve(moduleUrl, url));
|
||||||
|
|
||||||
@ -297,13 +308,21 @@ class TemplatePreparseVisitor implements html.Visitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpansion(ast: html.Expansion, context: any): any { html.visitAll(this, ast.cases); }
|
visitExpansion(ast: html.Expansion, context: any): any {
|
||||||
|
html.visitAll(this, ast.cases);
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansionCase(ast: html.ExpansionCase, context: any): any {
|
visitExpansionCase(ast: html.ExpansionCase, context: any): any {
|
||||||
html.visitAll(this, ast.expression);
|
html.visitAll(this, ast.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitComment(ast: html.Comment, context: any): any { return null; }
|
visitComment(ast: html.Comment, context: any): any {
|
||||||
visitAttribute(ast: html.Attribute, context: any): any { return null; }
|
return null;
|
||||||
visitText(ast: html.Text, context: any): any { return null; }
|
}
|
||||||
|
visitAttribute(ast: html.Attribute, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visitText(ast: html.Text, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileReflector} from './compile_reflector';
|
import {CompileReflector} from './compile_reflector';
|
||||||
import {Component, Directive, Type, createComponent, createContentChild, createContentChildren, createDirective, createHostBinding, createHostListener, createInput, createOutput, createViewChild, createViewChildren} from './core';
|
import {Component, createComponent, createContentChild, createContentChildren, createDirective, createHostBinding, createHostListener, createInput, createOutput, createViewChild, createViewChildren, Directive, Type} from './core';
|
||||||
import {resolveForwardRef, splitAtColon, stringify} from './util';
|
import {resolveForwardRef, splitAtColon, stringify} from './util';
|
||||||
|
|
||||||
const QUERY_METADATA_IDENTIFIERS = [
|
const QUERY_METADATA_IDENTIFIERS = [
|
||||||
@ -109,7 +109,9 @@ export class DirectiveResolver {
|
|||||||
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
|
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); }
|
private _extractPublicName(def: string) {
|
||||||
|
return splitAtColon(def, [null!, def])[1].trim();
|
||||||
|
}
|
||||||
|
|
||||||
private _dedupeBindings(bindings: string[]): string[] {
|
private _dedupeBindings(bindings: string[]): string[] {
|
||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
@ -168,7 +170,8 @@ export class DirectiveResolver {
|
|||||||
host: mergedHost,
|
host: mergedHost,
|
||||||
exportAs: directive.exportAs,
|
exportAs: directive.exportAs,
|
||||||
queries: mergedQueries,
|
queries: mergedQueries,
|
||||||
providers: directive.providers, guards
|
providers: directive.providers,
|
||||||
|
guards
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,12 @@ export class AST {
|
|||||||
* Absolute location of the expression AST in a source code file.
|
* Absolute location of the expression AST in a source code file.
|
||||||
*/
|
*/
|
||||||
public sourceSpan: AbsoluteSourceSpan) {}
|
public sourceSpan: AbsoluteSourceSpan) {}
|
||||||
visit(visitor: AstVisitor, context: any = null): any { return null; }
|
visit(visitor: AstVisitor, context: any = null): any {
|
||||||
toString(): string { return 'AST'; }
|
return null;
|
||||||
|
}
|
||||||
|
toString(): string {
|
||||||
|
return 'AST';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,8 +58,12 @@ export class Quote extends AST {
|
|||||||
public uninterpretedExpression: string, public location: any) {
|
public uninterpretedExpression: string, public location: any) {
|
||||||
super(span, sourceSpan);
|
super(span, sourceSpan);
|
||||||
}
|
}
|
||||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitQuote(this, context); }
|
visit(visitor: AstVisitor, context: any = null): any {
|
||||||
toString(): string { return 'Quote'; }
|
return visitor.visitQuote(this, context);
|
||||||
|
}
|
||||||
|
toString(): string {
|
||||||
|
return 'Quote';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EmptyExpr extends AST {
|
export class EmptyExpr extends AST {
|
||||||
@ -77,7 +85,9 @@ export class Chain extends AST {
|
|||||||
constructor(span: ParseSpan, sourceSpan: AbsoluteSourceSpan, public expressions: any[]) {
|
constructor(span: ParseSpan, sourceSpan: AbsoluteSourceSpan, public expressions: any[]) {
|
||||||
super(span, sourceSpan);
|
super(span, sourceSpan);
|
||||||
}
|
}
|
||||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitChain(this, context); }
|
visit(visitor: AstVisitor, context: any = null): any {
|
||||||
|
return visitor.visitChain(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Conditional extends AST {
|
export class Conditional extends AST {
|
||||||
@ -148,7 +158,9 @@ export class BindingPipe extends AST {
|
|||||||
public args: any[], public nameSpan: AbsoluteSourceSpan) {
|
public args: any[], public nameSpan: AbsoluteSourceSpan) {
|
||||||
super(span, sourceSpan);
|
super(span, sourceSpan);
|
||||||
}
|
}
|
||||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitPipe(this, context); }
|
visit(visitor: AstVisitor, context: any = null): any {
|
||||||
|
return visitor.visitPipe(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LiteralPrimitive extends AST {
|
export class LiteralPrimitive extends AST {
|
||||||
@ -280,7 +292,9 @@ export class ASTWithSource extends AST {
|
|||||||
}
|
}
|
||||||
return this.ast.visit(visitor, context);
|
return this.ast.visit(visitor, context);
|
||||||
}
|
}
|
||||||
toString(): string { return `${this.source} in ${this.location}`; }
|
toString(): string {
|
||||||
|
return `${this.source} in ${this.location}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,7 +316,7 @@ export class ASTWithSource extends AST {
|
|||||||
* the LHS of a HTML attribute to the expression in the RHS. All other bindings
|
* the LHS of a HTML attribute to the expression in the RHS. All other bindings
|
||||||
* in the example above are derived solely from the RHS.
|
* in the example above are derived solely from the RHS.
|
||||||
*/
|
*/
|
||||||
export type TemplateBinding = VariableBinding | ExpressionBinding;
|
export type TemplateBinding = VariableBinding|ExpressionBinding;
|
||||||
|
|
||||||
export class VariableBinding {
|
export class VariableBinding {
|
||||||
/**
|
/**
|
||||||
@ -379,7 +393,9 @@ export class RecursiveAstVisitor implements AstVisitor {
|
|||||||
this.visit(ast.left, context);
|
this.visit(ast.left, context);
|
||||||
this.visit(ast.right, context);
|
this.visit(ast.right, context);
|
||||||
}
|
}
|
||||||
visitChain(ast: Chain, context: any): any { this.visitAll(ast.expressions, context); }
|
visitChain(ast: Chain, context: any): any {
|
||||||
|
this.visitAll(ast.expressions, context);
|
||||||
|
}
|
||||||
visitConditional(ast: Conditional, context: any): any {
|
visitConditional(ast: Conditional, context: any): any {
|
||||||
this.visit(ast.condition, context);
|
this.visit(ast.condition, context);
|
||||||
this.visit(ast.trueExp, context);
|
this.visit(ast.trueExp, context);
|
||||||
@ -411,15 +427,23 @@ export class RecursiveAstVisitor implements AstVisitor {
|
|||||||
visitLiteralArray(ast: LiteralArray, context: any): any {
|
visitLiteralArray(ast: LiteralArray, context: any): any {
|
||||||
this.visitAll(ast.expressions, context);
|
this.visitAll(ast.expressions, context);
|
||||||
}
|
}
|
||||||
visitLiteralMap(ast: LiteralMap, context: any): any { this.visitAll(ast.values, context); }
|
visitLiteralMap(ast: LiteralMap, context: any): any {
|
||||||
|
this.visitAll(ast.values, context);
|
||||||
|
}
|
||||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): any {}
|
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): any {}
|
||||||
visitMethodCall(ast: MethodCall, context: any): any {
|
visitMethodCall(ast: MethodCall, context: any): any {
|
||||||
this.visit(ast.receiver, context);
|
this.visit(ast.receiver, context);
|
||||||
this.visitAll(ast.args, context);
|
this.visitAll(ast.args, context);
|
||||||
}
|
}
|
||||||
visitPrefixNot(ast: PrefixNot, context: any): any { this.visit(ast.expression, context); }
|
visitPrefixNot(ast: PrefixNot, context: any): any {
|
||||||
visitNonNullAssert(ast: NonNullAssert, context: any): any { this.visit(ast.expression, context); }
|
this.visit(ast.expression, context);
|
||||||
visitPropertyRead(ast: PropertyRead, context: any): any { this.visit(ast.receiver, context); }
|
}
|
||||||
|
visitNonNullAssert(ast: NonNullAssert, context: any): any {
|
||||||
|
this.visit(ast.expression, context);
|
||||||
|
}
|
||||||
|
visitPropertyRead(ast: PropertyRead, context: any): any {
|
||||||
|
this.visit(ast.receiver, context);
|
||||||
|
}
|
||||||
visitPropertyWrite(ast: PropertyWrite, context: any): any {
|
visitPropertyWrite(ast: PropertyWrite, context: any): any {
|
||||||
this.visit(ast.receiver, context);
|
this.visit(ast.receiver, context);
|
||||||
this.visit(ast.value, context);
|
this.visit(ast.value, context);
|
||||||
@ -441,7 +465,9 @@ export class RecursiveAstVisitor implements AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AstTransformer implements AstVisitor {
|
export class AstTransformer implements AstVisitor {
|
||||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { return ast; }
|
visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
visitInterpolation(ast: Interpolation, context: any): AST {
|
visitInterpolation(ast: Interpolation, context: any): AST {
|
||||||
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
|
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
|
||||||
@ -476,7 +502,7 @@ export class AstTransformer implements AstVisitor {
|
|||||||
|
|
||||||
visitFunctionCall(ast: FunctionCall, context: any): AST {
|
visitFunctionCall(ast: FunctionCall, context: any): AST {
|
||||||
return new FunctionCall(
|
return new FunctionCall(
|
||||||
ast.span, ast.sourceSpan, ast.target !.visit(this), this.visitAll(ast.args));
|
ast.span, ast.sourceSpan, ast.target!.visit(this), this.visitAll(ast.args));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralArray(ast: LiteralArray, context: any): AST {
|
visitLiteralArray(ast: LiteralArray, context: any): AST {
|
||||||
@ -542,7 +568,9 @@ export class AstTransformer implements AstVisitor {
|
|||||||
// A transformer that only creates new nodes if the transformer makes a change or
|
// A transformer that only creates new nodes if the transformer makes a change or
|
||||||
// a change is made a child node.
|
// a change is made a child node.
|
||||||
export class AstMemoryEfficientTransformer implements AstVisitor {
|
export class AstMemoryEfficientTransformer implements AstVisitor {
|
||||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { return ast; }
|
visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
visitInterpolation(ast: Interpolation, context: any): Interpolation {
|
visitInterpolation(ast: Interpolation, context: any): Interpolation {
|
||||||
const expressions = this.visitAll(ast.expressions);
|
const expressions = this.visitAll(ast.expressions);
|
||||||
@ -551,7 +579,9 @@ export class AstMemoryEfficientTransformer implements AstVisitor {
|
|||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): AST { return ast; }
|
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): AST {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
visitPropertyRead(ast: PropertyRead, context: any): AST {
|
visitPropertyRead(ast: PropertyRead, context: any): AST {
|
||||||
const receiver = ast.receiver.visit(this);
|
const receiver = ast.receiver.visit(this);
|
||||||
@ -704,7 +734,9 @@ export class AstMemoryEfficientTransformer implements AstVisitor {
|
|||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitQuote(ast: Quote, context: any): AST { return ast; }
|
visitQuote(ast: Quote, context: any): AST {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bindings
|
// Bindings
|
||||||
|
@ -42,37 +42,61 @@ export class Token {
|
|||||||
return this.type == TokenType.Character && this.numValue == code;
|
return this.type == TokenType.Character && this.numValue == code;
|
||||||
}
|
}
|
||||||
|
|
||||||
isNumber(): boolean { return this.type == TokenType.Number; }
|
isNumber(): boolean {
|
||||||
|
return this.type == TokenType.Number;
|
||||||
|
}
|
||||||
|
|
||||||
isString(): boolean { return this.type == TokenType.String; }
|
isString(): boolean {
|
||||||
|
return this.type == TokenType.String;
|
||||||
|
}
|
||||||
|
|
||||||
isOperator(operator: string): boolean {
|
isOperator(operator: string): boolean {
|
||||||
return this.type == TokenType.Operator && this.strValue == operator;
|
return this.type == TokenType.Operator && this.strValue == operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
isIdentifier(): boolean { return this.type == TokenType.Identifier; }
|
isIdentifier(): boolean {
|
||||||
|
return this.type == TokenType.Identifier;
|
||||||
|
}
|
||||||
|
|
||||||
isKeyword(): boolean { return this.type == TokenType.Keyword; }
|
isKeyword(): boolean {
|
||||||
|
return this.type == TokenType.Keyword;
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordLet(): boolean { return this.type == TokenType.Keyword && this.strValue == 'let'; }
|
isKeywordLet(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'let';
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordAs(): boolean { return this.type == TokenType.Keyword && this.strValue == 'as'; }
|
isKeywordAs(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'as';
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordNull(): boolean { return this.type == TokenType.Keyword && this.strValue == 'null'; }
|
isKeywordNull(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'null';
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordUndefined(): boolean {
|
isKeywordUndefined(): boolean {
|
||||||
return this.type == TokenType.Keyword && this.strValue == 'undefined';
|
return this.type == TokenType.Keyword && this.strValue == 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
isKeywordTrue(): boolean { return this.type == TokenType.Keyword && this.strValue == 'true'; }
|
isKeywordTrue(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'true';
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordFalse(): boolean { return this.type == TokenType.Keyword && this.strValue == 'false'; }
|
isKeywordFalse(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'false';
|
||||||
|
}
|
||||||
|
|
||||||
isKeywordThis(): boolean { return this.type == TokenType.Keyword && this.strValue == 'this'; }
|
isKeywordThis(): boolean {
|
||||||
|
return this.type == TokenType.Keyword && this.strValue == 'this';
|
||||||
|
}
|
||||||
|
|
||||||
isError(): boolean { return this.type == TokenType.Error; }
|
isError(): boolean {
|
||||||
|
return this.type == TokenType.Error;
|
||||||
|
}
|
||||||
|
|
||||||
toNumber(): number { return this.type == TokenType.Number ? this.numValue : -1; }
|
toNumber(): number {
|
||||||
|
return this.type == TokenType.Number ? this.numValue : -1;
|
||||||
|
}
|
||||||
|
|
||||||
toString(): string|null {
|
toString(): string|null {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
|
@ -10,8 +10,8 @@ import * as chars from '../chars';
|
|||||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||||
import {escapeRegExp} from '../util';
|
import {escapeRegExp} from '../util';
|
||||||
|
|
||||||
import {AST, ASTWithSource, AbsoluteSourceSpan, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, ExpressionBinding, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralMapKey, LiteralPrimitive, MethodCall, NonNullAssert, ParseSpan, ParserError, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding, TemplateBindingIdentifier, VariableBinding} from './ast';
|
import {AbsoluteSourceSpan, AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, EmptyExpr, ExpressionBinding, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralMapKey, LiteralPrimitive, MethodCall, NonNullAssert, ParserError, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding, TemplateBindingIdentifier, VariableBinding} from './ast';
|
||||||
import {EOF, Lexer, Token, TokenType, isIdentifier, isQuote} from './lexer';
|
import {EOF, isIdentifier, isQuote, Lexer, Token, TokenType} from './lexer';
|
||||||
|
|
||||||
export class SplitInterpolation {
|
export class SplitInterpolation {
|
||||||
constructor(public strings: string[], public expressions: string[], public offsets: number[]) {}
|
constructor(public strings: string[], public expressions: string[], public offsets: number[]) {}
|
||||||
@ -253,7 +253,8 @@ export class Parser {
|
|||||||
const parts = input.split(regexp);
|
const parts = input.split(regexp);
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Got interpolation (${interpolationConfig.start}${interpolationConfig.end}) where expression was expected`,
|
`Got interpolation (${interpolationConfig.start}${
|
||||||
|
interpolationConfig.end}) where expression was expected`,
|
||||||
input,
|
input,
|
||||||
`at column ${this._findInterpolationErrorColumn(parts, 1, interpolationConfig)} in`,
|
`at column ${this._findInterpolationErrorColumn(parts, 1, interpolationConfig)} in`,
|
||||||
location);
|
location);
|
||||||
@ -300,7 +301,9 @@ export class _ParseAST {
|
|||||||
return i < this.tokens.length ? this.tokens[i] : EOF;
|
return i < this.tokens.length ? this.tokens[i] : EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
get next(): Token { return this.peek(0); }
|
get next(): Token {
|
||||||
|
return this.peek(0);
|
||||||
|
}
|
||||||
|
|
||||||
get inputIndex(): number {
|
get inputIndex(): number {
|
||||||
return (this.index < this.tokens.length) ? this.next.index + this.offset :
|
return (this.index < this.tokens.length) ? this.next.index + this.offset :
|
||||||
@ -310,7 +313,9 @@ export class _ParseAST {
|
|||||||
/**
|
/**
|
||||||
* Returns the absolute offset of the start of the current token.
|
* Returns the absolute offset of the start of the current token.
|
||||||
*/
|
*/
|
||||||
get currentAbsoluteOffset(): number { return this.absoluteOffset + this.inputIndex; }
|
get currentAbsoluteOffset(): number {
|
||||||
|
return this.absoluteOffset + this.inputIndex;
|
||||||
|
}
|
||||||
|
|
||||||
span(start: number) {
|
span(start: number) {
|
||||||
// `end` is either the
|
// `end` is either the
|
||||||
@ -326,10 +331,12 @@ export class _ParseAST {
|
|||||||
if (!this.sourceSpanCache.has(serial)) {
|
if (!this.sourceSpanCache.has(serial)) {
|
||||||
this.sourceSpanCache.set(serial, this.span(start).toAbsolute(this.absoluteOffset));
|
this.sourceSpanCache.set(serial, this.span(start).toAbsolute(this.absoluteOffset));
|
||||||
}
|
}
|
||||||
return this.sourceSpanCache.get(serial) !;
|
return this.sourceSpanCache.get(serial)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
advance() { this.index++; }
|
advance() {
|
||||||
|
this.index++;
|
||||||
|
}
|
||||||
|
|
||||||
consumeOptionalCharacter(code: number): boolean {
|
consumeOptionalCharacter(code: number): boolean {
|
||||||
if (this.next.isCharacter(code)) {
|
if (this.next.isCharacter(code)) {
|
||||||
@ -340,8 +347,12 @@ export class _ParseAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
peekKeywordLet(): boolean { return this.next.isKeywordLet(); }
|
peekKeywordLet(): boolean {
|
||||||
peekKeywordAs(): boolean { return this.next.isKeywordAs(); }
|
return this.next.isKeywordLet();
|
||||||
|
}
|
||||||
|
peekKeywordAs(): boolean {
|
||||||
|
return this.next.isKeywordAs();
|
||||||
|
}
|
||||||
|
|
||||||
expectCharacter(code: number) {
|
expectCharacter(code: number) {
|
||||||
if (this.consumeOptionalCharacter(code)) return;
|
if (this.consumeOptionalCharacter(code)) return;
|
||||||
@ -428,7 +439,9 @@ export class _ParseAST {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseExpression(): AST { return this.parseConditional(); }
|
parseExpression(): AST {
|
||||||
|
return this.parseConditional();
|
||||||
|
}
|
||||||
|
|
||||||
parseConditional(): AST {
|
parseConditional(): AST {
|
||||||
const start = this.inputIndex;
|
const start = this.inputIndex;
|
||||||
@ -984,8 +997,8 @@ export class _ParseAST {
|
|||||||
(this.rbracesExpected <= 0 || !n.isCharacter(chars.$RBRACE)) &&
|
(this.rbracesExpected <= 0 || !n.isCharacter(chars.$RBRACE)) &&
|
||||||
(this.rbracketsExpected <= 0 || !n.isCharacter(chars.$RBRACKET))) {
|
(this.rbracketsExpected <= 0 || !n.isCharacter(chars.$RBRACKET))) {
|
||||||
if (this.next.isError()) {
|
if (this.next.isError()) {
|
||||||
this.errors.push(new ParserError(
|
this.errors.push(
|
||||||
this.next.toString() !, this.input, this.locationText(), this.location));
|
new ParserError(this.next.toString()!, this.input, this.locationText(), this.location));
|
||||||
}
|
}
|
||||||
this.advance();
|
this.advance();
|
||||||
n = this.next;
|
n = this.next;
|
||||||
@ -1014,9 +1027,13 @@ class SimpleExpressionChecker implements AstVisitor {
|
|||||||
|
|
||||||
visitFunctionCall(ast: FunctionCall, context: any) {}
|
visitFunctionCall(ast: FunctionCall, context: any) {}
|
||||||
|
|
||||||
visitLiteralArray(ast: LiteralArray, context: any) { this.visitAll(ast.expressions); }
|
visitLiteralArray(ast: LiteralArray, context: any) {
|
||||||
|
this.visitAll(ast.expressions);
|
||||||
|
}
|
||||||
|
|
||||||
visitLiteralMap(ast: LiteralMap, context: any) { this.visitAll(ast.values); }
|
visitLiteralMap(ast: LiteralMap, context: any) {
|
||||||
|
this.visitAll(ast.values);
|
||||||
|
}
|
||||||
|
|
||||||
visitBinary(ast: Binary, context: any) {}
|
visitBinary(ast: Binary, context: any) {}
|
||||||
|
|
||||||
@ -1026,13 +1043,17 @@ class SimpleExpressionChecker implements AstVisitor {
|
|||||||
|
|
||||||
visitConditional(ast: Conditional, context: any) {}
|
visitConditional(ast: Conditional, context: any) {}
|
||||||
|
|
||||||
visitPipe(ast: BindingPipe, context: any) { this.errors.push('pipes'); }
|
visitPipe(ast: BindingPipe, context: any) {
|
||||||
|
this.errors.push('pipes');
|
||||||
|
}
|
||||||
|
|
||||||
visitKeyedRead(ast: KeyedRead, context: any) {}
|
visitKeyedRead(ast: KeyedRead, context: any) {}
|
||||||
|
|
||||||
visitKeyedWrite(ast: KeyedWrite, context: any) {}
|
visitKeyedWrite(ast: KeyedWrite, context: any) {}
|
||||||
|
|
||||||
visitAll(asts: any[]): any[] { return asts.map(node => node.visit(this)); }
|
visitAll(asts: any[]): any[] {
|
||||||
|
return asts.map(node => node.visit(this));
|
||||||
|
}
|
||||||
|
|
||||||
visitChain(ast: Chain, context: any) {}
|
visitChain(ast: Chain, context: any) {}
|
||||||
|
|
||||||
@ -1052,5 +1073,7 @@ class IvySimpleExpressionChecker extends SimpleExpressionChecker {
|
|||||||
ast.right.visit(this);
|
ast.right.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPrefixNot(ast: PrefixNot, context: any) { ast.expression.visit(this); }
|
visitPrefixNot(ast: PrefixNot, context: any) {
|
||||||
|
ast.expression.visit(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@ export function computeDecimalDigest(message: i18n.Message): string {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
class _SerializerVisitor implements i18n.Visitor {
|
class _SerializerVisitor implements i18n.Visitor {
|
||||||
visitText(text: i18n.Text, context: any): any { return text.value; }
|
visitText(text: i18n.Text, context: any): any {
|
||||||
|
return text.value;
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container, context: any): any {
|
visitContainer(container: i18n.Container, context: any): any {
|
||||||
return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
|
return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
|
||||||
@ -63,7 +65,8 @@ class _SerializerVisitor implements i18n.Visitor {
|
|||||||
visitTagPlaceholder(ph: i18n.TagPlaceholder, context: any): any {
|
visitTagPlaceholder(ph: i18n.TagPlaceholder, context: any): any {
|
||||||
return ph.isVoid ?
|
return ph.isVoid ?
|
||||||
`<ph tag name="${ph.startName}"/>` :
|
`<ph tag name="${ph.startName}"/>` :
|
||||||
`<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
|
`<ph tag name="${ph.startName}">${
|
||||||
|
ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPlaceholder(ph: i18n.Placeholder, context: any): any {
|
visitPlaceholder(ph: i18n.Placeholder, context: any): any {
|
||||||
|
@ -78,11 +78,11 @@ export class Extractor {
|
|||||||
// Template URL points to either an HTML or TS file depending on
|
// Template URL points to either an HTML or TS file depending on
|
||||||
// whether the file is used with `templateUrl:` or `template:`,
|
// whether the file is used with `templateUrl:` or `template:`,
|
||||||
// respectively.
|
// respectively.
|
||||||
const templateUrl = compMeta.template !.templateUrl !;
|
const templateUrl = compMeta.template !.templateUrl!;
|
||||||
const interpolationConfig =
|
const interpolationConfig =
|
||||||
InterpolationConfig.fromArray(compMeta.template !.interpolation);
|
InterpolationConfig.fromArray(compMeta.template !.interpolation);
|
||||||
errors.push(...this.messageBundle.updateFromTemplate(
|
errors.push(...this.messageBundle.updateFromTemplate(
|
||||||
html, templateUrl, interpolationConfig) !);
|
html, templateUrl, interpolationConfig)!);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -9,8 +9,9 @@
|
|||||||
import * as html from '../ml_parser/ast';
|
import * as html from '../ml_parser/ast';
|
||||||
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||||
import {ParseTreeResult} from '../ml_parser/parser';
|
import {ParseTreeResult} from '../ml_parser/parser';
|
||||||
|
|
||||||
import * as i18n from './i18n_ast';
|
import * as i18n from './i18n_ast';
|
||||||
import {I18nMessageFactory, createI18nMessageFactory} from './i18n_parser';
|
import {createI18nMessageFactory, I18nMessageFactory} from './i18n_parser';
|
||||||
import {I18nError} from './parse_util';
|
import {I18nError} from './parse_util';
|
||||||
import {TranslationBundle} from './translation_bundle';
|
import {TranslationBundle} from './translation_bundle';
|
||||||
|
|
||||||
@ -56,44 +57,44 @@ enum _VisitorMode {
|
|||||||
*/
|
*/
|
||||||
class _Visitor implements html.Visitor {
|
class _Visitor implements html.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _depth !: number;
|
private _depth!: number;
|
||||||
|
|
||||||
// <el i18n>...</el>
|
// <el i18n>...</el>
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _inI18nNode !: boolean;
|
private _inI18nNode!: boolean;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _inImplicitNode !: boolean;
|
private _inImplicitNode!: boolean;
|
||||||
|
|
||||||
// <!--i18n-->...<!--/i18n-->
|
// <!--i18n-->...<!--/i18n-->
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _inI18nBlock !: boolean;
|
private _inI18nBlock!: boolean;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _blockMeaningAndDesc !: string;
|
private _blockMeaningAndDesc!: string;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _blockChildren !: html.Node[];
|
private _blockChildren!: html.Node[];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _blockStartDepth !: number;
|
private _blockStartDepth!: number;
|
||||||
|
|
||||||
// {<icu message>}
|
// {<icu message>}
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _inIcu !: boolean;
|
private _inIcu!: boolean;
|
||||||
|
|
||||||
// set to void 0 when not in a section
|
// set to void 0 when not in a section
|
||||||
private _msgCountAtSectionStart: number|undefined;
|
private _msgCountAtSectionStart: number|undefined;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _mode !: _VisitorMode;
|
private _mode!: _VisitorMode;
|
||||||
|
|
||||||
// _VisitorMode.Extract only
|
// _VisitorMode.Extract only
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _messages !: i18n.Message[];
|
private _messages!: i18n.Message[];
|
||||||
|
|
||||||
// _VisitorMode.Merge only
|
// _VisitorMode.Merge only
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _translations !: TranslationBundle;
|
private _translations!: TranslationBundle;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _createI18nMessage !: I18nMessageFactory;
|
private _createI18nMessage!: I18nMessageFactory;
|
||||||
|
|
||||||
|
|
||||||
constructor(private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
|
constructor(private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
|
||||||
@ -123,7 +124,7 @@ class _Visitor implements html.Visitor {
|
|||||||
this._translations = translations;
|
this._translations = translations;
|
||||||
|
|
||||||
// Construct a single fake root element
|
// Construct a single fake root element
|
||||||
const wrapper = new html.Element('wrapper', [], nodes, undefined !, undefined, undefined);
|
const wrapper = new html.Element('wrapper', [], nodes, undefined!, undefined, undefined);
|
||||||
|
|
||||||
const translatedNode = wrapper.visit(this, null);
|
const translatedNode = wrapper.visit(this, null);
|
||||||
|
|
||||||
@ -193,14 +194,14 @@ class _Visitor implements html.Visitor {
|
|||||||
i18nCommentsWarned = true;
|
i18nCommentsWarned = true;
|
||||||
const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : '';
|
const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : '';
|
||||||
// TODO(ocombe): use a log service once there is a public one available
|
// TODO(ocombe): use a log service once there is a public one available
|
||||||
console.warn(
|
console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${
|
||||||
`I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`);
|
comment.sourceSpan.start}${details})`);
|
||||||
}
|
}
|
||||||
this._inI18nBlock = true;
|
this._inI18nBlock = true;
|
||||||
this._blockStartDepth = this._depth;
|
this._blockStartDepth = this._depth;
|
||||||
this._blockChildren = [];
|
this._blockChildren = [];
|
||||||
this._blockMeaningAndDesc =
|
this._blockMeaningAndDesc =
|
||||||
comment.value !.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
|
comment.value!.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
|
||||||
this._openTranslatableSection(comment);
|
this._openTranslatableSection(comment);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -208,7 +209,7 @@ class _Visitor implements html.Visitor {
|
|||||||
if (this._depth == this._blockStartDepth) {
|
if (this._depth == this._blockStartDepth) {
|
||||||
this._closeTranslatableSection(comment, this._blockChildren);
|
this._closeTranslatableSection(comment, this._blockChildren);
|
||||||
this._inI18nBlock = false;
|
this._inI18nBlock = false;
|
||||||
const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc) !;
|
const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc)!;
|
||||||
// merge attributes in sections
|
// merge attributes in sections
|
||||||
const nodes = this._translateMessage(comment, message);
|
const nodes = this._translateMessage(comment, message);
|
||||||
return html.visitAll(this, nodes);
|
return html.visitAll(this, nodes);
|
||||||
@ -234,7 +235,7 @@ class _Visitor implements html.Visitor {
|
|||||||
const wasInI18nNode = this._inI18nNode;
|
const wasInI18nNode = this._inI18nNode;
|
||||||
const wasInImplicitNode = this._inImplicitNode;
|
const wasInImplicitNode = this._inImplicitNode;
|
||||||
let childNodes: html.Node[] = [];
|
let childNodes: html.Node[] = [];
|
||||||
let translatedChildNodes: html.Node[] = undefined !;
|
let translatedChildNodes: html.Node[] = undefined!;
|
||||||
|
|
||||||
// Extract:
|
// Extract:
|
||||||
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
||||||
@ -249,7 +250,7 @@ class _Visitor implements html.Visitor {
|
|||||||
if (!this._isInTranslatableSection && !this._inIcu) {
|
if (!this._isInTranslatableSection && !this._inIcu) {
|
||||||
if (i18nAttr || isTopLevelImplicit) {
|
if (i18nAttr || isTopLevelImplicit) {
|
||||||
this._inI18nNode = true;
|
this._inI18nNode = true;
|
||||||
const message = this._addMessage(el.children, i18nMeta) !;
|
const message = this._addMessage(el.children, i18nMeta)!;
|
||||||
translatedChildNodes = this._translateMessage(el, message);
|
translatedChildNodes = this._translateMessage(el, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,12 +401,14 @@ class _Visitor implements html.Visitor {
|
|||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
el,
|
el,
|
||||||
`Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
|
`Unexpected translation for attribute "${attr.name}" (id="${
|
||||||
|
id || this._translations.digest(message)}")`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
el,
|
el,
|
||||||
`Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
|
`Translation unavailable for attribute "${attr.name}" (id="${
|
||||||
|
id || this._translations.digest(message)}")`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
translatedAttributes.push(attr);
|
translatedAttributes.push(attr);
|
||||||
@ -476,7 +479,7 @@ class _Visitor implements html.Visitor {
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
if (significantChildren == 1) {
|
if (significantChildren == 1) {
|
||||||
for (let i = this._messages.length - 1; i >= startIndex !; i--) {
|
for (let i = this._messages.length - 1; i >= startIndex!; i--) {
|
||||||
const ast = this._messages[i].nodes;
|
const ast = this._messages[i].nodes;
|
||||||
if (!(ast.length == 1 && ast[0] instanceof i18n.Text)) {
|
if (!(ast.length == 1 && ast[0] instanceof i18n.Text)) {
|
||||||
this._messages.splice(i, 1);
|
this._messages.splice(i, 1);
|
||||||
@ -489,7 +492,7 @@ class _Visitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _reportError(node: html.Node, msg: string): void {
|
private _reportError(node: html.Node, msg: string): void {
|
||||||
this._errors.push(new I18nError(node.sourceSpan !, msg));
|
this._errors.push(new I18nError(node.sourceSpan!, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,24 +57,30 @@ export interface Node {
|
|||||||
export class Text implements Node {
|
export class Text implements Node {
|
||||||
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitText(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitText(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(vicb): do we really need this node (vs an array) ?
|
// TODO(vicb): do we really need this node (vs an array) ?
|
||||||
export class Container implements Node {
|
export class Container implements Node {
|
||||||
constructor(public children: Node[], public sourceSpan: ParseSourceSpan) {}
|
constructor(public children: Node[], public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitContainer(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitContainer(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Icu implements Node {
|
export class Icu implements Node {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
public expressionPlaceholder !: string;
|
public expressionPlaceholder!: string;
|
||||||
constructor(
|
constructor(
|
||||||
public expression: string, public type: string, public cases: {[k: string]: Node},
|
public expression: string, public type: string, public cases: {[k: string]: Node},
|
||||||
public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitIcu(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitIcu(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TagPlaceholder implements Node {
|
export class TagPlaceholder implements Node {
|
||||||
@ -83,13 +89,17 @@ export class TagPlaceholder implements Node {
|
|||||||
public closeName: string, public children: Node[], public isVoid: boolean,
|
public closeName: string, public children: Node[], public isVoid: boolean,
|
||||||
public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitTagPlaceholder(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitTagPlaceholder(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Placeholder implements Node {
|
export class Placeholder implements Node {
|
||||||
constructor(public value: string, public name: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public value: string, public name: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitPlaceholder(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitPlaceholder(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IcuPlaceholder implements Node {
|
export class IcuPlaceholder implements Node {
|
||||||
@ -97,7 +107,9 @@ export class IcuPlaceholder implements Node {
|
|||||||
previousMessage?: Message;
|
previousMessage?: Message;
|
||||||
constructor(public value: Icu, public name: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public value: Icu, public name: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context?: any): any { return visitor.visitIcuPlaceholder(this, context); }
|
visit(visitor: Visitor, context?: any): any {
|
||||||
|
return visitor.visitIcuPlaceholder(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +118,7 @@ export class IcuPlaceholder implements Node {
|
|||||||
* This information is either a `Message`, which indicates it is the root of an i18n message, or a
|
* This information is either a `Message`, which indicates it is the root of an i18n message, or a
|
||||||
* `Node`, which indicates is it part of a containing `Message`.
|
* `Node`, which indicates is it part of a containing `Message`.
|
||||||
*/
|
*/
|
||||||
export type I18nMeta = Message | Node;
|
export type I18nMeta = Message|Node;
|
||||||
|
|
||||||
export interface Visitor {
|
export interface Visitor {
|
||||||
visitText(text: Text, context?: any): any;
|
visitText(text: Text, context?: any): any;
|
||||||
@ -119,7 +131,9 @@ export interface Visitor {
|
|||||||
|
|
||||||
// Clone the AST
|
// Clone the AST
|
||||||
export class CloneVisitor implements Visitor {
|
export class CloneVisitor implements Visitor {
|
||||||
visitText(text: Text, context?: any): Text { return new Text(text.value, text.sourceSpan); }
|
visitText(text: Text, context?: any): Text {
|
||||||
|
return new Text(text.value, text.sourceSpan);
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: Container, context?: any): Container {
|
visitContainer(container: Container, context?: any): Container {
|
||||||
const children = container.children.map(n => n.visit(this, context));
|
const children = container.children.map(n => n.visit(this, context));
|
||||||
@ -158,7 +172,9 @@ export class RecurseVisitor implements Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitIcu(icu: Icu, context?: any): any {
|
visitIcu(icu: Icu, context?: any): any {
|
||||||
Object.keys(icu.cases).forEach(k => { icu.cases[k].visit(this); });
|
Object.keys(icu.cases).forEach(k => {
|
||||||
|
icu.cases[k].visit(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
visitTagPlaceholder(ph: TagPlaceholder, context?: any): any {
|
visitTagPlaceholder(ph: TagPlaceholder, context?: any): any {
|
||||||
|
@ -83,7 +83,7 @@ class _I18nVisitor implements html.Visitor {
|
|||||||
const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid;
|
const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid;
|
||||||
const startPhName =
|
const startPhName =
|
||||||
context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
|
context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
|
||||||
context.placeholderToContent[startPhName] = el.sourceSpan !.toString();
|
context.placeholderToContent[startPhName] = el.sourceSpan!.toString();
|
||||||
|
|
||||||
let closePhName = '';
|
let closePhName = '';
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class _I18nVisitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const node = new i18n.TagPlaceholder(
|
const node = new i18n.TagPlaceholder(
|
||||||
el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan !);
|
el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan!);
|
||||||
return context.visitNodeFn(el, node);
|
return context.visitNodeFn(el, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class _I18nVisitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: html.Text, context: I18nMessageVisitorContext): i18n.Node {
|
visitText(text: html.Text, context: I18nMessageVisitorContext): i18n.Node {
|
||||||
const node = this._visitTextWithInterpolation(text.value, text.sourceSpan !, context);
|
const node = this._visitTextWithInterpolation(text.value, text.sourceSpan!, context);
|
||||||
return context.visitNodeFn(text, node);
|
return context.visitNodeFn(text, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,9 @@ export class MessageBundle {
|
|||||||
|
|
||||||
// Return the message in the internal format
|
// Return the message in the internal format
|
||||||
// The public (serialized) format might be different, see the `write` method.
|
// The public (serialized) format might be different, see the `write` method.
|
||||||
getMessages(): i18n.Message[] { return this._messages; }
|
getMessages(): i18n.Message[] {
|
||||||
|
return this._messages;
|
||||||
|
}
|
||||||
|
|
||||||
write(serializer: Serializer, filterSources?: (path: string) => string): string {
|
write(serializer: Serializer, filterSources?: (path: string) => string): string {
|
||||||
const messages: {[id: string]: i18n.Message} = {};
|
const messages: {[id: string]: i18n.Message} = {};
|
||||||
@ -88,18 +90,18 @@ class MapPlaceholderNames extends i18n.CloneVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitTagPlaceholder(ph: i18n.TagPlaceholder, mapper: PlaceholderMapper): i18n.TagPlaceholder {
|
visitTagPlaceholder(ph: i18n.TagPlaceholder, mapper: PlaceholderMapper): i18n.TagPlaceholder {
|
||||||
const startName = mapper.toPublicName(ph.startName) !;
|
const startName = mapper.toPublicName(ph.startName)!;
|
||||||
const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) ! : ph.closeName;
|
const closeName = ph.closeName ? mapper.toPublicName(ph.closeName)! : ph.closeName;
|
||||||
const children = ph.children.map(n => n.visit(this, mapper));
|
const children = ph.children.map(n => n.visit(this, mapper));
|
||||||
return new i18n.TagPlaceholder(
|
return new i18n.TagPlaceholder(
|
||||||
ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan);
|
ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder {
|
visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder {
|
||||||
return new i18n.Placeholder(ph.value, mapper.toPublicName(ph.name) !, ph.sourceSpan);
|
return new i18n.Placeholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, mapper: PlaceholderMapper): i18n.IcuPlaceholder {
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, mapper: PlaceholderMapper): i18n.IcuPlaceholder {
|
||||||
return new i18n.IcuPlaceholder(ph.value, mapper.toPublicName(ph.name) !, ph.sourceSpan);
|
return new i18n.IcuPlaceholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,7 @@ import {ParseError, ParseSourceSpan} from '../parse_util';
|
|||||||
* An i18n error.
|
* An i18n error.
|
||||||
*/
|
*/
|
||||||
export class I18nError extends ParseError {
|
export class I18nError extends ParseError {
|
||||||
constructor(span: ParseSourceSpan, msg: string) { super(span, msg); }
|
constructor(span: ParseSourceSpan, msg: string) {
|
||||||
|
super(span, msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,9 @@ export class PlaceholderRegistry {
|
|||||||
return start + strAttrs + end;
|
return start + strAttrs + end;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _hashClosingTag(tag: string): string { return this._hashTag(`/${tag}`, {}, false); }
|
private _hashClosingTag(tag: string): string {
|
||||||
|
return this._hashTag(`/${tag}`, {}, false);
|
||||||
|
}
|
||||||
|
|
||||||
private _generateUniqueName(base: string): string {
|
private _generateUniqueName(base: string): string {
|
||||||
const seen = this._placeHolderNameCounts.hasOwnProperty(base);
|
const seen = this._placeHolderNameCounts.hasOwnProperty(base);
|
||||||
|
@ -15,13 +15,15 @@ export abstract class Serializer {
|
|||||||
abstract write(messages: i18n.Message[], locale: string|null): string;
|
abstract write(messages: i18n.Message[], locale: string|null): string;
|
||||||
|
|
||||||
abstract load(content: string, url: string):
|
abstract load(content: string, url: string):
|
||||||
{locale: string | null, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}};
|
{locale: string|null, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}};
|
||||||
|
|
||||||
abstract digest(message: i18n.Message): string;
|
abstract digest(message: i18n.Message): string;
|
||||||
|
|
||||||
// Creates a name mapper, see `PlaceholderMapper`
|
// Creates a name mapper, see `PlaceholderMapper`
|
||||||
// Returning `null` means that no name mapping is used.
|
// Returning `null` means that no name mapping is used.
|
||||||
createNameMapper(message: i18n.Message): PlaceholderMapper|null { return null; }
|
createNameMapper(message: i18n.Message): PlaceholderMapper|null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +63,9 @@ export class SimplePlaceholderMapper extends i18n.RecurseVisitor implements Plac
|
|||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: i18n.Text, context?: any): any { return null; }
|
visitText(text: i18n.Text, context?: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): any {
|
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): any {
|
||||||
this.visitPlaceholderName(ph.startName);
|
this.visitPlaceholderName(ph.startName);
|
||||||
@ -69,7 +73,9 @@ export class SimplePlaceholderMapper extends i18n.RecurseVisitor implements Plac
|
|||||||
this.visitPlaceholderName(ph.closeName);
|
this.visitPlaceholderName(ph.closeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPlaceholder(ph: i18n.Placeholder, context?: any): any { this.visitPlaceholderName(ph.name); }
|
visitPlaceholder(ph: i18n.Placeholder, context?: any): any {
|
||||||
|
this.visitPlaceholderName(ph.name);
|
||||||
|
}
|
||||||
|
|
||||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
||||||
this.visitPlaceholderName(ph.name);
|
this.visitPlaceholderName(ph.name);
|
||||||
|
@ -46,9 +46,9 @@ export class Xliff extends Serializer {
|
|||||||
new xml.CR(10),
|
new xml.CR(10),
|
||||||
new xml.Tag(
|
new xml.Tag(
|
||||||
_CONTEXT_TAG, {'context-type': 'sourcefile'}, [new xml.Text(source.filePath)]),
|
_CONTEXT_TAG, {'context-type': 'sourcefile'}, [new xml.Text(source.filePath)]),
|
||||||
new xml.CR(10), new xml.Tag(
|
new xml.CR(10),
|
||||||
_CONTEXT_TAG, {'context-type': 'linenumber'},
|
new xml.Tag(_CONTEXT_TAG, {'context-type': 'linenumber'}, [new xml.Text(
|
||||||
[new xml.Text(`${source.startLine}`)]),
|
`${source.startLine}`)]),
|
||||||
new xml.CR(8));
|
new xml.CR(8));
|
||||||
contextTags.push(new xml.CR(8), contextGroupTag);
|
contextTags.push(new xml.CR(8), contextGroupTag);
|
||||||
});
|
});
|
||||||
@ -112,14 +112,18 @@ export class Xliff extends Serializer {
|
|||||||
throw new Error(`xliff parse errors:\n${errors.join('\n')}`);
|
throw new Error(`xliff parse errors:\n${errors.join('\n')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {locale: locale !, i18nNodesByMsgId};
|
return {locale: locale!, i18nNodesByMsgId};
|
||||||
}
|
}
|
||||||
|
|
||||||
digest(message: i18n.Message): string { return digest(message); }
|
digest(message: i18n.Message): string {
|
||||||
|
return digest(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _WriteVisitor implements i18n.Visitor {
|
class _WriteVisitor implements i18n.Visitor {
|
||||||
visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; }
|
visitText(text: i18n.Text, context?: any): xml.Node[] {
|
||||||
|
return [new xml.Text(text.value)];
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
|
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
|
||||||
const nodes: xml.Node[] = [];
|
const nodes: xml.Node[] = [];
|
||||||
@ -161,8 +165,8 @@ class _WriteVisitor implements i18n.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] {
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] {
|
||||||
const equivText =
|
const equivText = `{${ph.value.expression}, ${ph.value.type}, ${
|
||||||
`{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`;
|
Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`;
|
||||||
return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name, 'equiv-text': equivText})];
|
return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name, 'equiv-text': equivText})];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,11 +179,11 @@ class _WriteVisitor implements i18n.Visitor {
|
|||||||
// Extract messages as xml nodes from the xliff file
|
// Extract messages as xml nodes from the xliff file
|
||||||
class XliffParser implements ml.Visitor {
|
class XliffParser implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _unitMlString !: string | null;
|
private _unitMlString!: string|null;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _msgIdToHtml !: {[msgId: string]: string};
|
private _msgIdToHtml!: {[msgId: string]: string};
|
||||||
private _locale: string|null = null;
|
private _locale: string|null = null;
|
||||||
|
|
||||||
parse(xliff: string, url: string) {
|
parse(xliff: string, url: string) {
|
||||||
@ -201,7 +205,7 @@ class XliffParser implements ml.Visitor {
|
|||||||
visitElement(element: ml.Element, context: any): any {
|
visitElement(element: ml.Element, context: any): any {
|
||||||
switch (element.name) {
|
switch (element.name) {
|
||||||
case _UNIT_TAG:
|
case _UNIT_TAG:
|
||||||
this._unitMlString = null !;
|
this._unitMlString = null!;
|
||||||
const idAttr = element.attrs.find((attr) => attr.name === 'id');
|
const idAttr = element.attrs.find((attr) => attr.name === 'id');
|
||||||
if (!idAttr) {
|
if (!idAttr) {
|
||||||
this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
|
this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
|
||||||
@ -227,9 +231,9 @@ class XliffParser implements ml.Visitor {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case _TARGET_TAG:
|
case _TARGET_TAG:
|
||||||
const innerTextStart = element.startSourceSpan !.end.offset;
|
const innerTextStart = element.startSourceSpan!.end.offset;
|
||||||
const innerTextEnd = element.endSourceSpan !.start.offset;
|
const innerTextEnd = element.endSourceSpan!.start.offset;
|
||||||
const content = element.startSourceSpan !.start.file.content;
|
const content = element.startSourceSpan!.start.file.content;
|
||||||
const innerText = content.slice(innerTextStart, innerTextEnd);
|
const innerText = content.slice(innerTextStart, innerTextEnd);
|
||||||
this._unitMlString = innerText;
|
this._unitMlString = innerText;
|
||||||
break;
|
break;
|
||||||
@ -260,14 +264,14 @@ class XliffParser implements ml.Visitor {
|
|||||||
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
|
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
|
||||||
|
|
||||||
private _addError(node: ml.Node, message: string): void {
|
private _addError(node: ml.Node, message: string): void {
|
||||||
this._errors.push(new I18nError(node.sourceSpan !, message));
|
this._errors.push(new I18nError(node.sourceSpan!, message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert ml nodes (xliff syntax) to i18n nodes
|
// Convert ml nodes (xliff syntax) to i18n nodes
|
||||||
class XmlToI18n implements ml.Visitor {
|
class XmlToI18n implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
|
|
||||||
convert(message: string, url: string) {
|
convert(message: string, url: string) {
|
||||||
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
||||||
@ -283,13 +287,15 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan !); }
|
visitText(text: ml.Text, context: any) {
|
||||||
|
return new i18n.Text(text.value, text.sourceSpan!);
|
||||||
|
}
|
||||||
|
|
||||||
visitElement(el: ml.Element, context: any): i18n.Placeholder|ml.Node[]|null {
|
visitElement(el: ml.Element, context: any): i18n.Placeholder|ml.Node[]|null {
|
||||||
if (el.name === _PLACEHOLDER_TAG) {
|
if (el.name === _PLACEHOLDER_TAG) {
|
||||||
const nameAttr = el.attrs.find((attr) => attr.name === 'id');
|
const nameAttr = el.attrs.find((attr) => attr.name === 'id');
|
||||||
if (nameAttr) {
|
if (nameAttr) {
|
||||||
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan !);
|
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "id" attribute`);
|
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "id" attribute`);
|
||||||
@ -326,7 +332,7 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
visitAttribute(attribute: ml.Attribute, context: any) {}
|
visitAttribute(attribute: ml.Attribute, context: any) {}
|
||||||
|
|
||||||
private _addError(node: ml.Node, message: string): void {
|
private _addError(node: ml.Node, message: string): void {
|
||||||
this._errors.push(new I18nError(node.sourceSpan !, message));
|
this._errors.push(new I18nError(node.sourceSpan!, message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ export class Xliff2 extends Serializer {
|
|||||||
|
|
||||||
message.sources.forEach((source: i18n.MessageSpan) => {
|
message.sources.forEach((source: i18n.MessageSpan) => {
|
||||||
notes.children.push(new xml.CR(8), new xml.Tag('note', {category: 'location'}, [
|
notes.children.push(new xml.CR(8), new xml.Tag('note', {category: 'location'}, [
|
||||||
new xml.Text(
|
new xml.Text(`${source.filePath}:${source.startLine}${
|
||||||
`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)
|
source.endLine !== source.startLine ? ',' + source.endLine : ''}`)
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,17 +105,21 @@ export class Xliff2 extends Serializer {
|
|||||||
throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
|
throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {locale: locale !, i18nNodesByMsgId};
|
return {locale: locale!, i18nNodesByMsgId};
|
||||||
}
|
}
|
||||||
|
|
||||||
digest(message: i18n.Message): string { return decimalDigest(message); }
|
digest(message: i18n.Message): string {
|
||||||
|
return decimalDigest(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _WriteVisitor implements i18n.Visitor {
|
class _WriteVisitor implements i18n.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _nextPlaceholderId !: number;
|
private _nextPlaceholderId!: number;
|
||||||
|
|
||||||
visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; }
|
visitText(text: i18n.Text, context?: any): xml.Node[] {
|
||||||
|
return [new xml.Text(text.value)];
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
|
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
|
||||||
const nodes: xml.Node[] = [];
|
const nodes: xml.Node[] = [];
|
||||||
@ -192,11 +196,11 @@ class _WriteVisitor implements i18n.Visitor {
|
|||||||
// Extract messages as xml nodes from the xliff file
|
// Extract messages as xml nodes from the xliff file
|
||||||
class Xliff2Parser implements ml.Visitor {
|
class Xliff2Parser implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _unitMlString !: string | null;
|
private _unitMlString!: string|null;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _msgIdToHtml !: {[msgId: string]: string};
|
private _msgIdToHtml!: {[msgId: string]: string};
|
||||||
private _locale: string|null = null;
|
private _locale: string|null = null;
|
||||||
|
|
||||||
parse(xliff: string, url: string) {
|
parse(xliff: string, url: string) {
|
||||||
@ -242,9 +246,9 @@ class Xliff2Parser implements ml.Visitor {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case _TARGET_TAG:
|
case _TARGET_TAG:
|
||||||
const innerTextStart = element.startSourceSpan !.end.offset;
|
const innerTextStart = element.startSourceSpan!.end.offset;
|
||||||
const innerTextEnd = element.endSourceSpan !.start.offset;
|
const innerTextEnd = element.endSourceSpan!.start.offset;
|
||||||
const content = element.startSourceSpan !.start.file.content;
|
const content = element.startSourceSpan!.start.file.content;
|
||||||
const innerText = content.slice(innerTextStart, innerTextEnd);
|
const innerText = content.slice(innerTextStart, innerTextEnd);
|
||||||
this._unitMlString = innerText;
|
this._unitMlString = innerText;
|
||||||
break;
|
break;
|
||||||
@ -290,7 +294,7 @@ class Xliff2Parser implements ml.Visitor {
|
|||||||
// Convert ml nodes (xliff syntax) to i18n nodes
|
// Convert ml nodes (xliff syntax) to i18n nodes
|
||||||
class XmlToI18n implements ml.Visitor {
|
class XmlToI18n implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
|
|
||||||
convert(message: string, url: string) {
|
convert(message: string, url: string) {
|
||||||
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
||||||
@ -306,7 +310,9 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan); }
|
visitText(text: ml.Text, context: any) {
|
||||||
|
return new i18n.Text(text.value, text.sourceSpan);
|
||||||
|
}
|
||||||
|
|
||||||
visitElement(el: ml.Element, context: any): i18n.Node[]|null {
|
visitElement(el: ml.Element, context: any): i18n.Node[]|null {
|
||||||
switch (el.name) {
|
switch (el.name) {
|
||||||
|
@ -57,10 +57,10 @@ export class Xmb extends Serializer {
|
|||||||
|
|
||||||
let sourceTags: xml.Tag[] = [];
|
let sourceTags: xml.Tag[] = [];
|
||||||
message.sources.forEach((source: i18n.MessageSpan) => {
|
message.sources.forEach((source: i18n.MessageSpan) => {
|
||||||
sourceTags.push(new xml.Tag(_SOURCE_TAG, {}, [
|
sourceTags.push(new xml.Tag(
|
||||||
new xml.Text(
|
_SOURCE_TAG, {},
|
||||||
`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)
|
[new xml.Text(`${source.filePath}:${source.startLine}${
|
||||||
]));
|
source.endLine !== source.startLine ? ',' + source.endLine : ''}`)]));
|
||||||
});
|
});
|
||||||
|
|
||||||
rootNode.children.push(
|
rootNode.children.push(
|
||||||
@ -85,7 +85,9 @@ export class Xmb extends Serializer {
|
|||||||
throw new Error('Unsupported');
|
throw new Error('Unsupported');
|
||||||
}
|
}
|
||||||
|
|
||||||
digest(message: i18n.Message): string { return digest(message); }
|
digest(message: i18n.Message): string {
|
||||||
|
return digest(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
createNameMapper(message: i18n.Message): PlaceholderMapper {
|
createNameMapper(message: i18n.Message): PlaceholderMapper {
|
||||||
@ -94,7 +96,9 @@ export class Xmb extends Serializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _Visitor implements i18n.Visitor {
|
class _Visitor implements i18n.Visitor {
|
||||||
visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; }
|
visitText(text: i18n.Text, context?: any): xml.Node[] {
|
||||||
|
return [new xml.Text(text.value)];
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container, context: any): xml.Node[] {
|
visitContainer(container: i18n.Container, context: any): xml.Node[] {
|
||||||
const nodes: xml.Node[] = [];
|
const nodes: xml.Node[] = [];
|
||||||
|
@ -25,7 +25,9 @@ class _Visitor implements IVisitor {
|
|||||||
return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
|
return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: Text): string { return text.value; }
|
visitText(text: Text): string {
|
||||||
|
return text.value;
|
||||||
|
}
|
||||||
|
|
||||||
visitDeclaration(decl: Declaration): string {
|
visitDeclaration(decl: Declaration): string {
|
||||||
return `<?xml${this._serializeAttributes(decl.attrs)} ?>`;
|
return `<?xml${this._serializeAttributes(decl.attrs)} ?>`;
|
||||||
@ -47,7 +49,9 @@ export function serialize(nodes: Node[]): string {
|
|||||||
return nodes.map((node: Node): string => node.visit(_visitor)).join('');
|
return nodes.map((node: Node): string => node.visit(_visitor)).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Node { visit(visitor: IVisitor): any; }
|
export interface Node {
|
||||||
|
visit(visitor: IVisitor): any;
|
||||||
|
}
|
||||||
|
|
||||||
export class Declaration implements Node {
|
export class Declaration implements Node {
|
||||||
public attrs: {[k: string]: string} = {};
|
public attrs: {[k: string]: string} = {};
|
||||||
@ -58,13 +62,17 @@ export class Declaration implements Node {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(visitor: IVisitor): any { return visitor.visitDeclaration(this); }
|
visit(visitor: IVisitor): any {
|
||||||
|
return visitor.visitDeclaration(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Doctype implements Node {
|
export class Doctype implements Node {
|
||||||
constructor(public rootTag: string, public dtd: string) {}
|
constructor(public rootTag: string, public dtd: string) {}
|
||||||
|
|
||||||
visit(visitor: IVisitor): any { return visitor.visitDoctype(this); }
|
visit(visitor: IVisitor): any {
|
||||||
|
return visitor.visitDoctype(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tag implements Node {
|
export class Tag implements Node {
|
||||||
@ -78,18 +86,26 @@ export class Tag implements Node {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(visitor: IVisitor): any { return visitor.visitTag(this); }
|
visit(visitor: IVisitor): any {
|
||||||
|
return visitor.visitTag(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Text implements Node {
|
export class Text implements Node {
|
||||||
value: string;
|
value: string;
|
||||||
constructor(unescapedValue: string) { this.value = escapeXml(unescapedValue); }
|
constructor(unescapedValue: string) {
|
||||||
|
this.value = escapeXml(unescapedValue);
|
||||||
|
}
|
||||||
|
|
||||||
visit(visitor: IVisitor): any { return visitor.visitText(this); }
|
visit(visitor: IVisitor): any {
|
||||||
|
return visitor.visitText(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CR extends Text {
|
export class CR extends Text {
|
||||||
constructor(ws: number = 0) { super(`\n${new Array(ws + 1).join(' ')}`); }
|
constructor(ws: number = 0) {
|
||||||
|
super(`\n${new Array(ws + 1).join(' ')}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _ESCAPED_CHARS: [RegExp, string][] = [
|
const _ESCAPED_CHARS: [RegExp, string][] = [
|
||||||
|
@ -19,7 +19,9 @@ const _TRANSLATION_TAG = 'translation';
|
|||||||
const _PLACEHOLDER_TAG = 'ph';
|
const _PLACEHOLDER_TAG = 'ph';
|
||||||
|
|
||||||
export class Xtb extends Serializer {
|
export class Xtb extends Serializer {
|
||||||
write(messages: i18n.Message[], locale: string|null): string { throw new Error('Unsupported'); }
|
write(messages: i18n.Message[], locale: string|null): string {
|
||||||
|
throw new Error('Unsupported');
|
||||||
|
}
|
||||||
|
|
||||||
load(content: string, url: string):
|
load(content: string, url: string):
|
||||||
{locale: string, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}} {
|
{locale: string, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}} {
|
||||||
@ -49,10 +51,12 @@ export class Xtb extends Serializer {
|
|||||||
throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
|
throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {locale: locale !, i18nNodesByMsgId};
|
return {locale: locale!, i18nNodesByMsgId};
|
||||||
}
|
}
|
||||||
|
|
||||||
digest(message: i18n.Message): string { return digest(message); }
|
digest(message: i18n.Message): string {
|
||||||
|
return digest(message);
|
||||||
|
}
|
||||||
|
|
||||||
createNameMapper(message: i18n.Message): PlaceholderMapper {
|
createNameMapper(message: i18n.Message): PlaceholderMapper {
|
||||||
return new SimplePlaceholderMapper(message, toPublicName);
|
return new SimplePlaceholderMapper(message, toPublicName);
|
||||||
@ -68,18 +72,20 @@ function createLazyProperty(messages: any, id: string, valueFn: () => any) {
|
|||||||
Object.defineProperty(messages, id, {enumerable: true, value});
|
Object.defineProperty(messages, id, {enumerable: true, value});
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
set: _ => { throw new Error('Could not overwrite an XTB translation'); },
|
set: _ => {
|
||||||
|
throw new Error('Could not overwrite an XTB translation');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract messages as xml nodes from the xtb file
|
// Extract messages as xml nodes from the xtb file
|
||||||
class XtbParser implements ml.Visitor {
|
class XtbParser implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _bundleDepth !: number;
|
private _bundleDepth!: number;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _msgIdToHtml !: {[msgId: string]: string};
|
private _msgIdToHtml!: {[msgId: string]: string};
|
||||||
private _locale: string|null = null;
|
private _locale: string|null = null;
|
||||||
|
|
||||||
parse(xtb: string, url: string) {
|
parse(xtb: string, url: string) {
|
||||||
@ -124,10 +130,10 @@ class XtbParser implements ml.Visitor {
|
|||||||
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
||||||
this._addError(element, `Duplicated translations for msg ${id}`);
|
this._addError(element, `Duplicated translations for msg ${id}`);
|
||||||
} else {
|
} else {
|
||||||
const innerTextStart = element.startSourceSpan !.end.offset;
|
const innerTextStart = element.startSourceSpan!.end.offset;
|
||||||
const innerTextEnd = element.endSourceSpan !.start.offset;
|
const innerTextEnd = element.endSourceSpan!.start.offset;
|
||||||
const content = element.startSourceSpan !.start.file.content;
|
const content = element.startSourceSpan!.start.file.content;
|
||||||
const innerText = content.slice(innerTextStart !, innerTextEnd !);
|
const innerText = content.slice(innerTextStart!, innerTextEnd!);
|
||||||
this._msgIdToHtml[id] = innerText;
|
this._msgIdToHtml[id] = innerText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,14 +155,14 @@ class XtbParser implements ml.Visitor {
|
|||||||
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
|
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
|
||||||
|
|
||||||
private _addError(node: ml.Node, message: string): void {
|
private _addError(node: ml.Node, message: string): void {
|
||||||
this._errors.push(new I18nError(node.sourceSpan !, message));
|
this._errors.push(new I18nError(node.sourceSpan!, message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert ml nodes (xtb syntax) to i18n nodes
|
// Convert ml nodes (xtb syntax) to i18n nodes
|
||||||
class XmlToI18n implements ml.Visitor {
|
class XmlToI18n implements ml.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _errors !: I18nError[];
|
private _errors!: I18nError[];
|
||||||
|
|
||||||
convert(message: string, url: string) {
|
convert(message: string, url: string) {
|
||||||
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true});
|
||||||
@ -172,7 +178,9 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan !); }
|
visitText(text: ml.Text, context: any) {
|
||||||
|
return new i18n.Text(text.value, text.sourceSpan!);
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansion(icu: ml.Expansion, context: any) {
|
visitExpansion(icu: ml.Expansion, context: any) {
|
||||||
const caseMap: {[value: string]: i18n.Node} = {};
|
const caseMap: {[value: string]: i18n.Node} = {};
|
||||||
@ -195,7 +203,7 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
if (el.name === _PLACEHOLDER_TAG) {
|
if (el.name === _PLACEHOLDER_TAG) {
|
||||||
const nameAttr = el.attrs.find((attr) => attr.name === 'name');
|
const nameAttr = el.attrs.find((attr) => attr.name === 'name');
|
||||||
if (nameAttr) {
|
if (nameAttr) {
|
||||||
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan !);
|
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`);
|
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`);
|
||||||
@ -210,6 +218,6 @@ class XmlToI18n implements ml.Visitor {
|
|||||||
visitAttribute(attribute: ml.Attribute, context: any) {}
|
visitAttribute(attribute: ml.Attribute, context: any) {}
|
||||||
|
|
||||||
private _addError(node: ml.Node, message: string): void {
|
private _addError(node: ml.Node, message: string): void {
|
||||||
this._errors.push(new I18nError(node.sourceSpan !, message));
|
this._errors.push(new I18nError(node.sourceSpan!, message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export class TranslationBundle {
|
|||||||
missingTranslationStrategy: MissingTranslationStrategy = MissingTranslationStrategy.Warning,
|
missingTranslationStrategy: MissingTranslationStrategy = MissingTranslationStrategy.Warning,
|
||||||
console?: Console) {
|
console?: Console) {
|
||||||
this._i18nToHtml = new I18nToHtmlVisitor(
|
this._i18nToHtml = new I18nToHtmlVisitor(
|
||||||
_i18nNodesByMsgId, locale, digest, mapperFactory !, missingTranslationStrategy, console);
|
_i18nNodesByMsgId, locale, digest, mapperFactory!, missingTranslationStrategy, console);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a `TranslationBundle` by parsing the given `content` with the `serializer`.
|
// Creates a `TranslationBundle` by parsing the given `content` with the `serializer`.
|
||||||
@ -40,7 +40,7 @@ export class TranslationBundle {
|
|||||||
console?: Console): TranslationBundle {
|
console?: Console): TranslationBundle {
|
||||||
const {locale, i18nNodesByMsgId} = serializer.load(content, url);
|
const {locale, i18nNodesByMsgId} = serializer.load(content, url);
|
||||||
const digestFn = (m: i18n.Message) => serializer.digest(m);
|
const digestFn = (m: i18n.Message) => serializer.digest(m);
|
||||||
const mapperFactory = (m: i18n.Message) => serializer.createNameMapper(m) !;
|
const mapperFactory = (m: i18n.Message) => serializer.createNameMapper(m)!;
|
||||||
return new TranslationBundle(
|
return new TranslationBundle(
|
||||||
i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
|
i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
|
||||||
}
|
}
|
||||||
@ -56,16 +56,18 @@ export class TranslationBundle {
|
|||||||
return html.nodes;
|
return html.nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
has(srcMsg: i18n.Message): boolean { return this.digest(srcMsg) in this._i18nNodesByMsgId; }
|
has(srcMsg: i18n.Message): boolean {
|
||||||
|
return this.digest(srcMsg) in this._i18nNodesByMsgId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class I18nToHtmlVisitor implements i18n.Visitor {
|
class I18nToHtmlVisitor implements i18n.Visitor {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _srcMsg !: i18n.Message;
|
private _srcMsg!: i18n.Message;
|
||||||
private _contextStack: {msg: i18n.Message, mapper: (name: string) => string}[] = [];
|
private _contextStack: {msg: i18n.Message, mapper: (name: string) => string}[] = [];
|
||||||
private _errors: I18nError[] = [];
|
private _errors: I18nError[] = [];
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _mapper !: (name: string) => string;
|
private _mapper!: (name: string) => string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {}, private _locale: string|null,
|
private _i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {}, private _locale: string|null,
|
||||||
@ -166,7 +168,7 @@ class I18nToHtmlVisitor implements i18n.Visitor {
|
|||||||
// When there is a translation use its nodes as the source
|
// When there is a translation use its nodes as the source
|
||||||
// And create a mapper to convert serialized placeholder names to internal names
|
// And create a mapper to convert serialized placeholder names to internal names
|
||||||
nodes = this._i18nNodesByMsgId[id];
|
nodes = this._i18nNodesByMsgId[id];
|
||||||
this._mapper = (name: string) => mapper ? mapper.toInternalName(name) ! : name;
|
this._mapper = (name: string) => mapper ? mapper.toInternalName(name)! : name;
|
||||||
} else {
|
} else {
|
||||||
// When no translation has been found
|
// When no translation has been found
|
||||||
// - report an error / a warning / nothing,
|
// - report an error / a warning / nothing,
|
||||||
@ -185,7 +187,7 @@ class I18nToHtmlVisitor implements i18n.Visitor {
|
|||||||
this._mapper = (name: string) => name;
|
this._mapper = (name: string) => name;
|
||||||
}
|
}
|
||||||
const text = nodes.map(node => node.visit(this)).join('');
|
const text = nodes.map(node => node.visit(this)).join('');
|
||||||
const context = this._contextStack.pop() !;
|
const context = this._contextStack.pop()!;
|
||||||
this._srcMsg = context.msg;
|
this._srcMsg = context.msg;
|
||||||
this._mapper = context.mapper;
|
this._mapper = context.mapper;
|
||||||
return text;
|
return text;
|
||||||
|
@ -121,7 +121,7 @@ export class InjectableCompiler {
|
|||||||
|
|
||||||
compile(injectable: CompileInjectableMetadata, ctx: OutputContext): void {
|
compile(injectable: CompileInjectableMetadata, ctx: OutputContext): void {
|
||||||
if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
|
if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
|
||||||
const className = identifierName(injectable.type) !;
|
const className = identifierName(injectable.type)!;
|
||||||
const clazz = new o.ClassStmt(
|
const clazz = new o.ClassStmt(
|
||||||
className, null,
|
className, null,
|
||||||
[
|
[
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
import {Identifiers} from './identifiers';
|
import {Identifiers} from './identifiers';
|
||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
import {R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, R3FactoryTarget, compileFactoryFunction} from './render3/r3_factory';
|
import {compileFactoryFunction, R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, R3FactoryTarget} from './render3/r3_factory';
|
||||||
import {R3Reference, mapToMapExpression, typeWithParameters} from './render3/util';
|
import {mapToMapExpression, R3Reference, typeWithParameters} from './render3/util';
|
||||||
|
|
||||||
export interface InjectableDef {
|
export interface InjectableDef {
|
||||||
expression: o.Expression;
|
expression: o.Expression;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileTypeSummary, ProviderMeta, ProxyClass, identifierName, ngModuleJitUrl, sharedStylesheetJitUrl, templateJitUrl, templateSourceUrl} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileTypeSummary, identifierName, ngModuleJitUrl, ProviderMeta, ProxyClass, sharedStylesheetJitUrl, templateJitUrl, templateSourceUrl} from '../compile_metadata';
|
||||||
import {CompileReflector} from '../compile_reflector';
|
import {CompileReflector} from '../compile_reflector';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {ConstantPool} from '../constant_pool';
|
import {ConstantPool} from '../constant_pool';
|
||||||
@ -20,7 +20,7 @@ import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
|||||||
import {SummaryResolver} from '../summary_resolver';
|
import {SummaryResolver} from '../summary_resolver';
|
||||||
import {TemplateAst} from '../template_parser/template_ast';
|
import {TemplateAst} from '../template_parser/template_ast';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from '../template_parser/template_parser';
|
||||||
import {Console, OutputContext, SyncAsync, stringify} from '../util';
|
import {Console, OutputContext, stringify, SyncAsync} from '../util';
|
||||||
import {ViewCompiler} from '../view_compiler/view_compiler';
|
import {ViewCompiler} from '../view_compiler/view_compiler';
|
||||||
|
|
||||||
export interface ModuleWithComponentFactories {
|
export interface ModuleWithComponentFactories {
|
||||||
@ -97,7 +97,9 @@ export class JitCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); }
|
hasAotSummary(ref: Type) {
|
||||||
|
return !!this._summaryResolver.resolveSummary(ref);
|
||||||
|
}
|
||||||
|
|
||||||
private _filterJitIdentifiers(ids: CompileIdentifierMetadata[]): any[] {
|
private _filterJitIdentifiers(ids: CompileIdentifierMetadata[]): any[] {
|
||||||
return ids.map(mod => mod.reference).filter((ref) => !this.hasAotSummary(ref));
|
return ids.map(mod => mod.reference).filter((ref) => !this.hasAotSummary(ref));
|
||||||
@ -124,12 +126,12 @@ export class JitCompiler {
|
|||||||
|
|
||||||
private _loadModules(mainModule: any, isSync: boolean): SyncAsync<any> {
|
private _loadModules(mainModule: any, isSync: boolean): SyncAsync<any> {
|
||||||
const loading: Promise<any>[] = [];
|
const loading: Promise<any>[] = [];
|
||||||
const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule) !;
|
const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule)!;
|
||||||
// Note: for runtime compilation, we want to transitively compile all modules,
|
// Note: for runtime compilation, we want to transitively compile all modules,
|
||||||
// so we also need to load the declared directives / pipes for all nested modules.
|
// so we also need to load the declared directives / pipes for all nested modules.
|
||||||
this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach((nestedNgModule) => {
|
this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach((nestedNgModule) => {
|
||||||
// getNgModuleMetadata only returns null if the value passed in is not an NgModule
|
// getNgModuleMetadata only returns null if the value passed in is not an NgModule
|
||||||
const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule) !;
|
const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule)!;
|
||||||
this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach((ref) => {
|
this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach((ref) => {
|
||||||
const promise =
|
const promise =
|
||||||
this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync);
|
this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync);
|
||||||
@ -144,9 +146,9 @@ export class JitCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _compileModule(moduleType: Type): object {
|
private _compileModule(moduleType: Type): object {
|
||||||
let ngModuleFactory = this._compiledNgModuleCache.get(moduleType) !;
|
let ngModuleFactory = this._compiledNgModuleCache.get(moduleType)!;
|
||||||
if (!ngModuleFactory) {
|
if (!ngModuleFactory) {
|
||||||
const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType) !;
|
const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType)!;
|
||||||
// Always provide a bound Compiler
|
// Always provide a bound Compiler
|
||||||
const extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference);
|
const extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference);
|
||||||
const outputCtx = createOutputContext();
|
const outputCtx = createOutputContext();
|
||||||
@ -162,13 +164,13 @@ export class JitCompiler {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
_compileComponents(mainModule: Type, allComponentFactories: object[]|null) {
|
_compileComponents(mainModule: Type, allComponentFactories: object[]|null) {
|
||||||
const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule) !;
|
const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule)!;
|
||||||
const moduleByJitDirective = new Map<any, CompileNgModuleMetadata>();
|
const moduleByJitDirective = new Map<any, CompileNgModuleMetadata>();
|
||||||
const templates = new Set<CompiledTemplate>();
|
const templates = new Set<CompiledTemplate>();
|
||||||
|
|
||||||
const transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules);
|
const transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules);
|
||||||
transJitModules.forEach((localMod) => {
|
transJitModules.forEach((localMod) => {
|
||||||
const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !;
|
const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod)!;
|
||||||
this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
|
this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
|
||||||
moduleByJitDirective.set(dirRef, localModuleMeta);
|
moduleByJitDirective.set(dirRef, localModuleMeta);
|
||||||
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
|
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
|
||||||
@ -184,12 +186,12 @@ export class JitCompiler {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
transJitModules.forEach((localMod) => {
|
transJitModules.forEach((localMod) => {
|
||||||
const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !;
|
const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod)!;
|
||||||
this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
|
this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
|
||||||
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
|
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
|
||||||
if (dirMeta.isComponent) {
|
if (dirMeta.isComponent) {
|
||||||
dirMeta.entryComponents.forEach((entryComponentType) => {
|
dirMeta.entryComponents.forEach((entryComponentType) => {
|
||||||
const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !;
|
const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType)!;
|
||||||
templates.add(
|
templates.add(
|
||||||
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
||||||
});
|
});
|
||||||
@ -197,7 +199,7 @@ export class JitCompiler {
|
|||||||
});
|
});
|
||||||
localModuleMeta.entryComponents.forEach((entryComponentType) => {
|
localModuleMeta.entryComponents.forEach((entryComponentType) => {
|
||||||
if (!this.hasAotSummary(entryComponentType.componentType)) {
|
if (!this.hasAotSummary(entryComponentType.componentType)) {
|
||||||
const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !;
|
const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType)!;
|
||||||
templates.add(
|
templates.add(
|
||||||
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
||||||
}
|
}
|
||||||
@ -227,8 +229,9 @@ export class JitCompiler {
|
|||||||
private _createCompiledHostTemplate(compType: Type, ngModule: CompileNgModuleMetadata):
|
private _createCompiledHostTemplate(compType: Type, ngModule: CompileNgModuleMetadata):
|
||||||
CompiledTemplate {
|
CompiledTemplate {
|
||||||
if (!ngModule) {
|
if (!ngModule) {
|
||||||
throw new Error(
|
throw new Error(`Component ${
|
||||||
`Component ${stringify(compType)} is not part of any NgModule or the module has not been imported into your module.`);
|
stringify(
|
||||||
|
compType)} is not part of any NgModule or the module has not been imported into your module.`);
|
||||||
}
|
}
|
||||||
let compiledTemplate = this._compiledHostTemplateCache.get(compType);
|
let compiledTemplate = this._compiledHostTemplateCache.get(compType);
|
||||||
if (!compiledTemplate) {
|
if (!compiledTemplate) {
|
||||||
@ -267,7 +270,7 @@ export class JitCompiler {
|
|||||||
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
||||||
const compiledStylesheet =
|
const compiledStylesheet =
|
||||||
this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
|
this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
|
||||||
externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl !, compiledStylesheet);
|
externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl!, compiledStylesheet);
|
||||||
});
|
});
|
||||||
this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
|
this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
|
||||||
const pipes = template.ngModule.transitiveModule.pipes.map(
|
const pipes = template.ngModule.transitiveModule.pipes.map(
|
||||||
@ -295,14 +298,14 @@ export class JitCompiler {
|
|||||||
const pipes = ngModule.transitiveModule.pipes.map(
|
const pipes = ngModule.transitiveModule.pipes.map(
|
||||||
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
||||||
return this._templateParser.parse(
|
return this._templateParser.parse(
|
||||||
compMeta, compMeta.template !.htmlAst !, directives, pipes, ngModule.schemas,
|
compMeta, compMeta.template !.htmlAst!, directives, pipes, ngModule.schemas,
|
||||||
templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces);
|
templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resolveStylesCompileResult(
|
private _resolveStylesCompileResult(
|
||||||
result: CompiledStylesheet, externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>) {
|
result: CompiledStylesheet, externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>) {
|
||||||
result.dependencies.forEach((dep, i) => {
|
result.dependencies.forEach((dep, i) => {
|
||||||
const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl) !;
|
const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl)!;
|
||||||
const nestedStylesArr = this._resolveAndEvalStylesCompileResult(
|
const nestedStylesArr = this._resolveAndEvalStylesCompileResult(
|
||||||
nestedCompileResult, externalStylesheetsByModuleUrl);
|
nestedCompileResult, externalStylesheetsByModuleUrl);
|
||||||
dep.setValue(nestedStylesArr);
|
dep.setValue(nestedStylesArr);
|
||||||
@ -329,7 +332,7 @@ export class JitCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CompiledTemplate {
|
class CompiledTemplate {
|
||||||
private _viewClass: Function = null !;
|
private _viewClass: Function = null!;
|
||||||
isCompiled = false;
|
isCompiled = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -16,13 +16,13 @@ import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/int
|
|||||||
import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast';
|
import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast';
|
||||||
import {JitEvaluator} from './output/output_jit';
|
import {JitEvaluator} from './output/output_jit';
|
||||||
import {ParseError, ParseSourceSpan, r3JitTypeSourceSpan} from './parse_util';
|
import {ParseError, ParseSourceSpan, r3JitTypeSourceSpan} from './parse_util';
|
||||||
import {R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType, compileFactoryFunction} from './render3/r3_factory';
|
import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType} from './render3/r3_factory';
|
||||||
import {R3JitReflector} from './render3/r3_jit';
|
import {R3JitReflector} from './render3/r3_jit';
|
||||||
import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule} from './render3/r3_module_compiler';
|
import {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler';
|
||||||
import {R3PipeMetadata, compilePipeFromMetadata} from './render3/r3_pipe_compiler';
|
import {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler';
|
||||||
import {R3Reference} from './render3/util';
|
import {R3Reference} from './render3/util';
|
||||||
import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api';
|
import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api';
|
||||||
import {ParsedHostBindings, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
|
import {compileComponentFromMetadata, compileDirectiveFromMetadata, ParsedHostBindings, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
|
||||||
import {makeBindingParser, parseTemplate} from './render3/view/template';
|
import {makeBindingParser, parseTemplate} from './render3/view/template';
|
||||||
import {ResourceLoader} from './resource_loader';
|
import {ResourceLoader} from './resource_loader';
|
||||||
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
||||||
@ -277,7 +277,7 @@ function wrapExpression(obj: any, property: string): WrappedNodeExpr<any>|undefi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeProvidedIn(providedIn: Type | string | null | undefined): Expression {
|
function computeProvidedIn(providedIn: Type|string|null|undefined): Expression {
|
||||||
if (providedIn == null || typeof providedIn === 'string') {
|
if (providedIn == null || typeof providedIn === 'string') {
|
||||||
return new LiteralExpr(providedIn);
|
return new LiteralExpr(providedIn);
|
||||||
} else {
|
} else {
|
||||||
@ -305,8 +305,8 @@ function convertR3DependencyMetadata(facade: R3DependencyMetadataFacade): R3Depe
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[] | null | undefined):
|
function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[]|null|
|
||||||
R3DependencyMetadata[]|null {
|
undefined): R3DependencyMetadata[]|null {
|
||||||
return facades == null ? null : facades.map(convertR3DependencyMetadata);
|
return facades == null ? null : facades.map(convertR3DependencyMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,13 +356,11 @@ function isOutput(value: any): value is Output {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseInputOutputs(values: string[]): StringMap {
|
function parseInputOutputs(values: string[]): StringMap {
|
||||||
return values.reduce(
|
return values.reduce((map, value) => {
|
||||||
(map, value) => {
|
|
||||||
const [field, property] = value.split(',').map(piece => piece.trim());
|
const [field, property] = value.split(',').map(piece => piece.trim());
|
||||||
map[field] = property || field;
|
map[field] = property || field;
|
||||||
return map;
|
return map;
|
||||||
},
|
}, {} as StringMap);
|
||||||
{} as StringMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function publishFacade(global: any) {
|
export function publishFacade(global: any) {
|
||||||
|
@ -12,7 +12,7 @@ import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
|||||||
import * as cpl from './compile_metadata';
|
import * as cpl from './compile_metadata';
|
||||||
import {CompileReflector} from './compile_reflector';
|
import {CompileReflector} from './compile_reflector';
|
||||||
import {CompilerConfig} from './config';
|
import {CompilerConfig} from './config';
|
||||||
import {ChangeDetectionStrategy, Component, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createNgModule, createOptional, createSelf, createSkipSelf} from './core';
|
import {ChangeDetectionStrategy, Component, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createNgModule, createOptional, createSelf, createSkipSelf, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation} from './core';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveResolver, findLast} from './directive_resolver';
|
import {DirectiveResolver, findLast} from './directive_resolver';
|
||||||
import {Identifiers} from './identifiers';
|
import {Identifiers} from './identifiers';
|
||||||
@ -23,7 +23,7 @@ import {PipeResolver} from './pipe_resolver';
|
|||||||
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
||||||
import {CssSelector} from './selector';
|
import {CssSelector} from './selector';
|
||||||
import {SummaryResolver} from './summary_resolver';
|
import {SummaryResolver} from './summary_resolver';
|
||||||
import {Console, SyncAsync, ValueTransformer, isPromise, noUndefined, resolveForwardRef, stringify, syntaxError, visitValue} from './util';
|
import {Console, isPromise, noUndefined, resolveForwardRef, stringify, SyncAsync, syntaxError, ValueTransformer, visitValue} from './util';
|
||||||
|
|
||||||
export type ErrorCollector = (error: any, type?: any) => void;
|
export type ErrorCollector = (error: any, type?: any) => void;
|
||||||
|
|
||||||
@ -55,7 +55,9 @@ export class CompileMetadataResolver {
|
|||||||
private _staticSymbolCache: StaticSymbolCache, private _reflector: CompileReflector,
|
private _staticSymbolCache: StaticSymbolCache, private _reflector: CompileReflector,
|
||||||
private _errorCollector?: ErrorCollector) {}
|
private _errorCollector?: ErrorCollector) {}
|
||||||
|
|
||||||
getReflector(): CompileReflector { return this._reflector; }
|
getReflector(): CompileReflector {
|
||||||
|
return this._reflector;
|
||||||
|
}
|
||||||
|
|
||||||
clearCacheFor(type: Type) {
|
clearCacheFor(type: Type) {
|
||||||
const dirMeta = this._directiveCache.get(type);
|
const dirMeta = this._directiveCache.get(type);
|
||||||
@ -176,7 +178,7 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
// Note: ! is ok here as this method should only be called with normalized directive
|
// Note: ! is ok here as this method should only be called with normalized directive
|
||||||
// metadata, which always fills in the selector.
|
// metadata, which always fills in the selector.
|
||||||
const template = CssSelector.parse(compMeta.selector !)[0].getMatchingElementTemplate();
|
const template = CssSelector.parse(compMeta.selector!)[0].getMatchingElementTemplate();
|
||||||
const templateUrl = '';
|
const templateUrl = '';
|
||||||
const htmlAst = this._htmlParser.parse(template, templateUrl);
|
const htmlAst = this._htmlParser.parse(template, templateUrl);
|
||||||
return cpl.CompileDirectiveMetadata.create({
|
return cpl.CompileDirectiveMetadata.create({
|
||||||
@ -209,8 +211,8 @@ export class CompileMetadataResolver {
|
|||||||
guards: {},
|
guards: {},
|
||||||
viewQueries: [],
|
viewQueries: [],
|
||||||
componentViewType: hostViewType,
|
componentViewType: hostViewType,
|
||||||
rendererType:
|
rendererType: {id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}} as
|
||||||
{id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}} as object,
|
object,
|
||||||
entryComponents: [],
|
entryComponents: [],
|
||||||
componentFactory: null
|
componentFactory: null
|
||||||
});
|
});
|
||||||
@ -221,9 +223,9 @@ export class CompileMetadataResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
directiveType = resolveForwardRef(directiveType);
|
directiveType = resolveForwardRef(directiveType);
|
||||||
const {annotation, metadata} = this.getNonNormalizedDirectiveMetadata(directiveType) !;
|
const {annotation, metadata} = this.getNonNormalizedDirectiveMetadata(directiveType)!;
|
||||||
|
|
||||||
const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata | null) => {
|
const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata|null) => {
|
||||||
const normalizedDirMeta = new cpl.CompileDirectiveMetadata({
|
const normalizedDirMeta = new cpl.CompileDirectiveMetadata({
|
||||||
isHost: false,
|
isHost: false,
|
||||||
type: metadata.type,
|
type: metadata.type,
|
||||||
@ -248,7 +250,7 @@ export class CompileMetadataResolver {
|
|||||||
template: templateMetadata
|
template: templateMetadata
|
||||||
});
|
});
|
||||||
if (templateMetadata) {
|
if (templateMetadata) {
|
||||||
this.initComponentFactory(metadata.componentFactory !, templateMetadata.ngContentSelectors);
|
this.initComponentFactory(metadata.componentFactory!, templateMetadata.ngContentSelectors);
|
||||||
}
|
}
|
||||||
this._directiveCache.set(directiveType, normalizedDirMeta);
|
this._directiveCache.set(directiveType, normalizedDirMeta);
|
||||||
this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
|
this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
|
||||||
@ -296,7 +298,7 @@ export class CompileMetadataResolver {
|
|||||||
if (!dirMeta) {
|
if (!dirMeta) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let nonNormalizedTemplateMetadata: cpl.CompileTemplateMetadata = undefined !;
|
let nonNormalizedTemplateMetadata: cpl.CompileTemplateMetadata = undefined!;
|
||||||
|
|
||||||
if (createComponent.isTypeOf(dirMeta)) {
|
if (createComponent.isTypeOf(dirMeta)) {
|
||||||
// component
|
// component
|
||||||
@ -323,7 +325,7 @@ export class CompileMetadataResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let changeDetectionStrategy: ChangeDetectionStrategy = null !;
|
let changeDetectionStrategy: ChangeDetectionStrategy = null!;
|
||||||
let viewProviders: cpl.CompileProviderMetadata[] = [];
|
let viewProviders: cpl.CompileProviderMetadata[] = [];
|
||||||
let entryComponentMetadata: cpl.CompileEntryComponentMetadata[] = [];
|
let entryComponentMetadata: cpl.CompileEntryComponentMetadata[] = [];
|
||||||
let selector = dirMeta.selector;
|
let selector = dirMeta.selector;
|
||||||
@ -331,7 +333,7 @@ export class CompileMetadataResolver {
|
|||||||
if (createComponent.isTypeOf(dirMeta)) {
|
if (createComponent.isTypeOf(dirMeta)) {
|
||||||
// Component
|
// Component
|
||||||
const compMeta = dirMeta as Component;
|
const compMeta = dirMeta as Component;
|
||||||
changeDetectionStrategy = compMeta.changeDetection !;
|
changeDetectionStrategy = compMeta.changeDetection!;
|
||||||
if (compMeta.viewProviders) {
|
if (compMeta.viewProviders) {
|
||||||
viewProviders = this._getProvidersMetadata(
|
viewProviders = this._getProvidersMetadata(
|
||||||
compMeta.viewProviders, entryComponentMetadata,
|
compMeta.viewProviders, entryComponentMetadata,
|
||||||
@ -339,7 +341,7 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
if (compMeta.entryComponents) {
|
if (compMeta.entryComponents) {
|
||||||
entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
|
entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
|
||||||
.map((type) => this._getEntryComponentMetadata(type) !)
|
.map((type) => this._getEntryComponentMetadata(type)!)
|
||||||
.concat(entryComponentMetadata);
|
.concat(entryComponentMetadata);
|
||||||
}
|
}
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
@ -348,7 +350,7 @@ export class CompileMetadataResolver {
|
|||||||
} else {
|
} else {
|
||||||
// Directive
|
// Directive
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
selector = null !;
|
selector = null!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,11 +403,12 @@ export class CompileMetadataResolver {
|
|||||||
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
|
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
|
||||||
*/
|
*/
|
||||||
getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
|
getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
|
||||||
const dirMeta = this._directiveCache.get(directiveType) !;
|
const dirMeta = this._directiveCache.get(directiveType)!;
|
||||||
if (!dirMeta) {
|
if (!dirMeta) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`),
|
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${
|
||||||
|
stringifyType(directiveType)}.`),
|
||||||
directiveType);
|
directiveType);
|
||||||
}
|
}
|
||||||
return dirMeta;
|
return dirMeta;
|
||||||
@ -530,7 +533,7 @@ export class CompileMetadataResolver {
|
|||||||
|
|
||||||
if (meta.imports) {
|
if (meta.imports) {
|
||||||
flattenAndDedupeArray(meta.imports).forEach((importedType) => {
|
flattenAndDedupeArray(meta.imports).forEach((importedType) => {
|
||||||
let importedModuleType: Type = undefined !;
|
let importedModuleType: Type = undefined!;
|
||||||
if (isValidType(importedType)) {
|
if (isValidType(importedType)) {
|
||||||
importedModuleType = importedType;
|
importedModuleType = importedType;
|
||||||
} else if (importedType && importedType.ngModule) {
|
} else if (importedType && importedType.ngModule) {
|
||||||
@ -549,8 +552,9 @@ export class CompileMetadataResolver {
|
|||||||
if (!alreadyCollecting) alreadyCollecting = new Set();
|
if (!alreadyCollecting) alreadyCollecting = new Set();
|
||||||
if (alreadyCollecting.has(importedModuleType)) {
|
if (alreadyCollecting.has(importedModuleType)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`${this._getTypeDescriptor(importedModuleType)} '${
|
||||||
`${this._getTypeDescriptor(importedModuleType)} '${stringifyType(importedType)}' is imported recursively by the module '${stringifyType(moduleType)}'.`),
|
stringifyType(importedType)}' is imported recursively by the module '${
|
||||||
|
stringifyType(moduleType)}'.`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -560,8 +564,9 @@ export class CompileMetadataResolver {
|
|||||||
alreadyCollecting.delete(importedModuleType);
|
alreadyCollecting.delete(importedModuleType);
|
||||||
if (!importedModuleSummary) {
|
if (!importedModuleSummary) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Unexpected ${this._getTypeDescriptor(importedType)} '${
|
||||||
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'. Please add a @NgModule annotation.`),
|
stringifyType(importedType)}' imported by the module '${
|
||||||
|
stringifyType(moduleType)}'. Please add a @NgModule annotation.`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -569,7 +574,8 @@ export class CompileMetadataResolver {
|
|||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`),
|
`Unexpected value '${stringifyType(importedType)}' imported by the module '${
|
||||||
|
stringifyType(moduleType)}'`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -581,15 +587,17 @@ export class CompileMetadataResolver {
|
|||||||
if (!isValidType(exportedType)) {
|
if (!isValidType(exportedType)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`),
|
`Unexpected value '${stringifyType(exportedType)}' exported by the module '${
|
||||||
|
stringifyType(moduleType)}'`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!alreadyCollecting) alreadyCollecting = new Set();
|
if (!alreadyCollecting) alreadyCollecting = new Set();
|
||||||
if (alreadyCollecting.has(exportedType)) {
|
if (alreadyCollecting.has(exportedType)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`${this._getTypeDescriptor(exportedType)} '${
|
||||||
`${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' is exported recursively by the module '${stringifyType(moduleType)}'`),
|
stringify(exportedType)}' is exported recursively by the module '${
|
||||||
|
stringifyType(moduleType)}'`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -612,7 +620,8 @@ export class CompileMetadataResolver {
|
|||||||
if (!isValidType(declaredType)) {
|
if (!isValidType(declaredType)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`),
|
`Unexpected value '${stringifyType(declaredType)}' declared by the module '${
|
||||||
|
stringifyType(moduleType)}'`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -634,8 +643,10 @@ export class CompileMetadataResolver {
|
|||||||
this._addTypeToModule(declaredType, moduleType);
|
this._addTypeToModule(declaredType, moduleType);
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Unexpected ${this._getTypeDescriptor(declaredType)} '${
|
||||||
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`),
|
stringifyType(declaredType)}' declared by the module '${
|
||||||
|
stringifyType(
|
||||||
|
moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -653,8 +664,9 @@ export class CompileMetadataResolver {
|
|||||||
transitiveModule.addExportedPipe(exportedId);
|
transitiveModule.addExportedPipe(exportedId);
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${
|
||||||
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`),
|
stringifyType(exportedId.reference)} from ${
|
||||||
|
stringifyType(moduleType)} as it was neither declared nor imported!`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -670,15 +682,16 @@ export class CompileMetadataResolver {
|
|||||||
|
|
||||||
if (meta.entryComponents) {
|
if (meta.entryComponents) {
|
||||||
entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
|
entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
|
||||||
.map(type => this._getEntryComponentMetadata(type) !));
|
.map(type => this._getEntryComponentMetadata(type)!));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.bootstrap) {
|
if (meta.bootstrap) {
|
||||||
flattenAndDedupeArray(meta.bootstrap).forEach(type => {
|
flattenAndDedupeArray(meta.bootstrap).forEach(type => {
|
||||||
if (!isValidType(type)) {
|
if (!isValidType(type)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Unexpected value '${
|
||||||
`Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`),
|
stringifyType(type)}' used in the bootstrap property of module '${
|
||||||
|
stringifyType(moduleType)}'`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -687,7 +700,7 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entryComponents.push(
|
entryComponents.push(
|
||||||
...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference) !));
|
...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)!));
|
||||||
|
|
||||||
if (meta.schemas) {
|
if (meta.schemas) {
|
||||||
schemas.push(...flattenAndDedupeArray(meta.schemas));
|
schemas.push(...flattenAndDedupeArray(meta.schemas));
|
||||||
@ -710,7 +723,7 @@ export class CompileMetadataResolver {
|
|||||||
});
|
});
|
||||||
|
|
||||||
entryComponents.forEach((id) => transitiveModule.addEntryComponent(id));
|
entryComponents.forEach((id) => transitiveModule.addEntryComponent(id));
|
||||||
providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta !.type));
|
providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta!.type));
|
||||||
transitiveModule.addModule(compileMeta.type);
|
transitiveModule.addModule(compileMeta.type);
|
||||||
this._ngModuleCache.set(moduleType, compileMeta);
|
this._ngModuleCache.set(moduleType, compileMeta);
|
||||||
return compileMeta;
|
return compileMeta;
|
||||||
@ -753,9 +766,13 @@ export class CompileMetadataResolver {
|
|||||||
if (oldModule && oldModule !== moduleType) {
|
if (oldModule && oldModule !== moduleType) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
|
`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${
|
||||||
`Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
|
stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
|
||||||
`You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`),
|
`Please consider moving ${stringifyType(type)} to a higher module that imports ${
|
||||||
|
stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
|
||||||
|
`You can also create a new NgModule that exports and includes ${
|
||||||
|
stringifyType(type)} then import that NgModule in ${
|
||||||
|
stringifyType(oldModule)} and ${stringifyType(moduleType)}.`),
|
||||||
moduleType);
|
moduleType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -870,7 +887,8 @@ export class CompileMetadataResolver {
|
|||||||
if (!pipeMeta) {
|
if (!pipeMeta) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(
|
||||||
`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`),
|
`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${
|
||||||
|
stringifyType(pipeType)}.`),
|
||||||
pipeType);
|
pipeType);
|
||||||
}
|
}
|
||||||
return pipeMeta || null;
|
return pipeMeta || null;
|
||||||
@ -898,7 +916,7 @@ export class CompileMetadataResolver {
|
|||||||
|
|
||||||
private _loadPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
private _loadPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
||||||
pipeType = resolveForwardRef(pipeType);
|
pipeType = resolveForwardRef(pipeType);
|
||||||
const pipeAnnotation = this._pipeResolver.resolve(pipeType) !;
|
const pipeAnnotation = this._pipeResolver.resolve(pipeType)!;
|
||||||
|
|
||||||
const pipeMeta = new cpl.CompilePipeMetadata({
|
const pipeMeta = new cpl.CompilePipeMetadata({
|
||||||
type: this._getTypeMetadata(pipeType),
|
type: this._getTypeMetadata(pipeType),
|
||||||
@ -962,7 +980,6 @@ export class CompileMetadataResolver {
|
|||||||
isOptional,
|
isOptional,
|
||||||
token: this._getTokenMetadata(token)
|
token: this._getTokenMetadata(token)
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasUnknownDeps) {
|
if (hasUnknownDeps) {
|
||||||
@ -1000,7 +1017,7 @@ export class CompileMetadataResolver {
|
|||||||
this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
|
this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
|
||||||
} else {
|
} else {
|
||||||
provider = resolveForwardRef(provider);
|
provider = resolveForwardRef(provider);
|
||||||
let providerMeta: cpl.ProviderMeta = undefined !;
|
let providerMeta: cpl.ProviderMeta = undefined!;
|
||||||
if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
|
if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
|
||||||
this._validateProvider(provider);
|
this._validateProvider(provider);
|
||||||
providerMeta = new cpl.ProviderMeta(provider.provide, provider);
|
providerMeta = new cpl.ProviderMeta(provider.provide, provider);
|
||||||
@ -1027,8 +1044,11 @@ export class CompileMetadataResolver {
|
|||||||
[])
|
[])
|
||||||
.join(', ');
|
.join(', ');
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Invalid ${
|
||||||
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`),
|
debugInfo ?
|
||||||
|
debugInfo :
|
||||||
|
'provider'} - only instances of Provider and Type are allowed, got: [${
|
||||||
|
providersInfo}]`),
|
||||||
type);
|
type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1045,8 +1065,8 @@ export class CompileMetadataResolver {
|
|||||||
|
|
||||||
private _validateProvider(provider: any): void {
|
private _validateProvider(provider: any): void {
|
||||||
if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
|
if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
|
||||||
this._reportError(syntaxError(
|
this._reportError(syntaxError(`Invalid provider for ${
|
||||||
`Invalid provider for ${stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}.
|
stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}.
|
||||||
Usually it happens when:
|
Usually it happens when:
|
||||||
1. There's a circular dependency (might be caused by using index.ts (barrel) files).
|
1. There's a circular dependency (might be caused by using index.ts (barrel) files).
|
||||||
2. Class was used before it was declared. Use forwardRef in this case.`));
|
2. Class was used before it was declared. Use forwardRef in this case.`));
|
||||||
@ -1085,12 +1105,12 @@ export class CompileMetadataResolver {
|
|||||||
cpl.CompileEntryComponentMetadata|null {
|
cpl.CompileEntryComponentMetadata|null {
|
||||||
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
||||||
if (dirMeta && dirMeta.metadata.isComponent) {
|
if (dirMeta && dirMeta.metadata.isComponent) {
|
||||||
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory !};
|
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory!};
|
||||||
}
|
}
|
||||||
const dirSummary =
|
const dirSummary =
|
||||||
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
||||||
if (dirSummary && dirSummary.isComponent) {
|
if (dirSummary && dirSummary.isComponent) {
|
||||||
return {componentType: dirType, componentFactory: dirSummary.componentFactory !};
|
return {componentType: dirType, componentFactory: dirSummary.componentFactory!};
|
||||||
}
|
}
|
||||||
if (throwIfNotFound) {
|
if (throwIfNotFound) {
|
||||||
throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
|
throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
|
||||||
@ -1108,9 +1128,9 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
||||||
let compileDeps: cpl.CompileDiDependencyMetadata[] = undefined !;
|
let compileDeps: cpl.CompileDiDependencyMetadata[] = undefined!;
|
||||||
let compileTypeMetadata: cpl.CompileTypeMetadata = null !;
|
let compileTypeMetadata: cpl.CompileTypeMetadata = null!;
|
||||||
let compileFactoryMetadata: cpl.CompileFactoryMetadata = null !;
|
let compileFactoryMetadata: cpl.CompileFactoryMetadata = null!;
|
||||||
let token: cpl.CompileTokenMetadata = this._getTokenMetadata(provider.token);
|
let token: cpl.CompileTokenMetadata = this._getTokenMetadata(provider.token);
|
||||||
|
|
||||||
if (provider.useClass) {
|
if (provider.useClass) {
|
||||||
@ -1152,7 +1172,9 @@ export class CompileMetadataResolver {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _queryVarBindings(selector: any): string[] { return selector.split(/\s*,\s*/); }
|
private _queryVarBindings(selector: any): string[] {
|
||||||
|
return selector.split(/\s*,\s*/);
|
||||||
|
}
|
||||||
|
|
||||||
private _getQueryMetadata(q: Query, propertyName: string, typeOrFunc: Type|Function):
|
private _getQueryMetadata(q: Query, propertyName: string, typeOrFunc: Type|Function):
|
||||||
cpl.CompileQueryMetadata {
|
cpl.CompileQueryMetadata {
|
||||||
@ -1163,8 +1185,8 @@ export class CompileMetadataResolver {
|
|||||||
} else {
|
} else {
|
||||||
if (!q.selector) {
|
if (!q.selector) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
syntaxError(
|
syntaxError(`Can't construct a query for the property "${propertyName}" of "${
|
||||||
`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`),
|
stringifyType(typeOrFunc)}" since the query selector wasn't defined.`),
|
||||||
typeOrFunc);
|
typeOrFunc);
|
||||||
selectors = [];
|
selectors = [];
|
||||||
} else {
|
} else {
|
||||||
@ -1175,8 +1197,9 @@ export class CompileMetadataResolver {
|
|||||||
return {
|
return {
|
||||||
selectors,
|
selectors,
|
||||||
first: q.first,
|
first: q.first,
|
||||||
descendants: q.descendants, propertyName,
|
descendants: q.descendants,
|
||||||
read: q.read ? this._getTokenMetadata(q.read) : null !,
|
propertyName,
|
||||||
|
read: q.read ? this._getTokenMetadata(q.read) : null!,
|
||||||
static: q.static
|
static: q.static
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ export class Text extends NodeWithI18n {
|
|||||||
constructor(public value: string, sourceSpan: ParseSourceSpan, i18n?: I18nMeta) {
|
constructor(public value: string, sourceSpan: ParseSourceSpan, i18n?: I18nMeta) {
|
||||||
super(sourceSpan, i18n);
|
super(sourceSpan, i18n);
|
||||||
}
|
}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitText(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitText(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Expansion extends NodeWithI18n {
|
export class Expansion extends NodeWithI18n {
|
||||||
@ -33,7 +35,9 @@ export class Expansion extends NodeWithI18n {
|
|||||||
sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan, i18n?: I18nMeta) {
|
sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan, i18n?: I18nMeta) {
|
||||||
super(sourceSpan, i18n);
|
super(sourceSpan, i18n);
|
||||||
}
|
}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitExpansion(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitExpansion(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpansionCase implements Node {
|
export class ExpansionCase implements Node {
|
||||||
@ -41,7 +45,9 @@ export class ExpansionCase implements Node {
|
|||||||
public value: string, public expression: Node[], public sourceSpan: ParseSourceSpan,
|
public value: string, public expression: Node[], public sourceSpan: ParseSourceSpan,
|
||||||
public valueSourceSpan: ParseSourceSpan, public expSourceSpan: ParseSourceSpan) {}
|
public valueSourceSpan: ParseSourceSpan, public expSourceSpan: ParseSourceSpan) {}
|
||||||
|
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitExpansionCase(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitExpansionCase(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Attribute extends NodeWithI18n {
|
export class Attribute extends NodeWithI18n {
|
||||||
@ -50,7 +56,9 @@ export class Attribute extends NodeWithI18n {
|
|||||||
public valueSpan?: ParseSourceSpan, i18n?: I18nMeta) {
|
public valueSpan?: ParseSourceSpan, i18n?: I18nMeta) {
|
||||||
super(sourceSpan, i18n);
|
super(sourceSpan, i18n);
|
||||||
}
|
}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitAttribute(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Element extends NodeWithI18n {
|
export class Element extends NodeWithI18n {
|
||||||
@ -60,12 +68,16 @@ export class Element extends NodeWithI18n {
|
|||||||
public endSourceSpan: ParseSourceSpan|null = null, i18n?: I18nMeta) {
|
public endSourceSpan: ParseSourceSpan|null = null, i18n?: I18nMeta) {
|
||||||
super(sourceSpan, i18n);
|
super(sourceSpan, i18n);
|
||||||
}
|
}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitElement(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitElement(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Comment implements Node {
|
export class Comment implements Node {
|
||||||
constructor(public value: string|null, public sourceSpan: ParseSourceSpan) {}
|
constructor(public value: string|null, public sourceSpan: ParseSourceSpan) {}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitComment(this, context); }
|
visit(visitor: Visitor, context: any): any {
|
||||||
|
return visitor.visitComment(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Visitor {
|
export interface Visitor {
|
||||||
@ -85,7 +97,7 @@ export function visitAll(visitor: Visitor, nodes: Node[], context: any = null):
|
|||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
|
|
||||||
const visit = visitor.visit ?
|
const visit = visitor.visit ?
|
||||||
(ast: Node) => visitor.visit !(ast, context) || ast.visit(visitor, context) :
|
(ast: Node) => visitor.visit!(ast, context) || ast.visit(visitor, context) :
|
||||||
(ast: Node) => ast.visit(visitor, context);
|
(ast: Node) => ast.visit(visitor, context);
|
||||||
nodes.forEach(ast => {
|
nodes.forEach(ast => {
|
||||||
const astResult = visit(ast);
|
const astResult = visit(ast);
|
||||||
@ -111,7 +123,9 @@ export class RecursiveVisitor implements Visitor {
|
|||||||
visitComment(ast: Comment, context: any): any {}
|
visitComment(ast: Comment, context: any): any {}
|
||||||
|
|
||||||
visitExpansion(ast: Expansion, context: any): any {
|
visitExpansion(ast: Expansion, context: any): any {
|
||||||
return this.visitChildren(context, visit => { visit(ast.cases); });
|
return this.visitChildren(context, visit => {
|
||||||
|
visit(ast.cases);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpansionCase(ast: ExpansionCase, context: any): any {}
|
visitExpansionCase(ast: ExpansionCase, context: any): any {}
|
||||||
@ -120,7 +134,7 @@ export class RecursiveVisitor implements Visitor {
|
|||||||
context: any, cb: (visit: (<V extends Node>(children: V[]|undefined) => void)) => void) {
|
context: any, cb: (visit: (<V extends Node>(children: V[]|undefined) => void)) => void) {
|
||||||
let results: any[][] = [];
|
let results: any[][] = [];
|
||||||
let t = this;
|
let t = this;
|
||||||
function visit<T extends Node>(children: T[] | undefined) {
|
function visit<T extends Node>(children: T[]|undefined) {
|
||||||
if (children) results.push(visitAll(t, children, context));
|
if (children) results.push(visitAll(t, children, context));
|
||||||
}
|
}
|
||||||
cb(visit);
|
cb(visit);
|
||||||
|
@ -8,12 +8,14 @@
|
|||||||
|
|
||||||
import {getHtmlTagDefinition} from './html_tags';
|
import {getHtmlTagDefinition} from './html_tags';
|
||||||
import {TokenizeOptions} from './lexer';
|
import {TokenizeOptions} from './lexer';
|
||||||
import {ParseTreeResult, Parser} from './parser';
|
import {Parser, ParseTreeResult} from './parser';
|
||||||
|
|
||||||
export {ParseTreeResult, TreeError} from './parser';
|
export {ParseTreeResult, TreeError} from './parser';
|
||||||
|
|
||||||
export class HtmlParser extends Parser {
|
export class HtmlParser extends Parser {
|
||||||
constructor() { super(getHtmlTagDefinition); }
|
constructor() {
|
||||||
|
super(getHtmlTagDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult {
|
parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult {
|
||||||
return super.parse(source, url, options);
|
return super.parse(source, url, options);
|
||||||
|
@ -18,9 +18,14 @@ export class HtmlTagDefinition implements TagDefinition {
|
|||||||
ignoreFirstLf: boolean;
|
ignoreFirstLf: boolean;
|
||||||
canSelfClose: boolean = false;
|
canSelfClose: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor({
|
||||||
{closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA,
|
closedByChildren,
|
||||||
closedByParent = false, isVoid = false, ignoreFirstLf = false}: {
|
implicitNamespacePrefix,
|
||||||
|
contentType = TagContentType.PARSABLE_DATA,
|
||||||
|
closedByParent = false,
|
||||||
|
isVoid = false,
|
||||||
|
ignoreFirstLf = false
|
||||||
|
}: {
|
||||||
closedByChildren?: string[],
|
closedByChildren?: string[],
|
||||||
closedByParent?: boolean,
|
closedByParent?: boolean,
|
||||||
implicitNamespacePrefix?: string,
|
implicitNamespacePrefix?: string,
|
||||||
@ -43,11 +48,11 @@ export class HtmlTagDefinition implements TagDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _DEFAULT_TAG_DEFINITION !: HtmlTagDefinition;
|
let _DEFAULT_TAG_DEFINITION!: HtmlTagDefinition;
|
||||||
|
|
||||||
// see http://www.w3.org/TR/html51/syntax.html#optional-tags
|
// see http://www.w3.org/TR/html51/syntax.html#optional-tags
|
||||||
// This implementation does not fully conform to the HTML5 spec.
|
// This implementation does not fully conform to the HTML5 spec.
|
||||||
let TAG_DEFINITIONS !: {[key: string]: HtmlTagDefinition};
|
let TAG_DEFINITIONS!: {[key: string]: HtmlTagDefinition};
|
||||||
|
|
||||||
export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
|
export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
|
||||||
if (!TAG_DEFINITIONS) {
|
if (!TAG_DEFINITIONS) {
|
||||||
|
@ -81,11 +81,17 @@ export class WhitespaceVisitor implements html.Visitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitComment(comment: html.Comment, context: any): any { return comment; }
|
visitComment(comment: html.Comment, context: any): any {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansion(expansion: html.Expansion, context: any): any { return expansion; }
|
visitExpansion(expansion: html.Expansion, context: any): any {
|
||||||
|
return expansion;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return expansionCase; }
|
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any {
|
||||||
|
return expansionCase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeWhitespaces(htmlAstWithErrors: ParseTreeResult): ParseTreeResult {
|
export function removeWhitespaces(htmlAstWithErrors: ParseTreeResult): ParseTreeResult {
|
||||||
|
@ -46,7 +46,9 @@ export class ExpansionResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ExpansionError extends ParseError {
|
export class ExpansionError extends ParseError {
|
||||||
constructor(span: ParseSourceSpan, errorMsg: string) { super(span, errorMsg); }
|
constructor(span: ParseSourceSpan, errorMsg: string) {
|
||||||
|
super(span, errorMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,11 +66,17 @@ class _Expander implements html.Visitor {
|
|||||||
element.startSourceSpan, element.endSourceSpan);
|
element.startSourceSpan, element.endSourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAttribute(attribute: html.Attribute, context: any): any { return attribute; }
|
visitAttribute(attribute: html.Attribute, context: any): any {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
|
||||||
visitText(text: html.Text, context: any): any { return text; }
|
visitText(text: html.Text, context: any): any {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
visitComment(comment: html.Comment, context: any): any { return comment; }
|
visitComment(comment: html.Comment, context: any): any {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansion(icu: html.Expansion, context: any): any {
|
visitExpansion(icu: html.Expansion, context: any): any {
|
||||||
this.isExpanded = true;
|
this.isExpanded = true;
|
||||||
@ -87,7 +95,7 @@ function _expandPluralForm(ast: html.Expansion, errors: ParseError[]): html.Elem
|
|||||||
if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) {
|
if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) {
|
||||||
errors.push(new ExpansionError(
|
errors.push(new ExpansionError(
|
||||||
c.valueSourceSpan,
|
c.valueSourceSpan,
|
||||||
`Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(", ")}`));
|
`Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(', ')}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const expansionResult = expandNodes(c.expression);
|
const expansionResult = expandNodes(c.expression);
|
||||||
|
@ -764,7 +764,7 @@ function mergeTextTokens(srcTokens: Token[]): Token[] {
|
|||||||
for (let i = 0; i < srcTokens.length; i++) {
|
for (let i = 0; i < srcTokens.length; i++) {
|
||||||
const token = srcTokens[i];
|
const token = srcTokens[i];
|
||||||
if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) {
|
if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) {
|
||||||
lastDstToken.parts[0] ! += token.parts[0];
|
lastDstToken.parts[0]! += token.parts[0];
|
||||||
lastDstToken.sourceSpan.end = token.sourceSpan.end;
|
lastDstToken.sourceSpan.end = token.sourceSpan.end;
|
||||||
} else {
|
} else {
|
||||||
lastDstToken = token;
|
lastDstToken = token;
|
||||||
@ -849,15 +849,27 @@ class PlainCharacterCursor implements CharacterCursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): PlainCharacterCursor { return new PlainCharacterCursor(this); }
|
clone(): PlainCharacterCursor {
|
||||||
|
return new PlainCharacterCursor(this);
|
||||||
|
}
|
||||||
|
|
||||||
peek() { return this.state.peek; }
|
peek() {
|
||||||
charsLeft() { return this.end - this.state.offset; }
|
return this.state.peek;
|
||||||
diff(other: this) { return this.state.offset - other.state.offset; }
|
}
|
||||||
|
charsLeft() {
|
||||||
|
return this.end - this.state.offset;
|
||||||
|
}
|
||||||
|
diff(other: this) {
|
||||||
|
return this.state.offset - other.state.offset;
|
||||||
|
}
|
||||||
|
|
||||||
advance(): void { this.advanceState(this.state); }
|
advance(): void {
|
||||||
|
this.advanceState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
init(): void { this.updatePeek(this.state); }
|
init(): void {
|
||||||
|
this.updatePeek(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
getSpan(start?: this, leadingTriviaCodePoints?: number[]): ParseSourceSpan {
|
getSpan(start?: this, leadingTriviaCodePoints?: number[]): ParseSourceSpan {
|
||||||
start = start || this;
|
start = start || this;
|
||||||
@ -880,7 +892,9 @@ class PlainCharacterCursor implements CharacterCursor {
|
|||||||
return this.input.substring(start.state.offset, this.state.offset);
|
return this.input.substring(start.state.offset, this.state.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
charAt(pos: number): number { return this.input.charCodeAt(pos); }
|
charAt(pos: number): number {
|
||||||
|
return this.input.charCodeAt(pos);
|
||||||
|
}
|
||||||
|
|
||||||
protected advanceState(state: CursorState) {
|
protected advanceState(state: CursorState) {
|
||||||
if (state.offset >= this.end) {
|
if (state.offset >= this.end) {
|
||||||
@ -913,7 +927,7 @@ class EscapedCharacterCursor extends PlainCharacterCursor {
|
|||||||
super(fileOrCursor);
|
super(fileOrCursor);
|
||||||
this.internalState = {...fileOrCursor.internalState};
|
this.internalState = {...fileOrCursor.internalState};
|
||||||
} else {
|
} else {
|
||||||
super(fileOrCursor, range !);
|
super(fileOrCursor, range!);
|
||||||
this.internalState = this.state;
|
this.internalState = this.state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -929,7 +943,9 @@ class EscapedCharacterCursor extends PlainCharacterCursor {
|
|||||||
this.processEscapeSequence();
|
this.processEscapeSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): EscapedCharacterCursor { return new EscapedCharacterCursor(this); }
|
clone(): EscapedCharacterCursor {
|
||||||
|
return new EscapedCharacterCursor(this);
|
||||||
|
}
|
||||||
|
|
||||||
getChars(start: this): string {
|
getChars(start: this): string {
|
||||||
const cursor = start.clone();
|
const cursor = start.clone();
|
||||||
|
@ -10,7 +10,7 @@ import {ParseError, ParseSourceSpan} from '../parse_util';
|
|||||||
|
|
||||||
import * as html from './ast';
|
import * as html from './ast';
|
||||||
import * as lex from './lexer';
|
import * as lex from './lexer';
|
||||||
import {TagDefinition, getNsPrefix, isNgContainer, mergeNsAndName} from './tags';
|
import {getNsPrefix, isNgContainer, mergeNsAndName, TagDefinition} from './tags';
|
||||||
|
|
||||||
export class TreeError extends ParseError {
|
export class TreeError extends ParseError {
|
||||||
static create(elementName: string|null, span: ParseSourceSpan, msg: string): TreeError {
|
static create(elementName: string|null, span: ParseSourceSpan, msg: string): TreeError {
|
||||||
@ -43,7 +43,7 @@ export class Parser {
|
|||||||
class _TreeBuilder {
|
class _TreeBuilder {
|
||||||
private _index: number = -1;
|
private _index: number = -1;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _peek !: lex.Token;
|
private _peek!: lex.Token;
|
||||||
|
|
||||||
private _rootNodes: html.Node[] = [];
|
private _rootNodes: html.Node[] = [];
|
||||||
private _errors: TreeError[] = [];
|
private _errors: TreeError[] = [];
|
||||||
@ -283,7 +283,7 @@ class _TreeBuilder {
|
|||||||
endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
|
endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
|
||||||
|
|
||||||
if (this._getParentElement()) {
|
if (this._getParentElement()) {
|
||||||
this._getParentElement() !.endSourceSpan = endTagToken.sourceSpan;
|
this._getParentElement()!.endSourceSpan = endTagToken.sourceSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getTagDefinition(fullName).isVoid) {
|
if (this.getTagDefinition(fullName).isVoid) {
|
||||||
@ -291,8 +291,8 @@ class _TreeBuilder {
|
|||||||
fullName, endTagToken.sourceSpan,
|
fullName, endTagToken.sourceSpan,
|
||||||
`Void elements do not have end tags "${endTagToken.parts[1]}"`));
|
`Void elements do not have end tags "${endTagToken.parts[1]}"`));
|
||||||
} else if (!this._popElement(fullName)) {
|
} else if (!this._popElement(fullName)) {
|
||||||
const errMsg =
|
const errMsg = `Unexpected closing tag "${
|
||||||
`Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`;
|
fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`;
|
||||||
this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
|
this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ class _TreeBuilder {
|
|||||||
const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
|
const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
|
||||||
let end = attrName.sourceSpan.end;
|
let end = attrName.sourceSpan.end;
|
||||||
let value = '';
|
let value = '';
|
||||||
let valueSpan: ParseSourceSpan = undefined !;
|
let valueSpan: ParseSourceSpan = undefined!;
|
||||||
if (this._peek.type === lex.TokenType.ATTR_QUOTE) {
|
if (this._peek.type === lex.TokenType.ATTR_QUOTE) {
|
||||||
this._advance();
|
this._advance();
|
||||||
}
|
}
|
||||||
@ -344,7 +344,7 @@ class _TreeBuilder {
|
|||||||
* `<ng-container>` elements are skipped as they are not rendered as DOM element.
|
* `<ng-container>` elements are skipped as they are not rendered as DOM element.
|
||||||
*/
|
*/
|
||||||
private _getParentElementSkippingContainers():
|
private _getParentElementSkippingContainers():
|
||||||
{parent: html.Element | null, container: html.Element|null} {
|
{parent: html.Element|null, container: html.Element|null} {
|
||||||
let container: html.Element|null = null;
|
let container: html.Element|null = null;
|
||||||
|
|
||||||
for (let i = this._elementStack.length - 1; i >= 0; i--) {
|
for (let i = this._elementStack.length - 1; i >= 0; i--) {
|
||||||
|
@ -23,7 +23,7 @@ export interface TagDefinition {
|
|||||||
isClosedByChild(name: string): boolean;
|
isClosedByChild(name: string): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function splitNsName(elementName: string): [string | null, string] {
|
export function splitNsName(elementName: string): [string|null, string] {
|
||||||
if (elementName[0] != ':') {
|
if (elementName[0] != ':') {
|
||||||
return [null, elementName];
|
return [null, elementName];
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ export function isNgTemplate(tagName: string): boolean {
|
|||||||
|
|
||||||
export function getNsPrefix(fullName: string): string;
|
export function getNsPrefix(fullName: string): string;
|
||||||
export function getNsPrefix(fullName: null): null;
|
export function getNsPrefix(fullName: null): null;
|
||||||
export function getNsPrefix(fullName: string | null): string|null {
|
export function getNsPrefix(fullName: string|null): string|null {
|
||||||
return fullName === null ? null : splitNsName(fullName)[0];
|
return fullName === null ? null : splitNsName(fullName)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,13 +7,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {TokenizeOptions} from './lexer';
|
import {TokenizeOptions} from './lexer';
|
||||||
import {ParseTreeResult, Parser} from './parser';
|
import {Parser, ParseTreeResult} from './parser';
|
||||||
import {getXmlTagDefinition} from './xml_tags';
|
import {getXmlTagDefinition} from './xml_tags';
|
||||||
|
|
||||||
export {ParseTreeResult, TreeError} from './parser';
|
export {ParseTreeResult, TreeError} from './parser';
|
||||||
|
|
||||||
export class XmlParser extends Parser {
|
export class XmlParser extends Parser {
|
||||||
constructor() { super(getXmlTagDefinition); }
|
constructor() {
|
||||||
|
super(getXmlTagDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult {
|
parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult {
|
||||||
return super.parse(source, url, options);
|
return super.parse(source, url, options);
|
||||||
|
@ -11,19 +11,23 @@ import {TagContentType, TagDefinition} from './tags';
|
|||||||
export class XmlTagDefinition implements TagDefinition {
|
export class XmlTagDefinition implements TagDefinition {
|
||||||
closedByParent: boolean = false;
|
closedByParent: boolean = false;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
requiredParents !: {[key: string]: boolean};
|
requiredParents!: {[key: string]: boolean};
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
parentToAdd !: string;
|
parentToAdd!: string;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
implicitNamespacePrefix !: string;
|
implicitNamespacePrefix!: string;
|
||||||
contentType: TagContentType = TagContentType.PARSABLE_DATA;
|
contentType: TagContentType = TagContentType.PARSABLE_DATA;
|
||||||
isVoid: boolean = false;
|
isVoid: boolean = false;
|
||||||
ignoreFirstLf: boolean = false;
|
ignoreFirstLf: boolean = false;
|
||||||
canSelfClose: boolean = true;
|
canSelfClose: boolean = true;
|
||||||
|
|
||||||
requireExtraParent(currentParent: string): boolean { return false; }
|
requireExtraParent(currentParent: string): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
isClosedByChild(name: string): boolean { return false; }
|
isClosedByChild(name: string): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _TAG_DEFINITION = new XmlTagDefinition();
|
const _TAG_DEFINITION = new XmlTagDefinition();
|
||||||
|
@ -43,8 +43,8 @@ export class NgModuleCompiler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]);
|
const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]);
|
||||||
const ngModuleDefFactory = o.fn(
|
const ngModuleDefFactory =
|
||||||
[new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
|
o.fn([new o.FnParam(LOG_VAR.name!)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
|
||||||
|
|
||||||
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
|
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
|
||||||
this._createNgModuleFactory(
|
this._createNgModuleFactory(
|
||||||
@ -77,7 +77,7 @@ export class NgModuleCompiler {
|
|||||||
.set(value)
|
.set(value)
|
||||||
.toDeclStmt(
|
.toDeclStmt(
|
||||||
o.importType(
|
o.importType(
|
||||||
Identifiers.NgModuleFactory, [o.expressionType(ctx.importExpr(reference)) !],
|
Identifiers.NgModuleFactory, [o.expressionType(ctx.importExpr(reference))!],
|
||||||
[o.TypeModifier.Const]),
|
[o.TypeModifier.Const]),
|
||||||
[o.StmtModifier.Final, o.StmtModifier.Exported]);
|
[o.StmtModifier.Final, o.StmtModifier.Exported]);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileReflector} from './compile_reflector';
|
import {CompileReflector} from './compile_reflector';
|
||||||
import {NgModule, Type, createNgModule} from './core';
|
import {createNgModule, NgModule, Type} from './core';
|
||||||
import {findLast} from './directive_resolver';
|
import {findLast} from './directive_resolver';
|
||||||
import {stringify} from './util';
|
import {stringify} from './util';
|
||||||
|
|
||||||
@ -18,7 +18,9 @@ import {stringify} from './util';
|
|||||||
export class NgModuleResolver {
|
export class NgModuleResolver {
|
||||||
constructor(private _reflector: CompileReflector) {}
|
constructor(private _reflector: CompileReflector) {}
|
||||||
|
|
||||||
isNgModule(type: any) { return this._reflector.annotations(type).some(createNgModule.isTypeOf); }
|
isNgModule(type: any) {
|
||||||
|
return this._reflector.annotations(type).some(createNgModule.isTypeOf);
|
||||||
|
}
|
||||||
|
|
||||||
resolve(type: Type, throwIfNotFound = true): NgModule|null {
|
resolve(type: Type, throwIfNotFound = true): NgModule|null {
|
||||||
const ngModuleMeta: NgModule =
|
const ngModuleMeta: NgModule =
|
||||||
|
@ -28,31 +28,39 @@ class _EmittedLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class EmitterVisitorContext {
|
export class EmitterVisitorContext {
|
||||||
static createRoot(): EmitterVisitorContext { return new EmitterVisitorContext(0); }
|
static createRoot(): EmitterVisitorContext {
|
||||||
|
return new EmitterVisitorContext(0);
|
||||||
|
}
|
||||||
|
|
||||||
private _lines: _EmittedLine[];
|
private _lines: _EmittedLine[];
|
||||||
private _classes: o.ClassStmt[] = [];
|
private _classes: o.ClassStmt[] = [];
|
||||||
private _preambleLineCount = 0;
|
private _preambleLineCount = 0;
|
||||||
|
|
||||||
constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; }
|
constructor(private _indent: number) {
|
||||||
|
this._lines = [new _EmittedLine(_indent)];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal strip this from published d.ts files due to
|
* @internal strip this from published d.ts files due to
|
||||||
* https://github.com/microsoft/TypeScript/issues/36216
|
* https://github.com/microsoft/TypeScript/issues/36216
|
||||||
*/
|
*/
|
||||||
private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; }
|
private get _currentLine(): _EmittedLine {
|
||||||
|
return this._lines[this._lines.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void {
|
println(from?: {sourceSpan: ParseSourceSpan|null}|null, lastPart: string = ''): void {
|
||||||
this.print(from || null, lastPart, true);
|
this.print(from || null, lastPart, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
lineIsEmpty(): boolean { return this._currentLine.parts.length === 0; }
|
lineIsEmpty(): boolean {
|
||||||
|
return this._currentLine.parts.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
lineLength(): number {
|
lineLength(): number {
|
||||||
return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
|
return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
print(from: {sourceSpan: ParseSourceSpan | null}|null, part: string, newLine: boolean = false) {
|
print(from: {sourceSpan: ParseSourceSpan|null}|null, part: string, newLine: boolean = false) {
|
||||||
if (part.length > 0) {
|
if (part.length > 0) {
|
||||||
this._currentLine.parts.push(part);
|
this._currentLine.parts.push(part);
|
||||||
this._currentLine.partsLength += part.length;
|
this._currentLine.partsLength += part.length;
|
||||||
@ -83,9 +91,13 @@ export class EmitterVisitorContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pushClass(clazz: o.ClassStmt) { this._classes.push(clazz); }
|
pushClass(clazz: o.ClassStmt) {
|
||||||
|
this._classes.push(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
popClass(): o.ClassStmt { return this._classes.pop() !; }
|
popClass(): o.ClassStmt {
|
||||||
|
return this._classes.pop()!;
|
||||||
|
}
|
||||||
|
|
||||||
get currentClass(): o.ClassStmt|null {
|
get currentClass(): o.ClassStmt|null {
|
||||||
return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
|
return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
|
||||||
@ -135,7 +147,7 @@ export class EmitterVisitorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (spanIdx < spans.length) {
|
while (spanIdx < spans.length) {
|
||||||
const span = spans[spanIdx] !;
|
const span = spans[spanIdx]!;
|
||||||
const source = span.start.file;
|
const source = span.start.file;
|
||||||
const sourceLine = span.start.line;
|
const sourceLine = span.start.line;
|
||||||
const sourceCol = span.start.col;
|
const sourceCol = span.start.col;
|
||||||
@ -156,7 +168,9 @@ export class EmitterVisitorContext {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPreambleLineCount(count: number) { return this._preambleLineCount = count; }
|
setPreambleLineCount(count: number) {
|
||||||
|
return this._preambleLineCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
spanOf(line: number, column: number): ParseSourceSpan|null {
|
spanOf(line: number, column: number): ParseSourceSpan|null {
|
||||||
const emittedLine = this._lines[line - this._preambleLineCount];
|
const emittedLine = this._lines[line - this._preambleLineCount];
|
||||||
@ -243,7 +257,9 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
if (stmt.multiline) {
|
if (stmt.multiline) {
|
||||||
ctx.println(stmt, `/* ${stmt.comment} */`);
|
ctx.println(stmt, `/* ${stmt.comment} */`);
|
||||||
} else {
|
} else {
|
||||||
stmt.comment.split('\n').forEach((line) => { ctx.println(stmt, `// ${line}`); });
|
stmt.comment.split('\n').forEach((line) => {
|
||||||
|
ctx.println(stmt, `// ${line}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -327,7 +343,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
expr.expr.visitExpression(this, ctx);
|
expr.expr.visitExpression(this, ctx);
|
||||||
}
|
}
|
||||||
visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): any {
|
visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): any {
|
||||||
let varName = ast.name !;
|
let varName = ast.name!;
|
||||||
if (ast.builtin != null) {
|
if (ast.builtin != null) {
|
||||||
switch (ast.builtin) {
|
switch (ast.builtin) {
|
||||||
case o.BuiltinVar.Super:
|
case o.BuiltinVar.Super:
|
||||||
@ -337,10 +353,10 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
varName = 'this';
|
varName = 'this';
|
||||||
break;
|
break;
|
||||||
case o.BuiltinVar.CatchError:
|
case o.BuiltinVar.CatchError:
|
||||||
varName = CATCH_ERROR_VAR.name !;
|
varName = CATCH_ERROR_VAR.name!;
|
||||||
break;
|
break;
|
||||||
case o.BuiltinVar.CatchStack:
|
case o.BuiltinVar.CatchStack:
|
||||||
varName = CATCH_STACK_VAR.name !;
|
varName = CATCH_STACK_VAR.name!;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown builtin variable ${ast.builtin}`);
|
throw new Error(`Unknown builtin variable ${ast.builtin}`);
|
||||||
@ -388,7 +404,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
ctx.print(ast, '? ');
|
ctx.print(ast, '? ');
|
||||||
ast.trueCase.visitExpression(this, ctx);
|
ast.trueCase.visitExpression(this, ctx);
|
||||||
ctx.print(ast, ': ');
|
ctx.print(ast, ': ');
|
||||||
ast.falseCase !.visitExpression(this, ctx);
|
ast.falseCase!.visitExpression(this, ctx);
|
||||||
ctx.print(ast, `)`);
|
ctx.print(ast, `)`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,9 @@ import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitor
|
|||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
|
|
||||||
export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
||||||
constructor() { super(false); }
|
constructor() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||||
ctx.pushClass(stmt);
|
ctx.pushClass(stmt);
|
||||||
this._visitClassConstructor(stmt, ctx);
|
this._visitClassConstructor(stmt, ctx);
|
||||||
@ -101,7 +103,7 @@ export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
|||||||
visitInvokeFunctionExpr(expr: o.InvokeFunctionExpr, ctx: EmitterVisitorContext): string|null {
|
visitInvokeFunctionExpr(expr: o.InvokeFunctionExpr, ctx: EmitterVisitorContext): string|null {
|
||||||
const fnExpr = expr.fn;
|
const fnExpr = expr.fn;
|
||||||
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
||||||
ctx.currentClass !.parent !.visitExpression(this, ctx);
|
ctx.currentClass!.parent!.visitExpression(this, ctx);
|
||||||
ctx.print(expr, `.call(this`);
|
ctx.print(expr, `.call(this`);
|
||||||
if (expr.args.length > 0) {
|
if (expr.args.length > 0) {
|
||||||
ctx.print(expr, `, `);
|
ctx.print(expr, `, `);
|
||||||
|
@ -51,7 +51,7 @@ class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
|||||||
}
|
}
|
||||||
ctx.print(ast, `${prefix}.`);
|
ctx.print(ast, `${prefix}.`);
|
||||||
}
|
}
|
||||||
ctx.print(ast, name !);
|
ctx.print(ast, name!);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||||
|
@ -24,7 +24,9 @@ export abstract class Type {
|
|||||||
}
|
}
|
||||||
abstract visitType(visitor: TypeVisitor, context: any): any;
|
abstract visitType(visitor: TypeVisitor, context: any): any;
|
||||||
|
|
||||||
hasModifier(modifier: TypeModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; }
|
hasModifier(modifier: TypeModifier): boolean {
|
||||||
|
return this.modifiers!.indexOf(modifier) !== -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BuiltinTypeName {
|
export enum BuiltinTypeName {
|
||||||
@ -60,7 +62,9 @@ export class ExpressionType extends Type {
|
|||||||
|
|
||||||
|
|
||||||
export class ArrayType extends Type {
|
export class ArrayType extends Type {
|
||||||
constructor(public of : Type, modifiers: TypeModifier[]|null = null) { super(modifiers); }
|
constructor(public of: Type, modifiers: TypeModifier[]|null = null) {
|
||||||
|
super(modifiers);
|
||||||
|
}
|
||||||
visitType(visitor: TypeVisitor, context: any): any {
|
visitType(visitor: TypeVisitor, context: any): any {
|
||||||
return visitor.visitArrayType(this, context);
|
return visitor.visitArrayType(this, context);
|
||||||
}
|
}
|
||||||
@ -73,7 +77,9 @@ export class MapType extends Type {
|
|||||||
super(modifiers);
|
super(modifiers);
|
||||||
this.valueType = valueType || null;
|
this.valueType = valueType || null;
|
||||||
}
|
}
|
||||||
visitType(visitor: TypeVisitor, context: any): any { return visitor.visitMapType(this, context); }
|
visitType(visitor: TypeVisitor, context: any): any {
|
||||||
|
return visitor.visitMapType(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
|
export const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
|
||||||
@ -113,15 +119,15 @@ export enum BinaryOperator {
|
|||||||
BiggerEquals
|
BiggerEquals
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nullSafeIsEquivalent<T extends{isEquivalent(other: T): boolean}>(
|
export function nullSafeIsEquivalent<T extends {isEquivalent(other: T): boolean}>(
|
||||||
base: T | null, other: T | null) {
|
base: T|null, other: T|null) {
|
||||||
if (base == null || other == null) {
|
if (base == null || other == null) {
|
||||||
return base == other;
|
return base == other;
|
||||||
}
|
}
|
||||||
return base.isEquivalent(other);
|
return base.isEquivalent(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function areAllEquivalent<T extends{isEquivalent(other: T): boolean}>(
|
export function areAllEquivalent<T extends {isEquivalent(other: T): boolean}>(
|
||||||
base: T[], other: T[]) {
|
base: T[], other: T[]) {
|
||||||
const len = base.length;
|
const len = base.length;
|
||||||
if (len !== other.length) {
|
if (len !== other.length) {
|
||||||
@ -243,7 +249,9 @@ export abstract class Expression {
|
|||||||
return new CastExpr(this, type, sourceSpan);
|
return new CastExpr(this, type, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
toStmt(): Statement { return new ExpressionStatement(this, null); }
|
toStmt(): Statement {
|
||||||
|
return new ExpressionStatement(this, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BuiltinVar {
|
export enum BuiltinVar {
|
||||||
@ -272,7 +280,9 @@ export class ReadVarExpr extends Expression {
|
|||||||
return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
|
return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitReadVarExpr(this, context);
|
return visitor.visitReadVarExpr(this, context);
|
||||||
@ -299,7 +309,9 @@ export class TypeofExpr extends Expression {
|
|||||||
return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
|
return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant(): boolean { return this.expr.isConstant(); }
|
isConstant(): boolean {
|
||||||
|
return this.expr.isConstant();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WrappedNodeExpr<T> extends Expression {
|
export class WrappedNodeExpr<T> extends Expression {
|
||||||
@ -311,7 +323,9 @@ export class WrappedNodeExpr<T> extends Expression {
|
|||||||
return e instanceof WrappedNodeExpr && this.node === e.node;
|
return e instanceof WrappedNodeExpr && this.node === e.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitWrappedNodeExpr(this, context);
|
return visitor.visitWrappedNodeExpr(this, context);
|
||||||
@ -330,7 +344,9 @@ export class WriteVarExpr extends Expression {
|
|||||||
return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
|
return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitWriteVarExpr(this, context);
|
return visitor.visitWriteVarExpr(this, context);
|
||||||
@ -340,7 +356,9 @@ export class WriteVarExpr extends Expression {
|
|||||||
return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
|
return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
toConstDecl(): DeclareVarStmt { return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]); }
|
toConstDecl(): DeclareVarStmt {
|
||||||
|
return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -358,7 +376,9 @@ export class WriteKeyExpr extends Expression {
|
|||||||
this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
|
this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitWriteKeyExpr(this, context);
|
return visitor.visitWriteKeyExpr(this, context);
|
||||||
@ -380,7 +400,9 @@ export class WritePropExpr extends Expression {
|
|||||||
this.name === e.name && this.value.isEquivalent(e.value);
|
this.name === e.name && this.value.isEquivalent(e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitWritePropExpr(this, context);
|
return visitor.visitWritePropExpr(this, context);
|
||||||
@ -414,7 +436,9 @@ export class InvokeMethodExpr extends Expression {
|
|||||||
this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
|
this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitInvokeMethodExpr(this, context);
|
return visitor.visitInvokeMethodExpr(this, context);
|
||||||
@ -434,7 +458,9 @@ export class InvokeFunctionExpr extends Expression {
|
|||||||
areAllEquivalent(this.args, e.args) && this.pure === e.pure;
|
areAllEquivalent(this.args, e.args) && this.pure === e.pure;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitInvokeFunctionExpr(this, context);
|
return visitor.visitInvokeFunctionExpr(this, context);
|
||||||
@ -454,7 +480,9 @@ export class InstantiateExpr extends Expression {
|
|||||||
areAllEquivalent(this.args, e.args);
|
areAllEquivalent(this.args, e.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitInstantiateExpr(this, context);
|
return visitor.visitInstantiateExpr(this, context);
|
||||||
@ -473,7 +501,9 @@ export class LiteralExpr extends Expression {
|
|||||||
return e instanceof LiteralExpr && this.value === e.value;
|
return e instanceof LiteralExpr && this.value === e.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return true; }
|
isConstant() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitLiteralExpr(this, context);
|
return visitor.visitLiteralExpr(this, context);
|
||||||
@ -494,7 +524,9 @@ export class LocalizedString extends Expression {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitLocalizedString(this, context);
|
return visitor.visitLocalizedString(this, context);
|
||||||
@ -521,8 +553,9 @@ export class LocalizedString extends Expression {
|
|||||||
metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`;
|
metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`;
|
||||||
}
|
}
|
||||||
if (this.metaBlock.legacyIds) {
|
if (this.metaBlock.legacyIds) {
|
||||||
this.metaBlock.legacyIds.forEach(
|
this.metaBlock.legacyIds.forEach(legacyId => {
|
||||||
legacyId => { metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; });
|
metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return createCookedRawString(metaBlock, this.messageParts[0]);
|
return createCookedRawString(metaBlock, this.messageParts[0]);
|
||||||
}
|
}
|
||||||
@ -588,7 +621,9 @@ export class ExternalExpr extends Expression {
|
|||||||
this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
|
this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitExternalExpr(this, context);
|
return visitor.visitExternalExpr(this, context);
|
||||||
@ -616,7 +651,9 @@ export class ConditionalExpr extends Expression {
|
|||||||
this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
|
this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitConditionalExpr(this, context);
|
return visitor.visitConditionalExpr(this, context);
|
||||||
@ -633,7 +670,9 @@ export class NotExpr extends Expression {
|
|||||||
return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
|
return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitNotExpr(this, context);
|
return visitor.visitNotExpr(this, context);
|
||||||
@ -649,7 +688,9 @@ export class AssertNotNull extends Expression {
|
|||||||
return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
|
return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitAssertNotNullExpr(this, context);
|
return visitor.visitAssertNotNullExpr(this, context);
|
||||||
@ -665,7 +706,9 @@ export class CastExpr extends Expression {
|
|||||||
return e instanceof CastExpr && this.value.isEquivalent(e.value);
|
return e instanceof CastExpr && this.value.isEquivalent(e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitCastExpr(this, context);
|
return visitor.visitCastExpr(this, context);
|
||||||
@ -676,7 +719,9 @@ export class CastExpr extends Expression {
|
|||||||
export class FnParam {
|
export class FnParam {
|
||||||
constructor(public name: string, public type: Type|null = null) {}
|
constructor(public name: string, public type: Type|null = null) {}
|
||||||
|
|
||||||
isEquivalent(param: FnParam): boolean { return this.name === param.name; }
|
isEquivalent(param: FnParam): boolean {
|
||||||
|
return this.name === param.name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -692,7 +737,9 @@ export class FunctionExpr extends Expression {
|
|||||||
areAllEquivalent(this.statements, e.statements);
|
areAllEquivalent(this.statements, e.statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitFunctionExpr(this, context);
|
return visitor.visitFunctionExpr(this, context);
|
||||||
@ -719,7 +766,9 @@ export class BinaryOperatorExpr extends Expression {
|
|||||||
this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
|
this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitBinaryOperatorExpr(this, context);
|
return visitor.visitBinaryOperatorExpr(this, context);
|
||||||
@ -739,7 +788,9 @@ export class ReadPropExpr extends Expression {
|
|||||||
this.name === e.name;
|
this.name === e.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitReadPropExpr(this, context);
|
return visitor.visitReadPropExpr(this, context);
|
||||||
@ -763,7 +814,9 @@ export class ReadKeyExpr extends Expression {
|
|||||||
this.index.isEquivalent(e.index);
|
this.index.isEquivalent(e.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitReadKeyExpr(this, context);
|
return visitor.visitReadKeyExpr(this, context);
|
||||||
@ -782,7 +835,9 @@ export class LiteralArrayExpr extends Expression {
|
|||||||
this.entries = entries;
|
this.entries = entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return this.entries.every(e => e.isConstant()); }
|
isConstant() {
|
||||||
|
return this.entries.every(e => e.isConstant());
|
||||||
|
}
|
||||||
|
|
||||||
isEquivalent(e: Expression): boolean {
|
isEquivalent(e: Expression): boolean {
|
||||||
return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
|
return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
|
||||||
@ -813,7 +868,9 @@ export class LiteralMapExpr extends Expression {
|
|||||||
return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
|
return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return this.entries.every(e => e.value.isConstant()); }
|
isConstant() {
|
||||||
|
return this.entries.every(e => e.value.isConstant());
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitLiteralMapExpr(this, context);
|
return visitor.visitLiteralMapExpr(this, context);
|
||||||
@ -829,7 +886,9 @@ export class CommaExpr extends Expression {
|
|||||||
return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
|
return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() { return false; }
|
isConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
return visitor.visitCommaExpr(this, context);
|
return visitor.visitCommaExpr(this, context);
|
||||||
@ -892,7 +951,9 @@ export abstract class Statement {
|
|||||||
|
|
||||||
abstract visitStatement(visitor: StatementVisitor, context: any): any;
|
abstract visitStatement(visitor: StatementVisitor, context: any): any;
|
||||||
|
|
||||||
hasModifier(modifier: StmtModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; }
|
hasModifier(modifier: StmtModifier): boolean {
|
||||||
|
return this.modifiers!.indexOf(modifier) !== -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -965,7 +1026,9 @@ export class AbstractClassPart {
|
|||||||
}
|
}
|
||||||
this.type = type || null;
|
this.type = type || null;
|
||||||
}
|
}
|
||||||
hasModifier(modifier: StmtModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; }
|
hasModifier(modifier: StmtModifier): boolean {
|
||||||
|
return this.modifiers!.indexOf(modifier) !== -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClassField extends AbstractClassPart {
|
export class ClassField extends AbstractClassPart {
|
||||||
@ -974,7 +1037,9 @@ export class ClassField extends AbstractClassPart {
|
|||||||
public initializer?: Expression) {
|
public initializer?: Expression) {
|
||||||
super(type, modifiers);
|
super(type, modifiers);
|
||||||
}
|
}
|
||||||
isEquivalent(f: ClassField) { return this.name === f.name; }
|
isEquivalent(f: ClassField) {
|
||||||
|
return this.name === f.name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1044,7 +1109,9 @@ export class CommentStmt extends Statement {
|
|||||||
constructor(public comment: string, public multiline = false, sourceSpan?: ParseSourceSpan|null) {
|
constructor(public comment: string, public multiline = false, sourceSpan?: ParseSourceSpan|null) {
|
||||||
super(null, sourceSpan);
|
super(null, sourceSpan);
|
||||||
}
|
}
|
||||||
isEquivalent(stmt: Statement): boolean { return stmt instanceof CommentStmt; }
|
isEquivalent(stmt: Statement): boolean {
|
||||||
|
return stmt instanceof CommentStmt;
|
||||||
|
}
|
||||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||||
return visitor.visitCommentStmt(this, context);
|
return visitor.visitCommentStmt(this, context);
|
||||||
}
|
}
|
||||||
@ -1060,7 +1127,9 @@ export class JSDocCommentStmt extends Statement {
|
|||||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||||
return visitor.visitJSDocCommentStmt(this, context);
|
return visitor.visitJSDocCommentStmt(this, context);
|
||||||
}
|
}
|
||||||
toString(): string { return serializeTags(this.tags); }
|
toString(): string {
|
||||||
|
return serializeTags(this.tags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TryCatchStmt extends Statement {
|
export class TryCatchStmt extends Statement {
|
||||||
@ -1105,11 +1174,17 @@ export interface StatementVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||||
transformExpr(expr: Expression, context: any): Expression { return expr; }
|
transformExpr(expr: Expression, context: any): Expression {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
transformStmt(stmt: Statement, context: any): Statement { return stmt; }
|
transformStmt(stmt: Statement, context: any): Statement {
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any { return this.transformExpr(ast, context); }
|
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
||||||
|
return this.transformExpr(ast, context);
|
||||||
|
}
|
||||||
|
|
||||||
visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any {
|
visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any {
|
||||||
return this.transformExpr(ast, context);
|
return this.transformExpr(ast, context);
|
||||||
@ -1148,7 +1223,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
|||||||
const method = ast.builtin || ast.name;
|
const method = ast.builtin || ast.name;
|
||||||
return this.transformExpr(
|
return this.transformExpr(
|
||||||
new InvokeMethodExpr(
|
new InvokeMethodExpr(
|
||||||
ast.receiver.visitExpression(this, context), method !,
|
ast.receiver.visitExpression(this, context), method!,
|
||||||
this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan),
|
this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan),
|
||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
@ -1169,7 +1244,9 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
|||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralExpr(ast: LiteralExpr, context: any): any { return this.transformExpr(ast, context); }
|
visitLiteralExpr(ast: LiteralExpr, context: any): any {
|
||||||
|
return this.transformExpr(ast, context);
|
||||||
|
}
|
||||||
|
|
||||||
visitLocalizedString(ast: LocalizedString, context: any): any {
|
visitLocalizedString(ast: LocalizedString, context: any): any {
|
||||||
return this.transformExpr(
|
return this.transformExpr(
|
||||||
@ -1188,7 +1265,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
|||||||
new ConditionalExpr(
|
new ConditionalExpr(
|
||||||
ast.condition.visitExpression(this, context),
|
ast.condition.visitExpression(this, context),
|
||||||
ast.trueCase.visitExpression(this, context),
|
ast.trueCase.visitExpression(this, context),
|
||||||
ast.falseCase !.visitExpression(this, context), ast.type, ast.sourceSpan),
|
ast.falseCase!.visitExpression(this, context), ast.type, ast.sourceSpan),
|
||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1284,7 +1361,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||||
const parent = stmt.parent !.visitExpression(this, context);
|
const parent = stmt.parent!.visitExpression(this, context);
|
||||||
const getters = stmt.getters.map(
|
const getters = stmt.getters.map(
|
||||||
getter => new ClassGetter(
|
getter => new ClassGetter(
|
||||||
getter.name, this.visitAllStatements(getter.body, context), getter.type,
|
getter.name, this.visitAllStatements(getter.body, context), getter.type,
|
||||||
@ -1341,14 +1418,18 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
|||||||
|
|
||||||
|
|
||||||
export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor {
|
export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor {
|
||||||
visitType(ast: Type, context: any): any { return ast; }
|
visitType(ast: Type, context: any): any {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
visitExpression(ast: Expression, context: any): any {
|
visitExpression(ast: Expression, context: any): any {
|
||||||
if (ast.type) {
|
if (ast.type) {
|
||||||
ast.type.visitType(this, context);
|
ast.type.visitType(this, context);
|
||||||
}
|
}
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
visitBuiltinType(type: BuiltinType, context: any): any { return this.visitType(type, context); }
|
visitBuiltinType(type: BuiltinType, context: any): any {
|
||||||
|
return this.visitType(type, context);
|
||||||
|
}
|
||||||
visitExpressionType(type: ExpressionType, context: any): any {
|
visitExpressionType(type: ExpressionType, context: any): any {
|
||||||
type.value.visitExpression(this, context);
|
type.value.visitExpression(this, context);
|
||||||
if (type.typeParams !== null) {
|
if (type.typeParams !== null) {
|
||||||
@ -1356,10 +1437,18 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
|||||||
}
|
}
|
||||||
return this.visitType(type, context);
|
return this.visitType(type, context);
|
||||||
}
|
}
|
||||||
visitArrayType(type: ArrayType, context: any): any { return this.visitType(type, context); }
|
visitArrayType(type: ArrayType, context: any): any {
|
||||||
visitMapType(type: MapType, context: any): any { return this.visitType(type, context); }
|
return this.visitType(type, context);
|
||||||
visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any { return ast; }
|
}
|
||||||
visitTypeofExpr(ast: TypeofExpr, context: any): any { return this.visitExpression(ast, context); }
|
visitMapType(type: MapType, context: any): any {
|
||||||
|
return this.visitType(type, context);
|
||||||
|
}
|
||||||
|
visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any {
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
visitTypeofExpr(ast: TypeofExpr, context: any): any {
|
||||||
|
return this.visitExpression(ast, context);
|
||||||
|
}
|
||||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
||||||
return this.visitExpression(ast, context);
|
return this.visitExpression(ast, context);
|
||||||
}
|
}
|
||||||
@ -1408,7 +1497,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
|||||||
visitConditionalExpr(ast: ConditionalExpr, context: any): any {
|
visitConditionalExpr(ast: ConditionalExpr, context: any): any {
|
||||||
ast.condition.visitExpression(this, context);
|
ast.condition.visitExpression(this, context);
|
||||||
ast.trueCase.visitExpression(this, context);
|
ast.trueCase.visitExpression(this, context);
|
||||||
ast.falseCase !.visitExpression(this, context);
|
ast.falseCase!.visitExpression(this, context);
|
||||||
return this.visitExpression(ast, context);
|
return this.visitExpression(ast, context);
|
||||||
}
|
}
|
||||||
visitNotExpr(ast: NotExpr, context: any): any {
|
visitNotExpr(ast: NotExpr, context: any): any {
|
||||||
@ -1482,7 +1571,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||||
stmt.parent !.visitExpression(this, context);
|
stmt.parent!.visitExpression(this, context);
|
||||||
stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context));
|
stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context));
|
||||||
if (stmt.constructorMethod) {
|
if (stmt.constructorMethod) {
|
||||||
this.visitAllStatements(stmt.constructorMethod.body, context);
|
this.visitAllStatements(stmt.constructorMethod.body, context);
|
||||||
@ -1505,8 +1594,12 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
|||||||
stmt.error.visitExpression(this, context);
|
stmt.error.visitExpression(this, context);
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; }
|
visitCommentStmt(stmt: CommentStmt, context: any): any {
|
||||||
visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any { return stmt; }
|
return stmt;
|
||||||
|
}
|
||||||
|
visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any {
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
visitAllStatements(stmts: Statement[], context: any): void {
|
visitAllStatements(stmts: Statement[], context: any): void {
|
||||||
stmts.forEach(stmt => stmt.visitStatement(this, context));
|
stmts.forEach(stmt => stmt.visitStatement(this, context));
|
||||||
}
|
}
|
||||||
@ -1551,7 +1644,7 @@ class _FindExternalReferencesVisitor extends RecursiveAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applySourceSpanToStatementIfNeeded(
|
export function applySourceSpanToStatementIfNeeded(
|
||||||
stmt: Statement, sourceSpan: ParseSourceSpan | null): Statement {
|
stmt: Statement, sourceSpan: ParseSourceSpan|null): Statement {
|
||||||
if (!sourceSpan) {
|
if (!sourceSpan) {
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
@ -1560,7 +1653,7 @@ export function applySourceSpanToStatementIfNeeded(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applySourceSpanToExpressionIfNeeded(
|
export function applySourceSpanToExpressionIfNeeded(
|
||||||
expr: Expression, sourceSpan: ParseSourceSpan | null): Expression {
|
expr: Expression, sourceSpan: ParseSourceSpan|null): Expression {
|
||||||
if (!sourceSpan) {
|
if (!sourceSpan) {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1662,9 @@ export function applySourceSpanToExpressionIfNeeded(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ApplySourceSpanTransformer extends AstTransformer {
|
class _ApplySourceSpanTransformer extends AstTransformer {
|
||||||
constructor(private sourceSpan: ParseSourceSpan) { super(); }
|
constructor(private sourceSpan: ParseSourceSpan) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
private _clone(obj: any): any {
|
private _clone(obj: any): any {
|
||||||
const clone = Object.create(obj.constructor.prototype);
|
const clone = Object.create(obj.constructor.prototype);
|
||||||
for (let prop of Object.keys(obj)) {
|
for (let prop of Object.keys(obj)) {
|
||||||
@ -1596,25 +1691,25 @@ class _ApplySourceSpanTransformer extends AstTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function variable(
|
export function variable(
|
||||||
name: string, type?: Type | null, sourceSpan?: ParseSourceSpan | null): ReadVarExpr {
|
name: string, type?: Type|null, sourceSpan?: ParseSourceSpan|null): ReadVarExpr {
|
||||||
return new ReadVarExpr(name, type, sourceSpan);
|
return new ReadVarExpr(name, type, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importExpr(
|
export function importExpr(
|
||||||
id: ExternalReference, typeParams: Type[] | null = null,
|
id: ExternalReference, typeParams: Type[]|null = null,
|
||||||
sourceSpan?: ParseSourceSpan | null): ExternalExpr {
|
sourceSpan?: ParseSourceSpan|null): ExternalExpr {
|
||||||
return new ExternalExpr(id, null, typeParams, sourceSpan);
|
return new ExternalExpr(id, null, typeParams, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importType(
|
export function importType(
|
||||||
id: ExternalReference, typeParams: Type[] | null = null,
|
id: ExternalReference, typeParams: Type[]|null = null,
|
||||||
typeModifiers: TypeModifier[] | null = null): ExpressionType|null {
|
typeModifiers: TypeModifier[]|null = null): ExpressionType|null {
|
||||||
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
|
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function expressionType(
|
export function expressionType(
|
||||||
expr: Expression, typeModifiers: TypeModifier[] | null = null,
|
expr: Expression, typeModifiers: TypeModifier[]|null = null,
|
||||||
typeParams: Type[] | null = null): ExpressionType {
|
typeParams: Type[]|null = null): ExpressionType {
|
||||||
return new ExpressionType(expr, typeModifiers, typeParams);
|
return new ExpressionType(expr, typeModifiers, typeParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1623,30 +1718,28 @@ export function typeofExpr(expr: Expression) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function literalArr(
|
export function literalArr(
|
||||||
values: Expression[], type?: Type | null,
|
values: Expression[], type?: Type|null, sourceSpan?: ParseSourceSpan|null): LiteralArrayExpr {
|
||||||
sourceSpan?: ParseSourceSpan | null): LiteralArrayExpr {
|
|
||||||
return new LiteralArrayExpr(values, type, sourceSpan);
|
return new LiteralArrayExpr(values, type, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function literalMap(
|
export function literalMap(
|
||||||
values: {key: string, quoted: boolean, value: Expression}[],
|
values: {key: string, quoted: boolean, value: Expression}[],
|
||||||
type: MapType | null = null): LiteralMapExpr {
|
type: MapType|null = null): LiteralMapExpr {
|
||||||
return new LiteralMapExpr(
|
return new LiteralMapExpr(
|
||||||
values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
|
values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function not(expr: Expression, sourceSpan?: ParseSourceSpan | null): NotExpr {
|
export function not(expr: Expression, sourceSpan?: ParseSourceSpan|null): NotExpr {
|
||||||
return new NotExpr(expr, sourceSpan);
|
return new NotExpr(expr, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertNotNull(
|
export function assertNotNull(expr: Expression, sourceSpan?: ParseSourceSpan|null): AssertNotNull {
|
||||||
expr: Expression, sourceSpan?: ParseSourceSpan | null): AssertNotNull {
|
|
||||||
return new AssertNotNull(expr, sourceSpan);
|
return new AssertNotNull(expr, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fn(
|
export function fn(
|
||||||
params: FnParam[], body: Statement[], type?: Type | null, sourceSpan?: ParseSourceSpan | null,
|
params: FnParam[], body: Statement[], type?: Type|null, sourceSpan?: ParseSourceSpan|null,
|
||||||
name?: string | null): FunctionExpr {
|
name?: string|null): FunctionExpr {
|
||||||
return new FunctionExpr(params, body, type, sourceSpan, name);
|
return new FunctionExpr(params, body, type, sourceSpan, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1655,13 +1748,13 @@ export function ifStmt(condition: Expression, thenClause: Statement[], elseClaus
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function literal(
|
export function literal(
|
||||||
value: any, type?: Type | null, sourceSpan?: ParseSourceSpan | null): LiteralExpr {
|
value: any, type?: Type|null, sourceSpan?: ParseSourceSpan|null): LiteralExpr {
|
||||||
return new LiteralExpr(value, type, sourceSpan);
|
return new LiteralExpr(value, type, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function localizedString(
|
export function localizedString(
|
||||||
metaBlock: I18nMeta, messageParts: string[], placeholderNames: string[],
|
metaBlock: I18nMeta, messageParts: string[], placeholderNames: string[],
|
||||||
expressions: Expression[], sourceSpan?: ParseSourceSpan | null): LocalizedString {
|
expressions: Expression[], sourceSpan?: ParseSourceSpan|null): LocalizedString {
|
||||||
return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
|
return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,13 +1777,12 @@ export const enum JSDocTagName {
|
|||||||
*/
|
*/
|
||||||
export type JSDocTag = {
|
export type JSDocTag = {
|
||||||
// `tagName` is e.g. "param" in an `@param` declaration
|
// `tagName` is e.g. "param" in an `@param` declaration
|
||||||
tagName: JSDocTagName | string,
|
tagName: JSDocTagName|string,
|
||||||
// Any remaining text on the tag, e.g. the description
|
// Any remaining text on the tag, e.g. the description
|
||||||
text?: string,
|
text?: string,
|
||||||
} | {
|
}|{
|
||||||
// no `tagName` for plain text documentation that occurs before any `@param` lines
|
// no `tagName` for plain text documentation that occurs before any `@param` lines
|
||||||
tagName?: undefined,
|
tagName?: undefined, text: string,
|
||||||
text: string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,7 +15,9 @@ export function interpretStatements(
|
|||||||
const visitor = new StatementInterpreter(reflector);
|
const visitor = new StatementInterpreter(reflector);
|
||||||
visitor.visitAllStatements(statements, ctx);
|
visitor.visitAllStatements(statements, ctx);
|
||||||
const result: {[key: string]: any} = {};
|
const result: {[key: string]: any} = {};
|
||||||
ctx.exports.forEach((exportName) => { result[exportName] = ctx.vars.get(exportName); });
|
ctx.exports.forEach((exportName) => {
|
||||||
|
result[exportName] = ctx.vars.get(exportName);
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ function createDynamicClass(
|
|||||||
_classStmt.methods.forEach(function(method: o.ClassMethod) {
|
_classStmt.methods.forEach(function(method: o.ClassMethod) {
|
||||||
const paramNames = method.params.map(param => param.name);
|
const paramNames = method.params.map(param => param.name);
|
||||||
// Note: use `function` instead of arrow function to capture `this`
|
// Note: use `function` instead of arrow function to capture `this`
|
||||||
propertyDescriptors[method.name !] = {
|
propertyDescriptors[method.name!] = {
|
||||||
writable: false,
|
writable: false,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
value: function(...args: any[]) {
|
value: function(...args: any[]) {
|
||||||
@ -77,7 +79,9 @@ function createDynamicClass(
|
|||||||
// Note: use `function` instead of arrow function to capture `this`
|
// Note: use `function` instead of arrow function to capture `this`
|
||||||
const ctor = function(this: Object, ...args: any[]) {
|
const ctor = function(this: Object, ...args: any[]) {
|
||||||
const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
||||||
_classStmt.fields.forEach((field) => { (this as any)[field.name] = undefined; });
|
_classStmt.fields.forEach((field) => {
|
||||||
|
(this as any)[field.name] = undefined;
|
||||||
|
});
|
||||||
_executeFunctionStatements(
|
_executeFunctionStatements(
|
||||||
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
||||||
};
|
};
|
||||||
@ -88,7 +92,9 @@ function createDynamicClass(
|
|||||||
|
|
||||||
class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||||
constructor(private reflector: CompileReflector) {}
|
constructor(private reflector: CompileReflector) {}
|
||||||
debugAst(ast: o.Expression|o.Statement|o.Type): string { return debugOutputAstAsTypeScript(ast); }
|
debugAst(ast: o.Expression|o.Statement|o.Type): string {
|
||||||
|
return debugOutputAstAsTypeScript(ast);
|
||||||
|
}
|
||||||
|
|
||||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
|
||||||
const initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined;
|
const initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined;
|
||||||
@ -106,7 +112,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
currCtx.vars.set(expr.name, value);
|
currCtx.vars.set(expr.name, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
currCtx = currCtx.parent !;
|
currCtx = currCtx.parent!;
|
||||||
}
|
}
|
||||||
throw new Error(`Not declared variable ${expr.name}`);
|
throw new Error(`Not declared variable ${expr.name}`);
|
||||||
}
|
}
|
||||||
@ -117,7 +123,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
throw new Error('Cannot interpret a TypeofExpr');
|
throw new Error('Cannot interpret a TypeofExpr');
|
||||||
}
|
}
|
||||||
visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any {
|
visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any {
|
||||||
let varName = ast.name !;
|
let varName = ast.name!;
|
||||||
if (ast.builtin != null) {
|
if (ast.builtin != null) {
|
||||||
switch (ast.builtin) {
|
switch (ast.builtin) {
|
||||||
case o.BuiltinVar.Super:
|
case o.BuiltinVar.Super:
|
||||||
@ -139,7 +145,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
if (currCtx.vars.has(varName)) {
|
if (currCtx.vars.has(varName)) {
|
||||||
return currCtx.vars.get(varName);
|
return currCtx.vars.get(varName);
|
||||||
}
|
}
|
||||||
currCtx = currCtx.parent !;
|
currCtx = currCtx.parent!;
|
||||||
}
|
}
|
||||||
throw new Error(`Not declared variable ${varName}`);
|
throw new Error(`Not declared variable ${varName}`);
|
||||||
}
|
}
|
||||||
@ -176,7 +182,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
throw new Error(`Unknown builtin method ${expr.builtin}`);
|
throw new Error(`Unknown builtin method ${expr.builtin}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = receiver[expr.name !].apply(receiver, args);
|
result = receiver[expr.name!].apply(receiver, args);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -184,7 +190,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
const args = this.visitAllExpressions(stmt.args, ctx);
|
const args = this.visitAllExpressions(stmt.args, ctx);
|
||||||
const fnExpr = stmt.fn;
|
const fnExpr = stmt.fn;
|
||||||
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
||||||
ctx.instance !.constructor.prototype.constructor.apply(ctx.instance, args);
|
ctx.instance!.constructor.prototype.constructor.apply(ctx.instance, args);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const fn = stmt.fn.visitExpression(this, ctx);
|
const fn = stmt.fn.visitExpression(this, ctx);
|
||||||
@ -227,15 +233,23 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any {
|
visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any {
|
||||||
throw stmt.error.visitExpression(this, ctx);
|
throw stmt.error.visitExpression(this, ctx);
|
||||||
}
|
}
|
||||||
visitCommentStmt(stmt: o.CommentStmt, context?: any): any { return null; }
|
visitCommentStmt(stmt: o.CommentStmt, context?: any): any {
|
||||||
visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, context?: any): any { return null; }
|
return null;
|
||||||
|
}
|
||||||
|
visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, context?: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
|
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
|
||||||
const args = this.visitAllExpressions(ast.args, ctx);
|
const args = this.visitAllExpressions(ast.args, ctx);
|
||||||
const clazz = ast.classExpr.visitExpression(this, ctx);
|
const clazz = ast.classExpr.visitExpression(this, ctx);
|
||||||
return new clazz(...args);
|
return new clazz(...args);
|
||||||
}
|
}
|
||||||
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; }
|
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any {
|
||||||
visitLocalizedString(ast: o.LocalizedString, context: any): any { return null; }
|
return ast.value;
|
||||||
|
}
|
||||||
|
visitLocalizedString(ast: o.LocalizedString, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any {
|
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any {
|
||||||
return this.reflector.resolveExternalReference(ast.value);
|
return this.reflector.resolveExternalReference(ast.value);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,9 @@ export class JitEvaluator {
|
|||||||
* @param args The arguments to pass to the function being executed.
|
* @param args The arguments to pass to the function being executed.
|
||||||
* @returns The return value of the executed function.
|
* @returns The return value of the executed function.
|
||||||
*/
|
*/
|
||||||
executeFunction(fn: Function, args: any[]) { return fn(...args); }
|
executeFunction(fn: Function, args: any[]) {
|
||||||
|
return fn(...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +100,9 @@ export class JitEmitterVisitor extends AbstractJsEmitterVisitor {
|
|||||||
private _evalArgValues: any[] = [];
|
private _evalArgValues: any[] = [];
|
||||||
private _evalExportedVars: string[] = [];
|
private _evalExportedVars: string[] = [];
|
||||||
|
|
||||||
constructor(private reflector: CompileReflector) { super(); }
|
constructor(private reflector: CompileReflector) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
createReturnStmt(ctx: EmitterVisitorContext) {
|
createReturnStmt(ctx: EmitterVisitorContext) {
|
||||||
const stmt = new o.ReturnStatement(new o.LiteralMapExpr(this._evalExportedVars.map(
|
const stmt = new o.ReturnStatement(new o.LiteralMapExpr(this._evalExportedVars.map(
|
||||||
|
@ -25,7 +25,7 @@ export type SourceMap = {
|
|||||||
file?: string,
|
file?: string,
|
||||||
sourceRoot: string,
|
sourceRoot: string,
|
||||||
sources: string[],
|
sources: string[],
|
||||||
sourcesContent: (string | null)[],
|
sourcesContent: (string|null)[],
|
||||||
mappings: string,
|
mappings: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,7 +78,9 @@ export class SourceMapGenerator {
|
|||||||
* @internal strip this from published d.ts files due to
|
* @internal strip this from published d.ts files due to
|
||||||
* https://github.com/microsoft/TypeScript/issues/36216
|
* https://github.com/microsoft/TypeScript/issues/36216
|
||||||
*/
|
*/
|
||||||
private get currentLine(): Segment[]|null { return this.lines.slice(-1)[0]; }
|
private get currentLine(): Segment[]|null {
|
||||||
|
return this.lines.slice(-1)[0];
|
||||||
|
}
|
||||||
|
|
||||||
toJSON(): SourceMap|null {
|
toJSON(): SourceMap|null {
|
||||||
if (!this.hasMappings) {
|
if (!this.hasMappings) {
|
||||||
@ -87,7 +89,7 @@ export class SourceMapGenerator {
|
|||||||
|
|
||||||
const sourcesIndex = new Map<string, number>();
|
const sourcesIndex = new Map<string, number>();
|
||||||
const sources: string[] = [];
|
const sources: string[] = [];
|
||||||
const sourcesContent: (string | null)[] = [];
|
const sourcesContent: (string|null)[] = [];
|
||||||
|
|
||||||
Array.from(this.sourcesContent.keys()).forEach((url: string, i: number) => {
|
Array.from(this.sourcesContent.keys()).forEach((url: string, i: number) => {
|
||||||
sourcesIndex.set(url, i);
|
sourcesIndex.set(url, i);
|
||||||
@ -113,14 +115,14 @@ export class SourceMapGenerator {
|
|||||||
if (segment.sourceUrl != null) {
|
if (segment.sourceUrl != null) {
|
||||||
// zero-based index into the “sources” list
|
// zero-based index into the “sources” list
|
||||||
segAsStr +=
|
segAsStr +=
|
||||||
toBase64VLQ(sourcesIndex.get(segment.sourceUrl) ! - lastSourceIndex);
|
toBase64VLQ(sourcesIndex.get(segment.sourceUrl)! - lastSourceIndex);
|
||||||
lastSourceIndex = sourcesIndex.get(segment.sourceUrl) !;
|
lastSourceIndex = sourcesIndex.get(segment.sourceUrl)!;
|
||||||
// the zero-based starting line in the original source
|
// the zero-based starting line in the original source
|
||||||
segAsStr += toBase64VLQ(segment.sourceLine0 ! - lastSourceLine0);
|
segAsStr += toBase64VLQ(segment.sourceLine0! - lastSourceLine0);
|
||||||
lastSourceLine0 = segment.sourceLine0 !;
|
lastSourceLine0 = segment.sourceLine0!;
|
||||||
// the zero-based starting column in the original source
|
// the zero-based starting column in the original source
|
||||||
segAsStr += toBase64VLQ(segment.sourceCol0 ! - lastSourceCol0);
|
segAsStr += toBase64VLQ(segment.sourceCol0! - lastSourceCol0);
|
||||||
lastSourceCol0 = segment.sourceCol0 !;
|
lastSourceCol0 = segment.sourceCol0!;
|
||||||
}
|
}
|
||||||
|
|
||||||
return segAsStr;
|
return segAsStr;
|
||||||
|
@ -15,8 +15,7 @@ import * as o from './output_ast';
|
|||||||
|
|
||||||
const _debugFilePath = '/debug/lib';
|
const _debugFilePath = '/debug/lib';
|
||||||
|
|
||||||
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
export function debugOutputAstAsTypeScript(ast: o.Statement|o.Expression|o.Type|any[]): string {
|
||||||
string {
|
|
||||||
const converter = new _TsEmitterVisitor();
|
const converter = new _TsEmitterVisitor();
|
||||||
const ctx = EmitterVisitorContext.createRoot();
|
const ctx = EmitterVisitorContext.createRoot();
|
||||||
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
||||||
@ -147,7 +146,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
reexports = [];
|
reexports = [];
|
||||||
this.reexports.set(moduleName, reexports);
|
this.reexports.set(moduleName, reexports);
|
||||||
}
|
}
|
||||||
reexports.push({name: name !, as: stmt.name});
|
reexports.push({name: name!, as: stmt.name});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +174,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
|
|
||||||
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
|
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
|
||||||
ctx.print(ast, `(<`);
|
ctx.print(ast, `(<`);
|
||||||
ast.type !.visitType(this, ctx);
|
ast.type!.visitType(this, ctx);
|
||||||
ctx.print(ast, `>`);
|
ctx.print(ast, `>`);
|
||||||
ast.value.visitExpression(this, ctx);
|
ast.value.visitExpression(this, ctx);
|
||||||
ctx.print(ast, `)`);
|
ctx.print(ast, `)`);
|
||||||
@ -422,7 +421,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
}
|
}
|
||||||
ctx.print(null, `${prefix}.`);
|
ctx.print(null, `${prefix}.`);
|
||||||
}
|
}
|
||||||
ctx.print(null, name !);
|
ctx.print(null, name!);
|
||||||
|
|
||||||
if (this.typeExpression > 0) {
|
if (this.typeExpression > 0) {
|
||||||
// If we are in a type expression that refers to a generic type then supply
|
// If we are in a type expression that refers to a generic type then supply
|
||||||
@ -433,7 +432,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
const suppliedParameters = typeParams || [];
|
const suppliedParameters = typeParams || [];
|
||||||
if (suppliedParameters.length > 0) {
|
if (suppliedParameters.length > 0) {
|
||||||
ctx.print(null, `<`);
|
ctx.print(null, `<`);
|
||||||
this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
|
this.visitAllObjects(type => type.visitType(this, ctx), typeParams!, ctx, ',');
|
||||||
ctx.print(null, `>`);
|
ctx.print(null, `>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import * as o from './output_ast';
|
|||||||
export const QUOTED_KEYS = '$quoted$';
|
export const QUOTED_KEYS = '$quoted$';
|
||||||
|
|
||||||
export function convertValueToOutputAst(
|
export function convertValueToOutputAst(
|
||||||
ctx: OutputContext, value: any, type: o.Type | null = null): o.Expression {
|
ctx: OutputContext, value: any, type: o.Type|null = null): o.Expression {
|
||||||
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
|
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,9 @@ class _ValueOutputAstTransformer implements ValueTransformer {
|
|||||||
return new o.LiteralMapExpr(entries, type);
|
return new o.LiteralMapExpr(entries, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPrimitive(value: any, type: o.Type): o.Expression { return o.literal(value, type); }
|
visitPrimitive(value: any, type: o.Type): o.Expression {
|
||||||
|
return o.literal(value, type);
|
||||||
|
}
|
||||||
|
|
||||||
visitOther(value: any, type: o.Type): o.Expression {
|
visitOther(value: any, type: o.Type): o.Expression {
|
||||||
if (value instanceof o.Expression) {
|
if (value instanceof o.Expression) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileReflector} from './compile_reflector';
|
import {CompileReflector} from './compile_reflector';
|
||||||
import {Pipe, Type, createPipe} from './core';
|
import {createPipe, Pipe, Type} from './core';
|
||||||
import {findLast} from './directive_resolver';
|
import {findLast} from './directive_resolver';
|
||||||
import {resolveForwardRef, stringify} from './util';
|
import {resolveForwardRef, stringify} from './util';
|
||||||
|
|
||||||
|
@ -9,12 +9,14 @@
|
|||||||
|
|
||||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenName, tokenReference} from './compile_metadata';
|
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenName, tokenReference} from './compile_metadata';
|
||||||
import {CompileReflector} from './compile_reflector';
|
import {CompileReflector} from './compile_reflector';
|
||||||
import {Identifiers, createTokenForExternalReference} from './identifiers';
|
import {createTokenForExternalReference, Identifiers} from './identifiers';
|
||||||
import {ParseError, ParseSourceSpan} from './parse_util';
|
import {ParseError, ParseSourceSpan} from './parse_util';
|
||||||
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst} from './template_parser/template_ast';
|
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst} from './template_parser/template_ast';
|
||||||
|
|
||||||
export class ProviderError extends ParseError {
|
export class ProviderError extends ParseError {
|
||||||
constructor(message: string, span: ParseSourceSpan) { super(span, message); }
|
constructor(message: string, span: ParseSourceSpan) {
|
||||||
|
super(span, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryWithId {
|
export interface QueryWithId {
|
||||||
@ -125,7 +127,9 @@ export class ProviderElementContext {
|
|||||||
|
|
||||||
get queryMatches(): QueryMatch[] {
|
get queryMatches(): QueryMatch[] {
|
||||||
const allMatches: QueryMatch[] = [];
|
const allMatches: QueryMatch[] = [];
|
||||||
this._queriedTokens.forEach((matches: QueryMatch[]) => { allMatches.push(...matches); });
|
this._queriedTokens.forEach((matches: QueryMatch[]) => {
|
||||||
|
allMatches.push(...matches);
|
||||||
|
});
|
||||||
return allMatches;
|
return allMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +175,8 @@ export class ProviderElementContext {
|
|||||||
requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
|
requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
|
||||||
eager: boolean): ProviderAst|null {
|
eager: boolean): ProviderAst|null {
|
||||||
const resolvedProvider = this._allProviders.get(tokenReference(token));
|
const resolvedProvider = this._allProviders.get(tokenReference(token));
|
||||||
if (!resolvedProvider || ((requestingProviderType === ProviderAstType.Directive ||
|
if (!resolvedProvider ||
|
||||||
|
((requestingProviderType === ProviderAstType.Directive ||
|
||||||
requestingProviderType === ProviderAstType.PublicService) &&
|
requestingProviderType === ProviderAstType.PublicService) &&
|
||||||
resolvedProvider.providerType === ProviderAstType.PrivateService) ||
|
resolvedProvider.providerType === ProviderAstType.PrivateService) ||
|
||||||
((requestingProviderType === ProviderAstType.PrivateService ||
|
((requestingProviderType === ProviderAstType.PrivateService ||
|
||||||
@ -191,25 +196,25 @@ export class ProviderElementContext {
|
|||||||
this._seenProviders.set(tokenReference(token), true);
|
this._seenProviders.set(tokenReference(token), true);
|
||||||
const transformedProviders = resolvedProvider.providers.map((provider) => {
|
const transformedProviders = resolvedProvider.providers.map((provider) => {
|
||||||
let transformedUseValue = provider.useValue;
|
let transformedUseValue = provider.useValue;
|
||||||
let transformedUseExisting = provider.useExisting !;
|
let transformedUseExisting = provider.useExisting!;
|
||||||
let transformedDeps: CompileDiDependencyMetadata[] = undefined !;
|
let transformedDeps: CompileDiDependencyMetadata[] = undefined!;
|
||||||
if (provider.useExisting != null) {
|
if (provider.useExisting != null) {
|
||||||
const existingDiDep = this._getDependency(
|
const existingDiDep = this._getDependency(
|
||||||
resolvedProvider.providerType, {token: provider.useExisting}, eager) !;
|
resolvedProvider.providerType, {token: provider.useExisting}, eager)!;
|
||||||
if (existingDiDep.token != null) {
|
if (existingDiDep.token != null) {
|
||||||
transformedUseExisting = existingDiDep.token;
|
transformedUseExisting = existingDiDep.token;
|
||||||
} else {
|
} else {
|
||||||
transformedUseExisting = null !;
|
transformedUseExisting = null!;
|
||||||
transformedUseValue = existingDiDep.value;
|
transformedUseValue = existingDiDep.value;
|
||||||
}
|
}
|
||||||
} else if (provider.useFactory) {
|
} else if (provider.useFactory) {
|
||||||
const deps = provider.deps || provider.useFactory.diDeps;
|
const deps = provider.deps || provider.useFactory.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager) !);
|
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)!);
|
||||||
} else if (provider.useClass) {
|
} else if (provider.useClass) {
|
||||||
const deps = provider.deps || provider.useClass.diDeps;
|
const deps = provider.deps || provider.useClass.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager) !);
|
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)!);
|
||||||
}
|
}
|
||||||
return _transformProvider(provider, {
|
return _transformProvider(provider, {
|
||||||
useExisting: transformedUseExisting,
|
useExisting: transformedUseExisting,
|
||||||
@ -227,7 +232,7 @@ export class ProviderElementContext {
|
|||||||
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata,
|
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata,
|
||||||
eager: boolean = false): CompileDiDependencyMetadata|null {
|
eager: boolean = false): CompileDiDependencyMetadata|null {
|
||||||
if (dep.isAttribute) {
|
if (dep.isAttribute) {
|
||||||
const attrValue = this._attrs[dep.token !.value];
|
const attrValue = this._attrs[dep.token!.value];
|
||||||
return {isValue: true, value: attrValue == null ? null : attrValue};
|
return {isValue: true, value: attrValue == null ? null : attrValue};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +253,7 @@ export class ProviderElementContext {
|
|||||||
}
|
}
|
||||||
if (tokenReference(dep.token) ===
|
if (tokenReference(dep.token) ===
|
||||||
this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
|
this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
|
||||||
(this as{transformedHasViewContainer: boolean}).transformedHasViewContainer = true;
|
(this as {transformedHasViewContainer: boolean}).transformedHasViewContainer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// access the injector
|
// access the injector
|
||||||
@ -290,8 +295,8 @@ export class ProviderElementContext {
|
|||||||
// check @Host restriction
|
// check @Host restriction
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!dep.isHost || this.viewContext.component.isHost ||
|
if (!dep.isHost || this.viewContext.component.isHost ||
|
||||||
this.viewContext.component.type.reference === tokenReference(dep.token !) ||
|
this.viewContext.component.type.reference === tokenReference(dep.token!) ||
|
||||||
this.viewContext.viewProviders.get(tokenReference(dep.token !)) != null) {
|
this.viewContext.viewProviders.get(tokenReference(dep.token!)) != null) {
|
||||||
result = dep;
|
result = dep;
|
||||||
} else {
|
} else {
|
||||||
result = dep.isOptional ? {isValue: true, value: null} : null;
|
result = dep.isOptional ? {isValue: true, value: null} : null;
|
||||||
@ -368,15 +373,15 @@ export class NgModuleProviderAnalyzer {
|
|||||||
this._seenProviders.set(tokenReference(token), true);
|
this._seenProviders.set(tokenReference(token), true);
|
||||||
const transformedProviders = resolvedProvider.providers.map((provider) => {
|
const transformedProviders = resolvedProvider.providers.map((provider) => {
|
||||||
let transformedUseValue = provider.useValue;
|
let transformedUseValue = provider.useValue;
|
||||||
let transformedUseExisting = provider.useExisting !;
|
let transformedUseExisting = provider.useExisting!;
|
||||||
let transformedDeps: CompileDiDependencyMetadata[] = undefined !;
|
let transformedDeps: CompileDiDependencyMetadata[] = undefined!;
|
||||||
if (provider.useExisting != null) {
|
if (provider.useExisting != null) {
|
||||||
const existingDiDep =
|
const existingDiDep =
|
||||||
this._getDependency({token: provider.useExisting}, eager, resolvedProvider.sourceSpan);
|
this._getDependency({token: provider.useExisting}, eager, resolvedProvider.sourceSpan);
|
||||||
if (existingDiDep.token != null) {
|
if (existingDiDep.token != null) {
|
||||||
transformedUseExisting = existingDiDep.token;
|
transformedUseExisting = existingDiDep.token;
|
||||||
} else {
|
} else {
|
||||||
transformedUseExisting = null !;
|
transformedUseExisting = null!;
|
||||||
transformedUseValue = existingDiDep.value;
|
transformedUseValue = existingDiDep.value;
|
||||||
}
|
}
|
||||||
} else if (provider.useFactory) {
|
} else if (provider.useFactory) {
|
||||||
@ -478,7 +483,8 @@ function _resolveProviders(
|
|||||||
let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
|
let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
|
||||||
if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
|
if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
|
||||||
targetErrors.push(new ProviderError(
|
targetErrors.push(new ProviderError(
|
||||||
`Mixing multi and non multi provider is not possible for token ${tokenName(resolvedProvider.token)}`,
|
`Mixing multi and non multi provider is not possible for token ${
|
||||||
|
tokenName(resolvedProvider.token)}`,
|
||||||
sourceSpan));
|
sourceSpan));
|
||||||
}
|
}
|
||||||
if (!resolvedProvider) {
|
if (!resolvedProvider) {
|
||||||
|
@ -18,19 +18,25 @@ export interface Node {
|
|||||||
|
|
||||||
export class Text implements Node {
|
export class Text implements Node {
|
||||||
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitText(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitText(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BoundText implements Node {
|
export class BoundText implements Node {
|
||||||
constructor(public value: AST, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
|
constructor(public value: AST, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundText(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitBoundText(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextAttribute implements Node {
|
export class TextAttribute implements Node {
|
||||||
constructor(
|
constructor(
|
||||||
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
||||||
public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {}
|
public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTextAttribute(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitTextAttribute(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BoundAttribute implements Node {
|
export class BoundAttribute implements Node {
|
||||||
@ -45,7 +51,9 @@ export class BoundAttribute implements Node {
|
|||||||
prop.valueSpan, i18n);
|
prop.valueSpan, i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundAttribute(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitBoundAttribute(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BoundEvent implements Node {
|
export class BoundEvent implements Node {
|
||||||
@ -62,7 +70,9 @@ export class BoundEvent implements Node {
|
|||||||
event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan);
|
event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundEvent(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitBoundEvent(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Element implements Node {
|
export class Element implements Node {
|
||||||
@ -76,7 +86,9 @@ export class Element implements Node {
|
|||||||
this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end);
|
this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitElement(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitElement(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Template implements Node {
|
export class Template implements Node {
|
||||||
@ -86,36 +98,46 @@ export class Template implements Node {
|
|||||||
public children: Node[], public references: Reference[], public variables: Variable[],
|
public children: Node[], public references: Reference[], public variables: Variable[],
|
||||||
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null,
|
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null,
|
||||||
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {}
|
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTemplate(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitTemplate(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Content implements Node {
|
export class Content implements Node {
|
||||||
constructor(
|
constructor(
|
||||||
public selector: string, public attributes: TextAttribute[],
|
public selector: string, public attributes: TextAttribute[],
|
||||||
public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
|
public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitContent(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitContent(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Variable implements Node {
|
export class Variable implements Node {
|
||||||
constructor(
|
constructor(
|
||||||
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
||||||
public valueSpan?: ParseSourceSpan) {}
|
public valueSpan?: ParseSourceSpan) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitVariable(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitVariable(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Reference implements Node {
|
export class Reference implements Node {
|
||||||
constructor(
|
constructor(
|
||||||
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
||||||
public valueSpan?: ParseSourceSpan) {}
|
public valueSpan?: ParseSourceSpan) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitReference(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitReference(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Icu implements Node {
|
export class Icu implements Node {
|
||||||
constructor(
|
constructor(
|
||||||
public vars: {[name: string]: BoundText},
|
public vars: {[name: string]: BoundText},
|
||||||
public placeholders: {[name: string]: Text | BoundText}, public sourceSpan: ParseSourceSpan,
|
public placeholders: {[name: string]: Text|BoundText}, public sourceSpan: ParseSourceSpan,
|
||||||
public i18n?: I18nMeta) {}
|
public i18n?: I18nMeta) {}
|
||||||
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitIcu(this); }
|
visit<Result>(visitor: Visitor<Result>): Result {
|
||||||
|
return visitor.visitIcu(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Visitor<Result = any> {
|
export interface Visitor<Result = any> {
|
||||||
@ -210,16 +232,34 @@ export class TransformVisitor implements Visitor<Node> {
|
|||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitContent(content: Content): Node { return content; }
|
visitContent(content: Content): Node {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
visitVariable(variable: Variable): Node { return variable; }
|
visitVariable(variable: Variable): Node {
|
||||||
visitReference(reference: Reference): Node { return reference; }
|
return variable;
|
||||||
visitTextAttribute(attribute: TextAttribute): Node { return attribute; }
|
}
|
||||||
visitBoundAttribute(attribute: BoundAttribute): Node { return attribute; }
|
visitReference(reference: Reference): Node {
|
||||||
visitBoundEvent(attribute: BoundEvent): Node { return attribute; }
|
return reference;
|
||||||
visitText(text: Text): Node { return text; }
|
}
|
||||||
visitBoundText(text: BoundText): Node { return text; }
|
visitTextAttribute(attribute: TextAttribute): Node {
|
||||||
visitIcu(icu: Icu): Node { return icu; }
|
return attribute;
|
||||||
|
}
|
||||||
|
visitBoundAttribute(attribute: BoundAttribute): Node {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
visitBoundEvent(attribute: BoundEvent): Node {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
visitText(text: Text): Node {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
visitBoundText(text: BoundText): Node {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
visitIcu(icu: Icu): Node {
|
||||||
|
return icu;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function visitAll<Result>(visitor: Visitor<Result>, nodes: Node[]): Result[] {
|
export function visitAll<Result>(visitor: Visitor<Result>, nodes: Node[]): Result[] {
|
||||||
|
@ -89,8 +89,8 @@ export interface R3ExpressionFactoryMetadata extends R3ConstructorFactoryMetadat
|
|||||||
expression: o.Expression;
|
expression: o.Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type R3FactoryMetadata = R3ConstructorFactoryMetadata | R3DelegatedFactoryMetadata |
|
export type R3FactoryMetadata = R3ConstructorFactoryMetadata|R3DelegatedFactoryMetadata|
|
||||||
R3DelegatedFnOrClassMetadata | R3ExpressionFactoryMetadata;
|
R3DelegatedFnOrClassMetadata|R3ExpressionFactoryMetadata;
|
||||||
|
|
||||||
export enum R3FactoryTarget {
|
export enum R3FactoryTarget {
|
||||||
Directive = 0,
|
Directive = 0,
|
||||||
@ -280,8 +280,7 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn {
|
|||||||
`${meta.name}_Factory`),
|
`${meta.name}_Factory`),
|
||||||
statements,
|
statements,
|
||||||
type: o.expressionType(o.importExpr(
|
type: o.expressionType(o.importExpr(
|
||||||
R3.FactoryDef,
|
R3.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]))
|
||||||
[typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +401,8 @@ export function dependenciesFromGlobalMetadata(
|
|||||||
// Construct the dependency.
|
// Construct the dependency.
|
||||||
deps.push({
|
deps.push({
|
||||||
token,
|
token,
|
||||||
attribute: null, resolved,
|
attribute: null,
|
||||||
|
resolved,
|
||||||
host: !!dependency.isHost,
|
host: !!dependency.isHost,
|
||||||
optional: !!dependency.isOptional,
|
optional: !!dependency.isOptional,
|
||||||
self: !!dependency.isSelf,
|
self: !!dependency.isSelf,
|
||||||
|
@ -21,28 +21,44 @@ export class R3JitReflector implements CompileReflector {
|
|||||||
resolveExternalReference(ref: o.ExternalReference): any {
|
resolveExternalReference(ref: o.ExternalReference): any {
|
||||||
// This reflector only handles @angular/core imports.
|
// This reflector only handles @angular/core imports.
|
||||||
if (ref.moduleName !== '@angular/core') {
|
if (ref.moduleName !== '@angular/core') {
|
||||||
throw new Error(
|
throw new Error(`Cannot resolve external reference to ${
|
||||||
`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
|
ref.moduleName}, only references to @angular/core are supported.`);
|
||||||
}
|
}
|
||||||
if (!this.context.hasOwnProperty(ref.name !)) {
|
if (!this.context.hasOwnProperty(ref.name!)) {
|
||||||
throw new Error(`No value provided for @angular/core symbol '${ref.name!}'.`);
|
throw new Error(`No value provided for @angular/core symbol '${ref.name!}'.`);
|
||||||
}
|
}
|
||||||
return this.context[ref.name !];
|
return this.context[ref.name!];
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters(typeOrFunc: any): any[][] { throw new Error('Not implemented.'); }
|
parameters(typeOrFunc: any): any[][] {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
annotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); }
|
annotations(typeOrFunc: any): any[] {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
shallowAnnotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); }
|
shallowAnnotations(typeOrFunc: any): any[] {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
tryAnnotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); }
|
tryAnnotations(typeOrFunc: any): any[] {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
propMetadata(typeOrFunc: any): {[key: string]: any[];} { throw new Error('Not implemented.'); }
|
propMetadata(typeOrFunc: any): {[key: string]: any[];} {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
hasLifecycleHook(type: any, lcProperty: string): boolean { throw new Error('Not implemented.'); }
|
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
guards(typeOrFunc: any): {[key: string]: any;} { throw new Error('Not implemented.'); }
|
guards(typeOrFunc: any): {[key: string]: any;} {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
componentModuleUrl(type: any, cmpMetadata: any): string { throw new Error('Not implemented.'); }
|
componentModuleUrl(type: any, cmpMetadata: any): string {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ import {mapLiteral} from '../output/map_util';
|
|||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {OutputContext} from '../util';
|
import {OutputContext} from '../util';
|
||||||
|
|
||||||
import {R3DependencyMetadata, R3FactoryTarget, compileFactoryFunction} from './r3_factory';
|
import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget} from './r3_factory';
|
||||||
import {Identifiers as R3} from './r3_identifiers';
|
import {Identifiers as R3} from './r3_identifiers';
|
||||||
import {R3Reference, convertMetaToOutput, jitOnlyGuardedExpression, mapToMapExpression} from './util';
|
import {convertMetaToOutput, jitOnlyGuardedExpression, mapToMapExpression, R3Reference} from './util';
|
||||||
|
|
||||||
export interface R3NgModuleDef {
|
export interface R3NgModuleDef {
|
||||||
expression: o.Expression;
|
expression: o.Expression;
|
||||||
@ -108,9 +108,7 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef {
|
|||||||
} = meta;
|
} = meta;
|
||||||
|
|
||||||
const additionalStatements: o.Statement[] = [];
|
const additionalStatements: o.Statement[] = [];
|
||||||
const definitionMap = {
|
const definitionMap = {type: internalType} as {
|
||||||
type: internalType
|
|
||||||
} as{
|
|
||||||
type: o.Expression,
|
type: o.Expression,
|
||||||
bootstrap: o.Expression,
|
bootstrap: o.Expression,
|
||||||
declarations: o.Expression,
|
declarations: o.Expression,
|
||||||
@ -177,7 +175,7 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef {
|
|||||||
function generateSetNgModuleScopeCall(meta: R3NgModuleMetadata): o.Statement|null {
|
function generateSetNgModuleScopeCall(meta: R3NgModuleMetadata): o.Statement|null {
|
||||||
const {adjacentType: moduleType, declarations, imports, exports, containsForwardDecls} = meta;
|
const {adjacentType: moduleType, declarations, imports, exports, containsForwardDecls} = meta;
|
||||||
|
|
||||||
const scopeMap = {} as{
|
const scopeMap = {} as {
|
||||||
declarations: o.Expression,
|
declarations: o.Expression,
|
||||||
imports: o.Expression,
|
imports: o.Expression,
|
||||||
exports: o.Expression,
|
exports: o.Expression,
|
||||||
@ -247,7 +245,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef {
|
|||||||
});
|
});
|
||||||
const definitionMap = {
|
const definitionMap = {
|
||||||
factory: result.factory,
|
factory: result.factory,
|
||||||
} as{factory: o.Expression, providers: o.Expression, imports: o.Expression};
|
} as {factory: o.Expression, providers: o.Expression, imports: o.Expression};
|
||||||
|
|
||||||
if (meta.providers !== null) {
|
if (meta.providers !== null) {
|
||||||
definitionMap.providers = meta.providers;
|
definitionMap.providers = meta.providers;
|
||||||
@ -267,7 +265,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef {
|
|||||||
export function compileNgModuleFromRender2(
|
export function compileNgModuleFromRender2(
|
||||||
ctx: OutputContext, ngModule: CompileShallowModuleMetadata,
|
ctx: OutputContext, ngModule: CompileShallowModuleMetadata,
|
||||||
injectableCompiler: InjectableCompiler): void {
|
injectableCompiler: InjectableCompiler): void {
|
||||||
const className = identifierName(ngModule.type) !;
|
const className = identifierName(ngModule.type)!;
|
||||||
|
|
||||||
const rawImports = ngModule.rawImports ? [ngModule.rawImports] : [];
|
const rawImports = ngModule.rawImports ? [ngModule.rawImports] : [];
|
||||||
const rawExports = ngModule.rawExports ? [ngModule.rawExports] : [];
|
const rawExports = ngModule.rawExports ? [ngModule.rawExports] : [];
|
||||||
@ -288,7 +286,8 @@ export function compileNgModuleFromRender2(
|
|||||||
/* name */ 'ɵinj',
|
/* name */ 'ɵinj',
|
||||||
/* type */ o.INFERRED_TYPE,
|
/* type */ o.INFERRED_TYPE,
|
||||||
/* modifiers */[o.StmtModifier.Static],
|
/* modifiers */[o.StmtModifier.Static],
|
||||||
/* initializer */ injectorDef, )],
|
/* initializer */ injectorDef,
|
||||||
|
)],
|
||||||
/* getters */[],
|
/* getters */[],
|
||||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||||
/* methods */[]));
|
/* methods */[]));
|
||||||
|
@ -10,9 +10,9 @@ import {CompilePipeMetadata, identifierName} from '../compile_metadata';
|
|||||||
import {CompileReflector} from '../compile_reflector';
|
import {CompileReflector} from '../compile_reflector';
|
||||||
import {DefinitionKind} from '../constant_pool';
|
import {DefinitionKind} from '../constant_pool';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {OutputContext, error} from '../util';
|
import {error, OutputContext} from '../util';
|
||||||
|
|
||||||
import {R3DependencyMetadata, R3FactoryTarget, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory';
|
import {compileFactoryFunction, dependenciesFromGlobalMetadata, R3DependencyMetadata, R3FactoryTarget} from './r3_factory';
|
||||||
import {Identifiers as R3} from './r3_identifiers';
|
import {Identifiers as R3} from './r3_identifiers';
|
||||||
import {R3Reference, typeWithParameters, wrapReference} from './util';
|
import {R3Reference, typeWithParameters, wrapReference} from './util';
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ class HtmlAstToIvyAst implements html.Visitor {
|
|||||||
// Moreover, if the node is an element, then we need to hoist its attributes to the template
|
// Moreover, if the node is an element, then we need to hoist its attributes to the template
|
||||||
// node for matching against content projection selectors.
|
// node for matching against content projection selectors.
|
||||||
const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
|
const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
|
||||||
const templateAttrs: (t.TextAttribute | t.BoundAttribute)[] = [];
|
const templateAttrs: (t.TextAttribute|t.BoundAttribute)[] = [];
|
||||||
attrs.literal.forEach(attr => templateAttrs.push(attr));
|
attrs.literal.forEach(attr => templateAttrs.push(attr));
|
||||||
attrs.bound.forEach(attr => templateAttrs.push(attr));
|
attrs.bound.forEach(attr => templateAttrs.push(attr));
|
||||||
const hoistedAttrs = parsedElement instanceof t.Element ?
|
const hoistedAttrs = parsedElement instanceof t.Element ?
|
||||||
@ -260,12 +260,12 @@ class HtmlAstToIvyAst implements html.Visitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!isI18nRootNode(expansion.i18n)) {
|
if (!isI18nRootNode(expansion.i18n)) {
|
||||||
throw new Error(
|
throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${
|
||||||
`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`);
|
expansion.sourceSpan.toString()}. Expected a "Message"`);
|
||||||
}
|
}
|
||||||
const message = expansion.i18n;
|
const message = expansion.i18n;
|
||||||
const vars: {[name: string]: t.BoundText} = {};
|
const vars: {[name: string]: t.BoundText} = {};
|
||||||
const placeholders: {[name: string]: t.Text | t.BoundText} = {};
|
const placeholders: {[name: string]: t.Text|t.BoundText} = {};
|
||||||
// extract VARs from ICUs - we process them separately while
|
// extract VARs from ICUs - we process them separately while
|
||||||
// assembling resulting message via goog.getMsg function, since
|
// assembling resulting message via goog.getMsg function, since
|
||||||
// we need to pass them to top-level goog.getMsg call
|
// we need to pass them to top-level goog.getMsg call
|
||||||
@ -284,9 +284,13 @@ class HtmlAstToIvyAst implements html.Visitor {
|
|||||||
return new t.Icu(vars, placeholders, expansion.sourceSpan, message);
|
return new t.Icu(vars, placeholders, expansion.sourceSpan, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase): null { return null; }
|
visitExpansionCase(expansionCase: html.ExpansionCase): null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitComment(comment: html.Comment): null { return null; }
|
visitComment(comment: html.Comment): null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// convert view engine `ParsedProperty` to a format suitable for IVY
|
// convert view engine `ParsedProperty` to a format suitable for IVY
|
||||||
private extractAttributes(
|
private extractAttributes(
|
||||||
@ -460,18 +464,26 @@ class NonBindableVisitor implements html.Visitor {
|
|||||||
ast.startSourceSpan, ast.endSourceSpan);
|
ast.startSourceSpan, ast.endSourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitComment(comment: html.Comment): any { return null; }
|
visitComment(comment: html.Comment): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitAttribute(attribute: html.Attribute): t.TextAttribute {
|
visitAttribute(attribute: html.Attribute): t.TextAttribute {
|
||||||
return new t.TextAttribute(
|
return new t.TextAttribute(
|
||||||
attribute.name, attribute.value, attribute.sourceSpan, undefined, attribute.i18n);
|
attribute.name, attribute.value, attribute.sourceSpan, undefined, attribute.i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: html.Text): t.Text { return new t.Text(text.value, text.sourceSpan); }
|
visitText(text: html.Text): t.Text {
|
||||||
|
return new t.Text(text.value, text.sourceSpan);
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansion(expansion: html.Expansion): any { return null; }
|
visitExpansion(expansion: html.Expansion): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase): any { return null; }
|
visitExpansionCase(expansionCase: html.ExpansionCase): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
||||||
|
@ -13,14 +13,13 @@ import {OutputContext} from '../util';
|
|||||||
/**
|
/**
|
||||||
* Convert an object map with `Expression` values into a `LiteralMapExpr`.
|
* Convert an object map with `Expression` values into a `LiteralMapExpr`.
|
||||||
*/
|
*/
|
||||||
export function mapToMapExpression(map: {[key: string]: o.Expression | undefined}):
|
export function mapToMapExpression(map: {[key: string]: o.Expression|undefined}): o.LiteralMapExpr {
|
||||||
o.LiteralMapExpr {
|
|
||||||
const result = Object.keys(map).map(
|
const result = Object.keys(map).map(
|
||||||
key => ({
|
key => ({
|
||||||
key,
|
key,
|
||||||
// The assertion here is because really TypeScript doesn't allow us to express that if the
|
// The assertion here is because really TypeScript doesn't allow us to express that if the
|
||||||
// key is present, it will have a value, but this is true in reality.
|
// key is present, it will have a value, but this is true in reality.
|
||||||
value: map[key] !,
|
value: map[key]!,
|
||||||
quoted: false,
|
quoted: false,
|
||||||
}));
|
}));
|
||||||
return o.literalMap(result);
|
return o.literalMap(result);
|
||||||
|
@ -88,7 +88,7 @@ export interface R3DirectiveMetadata {
|
|||||||
/**
|
/**
|
||||||
* A mapping of input field names to the property names.
|
* A mapping of input field names to the property names.
|
||||||
*/
|
*/
|
||||||
inputs: {[field: string]: string | [string, string]};
|
inputs: {[field: string]: string|[string, string]};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping of output field names to the property names.
|
* A mapping of output field names to the property names.
|
||||||
|
@ -20,17 +20,17 @@ import {CssSelector, SelectorMatcher} from '../../selector';
|
|||||||
import {ShadowCss} from '../../shadow_css';
|
import {ShadowCss} from '../../shadow_css';
|
||||||
import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler';
|
import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler';
|
||||||
import {BindingParser} from '../../template_parser/binding_parser';
|
import {BindingParser} from '../../template_parser/binding_parser';
|
||||||
import {OutputContext, error} from '../../util';
|
import {error, OutputContext} from '../../util';
|
||||||
import {BoundEvent} from '../r3_ast';
|
import {BoundEvent} from '../r3_ast';
|
||||||
import {R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType, compileFactoryFunction} from '../r3_factory';
|
import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType} from '../r3_factory';
|
||||||
import {Identifiers as R3} from '../r3_identifiers';
|
import {Identifiers as R3} from '../r3_identifiers';
|
||||||
import {Render3ParseResult} from '../r3_template_transform';
|
import {Render3ParseResult} from '../r3_template_transform';
|
||||||
import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util';
|
import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util';
|
||||||
|
|
||||||
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from './api';
|
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from './api';
|
||||||
import {MIN_STYLING_BINDING_SLOTS_REQUIRED, StylingBuilder, StylingInstructionCall} from './styling_builder';
|
import {MIN_STYLING_BINDING_SLOTS_REQUIRED, StylingBuilder, StylingInstructionCall} from './styling_builder';
|
||||||
import {BindingScope, TemplateDefinitionBuilder, ValueConverter, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn} from './template';
|
import {BindingScope, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn, TemplateDefinitionBuilder, ValueConverter} from './template';
|
||||||
import {CONTEXT_NAME, DefinitionMap, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator} from './util';
|
import {asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, CONTEXT_NAME, DefinitionMap, getQueryPredicate, RENDER_FLAGS, TEMPORARY_NAME, temporaryAllocator} from './util';
|
||||||
|
|
||||||
const EMPTY_ARRAY: any[] = [];
|
const EMPTY_ARRAY: any[] = [];
|
||||||
|
|
||||||
@ -65,9 +65,10 @@ function baseDirectiveFields(
|
|||||||
|
|
||||||
// e.g. `hostBindings: (rf, ctx) => { ... }
|
// e.g. `hostBindings: (rf, ctx) => { ... }
|
||||||
definitionMap.set(
|
definitionMap.set(
|
||||||
'hostBindings', createHostBindingsFunction(
|
'hostBindings',
|
||||||
meta.host, meta.typeSourceSpan, bindingParser, constantPool,
|
createHostBindingsFunction(
|
||||||
meta.selector || '', meta.name, definitionMap));
|
meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '',
|
||||||
|
meta.name, definitionMap));
|
||||||
|
|
||||||
// e.g 'inputs: {a: 'a'}`
|
// e.g 'inputs: {a: 'a'}`
|
||||||
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
||||||
@ -85,8 +86,7 @@ function baseDirectiveFields(
|
|||||||
/**
|
/**
|
||||||
* Add features to the definition map.
|
* Add features to the definition map.
|
||||||
*/
|
*/
|
||||||
function addFeatures(
|
function addFeatures(definitionMap: DefinitionMap, meta: R3DirectiveMetadata|R3ComponentMetadata) {
|
||||||
definitionMap: DefinitionMap, meta: R3DirectiveMetadata | R3ComponentMetadata) {
|
|
||||||
// e.g. `features: [NgOnChangesFeature]`
|
// e.g. `features: [NgOnChangesFeature]`
|
||||||
const features: o.Expression[] = [];
|
const features: o.Expression[] = [];
|
||||||
|
|
||||||
@ -148,7 +148,8 @@ export function compileComponentFromMetadata(
|
|||||||
const selectorAttributes = firstSelector.getAttrs();
|
const selectorAttributes = firstSelector.getAttrs();
|
||||||
if (selectorAttributes.length) {
|
if (selectorAttributes.length) {
|
||||||
definitionMap.set(
|
definitionMap.set(
|
||||||
'attrs', constantPool.getConstLiteral(
|
'attrs',
|
||||||
|
constantPool.getConstLiteral(
|
||||||
o.literalArr(selectorAttributes.map(
|
o.literalArr(selectorAttributes.map(
|
||||||
value => value != null ? o.literal(value) : o.literal(undefined))),
|
value => value != null ? o.literal(value) : o.literal(undefined))),
|
||||||
/* forceShared */ true));
|
/* forceShared */ true));
|
||||||
@ -273,7 +274,7 @@ export function compileComponentFromMetadata(
|
|||||||
export function compileDirectiveFromRender2(
|
export function compileDirectiveFromRender2(
|
||||||
outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector,
|
outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector,
|
||||||
bindingParser: BindingParser) {
|
bindingParser: BindingParser) {
|
||||||
const name = identifierName(directive.type) !;
|
const name = identifierName(directive.type)!;
|
||||||
name || error(`Cannot resolver the name of ${directive.type}`);
|
name || error(`Cannot resolver the name of ${directive.type}`);
|
||||||
|
|
||||||
const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Directive);
|
const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Directive);
|
||||||
@ -306,7 +307,7 @@ export function compileComponentFromRender2(
|
|||||||
outputCtx: OutputContext, component: CompileDirectiveMetadata, render3Ast: Render3ParseResult,
|
outputCtx: OutputContext, component: CompileDirectiveMetadata, render3Ast: Render3ParseResult,
|
||||||
reflector: CompileReflector, bindingParser: BindingParser, directiveTypeBySel: Map<string, any>,
|
reflector: CompileReflector, bindingParser: BindingParser, directiveTypeBySel: Map<string, any>,
|
||||||
pipeTypeByName: Map<string, any>) {
|
pipeTypeByName: Map<string, any>) {
|
||||||
const name = identifierName(component.type) !;
|
const name = identifierName(component.type)!;
|
||||||
name || error(`Cannot resolver the name of ${component.type}`);
|
name || error(`Cannot resolver the name of ${component.type}`);
|
||||||
|
|
||||||
const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Component);
|
const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Component);
|
||||||
@ -372,7 +373,8 @@ function queriesFromGlobalMetadata(
|
|||||||
propertyName: query.propertyName,
|
propertyName: query.propertyName,
|
||||||
first: query.first,
|
first: query.first,
|
||||||
predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
|
predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
|
||||||
descendants: query.descendants, read,
|
descendants: query.descendants,
|
||||||
|
read,
|
||||||
static: !!query.static
|
static: !!query.static
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -464,7 +466,7 @@ function stringAsType(str: string): o.Type {
|
|||||||
return o.expressionType(o.literal(str));
|
return o.expressionType(o.literal(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringMapAsType(map: {[key: string]: string | string[]}): o.Type {
|
function stringMapAsType(map: {[key: string]: string|string[]}): o.Type {
|
||||||
const mapValues = Object.keys(map).map(key => {
|
const mapValues = Object.keys(map).map(key => {
|
||||||
const value = Array.isArray(map[key]) ? map[key][0] : map[key];
|
const value = Array.isArray(map[key]) ? map[key][0] : map[key];
|
||||||
return {
|
return {
|
||||||
@ -723,7 +725,7 @@ function convertStylingCall(
|
|||||||
function getBindingNameAndInstruction(binding: ParsedProperty):
|
function getBindingNameAndInstruction(binding: ParsedProperty):
|
||||||
{bindingName: string, instruction: o.ExternalReference, isAttribute: boolean} {
|
{bindingName: string, instruction: o.ExternalReference, isAttribute: boolean} {
|
||||||
let bindingName = binding.name;
|
let bindingName = binding.name;
|
||||||
let instruction !: o.ExternalReference;
|
let instruction!: o.ExternalReference;
|
||||||
|
|
||||||
// Check to see if this is an attr binding or a property binding
|
// Check to see if this is an attr binding or a property binding
|
||||||
const attrMatches = bindingName.match(ATTR_REGEX);
|
const attrMatches = bindingName.match(ATTR_REGEX);
|
||||||
@ -817,8 +819,7 @@ export interface ParsedHostBindings {
|
|||||||
specialAttributes: {styleAttr?: string; classAttr?: string;};
|
specialAttributes: {styleAttr?: string; classAttr?: string;};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseHostBindings(host: {[key: string]: string | o.Expression}):
|
export function parseHostBindings(host: {[key: string]: string|o.Expression}): ParsedHostBindings {
|
||||||
ParsedHostBindings {
|
|
||||||
const attributes: {[key: string]: o.Expression} = {};
|
const attributes: {[key: string]: o.Expression} = {};
|
||||||
const listeners: {[key: string]: string} = {};
|
const listeners: {[key: string]: string} = {};
|
||||||
const properties: {[key: string]: string} = {};
|
const properties: {[key: string]: string} = {};
|
||||||
@ -893,5 +894,7 @@ export function verifyHostBindings(
|
|||||||
|
|
||||||
function compileStyles(styles: string[], selector: string, hostSelector: string): string[] {
|
function compileStyles(styles: string[], selector: string, hostSelector: string): string[] {
|
||||||
const shadowCss = new ShadowCss();
|
const shadowCss = new ShadowCss();
|
||||||
return styles.map(style => { return shadowCss !.shimCssText(style, selector, hostSelector); });
|
return styles.map(style => {
|
||||||
|
return shadowCss!.shimCssText(style, selector, hostSelector);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ export class I18nContext {
|
|||||||
public placeholders = new Map<string, any[]>();
|
public placeholders = new Map<string, any[]>();
|
||||||
public isEmitted: boolean = false;
|
public isEmitted: boolean = false;
|
||||||
|
|
||||||
private _registry !: any;
|
private _registry!: any;
|
||||||
private _unresolvedCtxCount: number = 0;
|
private _unresolvedCtxCount: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -66,9 +66,15 @@ export class I18nContext {
|
|||||||
updatePlaceholderMap(this.placeholders, ph, content);
|
updatePlaceholderMap(this.placeholders, ph, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
get icus() { return this._registry.icus; }
|
get icus() {
|
||||||
get isRoot() { return this.level === 0; }
|
return this._registry.icus;
|
||||||
get isResolved() { return this._unresolvedCtxCount === 0; }
|
}
|
||||||
|
get isRoot() {
|
||||||
|
return this.level === 0;
|
||||||
|
}
|
||||||
|
get isResolved() {
|
||||||
|
return this._unresolvedCtxCount === 0;
|
||||||
|
}
|
||||||
|
|
||||||
getSerializedPlaceholders() {
|
getSerializedPlaceholders() {
|
||||||
const result = new Map<string, any[]>();
|
const result = new Map<string, any[]>();
|
||||||
@ -78,7 +84,9 @@ export class I18nContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// public API to accumulate i18n-related content
|
// public API to accumulate i18n-related content
|
||||||
appendBinding(binding: AST) { this.bindings.add(binding); }
|
appendBinding(binding: AST) {
|
||||||
|
this.bindings.add(binding);
|
||||||
|
}
|
||||||
appendIcu(name: string, ref: o.Expression) {
|
appendIcu(name: string, ref: o.Expression) {
|
||||||
updatePlaceholderMap(this._registry.icus, name, ref);
|
updatePlaceholderMap(this._registry.icus, name, ref);
|
||||||
}
|
}
|
||||||
@ -181,7 +189,7 @@ function wrapTag(symbol: string, {index, ctx, isVoid}: any, closed?: boolean): s
|
|||||||
wrap(symbol, index, ctx, closed);
|
wrap(symbol, index, ctx, closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findTemplateFn(ctx: number, templateIndex: number | null) {
|
function findTemplateFn(ctx: number, templateIndex: number|null) {
|
||||||
return (token: any) => typeof token === 'object' && token.type === TagType.TEMPLATE &&
|
return (token: any) => typeof token === 'object' && token.type === TagType.TEMPLATE &&
|
||||||
token.index === templateIndex && token.ctx === ctx;
|
token.index === templateIndex && token.ctx === ctx;
|
||||||
}
|
}
|
||||||
|
@ -47,23 +47,32 @@ export function createGoogleGetMsgStatements(
|
|||||||
* placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
|
* placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
|
||||||
*/
|
*/
|
||||||
class GetMsgSerializerVisitor implements i18n.Visitor {
|
class GetMsgSerializerVisitor implements i18n.Visitor {
|
||||||
private formatPh(value: string): string { return `{$${formatI18nPlaceholderName(value)}}`; }
|
private formatPh(value: string): string {
|
||||||
|
return `{$${formatI18nPlaceholderName(value)}}`;
|
||||||
|
}
|
||||||
|
|
||||||
visitText(text: i18n.Text): any { return text.value; }
|
visitText(text: i18n.Text): any {
|
||||||
|
return text.value;
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container): any {
|
visitContainer(container: i18n.Container): any {
|
||||||
return container.children.map(child => child.visit(this)).join('');
|
return container.children.map(child => child.visit(this)).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
visitIcu(icu: i18n.Icu): any { return serializeIcuNode(icu); }
|
visitIcu(icu: i18n.Icu): any {
|
||||||
|
return serializeIcuNode(icu);
|
||||||
|
}
|
||||||
|
|
||||||
visitTagPlaceholder(ph: i18n.TagPlaceholder): any {
|
visitTagPlaceholder(ph: i18n.TagPlaceholder): any {
|
||||||
return ph.isVoid ?
|
return ph.isVoid ?
|
||||||
this.formatPh(ph.startName) :
|
this.formatPh(ph.startName) :
|
||||||
`${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
|
`${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${
|
||||||
|
this.formatPh(ph.closeName)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPlaceholder(ph: i18n.Placeholder): any { return this.formatPh(ph.name); }
|
visitPlaceholder(ph: i18n.Placeholder): any {
|
||||||
|
return this.formatPh(ph.name);
|
||||||
|
}
|
||||||
|
|
||||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
||||||
return this.formatPh(ph.name);
|
return this.formatPh(ph.name);
|
||||||
|
@ -11,7 +11,9 @@ import * as i18n from '../../../i18n/i18n_ast';
|
|||||||
import {formatI18nPlaceholderName} from './util';
|
import {formatI18nPlaceholderName} from './util';
|
||||||
|
|
||||||
class IcuSerializerVisitor implements i18n.Visitor {
|
class IcuSerializerVisitor implements i18n.Visitor {
|
||||||
visitText(text: i18n.Text): any { return text.value; }
|
visitText(text: i18n.Text): any {
|
||||||
|
return text.value;
|
||||||
|
}
|
||||||
|
|
||||||
visitContainer(container: i18n.Container): any {
|
visitContainer(container: i18n.Container): any {
|
||||||
return container.children.map(child => child.visit(this)).join('');
|
return container.children.map(child => child.visit(this)).join('');
|
||||||
@ -27,10 +29,13 @@ class IcuSerializerVisitor implements i18n.Visitor {
|
|||||||
visitTagPlaceholder(ph: i18n.TagPlaceholder): any {
|
visitTagPlaceholder(ph: i18n.TagPlaceholder): any {
|
||||||
return ph.isVoid ?
|
return ph.isVoid ?
|
||||||
this.formatPh(ph.startName) :
|
this.formatPh(ph.startName) :
|
||||||
`${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
|
`${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${
|
||||||
|
this.formatPh(ph.closeName)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPlaceholder(ph: i18n.Placeholder): any { return this.formatPh(ph.name); }
|
visitPlaceholder(ph: i18n.Placeholder): any {
|
||||||
|
return this.formatPh(ph.name);
|
||||||
|
}
|
||||||
|
|
||||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
||||||
return this.formatPh(ph.name);
|
return this.formatPh(ph.name);
|
||||||
|
@ -28,7 +28,9 @@ class MessagePiece {
|
|||||||
}
|
}
|
||||||
class LiteralPiece extends MessagePiece {}
|
class LiteralPiece extends MessagePiece {}
|
||||||
class PlaceholderPiece extends MessagePiece {
|
class PlaceholderPiece extends MessagePiece {
|
||||||
constructor(name: string) { super(formatI18nPlaceholderName(name, /* useCamelCase */ false)); }
|
constructor(name: string) {
|
||||||
|
super(formatI18nPlaceholderName(name, /* useCamelCase */ false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
import {computeDecimalDigest, computeDigest, decimalDigest} from '../../../i18n/digest';
|
import {computeDecimalDigest, computeDigest, decimalDigest} from '../../../i18n/digest';
|
||||||
import * as i18n from '../../../i18n/i18n_ast';
|
import * as i18n from '../../../i18n/i18n_ast';
|
||||||
import {VisitNodeFn, createI18nMessageFactory} from '../../../i18n/i18n_parser';
|
import {createI18nMessageFactory, VisitNodeFn} from '../../../i18n/i18n_parser';
|
||||||
import * as html from '../../../ml_parser/ast';
|
import * as html from '../../../ml_parser/ast';
|
||||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../ml_parser/interpolation_config';
|
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../ml_parser/interpolation_config';
|
||||||
import * as o from '../../../output/output_ast';
|
import * as o from '../../../output/output_ast';
|
||||||
|
|
||||||
import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './util';
|
import {hasI18nAttrs, I18N_ATTR, I18N_ATTR_PREFIX, icuFromI18nMessage} from './util';
|
||||||
|
|
||||||
export type I18nMeta = {
|
export type I18nMeta = {
|
||||||
id?: string,
|
id?: string,
|
||||||
@ -134,10 +134,18 @@ export class I18nMetaVisitor implements html.Visitor {
|
|||||||
return expansion;
|
return expansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: html.Text): any { return text; }
|
visitText(text: html.Text): any {
|
||||||
visitAttribute(attribute: html.Attribute): any { return attribute; }
|
return text;
|
||||||
visitComment(comment: html.Comment): any { return comment; }
|
}
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase): any { return expansionCase; }
|
visitAttribute(attribute: html.Attribute): any {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
visitComment(comment: html.Comment): any {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
visitExpansionCase(expansionCase: html.ExpansionCase): any {
|
||||||
|
return expansionCase;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the general form `meta` passed into extract the explicit metadata needed to create a
|
* Parse the general form `meta` passed into extract the explicit metadata needed to create a
|
||||||
|
@ -49,7 +49,7 @@ export function icuFromI18nMessage(message: i18n.Message) {
|
|||||||
return message.nodes[0] as i18n.IcuPlaceholder;
|
return message.nodes[0] as i18n.IcuPlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapI18nPlaceholder(content: string | number, contextId: number = 0): string {
|
export function wrapI18nPlaceholder(content: string|number, contextId: number = 0): string {
|
||||||
const blockId = contextId > 0 ? `:${contextId}` : '';
|
const blockId = contextId > 0 ? `:${contextId}` : '';
|
||||||
return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
|
return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ export function formatI18nPlaceholderName(name: string, useCamelCase: boolean =
|
|||||||
if (/^\d+$/.test(chunks[chunks.length - 1])) {
|
if (/^\d+$/.test(chunks[chunks.length - 1])) {
|
||||||
postfix = chunks.pop();
|
postfix = chunks.pop();
|
||||||
}
|
}
|
||||||
let raw = chunks.shift() !.toLowerCase();
|
let raw = chunks.shift()!.toLowerCase();
|
||||||
if (chunks.length) {
|
if (chunks.length) {
|
||||||
raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
|
raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
|
||||||
}
|
}
|
||||||
@ -170,5 +170,5 @@ export function getTranslationConstPrefix(extra: string): string {
|
|||||||
*/
|
*/
|
||||||
export function declareI18nVariable(variable: o.ReadVarExpr): o.Statement {
|
export function declareI18nVariable(variable: o.ReadVarExpr): o.Statement {
|
||||||
return new o.DeclareVarStmt(
|
return new o.DeclareVarStmt(
|
||||||
variable.name !, undefined, o.INFERRED_TYPE, null, variable.sourceSpan);
|
variable.name!, undefined, o.INFERRED_TYPE, null, variable.sourceSpan);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,11 @@ export function stripUnnecessaryQuotes(value: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hyphenate(value: string): string {
|
export function hyphenate(value: string): string {
|
||||||
return value.replace(/[a-z][A-Z]/g, v => {
|
return value
|
||||||
|
.replace(
|
||||||
|
/[a-z][A-Z]/g,
|
||||||
|
v => {
|
||||||
return v.charAt(0) + '-' + v.charAt(1);
|
return v.charAt(0) + '-' + v.charAt(1);
|
||||||
}).toLowerCase();
|
})
|
||||||
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,10 @@ export class StylingBuilder {
|
|||||||
const entry: BoundStylingEntry = {
|
const entry: BoundStylingEntry = {
|
||||||
name: property,
|
name: property,
|
||||||
sanitize: property ? isStyleSanitizable(property) : true,
|
sanitize: property ? isStyleSanitizable(property) : true,
|
||||||
unit: unit || bindingUnit, value, sourceSpan, hasOverrideFlag
|
unit: unit || bindingUnit,
|
||||||
|
value,
|
||||||
|
sourceSpan,
|
||||||
|
hasOverrideFlag
|
||||||
};
|
};
|
||||||
if (isMapBased) {
|
if (isMapBased) {
|
||||||
this._styleMapInput = entry;
|
this._styleMapInput = entry;
|
||||||
@ -385,7 +388,7 @@ export class StylingBuilder {
|
|||||||
supportsInterpolation: true,
|
supportsInterpolation: true,
|
||||||
sourceSpan: stylingInput.sourceSpan,
|
sourceSpan: stylingInput.sourceSpan,
|
||||||
allocateBindingSlots: totalBindingSlotsRequired,
|
allocateBindingSlots: totalBindingSlotsRequired,
|
||||||
params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
|
params: (convertFn: (value: any) => o.Expression|o.Expression[]) => {
|
||||||
const convertResult = convertFn(mapValue);
|
const convertResult = convertFn(mapValue);
|
||||||
const params = Array.isArray(convertResult) ? convertResult : [convertResult];
|
const params = Array.isArray(convertResult) ? convertResult : [convertResult];
|
||||||
return params;
|
return params;
|
||||||
|
@ -22,7 +22,9 @@ import {BoundAttribute, BoundEvent, Element, Node, Reference, Template, TextAttr
|
|||||||
/**
|
/**
|
||||||
* A logical target for analysis, which could contain a template or other types of bindings.
|
* A logical target for analysis, which could contain a template or other types of bindings.
|
||||||
*/
|
*/
|
||||||
export interface Target { template?: Node[]; }
|
export interface Target {
|
||||||
|
template?: Node[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata regarding a directive that's needed to match it against template elements. This is
|
* Metadata regarding a directive that's needed to match it against template elements. This is
|
||||||
@ -44,7 +46,7 @@ export interface DirectiveMeta {
|
|||||||
*
|
*
|
||||||
* Goes from property names to field names.
|
* Goes from property names to field names.
|
||||||
*/
|
*/
|
||||||
inputs: {[property: string]: string | [string, string]};
|
inputs: {[property: string]: string|[string, string]};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of outputs which this directive claims.
|
* Set of outputs which this directive claims.
|
||||||
@ -67,7 +69,9 @@ export interface DirectiveMeta {
|
|||||||
*
|
*
|
||||||
* The returned `BoundTarget` has an API for extracting information about the processed target.
|
* The returned `BoundTarget` has an API for extracting information about the processed target.
|
||||||
*/
|
*/
|
||||||
export interface TargetBinder<D extends DirectiveMeta> { bind(target: Target): BoundTarget<D>; }
|
export interface TargetBinder<D extends DirectiveMeta> {
|
||||||
|
bind(target: Target): BoundTarget<D>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of performing the binding operation against a `Target`.
|
* Result of performing the binding operation against a `Target`.
|
||||||
|
@ -152,7 +152,7 @@ class Scope implements Visitor {
|
|||||||
lookup(name: string): Reference|Variable|null {
|
lookup(name: string): Reference|Variable|null {
|
||||||
if (this.namedEntities.has(name)) {
|
if (this.namedEntities.has(name)) {
|
||||||
// Found in the local scope.
|
// Found in the local scope.
|
||||||
return this.namedEntities.get(name) !;
|
return this.namedEntities.get(name)!;
|
||||||
} else if (this.parentScope !== undefined) {
|
} else if (this.parentScope !== undefined) {
|
||||||
// Not in the local scope, but there's a parent scope so check there.
|
// Not in the local scope, but there's a parent scope so check there.
|
||||||
return this.parentScope.lookup(name);
|
return this.parentScope.lookup(name);
|
||||||
@ -217,11 +217,17 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor {
|
|||||||
return {directives, bindings, references};
|
return {directives, bindings, references};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ingest(template: Node[]): void { template.forEach(node => node.visit(this)); }
|
private ingest(template: Node[]): void {
|
||||||
|
template.forEach(node => node.visit(this));
|
||||||
|
}
|
||||||
|
|
||||||
visitElement(element: Element): void { this.visitElementOrTemplate(element.name, element); }
|
visitElement(element: Element): void {
|
||||||
|
this.visitElementOrTemplate(element.name, element);
|
||||||
|
}
|
||||||
|
|
||||||
visitTemplate(template: Template): void { this.visitElementOrTemplate('ng-template', template); }
|
visitTemplate(template: Template): void {
|
||||||
|
this.visitElementOrTemplate('ng-template', template);
|
||||||
|
}
|
||||||
|
|
||||||
visitElementOrTemplate(elementName: string, node: Element|Template): void {
|
visitElementOrTemplate(elementName: string, node: Element|Template): void {
|
||||||
// First, determine the HTML shape of the node for the purpose of directive matching.
|
// First, determine the HTML shape of the node for the purpose of directive matching.
|
||||||
@ -269,7 +275,7 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Associate attributes/bindings on the node with directives or with the node itself.
|
// Associate attributes/bindings on the node with directives or with the node itself.
|
||||||
type BoundNode = BoundAttribute | BoundEvent | TextAttribute;
|
type BoundNode = BoundAttribute|BoundEvent|TextAttribute;
|
||||||
const setAttributeBinding =
|
const setAttributeBinding =
|
||||||
(attribute: BoundNode, ioType: keyof Pick<DirectiveMeta, 'inputs'|'outputs'>) => {
|
(attribute: BoundNode, ioType: keyof Pick<DirectiveMeta, 'inputs'|'outputs'>) => {
|
||||||
const dir = directives.find(dir => dir[ioType].hasOwnProperty(attribute.name));
|
const dir = directives.find(dir => dir[ioType].hasOwnProperty(attribute.name));
|
||||||
@ -432,11 +438,17 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
|
|||||||
|
|
||||||
// The remaining visitors are concerned with processing AST expressions within template bindings
|
// The remaining visitors are concerned with processing AST expressions within template bindings
|
||||||
|
|
||||||
visitBoundAttribute(attribute: BoundAttribute) { attribute.value.visit(this); }
|
visitBoundAttribute(attribute: BoundAttribute) {
|
||||||
|
attribute.value.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
visitBoundEvent(event: BoundEvent) { event.handler.visit(this); }
|
visitBoundEvent(event: BoundEvent) {
|
||||||
|
event.handler.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
visitBoundText(text: BoundText) { text.value.visit(this); }
|
visitBoundText(text: BoundText) {
|
||||||
|
text.value.visit(this);
|
||||||
|
}
|
||||||
visitPipe(ast: BindingPipe, context: any): any {
|
visitPipe(ast: BindingPipe, context: any): any {
|
||||||
this.usedPipes.add(ast.name);
|
this.usedPipes.add(ast.name);
|
||||||
return super.visitPipe(ast, context);
|
return super.visitPipe(ast, context);
|
||||||
@ -526,7 +538,9 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
|
|||||||
return this.symbols.get(symbol) || null;
|
return this.symbols.get(symbol) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNestingLevel(template: Template): number { return this.nestingLevel.get(template) || 0; }
|
getNestingLevel(template: Template): number {
|
||||||
|
return this.nestingLevel.get(template) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
getUsedDirectives(): DirectiveT[] {
|
getUsedDirectives(): DirectiveT[] {
|
||||||
const set = new Set<DirectiveT>();
|
const set = new Set<DirectiveT>();
|
||||||
@ -534,5 +548,7 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
|
|||||||
return Array.from(set.values());
|
return Array.from(set.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsedPipes(): string[] { return Array.from(this.usedPipes); }
|
getUsedPipes(): string[] {
|
||||||
|
return Array.from(this.usedPipes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {flatten, sanitizeIdentifier} from '../../compile_metadata';
|
import {flatten, sanitizeIdentifier} from '../../compile_metadata';
|
||||||
import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding, convertUpdateArguments} from '../../compiler_util/expression_converter';
|
import {BindingForm, BuiltinFunctionCall, convertActionBinding, convertPropertyBinding, convertUpdateArguments, LocalResolver} from '../../compiler_util/expression_converter';
|
||||||
import {ConstantPool} from '../../constant_pool';
|
import {ConstantPool} from '../../constant_pool';
|
||||||
import * as core from '../../core';
|
import * as core from '../../core';
|
||||||
import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast';
|
import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast';
|
||||||
@ -36,9 +36,9 @@ import {I18nContext} from './i18n/context';
|
|||||||
import {createGoogleGetMsgStatements} from './i18n/get_msg_utils';
|
import {createGoogleGetMsgStatements} from './i18n/get_msg_utils';
|
||||||
import {createLocalizeStatements} from './i18n/localize_utils';
|
import {createLocalizeStatements} from './i18n/localize_utils';
|
||||||
import {I18nMetaVisitor} from './i18n/meta';
|
import {I18nMetaVisitor} from './i18n/meta';
|
||||||
import {I18N_ICU_MAPPING_PREFIX, TRANSLATION_PREFIX, assembleBoundTextPlaceholders, assembleI18nBoundString, declareI18nVariable, getTranslationConstPrefix, i18nFormatPlaceholderNames, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, placeholdersToParams, wrapI18nPlaceholder} from './i18n/util';
|
import {assembleBoundTextPlaceholders, assembleI18nBoundString, declareI18nVariable, getTranslationConstPrefix, I18N_ICU_MAPPING_PREFIX, i18nFormatPlaceholderNames, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, placeholdersToParams, TRANSLATION_PREFIX, wrapI18nPlaceholder} from './i18n/util';
|
||||||
import {StylingBuilder, StylingInstruction} from './styling_builder';
|
import {StylingBuilder, StylingInstruction} from './styling_builder';
|
||||||
import {CONTEXT_NAME, IMPLICIT_REFERENCE, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, asLiteral, chainedInstruction, getAttrsForDirectiveMatching, getInterpolationArgsLength, invalid, trimTrailingNulls, unsupported} from './util';
|
import {asLiteral, chainedInstruction, CONTEXT_NAME, getAttrsForDirectiveMatching, getInterpolationArgsLength, IMPLICIT_REFERENCE, invalid, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, trimTrailingNulls, unsupported} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -61,8 +61,8 @@ export function renderFlagCheckIfStmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function prepareEventListenerParameters(
|
export function prepareEventListenerParameters(
|
||||||
eventAst: t.BoundEvent, handlerName: string | null = null,
|
eventAst: t.BoundEvent, handlerName: string|null = null,
|
||||||
scope: BindingScope | null = null): o.Expression[] {
|
scope: BindingScope|null = null): o.Expression[] {
|
||||||
const {type, name, target, phase, handler} = eventAst;
|
const {type, name, target, phase, handler} = eventAst;
|
||||||
if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
|
if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
|
||||||
throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
|
throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
|
||||||
@ -85,7 +85,7 @@ export function prepareEventListenerParameters(
|
|||||||
statements.push(...bindingExpr.render3Stmts);
|
statements.push(...bindingExpr.render3Stmts);
|
||||||
|
|
||||||
const eventName: string =
|
const eventName: string =
|
||||||
type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase !) : name;
|
type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase!) : name;
|
||||||
const fnName = handlerName && sanitizeIdentifier(handlerName);
|
const fnName = handlerName && sanitizeIdentifier(handlerName);
|
||||||
const fnArgs: o.FnParam[] = [];
|
const fnArgs: o.FnParam[] = [];
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ export function prepareEventListenerParameters(
|
|||||||
if (target) {
|
if (target) {
|
||||||
params.push(
|
params.push(
|
||||||
o.literal(false), // `useCapture` flag, defaults to `false`
|
o.literal(false), // `useCapture` flag, defaults to `false`
|
||||||
o.importExpr(GLOBAL_TARGET_RESOLVERS.get(target) !));
|
o.importExpr(GLOBAL_TARGET_RESOLVERS.get(target)!));
|
||||||
}
|
}
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
@ -207,12 +207,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
// - this template has parent i18n context
|
// - this template has parent i18n context
|
||||||
// - or the template has i18n meta associated with it,
|
// - or the template has i18n meta associated with it,
|
||||||
// but it's not initiated by the Element (e.g. <ng-template i18n>)
|
// but it's not initiated by the Element (e.g. <ng-template i18n>)
|
||||||
const initI18nContext =
|
const initI18nContext = this.i18nContext ||
|
||||||
this.i18nContext || (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
|
(isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
|
||||||
!(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
|
!(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
|
||||||
const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
|
const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
|
||||||
if (initI18nContext) {
|
if (initI18nContext) {
|
||||||
this.i18nStart(null, i18n !, selfClosingI18nInstruction);
|
this.i18nStart(null, i18n!, selfClosingI18nInstruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the initial pass through the nodes of this template. In this pass, we
|
// This is the initial pass through the nodes of this template. In this pass, we
|
||||||
@ -295,10 +295,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LocalResolver
|
// LocalResolver
|
||||||
getLocal(name: string): o.Expression|null { return this._bindingScope.get(name); }
|
getLocal(name: string): o.Expression|null {
|
||||||
|
return this._bindingScope.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
// LocalResolver
|
// LocalResolver
|
||||||
notifyImplicitReceiverUse(): void { this._bindingScope.notifyImplicitReceiverUse(); }
|
notifyImplicitReceiverUse(): void {
|
||||||
|
this._bindingScope.notifyImplicitReceiverUse();
|
||||||
|
}
|
||||||
|
|
||||||
private i18nTranslate(
|
private i18nTranslate(
|
||||||
message: i18n.Message, params: {[name: string]: o.Expression} = {}, ref?: o.ReadVarExpr,
|
message: i18n.Message, params: {[name: string]: o.Expression} = {}, ref?: o.ReadVarExpr,
|
||||||
@ -335,12 +339,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
|
|
||||||
private i18nAppendBindings(expressions: AST[]) {
|
private i18nAppendBindings(expressions: AST[]) {
|
||||||
if (expressions.length > 0) {
|
if (expressions.length > 0) {
|
||||||
expressions.forEach(expression => this.i18n !.appendBinding(expression));
|
expressions.forEach(expression => this.i18n!.appendBinding(expression));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private i18nBindProps(props: {[key: string]: t.Text | t.BoundText}):
|
private i18nBindProps(props: {[key: string]: t.Text|t.BoundText}): {[key: string]: o.Expression} {
|
||||||
{[key: string]: o.Expression} {
|
|
||||||
const bound: {[key: string]: o.Expression} = {};
|
const bound: {[key: string]: o.Expression} = {};
|
||||||
Object.keys(props).forEach(key => {
|
Object.keys(props).forEach(key => {
|
||||||
const prop = props[key];
|
const prop = props[key];
|
||||||
@ -351,7 +354,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
this.allocateBindingSlots(value);
|
this.allocateBindingSlots(value);
|
||||||
if (value instanceof Interpolation) {
|
if (value instanceof Interpolation) {
|
||||||
const {strings, expressions} = value;
|
const {strings, expressions} = value;
|
||||||
const {id, bindings} = this.i18n !;
|
const {id, bindings} = this.i18n!;
|
||||||
const label = assembleI18nBoundString(strings, bindings.size, id);
|
const label = assembleI18nBoundString(strings, bindings.size, id);
|
||||||
this.i18nAppendBindings(expressions);
|
this.i18nAppendBindings(expressions);
|
||||||
bound[key] = o.literal(label);
|
bound[key] = o.literal(label);
|
||||||
@ -424,7 +427,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
void {
|
void {
|
||||||
const index = this.allocateDataSlot();
|
const index = this.allocateDataSlot();
|
||||||
if (this.i18nContext) {
|
if (this.i18nContext) {
|
||||||
this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex !, meta);
|
this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex!, meta);
|
||||||
} else {
|
} else {
|
||||||
const ref = o.variable(this.constantPool.uniqueName(TRANSLATION_PREFIX));
|
const ref = o.variable(this.constantPool.uniqueName(TRANSLATION_PREFIX));
|
||||||
this.i18n = new I18nContext(index, ref, 0, this.templateIndex, meta);
|
this.i18n = new I18nContext(index, ref, 0, this.templateIndex, meta);
|
||||||
@ -479,7 +482,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const i18nAttrArgs: o.Expression[] = [];
|
const i18nAttrArgs: o.Expression[] = [];
|
||||||
const bindings: ChainableBindingInstruction[] = [];
|
const bindings: ChainableBindingInstruction[] = [];
|
||||||
attrs.forEach(attr => {
|
attrs.forEach(attr => {
|
||||||
const message = attr.i18n !as i18n.Message;
|
const message = attr.i18n! as i18n.Message;
|
||||||
if (attr instanceof t.TextAttribute) {
|
if (attr instanceof t.TextAttribute) {
|
||||||
i18nAttrArgs.push(o.literal(attr.name), this.i18nTranslate(message));
|
i18nAttrArgs.push(o.literal(attr.name), this.i18nTranslate(message));
|
||||||
} else {
|
} else {
|
||||||
@ -559,7 +562,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
|
|
||||||
this.creationInstruction(ngContent.sourceSpan, R3.projection, parameters);
|
this.creationInstruction(ngContent.sourceSpan, R3.projection, parameters);
|
||||||
if (this.i18n) {
|
if (this.i18n) {
|
||||||
this.i18n.appendProjection(ngContent.i18n !, slot);
|
this.i18n.appendProjection(ngContent.i18n!, slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +574,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const isI18nRootElement: boolean =
|
const isI18nRootElement: boolean =
|
||||||
isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
|
isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
|
||||||
|
|
||||||
const i18nAttrs: (t.TextAttribute | t.BoundAttribute)[] = [];
|
const i18nAttrs: (t.TextAttribute|t.BoundAttribute)[] = [];
|
||||||
const outputAttrs: t.TextAttribute[] = [];
|
const outputAttrs: t.TextAttribute[] = [];
|
||||||
|
|
||||||
const [namespaceKey, elementName] = splitNsName(element.name);
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
||||||
@ -633,7 +636,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.i18n) {
|
if (this.i18n) {
|
||||||
this.i18n.appendElement(element.i18n !, elementIndex);
|
this.i18n.appendElement(element.i18n!, elementIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we do not append text node instructions and ICUs inside i18n section,
|
// Note that we do not append text node instructions and ICUs inside i18n section,
|
||||||
@ -676,7 +679,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
|
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
|
||||||
// listeners, to make sure i18nAttributes instruction targets current element at runtime.
|
// listeners, to make sure i18nAttributes instruction targets current element at runtime.
|
||||||
if (isI18nRootElement) {
|
if (isI18nRootElement) {
|
||||||
this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction);
|
this.i18nStart(element.sourceSpan, element.i18n!, createSelfClosingI18nInstruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,7 +760,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
propertyBindings.push({
|
propertyBindings.push({
|
||||||
name: attrName,
|
name: attrName,
|
||||||
sourceSpan: input.sourceSpan,
|
sourceSpan: input.sourceSpan,
|
||||||
value: () => this.convertPropertyBinding(value), params
|
value: () => this.convertPropertyBinding(value),
|
||||||
|
params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (inputType === BindingType.Attribute) {
|
} else if (inputType === BindingType.Attribute) {
|
||||||
@ -773,7 +777,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
attributeBindings.push({
|
attributeBindings.push({
|
||||||
name: attrName,
|
name: attrName,
|
||||||
sourceSpan: input.sourceSpan,
|
sourceSpan: input.sourceSpan,
|
||||||
value: () => this.convertPropertyBinding(boundValue), params
|
value: () => this.convertPropertyBinding(boundValue),
|
||||||
|
params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -801,7 +806,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
t.visitAll(this, element.children);
|
t.visitAll(this, element.children);
|
||||||
|
|
||||||
if (!isI18nRootElement && this.i18n) {
|
if (!isI18nRootElement && this.i18n) {
|
||||||
this.i18n.appendElement(element.i18n !, elementIndex, true);
|
this.i18n.appendElement(element.i18n!, elementIndex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!createSelfClosingInstruction) {
|
if (!createSelfClosingInstruction) {
|
||||||
@ -823,7 +828,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const templateIndex = this.allocateDataSlot();
|
const templateIndex = this.allocateDataSlot();
|
||||||
|
|
||||||
if (this.i18n) {
|
if (this.i18n) {
|
||||||
this.i18n.appendTemplate(template.i18n !, templateIndex);
|
this.i18n.appendTemplate(template.i18n!, templateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagName = sanitizeIdentifier(template.tagName || '');
|
const tagName = sanitizeIdentifier(template.tagName || '');
|
||||||
@ -892,7 +897,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
// Only add normal input/output binding instructions on explicit <ng-template> elements.
|
// Only add normal input/output binding instructions on explicit <ng-template> elements.
|
||||||
if (template.tagName === NG_TEMPLATE_TAG_NAME) {
|
if (template.tagName === NG_TEMPLATE_TAG_NAME) {
|
||||||
const inputs: t.BoundAttribute[] = [];
|
const inputs: t.BoundAttribute[] = [];
|
||||||
const i18nAttrs: (t.TextAttribute | t.BoundAttribute)[] =
|
const i18nAttrs: (t.TextAttribute|t.BoundAttribute)[] =
|
||||||
template.attributes.filter(attr => !!attr.i18n);
|
template.attributes.filter(attr => !!attr.i18n);
|
||||||
|
|
||||||
template.inputs.forEach(
|
template.inputs.forEach(
|
||||||
@ -935,7 +940,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const value = text.value.visit(this._valueConverter);
|
const value = text.value.visit(this._valueConverter);
|
||||||
this.allocateBindingSlots(value);
|
this.allocateBindingSlots(value);
|
||||||
if (value instanceof Interpolation) {
|
if (value instanceof Interpolation) {
|
||||||
this.i18n.appendBoundText(text.i18n !);
|
this.i18n.appendBoundText(text.i18n!);
|
||||||
this.i18nAppendBindings(value.expressions);
|
this.i18nAppendBindings(value.expressions);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -975,15 +980,15 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
// to generate i18n context and the necessary instructions
|
// to generate i18n context and the necessary instructions
|
||||||
if (!this.i18n) {
|
if (!this.i18n) {
|
||||||
initWasInvoked = true;
|
initWasInvoked = true;
|
||||||
this.i18nStart(null, icu.i18n !, true);
|
this.i18nStart(null, icu.i18n!, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const i18n = this.i18n !;
|
const i18n = this.i18n!;
|
||||||
const vars = this.i18nBindProps(icu.vars);
|
const vars = this.i18nBindProps(icu.vars);
|
||||||
const placeholders = this.i18nBindProps(icu.placeholders);
|
const placeholders = this.i18nBindProps(icu.placeholders);
|
||||||
|
|
||||||
// output ICU directly and keep ICU reference in context
|
// output ICU directly and keep ICU reference in context
|
||||||
const message = icu.i18n !as i18n.Message;
|
const message = icu.i18n! as i18n.Message;
|
||||||
|
|
||||||
// we always need post-processing function for ICUs, to make sure that:
|
// we always need post-processing function for ICUs, to make sure that:
|
||||||
// - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
|
// - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
|
||||||
@ -1016,13 +1021,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private allocateDataSlot() { return this._dataIndex++; }
|
private allocateDataSlot() {
|
||||||
|
return this._dataIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
getConstCount() { return this._dataIndex; }
|
getConstCount() {
|
||||||
|
return this._dataIndex;
|
||||||
|
}
|
||||||
|
|
||||||
getVarCount() { return this._pureFunctionSlots; }
|
getVarCount() {
|
||||||
|
return this._pureFunctionSlots;
|
||||||
|
}
|
||||||
|
|
||||||
getConsts() { return this._constants; }
|
getConsts() {
|
||||||
|
return this._constants;
|
||||||
|
}
|
||||||
|
|
||||||
getNgContentSelectors(): o.Expression|null {
|
getNgContentSelectors(): o.Expression|null {
|
||||||
return this._ngContentReservedSlots.length ?
|
return this._ngContentReservedSlots.length ?
|
||||||
@ -1030,7 +1043,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindingContext() { return `${this._bindingContext++}`; }
|
private bindingContext() {
|
||||||
|
return `${this._bindingContext++}`;
|
||||||
|
}
|
||||||
|
|
||||||
private templatePropertyBindings(
|
private templatePropertyBindings(
|
||||||
templateIndex: number, attrs: (t.BoundAttribute|t.TextAttribute)[]) {
|
templateIndex: number, attrs: (t.BoundAttribute|t.TextAttribute)[]) {
|
||||||
@ -1092,8 +1107,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
calls.push({
|
calls.push({
|
||||||
sourceSpan: call.sourceSpan,
|
sourceSpan: call.sourceSpan,
|
||||||
value: () => {
|
value: () => {
|
||||||
return call
|
return call.params(
|
||||||
.params(
|
|
||||||
value => (call.supportsInterpolation && value instanceof Interpolation) ?
|
value => (call.supportsInterpolation && value instanceof Interpolation) ?
|
||||||
this.getUpdateInstructionArguments(value) :
|
this.getUpdateInstructionArguments(value) :
|
||||||
this.convertPropertyBinding(value)) as o.Expression[];
|
this.convertPropertyBinding(value)) as o.Expression[];
|
||||||
@ -1114,7 +1128,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
private creationInstructionChain(reference: o.ExternalReference, calls: {
|
private creationInstructionChain(reference: o.ExternalReference, calls: {
|
||||||
sourceSpan: ParseSourceSpan | null,
|
sourceSpan: ParseSourceSpan|null,
|
||||||
params: () => o.Expression[]
|
params: () => o.Expression[]
|
||||||
}[]) {
|
}[]) {
|
||||||
const span = calls.length ? calls[0].sourceSpan : null;
|
const span = calls.length ? calls[0].sourceSpan : null;
|
||||||
@ -1228,8 +1242,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
private matchDirectives(elementName: string, elOrTpl: t.Element|t.Template) {
|
private matchDirectives(elementName: string, elOrTpl: t.Element|t.Template) {
|
||||||
if (this.directiveMatcher) {
|
if (this.directiveMatcher) {
|
||||||
const selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl));
|
const selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl));
|
||||||
this.directiveMatcher.match(
|
this.directiveMatcher.match(selector, (cssSelector, staticType) => {
|
||||||
selector, (cssSelector, staticType) => { this.directives.add(staticType); });
|
this.directives.add(staticType);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1277,7 +1292,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr));
|
attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAttrExpr(key: string | number, value?: o.Expression): void {
|
function addAttrExpr(key: string|number, value?: o.Expression): void {
|
||||||
if (typeof key === 'string') {
|
if (typeof key === 'string') {
|
||||||
if (!alreadySeen.has(key)) {
|
if (!alreadySeen.has(key)) {
|
||||||
attrExprs.push(...getAttributeNameLiterals(key));
|
attrExprs.push(...getAttributeNameLiterals(key));
|
||||||
@ -1390,7 +1405,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const eventName: string = outputAst.name;
|
const eventName: string = outputAst.name;
|
||||||
const bindingFnName = outputAst.type === ParsedEventType.Animation ?
|
const bindingFnName = outputAst.type === ParsedEventType.Animation ?
|
||||||
// synthetic @listener.foo values are treated the exact same as are standard listeners
|
// synthetic @listener.foo values are treated the exact same as are standard listeners
|
||||||
prepareSyntheticListenerFunctionName(eventName, outputAst.phase !) :
|
prepareSyntheticListenerFunctionName(eventName, outputAst.phase!) :
|
||||||
sanitizeIdentifier(eventName);
|
sanitizeIdentifier(eventName);
|
||||||
const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
|
const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
|
||||||
const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel);
|
const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel);
|
||||||
@ -1492,7 +1507,7 @@ function pureFunctionCallInfo(args: o.Expression[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function instruction(
|
function instruction(
|
||||||
span: ParseSourceSpan | null, reference: o.ExternalReference,
|
span: ParseSourceSpan|null, reference: o.ExternalReference,
|
||||||
params: o.Expression[]): o.Expression {
|
params: o.Expression[]): o.Expression {
|
||||||
return o.importExpr(reference, null, span).callFn(params, span);
|
return o.importExpr(reference, null, span).callFn(params, span);
|
||||||
}
|
}
|
||||||
@ -1504,7 +1519,7 @@ function generateNextContextExpr(relativeLevelDiff: number): o.Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getLiteralFactory(
|
function getLiteralFactory(
|
||||||
constantPool: ConstantPool, literal: o.LiteralArrayExpr | o.LiteralMapExpr,
|
constantPool: ConstantPool, literal: o.LiteralArrayExpr|o.LiteralMapExpr,
|
||||||
allocateSlots: (numSlots: number) => number): o.Expression {
|
allocateSlots: (numSlots: number) => number): o.Expression {
|
||||||
const {literalFactory, literalFactoryArguments} = constantPool.getLiteralFactory(literal);
|
const {literalFactory, literalFactoryArguments} = constantPool.getLiteralFactory(literal);
|
||||||
// Allocate 1 slot for the result plus 1 per argument
|
// Allocate 1 slot for the result plus 1 per argument
|
||||||
@ -1570,9 +1585,8 @@ const SHARED_CONTEXT_KEY = '$$shared_ctx$$';
|
|||||||
* declaration should always come before the local ref declaration.
|
* declaration should always come before the local ref declaration.
|
||||||
*/
|
*/
|
||||||
type BindingData = {
|
type BindingData = {
|
||||||
retrievalLevel: number; lhs: o.Expression; declareLocalCallback?: DeclareLocalVarCallback;
|
retrievalLevel: number; lhs: o.Expression;
|
||||||
declare: boolean;
|
declareLocalCallback?: DeclareLocalVarCallback; declare: boolean; priority: number;
|
||||||
priority: number;
|
|
||||||
localRef: boolean;
|
localRef: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1580,7 +1594,11 @@ type BindingData = {
|
|||||||
* The sorting priority of a local variable declaration. Higher numbers
|
* The sorting priority of a local variable declaration. Higher numbers
|
||||||
* mean the declaration will appear first in the generated code.
|
* mean the declaration will appear first in the generated code.
|
||||||
*/
|
*/
|
||||||
const enum DeclarationPriority { DEFAULT = 0, CONTEXT = 1, SHARED_CONTEXT = 2 }
|
const enum DeclarationPriority {
|
||||||
|
DEFAULT = 0,
|
||||||
|
CONTEXT = 1,
|
||||||
|
SHARED_CONTEXT = 2
|
||||||
|
}
|
||||||
|
|
||||||
export class BindingScope implements LocalResolver {
|
export class BindingScope implements LocalResolver {
|
||||||
/** Keeps a map from local variables to their BindingData. */
|
/** Keeps a map from local variables to their BindingData. */
|
||||||
@ -1669,7 +1687,9 @@ export class BindingScope implements LocalResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implemented as part of LocalResolver.
|
// Implemented as part of LocalResolver.
|
||||||
getLocal(name: string): (o.Expression|null) { return this.get(name); }
|
getLocal(name: string): (o.Expression|null) {
|
||||||
|
return this.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
// Implemented as part of LocalResolver.
|
// Implemented as part of LocalResolver.
|
||||||
notifyImplicitReceiverUse(): void {
|
notifyImplicitReceiverUse(): void {
|
||||||
@ -1677,7 +1697,7 @@ export class BindingScope implements LocalResolver {
|
|||||||
// Since the implicit receiver is accessed in an embedded view, we need to
|
// Since the implicit receiver is accessed in an embedded view, we need to
|
||||||
// ensure that we declare a shared context variable for the current template
|
// ensure that we declare a shared context variable for the current template
|
||||||
// in the update variables.
|
// in the update variables.
|
||||||
this.map.get(SHARED_CONTEXT_KEY + 0) !.declare = true;
|
this.map.get(SHARED_CONTEXT_KEY + 0)!.declare = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1698,7 +1718,7 @@ export class BindingScope implements LocalResolver {
|
|||||||
this.generateSharedContextVar(retrievalLevel);
|
this.generateSharedContextVar(retrievalLevel);
|
||||||
}
|
}
|
||||||
// Shared context variables are always generated as "ReadVarExpr".
|
// Shared context variables are always generated as "ReadVarExpr".
|
||||||
return this.map.get(bindingKey) !.lhs as o.ReadVarExpr;
|
return this.map.get(bindingKey)!.lhs as o.ReadVarExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSharedContextName(retrievalLevel: number): o.ReadVarExpr|null {
|
getSharedContextName(retrievalLevel: number): o.ReadVarExpr|null {
|
||||||
@ -1735,7 +1755,7 @@ export class BindingScope implements LocalResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getComponentProperty(name: string): o.Expression {
|
getComponentProperty(name: string): o.Expression {
|
||||||
const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0) !;
|
const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0)!;
|
||||||
componentValue.declare = true;
|
componentValue.declare = true;
|
||||||
this.maybeRestoreView(0, false);
|
this.maybeRestoreView(0, false);
|
||||||
return componentValue.lhs.prop(name);
|
return componentValue.lhs.prop(name);
|
||||||
@ -1748,11 +1768,11 @@ export class BindingScope implements LocalResolver {
|
|||||||
// 2 - we are looking up a local ref, which requires restoring the view where the local
|
// 2 - we are looking up a local ref, which requires restoring the view where the local
|
||||||
// ref is stored
|
// ref is stored
|
||||||
if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) {
|
if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) {
|
||||||
if (!this.parent !.restoreViewVariable) {
|
if (!this.parent!.restoreViewVariable) {
|
||||||
// parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
|
// parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
|
||||||
this.parent !.restoreViewVariable = o.variable(this.parent !.freshReferenceName());
|
this.parent!.restoreViewVariable = o.variable(this.parent!.freshReferenceName());
|
||||||
}
|
}
|
||||||
this.restoreViewVariable = this.parent !.restoreViewVariable;
|
this.restoreViewVariable = this.parent!.restoreViewVariable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1771,7 +1791,9 @@ export class BindingScope implements LocalResolver {
|
|||||||
[];
|
[];
|
||||||
}
|
}
|
||||||
|
|
||||||
isListenerScope() { return this.parent && this.parent.bindingLevel === this.bindingLevel; }
|
isListenerScope() {
|
||||||
|
return this.parent && this.parent.bindingLevel === this.bindingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
variableDeclarations(): o.Statement[] {
|
variableDeclarations(): o.Statement[] {
|
||||||
let currentContextLevel = 0;
|
let currentContextLevel = 0;
|
||||||
@ -1780,7 +1802,8 @@ export class BindingScope implements LocalResolver {
|
|||||||
.sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority)
|
.sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority)
|
||||||
.reduce((stmts: o.Statement[], value: BindingData) => {
|
.reduce((stmts: o.Statement[], value: BindingData) => {
|
||||||
const levelDiff = this.bindingLevel - value.retrievalLevel;
|
const levelDiff = this.bindingLevel - value.retrievalLevel;
|
||||||
const currStmts = value.declareLocalCallback !(this, levelDiff - currentContextLevel);
|
const currStmts =
|
||||||
|
value.declareLocalCallback!(this, levelDiff - currentContextLevel);
|
||||||
currentContextLevel = levelDiff;
|
currentContextLevel = levelDiff;
|
||||||
return stmts.concat(currStmts);
|
return stmts.concat(currStmts);
|
||||||
}, []) as o.Statement[];
|
}, []) as o.Statement[];
|
||||||
@ -2126,7 +2149,8 @@ export function getTranslationDeclStmts(
|
|||||||
const statements: o.Statement[] = [
|
const statements: o.Statement[] = [
|
||||||
declareI18nVariable(variable),
|
declareI18nVariable(variable),
|
||||||
o.ifStmt(
|
o.ifStmt(
|
||||||
createClosureModeGuard(), createGoogleGetMsgStatements(
|
createClosureModeGuard(),
|
||||||
|
createGoogleGetMsgStatements(
|
||||||
variable, message, closureVar,
|
variable, message, closureVar,
|
||||||
i18nFormatPlaceholderNames(params, /* useCamelCase */ true)),
|
i18nFormatPlaceholderNames(params, /* useCamelCase */ true)),
|
||||||
createLocalizeStatements(
|
createLocalizeStatements(
|
||||||
|
@ -69,7 +69,7 @@ export function unsupported(this: void|Function, feature: string): never {
|
|||||||
throw new Error(`Feature ${feature} is not supported yet`);
|
throw new Error(`Feature ${feature} is not supported yet`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function invalid<T>(this: t.Visitor, arg: o.Expression | o.Statement | t.Node): never {
|
export function invalid<T>(this: t.Visitor, arg: o.Expression|o.Statement|t.Node): never {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
|
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ export function asLiteral(value: any): o.Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function conditionallyCreateMapObjectLiteral(
|
export function conditionallyCreateMapObjectLiteral(
|
||||||
keys: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression|null {
|
keys: {[key: string]: string|string[]}, keepDeclared?: boolean): o.Expression|null {
|
||||||
if (Object.getOwnPropertyNames(keys).length > 0) {
|
if (Object.getOwnPropertyNames(keys).length > 0) {
|
||||||
return mapToExpression(keys, keepDeclared);
|
return mapToExpression(keys, keepDeclared);
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ export function conditionallyCreateMapObjectLiteral(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapToExpression(
|
function mapToExpression(
|
||||||
map: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression {
|
map: {[key: string]: string|string[]}, keepDeclared?: boolean): o.Expression {
|
||||||
return o.literalMap(Object.getOwnPropertyNames(map).map(key => {
|
return o.literalMap(Object.getOwnPropertyNames(map).map(key => {
|
||||||
// canonical syntax: `dirProp: publicProp`
|
// canonical syntax: `dirProp: publicProp`
|
||||||
// if there is no `:`, use dirProp = elProp
|
// if there is no `:`, use dirProp = elProp
|
||||||
@ -153,7 +153,9 @@ export class DefinitionMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toLiteralMap(): o.LiteralMapExpr { return o.literalMap(this.values); }
|
toLiteralMap(): o.LiteralMapExpr {
|
||||||
|
return o.literalMap(this.values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,8 +167,8 @@ export class DefinitionMap {
|
|||||||
* object maps a property name to its (static) value. For any bindings, this map simply maps the
|
* object maps a property name to its (static) value. For any bindings, this map simply maps the
|
||||||
* property name to an empty string.
|
* property name to an empty string.
|
||||||
*/
|
*/
|
||||||
export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template):
|
export function getAttrsForDirectiveMatching(elOrTpl: t.Element|
|
||||||
{[name: string]: string} {
|
t.Template): {[name: string]: string} {
|
||||||
const attributesMap: {[name: string]: string} = {};
|
const attributesMap: {[name: string]: string} = {};
|
||||||
|
|
||||||
|
|
||||||
@ -179,8 +181,12 @@ export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template):
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
elOrTpl.inputs.forEach(i => { attributesMap[i.name] = ''; });
|
elOrTpl.inputs.forEach(i => {
|
||||||
elOrTpl.outputs.forEach(o => { attributesMap[o.name] = ''; });
|
attributesMap[i.name] = '';
|
||||||
|
});
|
||||||
|
elOrTpl.outputs.forEach(o => {
|
||||||
|
attributesMap[o.name] = '';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return attributesMap;
|
return attributesMap;
|
||||||
@ -188,7 +194,7 @@ export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template):
|
|||||||
|
|
||||||
/** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
|
/** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
|
||||||
export function chainedInstruction(
|
export function chainedInstruction(
|
||||||
reference: o.ExternalReference, calls: o.Expression[][], span?: ParseSourceSpan | null) {
|
reference: o.ExternalReference, calls: o.Expression[][], span?: ParseSourceSpan|null) {
|
||||||
let expression = o.importExpr(reference, null, span) as o.Expression;
|
let expression = o.importExpr(reference, null, span) as o.Expression;
|
||||||
|
|
||||||
if (calls.length > 0) {
|
if (calls.length > 0) {
|
||||||
|
@ -11,5 +11,7 @@
|
|||||||
* to load templates.
|
* to load templates.
|
||||||
*/
|
*/
|
||||||
export class ResourceLoader {
|
export class ResourceLoader {
|
||||||
get(url: string): Promise<string>|string { return ''; }
|
get(url: string): Promise<string>|string {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,9 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type);
|
typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type);
|
||||||
const superType = superName && this._schema[superName.toLowerCase()];
|
const superType = superName && this._schema[superName.toLowerCase()];
|
||||||
if (superType) {
|
if (superType) {
|
||||||
Object.keys(superType).forEach((prop: string) => { type[prop] = superType[prop]; });
|
Object.keys(superType).forEach((prop: string) => {
|
||||||
|
type[prop] = superType[prop];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
properties.forEach((property: string) => {
|
properties.forEach((property: string) => {
|
||||||
if (property.length > 0) {
|
if (property.length > 0) {
|
||||||
@ -350,9 +352,13 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
return ctx ? ctx : SecurityContext.NONE;
|
return ctx ? ctx : SecurityContext.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; }
|
getMappedPropName(propName: string): string {
|
||||||
|
return _ATTR_TO_PROP[propName] || propName;
|
||||||
|
}
|
||||||
|
|
||||||
getDefaultComponentElementName(): string { return 'ng-component'; }
|
getDefaultComponentElementName(): string {
|
||||||
|
return 'ng-component';
|
||||||
|
}
|
||||||
|
|
||||||
validateProperty(name: string): {error: boolean, msg?: string} {
|
validateProperty(name: string): {error: boolean, msg?: string} {
|
||||||
if (name.toLowerCase().startsWith('on')) {
|
if (name.toLowerCase().startsWith('on')) {
|
||||||
@ -376,7 +382,9 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allKnownElementNames(): string[] { return Object.keys(this._schema); }
|
allKnownElementNames(): string[] {
|
||||||
|
return Object.keys(this._schema);
|
||||||
|
}
|
||||||
|
|
||||||
normalizeAnimationStyleProperty(propName: string): string {
|
normalizeAnimationStyleProperty(propName: string): string {
|
||||||
return dashCaseToCamelCase(propName);
|
return dashCaseToCamelCase(propName);
|
||||||
@ -386,7 +394,7 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
{error: string, value: string} {
|
{error: string, value: string} {
|
||||||
let unit: string = '';
|
let unit: string = '';
|
||||||
const strVal = val.toString().trim();
|
const strVal = val.toString().trim();
|
||||||
let errorMsg: string = null !;
|
let errorMsg: string = null!;
|
||||||
|
|
||||||
if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
|
if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
|
||||||
if (typeof val === 'number') {
|
if (typeof val === 'number') {
|
||||||
|
@ -20,7 +20,7 @@ import {SecurityContext} from '../core';
|
|||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
|
/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
|
||||||
let _SECURITY_SCHEMA !: {[k: string]: SecurityContext};
|
let _SECURITY_SCHEMA!: {[k: string]: SecurityContext};
|
||||||
|
|
||||||
export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
|
export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
|
||||||
if (!_SECURITY_SCHEMA) {
|
if (!_SECURITY_SCHEMA) {
|
||||||
|
@ -118,9 +118,13 @@ export class CssSelector {
|
|||||||
this.notSelectors.length === 0;
|
this.notSelectors.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasElementSelector(): boolean { return !!this.element; }
|
hasElementSelector(): boolean {
|
||||||
|
return !!this.element;
|
||||||
|
}
|
||||||
|
|
||||||
setElement(element: string|null = null) { this.element = element; }
|
setElement(element: string|null = null) {
|
||||||
|
this.element = element;
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets a template string for an element that matches the selector. */
|
/** Gets a template string for an element that matches the selector. */
|
||||||
getMatchingElementTemplate(): string {
|
getMatchingElementTemplate(): string {
|
||||||
@ -150,7 +154,9 @@ export class CssSelector {
|
|||||||
this.attrs.push(name, value && value.toLowerCase() || '');
|
this.attrs.push(name, value && value.toLowerCase() || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
addClassName(name: string) { this.classNames.push(name.toLowerCase()); }
|
addClassName(name: string) {
|
||||||
|
this.classNames.push(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
let res: string = this.element || '';
|
let res: string = this.element || '';
|
||||||
@ -189,7 +195,7 @@ export class SelectorMatcher<T = any> {
|
|||||||
private _listContexts: SelectorListContext[] = [];
|
private _listContexts: SelectorListContext[] = [];
|
||||||
|
|
||||||
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: T) {
|
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: T) {
|
||||||
let listContext: SelectorListContext = null !;
|
let listContext: SelectorListContext = null!;
|
||||||
if (cssSelectors.length > 1) {
|
if (cssSelectors.length > 1) {
|
||||||
listContext = new SelectorListContext(cssSelectors);
|
listContext = new SelectorListContext(cssSelectors);
|
||||||
this._listContexts.push(listContext);
|
this._listContexts.push(listContext);
|
||||||
@ -287,7 +293,7 @@ export class SelectorMatcher<T = any> {
|
|||||||
*/
|
*/
|
||||||
match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: T) => void)|null): boolean {
|
match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: T) => void)|null): boolean {
|
||||||
let result = false;
|
let result = false;
|
||||||
const element = cssSelector.element !;
|
const element = cssSelector.element!;
|
||||||
const classNames = cssSelector.classNames;
|
const classNames = cssSelector.classNames;
|
||||||
const attrs = cssSelector.attrs;
|
const attrs = cssSelector.attrs;
|
||||||
|
|
||||||
@ -315,7 +321,7 @@ export class SelectorMatcher<T = any> {
|
|||||||
const name = attrs[i];
|
const name = attrs[i];
|
||||||
const value = attrs[i + 1];
|
const value = attrs[i + 1];
|
||||||
|
|
||||||
const terminalValuesMap = this._attrValueMap.get(name) !;
|
const terminalValuesMap = this._attrValueMap.get(name)!;
|
||||||
if (value) {
|
if (value) {
|
||||||
result =
|
result =
|
||||||
this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
|
this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
@ -323,7 +329,7 @@ export class SelectorMatcher<T = any> {
|
|||||||
result =
|
result =
|
||||||
this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
|
this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
|
||||||
|
|
||||||
const partialValuesMap = this._attrValuePartialMap.get(name) !;
|
const partialValuesMap = this._attrValuePartialMap.get(name)!;
|
||||||
if (value) {
|
if (value) {
|
||||||
result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
|
result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
}
|
}
|
||||||
@ -343,7 +349,7 @@ export class SelectorMatcher<T = any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let selectables: SelectorContext<T>[] = map.get(name) || [];
|
let selectables: SelectorContext<T>[] = map.get(name) || [];
|
||||||
const starSelectables: SelectorContext<T>[] = map.get('*') !;
|
const starSelectables: SelectorContext<T>[] = map.get('*')!;
|
||||||
if (starSelectables) {
|
if (starSelectables) {
|
||||||
selectables = selectables.concat(starSelectables);
|
selectables = selectables.concat(starSelectables);
|
||||||
}
|
}
|
||||||
|
@ -175,8 +175,9 @@ export class ShadowCss {
|
|||||||
**/
|
**/
|
||||||
private _insertPolyfillDirectivesInCssText(cssText: string): string {
|
private _insertPolyfillDirectivesInCssText(cssText: string): string {
|
||||||
// Difference with webcomponents.js: does not handle comments
|
// Difference with webcomponents.js: does not handle comments
|
||||||
return cssText.replace(
|
return cssText.replace(_cssContentNextSelectorRe, function(...m: string[]) {
|
||||||
_cssContentNextSelectorRe, function(...m: string[]) { return m[2] + '{'; });
|
return m[2] + '{';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -505,7 +506,9 @@ class SafeSelector {
|
|||||||
return content.replace(/__ph-(\d+)__/g, (ph, index) => this.placeholders[+index]);
|
return content.replace(/__ph-(\d+)__/g, (ph, index) => this.placeholders[+index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
content(): string { return this._content; }
|
content(): string {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _cssContentNextSelectorRe =
|
const _cssContentNextSelectorRe =
|
||||||
|
@ -66,7 +66,7 @@ export class StyleCompiler {
|
|||||||
stylesheet.styleUrls.forEach((styleUrl) => {
|
stylesheet.styleUrls.forEach((styleUrl) => {
|
||||||
const exprIndex = styleExpressions.length;
|
const exprIndex = styleExpressions.length;
|
||||||
// Note: This placeholder will be filled later.
|
// Note: This placeholder will be filled later.
|
||||||
styleExpressions.push(null !);
|
styleExpressions.push(null!);
|
||||||
dependencies.push(new StylesCompileDependency(
|
dependencies.push(new StylesCompileDependency(
|
||||||
getStylesVarName(null), styleUrl,
|
getStylesVarName(null), styleUrl,
|
||||||
(value) => styleExpressions[exprIndex] = outputCtx.importExpr(value)));
|
(value) => styleExpressions[exprIndex] = outputCtx.importExpr(value)));
|
||||||
@ -89,7 +89,7 @@ export class StyleCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStylesVarName(component: CompileDirectiveMetadata | null): string {
|
function getStylesVarName(component: CompileDirectiveMetadata|null): string {
|
||||||
let result = `styles`;
|
let result = `styles`;
|
||||||
if (component) {
|
if (component) {
|
||||||
result += `_${identifierName(component.type)}`;
|
result += `_${identifierName(component.type)}`;
|
||||||
|
@ -28,14 +28,28 @@ export abstract class SummaryResolver<T> {
|
|||||||
export class JitSummaryResolver implements SummaryResolver<Type> {
|
export class JitSummaryResolver implements SummaryResolver<Type> {
|
||||||
private _summaries = new Map<Type, Summary<Type>>();
|
private _summaries = new Map<Type, Summary<Type>>();
|
||||||
|
|
||||||
isLibraryFile(): boolean { return false; }
|
isLibraryFile(): boolean {
|
||||||
toSummaryFileName(fileName: string): string { return fileName; }
|
return false;
|
||||||
fromSummaryFileName(fileName: string): string { return fileName; }
|
}
|
||||||
|
toSummaryFileName(fileName: string): string {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
fromSummaryFileName(fileName: string): string {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
resolveSummary(reference: Type): Summary<Type>|null {
|
resolveSummary(reference: Type): Summary<Type>|null {
|
||||||
return this._summaries.get(reference) || null;
|
return this._summaries.get(reference) || null;
|
||||||
}
|
}
|
||||||
getSymbolsOf(): Type[] { return []; }
|
getSymbolsOf(): Type[] {
|
||||||
getImportAs(reference: Type): Type { return reference; }
|
return [];
|
||||||
getKnownModuleName(fileName: string) { return null; }
|
}
|
||||||
addSummary(summary: Summary<Type>) { this._summaries.set(summary.symbol, summary); }
|
getImportAs(reference: Type): Type {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
getKnownModuleName(fileName: string) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
addSummary(summary: Summary<Type>) {
|
||||||
|
this._summaries.set(summary.symbol, summary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
||||||
import {SecurityContext} from '../core';
|
import {SecurityContext} from '../core';
|
||||||
import {ASTWithSource, AbsoluteSourceSpan, BindingPipe, BindingType, BoundElementProperty, EmptyExpr, ParsedEvent, ParsedEventType, ParsedProperty, ParsedPropertyType, ParsedVariable, ParserError, RecursiveAstVisitor, TemplateBinding, VariableBinding} from '../expression_parser/ast';
|
import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, BindingType, BoundElementProperty, EmptyExpr, ParsedEvent, ParsedEventType, ParsedProperty, ParsedPropertyType, ParsedVariable, ParserError, RecursiveAstVisitor, TemplateBinding, VariableBinding} from '../expression_parser/ast';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from '../expression_parser/parser';
|
||||||
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||||
import {mergeNsAndName} from '../ml_parser/tags';
|
import {mergeNsAndName} from '../ml_parser/tags';
|
||||||
@ -45,9 +45,13 @@ export class BindingParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get interpolationConfig(): InterpolationConfig { return this._interpolationConfig; }
|
get interpolationConfig(): InterpolationConfig {
|
||||||
|
return this._interpolationConfig;
|
||||||
|
}
|
||||||
|
|
||||||
getUsedPipes(): CompilePipeSummary[] { return Array.from(this._usedPipes.values()); }
|
getUsedPipes(): CompilePipeSummary[] {
|
||||||
|
return Array.from(this._usedPipes.values());
|
||||||
|
}
|
||||||
|
|
||||||
createBoundHostProperties(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
|
createBoundHostProperties(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
|
||||||
ParsedProperty[]|null {
|
ParsedProperty[]|null {
|
||||||
@ -61,7 +65,9 @@ export class BindingParser {
|
|||||||
boundProps);
|
boundProps);
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
`Value of the host property binding "${
|
||||||
|
propName}" needs to be a string representing an expression but got "${
|
||||||
|
expression}" (${typeof expression})`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -89,7 +95,9 @@ export class BindingParser {
|
|||||||
this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents);
|
this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents);
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
`Value of the host listener "${
|
||||||
|
propName}" needs to be a string representing an expression but got "${
|
||||||
|
expression}" (${typeof expression})`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -103,7 +111,7 @@ export class BindingParser {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const ast = this._exprParser.parseInterpolation(
|
const ast = this._exprParser.parseInterpolation(
|
||||||
value, sourceInfo, sourceSpan.start.offset, this._interpolationConfig) !;
|
value, sourceInfo, sourceSpan.start.offset, this._interpolationConfig)!;
|
||||||
if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
||||||
this._checkPipes(ast, sourceSpan);
|
this._checkPipes(ast, sourceSpan);
|
||||||
return ast;
|
return ast;
|
||||||
@ -183,8 +191,9 @@ export class BindingParser {
|
|||||||
this._checkPipes(binding.value, sourceSpan);
|
this._checkPipes(binding.value, sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bindingsResult.warnings.forEach(
|
bindingsResult.warnings.forEach((warning) => {
|
||||||
(warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
|
this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
|
||||||
|
});
|
||||||
return bindingsResult.templateBindings;
|
return bindingsResult.templateBindings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
@ -257,7 +266,7 @@ export class BindingParser {
|
|||||||
name: string, ast: ASTWithSource, sourceSpan: ParseSourceSpan,
|
name: string, ast: ASTWithSource, sourceSpan: ParseSourceSpan,
|
||||||
valueSpan: ParseSourceSpan|undefined, targetMatchableAttrs: string[][],
|
valueSpan: ParseSourceSpan|undefined, targetMatchableAttrs: string[][],
|
||||||
targetProps: ParsedProperty[]) {
|
targetProps: ParsedProperty[]) {
|
||||||
targetMatchableAttrs.push([name, ast.source !]);
|
targetMatchableAttrs.push([name, ast.source!]);
|
||||||
targetProps.push(
|
targetProps.push(
|
||||||
new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, valueSpan));
|
new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, valueSpan));
|
||||||
}
|
}
|
||||||
@ -275,7 +284,7 @@ export class BindingParser {
|
|||||||
// states will be applied by angular when the element is attached/detached
|
// states will be applied by angular when the element is attached/detached
|
||||||
const ast = this._parseBinding(
|
const ast = this._parseBinding(
|
||||||
expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
|
expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
|
||||||
targetMatchableAttrs.push([name, ast.source !]);
|
targetMatchableAttrs.push([name, ast.source!]);
|
||||||
targetProps.push(
|
targetProps.push(
|
||||||
new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, valueSpan));
|
new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, valueSpan));
|
||||||
}
|
}
|
||||||
@ -310,10 +319,10 @@ export class BindingParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let unit: string|null = null;
|
let unit: string|null = null;
|
||||||
let bindingType: BindingType = undefined !;
|
let bindingType: BindingType = undefined!;
|
||||||
let boundPropertyName: string|null = null;
|
let boundPropertyName: string|null = null;
|
||||||
const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
|
const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
|
||||||
let securityContexts: SecurityContext[] = undefined !;
|
let securityContexts: SecurityContext[] = undefined!;
|
||||||
|
|
||||||
// Check for special cases (prefix style, attr, class)
|
// Check for special cases (prefix style, attr, class)
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
@ -401,13 +410,15 @@ export class BindingParser {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`,
|
`The provided animation output phase value "${phase}" for "@${
|
||||||
|
eventName}" is not supported (use start or done)`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`,
|
`The animation trigger output event (@${
|
||||||
|
eventName}) is missing its phase value name (start or done are currently supported)`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,9 +427,9 @@ export class BindingParser {
|
|||||||
name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan,
|
name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) {
|
targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) {
|
||||||
// long format: 'target: eventName'
|
// long format: 'target: eventName'
|
||||||
const [target, eventName] = splitAtColon(name, [null !, name]);
|
const [target, eventName] = splitAtColon(name, [null!, name]);
|
||||||
const ast = this._parseAction(expression, handlerSpan);
|
const ast = this._parseAction(expression, handlerSpan);
|
||||||
targetMatchableAttrs.push([name !, ast.source !]);
|
targetMatchableAttrs.push([name!, ast.source!]);
|
||||||
targetEvents.push(
|
targetEvents.push(
|
||||||
new ParsedEvent(eventName, target, ParsedEventType.Regular, ast, sourceSpan, handlerSpan));
|
new ParsedEvent(eventName, target, ParsedEventType.Regular, ast, sourceSpan, handlerSpan));
|
||||||
// Don't detect directives for event names for now,
|
// Don't detect directives for event names for now,
|
||||||
@ -465,7 +476,7 @@ export class BindingParser {
|
|||||||
const collector = new PipeCollector();
|
const collector = new PipeCollector();
|
||||||
ast.visit(collector);
|
ast.visit(collector);
|
||||||
collector.pipes.forEach((ast, pipeName) => {
|
collector.pipes.forEach((ast, pipeName) => {
|
||||||
const pipeMeta = this.pipesByName !.get(pipeName);
|
const pipeMeta = this.pipesByName!.get(pipeName);
|
||||||
if (!pipeMeta) {
|
if (!pipeMeta) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`The pipe '${pipeName}' could not be found`,
|
`The pipe '${pipeName}' could not be found`,
|
||||||
@ -488,7 +499,7 @@ export class BindingParser {
|
|||||||
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
||||||
this._schemaRegistry.validateProperty(propName);
|
this._schemaRegistry.validateProperty(propName);
|
||||||
if (report.error) {
|
if (report.error) {
|
||||||
this._reportError(report.msg !, sourceSpan, ParseErrorLevel.ERROR);
|
this._reportError(report.msg!, sourceSpan, ParseErrorLevel.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,9 @@ export interface TemplateAst {
|
|||||||
export class TextAst implements TemplateAst {
|
export class TextAst implements TemplateAst {
|
||||||
constructor(
|
constructor(
|
||||||
public value: string, public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
public value: string, public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
||||||
visit(visitor: TemplateAstVisitor, context: any): any { return visitor.visitText(this, context); }
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
|
return visitor.visitText(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +58,9 @@ export class BoundTextAst implements TemplateAst {
|
|||||||
*/
|
*/
|
||||||
export class AttrAst implements TemplateAst {
|
export class AttrAst implements TemplateAst {
|
||||||
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
visit(visitor: TemplateAstVisitor, context: any): any { return visitor.visitAttr(this, context); }
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
|
return visitor.visitAttr(this, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum PropertyBindingType {
|
export const enum PropertyBindingType {
|
||||||
@ -319,7 +323,9 @@ export class NullTemplateVisitor implements TemplateAstVisitor {
|
|||||||
* in an template ast recursively.
|
* in an template ast recursively.
|
||||||
*/
|
*/
|
||||||
export class RecursiveTemplateAstVisitor extends NullTemplateVisitor implements TemplateAstVisitor {
|
export class RecursiveTemplateAstVisitor extends NullTemplateVisitor implements TemplateAstVisitor {
|
||||||
constructor() { super(); }
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
// Nodes with children
|
// Nodes with children
|
||||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||||
@ -358,7 +364,7 @@ export class RecursiveTemplateAstVisitor extends NullTemplateVisitor implements
|
|||||||
cb: (visit: (<V extends TemplateAst>(children: V[]|undefined) => void)) => void) {
|
cb: (visit: (<V extends TemplateAst>(children: V[]|undefined) => void)) => void) {
|
||||||
let results: any[][] = [];
|
let results: any[][] = [];
|
||||||
let t = this;
|
let t = this;
|
||||||
function visit<T extends TemplateAst>(children: T[] | undefined) {
|
function visit<T extends TemplateAst>(children: T[]|undefined) {
|
||||||
if (children && children.length) results.push(templateVisitAll(t, children, context));
|
if (children && children.length) results.push(templateVisitAll(t, children, context));
|
||||||
}
|
}
|
||||||
cb(visit);
|
cb(visit);
|
||||||
@ -373,7 +379,7 @@ export function templateVisitAll(
|
|||||||
visitor: TemplateAstVisitor, asts: TemplateAst[], context: any = null): any[] {
|
visitor: TemplateAstVisitor, asts: TemplateAst[], context: any = null): any[] {
|
||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
const visit = visitor.visit ?
|
const visit = visitor.visit ?
|
||||||
(ast: TemplateAst) => visitor.visit !(ast, context) || ast.visit(visitor, context) :
|
(ast: TemplateAst) => visitor.visit!(ast, context) || ast.visit(visitor, context) :
|
||||||
(ast: TemplateAst) => ast.visit(visitor, context);
|
(ast: TemplateAst) => ast.visit(visitor, context);
|
||||||
asts.forEach(ast => {
|
asts.forEach(ast => {
|
||||||
const astResult = visit(ast);
|
const astResult = visit(ast);
|
||||||
|
@ -12,7 +12,7 @@ import {CompilerConfig} from '../config';
|
|||||||
import {SchemaMetadata} from '../core';
|
import {SchemaMetadata} from '../core';
|
||||||
import {AST, ASTWithSource, EmptyExpr, ParsedEvent, ParsedProperty, ParsedVariable} from '../expression_parser/ast';
|
import {AST, ASTWithSource, EmptyExpr, ParsedEvent, ParsedProperty, ParsedVariable} from '../expression_parser/ast';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from '../expression_parser/parser';
|
||||||
import {Identifiers, createTokenForExternalReference, createTokenForReference} from '../identifiers';
|
import {createTokenForExternalReference, createTokenForReference, Identifiers} from '../identifiers';
|
||||||
import * as html from '../ml_parser/ast';
|
import * as html from '../ml_parser/ast';
|
||||||
import {HtmlParser, ParseTreeResult} from '../ml_parser/html_parser';
|
import {HtmlParser, ParseTreeResult} from '../ml_parser/html_parser';
|
||||||
import {removeWhitespaces, replaceNgsp} from '../ml_parser/html_whitespaces';
|
import {removeWhitespaces, replaceNgsp} from '../ml_parser/html_whitespaces';
|
||||||
@ -57,7 +57,7 @@ const IDENT_EVENT_IDX = 10;
|
|||||||
const TEMPLATE_ATTR_PREFIX = '*';
|
const TEMPLATE_ATTR_PREFIX = '*';
|
||||||
const CLASS_ATTR = 'class';
|
const CLASS_ATTR = 'class';
|
||||||
|
|
||||||
let _TEXT_CSS_SELECTOR !: CssSelector;
|
let _TEXT_CSS_SELECTOR!: CssSelector;
|
||||||
function TEXT_CSS_SELECTOR(): CssSelector {
|
function TEXT_CSS_SELECTOR(): CssSelector {
|
||||||
if (!_TEXT_CSS_SELECTOR) {
|
if (!_TEXT_CSS_SELECTOR) {
|
||||||
_TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
_TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
||||||
@ -84,7 +84,9 @@ export class TemplateParser {
|
|||||||
private _htmlParser: HtmlParser, private _console: Console,
|
private _htmlParser: HtmlParser, private _console: Console,
|
||||||
public transforms: t.TemplateAstVisitor[]) {}
|
public transforms: t.TemplateAstVisitor[]) {}
|
||||||
|
|
||||||
public get expressionParser() { return this._exprParser; }
|
public get expressionParser() {
|
||||||
|
return this._exprParser;
|
||||||
|
}
|
||||||
|
|
||||||
parse(
|
parse(
|
||||||
component: CompileDirectiveMetadata, template: string|ParseTreeResult,
|
component: CompileDirectiveMetadata, template: string|ParseTreeResult,
|
||||||
@ -93,9 +95,9 @@ export class TemplateParser {
|
|||||||
preserveWhitespaces: boolean): {template: t.TemplateAst[], pipes: CompilePipeSummary[]} {
|
preserveWhitespaces: boolean): {template: t.TemplateAst[], pipes: CompilePipeSummary[]} {
|
||||||
const result = this.tryParse(
|
const result = this.tryParse(
|
||||||
component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
|
component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
|
||||||
const warnings = result.errors !.filter(error => error.level === ParseErrorLevel.WARNING);
|
const warnings = result.errors!.filter(error => error.level === ParseErrorLevel.WARNING);
|
||||||
|
|
||||||
const errors = result.errors !.filter(error => error.level === ParseErrorLevel.ERROR);
|
const errors = result.errors!.filter(error => error.level === ParseErrorLevel.ERROR);
|
||||||
|
|
||||||
if (warnings.length > 0) {
|
if (warnings.length > 0) {
|
||||||
this._console.warn(`Template parse warnings:\n${warnings.join('\n')}`);
|
this._console.warn(`Template parse warnings:\n${warnings.join('\n')}`);
|
||||||
@ -106,7 +108,7 @@ export class TemplateParser {
|
|||||||
throw syntaxError(`Template parse errors:\n${errorString}`, errors);
|
throw syntaxError(`Template parse errors:\n${errorString}`, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {template: result.templateAst !, pipes: result.usedPipes !};
|
return {template: result.templateAst!, pipes: result.usedPipes!};
|
||||||
}
|
}
|
||||||
|
|
||||||
tryParse(
|
tryParse(
|
||||||
@ -114,7 +116,7 @@ export class TemplateParser {
|
|||||||
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
|
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
|
||||||
templateUrl: string, preserveWhitespaces: boolean): TemplateParseResult {
|
templateUrl: string, preserveWhitespaces: boolean): TemplateParseResult {
|
||||||
let htmlParseResult = typeof template === 'string' ?
|
let htmlParseResult = typeof template === 'string' ?
|
||||||
this._htmlParser !.parse(template, templateUrl, {
|
this._htmlParser!.parse(template, templateUrl, {
|
||||||
tokenizeExpansionForms: true,
|
tokenizeExpansionForms: true,
|
||||||
interpolationConfig: this.getInterpolationConfig(component)
|
interpolationConfig: this.getInterpolationConfig(component)
|
||||||
}) :
|
}) :
|
||||||
@ -139,7 +141,7 @@ export class TemplateParser {
|
|||||||
const uniqDirectives = removeSummaryDuplicates(directives);
|
const uniqDirectives = removeSummaryDuplicates(directives);
|
||||||
const uniqPipes = removeSummaryDuplicates(pipes);
|
const uniqPipes = removeSummaryDuplicates(pipes);
|
||||||
const providerViewContext = new ProviderViewContext(this._reflector, component);
|
const providerViewContext = new ProviderViewContext(this._reflector, component);
|
||||||
let interpolationConfig: InterpolationConfig = undefined !;
|
let interpolationConfig: InterpolationConfig = undefined!;
|
||||||
if (component.template && component.template.interpolation) {
|
if (component.template && component.template.interpolation) {
|
||||||
interpolationConfig = {
|
interpolationConfig = {
|
||||||
start: component.template.interpolation[0],
|
start: component.template.interpolation[0],
|
||||||
@ -147,7 +149,7 @@ export class TemplateParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const bindingParser = new BindingParser(
|
const bindingParser = new BindingParser(
|
||||||
this._exprParser, interpolationConfig !, this._schemaRegistry, uniqPipes, errors);
|
this._exprParser, interpolationConfig!, this._schemaRegistry, uniqPipes, errors);
|
||||||
const parseVisitor = new TemplateParseVisitor(
|
const parseVisitor = new TemplateParseVisitor(
|
||||||
this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser,
|
this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser,
|
||||||
this._schemaRegistry, schemas, errors);
|
this._schemaRegistry, schemas, errors);
|
||||||
@ -164,8 +166,9 @@ export class TemplateParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.transforms) {
|
if (this.transforms) {
|
||||||
this.transforms.forEach(
|
this.transforms.forEach((transform: t.TemplateAstVisitor) => {
|
||||||
(transform: t.TemplateAstVisitor) => { result = t.templateVisitAll(transform, result); });
|
result = t.templateVisitAll(transform, result);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TemplateParseResult(result, usedPipes, errors);
|
return new TemplateParseResult(result, usedPipes, errors);
|
||||||
@ -224,29 +227,35 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
||||||
this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
|
this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
|
||||||
directives.forEach((directive, index) => {
|
directives.forEach((directive, index) => {
|
||||||
const selector = CssSelector.parse(directive.selector !);
|
const selector = CssSelector.parse(directive.selector!);
|
||||||
this.selectorMatcher.addSelectables(selector, directive);
|
this.selectorMatcher.addSelectables(selector, directive);
|
||||||
this.directivesIndex.set(directive, index);
|
this.directivesIndex.set(directive, index);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpansion(expansion: html.Expansion, context: any): any { return null; }
|
visitExpansion(expansion: html.Expansion, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return null; }
|
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitText(text: html.Text, parent: ElementContext): any {
|
visitText(text: html.Text, parent: ElementContext): any {
|
||||||
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !;
|
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!;
|
||||||
const valueNoNgsp = replaceNgsp(text.value);
|
const valueNoNgsp = replaceNgsp(text.value);
|
||||||
const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan !);
|
const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan!);
|
||||||
return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan !) :
|
return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan!) :
|
||||||
new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan !);
|
new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAttribute(attribute: html.Attribute, context: any): any {
|
visitAttribute(attribute: html.Attribute, context: any): any {
|
||||||
return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitComment(comment: html.Comment, context: any): any { return null; }
|
visitComment(comment: html.Comment, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitElement(element: html.Element, parent: ElementContext): any {
|
visitElement(element: html.Element, parent: ElementContext): any {
|
||||||
const queryStartIndex = this.contentQueryStartId;
|
const queryStartIndex = this.contentQueryStartId;
|
||||||
@ -307,7 +316,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const parsedVariables: ParsedVariable[] = [];
|
const parsedVariables: ParsedVariable[] = [];
|
||||||
const absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset;
|
const absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset;
|
||||||
this._bindingParser.parseInlineTemplateBinding(
|
this._bindingParser.parseInlineTemplateBinding(
|
||||||
templateKey !, templateValue !, attr.sourceSpan, absoluteOffset, templateMatchableAttrs,
|
templateKey!, templateValue!, attr.sourceSpan, absoluteOffset, templateMatchableAttrs,
|
||||||
templateElementOrDirectiveProps, parsedVariables);
|
templateElementOrDirectiveProps, parsedVariables);
|
||||||
templateElementVars.push(...parsedVariables.map(v => t.VariableAst.fromParsedVariable(v)));
|
templateElementVars.push(...parsedVariables.map(v => t.VariableAst.fromParsedVariable(v)));
|
||||||
}
|
}
|
||||||
@ -326,52 +335,51 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const boundDirectivePropNames = new Set<string>();
|
const boundDirectivePropNames = new Set<string>();
|
||||||
const directiveAsts = this._createDirectiveAsts(
|
const directiveAsts = this._createDirectiveAsts(
|
||||||
isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps,
|
isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps,
|
||||||
elementOrDirectiveRefs, element.sourceSpan !, references, boundDirectivePropNames);
|
elementOrDirectiveRefs, element.sourceSpan!, references, boundDirectivePropNames);
|
||||||
const elementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
const elementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
||||||
element.name, elementOrDirectiveProps, boundDirectivePropNames);
|
element.name, elementOrDirectiveProps, boundDirectivePropNames);
|
||||||
const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
||||||
|
|
||||||
const providerContext = new ProviderElementContext(
|
const providerContext = new ProviderElementContext(
|
||||||
this.providerViewContext, parent.providerContext !, isViewRoot, directiveAsts, attrs,
|
this.providerViewContext, parent.providerContext!, isViewRoot, directiveAsts, attrs,
|
||||||
references, isTemplateElement, queryStartIndex, element.sourceSpan !);
|
references, isTemplateElement, queryStartIndex, element.sourceSpan!);
|
||||||
|
|
||||||
const children: t.TemplateAst[] = html.visitAll(
|
const children: t.TemplateAst[] = html.visitAll(
|
||||||
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
||||||
ElementContext.create(
|
ElementContext.create(
|
||||||
isTemplateElement, directiveAsts,
|
isTemplateElement, directiveAsts,
|
||||||
isTemplateElement ? parent.providerContext ! : providerContext));
|
isTemplateElement ? parent.providerContext! : providerContext));
|
||||||
providerContext.afterElement();
|
providerContext.afterElement();
|
||||||
// Override the actual selector when the `ngProjectAs` attribute is provided
|
// Override the actual selector when the `ngProjectAs` attribute is provided
|
||||||
const projectionSelector = preparsedElement.projectAs != '' ?
|
const projectionSelector = preparsedElement.projectAs != '' ?
|
||||||
CssSelector.parse(preparsedElement.projectAs)[0] :
|
CssSelector.parse(preparsedElement.projectAs)[0] :
|
||||||
elementCssSelector;
|
elementCssSelector;
|
||||||
const ngContentIndex = parent.findNgContentIndex(projectionSelector) !;
|
const ngContentIndex = parent.findNgContentIndex(projectionSelector)!;
|
||||||
let parsedElement: t.TemplateAst;
|
let parsedElement: t.TemplateAst;
|
||||||
|
|
||||||
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
||||||
// `<ng-content>` element
|
// `<ng-content>` element
|
||||||
if (element.children && !element.children.every(_isEmptyTextNode)) {
|
if (element.children && !element.children.every(_isEmptyTextNode)) {
|
||||||
this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan !);
|
this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedElement = new t.NgContentAst(
|
parsedElement = new t.NgContentAst(
|
||||||
this.ngContentCount++, hasInlineTemplates ? null ! : ngContentIndex,
|
this.ngContentCount++, hasInlineTemplates ? null! : ngContentIndex, element.sourceSpan!);
|
||||||
element.sourceSpan !);
|
|
||||||
} else if (isTemplateElement) {
|
} else if (isTemplateElement) {
|
||||||
// `<ng-template>` element
|
// `<ng-template>` element
|
||||||
this._assertAllEventsPublishedByDirectives(directiveAsts, events);
|
this._assertAllEventsPublishedByDirectives(directiveAsts, events);
|
||||||
this._assertNoComponentsNorElementBindingsOnTemplate(
|
this._assertNoComponentsNorElementBindingsOnTemplate(
|
||||||
directiveAsts, elementProps, element.sourceSpan !);
|
directiveAsts, elementProps, element.sourceSpan!);
|
||||||
|
|
||||||
parsedElement = new t.EmbeddedTemplateAst(
|
parsedElement = new t.EmbeddedTemplateAst(
|
||||||
attrs, events, references, elementVars, providerContext.transformedDirectiveAsts,
|
attrs, events, references, elementVars, providerContext.transformedDirectiveAsts,
|
||||||
providerContext.transformProviders, providerContext.transformedHasViewContainer,
|
providerContext.transformProviders, providerContext.transformedHasViewContainer,
|
||||||
providerContext.queryMatches, children, hasInlineTemplates ? null ! : ngContentIndex,
|
providerContext.queryMatches, children, hasInlineTemplates ? null! : ngContentIndex,
|
||||||
element.sourceSpan !);
|
element.sourceSpan!);
|
||||||
} else {
|
} else {
|
||||||
// element other than `<ng-content>` and `<ng-template>`
|
// element other than `<ng-content>` and `<ng-template>`
|
||||||
this._assertElementExists(matchElement, element);
|
this._assertElementExists(matchElement, element);
|
||||||
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan !);
|
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan!);
|
||||||
|
|
||||||
const ngContentIndex =
|
const ngContentIndex =
|
||||||
hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
|
hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
|
||||||
@ -389,22 +397,22 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector);
|
const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector);
|
||||||
const templateBoundDirectivePropNames = new Set<string>();
|
const templateBoundDirectivePropNames = new Set<string>();
|
||||||
const templateDirectiveAsts = this._createDirectiveAsts(
|
const templateDirectiveAsts = this._createDirectiveAsts(
|
||||||
true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan !, [],
|
true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan!, [],
|
||||||
templateBoundDirectivePropNames);
|
templateBoundDirectivePropNames);
|
||||||
const templateElementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
const templateElementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
||||||
elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
|
elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
|
||||||
this._assertNoComponentsNorElementBindingsOnTemplate(
|
this._assertNoComponentsNorElementBindingsOnTemplate(
|
||||||
templateDirectiveAsts, templateElementProps, element.sourceSpan !);
|
templateDirectiveAsts, templateElementProps, element.sourceSpan!);
|
||||||
const templateProviderContext = new ProviderElementContext(
|
const templateProviderContext = new ProviderElementContext(
|
||||||
this.providerViewContext, parent.providerContext !, parent.isTemplateElement,
|
this.providerViewContext, parent.providerContext!, parent.isTemplateElement,
|
||||||
templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan !);
|
templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan!);
|
||||||
templateProviderContext.afterElement();
|
templateProviderContext.afterElement();
|
||||||
|
|
||||||
parsedElement = new t.EmbeddedTemplateAst(
|
parsedElement = new t.EmbeddedTemplateAst(
|
||||||
[], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts,
|
[], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts,
|
||||||
templateProviderContext.transformProviders,
|
templateProviderContext.transformProviders,
|
||||||
templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches,
|
templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches,
|
||||||
[parsedElement], ngContentIndex, element.sourceSpan !);
|
[parsedElement], ngContentIndex, element.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedElement;
|
return parsedElement;
|
||||||
@ -538,7 +546,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
let matchElement = false;
|
let matchElement = false;
|
||||||
|
|
||||||
selectorMatcher.match(elementCssSelector, (selector, directive) => {
|
selectorMatcher.match(elementCssSelector, (selector, directive) => {
|
||||||
directives[this.directivesIndex.get(directive) !] = directive;
|
directives[this.directivesIndex.get(directive)!] = directive;
|
||||||
matchElement = matchElement || selector.hasElementSelector();
|
matchElement = matchElement || selector.hasElementSelector();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -554,7 +562,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
elementSourceSpan: ParseSourceSpan, targetReferences: t.ReferenceAst[],
|
elementSourceSpan: ParseSourceSpan, targetReferences: t.ReferenceAst[],
|
||||||
targetBoundDirectivePropNames: Set<string>): t.DirectiveAst[] {
|
targetBoundDirectivePropNames: Set<string>): t.DirectiveAst[] {
|
||||||
const matchedReferences = new Set<string>();
|
const matchedReferences = new Set<string>();
|
||||||
let component: CompileDirectiveSummary = null !;
|
let component: CompileDirectiveSummary = null!;
|
||||||
|
|
||||||
const directiveAsts = directives.map((directive) => {
|
const directiveAsts = directives.map((directive) => {
|
||||||
const sourceSpan = new ParseSourceSpan(
|
const sourceSpan = new ParseSourceSpan(
|
||||||
@ -566,15 +574,14 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
const directiveProperties: t.BoundDirectivePropertyAst[] = [];
|
const directiveProperties: t.BoundDirectivePropertyAst[] = [];
|
||||||
const boundProperties =
|
const boundProperties =
|
||||||
this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan) !;
|
this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan)!;
|
||||||
|
|
||||||
let hostProperties =
|
let hostProperties =
|
||||||
boundProperties.map(prop => t.BoundElementPropertyAst.fromBoundProperty(prop));
|
boundProperties.map(prop => t.BoundElementPropertyAst.fromBoundProperty(prop));
|
||||||
// Note: We need to check the host properties here as well,
|
// Note: We need to check the host properties here as well,
|
||||||
// as we don't know the element name in the DirectiveWrapperCompiler yet.
|
// as we don't know the element name in the DirectiveWrapperCompiler yet.
|
||||||
hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
|
hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
|
||||||
const parsedEvents =
|
const parsedEvents = this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan)!;
|
||||||
this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan) !;
|
|
||||||
this._createDirectivePropertyAsts(
|
this._createDirectivePropertyAsts(
|
||||||
directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
|
directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
|
||||||
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
||||||
@ -602,7 +609,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
elOrDirRef.sourceSpan);
|
elOrDirRef.sourceSpan);
|
||||||
}
|
}
|
||||||
} else if (!component) {
|
} else if (!component) {
|
||||||
let refToken: CompileTokenMetadata = null !;
|
let refToken: CompileTokenMetadata = null!;
|
||||||
if (isTemplateElement) {
|
if (isTemplateElement) {
|
||||||
refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
|
refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
|
||||||
}
|
}
|
||||||
@ -663,7 +670,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
|
|
||||||
private _findComponentDirectiveNames(directives: t.DirectiveAst[]): string[] {
|
private _findComponentDirectiveNames(directives: t.DirectiveAst[]): string[] {
|
||||||
return this._findComponentDirectives(directives)
|
return this._findComponentDirectives(directives)
|
||||||
.map(directive => identifierName(directive.directive.type) !);
|
.map(directive => identifierName(directive.directive.type)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _assertOnlyOneComponent(directives: t.DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
private _assertOnlyOneComponent(directives: t.DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
||||||
@ -691,16 +698,16 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
|
|
||||||
if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
|
if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
|
||||||
let errorMsg = `'${elName}' is not a known element:\n`;
|
let errorMsg = `'${elName}' is not a known element:\n`;
|
||||||
errorMsg +=
|
errorMsg += `1. If '${
|
||||||
`1. If '${elName}' is an Angular component, then verify that it is part of this module.\n`;
|
elName}' is an Angular component, then verify that it is part of this module.\n`;
|
||||||
if (elName.indexOf('-') > -1) {
|
if (elName.indexOf('-') > -1) {
|
||||||
errorMsg +=
|
errorMsg += `2. If '${
|
||||||
`2. If '${elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
|
elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
|
||||||
} else {
|
} else {
|
||||||
errorMsg +=
|
errorMsg +=
|
||||||
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
||||||
}
|
}
|
||||||
this._reportError(errorMsg, element.sourceSpan !);
|
this._reportError(errorMsg, element.sourceSpan!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,7 +721,8 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
elementProps.forEach(prop => {
|
elementProps.forEach(prop => {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`,
|
`Property binding ${
|
||||||
|
prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -733,7 +741,9 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
events.forEach(event => {
|
events.forEach(event => {
|
||||||
if (event.target != null || !allDirectiveEvents.has(event.name)) {
|
if (event.target != null || !allDirectiveEvents.has(event.name)) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Event binding ${event.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`,
|
`Event binding ${
|
||||||
|
event
|
||||||
|
.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`,
|
||||||
event.sourceSpan);
|
event.sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -746,16 +756,20 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
return boundProps.filter((boundProp) => {
|
return boundProps.filter((boundProp) => {
|
||||||
if (boundProp.type === t.PropertyBindingType.Property &&
|
if (boundProp.type === t.PropertyBindingType.Property &&
|
||||||
!this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) {
|
!this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) {
|
||||||
let errorMsg =
|
let errorMsg = `Can't bind to '${boundProp.name}' since it isn't a known property of '${
|
||||||
`Can't bind to '${boundProp.name}' since it isn't a known property of '${elementName}'.`;
|
elementName}'.`;
|
||||||
if (elementName.startsWith('ng-')) {
|
if (elementName.startsWith('ng-')) {
|
||||||
errorMsg +=
|
errorMsg +=
|
||||||
`\n1. If '${boundProp.name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` +
|
`\n1. If '${
|
||||||
|
boundProp
|
||||||
|
.name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` +
|
||||||
`\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
`\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
||||||
} else if (elementName.indexOf('-') > -1) {
|
} else if (elementName.indexOf('-') > -1) {
|
||||||
errorMsg +=
|
errorMsg +=
|
||||||
`\n1. If '${elementName}' is an Angular component and it has '${boundProp.name}' input, then verify that it is part of this module.` +
|
`\n1. If '${elementName}' is an Angular component and it has '${
|
||||||
`\n2. If '${elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` +
|
boundProp.name}' input, then verify that it is part of this module.` +
|
||||||
|
`\n2. If '${
|
||||||
|
elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` +
|
||||||
`\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
`\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
|
||||||
}
|
}
|
||||||
this._reportError(errorMsg, boundProp.sourceSpan);
|
this._reportError(errorMsg, boundProp.sourceSpan);
|
||||||
@ -791,20 +805,26 @@ class NonBindableVisitor implements html.Visitor {
|
|||||||
ast.name, html.visitAll(this, ast.attrs), [], [], [], [], [], false, [], children,
|
ast.name, html.visitAll(this, ast.attrs), [], [], [], [], [], false, [], children,
|
||||||
ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
|
ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
|
||||||
}
|
}
|
||||||
visitComment(comment: html.Comment, context: any): any { return null; }
|
visitComment(comment: html.Comment, context: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitAttribute(attribute: html.Attribute, context: any): t.AttrAst {
|
visitAttribute(attribute: html.Attribute, context: any): t.AttrAst {
|
||||||
return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: html.Text, parent: ElementContext): t.TextAst {
|
visitText(text: html.Text, parent: ElementContext): t.TextAst {
|
||||||
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !;
|
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!;
|
||||||
return new t.TextAst(text.value, ngContentIndex, text.sourceSpan !);
|
return new t.TextAst(text.value, ngContentIndex, text.sourceSpan!);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpansion(expansion: html.Expansion, context: any): any { return expansion; }
|
visitExpansion(expansion: html.Expansion, context: any): any {
|
||||||
|
return expansion;
|
||||||
|
}
|
||||||
|
|
||||||
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return expansionCase; }
|
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any {
|
||||||
|
return expansionCase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -824,7 +844,7 @@ class ElementOrDirectiveRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
|
/** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
|
||||||
function splitExportAs(exportAs: string | null): string[] {
|
function splitExportAs(exportAs: string|null): string[] {
|
||||||
return exportAs ? exportAs.split(',').map(e => e.trim()) : [];
|
return exportAs ? exportAs.split(',').map(e => e.trim()) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +857,7 @@ class ElementContext {
|
|||||||
isTemplateElement: boolean, directives: t.DirectiveAst[],
|
isTemplateElement: boolean, directives: t.DirectiveAst[],
|
||||||
providerContext: ProviderElementContext): ElementContext {
|
providerContext: ProviderElementContext): ElementContext {
|
||||||
const matcher = new SelectorMatcher();
|
const matcher = new SelectorMatcher();
|
||||||
let wildcardNgContentIndex: number = null !;
|
let wildcardNgContentIndex: number = null!;
|
||||||
const component = directives.find(directive => directive.directive.isComponent);
|
const component = directives.find(directive => directive.directive.isComponent);
|
||||||
if (component) {
|
if (component) {
|
||||||
const ngContentSelectors = component.directive.template !.ngContentSelectors;
|
const ngContentSelectors = component.directive.template !.ngContentSelectors;
|
||||||
@ -859,8 +879,9 @@ class ElementContext {
|
|||||||
|
|
||||||
findNgContentIndex(selector: CssSelector): number|null {
|
findNgContentIndex(selector: CssSelector): number|null {
|
||||||
const ngContentIndices: number[] = [];
|
const ngContentIndices: number[] = [];
|
||||||
this._ngContentIndexMatcher.match(
|
this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => {
|
||||||
selector, (selector, ngContentIndex) => { ngContentIndices.push(ngContentIndex); });
|
ngContentIndices.push(ngContentIndex);
|
||||||
|
});
|
||||||
ngContentIndices.sort();
|
ngContentIndices.sort();
|
||||||
if (this._wildcardNgContentIndex != null) {
|
if (this._wildcardNgContentIndex != null) {
|
||||||
ngContentIndices.push(this._wildcardNgContentIndex);
|
ngContentIndices.push(this._wildcardNgContentIndex);
|
||||||
@ -897,7 +918,7 @@ function _isEmptyTextNode(node: html.Node): boolean {
|
|||||||
return node instanceof html.Text && node.value.trim().length == 0;
|
return node instanceof html.Text && node.value.trim().length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeSummaryDuplicates<T extends{type: CompileTypeMetadata}>(items: T[]): T[] {
|
export function removeSummaryDuplicates<T extends {type: CompileTypeMetadata}>(items: T[]): T[] {
|
||||||
const map = new Map<any, T>();
|
const map = new Map<any, T>();
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
|
@ -20,9 +20,9 @@ const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
|
|||||||
const NG_PROJECT_AS = 'ngProjectAs';
|
const NG_PROJECT_AS = 'ngProjectAs';
|
||||||
|
|
||||||
export function preparseElement(ast: html.Element): PreparsedElement {
|
export function preparseElement(ast: html.Element): PreparsedElement {
|
||||||
let selectAttr: string = null !;
|
let selectAttr: string = null!;
|
||||||
let hrefAttr: string = null !;
|
let hrefAttr: string = null!;
|
||||||
let relAttr: string = null !;
|
let relAttr: string = null!;
|
||||||
let nonBindable = false;
|
let nonBindable = false;
|
||||||
let projectAs = '';
|
let projectAs = '';
|
||||||
ast.attrs.forEach(attr => {
|
ast.attrs.forEach(attr => {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user