fix: Merge remote-tracking branch 'en/master' into aio

# Conflicts:
#	aio/tools/transforms/templates/cli/cli-command.template.html
This commit is contained in:
Zhicheng WANG 2019-10-01 10:35:26 +08:00
commit b6a5b3bc62
95 changed files with 952 additions and 1390 deletions

View File

@ -1,3 +1,13 @@
<a name="8.1.0-next.1"></a>
# [8.1.0-next.1](https://github.com/angular/angular/compare/8.1.0-beta.0...8.1.0-next.1) (2019-06-05)
### Bug Fixes
* **core:** TypeScript related migrations should cater for BOM ([#30719](https://github.com/angular/angular/issues/30719)) ([80394ce](https://github.com/angular/angular/commit/80394ce)), closes [/github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts#L72](https://github.com//github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts/issues/L72) [#30713](https://github.com/angular/angular/issues/30713)
<a name="8.1.0-beta.0"></a>
# [8.1.0-beta.0](https://github.com/angular/angular/compare/8.0.0...8.1.0-beta.0) (2019-05-30)

View File

@ -7,6 +7,10 @@ body {
-moz-osx-font-smoothing: grayscale;
}
h1, h2, h3, h4, h5, h6 {
color: $deepgray;
}
h1 {
font-size: 24px;
font-weight: 500;
@ -72,6 +76,7 @@ p, ol, ul, ol, li, input, a {
line-height: 24px;
letter-spacing: 0.30px;
font-weight: 400;
color: $darkgray;
& > em {
letter-spacing: 0.30px;
}
@ -102,7 +107,7 @@ a {
.app-toolbar a {
font-size: 16px;
font-weight: 400;
color: white;
color: $white;
font-family: $main-font;
text-transform: uppercase;
padding: 21px 0;

View File

@ -5,12 +5,15 @@ footer {
padding: 48px;
z-index: 0;
background-color: $blue;
color: $offwhite;
font-weight: 300;
aio-footer {
position: relative;
z-index: 0;
& > * {
color: $white;
}
}
.footer-block {
@ -19,8 +22,7 @@ footer {
}
a {
color: $offwhite;
font-weight: 300;
color: $white;
text-decoration: none;
z-index: 20;
position: relative;
@ -39,6 +41,7 @@ footer {
text-transform: uppercase;
font-weight: 400;
margin: 0 0 16px;
color: $white;
}
p {
text-align: center;

View File

@ -2,8 +2,9 @@ html, body {
height: 100%;
}
body {
background-color: $offwhite;
body,
.content {
background-color: $white;
}
.clearfix {
@ -48,4 +49,4 @@ body {
.text-uppercase {
text-transform: uppercase;
}
}

View File

@ -42,7 +42,7 @@ section#intro {
height: 480px;
margin: 0 auto -32px;
padding: 48px 0 0;
color: white;
color: $white;
@media (max-width: 780px) {
flex-direction: column;
@ -426,7 +426,7 @@ div[layout=row]{
text-transform: uppercase;
font-size: 24px;
font-weight: 300;
color: white;
color: $white;
margin: 0;
-webkit-margin-before: 0;
-webkit-margin-after: 0;

View File

@ -28,7 +28,7 @@ mat-sidenav.mat-sidenav.sidenav {
left: 0;
padding: 0;
min-width: 260px;
background-color: $offwhite;
background-color: $white;
box-shadow: 6px 0 6px rgba(0,0,0,0.10);
&.collapsed {
@ -48,6 +48,11 @@ mat-sidenav-container.sidenav-container {
}
}
mat-sidenav-container.sidenav-container.mat-drawer-container.mat-sidenav-container,
mat-sidenav-container .sidenav-content {
background-color: $white;
}
mat-sidenav-container div.mat-sidenav-content {
height: auto;
}

View File

@ -180,7 +180,7 @@ aio-search-box.search-container {
color: $darkgray;
border: none;
border-radius: 100px;
background-color: $offwhite;
background-color: $white;
padding: 5px 16px;
margin-left: 8px;
width: 180px;

View File

@ -94,7 +94,7 @@ a.filter-button {
&:hover {
background-color: $blue;
color: white;
color: $white;
}
}

View File

@ -35,7 +35,7 @@
section {
color: $darkgray;
color: $deepgray;
font-size: 20px;
line-height: 24px;
margin: 0;

View File

@ -22,7 +22,7 @@ aio-contributor-list {
a {
&.selected {
background-color: $blue;
color: white;
color: $white;
}
}
}

View File

@ -1,5 +1,5 @@
.filetree {
background: $offwhite;
background: $white;
border: 4px solid $lightgray;
border-radius: 4px;
margin: 0 0 24px 0;
@ -35,4 +35,4 @@
}
}
}
}
}

View File

@ -32,15 +32,28 @@
}
figure {
border-radius: 4px;
margin: 0;
margin-top: 14px;
margin-bottom: 14px;
border-radius: 1px;
background: $white;
padding: 20px;
border: 1px solid $lightgray;
padding: 32px;
box-sizing: border-box;
display: inline-block;
box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, .2);
margin: 0 0 14px 0;
img {
&.lightbox {
background-color: $lightboxgray;
width: 100%;
display: flex;
justify-content: center;
}
div.card {
box-shadow: 0 2px 2px rgba(10, 16, 20, 0.24), 0 0 2px rgba(10, 16, 20, 0.12);
border-radius: 4px;
padding: 8px;
background-color: $white;
}
}
}

View File

@ -3,7 +3,7 @@ label.raised, .api-header label {
padding: 4px 16px;
display: inline;
font-size: 14px;
color: white;
color: $white;
margin-right: 8px;
font-weight: 500;
text-transform: uppercase;
@ -64,4 +64,4 @@ label.raised, .api-header label {
}
}
}
}

View File

@ -2,7 +2,7 @@ table {
margin: 24px 0px;
box-shadow: 0 2px 2px rgba($black, 0.24), 0 0 2px rgba($black, 0.12);
border-radius: 2px;
background: $offwhite;
background: $white;
&.is-full-width {
width: 100%;

View File

@ -18,9 +18,11 @@ $white: #FFFFFF;
$offwhite: #FAFAFA;
$backgroundgray: #F1F1F1;
$lightgray: #DBDBDB;
$lightboxgray: #EBEBEB;
$mist: #ECEFF1;
$mediumgray: #6e6e6e;
$darkgray: #333;
$mediumgray: #6E6E6E;
$darkgray: #444444;
$deepgray: #333333;
$black: #0A1014;
$orange: #FF9800;
$darkorange: #940;
@ -119,4 +121,4 @@ $api-symbols: (
// OTHER
$small-breakpoint-width: 840px;
$phone-breakpoint: 480px;
$tablet-breakpoint: 800px;
$tablet-breakpoint: 800px;

View File

@ -1,4 +1,5 @@
const {resolve} = require('canonical-path');
const semver = require('semver');
const Package = require('dgeni').Package;
const basePackage = require('../angular-base-package');
const contentPackage = require('../content-package');
@ -8,59 +9,60 @@ const CLI_SOURCE_PATH = resolve(CLI_SOURCE_ROOT, 'node_modules/@angular/cli');
const CLI_SOURCE_HELP_PATH = resolve(CLI_SOURCE_PATH, 'help');
// Define the dgeni package for generating the docs
module.exports = new Package('cli-docs', [basePackage, contentPackage])
module.exports =
new Package('cli-docs', [basePackage, contentPackage])
// Register the services and file readers
.factory(require('./readers/cli-command'))
// Register the services and file readers
.factory(require('./readers/cli-command'))
// Register the processors
.processor(require('./processors/processCliContainerDoc'))
.processor(require('./processors/processCliCommands'))
.processor(require('./processors/filterHiddenCommands'))
// Register the processors
.processor(require('./processors/processCliContainerDoc'))
.processor(require('./processors/processCliCommands'))
.processor(require('./processors/filterHiddenCommands'))
// Configure file reading
.config(function(readFilesProcessor, cliCommandFileReader) {
readFilesProcessor.fileReaders.push(cliCommandFileReader);
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
{
basePath: CLI_SOURCE_HELP_PATH,
include: resolve(CLI_SOURCE_HELP_PATH, '*.json'),
fileReader: 'cliCommandFileReader'
},
{
basePath: CONTENTS_PATH,
include: resolve(CONTENTS_PATH, 'cli/**'),
fileReader: 'contentFileReader'
},
]);
})
// Configure file reading
.config(function(readFilesProcessor, cliCommandFileReader) {
readFilesProcessor.fileReaders.push(cliCommandFileReader);
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
{
basePath: CLI_SOURCE_HELP_PATH,
include: resolve(CLI_SOURCE_HELP_PATH, '*.json'),
fileReader: 'cliCommandFileReader'
},
{
basePath: CONTENTS_PATH,
include: resolve(CONTENTS_PATH, 'cli/**'),
fileReader: 'contentFileReader'
},
]);
})
.config(function(templateFinder, templateEngine, getInjectables) {
// Where to find the templates for the CLI doc rendering
templateFinder.templateFolders.unshift(resolve(TEMPLATES_PATH, 'cli'));
// Add in templating filters and tags
templateEngine.filters = templateEngine.filters.concat(getInjectables(requireFolder(__dirname, './rendering')));
})
.config(function(templateFinder, templateEngine, getInjectables) {
// Where to find the templates for the CLI doc rendering
templateFinder.templateFolders.unshift(resolve(TEMPLATES_PATH, 'cli'));
// Add in templating filters and tags
templateEngine.filters = templateEngine.filters.concat(
getInjectables(requireFolder(__dirname, './rendering')));
})
.config(function(renderDocsProcessor) {
.config(function(renderDocsProcessor) {
const cliPackage = require(resolve(CLI_SOURCE_PATH, 'package.json'));
const repoUrlParts = cliPackage.repository.url.replace(/\.git$/, '').split('/');
const version = `v${cliPackage.version}`;
const repo = repoUrlParts.pop();
const owner = repoUrlParts.pop();
const cliVersionInfo = {
gitRepoInfo: { owner, repo },
currentVersion: { raw: version }
};
const cliPackage = require(resolve(CLI_SOURCE_PATH, 'package.json'));
const repoUrlParts = cliPackage.repository.url.replace(/\.git$/, '').split('/');
const version = `v${semver.clean(cliPackage.version)}`;
const repo = repoUrlParts.pop();
const owner = repoUrlParts.pop();
const cliVersionInfo = {gitRepoInfo: {owner, repo}, currentVersion: {raw: version}};
// Add the cli version data to the renderer, for use in things like github links
renderDocsProcessor.extraData.cliVersionInfo = cliVersionInfo;
})
// Add the cli version data to the renderer, for use in things like github links
renderDocsProcessor.extraData.cliVersionInfo = cliVersionInfo;
})
.config(function(convertToJsonProcessor, postProcessHtml) {
convertToJsonProcessor.docTypes = convertToJsonProcessor.docTypes.concat(['cli-command', 'cli-overview']);
postProcessHtml.docTypes = postProcessHtml.docTypes.concat(['cli-command', 'cli-overview']);
});
.config(function(convertToJsonProcessor, postProcessHtml) {
convertToJsonProcessor.docTypes =
convertToJsonProcessor.docTypes.concat(['cli-command', 'cli-overview']);
postProcessHtml.docTypes =
postProcessHtml.docTypes.concat(['cli-command', 'cli-overview']);
});

View File

@ -26,22 +26,59 @@ module.exports = function cliCommandFileReader(log) {
docType: 'cli-command',
id: `cli-${doc.name}`,
commandAliases: doc.aliases || [],
aliases: computeAliases(doc),
path,
aliases: computeAliases(doc), path,
outputPath: `${path}.json`,
breadCrumbs: [
{ text: 'CLI', path: 'cli' },
{ text: name, path },
{text: 'CLI', path: 'cli'},
{text: name, path},
]
});
if (doc.longDescription) {
doc.longDescriptionDoc = createLongDescriptionDoc(fileInfo);
}
return [result];
} catch (e) {
log.warn(`Failed to read cli command file: "${fileInfo.relativePath}" - ${e.message}`);
}
}
};
};
function computeAliases(doc) {
return [doc.name].concat(doc.aliases || []).map(alias => `cli-${alias}`);
}
function computeAliases(doc) {
return [doc.name].concat(doc.aliases || []).map(alias => `cli-${alias}`);
}
/**
* Synthesize a doc for the CLI command long description, which is used to generate links
* for viewing and editing the long description in GitHub.
*
* The long description is stored in a markdown file that is referenced from the original
* schema file for the command, via the `$longDescription` field. The field is a relative path
* to the markdown file from the schema file.
*
* This function tries to retrieve that original schema based on the file path of the help JSON
* file, which was passed to the `cliCommandFileReader.getDocs()` method.
*/
function createLongDescriptionDoc(fileInfo) {
try {
const path = require('canonical-path');
const fs = require('fs');
const json5 = require('json5');
const schemaJsonPath = path.resolve(fileInfo.basePath, '../commands', fileInfo.relativePath);
const schemaJson = fs.readFileSync(schemaJsonPath);
const schema = json5.parse(schemaJson);
if (schema.$longDescription) {
return {
docType: 'content',
startingLine: 0,
fileInfo: {
realProjectRelativePath:
path.join(path.dirname(fileInfo.realProjectRelativePath), schema.$longDescription)
}
};
}
} catch (e) {
log.warn('Unable to read CLI long description file info', e, fileInfo);
return undefined;
}
}
};

View File

@ -40,7 +40,12 @@ const content = `
}
`;
const fileInfo = {content, baseName: 'add'};
const fileInfo = {
content,
baseName: 'add',
relativePath: 'add.json',
basePath: __dirname + '/mocks/help',
};
describe('cli-command reader', () => {
describe('getDocs', () => {
@ -77,8 +82,8 @@ describe('cli-command reader', () => {
it('should compute the bread crumbs', () => {
const docs = reader.getDocs(fileInfo);
expect(docs[0].breadCrumbs).toEqual([
{ text: 'CLI', path: 'cli' },
{ text: 'add', path: 'cli/add' },
{text: 'CLI', path: 'cli'},
{text: 'add', path: 'cli/add'},
]);
});
@ -89,7 +94,9 @@ describe('cli-command reader', () => {
it('should extract the long description', () => {
const docs = reader.getDocs(fileInfo);
expect(docs[0].longDescription).toEqual('Add support for a library in your project, for example adding `@angular/pwa` which would configure\nyour project for PWA support.\n');
expect(docs[0].longDescription)
.toEqual(
'Add support for a library in your project, for example adding `@angular/pwa` which would configure\nyour project for PWA support.\n');
});
it('should extract the command type', () => {
@ -110,10 +117,19 @@ describe('cli-command reader', () => {
it('should extract the options', () => {
const docs = reader.getDocs(fileInfo);
expect(docs[0].options).toEqual([
jasmine.objectContaining({ name: 'collection' }),
jasmine.objectContaining({ name: 'help' }),
jasmine.objectContaining({ name: 'helpJson' }),
jasmine.objectContaining({name: 'collection'}),
jasmine.objectContaining({name: 'help'}),
jasmine.objectContaining({name: 'helpJson'}),
]);
});
it('should extract file info for the long description', () => {
const [doc] = reader.getDocs(fileInfo);
expect(doc.longDescriptionDoc).toEqual({
docType: 'content',
startingLine: 0,
fileInfo: {realProjectRelativePath: 'packages/angular/cli/commands/add-long.md'}
});
});
});
});

View File

@ -0,0 +1,3 @@
{
"$longDescription": "./add-long.md"
}

View File

@ -14,7 +14,10 @@
{$ cli.renderSyntax(doc) $}
{% if doc.longDescription.length %}
<h2 class="no-anchor">说明</h2>
<h2 class="no-anchor">
{$ github.githubLinks(doc.longDescriptionDoc, cliVersionInfo) $}
说明
</h2>
{$ doc.longDescription | marked $}
{% endif%}

View File

@ -24,6 +24,8 @@
"node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*"
"node_modules/@angular/router/upgrade*",
"node_modules/@angular/cdk/schematics*",
"node_modules/@angular/material/schematics*"
]
}

View File

@ -14,23 +14,23 @@ if [[ $? != 0 ]]; then exit 1; fi
# Did it add the appropriate build markers?
# - esm2015
grep '"__processed_by_ivy_ngcc__":[^}]*"esm2015":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"esm2015": "'
if [[ $? != 0 ]]; then exit 1; fi
# - fesm2015
grep '"__processed_by_ivy_ngcc__":[^}]*"fesm2015":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"fesm2015": "'
if [[ $? != 0 ]]; then exit 1; fi
grep '"__processed_by_ivy_ngcc__":[^}]*"es2015":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"es2015": "'
if [[ $? != 0 ]]; then exit 1; fi
# - esm5
grep '"__processed_by_ivy_ngcc__":[^}]*"esm5":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"esm5": "'
if [[ $? != 0 ]]; then exit 1; fi
# - fesm5
grep '"__processed_by_ivy_ngcc__":[^}]*"module":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"module": "'
if [[ $? != 0 ]]; then exit 1; fi
grep '"__processed_by_ivy_ngcc__":[^}]*"fesm5":"' node_modules/@angular/common/package.json
cat node_modules/@angular/common/package.json | awk 'ORS=" "' | grep '"__processed_by_ivy_ngcc__":[^}]*"fesm5": "'
if [[ $? != 0 ]]; then exit 1; fi
# Did it replace the PRE_R3 markers correctly?

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "8.1.0-beta.0",
"version": "8.1.0-next.1",
"private": true,
"description": "Angular - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
@ -165,4 +165,4 @@
"resolutions": {
"natives": "1.1.6"
}
}
}

View File

@ -1,29 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../../",
"paths": {
"@angular/animations": ["../../../../dist/packages/animations"],
"@angular/animations/browser": ["../../../../dist/packages/animations/browser"],
"@angular/core": ["../../../../dist/packages/core"]
},
"outDir": "../../../../dist/packages/animations"
},
"files": [
"public_api.ts",
"../../../../node_modules/@types/hammerjs/index.d.ts",
"../../../../node_modules/@types/jasmine/index.d.ts",
"../../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/animations/browser/testing"
}
}

View File

@ -1,28 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/animations": ["../../../dist/packages/animations"],
"@angular/core": ["../../../dist/packages/core"]
},
"outDir": "../../../dist/packages/animations"
},
"files": [
"public_api.ts",
"../../../node_modules/@types/node/index.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts",
"../../system.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "browser.js",
"flatModuleId": "@angular/animations/browser"
}
}

View File

@ -1,26 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"]
},
"outDir": "../../dist/packages/animations"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts",
"../system.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "animations.js",
"flatModuleId": "@angular/animations"
}
}

