UNPKG

angular2

Version:

Angular 2 - a web framework for modern web apps

195 lines (194 loc) 8.79 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { Injectable } from 'angular2/src/core/di'; import { StringWrapper, RegExpWrapper, CONST_EXPR, isPresent } from 'angular2/src/facade/lang'; import { HtmlAttrAst, HtmlElementAst, HtmlExpansionAst } from './html_ast'; import { HtmlParser, HtmlParseTreeResult } from './html_parser'; import { dashCaseToCamelCase } from './util'; var LONG_SYNTAX_REGEXP = /^(?:on-(.*)|bindon-(.*)|bind-(.*)|var-(.*))$/ig; var SHORT_SYNTAX_REGEXP = /^(?:\((.*)\)|\[\((.*)\)\]|\[(.*)\]|#(.*))$/ig; var VARIABLE_TPL_BINDING_REGEXP = /(\bvar\s+|#)(\S+)/ig; var TEMPLATE_SELECTOR_REGEXP = /^(\S+)/g; var SPECIAL_PREFIXES_REGEXP = /^(class|style|attr)\./ig; var INTERPOLATION_REGEXP = /\{\{.*?\}\}/g; const SPECIAL_CASES = CONST_EXPR([ 'ng-non-bindable', 'ng-default-control', 'ng-no-form', ]); /** * Convert templates to the case sensitive syntax * * @internal */ export class LegacyHtmlAstTransformer { constructor(dashCaseSelectors) { this.dashCaseSelectors = dashCaseSelectors; this.rewrittenAst = []; this.visitingTemplateEl = false; } visitComment(ast, context) { return ast; } visitElement(ast, context) { this.visitingTemplateEl = ast.name.toLowerCase() == 'template'; let attrs = ast.attrs.map(attr => attr.visit(this, null)); let children = ast.children.map(child => child.visit(this, null)); return new HtmlElementAst(ast.name, attrs, children, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan); } visitAttr(originalAst, context) { let ast = originalAst; if (this.visitingTemplateEl) { if (isPresent(RegExpWrapper.firstMatch(LONG_SYNTAX_REGEXP, ast.name))) { // preserve the "-" in the prefix for the long syntax ast = this._rewriteLongSyntax(ast); } else { // rewrite any other attribute let name = dashCaseToCamelCase(ast.name); ast = name == ast.name ? ast : new HtmlAttrAst(name, ast.value, ast.sourceSpan); } } else { ast = this._rewriteTemplateAttribute(ast); ast = this._rewriteLongSyntax(ast); ast = this._rewriteShortSyntax(ast); ast = this._rewriteStar(ast); ast = this._rewriteInterpolation(ast); ast = this._rewriteSpecialCases(ast); } if (ast !== originalAst) { this.rewrittenAst.push(ast); } return ast; } visitText(ast, context) { return ast; } visitExpansion(ast, context) { let cases = ast.cases.map(c => c.visit(this, null)); return new HtmlExpansionAst(ast.switchValue, ast.type, cases, ast.sourceSpan, ast.switchValueSourceSpan); } visitExpansionCase(ast, context) { return ast; } _rewriteLongSyntax(ast) { let m = RegExpWrapper.firstMatch(LONG_SYNTAX_REGEXP, ast.name); let attrName = ast.name; let attrValue = ast.value; if (isPresent(m)) { if (isPresent(m[1])) { attrName = `on-${dashCaseToCamelCase(m[1])}`; } else if (isPresent(m[2])) { attrName = `bindon-${dashCaseToCamelCase(m[2])}`; } else if (isPresent(m[3])) { attrName = `bind-${dashCaseToCamelCase(m[3])}`; } else if (isPresent(m[4])) { attrName = `var-${dashCaseToCamelCase(m[4])}`; attrValue = dashCaseToCamelCase(attrValue); } } return attrName == ast.name && attrValue == ast.value ? ast : new HtmlAttrAst(attrName, attrValue, ast.sourceSpan); } _rewriteTemplateAttribute(ast) { let name = ast.name; let value = ast.value; if (name.toLowerCase() == 'template') { name = 'template'; // rewrite the directive selector value = StringWrapper.replaceAllMapped(value, TEMPLATE_SELECTOR_REGEXP, (m) => { return dashCaseToCamelCase(m[1]); }); // rewrite the var declarations value = StringWrapper.replaceAllMapped(value, VARIABLE_TPL_BINDING_REGEXP, m => { return `${m[1].toLowerCase()}${dashCaseToCamelCase(m[2])}`; }); } if (name == ast.name && value == ast.value) { return ast; } return new HtmlAttrAst(name, value, ast.sourceSpan); } _rewriteShortSyntax(ast) { let m = RegExpWrapper.firstMatch(SHORT_SYNTAX_REGEXP, ast.name); let attrName = ast.name; let attrValue = ast.value; if (isPresent(m)) { if (isPresent(m[1])) { attrName = `(${dashCaseToCamelCase(m[1])})`; } else if (isPresent(m[2])) { attrName = `[(${dashCaseToCamelCase(m[2])})]`; } else if (isPresent(m[3])) { let prop = StringWrapper.replaceAllMapped(m[3], SPECIAL_PREFIXES_REGEXP, (m) => { return m[1].toLowerCase() + '.'; }); if (prop.startsWith('class.') || prop.startsWith('attr.') || prop.startsWith('style.')) { attrName = `[${prop}]`; } else { attrName = `[${dashCaseToCamelCase(prop)}]`; } } else if (isPresent(m[4])) { attrName = `#${dashCaseToCamelCase(m[4])}`; attrValue = dashCaseToCamelCase(attrValue); } } return attrName == ast.name && attrValue == ast.value ? ast : new HtmlAttrAst(attrName, attrValue, ast.sourceSpan); } _rewriteStar(ast) { let attrName = ast.name; let attrValue = ast.value; if (attrName[0] == '*') { attrName = dashCaseToCamelCase(attrName); // rewrite the var declarations attrValue = StringWrapper.replaceAllMapped(attrValue, VARIABLE_TPL_BINDING_REGEXP, m => { return `${m[1].toLowerCase()}${dashCaseToCamelCase(m[2])}`; }); } return attrName == ast.name && attrValue == ast.value ? ast : new HtmlAttrAst(attrName, attrValue, ast.sourceSpan); } _rewriteInterpolation(ast) { let hasInterpolation = RegExpWrapper.test(INTERPOLATION_REGEXP, ast.value); if (!hasInterpolation) { return ast; } let name = ast.name; if (!(name.startsWith('attr.') || name.startsWith('class.') || name.startsWith('style.'))) { name = dashCaseToCamelCase(ast.name); } return name == ast.name ? ast : new HtmlAttrAst(name, ast.value, ast.sourceSpan); } _rewriteSpecialCases(ast) { let attrName = ast.name; if (SPECIAL_CASES.indexOf(attrName) > -1) { return new HtmlAttrAst(dashCaseToCamelCase(attrName), ast.value, ast.sourceSpan); } if (isPresent(this.dashCaseSelectors) && this.dashCaseSelectors.indexOf(attrName) > -1) { return new HtmlAttrAst(dashCaseToCamelCase(attrName), ast.value, ast.sourceSpan); } return ast; } } export let LegacyHtmlParser = class LegacyHtmlParser extends HtmlParser { parse(sourceContent, sourceUrl, parseExpansionForms = false) { let transformer = new LegacyHtmlAstTransformer(); let htmlParseTreeResult = super.parse(sourceContent, sourceUrl, parseExpansionForms); let rootNodes = htmlParseTreeResult.rootNodes.map(node => node.visit(transformer, null)); return transformer.rewrittenAst.length > 0 ? new HtmlParseTreeResult(rootNodes, htmlParseTreeResult.errors) : htmlParseTreeResult; } }; LegacyHtmlParser = __decorate([ Injectable(), __metadata('design:paramtypes', []) ], LegacyHtmlParser);