Skip to content

Commit

Permalink
feat(peer-deps): support Angular 9.1 (#187)
Browse files Browse the repository at this point in the history
BREAKING CHANGES:
require `@angular/compiler@^9.1.0`
  • Loading branch information
ikatyang authored Apr 2, 2020
1 parent d7e7d5c commit f919800
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 105 deletions.
16 changes: 0 additions & 16 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,6 @@ script:
- yarn run lint
- yarn run test

- yarn upgrade @angular/compiler@8.2.0
- node -e "assert.equal(require('@angular/compiler').VERSION.full, '8.2.0')"
- yarn run test

- yarn upgrade @angular/compiler@8.0.0
- node -e "assert.equal(require('@angular/compiler').VERSION.full, '8.0.0')"
- yarn run test

- yarn upgrade @angular/compiler@7
- node -e "assert.equal(require('@angular/compiler').VERSION.major, '7')"
- yarn run test

- yarn upgrade @angular/compiler@6
- node -e "assert.equal(require('@angular/compiler').VERSION.major, '6')"
- yarn run test

after_script:
- codecov

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"tslib": "^1.9.3"
},
"devDependencies": {
"@angular/compiler": "9.0.0",
"@angular/compiler": "9.1.0",
"@babel/code-frame": "7.8.3",
"@babel/parser": "7.6.4",
"@babel/types": "7.1.5",
Expand All @@ -46,7 +46,7 @@
"typescript": "3.7.5"
},
"peerDependencies": {
"@angular/compiler": ">= 6.0.0 < 9.0.6"
"@angular/compiler": "^9.1.0"
},
"engines": {
"node": ">= 6"
Expand Down
171 changes: 99 additions & 72 deletions src/transform-microsyntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ import {
NGNode,
RawNGSpan,
} from './types';
import { findBackChar, toLowerCamelCase } from './utils';
import { toLowerCamelCase } from './utils';

export function transformTemplateBindings(
rawTemplateBindings: ng.TemplateBinding[],
context: Context,
): NGMicrosyntax {
rawTemplateBindings.forEach(fixTemplateBindingSpan);

const [firstTemplateBinding] = rawTemplateBindings;
const { key: prefix } = firstTemplateBinding;
const templateBindings =
context.text
.slice(firstTemplateBinding.span.start, firstTemplateBinding.span.end)
.slice(
firstTemplateBinding.sourceSpan.start,
firstTemplateBinding.sourceSpan.end,
)
.trim().length === 0
? rawTemplateBindings.slice(1)
: rawTemplateBindings;
Expand All @@ -32,20 +37,18 @@ export function transformTemplateBindings(
let lastTemplateBinding: ng.TemplateBinding | null = null;
for (let i = 0; i < templateBindings.length; i++) {
const templateBinding = templateBindings[i];
const { key, keyIsVar, name, span } = templateBinding;

if (
lastTemplateBinding &&
lastTemplateBinding.key === name &&
keyIsVar &&
/^as\s$/.test(context.text.slice(span.start, span.start + 3))
isExpressionBinding(lastTemplateBinding) &&
isVariableBinding(templateBinding) &&
templateBinding.value &&
templateBinding.value.source === lastTemplateBinding.key.source
) {
const keyStart = findBackChar(/\S/, span.start + 3, context.text);
const keySpan = findBackKeySpan(keyStart, key);
const alias = _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: key },
keySpan,
{ name: templateBinding.key.source },
templateBinding.key.span,
);
const updateSpanEnd = <T extends NGNode>(node: T, end: number): T => ({
// @ts-ignore
Expand Down Expand Up @@ -78,91 +81,89 @@ export function transformTemplateBindings(
'NGMicrosyntax',
{ body },
body.length === 0
? rawTemplateBindings[0].span
? rawTemplateBindings[0].sourceSpan
: { start: body[0].start, end: body[body.length - 1].end },
);

function transformTemplateBinding(
{ key, keyIsVar, name, expression, span }: ng.TemplateBinding,
templateBinding: ng.TemplateBinding,
index: number,
): Exclude<NGMicrosyntaxNode, NGMicrosyntax> {
if (!keyIsVar) {
if (!expression) {
if (isExpressionBinding(templateBinding)) {
const { key, value } = templateBinding;
if (!value) {
return _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: removePrefix(key) },
span,
{ name: removePrefix(key.source) },
key.span,
);
} else if (index === 0) {
return _c<NGMicrosyntaxExpression>(
'NGMicrosyntaxExpression',
{ expression: _t<NGNode>(expression.ast), alias: null },
span,
{ expression: _t<NGNode>(value.ast), alias: null },
value.sourceSpan,
);
} else {
const ngExpression = _t<NGNode>(expression.ast);
const { start, end } = ngExpression;
const keyName = removePrefix(key);
return _c<NGMicrosyntaxKeyedExpression>(
'NGMicrosyntaxKeyedExpression',
{
key: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: keyName },
findBackKeySpan(span.start, keyName),
{ name: removePrefix(key.source) },
key.span,
),
expression: _c<NGMicrosyntaxExpression>(
'NGMicrosyntaxExpression',
{ expression: ngExpression, alias: null },
{ start, end },
{ expression: _t<NGNode>(value.ast), alias: null },
value.sourceSpan,
),
},
span,
{ start: key.span.start, end: value.sourceSpan.end },
);
}
} else {
if (/^let\s$/.test(context.text.slice(span.start, span.start + 4))) {
const keyStart = findBackChar(/\S/, span.start + 4, context.text);
const keySpan = findBackKeySpan(keyStart, key);
const { key, value, sourceSpan } = templateBinding;
const startsWithLet = /^let\s$/.test(
context.text.slice(sourceSpan.start, sourceSpan.start + 4),
);
if (startsWithLet) {
return _c<NGMicrosyntaxLet>(
'NGMicrosyntaxLet',
{
key: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: key },
keySpan,
{ name: key.source },
key.span,
),
value:
context.text.slice(keySpan.end, span.end).trim().length === 0
? null
: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name },
{
start: findBackChar(/=/, keySpan.end, context.text) + 1,
end: span.end,
},
),
value: !value
? null
: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: value.source },
value.span,
),
},
{
start: sourceSpan.start,
end: value ? value.span.end : key.span.end,
},
span,
);
} else {
const keySpan = findBackKeySpan(span.start, name);
return _c<NGMicrosyntaxAs>(
'NGMicrosyntaxAs',
{
key: _c<NGMicrosyntaxKey>('NGMicrosyntaxKey', { name }, keySpan),
key: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: value!.source },
value!.span,
),
alias: _c<NGMicrosyntaxKey>(
'NGMicrosyntaxKey',
{ name: key },
{
start:
findBackChar(/\S/, keySpan.end, context.text) + 'as'.length,
end: span.end,
},
{ name: key.source },
key.span,
),
},
span,
{ start: value!.span.start, end: key.span.end },
);
}
}
Expand All @@ -186,28 +187,54 @@ export function transformTemplateBindings(
} as T & RawNGSpan;
}