View File

@ -5,11 +5,20 @@ load("@npm_bazel_karma//:index.bzl", "ts_web_test_suite")
load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "history_server")
load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_package")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary")
load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary", "sass_binary")
sass_binary(
name = "global_stylesheet",
src = glob(["styles.css", "styles.scss"])[0],
output_name = "global_stylesheet.css",
)
multi_sass_binary(
name = "styles",
srcs = glob(["**/*.scss"]),
srcs = glob(
include = ["**/*.scss"],
exclude = ["styles.scss"],
),
)
ng_module(
@ -52,6 +61,7 @@ web_package(
# do not sort
"@npm//node_modules/zone.js:dist/zone.min.js",
":bundle.min.js",
":global_stylesheet",
],
data = [
"favicon.ico",
@ -85,6 +95,7 @@ ts_devserver(
],
static_files = [
"@npm//node_modules/zone.js:dist/zone.min.js",
":global_stylesheet",
],
data = [
"favicon.ico",

View File

@ -21,6 +21,8 @@
"node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*"
"node_modules/@angular/router/upgrade*",
"node_modules/@angular/cdk/schematics*",
"node_modules/@angular/material/schematics*"
]
}

View File

@ -1,21 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"rootDir": ".",
"sourceRoot": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"]
},
"outDir": "../../dist/packages/benchpress"
},
"files": [
"index.ts",
"../../node_modules/@types/node/index.d.ts",
"../../node_modules/@types/jasmine/index.d.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
]
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../../",
"paths": {
"@angular/core": ["../../../../dist/packages/core"],
"@angular/common": ["../../../../dist/packages/common"],
"@angular/common/http": ["../../../../dist/packages/common/http"],
"@angular/platform-browser": ["../../../../dist/packages/platform-browser"]
},
"outDir": "../../../../dist/packages/common"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/common/http/testing"
}
}

View File

@ -1,25 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/common": ["../../../dist/packages/common"],
"@angular/core": ["../../../dist/packages/core"]
},
"outDir": "../../../dist/packages/common"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "http.js",
"flatModuleId": "@angular/common/http"
}
}

View File

@ -1,27 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../../dist/packages/common/locales",
"paths": {
"@angular/common": ["../../../dist/packages/common"],
"@angular/core": ["../../../dist/packages/core"]
},
"sourceMap": true,
"inlineSources": true,
"target": "es5",
"skipLibCheck": true,
"lib": ["es2015", "dom"]
},
"exclude": [
"./closure-locale.ts"
],
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"skipMetadataEmit": true
}
}

View File

@ -204,6 +204,20 @@ describe('NgTemplateOutlet', () => {
fixture.componentInstance.value = 'baz';
detectChangesAndExpectText('');
});
// https://github.com/angular/angular/issues/30801
it('should not throw if the context is left blank', () => {
const template = `
<ng-template #testTemplate>test</ng-template>
<ng-template [ngTemplateOutlet]="testTemplate" [ngTemplateOutletContext]=""></ng-template>
`;
expect(() => {
fixture = createTestComponent(template);
detectChangesAndExpectText('test');
}).not.toThrow();
});
});
@Injectable()

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": [
"../../../dist/packages/core"
],
"@angular/common": [
"../../../dist/packages/common"
]
},
"outDir": "../../../dist/packages/common"
},
"files": [
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/common/testing"
}
}

View File

@ -1,25 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"rootDir": ".",
"baseUrl": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"]
},
"outDir": "../../dist/packages/common"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "common.js",
"flatModuleId": "@angular/common"
}
}

View File

@ -1,29 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/common": [
"../../../dist/packages/common"
],
"@angular/core": [
"../../../dist/packages/core"
],
"@angular/platform-browser": [
"../../../dist/packages/platform-browser"
]
},
"outDir": "../../../dist/packages/common"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "upgrade.js",
"flatModuleId": "@angular/common/upgrade"
}
}

