fix(compiler): inputs/outputs incorrectly parsed in jit mode (#46813)

The `Directive` and `Component` decorators support `inputs` and `outputs` fields which accept an array in the format of `"someInput"` or `"someInput: someAlias"`, however the parsing during JIT compilation was splitting on commas, not on colons, which resulted in incorrect parsing. E.g. `inputs: ["someInput: someAlias"]` was being parsed into `{"someInput: someAlias": "someInput: someAlias"}` instead of `{someInput: "someAlias"}`.

The feature was working by accident, because there's some logic further down in the compiler pipeline that was splitting the strings again.

PR Close #46813
This commit is contained in:
Kristiyan Kostadinov 2022-07-13 20:19:40 +02:00 committed by Jessica Janiuk
parent 7e03fc90d6
commit f67d2cabaf
3 changed files with 20 additions and 16 deletions

View file

@ -637,10 +637,10 @@ function isOutput(value: any): value is Output {
}
function parseInputOutputs(values: string[]): StringMap {
return values.reduce((map, value) => {
const [field, property] = value.split(',').map(piece => piece.trim());
map[field] = property || field;
return map;
return values.reduce((results, value) => {
const [field, property] = value.split(':', 2).map(str => str.trim());
results[field] = property || field;
return results;
}, {} as StringMap);
}

View file

@ -175,7 +175,6 @@ function mapToExpression(
map: {[key: string]: string|string[]}, keepDeclared?: boolean): o.Expression {
return o.literalMap(Object.getOwnPropertyNames(map).map(key => {
// canonical syntax: `dirProp: publicProp`
// if there is no `:`, use dirProp = elProp
const value = map[key];
let declaredName: string;
let publicName: string;
@ -186,12 +185,9 @@ function mapToExpression(
minifiedName = key;
needsDeclaredName = publicName !== declaredName;
} else {
[declaredName, publicName] = splitAtColon(key, [key, value]);
minifiedName = declaredName;
// Only include the declared name if extracted from the key, i.e. the key contains a colon.
// Otherwise the declared name should be omitted even if it is different from the public name,
// as it may have already been minified.
needsDeclaredName = publicName !== declaredName && key.includes(':');
minifiedName = declaredName = key;
publicName = value;
needsDeclaredName = false;
}
return {
key: minifiedName,

View file

@ -20,6 +20,13 @@ const INITIAL_VALUE = {
};
const NOT_SUPPORTED: any = 'NOT_SUPPORTED';
function getInputPropertyMapName(name: string): string {
return `input_${name}`;
}
function getOutputPropertyMapName(name: string): string {
return `output_${name}`;
}
export class UpgradeNg1ComponentAdapterBuilder {
// TODO(issue/24571): remove '!'.
@ -33,7 +40,7 @@ export class UpgradeNg1ComponentAdapterBuilder {
propertyMap: {[name: string]: string} = {};
directive: IDirective|null = null;
// TODO(issue/24571): remove '!'.
template !: string;
template!: string;
constructor(public name: string) {
const selector =
@ -76,9 +83,9 @@ export class UpgradeNg1ComponentAdapterBuilder {
// QUESTION: What about `=*`? Ignore? Throw? Support?
const inputName = `input_${attrName}`;
const inputName = getInputPropertyMapName(attrName);
const inputNameRename = `${inputName}: ${attrName}`;
const outputName = `output_${attrName}`;
const outputName = getOutputPropertyMapName(attrName);
const outputNameRename = `${outputName}: ${attrName}`;
const outputNameRenameChange = `${outputNameRename}Change`;
@ -225,8 +232,9 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
const ng1Changes: any = {};
Object.keys(changes).forEach(name => {
const change: SimpleChange = changes[name];
this.setComponentProperty(name, change.currentValue);
ng1Changes[this.propertyMap[name]] = change;
const propertyMapName = getInputPropertyMapName(name);
this.setComponentProperty(propertyMapName, change.currentValue);
ng1Changes[this.propertyMap[propertyMapName]] = change;
});
if (isFunction(this.destinationObj!.$onChanges)) {