Revert "refactor(upgrade): don’t rely on compiler internals"
This reverts commit 8e2c8b3e4d.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
The following code has been copied from the Angular compiler to be used in the upgrade library without
|
||||
the need to import the entire compiler:
|
||||
|
||||
* `selector.ts`
|
||||
* `ml_parser/html_tags.ts`
|
||||
* `ml_parser/tags.ts`
|
||||
* `createElementCssSelector.ts`
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CssSelector} from './selector';
|
||||
|
||||
/*
|
||||
* The following items are copied from the Angular Compiler to be used here
|
||||
* without the need to import the entire compiler into the build
|
||||
*/
|
||||
|
||||
const CLASS_ATTR = 'class';
|
||||
|
||||
export function createElementCssSelector(
|
||||
elementName: string, attributes: [string, string][]): CssSelector {
|
||||
const cssSelector = new CssSelector();
|
||||
const elNameNoNs = splitNsName(elementName)[1];
|
||||
|
||||
cssSelector.setElement(elNameNoNs);
|
||||
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
const attrName = attributes[i][0];
|
||||
const attrNameNoNs = splitNsName(attrName)[1];
|
||||
const attrValue = attributes[i][1];
|
||||
|
||||
cssSelector.addAttribute(attrNameNoNs, attrValue);
|
||||
if (attrName.toLowerCase() == CLASS_ATTR) {
|
||||
const classes = splitClasses(attrValue);
|
||||
classes.forEach(className => cssSelector.addClassName(className));
|
||||
}
|
||||
}
|
||||
return cssSelector;
|
||||
}
|
||||
|
||||
export function splitNsName(elementName: string): [string, string] {
|
||||
if (elementName[0] != ':') {
|
||||
return [null, elementName];
|
||||
}
|
||||
|
||||
const colonIndex = elementName.indexOf(':', 1);
|
||||
|
||||
if (colonIndex == -1) {
|
||||
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
||||
}
|
||||
|
||||
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
||||
}
|
||||
|
||||
export function splitClasses(classAttrValue: string): string[] {
|
||||
return classAttrValue.trim().split(/\s+/g);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {TagContentType, TagDefinition} from './tags';
|
||||
|
||||
export class HtmlTagDefinition implements TagDefinition {
|
||||
private closedByChildren: {[key: string]: boolean} = {};
|
||||
|
||||
closedByParent: boolean = false;
|
||||
requiredParents: {[key: string]: boolean};
|
||||
parentToAdd: string;
|
||||
implicitNamespacePrefix: string;
|
||||
contentType: TagContentType;
|
||||
isVoid: boolean;
|
||||
ignoreFirstLf: boolean;
|
||||
canSelfClose: boolean = false;
|
||||
|
||||
constructor(
|
||||
{closedByChildren, requiredParents, implicitNamespacePrefix,
|
||||
contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false,
|
||||
ignoreFirstLf = false}: {
|
||||
closedByChildren?: string[],
|
||||
closedByParent?: boolean,
|
||||
requiredParents?: string[],
|
||||
implicitNamespacePrefix?: string,
|
||||
contentType?: TagContentType,
|
||||
isVoid?: boolean,
|
||||
ignoreFirstLf?: boolean
|
||||
} = {}) {
|
||||
if (closedByChildren && closedByChildren.length > 0) {
|
||||
closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
|
||||
}
|
||||
this.isVoid = isVoid;
|
||||
this.closedByParent = closedByParent || isVoid;
|
||||
if (requiredParents && requiredParents.length > 0) {
|
||||
this.requiredParents = {};
|
||||
// The first parent is the list is automatically when none of the listed parents are present
|
||||
this.parentToAdd = requiredParents[0];
|
||||
requiredParents.forEach(tagName => this.requiredParents[tagName] = true);
|
||||
}
|
||||
this.implicitNamespacePrefix = implicitNamespacePrefix;
|
||||
this.contentType = contentType;
|
||||
this.ignoreFirstLf = ignoreFirstLf;
|
||||
}
|
||||
|
||||
requireExtraParent(currentParent: string): boolean {
|
||||
if (!this.requiredParents) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!currentParent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lcParent = currentParent.toLowerCase();
|
||||
const isParentTemplate = lcParent === 'template' || currentParent === 'ng-template';
|
||||
return !isParentTemplate && this.requiredParents[lcParent] != true;
|
||||
}
|
||||
|
||||
isClosedByChild(name: string): boolean {
|
||||
return this.isVoid || name.toLowerCase() in this.closedByChildren;
|
||||
}
|
||||
}
|
||||
|
||||
// see http://www.w3.org/TR/html51/syntax.html#optional-tags
|
||||
// This implementation does not fully conform to the HTML5 spec.
|
||||
const TAG_DEFINITIONS: {[key: string]: HtmlTagDefinition} = {
|
||||
'base': new HtmlTagDefinition({isVoid: true}),
|
||||
'meta': new HtmlTagDefinition({isVoid: true}),
|
||||
'area': new HtmlTagDefinition({isVoid: true}),
|
||||
'embed': new HtmlTagDefinition({isVoid: true}),
|
||||
'link': new HtmlTagDefinition({isVoid: true}),
|
||||
'img': new HtmlTagDefinition({isVoid: true}),
|
||||
'input': new HtmlTagDefinition({isVoid: true}),
|
||||
'param': new HtmlTagDefinition({isVoid: true}),
|
||||
'hr': new HtmlTagDefinition({isVoid: true}),
|
||||
'br': new HtmlTagDefinition({isVoid: true}),
|
||||
'source': new HtmlTagDefinition({isVoid: true}),
|
||||
'track': new HtmlTagDefinition({isVoid: true}),
|
||||
'wbr': new HtmlTagDefinition({isVoid: true}),
|
||||
'p': new HtmlTagDefinition({
|
||||
closedByChildren: [
|
||||
'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form',
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr',
|
||||
'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'
|
||||
],
|
||||
closedByParent: true
|
||||
}),
|
||||
'thead': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot']}),
|
||||
'tbody': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot'], closedByParent: true}),
|
||||
'tfoot': new HtmlTagDefinition({closedByChildren: ['tbody'], closedByParent: true}),
|
||||
'tr': new HtmlTagDefinition({
|
||||
closedByChildren: ['tr'],
|
||||
requiredParents: ['tbody', 'tfoot', 'thead'],
|
||||
closedByParent: true
|
||||
}),
|
||||
'td': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
|
||||
'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
|
||||
'col': new HtmlTagDefinition({requiredParents: ['colgroup'], isVoid: true}),
|
||||
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
|
||||
'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
|
||||
'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
|
||||
'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
|
||||
'dd': new HtmlTagDefinition({closedByChildren: ['dt', 'dd'], closedByParent: true}),
|
||||
'rb': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||
'rt': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||
'rtc': new HtmlTagDefinition({closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true}),
|
||||
'rp': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||
'optgroup': new HtmlTagDefinition({closedByChildren: ['optgroup'], closedByParent: true}),
|
||||
'option': new HtmlTagDefinition({closedByChildren: ['option', 'optgroup'], closedByParent: true}),
|
||||
'pre': new HtmlTagDefinition({ignoreFirstLf: true}),
|
||||
'listing': new HtmlTagDefinition({ignoreFirstLf: true}),
|
||||
'style': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
|
||||
'script': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
|
||||
'title': new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT}),
|
||||
'textarea':
|
||||
new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true}),
|
||||
};
|
||||
|
||||
const _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
|
||||
|
||||
export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
|
||||
return TAG_DEFINITIONS[tagName.toLowerCase()] || _DEFAULT_TAG_DEFINITION;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,8 @@
|
||||
import {ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, ReflectiveInjector, SimpleChange, SimpleChanges, Type} from '@angular/core';
|
||||
|
||||
import * as angular from './angular1';
|
||||
import {createElementCssSelector} from './compiler_helpers/createElementCssSelector';
|
||||
import {CssSelector, SelectorMatcher} from './compiler_helpers/selector';
|
||||
import {ComponentInfo, PropertyBinding} from './component_info';
|
||||
import {$SCOPE} from './constants';
|
||||
import {NgContentSelectorHelper} from './ng_content_selector_helper';
|
||||
@@ -199,52 +201,38 @@ export class DowngradeComponentAdapter {
|
||||
*/
|
||||
private _groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
||||
const projectableNodes: Node[][] = [];
|
||||
let matcher = new SelectorMatcher();
|
||||
let wildcardNgContentIndex: number;
|
||||
|
||||
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
||||
projectableNodes[i] = [];
|
||||
|
||||
const selector = ngContentSelectors[i];
|
||||
if (selector === '*') {
|
||||
wildcardNgContentIndex = i;
|
||||
} else {
|
||||
matcher.addSelectables(CssSelector.parse(selector), i);
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
||||
const ngContentIndices: number[] = [];
|
||||
const node = nodes[j];
|
||||
const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
|
||||
if (ngContentIndex != null) {
|
||||
projectableNodes[ngContentIndex].push(node);
|
||||
const selector =
|
||||
createElementCssSelector(node.nodeName.toLowerCase(), getAttributesAsArray(node));
|
||||
|
||||
matcher.match(selector, (_, index) => ngContentIndices.push(index));
|
||||
ngContentIndices.sort();
|
||||
|
||||
if (wildcardNgContentIndex !== undefined) {
|
||||
ngContentIndices.push(wildcardNgContentIndex);
|
||||
}
|
||||
|
||||
if (ngContentIndices.length) {
|
||||
projectableNodes[ngContentIndices[0]].push(node);
|
||||
}
|
||||
}
|
||||
|
||||
return projectableNodes;
|
||||
}
|
||||
}
|
||||
|
||||
let _matches: (this: any, selector: string) => boolean;
|
||||
|
||||
function matchesSelector(el: any, selector: string): boolean {
|
||||
if (!_matches) {
|
||||
const elProto = <any>Element.prototype;
|
||||
_matches = elProto.matchesSelector || elProto.mozMatchesSelector || elProto.msMatchesSelector ||
|
||||
elProto.oMatchesSelector || elProto.webkitMatchesSelector;
|
||||
}
|
||||
return _matches.call(el, selector);
|
||||
}
|
||||
|
||||
function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number {
|
||||
const ngContentIndices: number[] = [];
|
||||
let wildcardNgContentIndex: number;
|
||||
for (let i = 0; i < ngContentSelectors.length; i++) {
|
||||
const selector = ngContentSelectors[i];
|
||||
if (selector === '*') {
|
||||
wildcardNgContentIndex = i;
|
||||
} else {
|
||||
if (matchesSelector(element, selector)) {
|
||||
ngContentIndices.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ngContentIndices.sort();
|
||||
|
||||
if (wildcardNgContentIndex !== undefined) {
|
||||
ngContentIndices.push(wildcardNgContentIndex);
|
||||
}
|
||||
return ngContentIndices.length ? ngContentIndices[0] : null;
|
||||
}
|
||||
Reference in New Issue
Block a user