View File

@ -51,5 +51,5 @@ export function markAsProcessed(
format: EntryPointJsonProperty) {
if (!packageJson.__processed_by_ivy_ngcc__) packageJson.__processed_by_ivy_ngcc__ = {};
packageJson.__processed_by_ivy_ngcc__[format] = NGCC_VERSION;
fs.writeFile(packageJsonPath, JSON.stringify(packageJson));
fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}

View File

@ -2932,6 +2932,28 @@ describe('compiler compliance', () => {
expectEmit(source, SomeDirectiveDefinition, 'Incorrect SomeDirective.ngDirectiveDef');
});
it('should not throw for empty property bindings on ng-template', () => {
const files = {
app: {
'example.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'my-app',
template: '<ng-template [id]=""></ng-template>'
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}`
}
};
expect(() => compile(files, angularFiles)).not.toThrow();
});
});
describe('inherited base classes', () => {

View File

@ -138,7 +138,7 @@ describe('compiler compliance: bindings', () => {
}
};
const result = compile(files, angularFiles);
expect(result.source).not.toContain('i0.ɵɵelementProperty');
expect(result.source).not.toContain('i0.ɵɵproperty');
});
it('should not remap property names whose names do not correspond to their attribute names',

View File

@ -2043,7 +2043,7 @@ describe('ngtsc behavioral tests', () => {
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).not.toContain('i0.ɵɵelementProperty');
expect(jsContents).not.toContain('i0.ɵɵproperty');
});
it('should correctly recognize local symbols', () => {

View File

@ -29,8 +29,6 @@ export class Identifiers {
static elementEnd: o.ExternalReference = {name: 'ɵɵelementEnd', moduleName: CORE};
static elementProperty: o.ExternalReference = {name: 'ɵɵelementProperty', moduleName: CORE};
static select: o.ExternalReference = {name: 'ɵɵselect', moduleName: CORE};
static updateSyntheticHostBinding:
@ -39,8 +37,6 @@ export class Identifiers {
static componentHostSyntheticListener:
o.ExternalReference = {name: 'ɵɵcomponentHostSyntheticListener', moduleName: CORE};
static elementAttribute: o.ExternalReference = {name: 'ɵɵelementAttribute', moduleName: CORE};
static attribute: o.ExternalReference = {name: 'ɵɵattribute', moduleName: CORE};
static attributeInterpolate1:

View File

@ -14,7 +14,8 @@ import {assembleBoundTextPlaceholders, findIndex, getSeqNumberGenerator, updateP
enum TagType {
ELEMENT,
TEMPLATE
TEMPLATE,
PROJECTION
}
/**
@ -94,6 +95,12 @@ export class I18nContext {
appendElement(node: i18n.AST, index: number, closed?: boolean) {
this.appendTag(TagType.ELEMENT, node as i18n.TagPlaceholder, index, closed);
}
appendProjection(node: i18n.AST, index: number) {
// add open and close tags at the same time,
// since we process projected content separately
this.appendTag(TagType.PROJECTION, node as i18n.TagPlaceholder, index, false);
this.appendTag(TagType.PROJECTION, node as i18n.TagPlaceholder, index, true);
}
/**
* Generates an instance of a child context based on the root one,
@ -181,6 +188,7 @@ function findTemplateFn(ctx: number, templateIndex: number | null) {
function serializePlaceholderValue(value: any): string {
const element = (data: any, closed?: boolean) => wrapTag('#', data, closed);
const template = (data: any, closed?: boolean) => wrapTag('*', data, closed);
const projection = (data: any, closed?: boolean) => wrapTag('!', data, closed);
switch (value.type) {
case TagType.ELEMENT:
@ -198,6 +206,9 @@ function serializePlaceholderValue(value: any): string {
case TagType.TEMPLATE:
return template(value, value.closed);
case TagType.PROJECTION:
return projection(value, value.closed);
default:
return value;
}

View File

@ -483,6 +483,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
this.creationInstruction(ngContent.sourceSpan, R3.projection, parameters);
if (this.i18n) {
this.i18n.appendProjection(ngContent.i18n !, slot);
}
}
@ -1021,10 +1024,13 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
attrs.forEach(input => {
if (input instanceof t.BoundAttribute) {
const value = input.value.visit(this._valueConverter);
this.allocateBindingSlots(value);
this.updateInstruction(
templateIndex, template.sourceSpan, R3.property,
() => [o.literal(input.name), this.convertPropertyBinding(context, value, true)]);
if (value !== undefined) {
this.allocateBindingSlots(value);
this.updateInstruction(
templateIndex, template.sourceSpan, R3.property,
() => [o.literal(input.name), this.convertPropertyBinding(context, value, true)]);
}
}
});
}

View File

@ -1,24 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/compiler": ["../../../dist/packages/compiler"],
"@angular/core": ["../../../dist/packages/core"]
},
"outDir": "../../../dist/packages/compiler"
},
"files": [
"testing.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"skipMetadataEmit": true,
"skipTemplateCodegen": true
}
}

View File

@ -1,37 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"stripInternal": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"noFallthroughCasesInSwitch": true,
"module": "es2015",
"moduleResolution": "node",
"outDir": "../../dist/packages/compiler",
"paths": {
"@angular/core": ["../../dist/packages/core"]
},
"rootDir": ".",
"sourceMap": true,
"inlineSources": true,
"target": "es2015",
"skipLibCheck": true,
"lib": ["es2015", "dom"],
// don't auto-discover @types/node, it results in a ///<reference in the .d.ts output
"types": []
},
"files": [
"index.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"skipMetadataEmit": true,
"skipTemplateCodegen": true
}
}

View File

@ -108,7 +108,6 @@ export {
ɵɵcontentQuery,
ɵɵloadContentQuery,
ɵɵelementEnd,
ɵɵelementProperty,
ɵɵproperty,
ɵɵpropertyInterpolate,
ɵɵpropertyInterpolate1,
@ -127,7 +126,6 @@ export {
ɵɵenableBindings,
ɵɵdisableBindings,
ɵɵallocHostVars,
ɵɵelementAttribute,
ɵɵelementContainerStart,
ɵɵelementContainerEnd,
ɵɵstyling,

View File

@ -276,13 +276,50 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme
get attributes(): {[key: string]: string | null;} {
const attributes: {[key: string]: string | null;} = {};
const element = this.nativeElement;
if (element) {
const eAttrs = element.attributes;
for (let i = 0; i < eAttrs.length; i++) {
const attr = eAttrs[i];
if (!element) {
return attributes;
}
const context = loadLContext(element);
const lView = context.lView;
const tNodeAttrs = (lView[TVIEW].data[context.nodeIndex] as TNode).attrs;
const lowercaseTNodeAttrs: string[] = [];
// For debug nodes we take the element's attribute directly from the DOM since it allows us
// to account for ones that weren't set via bindings (e.g. ViewEngine keeps track of the ones
// that are set through `Renderer2`). The problem is that the browser will lowercase all names,
// however since we have the attributes already on the TNode, we can preserve the case by going
// through them once, adding them to the `attributes` map and putting their lower-cased name
// into an array. Afterwards when we're going through the native DOM attributes, we can check
// whether we haven't run into an attribute already through the TNode.
if (tNodeAttrs) {
let i = 0;
while (i < tNodeAttrs.length) {
const attrName = tNodeAttrs[i];
// Stop as soon as we hit a marker. We only care about the regular attributes. Everything
// else will be handled below when we read the final attributes off the DOM.
if (typeof attrName !== 'string') break;
const attrValue = tNodeAttrs[i + 1];
attributes[attrName] = attrValue as string;
lowercaseTNodeAttrs.push(attrName.toLowerCase());
i += 2;
}
}
const eAttrs = element.attributes;
for (let i = 0; i < eAttrs.length; i++) {
const attr = eAttrs[i];
// Make sure that we don't assign the same attribute both in its
// case-sensitive form and the lower-cased one from the browser.
if (lowercaseTNodeAttrs.indexOf(attr.name) === -1) {
attributes[attr.name] = attr.value;
}
}
return attributes;
}

View File

@ -98,8 +98,10 @@ class MyApp {
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'title', ɵɵbind(ctx.name));
ɵɵtextBinding(1, ɵɵinterpolation1('Hello ', ctx.name, '!'));
ɵɵselect(0);
ɵɵproperty('title', ctx.name);
ɵɵselect(1);
ɵɵtextInterpolate1('Hello ', ctx.name, '!');
}
...
}

View File

@ -16,29 +16,35 @@ import {addAllToArray} from '../util/array_utils';
import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '../util/assert';
import {attachPatchData} from './context_discovery';
import {elementAttributeInternal, ɵɵload, ɵɵtextBinding} from './instructions/all';
import {setDelayProjection, ɵɵload, ɵɵtextBinding} from './instructions/all';
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
import {allocExpando, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared';
import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared';
import {LContainer, NATIVE} from './interfaces/container';
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n';
import {TElementNode, TIcuContainerNode, TNode, TNodeType} from './interfaces/node';
import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from './interfaces/node';
import {RComment, RElement, RText} from './interfaces/renderer';
import {SanitizerFn} from './interfaces/sanitization';
import {StylingContext} from './interfaces/styling';
import {BINDING_INDEX, HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view';
import {appendChild, createTextNode, nativeRemoveNode} from './node_manipulation';
import {appendChild, appendProjectedNodes, createTextNode, nativeRemoveNode} from './node_manipulation';
import {getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from './state';
import {NO_CHANGE} from './tokens';
import {renderStringify} from './util/misc_utils';
import {findComponentView} from './util/view_traversal_utils';
import {getNativeByIndex, getNativeByTNode, getTNode, isLContainer} from './util/view_utils';
const MARKER = `<EFBFBD>`;
const ICU_BLOCK_REGEXP = /^\s*(<28>\d+:?\d*<2A>)\s*,\s*(select|plural)\s*,/;
const SUBTEMPLATE_REGEXP = /<2F>\/?\*(\d+:\d+)<29>/gi;
const PH_REGEXP = /<2F>(\/?[#*]\d+):?\d*<2A>/gi;
const PH_REGEXP = /<2F>(\/?[#*!]\d+):?\d*<2A>/gi;
const BINDING_REGEXP = /<2F>(\d+):?\d*<2A>/gi;
const ICU_REGEXP = /({\s*<2A>\d+:?\d*<2A>\s*,\s*\S{6}\s*,[\s\S]*})/gi;
const enum TagType {
ELEMENT = '#',
TEMPLATE = '*',
PROJECTION = '!',
}
// i18nPostprocess consts
const ROOT_TEMPLATE_ID = 0;
@ -340,6 +346,10 @@ const parentIndexStack: number[] = [];
* and end of DOM element that were embedded in the original translation block. The placeholder
* `index` points to the element index in the template instructions set. An optional `block` that
* matches the sub-template in which it was declared.
* - `<EFBFBD>!{index}(:{block})<29>`/`<EFBFBD>/!{index}(:{block})<29>`: *Projection Placeholder*: Marks the
* beginning and end of <ng-content> that was embedded in the original translation block.
* The placeholder `index` points to the element index in the template instructions set.
* An optional `block` that matches the sub-template in which it was declared.
* - `<EFBFBD>*{index}:{block}<7D>`/`<EFBFBD>/*{index}:{block}<7D>`: *Sub-template Placeholder*: Sub-templates must be
* split up and translated separately in each angular template function. The `index` points to the
* `template` instruction index. A `block` that matches the sub-template in which it was declared.
@ -354,6 +364,8 @@ export function ɵɵi18nStart(index: number, message: string, subTemplateIndex?:
const tView = getLView()[TVIEW];
ngDevMode && assertDefined(tView, `tView should be defined`);
i18nIndexStack[++i18nIndexStackPointer] = index;
// We need to delay projections until `i18nEnd`
setDelayProjection(true);
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
i18nStartFirstPass(tView, index, message, subTemplateIndex);
}
@ -398,7 +410,7 @@ function i18nStartFirstPass(
// Odd indexes are placeholders (elements and sub-templates)
if (value.charAt(0) === '/') {
// It is a closing tag
if (value.charAt(1) === '#') {
if (value.charAt(1) === TagType.ELEMENT) {
const phIndex = parseInt(value.substr(2), 10);
parentIndex = parentIndexStack[--parentIndexPointer];
createOpCodes.push(phIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.ElementEnd);
@ -410,7 +422,7 @@ function i18nStartFirstPass(
phIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select,
parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild);
if (value.charAt(0) === '#') {
if (value.charAt(0) === TagType.ELEMENT) {
parentIndexStack[++parentIndexPointer] = parentIndex = phIndex;
}
}
@ -508,6 +520,14 @@ function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode |
cursor = cursor.next;
}
// If the placeholder to append is a projection, we need to move the projected nodes instead
if (tNode.type === TNodeType.Projection) {
const tProjectionNode = tNode as TProjectionNode;
appendProjectedNodes(
viewData, tProjectionNode, tProjectionNode.projection, findComponentView(viewData));
return tNode;
}
appendChild(getNativeByTNode(tNode, viewData), tNode, viewData);
const slotValue = viewData[tNode.index];
@ -632,6 +652,8 @@ export function ɵɵi18nEnd(): void {
const tView = getLView()[TVIEW];
ngDevMode && assertDefined(tView, `tView should be defined`);
i18nEndFirstPass(tView);
// Stop delaying projections
setDelayProjection(false);
}
/**
@ -735,10 +757,9 @@ function readCreateOpCodes(
const elementNodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF;
const attrName = createOpCodes[++i] as string;
const attrValue = createOpCodes[++i] as string;
const renderer = viewData[RENDERER];
// This code is used for ICU expressions only, since we don't support
// directives/components in ICUs, we don't need to worry about inputs here
elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData, renderer);
elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData);
break;
default:
throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
@ -890,6 +911,8 @@ function removeNode(index: number, viewData: LView) {
}
}
// Define this node as detached so that we don't risk projecting it
removedPhTNode.flags |= TNodeFlags.isDetached;
ngDevMode && ngDevMode.rendererRemoveNode++;
}
@ -935,9 +958,7 @@ export function ɵɵi18n(index: number, message: string, subTemplateIndex?: numb
export function ɵɵi18nAttributes(index: number, values: string[]): void {
const tView = getLView()[TVIEW];
ngDevMode && assertDefined(tView, `tView should be defined`);
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
i18nAttributesFirstPass(tView, index, values);
}
i18nAttributesFirstPass(tView, index, values);
}
/**
@ -962,12 +983,13 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[])
// Even indexes are text (including bindings)
const hasBinding = !!value.match(BINDING_REGEXP);
if (hasBinding) {
addAllToArray(
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
addAllToArray(
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
}
} else {
const lView = getLView();
const renderer = lView[RENDERER];
elementAttributeInternal(previousElementIndex, attrName, value, lView, renderer);
elementAttributeInternal(previousElementIndex, attrName, value, lView);
// Check if that attribute is a directive input
const tNode = getTNode(previousElementIndex, lView);
const dataValue = tNode.inputs && tNode.inputs[attrName];
@ -979,7 +1001,9 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[])
}
}
tView.data[index + HEADER_OFFSET] = updateOpCodes;
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
tView.data[index + HEADER_OFFSET] = updateOpCodes;
}
}
let changeMask = 0b0;

View File

@ -47,14 +47,12 @@ export {
ɵɵdirectiveInject,
ɵɵelement,
ɵɵelementAttribute,
ɵɵelementContainerEnd,
ɵɵelementContainerStart,
ɵɵelementEnd,
ɵɵelementHostAttrs,
ɵɵelementProperty,
ɵɵelementStart,
ɵɵembeddedViewEnd,

View File

@ -6,10 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {SanitizerFn} from '../interfaces/sanitization';
import {getSelectedIndex} from '../state';
import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
import {ɵɵelementAttribute} from './element';
import {ɵɵbind} from './property';
import {elementAttributeInternal} from './shared';
/**
* Updates the value of or removes a bound attribute on an Element.
@ -27,6 +30,10 @@ import {ɵɵbind} from './property';
export function ɵɵattribute(
name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string) {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
return ɵɵelementAttribute(index, name, ɵɵbind(value), sanitizer, namespace);
const bound = ɵɵbind(value);
if (bound !== NO_CHANGE) {
return elementAttributeInternal(index, name, bound, lView, sanitizer, namespace);
}
}

View File

@ -6,10 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {SanitizerFn} from '../interfaces/sanitization';
import {getSelectedIndex} from '../state';
import {ɵɵelementAttribute} from './element';
import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
import {TsickleIssue1009} from './shared';
import {TsickleIssue1009, elementAttributeInternal} from './shared';
@ -41,12 +42,13 @@ export function ɵɵattributeInterpolate1(
attrName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate1;
}
@ -80,10 +82,13 @@ export function ɵɵattributeInterpolate2(
attrName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string,
sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate2;
}
@ -120,10 +125,13 @@ export function ɵɵattributeInterpolate3(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate3;
}
@ -162,10 +170,13 @@ export function ɵɵattributeInterpolate4(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate4;
}
@ -207,10 +218,13 @@ export function ɵɵattributeInterpolate5(
v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate5;
}
@ -254,10 +268,13 @@ export function ɵɵattributeInterpolate6(
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue =
ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate6;
}
@ -303,10 +320,13 @@ export function ɵɵattributeInterpolate7(
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string,
sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue =
ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate7;
}
@ -354,10 +374,13 @@ export function ɵɵattributeInterpolate8(
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
const interpolatedValue =
ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
if (interpolatedValue !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolate8;
}
@ -391,7 +414,11 @@ export function ɵɵattributeInterpolateV(
attrName: string, values: any[], sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(FW-1340): Refactor to remove the use of other instructions here.
ɵɵelementAttribute(index, attrName, ɵɵinterpolationV(values), sanitizer, namespace);
const interpolated = ɵɵinterpolationV(values);
if (interpolated !== NO_CHANGE) {
elementAttributeInternal(index, attrName, interpolated, lView, sanitizer, namespace);
}
return ɵɵattributeInterpolateV;
}

View File

@ -5,16 +5,14 @@
* 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 {validateAgainstEventAttributes} from '../../sanitization/sanitization';
import {assertDataInRange, assertDefined, assertEqual} from '../../util/assert';
import {assertHasParent} from '../assert';
import {attachPatchData} from '../context_discovery';
import {registerPostOrderHooks} from '../hooks';
import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node';
import {RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer';
import {SanitizerFn} from '../interfaces/sanitization';
import {RElement} from '../interfaces/renderer';
import {StylingContext} from '../interfaces/styling';
import {BINDING_INDEX, HEADER_OFFSET, LView, QUERIES, RENDERER, TVIEW, T_HOST} from '../interfaces/view';
import {BINDING_INDEX, HEADER_OFFSET, QUERIES, RENDERER, TVIEW, T_HOST} from '../interfaces/view';
import {assertNodeType} from '../node_assert';
import {appendChild} from '../node_manipulation';
import {applyOnCreateInstructions} from '../node_util';
@ -23,14 +21,14 @@ import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticCo
import {getStylingContextFromLView, hasClassInput, hasStyleInput} from '../styling/util';
import {registerInitialStylingIntoContext} from '../styling_next/instructions';
import {runtimeIsNewStylingInUse} from '../styling_next/state';
import {NO_CHANGE} from '../tokens';
import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils';
import {renderStringify} from '../util/misc_utils';
import {getNativeByIndex, getNativeByTNode, getTNode} from '../util/view_utils';
import {getNativeByTNode, getTNode} from '../util/view_utils';
import {createDirectivesAndLocals, elementCreate, executeContentQueries, getOrCreateTNode, initializeTNodeInputs, setInputsForProperty, setNodeStylingTemplate} from './shared';
import {getActiveDirectiveStylingIndex} from './styling';
/**
* Create DOM element. The instruction must later be followed by `elementEnd()` call.
*
@ -197,54 +195,6 @@ export function ɵɵelement(
ɵɵelementEnd();
}
/**
* Updates the value or removes an attribute on an Element.
*
* @param index The index of the element in the data array
* @param name name The name of the attribute.
* @param value value The attribute is removed when value is `null` or `undefined`.
* Otherwise the attribute value is set to the stringified value.
* @param sanitizer An optional function used to sanitize the value.
* @param namespace Optional namespace to use when setting the attribute.
*
* @codeGenApi
*/
export function ɵɵelementAttribute(
index: number, name: string, value: any, sanitizer?: SanitizerFn | null,
namespace?: string): void {
if (value !== NO_CHANGE) {
const lView = getLView();
const renderer = lView[RENDERER];
elementAttributeInternal(index, name, value, lView, renderer, sanitizer, namespace);
}
}
export function elementAttributeInternal(
index: number, name: string, value: any, lView: LView, renderer: Renderer3,
sanitizer?: SanitizerFn | null, namespace?: string) {
ngDevMode && validateAgainstEventAttributes(name);
const element = getNativeByIndex(index, lView) as RElement;
if (value == null) {
ngDevMode && ngDevMode.rendererRemoveAttribute++;
isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
element.removeAttribute(name);
} else {
ngDevMode && ngDevMode.rendererSetAttribute++;
const tNode = getTNode(index, lView);
const strValue =
sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name);
if (isProceduralRenderer(renderer)) {
renderer.setAttribute(element, name, strValue, namespace);
} else {
namespace ? element.setAttributeNS(namespace, name, strValue) :
element.setAttribute(name, strValue);
}
}
}
/**
* Assign static attribute values to a host element.
*

View File

@ -12,7 +12,6 @@ import {appendProjectedNodes} from '../node_manipulation';
import {getProjectAsAttrValue, isNodeMatchingSelectorList, isSelectorInSelectorList} from '../node_selector_matcher';
import {getLView, setIsNotParent} from '../state';
import {findComponentView} from '../util/view_traversal_utils';
import {getOrCreateTNode} from './shared';
@ -103,6 +102,11 @@ export function ɵɵprojectionDef(projectionSlots?: ProjectionSlots): void {
}
}
let delayProjection = false;
export function setDelayProjection(value: boolean) {
delayProjection = value;
}
/**
* Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
@ -127,6 +131,9 @@ export function ɵɵprojection(
// `<ng-content>` has no content
setIsNotParent();
// re-distribution of projectable nodes is stored on a component's view level
appendProjectedNodes(lView, tProjectionNode, selectorIndex, findComponentView(lView));
// We might need to delay the projection of nodes if they are in the middle of an i18n block
if (!delayProjection) {
// re-distribution of projectable nodes is stored on a component's view level
appendProjectedNodes(lView, tProjectionNode, selectorIndex, findComponentView(lView));
}
}

View File

@ -61,32 +61,6 @@ export function ɵɵbind<T>(value: T): T|NO_CHANGE {
return bindingUpdated(lView, bindingIndex, value) ? value : NO_CHANGE;
}
/**
* **TODO: Remove this function after `property` is in use**
* Update a property on an element.
*
* If the property name also exists as an input property on one of the element's directives,
* the component property will be set instead of the element property. This check must
* be conducted at runtime so child components that add new @Inputs don't have to be re-compiled.
*
* @param index The index of the element to update in the data array
* @param propName Name of property. Because it is going to DOM, this is not subject to
* renaming as part of minification.
* @param value New value to write.
* @param sanitizer An optional function used to sanitize the value.
* @param nativeOnly Whether or not we should only set native properties and skip input check
* (this is necessary for host property bindings)
*
* @codeGenApi
*/
export function ɵɵelementProperty<T>(
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null,
nativeOnly?: boolean): void {
if (value !== NO_CHANGE) {
elementPropertyInternal(index, propName, value, sanitizer, nativeOnly);
}
}
/**
* Updates a synthetic host binding (e.g. `[@foo]`) on a component.
*

View File

@ -9,7 +9,7 @@ import {Injector} from '../../di';
import {ErrorHandler} from '../../error_handler';
import {Type} from '../../interface/type';
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../metadata/schema';
import {validateAgainstEventProperties} from '../../sanitization/sanitization';
import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization';
import {Sanitizer} from '../../sanitization/security';
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertLessThan, assertNotEqual, assertNotSame} from '../../util/assert';
import {createNamedArrayType} from '../../util/named_array_type';
@ -35,7 +35,7 @@ import {initializeStaticContext as initializeStaticStylingContext} from '../styl
import {ANIMATION_PROP_PREFIX, isAnimationProp} from '../styling/util';
import {NO_CHANGE} from '../tokens';
import {attrsStylingIndexOf} from '../util/attrs_utils';
import {INTERPOLATION_DELIMITER, stringifyForError} from '../util/misc_utils';
import {INTERPOLATION_DELIMITER, renderStringify, stringifyForError} from '../util/misc_utils';
import {getLViewParent, getRootContext} from '../util/view_traversal_utils';
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isLContainer, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils';
@ -1303,6 +1303,33 @@ function addComponentLogic<T>(
}
}
export function elementAttributeInternal(
index: number, name: string, value: any, lView: LView, sanitizer?: SanitizerFn | null,
namespace?: string) {
ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.');
ngDevMode && validateAgainstEventAttributes(name);
const element = getNativeByIndex(index, lView) as RElement;
const renderer = lView[RENDERER];
if (value == null) {
ngDevMode && ngDevMode.rendererRemoveAttribute++;
isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
element.removeAttribute(name);
} else {
ngDevMode && ngDevMode.rendererSetAttribute++;
const tNode = getTNode(index, lView);
const strValue =
sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name);
if (isProceduralRenderer(renderer)) {
renderer.setAttribute(element, name, strValue, namespace);
} else {
namespace ? element.setAttributeNS(namespace, name, strValue) :
element.setAttribute(name, strValue);
}
}
}
/**
* Sets initial input properties on directive instances from attribute data
*

View File

@ -47,19 +47,22 @@ export const enum TNodeType {
*/
export const enum TNodeFlags {
/** This bit is set if the node is a component */
isComponent = 0b00001,
isComponent = 0b000001,
/** This bit is set if the node has been projected */
isProjected = 0b00010,
isProjected = 0b000010,
/** This bit is set if any directive on this node has content queries */
hasContentQuery = 0b00100,
hasContentQuery = 0b000100,
/** This bit is set if the node has any "class" inputs */
hasClassInput = 0b01000,
hasClassInput = 0b001000,
/** This bit is set if the node has any "style" inputs */
hasStyleInput = 0b10000,
hasStyleInput = 0b010000,
/** This bit is set if the node has been detached by i18n */
isDetached = 0b100000,
}
/**

View File

@ -46,7 +46,6 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵNgOnChangesFeature': r3.ɵɵNgOnChangesFeature,
'ɵɵProvidersFeature': r3.ɵɵProvidersFeature,
'ɵɵInheritDefinitionFeature': r3.ɵɵInheritDefinitionFeature,
'ɵɵelementAttribute': r3.ɵɵelementAttribute,
'ɵɵbind': r3.ɵɵbind,
'ɵɵcontainer': r3.ɵɵcontainer,
'ɵɵnextContext': r3.ɵɵnextContext,
@ -87,7 +86,6 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵlistener': r3.ɵɵlistener,
'ɵɵload': r3.ɵɵload,
'ɵɵprojection': r3.ɵɵprojection,
'ɵɵelementProperty': r3.ɵɵelementProperty,
'ɵɵupdateSyntheticHostBinding': r3.ɵɵupdateSyntheticHostBinding,
'ɵɵcomponentHostSyntheticListener': r3.ɵɵcomponentHostSyntheticListener,
'ɵɵpipeBind1': r3.ɵɵpipeBind1,

View File

@ -784,15 +784,17 @@ export function appendProjectedNodes(
appendChild(nodeToProject, tProjectionNode, lView);
} else {
while (nodeToProject) {
if (nodeToProject.type === TNodeType.Projection) {
appendProjectedNodes(
lView, tProjectionNode, (nodeToProject as TProjectionNode).projection,
findComponentView(projectedView));
} else {
// This flag must be set now or we won't know that this node is projected
// if the nodes are inserted into a container later.
nodeToProject.flags |= TNodeFlags.isProjected;
appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView);
if (!(nodeToProject.flags & TNodeFlags.isDetached)) {
if (nodeToProject.type === TNodeType.Projection) {
appendProjectedNodes(
lView, tProjectionNode, (nodeToProject as TProjectionNode).projection,
findComponentView(projectedView));
} else {
// This flag must be set now or we won't know that this node is projected
// if the nodes are inserted into a container later.
nodeToProject.flags |= TNodeFlags.isProjected;
appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView);
}
}
nodeToProject = nodeToProject.projectionNext;
}

View File

@ -26,7 +26,6 @@ export function isDifferent(a: any, b: any): boolean {
* be extra careful not to introduce megamorphic reads in it.
*/
export function renderStringify(value: any): string {
if (typeof value === 'function') return value.name || value;
if (typeof value === 'string') return value;
if (value == null) return '';
return '' + value;
@ -38,9 +37,10 @@ export function renderStringify(value: any): string {
* Important! This function contains a megamorphic read and should only be
* used for error messages.
*/
export function stringifyForError(value: any) {
export function stringifyForError(value: any): string {
if (typeof value === 'function') return value.name || value.toString();
if (typeof value === 'object' && value != null && typeof value.type === 'function') {
return value.type.name || value.type;
return value.type.name || value.type.toString();
}
return renderStringify(value);

View File

@ -9,6 +9,7 @@
import {registerLocaleData} from '@angular/common';
import localeRo from '@angular/common/locales/ro';
import {Component, ContentChild, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, ɵi18nConfigureLocalize} from '@angular/core';
import {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing';
@ -19,6 +20,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [AppComp, DirectiveWithTplRef]});
});
afterEach(() => { setDelayProjection(false); });
it('should translate text', () => {
ɵi18nConfigureLocalize({translations: {'text': 'texte'}});
const fixture = initWithTemplate(AppComp, `<div i18n>text</div>`);
@ -712,6 +715,42 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const element = fixture.nativeElement.firstChild;
expect(element.title).toBe('Bonjour Angular');
});
it('should apply i18n attributes during second template pass', () => {
@Directive({
selector: '[test]',
inputs: ['test'],
exportAs: 'dir',
})
class Dir {
}
@Component({
selector: 'other',
template: `<div i18n #ref="dir" test="Set" i18n-test="This is also a test"></div>`
})
class Other {
}
@Component({
selector: 'blah',
template: `
<other></other>
<other></other>
`
})
class Cmp {
}
TestBed.configureTestingModule({
declarations: [Dir, Cmp, Other],
});
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
expect(fixture.debugElement.children[0].children[0].references.ref.test).toBe('Set');
expect(fixture.debugElement.children[1].children[0].references.ref.test).toBe('Set');
});
});
it('should work with directives and host bindings', () => {
@ -936,8 +975,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
.toEqual('<child><grand-child><div><b>Bonjour</b> monde!</div></grand-child></child>');
});
// FW-1319 Runtime i18n should be able to remove projected placeholders
xit('should be able to remove projected placeholders', () => {
it('should be able to remove projected placeholders', () => {
@Component({selector: 'grand-child', template: '<div><ng-content></ng-content></div>'})
class GrandChild {
}
@ -990,6 +1028,170 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
expect(fixture.nativeElement.innerHTML)
.toEqual('<child><span title="keepMe">Contenu</span></child>');
});
it('should project content in i18n blocks', () => {
@Component({
selector: 'child',
template: `<div i18n>Content projected from <ng-content></ng-content></div>`
})
class Child {
}
@Component({selector: 'parent', template: `<child>{{name}}</child>`})
class Parent {
name: string = 'Parent';
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({
translations: {
'Content projected from {$startTagNgContent}{$closeTagNgContent}':
'Contenu projeté depuis {$startTagNgContent}{$closeTagNgContent}'
}
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<child><div>Contenu projeté depuis Parent</div></child>`);
fixture.componentRef.instance.name = 'Parent component';
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<child><div>Contenu projeté depuis Parent component</div></child>`);
});
it('should project content in i18n blocks with placeholders', () => {
@Component({
selector: 'child',
template: `<div i18n>Content projected from <ng-content></ng-content></div>`
})
class Child {
}
@Component({selector: 'parent', template: `<child><b>{{name}}</b></child>`})
class Parent {
name: string = 'Parent';
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({
translations: {
'Content projected from {$startTagNgContent}{$closeTagNgContent}':
'{$startTagNgContent}{$closeTagNgContent} a projeté le contenu'
}
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<child><div><b>Parent</b> a projeté le contenu</div></child>`);
});
it('should project translated content in i18n blocks', () => {
@Component(
{selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`})
class Child {
}
@Component({selector: 'parent', template: `<child i18n>and projection from {{name}}</child>`})
class Parent {
name: string = 'Parent';
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({
translations: {
'Child content {$startTagNgContent}{$closeTagNgContent}':
'Contenu enfant {$startTagNgContent}{$closeTagNgContent}',
'and projection from {$interpolation}': 'et projection depuis {$interpolation}'
}
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<child><div>Contenu enfant et projection depuis Parent</div></child>`);
});
it('should project bare ICU expressions', () => {
@Component({selector: 'child', template: '<div><ng-content></ng-content></div>'})
class Child {
}
@Component({
selector: 'parent',
template: `
<child i18n>{
value // i18n(ph = "blah"),
plural,
=1 {one}
other {at least {{value}} .}
}</child>`
})
class Parent {
value = 3;
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({translations: {}});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toContain('at least');
});
it('should project ICUs in i18n blocks', () => {
@Component(
{selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`})
class Child {
}
@Component({
selector: 'parent',
template:
`<child i18n>and projection from {name, select, angular {Angular} other {{{name}}}}</child>`
})
class Parent {
name: string = 'Parent';
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({
translations: {
'Child content {$startTagNgContent}{$closeTagNgContent}':
'Contenu enfant {$startTagNgContent}{$closeTagNgContent}',
'and projection from {$icu}': 'et projection depuis {$icu}'
}
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<child><div>Contenu enfant et projection depuis Parent<!--ICU 15--></div></child>`);
fixture.componentRef.instance.name = 'angular';
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<child><div>Contenu enfant et projection depuis Angular<!--ICU 15--></div></child>`);
});
it(`shouldn't project deleted projections in i18n blocks`, () => {
@Component(
{selector: 'child', template: `<div i18n>Child content <ng-content></ng-content></div>`})
class Child {
}
@Component({selector: 'parent', template: `<child i18n>and projection from {{name}}</child>`})
class Parent {
name: string = 'Parent';
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
ɵi18nConfigureLocalize({
translations: {
'Child content {$startTagNgContent}{$closeTagNgContent}': 'Contenu enfant',
'and projection from {$interpolation}': 'et projection depuis {$interpolation}'
}
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual(`<child><div>Contenu enfant</div></child>`);
});
});
describe('queries', () => {

View File

@ -112,4 +112,20 @@ describe('text instructions', () => {
expect(div.innerHTML).toBe('&lt;h1&gt;LOL, big text&lt;/h1&gt;');
});
it('should stringify functions used in bindings', () => {
@Component({
template: '<div>{{test}}</div>',
})
class App {
test = function foo() {};
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const div = fixture.nativeElement.querySelector('div');
expect(div.innerHTML).toBe('function foo() { }');
});
});

View File

@ -7,7 +7,7 @@
*/
import {Component, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {Component, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -736,5 +736,58 @@ class TestCmptWithPropBindings {
]);
});
it('should preserve the attribute case in DebugNode.attributes', () => {
@Component({selector: 'my-icon', template: ''})
class Icon {
@Input() svgIcon: any = '';
}
@Component({template: `<my-icon svgIcon="test"></my-icon>`})
class App {
}
TestBed.configureTestingModule({declarations: [App, Icon]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const element = fixture.debugElement.children[0];
// Assert that the camel-case attribute is correct.
expect(element.attributes.svgIcon).toBe('test');
// Make sure that we somehow didn't preserve the native lower-cased value.
expect(element.attributes.svgicon).toBeFalsy();
});
it('should include namespaced attributes in DebugNode.attributes', () => {
@Component({
template: `<div xlink:href="foo"></div>`,
})
class Comp {
}
TestBed.configureTestingModule({declarations: [Comp]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('div')).attributes['xlink:href']).toBe('foo');
});
it('should include attributes added via Renderer2 in DebugNode.attributes', () => {
@Component({
template: '<div></div>',
})
class Comp {
constructor(public renderer: Renderer2) {}
}
TestBed.configureTestingModule({declarations: [Comp]});
const fixture = TestBed.createComponent(Comp);
const div = fixture.debugElement.query(By.css('div'));
fixture.componentInstance.renderer.setAttribute(div.nativeElement, 'foo', 'bar');
expect(div.attributes.foo).toBe('bar');
});
});
}

View File

@ -10,8 +10,8 @@ import {withBody} from '@angular/private/testing';
import {ChangeDetectionStrategy, DoCheck} from '../../src/core';
import {whenRendered} from '../../src/render3/component';
import {LifecycleHooksFeature, getRenderedText, ɵɵdefineComponent, ɵɵgetCurrentView} from '../../src/render3/index';
import {detectChanges, markDirty, tick, ɵɵbind, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵinterpolation1, ɵɵinterpolation2, ɵɵlistener, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {LifecycleHooksFeature, getRenderedText, ɵɵdefineComponent, ɵɵgetCurrentView, ɵɵproperty, ɵɵselect} from '../../src/render3/index';
import {detectChanges, markDirty, tick, ɵɵbind, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵinterpolation1, ɵɵinterpolation2, ɵɵlistener, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer';
import {FLAGS, LViewFlags} from '../../src/render3/interfaces/view';
@ -186,7 +186,8 @@ describe('change detection', () => {
ɵɵelement(0, 'manual-comp');
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'name', ɵɵbind(ctx.name));
ɵɵselect(0);
ɵɵproperty('name', ctx.name);
}
},

View File

@ -8,8 +8,8 @@
import {ViewEncapsulation, ɵɵdefineInjectable, ɵɵdefineInjector} from '../../src/core';
import {createInjector} from '../../src/di/r3_injector';
import {AttributeMarker, ComponentFactory, LifecycleHooksFeature, getRenderedText, markDirty, ɵɵdefineComponent, ɵɵdirectiveInject, ɵɵtemplate} from '../../src/render3/index';
import {tick, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵnextContext, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {AttributeMarker, ComponentFactory, LifecycleHooksFeature, getRenderedText, markDirty, ɵɵdefineComponent, ɵɵdirectiveInject, ɵɵproperty, ɵɵselect, ɵɵtemplate} from '../../src/render3/index';
import {tick, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵnextContext, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {ComponentDef, RenderFlags} from '../../src/render3/interfaces/definition';
import {NgIf} from './common_with_def';
@ -137,7 +137,8 @@ describe('component', () => {
ɵɵelement(4097, 'comp');
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(4097, 'name', ɵɵbind(ctx.name));
ɵɵselect(4097);
ɵɵproperty('name', ctx.name);
}
}, 4098, 1, [Comp]);
@ -188,7 +189,8 @@ it('should not invoke renderer destroy method for embedded views', () => {
2, MyComponent_div_Template_2, 2, 0, 'div', [AttributeMarker.Template, 'ngIf']);
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(2, 'ngIf', ɵɵbind(ctx.visible));
ɵɵselect(2);
ɵɵproperty('ngIf', ctx.visible);
}
}
});
@ -269,7 +271,8 @@ describe('component with a container', () => {
ɵɵelement(0, 'wrapper');
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'items', ɵɵbind(ctx.items));
ɵɵselect(0);
ɵɵproperty('items', ctx.items);
}
}
@ -339,7 +342,8 @@ describe('recursive components', () => {
ɵɵelement(0, 'tree-comp');
}
if (rf0 & RenderFlags.Update) {
ɵɵelementProperty(0, 'data', ɵɵbind(ctx.data.left));
ɵɵselect(0);
ɵɵproperty('data', ctx.data.left);
}
ɵɵembeddedViewEnd();
}
@ -353,7 +357,8 @@ describe('recursive components', () => {
ɵɵelement(0, 'tree-comp');
}
if (rf0 & RenderFlags.Update) {
ɵɵelementProperty(0, 'data', ɵɵbind(ctx.data.right));
ɵɵselect(0);
ɵɵproperty('data', ctx.data.right);
}
ɵɵembeddedViewEnd();
}
@ -400,8 +405,10 @@ describe('recursive components', () => {
}
if (rf & RenderFlags.Update) {
ɵɵtextBinding(0, ɵɵbind(ctx.data.value));
ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.data.left));
ɵɵelementProperty(2, 'ngIf', ɵɵbind(ctx.data.right));
ɵɵselect(1);
ɵɵproperty('ngIf', ɵɵbind(ctx.data.left));
ɵɵselect(2);
ɵɵproperty('ngIf', ctx.data.right);
}
},
@ -416,7 +423,8 @@ describe('recursive components', () => {
}
if (rf & RenderFlags.Update) {
const parent = ɵɵnextContext();
ɵɵelementProperty(0, 'data', ɵɵbind(parent.data.left));
ɵɵselect(0);
ɵɵproperty('data', parent.data.left);
}
}
@ -427,7 +435,8 @@ describe('recursive components', () => {
}
if (rf & RenderFlags.Update) {
const parent = ɵɵnextContext();
ɵɵelementProperty(0, 'data', ɵɵbind(parent.data.right));
ɵɵselect(0);
ɵɵproperty('data', parent.data.right);
}
}

View File

@ -8,13 +8,14 @@
import {noop} from '../../../compiler/src/render3/view/util';
import {getTranslationForTemplate, ɵɵi18nAttributes, ɵɵi18nPostprocess, ɵɵi18nStart} from '../../src/render3/i18n';
import {ɵɵelementEnd, ɵɵelementStart} from '../../src/render3/instructions/all';
import {setDelayProjection, ɵɵelementEnd, ɵɵelementStart} from '../../src/render3/instructions/all';
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nUpdateOpCode, I18nUpdateOpCodes, TI18n} from '../../src/render3/interfaces/i18n';
import {HEADER_OFFSET, LView, TVIEW} from '../../src/render3/interfaces/view';
import {getNativeByIndex} from '../../src/render3/util/view_utils';
import {TemplateFixture} from './render_util';
describe('Runtime i18n', () => {
afterEach(() => { setDelayProjection(false); });
describe('getTranslationForTemplate', () => {
it('should crop messages for the selected template', () => {
let message = `simple text`;

View File

@ -9,7 +9,7 @@
import {NgForOfContext} from '@angular/common';
import {ɵɵdefineComponent} from '../../src/render3/definition';
import {RenderFlags, ɵɵbind, ɵɵclassMap, ɵɵelement, ɵɵelementAttribute, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index';
import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index';
import {AttributeMarker} from '../../src/render3/interfaces/node';
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass';
import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization';
@ -58,10 +58,16 @@ describe('instructions', () => {
it('should update bindings when value changes with the correct perf counters', () => {
const t = new TemplateFixture(createAnchor, () => {}, 1, 1);
t.update(() => ɵɵelementProperty(0, 'title', ɵɵbind('Hello')));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('title', 'Hello');
});
expect(t.html).toEqual('<a title="Hello"></a>');
t.update(() => ɵɵelementProperty(0, 'title', ɵɵbind('World')));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('title', 'World');
});
expect(t.html).toEqual('<a title="World"></a>');
expect(ngDevMode).toHaveProperties({
firstTemplatePass: 1,
@ -74,7 +80,10 @@ describe('instructions', () => {
it('should not update bindings when value does not change, with the correct perf counters',
() => {
const idempotentUpdate = () => ɵɵelementProperty(0, 'title', ɵɵbind('Hello'));
const idempotentUpdate = () => {
ɵɵselect(0);
ɵɵproperty('title', 'Hello');
};
const t = new TemplateFixture(createAnchor, idempotentUpdate, 1, 1);
t.update();
@ -110,16 +119,20 @@ describe('instructions', () => {
});
});
describe('elementAttribute', () => {
describe('attribute', () => {
it('should use sanitizer function', () => {
const t = new TemplateFixture(createDiv, () => {}, 1);
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
t.update(() => ɵɵelementAttribute(0, 'title', 'javascript:true', ɵɵsanitizeUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('title', 'javascript:true', ɵɵsanitizeUrl);
});
expect(t.html).toEqual('<div title="unsafe:javascript:true"></div>');
t.update(
() => ɵɵelementAttribute(
0, 'title', bypassSanitizationTrustUrl('javascript:true'), ɵɵsanitizeUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('title', bypassSanitizationTrustUrl('javascript:true'), ɵɵsanitizeUrl);
});
expect(t.html).toEqual('<div title="javascript:true"></div>');
expect(ngDevMode).toHaveProperties({
firstTemplatePass: 1,
@ -295,7 +308,8 @@ describe('instructions', () => {
}
if (rf & RenderFlags.Update) {
const row_r2 = ctx0.$implicit;
ɵɵelementProperty(1, 'ngForOf', ɵɵbind(row_r2));
ɵɵselect(1);
ɵɵproperty('ngForOf', row_r2);
}
}
@ -331,7 +345,8 @@ describe('instructions', () => {
ɵɵtemplate(0, ToDoAppComponent_NgForOf_Template_0, 2, 1, 'ul', _c0);
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'ngForOf', ɵɵbind(ctx.rows));
ɵɵselect(0);
ɵɵproperty('ngForOf', ctx.rows);
}
},
directives: [NgForOf]
@ -349,165 +364,210 @@ describe('instructions', () => {
describe('sanitization injection compatibility', () => {
it('should work for url sanitization', () => {
const s = new LocalMockSanitizer(value => `${value}-sanitized`);
const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s);
const inputValue = 'http://foo';
const outputValue = 'http://foo-sanitized';
t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('href', inputValue, ɵɵsanitizeUrl);
});
expect(t.html).toEqual(`<a href="${outputValue}"></a>`);
expect(s.lastSanitizedValue).toEqual(outputValue);
});
it('should bypass url sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s);
const inputValue = s.bypassSecurityTrustUrl('http://foo');
const outputValue = 'http://foo';
t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('href', inputValue, ɵɵsanitizeUrl);
});
expect(t.html).toEqual(`<a href="${outputValue}"></a>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should bypass ivy-level url sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s);
const inputValue = bypassSanitizationTrustUrl('http://foo');
const outputValue = 'http://foo-ivy';
t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('href', inputValue, ɵɵsanitizeUrl);
});
expect(t.html).toEqual(`<a href="${outputValue}"></a>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should work for style sanitization', () => {
const s = new LocalMockSanitizer(value => `color:blue`);
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = 'color:red';
const outputValue = 'color:blue';
t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('style', inputValue, ɵɵsanitizeStyle);
});
expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`);
expect(s.lastSanitizedValue).toEqual(outputValue);
});
it('should bypass style sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = s.bypassSecurityTrustStyle('color:maroon');
const outputValue = 'color:maroon';
t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('style', inputValue, ɵɵsanitizeStyle);
});
expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should bypass ivy-level style sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = bypassSanitizationTrustStyle('font-family:foo');
const outputValue = 'font-family:foo-ivy';
t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('style', inputValue, ɵɵsanitizeStyle);
});
expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should work for resourceUrl sanitization', () => {
const s = new LocalMockSanitizer(value => `${value}-sanitized`);
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = 'http://resource';
const outputValue = 'http://resource-sanitized';
t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl);
});
expect(t.html).toEqual(`<script src="${outputValue}"></script>`);
expect(s.lastSanitizedValue).toEqual(outputValue);
});
it('should bypass resourceUrl sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = s.bypassSecurityTrustResourceUrl('file://all-my-secrets.pdf');
const outputValue = 'file://all-my-secrets.pdf';
t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl);
});
expect(t.html).toEqual(`<script src="${outputValue}"></script>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should bypass ivy-level resourceUrl sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = bypassSanitizationTrustResourceUrl('file://all-my-secrets.pdf');
const outputValue = 'file://all-my-secrets.pdf-ivy';
t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl));
t.update(() => {
ɵɵselect(0);
ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl);
});
expect(t.html).toEqual(`<script src="${outputValue}"></script>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should work for script sanitization', () => {
const s = new LocalMockSanitizer(value => `${value} //sanitized`);
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = 'fn();';
const outputValue = 'fn(); //sanitized';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeScript));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript);
});
expect(t.html).toEqual(`<script>${outputValue}</script>`);
expect(s.lastSanitizedValue).toEqual(outputValue);
});
it('should bypass script sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = s.bypassSecurityTrustScript('alert("bar")');
const outputValue = 'alert("bar")';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeScript));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript);
});
expect(t.html).toEqual(`<script>${outputValue}</script>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s);
const inputValue = bypassSanitizationTrustScript('alert("bar")');
const outputValue = 'alert("bar")-ivy';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeScript));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript);
});
expect(t.html).toEqual(`<script>${outputValue}</script>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should work for html sanitization', () => {
const s = new LocalMockSanitizer(value => `${value} <!--sanitized-->`);
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = '<header></header>';
const outputValue = '<header></header> <!--sanitized-->';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeHtml));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml);
});
expect(t.html).toEqual(`<div>${outputValue}</div>`);
expect(s.lastSanitizedValue).toEqual(outputValue);
});
it('should bypass html sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = s.bypassSecurityTrustHtml('<div onclick="alert(123)"></div>');
const outputValue = '<div onclick="alert(123)"></div>';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeHtml));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml);
});
expect(t.html).toEqual(`<div>${outputValue}</div>`);
expect(s.lastSanitizedValue).toBeFalsy();
});
it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s);
const inputValue = bypassSanitizationTrustHtml('<div onclick="alert(123)"></div>');
const outputValue = '<div onclick="alert(123)"></div>-ivy';
t.update(() => ɵɵelementProperty(0, 'innerHTML', inputValue, ɵɵsanitizeHtml));
t.update(() => {
ɵɵselect(0);
ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml);
});
expect(t.html).toEqual(`<div>${outputValue}</div>`);
expect(s.lastSanitizedValue).toBeFalsy();
});

