test: Add bundle symbol extractor tool (#22002)

This tool will be used for extracting symbols out of bundles so that
we can assert that only whitelisted symbols are allowed.

PR Close #22002
This commit is contained in:
Miško Hevery 2018-02-02 15:08:25 -08:00 committed by Miško Hevery
parent 6435ecd3c6
commit 20a900b648
22 changed files with 1172 additions and 5 deletions

View File

@ -1,6 +1,7 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
load("//packages/bazel/src:ng_rollup_bundle.bzl", "ng_rollup_bundle")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
@ -31,7 +32,9 @@ ts_library(
name = "test_lib",
testonly = 1,
srcs = ["domino_typings.d.ts"] + glob(["*_spec.ts"]),
deps = ["//packages:types"],
deps = [
"//packages:types",
],
)
jasmine_node_test(
@ -44,3 +47,9 @@ jasmine_node_test(
],
deps = [":test_lib"],
)
js_expected_symbol_test(
name = "symbol_test",
src = ":bundle.min_debug.js",
golden = ":bundle.golden_symbols.json",
)

View File

@ -0,0 +1,83 @@
[
{
"name": "EMPTY$1"
},
{
"name": "NO_CHANGE"
},
{
"name": "Symbol$1"
},
{
"name": "__global$1"
},
{
"name": "__self$1"
},
{
"name": "__window$1"
},
{
"name": "_renderCompCount"
},
{
"name": "_root"
},
{
"name": "canInsertNativeNode"
},
{
"name": "createLNode"
},
{
"name": "createLView"
},
{
"name": "domRendererFactory3"
},
{
"name": "enterView"
},
{
"name": "executeHooks"
},
{
"name": "findFirstRNode"
},
{
"name": "getDirectiveInstance"
},
{
"name": "getNextLNodeWithProjection"
},
{
"name": "getNextOrParentSiblingNode"
},
{
"name": "invertObject"
},
{
"name": "isProceduralRenderer"
},
{
"name": "leaveView"
},
{
"name": "locateHostElement"
},
{
"name": "noop$2"
},
{
"name": "refreshDynamicChildren"
},
{
"name": "renderComponentOrTemplate"
},
{
"name": "renderEmbeddedTemplate"
},
{
"name": "stringify$1"
}
]

View File

@ -18,10 +18,8 @@ import * as domino from 'domino';
describe('treeshaking with uglify', () => {
let content: string;
beforeAll(() => {
content = fs.readFileSync(
path.join(process.env['TEST_SRCDIR'], PACKAGE, 'bundle.min_debug.js'), UTF8);
});
const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js'));
beforeAll(() => { content = fs.readFileSync(contentPath, UTF8); });
it('should drop unused TypeScript helpers',
() => { expect(content).not.toContain('__asyncGenerator'); });

View File

@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
ts_library(
name = "lib",
testonly = 1,
srcs = glob(
["**/*.ts"],
exclude = [
"**/*_spec.ts",
"**/*_spec",
],
),
deps = [
"//packages:types",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(
["**/*_spec.ts"],
exclude = ["symbol_extractor_spec/**"],
),
deps = [
":lib",
"//packages:types",
],
)
jasmine_node_test(
name = "test",
data = glob(["symbol_extractor_spec/**"]),
deps = [
":test_lib",
],
)

View File

@ -0,0 +1,54 @@
/**
* @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 * as fs from 'fs';
import * as path from 'path';
import {SymbolExtractor} from './symbol_extractor';
// These keys are arbitrary and local to this test.
const update_var = 'UPDATE_GOLDEN';
const update_val = 1;
if (require.main === module) {
const doUpdate = process.env[update_var] == update_val;
const args = process.argv.slice(2) as[string, string];
process.exitCode = main(args, doUpdate) ? 0 : 1;
}
/**
* CLI main method.
*
* ```
* cli javascriptFilePath.js goldenFilePath.json
* ```
*/
function main(argv: [string, string], doUpdate: boolean): boolean {
const javascriptFilePath = require.resolve(argv[0]);
const goldenFilePath = require.resolve(argv[1]);
const javascriptContent = fs.readFileSync(javascriptFilePath).toString();
const goldenContent = fs.readFileSync(goldenFilePath).toString();
const symbolExtractor = new SymbolExtractor(javascriptFilePath, javascriptContent);
let passed: boolean = false;
if (doUpdate) {
fs.writeFileSync(goldenFilePath, JSON.stringify(symbolExtractor.actual, undefined, 2));
console.error('Updated gold file:', goldenFilePath);
passed = true;
} else {
passed = symbolExtractor.compareAndPrintError(goldenFilePath, goldenContent);
if (!passed) {
console.error(`TEST FAILED!`);
console.error(` To update the golden file run: `);
console.error(
` bazel run --define ${update_var}=${update_val} ${process.env['BAZEL_TARGET']}`);
}
}
return passed;
}

View File

@ -0,0 +1,22 @@
# 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
"""This test verifies that a set of top level symbols from a javascript file match a gold file.
"""
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_test")
def js_expected_symbol_test(name, src, golden, **kwargs):
all_data = [src, golden]
all_data += [Label("//tools/symbol-extractor:lib")]
entry_point = "angular/tools/symbol-extractor/cli.js"
nodejs_test(
name = name,
data = all_data,
entry_point = entry_point,
templated_args = ["$(location %s)" % src, "$(location %s)" % golden],
**kwargs
)

View File

@ -0,0 +1,116 @@
/**
* @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 * as fs from 'fs';
import * as ts from 'typescript';
export interface Symbol { name: string; }
export class SymbolExtractor {
public actual: Symbol[];
static symbolSort(a: Symbol, b: Symbol): number {
return a.name == b.name ? 0 : a.name < b.name ? -1 : 1;
}
static parse(path: string, contents: string): Symbol[] {
const symbols: Symbol[] = [];
const source: ts.SourceFile = ts.createSourceFile(path, contents, ts.ScriptTarget.Latest, true);
let fnDepth = 0;
function visitor(child: ts.Node) {
switch (child.kind) {
case ts.SyntaxKind.FunctionExpression:
fnDepth++;
if (fnDepth <= 1) {
// Only go into function expression once for the outer closure.
ts.forEachChild(child, visitor);
}
break;
case ts.SyntaxKind.SourceFile:
case ts.SyntaxKind.VariableStatement:
case ts.SyntaxKind.VariableDeclarationList:
case ts.SyntaxKind.ExpressionStatement:
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.Block:
case ts.SyntaxKind.PrefixUnaryExpression:
ts.forEachChild(child, visitor);
break;
case ts.SyntaxKind.VariableDeclaration:
const varDecl = child as ts.VariableDeclaration;
if (varDecl.initializer) {
symbols.push({name: varDecl.name.getText()});
}
break;
case ts.SyntaxKind.FunctionDeclaration:
const funcDecl = child as ts.FunctionDeclaration;
funcDecl.name && symbols.push({name: funcDecl.name.getText()});
break;
default:
// Left for easier debugging.
// console.log('###', ts.SyntaxKind[child.kind], child.getText());
}
if (symbols.length && symbols[symbols.length - 1].name == 'type') {
debugger;
}
}
visitor(source);
symbols.sort(SymbolExtractor.symbolSort);
return symbols;
}
static diff(actual: Symbol[], expected: string|((Symbol | string)[])): {[name: string]: string} {
if (typeof expected == 'string') {
expected = JSON.parse(expected);
}
const diff: {[name: string]: ('missing' | 'extra')} = {};
(expected as(Symbol | string)[]).forEach((nameOrSymbol) => {
diff[typeof nameOrSymbol == 'string' ? nameOrSymbol : nameOrSymbol.name] = 'missing';
});
actual.forEach((s) => {
if (diff[s.name] === 'missing') {
delete diff[s.name];
} else {
diff[s.name] = 'extra';
}
});
return diff;
}
constructor(private path: string, private contents: string) {
this.actual = SymbolExtractor.parse(path, contents);
}
expect(expectedSymbols: (string|Symbol)[]) {
expect(SymbolExtractor.diff(this.actual, expectedSymbols)).toEqual({});
}
compareAndPrintError(goldenFilePath: string, expected: string|((Symbol | string)[])): boolean {
let passed = true;
const diff = SymbolExtractor.diff(this.actual, expected);
Object.keys(diff).forEach((key) => {
if (passed) {
console.error(`Expected symbols in '${this.path}' did not match gold file.`);
passed = false;
}
console.error(` Symbol: ${key} => ${diff[key]}`);
});
return passed;
}
}
function toSymbol(v: string | Symbol): Symbol {
return typeof v == 'string' ? {'name': v} : v as Symbol;
}
function toName(symbol: Symbol): string {
return symbol.name;
}

View File

@ -0,0 +1,38 @@
/**
* @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 * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import {Symbol, SymbolExtractor} from './symbol_extractor';
describe('scenarios', () => {
const symbolExtractorSpecDir = path.dirname(
require.resolve('angular/tools/symbol-extractor/symbol_extractor_spec/empty.json'));
const scenarioFiles = fs.readdirSync(symbolExtractorSpecDir);
for (let i = 0; i < scenarioFiles.length; i = i + 2) {
let jsFile = scenarioFiles[i];
let jsonFile = scenarioFiles[i + 1];
let testName = jsFile.substring(0, jsFile.lastIndexOf('.'));
if (!jsFile.endsWith('.js')) throw new Error('Expected: .js file found: ' + jsFile);
if (!jsonFile.endsWith('.json')) throw new Error('Expected: .json file found: ' + jsonFile);
// Left here so that it is easy to debug single test.
// if (testName !== 'hello_world_min_debug') continue;
it(testName, () => {
const jsFileContent = fs.readFileSync(path.join(symbolExtractorSpecDir, jsFile)).toString();
const jsonFileContent =
fs.readFileSync(path.join(symbolExtractorSpecDir, jsonFile)).toString();
const symbols = SymbolExtractor.parse(testName, jsFileContent);
const diff = SymbolExtractor.diff(symbols, jsonFileContent);
expect(diff).toEqual({});
});
}
});

View File

@ -0,0 +1,15 @@
/**
* @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
*/
!function() {
function A() {
function ignoreA() {}
}
function B() { let ignoreB = {}; }
!function() { let ignoreC = {}; };
}();

View File

@ -0,0 +1,4 @@
[
"A",
"B"
]

View File

@ -0,0 +1,9 @@
/**
* @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
*/
export let __empty__;

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,9 @@
/**
* @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
*/
(function() {})();

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,675 @@
/**
* @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
*/
!function() {
'use strict';
/**
*@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
*/
/**
*@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
*/
var ChangeDetectionStrategy, ChangeDetectorStatus, ViewEncapsulation;
Object;
ChangeDetectionStrategy || (ChangeDetectionStrategy = {});
ChangeDetectorStatus || (ChangeDetectorStatus = {});
/**
* @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
*/ Object;
ViewEncapsulation || (ViewEncapsulation = {});
/**
*@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
*/
/**
* @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
*/ 'undefined' != typeof window &&
window,
'undefined' != typeof self && 'undefined' != typeof WorkerGlobalScope &&
self instanceof WorkerGlobalScope && self,
'undefined' != typeof global && global;
/**
*@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
*/
String;
/**
*@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
*/
Function;
var __window$1 = 'undefined' != typeof window && window, __self$1 = 'undefined' != typeof self &&
'undefined' != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope && self,
__global$1 = 'undefined' != typeof global && global,
_root = __window$1 || __global$1 || __self$1;
!function() {
if (!_root) throw new Error('RxJS could not find any global context (window, self, global)');
}();
Array;
!function() { Object.setPrototypeOf || Array; }();
Error;
var RendererStyleFlags2, Symbol$1 = _root.Symbol;
'function' == typeof Symbol$1 && 'function' == typeof Symbol$1.for &&
Symbol$1.for ('rxSubscriber'),
function() { Object.setPrototypeOf || Array; }();
!function(context) {
var $$observable, Symbol = _root.Symbol;
if ('function' == typeof Symbol)
if (Symbol.observable)
$$observable = Symbol.observable;
else {
$$observable = Symbol('observable');
Symbol.observable = $$observable;
}
else
$$observable = '@@observable';
}();
(function() { Object.setPrototypeOf || Array; })(),
function() { Object.setPrototypeOf || Array; }();
!function() { Object.setPrototypeOf || Array; }();
(function(root) {
var Symbol = root.Symbol;
if ('function' == typeof Symbol) {
Symbol.iterator || (Symbol.iterator = Symbol('iterator polyfill'));
return Symbol.iterator;
}
var Set_1 = root.Set;
if (Set_1 && 'function' == typeof new Set_1()['@@iterator']) return '@@iterator';
var Map_1 = root.Map;
if (Map_1)
for (var keys = Object.getOwnPropertyNames(Map_1.prototype), i = 0; i < keys.length; ++i) {
var key = keys[i];
if ('entries' !== key && 'size' !== key && Map_1.prototype[key] === Map_1.prototype.entries)
return key;
}
})(_root),
function() { Object.setPrototypeOf || Array; }();
(function() { Object.setPrototypeOf || Array; })(),
function() { Object.setPrototypeOf || Array; }();
!function() { Object.setPrototypeOf || Array; }();
Error, function() { Object.setPrototypeOf || Array; }(), function() {
Object.setPrototypeOf || Array;
}(), function() { Object.setPrototypeOf || Array; }();
!function() { Object.setPrototypeOf || Array; }();
Object;
RendererStyleFlags2 || (RendererStyleFlags2 = {});
var RendererStyleFlags3, _renderCompCount = 0;
function executeHooks(data, allHooks, checkHooks, creationMode) {
var hooksToCall = creationMode ? allHooks : checkHooks;
null != hooksToCall &&
function(data, arr) {
for (var i = 0; i < arr.length; i += 2) arr[1 | i].call(data[arr[i]]);
}
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/ (data, hooksToCall);
}
RendererStyleFlags3 || (RendererStyleFlags3 = {});
var domRendererFactory3 = {
createRenderer: function(hostElement, rendererType) { return document; }
};
/**
*@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
*/
/**
* @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
*/ function
getNextLNodeWithProjection(node) {
var pNextOrParent = node.pNextOrParent;
return pNextOrParent ? 1 == (3 & pNextOrParent.flags) ? null : pNextOrParent : node.next;
}
function getNextOrParentSiblingNode(initialNode, rootNode) {
for (var node = initialNode, nextNode = getNextLNodeWithProjection(node); node && !nextNode;) {
if ((node = node.pNextOrParent || node.parent) === rootNode) return null;
nextNode = node && getNextLNodeWithProjection(node);
}
return nextNode;
}
function findFirstRNode(rootNode) {
for (var node = rootNode; node;) {
var type = 3 & node.flags, nextNode = null;
if (3 === type) return node.native;
if (0 === type) {
var childContainerData = node.data;
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
} else
nextNode = 1 === type ? node.data.head : node.child;
node = null === nextNode ? getNextOrParentSiblingNode(node, rootNode) : nextNode;
}
return null;
}
function canInsertNativeNode(parent, view) {
return 3 == (3 & parent.flags) && (parent.view !== view || null === parent.data);
}
function stringify$1(value) {
return 'function' == typeof value ?
value.name || value :
'string' == typeof value ? value : null == value ? '' : '' + value;
}
/**
*@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
*/
var renderer, rendererFactory, previousOrParentNode, isParent, tData, currentView, currentQueries,
creationMode, data, bindingIndex;
currentView = createLView(null, null, createTView());
function enterView(newView, host) {
var oldView = currentView;
data = newView.data;
bindingIndex = newView.bindingStartIndex || 0;
tData = newView.tView.data;
creationMode = newView.creationMode;
renderer = newView.renderer;
if (null != host) {
previousOrParentNode = host;
isParent = !0;
}
currentView = newView;
currentQueries = newView.queries;
return oldView;
}
function leaveView(newView) {
executeHooks(
currentView.data, currentView.tView.viewHooks, currentView.tView.viewCheckHooks,
creationMode);
currentView.creationMode = !1;
currentView.lifecycleStage = 1;
currentView.tView.firstTemplatePass = !1;
enterView(newView, null);
}
function createLView(viewId, renderer, tView, template, context) {
void 0 === template && (template = null);
void 0 === context && (context = null);
return {
parent: currentView,
id: viewId,
node: null,
data: [],
tView: tView,
cleanup: null,
renderer: renderer,
child: null,
tail: null,
next: null,
bindingStartIndex: null,
creationMode: !0,
template: template,
context: context,
dynamicViewCount: 0,
lifecycleStage: 1,
queries: null
};
}
function createLNode(index, type, native, state) {
var parent =
isParent ? previousOrParentNode : previousOrParentNode && previousOrParentNode.parent,
queries =
(isParent ? currentQueries : previousOrParentNode && previousOrParentNode.queries) ||
parent && parent.queries && parent.queries.child(),
isState = null != state, node = {
flags: type,
native: native,
view: currentView,
parent: parent,
child: null,
next: null,
nodeInjector: parent ? parent.nodeInjector : null,
data: isState ? state : null,
queries: queries,
tNode: null,
pNextOrParent: null
};
2 == (2 & type) && isState && (state.node = node);
if (null != index) {
data[index] = node;
index >= tData.length ? tData[index] = null : node.tNode = tData[index];
if (isParent) {
currentQueries = null;
previousOrParentNode.view !== currentView && 2 != (3 & previousOrParentNode.flags) ||
(previousOrParentNode.child = node);
} else
previousOrParentNode && (previousOrParentNode.next = node);
}
previousOrParentNode = node;
isParent = !0;
return node;
}
function renderEmbeddedTemplate(viewNode, template, context, renderer) {
var _isParent = isParent, _previousOrParentNode = previousOrParentNode;
try {
isParent = !0;
previousOrParentNode = null;
var cm = !1;
if (null == viewNode) {
viewNode =
createLNode(null, 2, null, createLView(-1, renderer, createTView(), template, context));
cm = !0;
}
enterView(viewNode.data, viewNode);
template(context, cm);
} finally {
refreshDynamicChildren();
leaveView(currentView.parent);
isParent = _isParent;
previousOrParentNode = _previousOrParentNode;
}
return viewNode;
}
function renderComponentOrTemplate(node, hostView, componentOrContext, template) {
var oldView = enterView(hostView, node);
try {
rendererFactory.begin && rendererFactory.begin();
template ? template(componentOrContext, creationMode) : function(
directiveIndex, elementIndex) {
!function(currentView, tView, creationMode) {
if (1 === currentView.lifecycleStage) {
executeHooks(currentView.data, tView.initHooks, tView.checkHooks, creationMode);
currentView.lifecycleStage = 2;
}
}(currentView, currentView.tView, creationMode);
!function(currentView, tView, creationMode) {
if (currentView.lifecycleStage < 3) {
executeHooks(
currentView.data, tView.contentHooks, tView.contentCheckHooks, creationMode);
currentView.lifecycleStage = 3;
}
}(currentView, currentView.tView, creationMode);
var template = tData[1].template;
if (null != template) {
var element = data[0], directive = getDirectiveInstance(data[1]),
oldView = enterView(element.data, element);
try {
template(directive, creationMode);
} finally {
refreshDynamicChildren();
leaveView(oldView);
}
}
}();
} finally {
rendererFactory.end && rendererFactory.end();
leaveView(oldView);
}
}
function createTView() {
return {
data: [],
firstTemplatePass: !0,
initHooks: null,
checkHooks: null,
contentHooks: null,
contentCheckHooks: null,
viewHooks: null,
viewCheckHooks: null,
destroyHooks: null,
objectLiterals: null
};
}
function locateHostElement(factory, elementOrSelector) {
rendererFactory = factory;
var defaultRenderer = factory.createRenderer(null, null);
return 'string' == typeof elementOrSelector ?
defaultRenderer.selectRootElement ? defaultRenderer.selectRootElement(elementOrSelector) :
defaultRenderer.querySelector(elementOrSelector) :
elementOrSelector;
}
function refreshDynamicChildren() {
for (var current = currentView.child; null !== current; current = current.next)
if (0 !== current.dynamicViewCount && current.views)
for (var container_1 = current, i = 0; i < container_1.views.length; i++) {
var view = container_1.views[i];
renderEmbeddedTemplate(view, view.data.template, view.data.context, renderer);
}
}
var NO_CHANGE = {};
function getDirectiveInstance(instanceOrArray) {
return Array.isArray(instanceOrArray) ? instanceOrArray[0] : instanceOrArray;
}
var EMPTY$1 = {};
function noop$2() {}
function invertObject(obj) {
if (null == obj) return EMPTY$1;
var newObj = {};
for (var minifiedKey in obj) newObj[obj[minifiedKey]] = minifiedKey;
return newObj;
}
/**
*@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
*/
/**
*@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
*/
/**
*@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
*/
/**
*@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
*/
/**
* @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
*/ Object;
/**
* @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
*/ !
/**
* @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
*/
function(componentType, opts) {
void 0 === opts && (opts = {});
var component, rendererFactory = opts.rendererFactory || domRendererFactory3,
componentDef = componentType.ngComponentDef;
componentDef.type != componentType && (componentDef.type = componentType);
var hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag),
oldView = enterView(
createLView(
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType),
createTView()),
null);
try {
!function(rNode, def) {
!function() {
isParent = !1;
previousOrParentNode = null;
}();
createLNode(0, 3, rNode, createLView(-1, renderer, function(template) {
return template.ngPrivateData || (template.ngPrivateData = createTView());
}(def.template)));
}(hostNode, componentDef);
component = getDirectiveInstance(function(index, directive, directiveDef, queryName) {
var instance, flags = previousOrParentNode.flags;
0 == (4092 & flags) ? flags = 4100 | 3 & flags : flags += 4;
previousOrParentNode.flags = flags;
Object.defineProperty(
directive, '__ngHostLNode__', {enumerable: !1, value: previousOrParentNode});
data[1] = instance = directive;
if (1 >= tData.length) {
tData[1] = directiveDef;
}
var diPublic = directiveDef.diPublic;
diPublic && diPublic(directiveDef);
var tNode = previousOrParentNode.tNode;
tNode && tNode.attrs && function(instance, inputs, tNode) {
var directiveIndex = ((4092 & previousOrParentNode.flags) >> 2) - 1,
initialInputData = tNode.initialInputs;
(void 0 === initialInputData || directiveIndex >= initialInputData.length) &&
(initialInputData = function(directiveIndex, inputs, tNode) {
var initialInputData = tNode.initialInputs || (tNode.initialInputs = []);
initialInputData[directiveIndex] = null;
for (var attrs = tNode.attrs, i = 0; i < attrs.length; i += 2) {
var minifiedInputName = inputs[attrs[i]];
void 0 !== minifiedInputName &&
(initialInputData[directiveIndex] || (initialInputData[directiveIndex] = [
])).push(minifiedInputName, attrs[1 | i]);
}
return initialInputData;
}(directiveIndex, directiveDef.inputs, tNode));
var initialInputs = initialInputData[directiveIndex];
if (initialInputs)
for (var i = 0; i < initialInputs.length; i += 2)
instance[initialInputs[i]] = initialInputs[1 | i];
}(instance, 0, tNode);
!
/**
* @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
*/
function(index, onInit, doCheck, tView) {
if (!0 === tView.firstTemplatePass) {
null != onInit && (tView.initHooks || (tView.initHooks = [])).push(1, onInit);
if (null != doCheck) {
(tView.initHooks || (tView.initHooks = [])).push(1, doCheck);
(tView.checkHooks || (tView.checkHooks = [])).push(1, doCheck);
}
}
}(0, directiveDef.onInit, directiveDef.doCheck, currentView.tView);
return instance;
}(0, componentDef.n(), componentDef));
} finally {
leaveView(oldView);
}
opts.features &&
opts.features.forEach(function(feature) { return feature(component, componentDef); });
!function(component) {
var hostNode = component.__ngHostLNode__;
renderComponentOrTemplate(hostNode, hostNode.view, component);
}
/**
* @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
*/
/**
* @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
*/ (component);
}(function() {
function HelloWorld() { this.name = 'World'; }
HelloWorld.ngComponentDef = function(componentDefinition) {
var type = componentDefinition.type, def = {
type: type,
diPublic: null,
n: componentDefinition.factory,
tag: componentDefinition.tag || null,
template: componentDefinition.template || null,
h: componentDefinition.hostBindings || noop$2,
inputs: invertObject(componentDefinition.inputs),
outputs: invertObject(componentDefinition.outputs),
methods: invertObject(componentDefinition.methods),
rendererType: function(type) {
if (type && '$$undefined' === type.id) {
var isFilled =
null != type.encapsulation && type.encapsulation !== ViewEncapsulation.None ||
type.styles.length || Object.keys(type.data).length;
type.id = isFilled ? 'c' + _renderCompCount++ : '$$empty';
}
type && '$$empty' === type.id && (type = null);
return type || null;
}(componentDefinition.rendererType) ||
null,
exportAs: componentDefinition.exportAs,
onInit: type.prototype.ngOnInit || null,
doCheck: type.prototype.ngDoCheck || null,
afterContentInit: type.prototype.ngAfterContentInit || null,
afterContentChecked: type.prototype.ngAfterContentChecked || null,
afterViewInit: type.prototype.ngAfterViewInit || null,
afterViewChecked: type.prototype.ngAfterViewChecked || null,
onDestroy: type.prototype.ngOnDestroy || null
},
feature = componentDefinition.features;
feature && feature.forEach(function(fn) { return fn(def); });
return def;
}({
type: HelloWorld,
tag: 'hello-world',
factory: function() { return new HelloWorld(); },
template: function(ctx, cm) {
cm && function(index, value) {
createLNode(0, 3, null);
isParent = !1;
}();
!function(index, value) {
var existingNode = data[0];
if (existingNode.native)
value !== NO_CHANGE &&
(renderer.setValue ?
renderer.setValue(existingNode.native, stringify$1(value)) :
existingNode.native.textContent = stringify$1(value));
else {
existingNode.native = renderer.createText ?
renderer.createText(stringify$1(value)) :
renderer.createTextNode(stringify$1(value));
!function(node, currentView) {
var parent = node.parent;
if (canInsertNativeNode(parent, currentView)) {
var nativeSibling = function(node, stopNode) {
for (var currentNode = node; currentNode && null !== currentNode;) {
var pNextOrParent = currentNode.pNextOrParent;
if (pNextOrParent) {
for (var pNextOrParentType = 3 & pNextOrParent.flags;
1 !== pNextOrParentType;) {
if (nativeNode = findFirstRNode(pNextOrParent)) return nativeNode;
pNextOrParent = pNextOrParent.pNextOrParent;
}
currentNode = pNextOrParent;
} else {
for (var currentSibling = currentNode.next; currentSibling;) {
var nativeNode;
if (nativeNode = findFirstRNode(currentSibling)) return nativeNode;
currentSibling = currentSibling.next;
}
var parentNode = currentNode.parent;
currentNode = null;
if (parentNode) {
var parentType = 3 & parentNode.flags;
0 !== parentType && 2 !== parentType || (currentNode = parentNode);
}
}
}
return null;
}(node), renderer = currentView.renderer;
renderer.listen ?
renderer.insertBefore(parent.native, node.native, nativeSibling) :
parent.native.insertBefore(node.native, nativeSibling, !1);
}
}
/**
* @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
*/
/**
* @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
*/ (existingNode, currentView);
}
}(0, function(prefix, value, suffix) {
return function(value) {
if (creationMode) {
!function() {
null == currentView.bindingStartIndex &&
(bindingIndex = currentView.bindingStartIndex = data.length);
}();
return data[bindingIndex++] = value;
}
var changed = value !== NO_CHANGE && function(a, b) {
return !(a != a && value != value) && a !== value;
}(data[bindingIndex]);
changed && (data[bindingIndex] = value);
bindingIndex++;
return changed ? value : NO_CHANGE;
}(value) === NO_CHANGE ?
NO_CHANGE :
'Hello ' + stringify$1(value) + '!';
}(0, ctx.name));
}
});
return HelloWorld;
}());
}();

View File

@ -0,0 +1,28 @@
[ "EMPTY$1",
"NO_CHANGE",
"Symbol$1",
"__global$1",
"__self$1",
"__window$1",
"_renderCompCount",
"_root",
"createLNode",
"createLView",
"domRendererFactory3",
"enterView",
"invertObject",
"leaveView",
"locateHostElement",
"noop$2",
"refreshDynamicChildren",
"renderComponentOrTemplate",
"renderEmbeddedTemplate",
"stringify$1",
"canInsertNativeNode",
"createTView",
"executeHooks",
"findFirstRNode",
"getDirectiveInstance",
"getNextLNodeWithProjection",
"getNextOrParentSiblingNode"
]

View File

@ -0,0 +1,9 @@
/**
* @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
*/
(function() { var Class = function() {}, fn = function() {}; })();

View File

@ -0,0 +1,8 @@
[
{
"name": "Class"
},
{
"name": "fn"
}
]

View File

@ -0,0 +1,23 @@
/**
* @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
*/
!function() {
'use strict';
// tslint:disable-next-line:no-console
console.log('Hello, Alice in Wonderland');
var A = function() {
function A() {}
return A.prototype.a = function() { return document.a; }, A;
}(), B = function() {
function B() {}
return B.prototype.b = function() { return window.b; }, B;
}();
var ignore_no_initializer;
// tslint:disable-next-line:no-console
console.error(new A().a(), new B().b());
}();

View File

@ -0,0 +1,8 @@
[
{
"name": "A"
},
{
"name": "B"
}
]

View File

@ -0,0 +1,12 @@
/**
* @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
*/
!function() {
'use strict';
var constant = 1, method = function() {}, clazz = class {};
}();

View File

@ -0,0 +1,5 @@
[
"clazz",
"constant",
"method"
]