function findBackKeySpan(start: number, key: string): RawNGSpan {
if (context.text[start] !== "'" && context.text[start] !== '"') {
return { start, end: start + key.length };
}
const quote = context.text[start];
let backslash = 0;
let index = start + 1;
while (true) {
const char = context.text[index];
if (char === quote && backslash % 2 === 0) {
return { start, end: index + 1 };
}
if (char === '\\') {
backslash++;
} else {
backslash = 0;
}
index++;
function removePrefix(string: string) {
return toLowerCamelCase(string.slice(prefix.source.length));
}

function isExpressionBinding(
templateBinding: ng.TemplateBinding,
): templateBinding is ng.ExpressionBinding {
return templateBinding instanceof ng.ExpressionBinding;
}

function isVariableBinding(
templateBinding: ng.TemplateBinding,
): templateBinding is ng.VariableBinding {
return templateBinding instanceof ng.VariableBinding;
}

function fixTemplateBindingSpan(templateBinding: ng.TemplateBinding) {
fixSpan(templateBinding.key.span);
if (isVariableBinding(templateBinding) && templateBinding.value) {
fixSpan(templateBinding.value.span);
}
}

function removePrefix(string: string) {
return toLowerCamelCase(string.slice(prefix.length));
/**
* - "a" (start=0 end=1) -> (start=0 end=3)
* - '\'' (start=0 end=1) -> (start=0 end=4)
*/
function fixSpan(span: RawNGSpan) {
if (context.text[span.start] !== '"' && context.text[span.start] !== "'") {
return;
}
const quote = context.text[span.start];
let hasBackSlash = false;
for (let i = span.start + 1; i < context.text.length; i++) {
switch (context.text[i]) {
case quote:
if (!hasBackSlash) {
span.end = i + 1;
return;
}
// fall through
default:
hasBackSlash = false;
break;
case '\\':
hasBackSlash = !hasBackSlash;
break;
}
}
}
}
2 changes: 1 addition & 1 deletion src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ export const transform = (
props: { computed: boolean; optional: boolean },
{ end = _getOuterEnd(tName), hasParentParens = false } = {},
) {
if (receiver.span.start === receiver.span.end) {
if (receiver.span.start >= receiver.span.end) {
return tName;
}
const tReceiver =
Expand Down
16 changes: 7 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { VERSION as NG_VERSION } from '@angular/compiler';
import * as ng from '@angular/compiler/src/expression_parser/ast';
import { Lexer } from '@angular/compiler/src/expression_parser/lexer';
import { Parser } from '@angular/compiler/src/expression_parser/parser';
Expand All @@ -7,13 +6,10 @@ import { RawNGComment, RawNGSpan } from './types';
const NG_PARSE_FAKE_LOCATION = 'angular-estree-parser';
const NG_PARSE_TEMPLATE_BINDINGS_FAKE_PREFIX = 'NgEstreeParser';
const NG_PARSE_FAKE_ABSOLUTE_OFFSET = 0;
/* istanbul ignore next */
const NG_PARSE_SHARED_PARAMS: readonly [
string,
number,
] = /^(?:[67]|8\.[01])\./.test(NG_VERSION.full)
? ([NG_PARSE_FAKE_LOCATION] as any)
: ([NG_PARSE_FAKE_LOCATION, NG_PARSE_FAKE_ABSOLUTE_OFFSET] as const);
const NG_PARSE_SHARED_PARAMS: readonly [string, number] = [
NG_PARSE_FAKE_LOCATION,
NG_PARSE_FAKE_ABSOLUTE_OFFSET,
];

function createNgParser() {
return new Parser(new Lexer());
Expand Down Expand Up @@ -53,7 +49,9 @@ export function parseNgTemplateBindings(input: string) {
const { templateBindings: ast, errors } = ngParser.parseTemplateBindings(
NG_PARSE_TEMPLATE_BINDINGS_FAKE_PREFIX,
input,
...NG_PARSE_SHARED_PARAMS,
NG_PARSE_FAKE_LOCATION,
NG_PARSE_FAKE_ABSOLUTE_OFFSET,
NG_PARSE_FAKE_ABSOLUTE_OFFSET,
);
assertAstErrors(errors);
return ast;
Expand Down
9 changes: 4 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# yarn lockfile v1


"@angular/compiler@9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0.tgz#87e0bef4c369b6cadae07e3a4295778fc93799d5"
integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==
"@angular/compiler@9.1.0":
version "9.1.0"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.0.tgz#e55b4f2f24df75283002d5e8e85e1acfc46928f6"
integrity sha512-QHw/JSeTXHiJQ2Ih0EtU7FGsYcOr+0hwZhqwSW3EEn8TtUgA3DS5lXeiDV66f+3DdvNZFPmgiZIvun3ypxn1HA==

"@babel/code-frame@7.8.3", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35":
version "7.8.3"
Expand Down Expand Up @@ -1476,7 +1476,6 @@ fsevents@^1.2.3:
dependencies:
bindings "^1.5.0"
nan "^2.12.1"
node-pre-gyp "*"

function-bind@^1.1.1:
version "1.1.1"
Expand Down

0 comments on commit f919800

Please sign in to comment.