View File

@ -8,8 +8,8 @@
import {RendererType2} from '../../src/render/api';
import {getLContext} from '../../src/render3/context_discovery';
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index';
import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementAttribute, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {AttributeMarker, ɵɵattribute, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵproperty} from '../../src/render3/index';
import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer';
@ -159,8 +159,9 @@ describe('render3 integration test', () => {
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'beforeTree', ɵɵbind(ctx.beforeTree));
ɵɵelementProperty(0, 'afterTree', ɵɵbind(ctx.afterTree));
ɵɵselect(0);
ɵɵproperty('beforeTree', ctx.beforeTree);
ɵɵproperty('afterTree', ctx.afterTree);
ɵɵcontainerRefreshStart(1);
{
const rf0 = ɵɵembeddedViewStart(0, 3, 0);
@ -285,7 +286,8 @@ describe('component animations', () => {
ɵɵelement(0, 'div', [AttributeMarker.Bindings, '@fooAnimation']);
}
if (rf & RenderFlags.Update) {
ɵɵelementAttribute(0, '@fooAnimation', ɵɵbind(ctx.animationValue));
ɵɵselect(0);
ɵɵattribute('@fooAnimation', ctx.animationValue);
}
}
});
@ -335,48 +337,54 @@ describe('component animations', () => {
expect(attr).toEqual('@fooAnimation');
});
it('should allow host binding animations to be picked up and rendered', () => {
class ChildCompWithAnim {
static ngDirectiveDef = ɵɵdefineDirective({
type: ChildCompWithAnim,
factory: () => new ChildCompWithAnim(),
selectors: [['child-comp-with-anim']],
hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void {
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, '@fooAnim', ctx.exp);
}
},
});
// TODO(benlesh): this test does not seem to be testing anything we could actually generate with
// these instructions. ɵɵbind should be present in the ɵɵelementProperty call in the hostBindings,
// however adding that causes an error because the slot has not been allocated. There is a
// directive called `comp-with-anim`, that seems to want to be a component, but is defined as a
// directive that is looking for a property `@fooAnim` to update.
exp = 'go';
}
// it('should allow host binding animations to be picked up and rendered', () => {
// class ChildCompWithAnim {
// static ngDirectiveDef = ɵɵdefineDirective({
// type: ChildCompWithAnim,
// factory: () => new ChildCompWithAnim(),
// selectors: [['child-comp-with-anim']],
// hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void {
// if (rf & RenderFlags.Update) {
// ɵɵelementProperty(0, '@fooAnim', ctx.exp);
// }
// },
// });
class ParentComp {
static ngComponentDef = ɵɵdefineComponent({
type: ParentComp,
consts: 1,
vars: 1,
selectors: [['foo']],
factory: () => new ParentComp(),
template: (rf: RenderFlags, ctx: ParentComp) => {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'child-comp-with-anim');
}
},
directives: [ChildCompWithAnim]
});
}
// exp = 'go';
// }
const rendererFactory = new MockRendererFactory(['setProperty']);
const fixture = new ComponentFixture(ParentComp, {rendererFactory});
// class ParentComp {
// static ngComponentDef = ɵɵdefineComponent({
// type: ParentComp,
// consts: 1,
// vars: 1,
// selectors: [['foo']],
// factory: () => new ParentComp(),
// template: (rf: RenderFlags, ctx: ParentComp) => {
// if (rf & RenderFlags.Create) {
// ɵɵelement(0, 'child-comp-with-anim');
// }
// },
// directives: [ChildCompWithAnim]
// });
// }
const renderer = rendererFactory.lastRenderer !;
fixture.update();
// const rendererFactory = new MockRendererFactory(['setProperty']);
// const fixture = new ComponentFixture(ParentComp, {rendererFactory});
const spy = renderer.spies['setProperty'];
const [elm, attr, value] = spy.calls.mostRecent().args;
expect(attr).toEqual('@fooAnim');
});
// const renderer = rendererFactory.lastRenderer !;
// fixture.update();
// const spy = renderer.spies['setProperty'];
// const [elm, attr, value] = spy.calls.mostRecent().args;
// expect(attr).toEqual('@fooAnim');
// });
});
describe('element discovery', () => {
@ -485,7 +493,8 @@ describe('element discovery', () => {
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(1, 'ngIf', true);
ɵɵselect(1);
ɵɵproperty('ngIf', true);
}
}
});
@ -1087,7 +1096,8 @@ describe('sanitization', () => {
ɵɵelement(0, 'a');
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'href', ɵɵbind(ctx.href), ɵɵsanitizeUrl);
ɵɵselect(0);
ɵɵproperty('href', ctx.href, ɵɵsanitizeUrl);
}
}
});
@ -1127,7 +1137,8 @@ describe('sanitization', () => {
ɵɵallocHostVars(1);
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(elementIndex, 'cite', ɵɵbind(ctx.cite), ɵɵsanitizeUrl, true);
ɵɵselect(elementIndex);
ɵɵproperty('cite', ctx.cite, ɵɵsanitizeUrl, true);
}
}
});

View File

@ -7,8 +7,8 @@
*/
import {OnDestroy} from '../../src/core';
import {AttributeMarker, ComponentTemplate, ɵɵNgOnChangesFeature, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index';
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all';
import {AttributeMarker, ComponentTemplate, ɵɵNgOnChangesFeature, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵproperty} from '../../src/render3/index';
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgIf} from './common_with_def';
@ -22,7 +22,8 @@ describe('lifecycles', () => {
ɵɵelement(0, name);
}
if (rf & RenderFlags.Update) {
ɵɵelementProperty(0, 'val', ɵɵbind(ctx.val));
ɵɵselect(0);
ɵɵproperty('val', ctx.val);
}
};
}

View File

@ -5,8 +5,8 @@
* 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 {ɵɵdefineComponent} from '../../src/render3/index';
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart} from '../../src/render3/instructions/all';
import {ɵɵdefineComponent, ɵɵproperty, ɵɵselect} from '../../src/render3/index';
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ɵɵpureFunction2} from '../../src/render3/pure_function';
import {getDirectiveOnNode, renderToHtml} from '../../test/render3/render_util';
@ -58,9 +58,10 @@ describe('object literals', () => {
ɵɵelementEnd();
}
if (rf1 & RenderFlags.Update) {
ɵɵelementProperty(
0, 'config', ɵɵbind(ɵɵpureFunction2(
1, e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
ɵɵselect(0);
ɵɵproperty(
'config',
ɵɵpureFunction2(1, e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration));
}
ɵɵembeddedViewEnd();
}

View File

@ -1,31 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"rxjs/*": [
"../../../node_modules/rxjs/*"
],
"@angular/core": [
"../../../dist/packages/core"
],
"@angular/compiler": [
"../../../dist/packages/compiler"
],
},
"outDir": "../../../dist/packages/core"
},
"files": [
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts",
"../../system.d.ts",
"../../types.d.ts"
],
"angularCompilerOptions": {
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/core/testing"
}
}

View File

@ -1,31 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"rxjs/*": [
"../../node_modules/rxjs/*"
],
"@angular/core": [
"."
],
"@angular/compiler": [
"../../dist/packages/compiler"
]
},
"outDir": "../../dist/packages/core"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts",
"../system.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "core.js",
"flatModuleId": "@angular/core"
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"],
"rxjs/*": ["../../node_modules/rxjs/*"]
},
"outDir": "../../dist/packages/elements"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "elements.js",
"flatModuleId": "@angular/elements"
}
}

View File

@ -1,31 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/core/testing": ["../../dist/packages/core/testing"],
"@angular/common": ["../../dist/packages/common"],
"@angular/common/testing": ["../../dist/packages/common/testing"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/compiler/testing": ["../../dist/packages/compiler/testing"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"]
},
"outDir": "../../dist/packages/forms"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "forms.js",
"flatModuleId": "@angular/forms"
}
}

View File

@ -1,26 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"],
"@angular/http": ["../../../dist/packages/http"],
"rxjs/*": ["../../../node_modules/rxjs/*"]
},
"outDir": "../../../dist/packages/http"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/http/testing"
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"]
},
"outDir": "../../dist/packages/http"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "http.js",
"flatModuleId": "@angular/http"
}
}

View File

@ -1,30 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/animation": ["../../dist/packages/animation"],
"@angular/animation/browser": ["../../dist/packages/animation/browser"],
"@angular/core/testing": ["../../dist/packages/core/testing"],
"@angular/common": ["../../dist/packages/common"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/compiler-cli": ["../../dist/packages/compiler-cli"],
"@angular/compiler-cli/*": ["../../dist/packages/compiler-cli/*"],
"@angular/http": ["../../dist/packages/http"],
"@angular/platform-server": ["../../dist/packages/platform-server"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"]
},
"outDir": "../../dist/packages/language-service"
},
"files": [
"index.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts",
"../../node_modules/@types/node/index.d.ts",
"../../node_modules/@types/jasmine/index.d.ts"
]
}

View File

@ -1,34 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"],
"@angular/core/testing": ["../../../dist/packages/core/testing"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/common/testing": ["../../../dist/packages/common/testing"],
"@angular/compiler": ["../../../dist/packages/compiler"],
"@angular/compiler/testing": ["../../../dist/packages/compiler/testing"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"],
"@angular/platform-browser/testing": ["../../../dist/packages/platform-browser/testing"],
"@angular/platform-browser-dynamic": ["../../../dist/packages/platform-browser-dynamic"]
},
"outDir": "../../../dist/packages/platform-browser-dynamic"
},
"files": [
"public_api.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/platform-browser-dynamic/testing"
}
}

View File

@ -1,33 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/core/testing": ["../../dist/packages/core/testing"],
"@angular/common": ["../../dist/packages/common"],
"@angular/common/testing": ["../../dist/packages/common/testing"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/compiler/testing": ["../../dist/packages/compiler/testing"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"],
"@angular/platform-browser/testing": ["../../dist/packages/platform-browser/testing"]
},
"outDir": "../../dist/packages/platform-browser-dynamic"
},
"files": [
"public_api.ts",
"../../node_modules/@types/jasmine/index.d.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "platform-browser-dynamic.js",
"flatModuleId": "@angular/platform-browser-dynamic"
}
}

View File

@ -1,32 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"rxjs/*": ["../../../node_modules/rxjs/*"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/core": ["../../../dist/packages/core"],
"@angular/core/testing": ["../../../dist/packages/core/testing"],
"@angular/animations": ["../../../dist/packages/animations"],
"@angular/animations/browser": ["../../../dist/packages/animations/browser"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"]
},
"outDir": "../../../dist/packages/platform-browser"
},
"files": [
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts",
"../../system.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "animations.js",
"flatModuleId": "@angular/platform-browser/animations"
}
}

View File

@ -1,31 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"],
"@angular/core/testing": ["../../../dist/packages/core/testing"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/common/testing": ["../../../dist/packages/common/testing"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"]
},
"outDir": "../../../dist/packages/platform-browser"
},
"files": [
"public_api.ts",
"../../../node_modules/@types/hammerjs/index.d.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/platform-browser/testing"
}
}

View File

@ -1,29 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/platform-browser/animations": ["../../dist/packages/platform-browser/animations"],
"@angular/common": ["../../dist/packages/common"]
},
"outDir": "../../dist/packages/platform-browser"
},
"files": [
"public_api.ts",
"../../node_modules/@types/hammerjs/index.d.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts",
"../goog.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "platform-browser.js",
"flatModuleId": "@angular/platform-browser"
}
}

View File

@ -1,42 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/animations": ["../../../dist/packages/animations"],
"@angular/animations/browser": ["../../../dist/packages/animations/browser"],
"@angular/core": ["../../../dist/packages/core"],
"@angular/core/testing": ["../../../dist/packages/core/testing"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/common/http": ["../../../dist/packages/common/http"],
"@angular/common/testing": ["../../../dist/packages/common/testing"],
"@angular/compiler": ["../../../dist/packages/compiler"],
"@angular/compiler/testing": ["../../../dist/packages/compiler/testing"],
"@angular/http": ["../../../dist/packages/http"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"],
"@angular/platform-browser/animations": ["../../../dist/packages/platform-browser/animations"],
"@angular/platform-browser/testing": ["../../../dist/packages/platform-browser/testing"],
"@angular/platform-browser-dynamic": ["../../../dist/packages/platform-browser-dynamic"],
"@angular/platform-browser-dynamic/testing": ["../../../dist/packages/platform-browser-dynamic/testing"],
"@angular/platform-server": ["../../../dist/packages/platform-server"]
},
"outDir": "../../../dist/packages/platform-server"
},
"files": [
"public_api.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../../node_modules/@types/node/index.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/platform-server/testing"
}
}

View File

@ -1,35 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/animations": ["../../dist/packages/animations"],
"@angular/animations/browser": ["../../dist/packages/animations/browser"],
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/common/http": ["../../dist/packages/common/http"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/http": ["../../dist/packages/http"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"],
"@angular/platform-browser/animations": ["../../dist/packages/platform-browser/animations"],
"@angular/platform-browser-dynamic": ["../../dist/packages/platform-browser-dynamic"]
},
"outDir": "../../dist/packages/platform-server"
},
"files": [
"public_api.ts",
"../../node_modules/@types/node/index.d.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "platform-server.js",
"flatModuleId": "@angular/platform-server"
}
}

View File

@ -1,30 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"],
"@angular/platform-browser-dynamic": ["../../dist/packages/platform-browser-dynamic"],
"@angular/platform-webworker": ["../../dist/packages/platform-webworker"]
},
"outDir": "../../dist/packages/platform-webworker-dynamic"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "platform-webworker-dynamic.js",
"flatModuleId": "@angular/platform-webworker-dynamic"
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"]
},
"outDir": "../../dist/packages/platform-webworker"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "platform-webworker.js",
"flatModuleId": "@angular/platform-webworker"
}
}

View File

@ -1,28 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/common/testing": ["../../../dist/packages/common/testing"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"],
"@angular/router": ["../../../dist/packages/router"]
},
"outDir": "../../../dist/packages/router"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "testing.js",
"flatModuleId": "@angular/router/testing"
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"emitDecoratorMetadata": true,
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"]
},
"outDir": "../../dist/packages/router"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "router.js",
"flatModuleId": "@angular/router"
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/common": ["../../../dist/packages/common"],
"@angular/core": ["../../../dist/packages/core"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"],
"@angular/router": ["../../../dist/packages/router"],
"@angular/upgrade/static": ["../../../dist/packages/upgrade/static"]
},
"outDir": "../../../dist/packages/router"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "upgrade.js",
"flatModuleId": "@angular/router/upgrade"
}
}

View File

@ -1,24 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"]
},
"outDir": "../../../dist/packages/service-worker"
},
"files": [
"public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"flatModuleOutFile": "config.js",
"flatModuleId": "@angular/service-worker/config",
"skipTemplateCodegen": true
}
}

View File

@ -1,26 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"]
},
"outDir": "../../dist/packages/service-worker"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"flatModuleOutFile": "service-worker.js",
"flatModuleId": "@angular/service-worker",
"skipTemplateCodegen": true
}
}

View File

@ -1,27 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@angular/core": ["../../../dist/packages/core"],
"@angular/common": ["../../../dist/packages/common"],
"@angular/platform-browser": ["../../../dist/packages/platform-browser"],
"@angular/platform-browser-dynamic": ["../../../dist/packages/platform-browser-dynamic"]
},
"outDir": "../../../dist/packages/upgrade"
},
"files": [
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "static.js",
"flatModuleId": "@angular/upgrade/static"
}
}

View File

@ -1,29 +0,0 @@
{
"extends": "../tsconfig-build.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@angular/core": ["../../dist/packages/core"],
"@angular/common": ["../../dist/packages/common"],
"@angular/compiler": ["../../dist/packages/compiler"],
"@angular/platform-browser": ["../../dist/packages/platform-browser"],
"@angular/platform-browser-dynamic": ["../../dist/packages/platform-browser-dynamic"]
},
"outDir": "../../dist/packages/upgrade"
},
"files": [
"public_api.ts",
"../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "upgrade.js",
"flatModuleId": "@angular/upgrade"
}
}

View File

@ -23,8 +23,10 @@ readonly bazel_bin=$(yarn bin)/bazel
readonly bin=$(${bazel_bin} info bazel-bin)
function buildTargetPackages() {
# List of targets to build, e.g. core, common, compiler, etc.
targets=$(${bazel_bin} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)')
# List of targets to build, e.g. core, common, compiler, etc. Note that we want to
# remove all carriage return ("\r") characters form the query output because otherwise
# the carriage return is part of the bazel target name and bazel will complain.
targets=$(${bazel_bin} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)' | tr -d "\r")
# Path to the output directory into which we copy the npm packages.
dest_path="$1"

View File

@ -818,8 +818,6 @@ export declare function ɵɵdisableBindings(): void;
export declare function ɵɵelement(index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void;
export declare function ɵɵelementAttribute(index: number, name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string): void;
export declare function ɵɵelementContainerEnd(): void;
export declare function ɵɵelementContainerStart(index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void;
@ -828,8 +826,6 @@ export declare function ɵɵelementEnd(): void;
export declare function ɵɵelementHostAttrs(attrs: TAttributes): void;
export declare function ɵɵelementProperty<T>(index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): void;
export declare function ɵɵelementStart(index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void;
export declare function ɵɵembeddedViewEnd(): void;