Skip to content

Commit d051884

Browse files
authored
[BUGFIX] Ensure legacy path.parts matches existing semantics (#1583)
The refactor in #1568 slightly changed the semantics of `path.parts` in that it didn't previously include `this` or the leading `@`. This commit restores the previous semantics.
1 parent 4f73b20 commit d051884

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

packages/@glimmer/syntax/lib/v1/legacy-interop.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,35 @@ export function buildLegacyPath({ head, tail, loc }: PathExpressionParams): ASTv
6161
Object.defineProperty(node, 'parts', {
6262
enumerable: false,
6363
get(this: { original: string }): readonly string[] {
64-
deprecate(`The parts property on path nodes is deprecated, use trusting instead`);
65-
return Object.freeze(this.original.split('.'));
64+
deprecate(`The parts property on path nodes is deprecated, use head and tail instead`);
65+
let parts = asPresentArray(this.original.split('.'));
66+
67+
if (parts[0] === 'this') {
68+
// parts does not include `this`
69+
parts.shift();
70+
} else if (parts[0].startsWith('@')) {
71+
// parts does not include leading `@`
72+
parts[0] = parts[0].slice(1);
73+
}
74+
75+
return Object.freeze(parts);
6676
},
67-
set(this: { original: string }, value: PresentArray<string>) {
68-
deprecate(`The parts property on mustache nodes is deprecated, use trusting instead`);
69-
this.original = value.join('.');
77+
set(this: { head: ASTv1.PathHead; original: string }, values: PresentArray<string>) {
78+
deprecate(`The parts property on mustache nodes is deprecated, use head and tail instead`);
79+
80+
let parts = [...values];
81+
82+
// you are not supposed to already have `this` or `@` in the parts, but since this is
83+
// deprecated anyway, we will infer what you meant and allow it
84+
if (parts[0] !== 'this' && !parts[0]?.startsWith('@')) {
85+
if (this.head.type === 'ThisHead') {
86+
parts.unshift('this');
87+
} else if (this.head.type === 'AtHead') {
88+
parts[0] = `@${parts[0]}`;
89+
}
90+
}
91+
92+
this.original = parts.join('.');
7093
},
7194
});
7295

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { builders as b } from '@glimmer/syntax';
2+
3+
QUnit.module('[glimmer-syntax] AST nodes legacy interop');
4+
5+
QUnit.test('path.parts does not include this', (assert) => {
6+
let path = b.path('this.foo.bar');
7+
8+
assert.deepEqual(path.original, 'this.foo.bar', 'path.original should include this');
9+
assert.deepEqual(path.head.type, 'ThisHead', 'path.head should be a ThisHead');
10+
assert.deepEqual(path.parts, ['foo', 'bar'], 'path.parts should not include this');
11+
12+
path.parts = ['bar', 'baz'];
13+
14+
assert.deepEqual(path.original, 'this.bar.baz', 'path.original should include this');
15+
assert.deepEqual(path.head.type, 'ThisHead', 'path.head should be a ThisHead');
16+
assert.deepEqual(path.parts, ['bar', 'baz'], 'path.parts should not include this');
17+
18+
path.head = b.head('@foo');
19+
assert.deepEqual(path.head.type, 'AtHead', 'path.head should be a AtHead');
20+
21+
// Inconsistent, but we will allow it
22+
path.parts = ['this', 'foo', 'bar', 'baz'];
23+
24+
assert.deepEqual(path.original, 'this.foo.bar.baz', 'path.original should include this');
25+
assert.deepEqual(path.head.type, 'ThisHead', 'path.head should be a ThisHead');
26+
assert.deepEqual(path.parts, ['foo', 'bar', 'baz'], 'path.parts should not include this');
27+
});
28+
29+
QUnit.test('path.parts does not include @', (assert) => {
30+
let path = b.path('@foo.bar');
31+
32+
assert.deepEqual(path.original, '@foo.bar', 'path.original should include @');
33+
assert.deepEqual(path.head.type, 'AtHead', 'path.head should be a AtHead');
34+
assert.deepEqual(path.parts, ['foo', 'bar'], 'path.parts should not include @');
35+
36+
path.parts = ['bar', 'baz'];
37+
38+
assert.deepEqual(path.original, '@bar.baz', 'path.original should include @');
39+
assert.deepEqual(path.head.type, 'AtHead', 'path.head should be a AtHead');
40+
assert.deepEqual(path.parts, ['bar', 'baz'], 'path.parts should not include @');
41+
42+
path.head = b.head('this');
43+
assert.deepEqual(path.head.type, 'ThisHead', 'path.head should be a ThisHead');
44+
45+
// Inconsistent, but we will allow it
46+
path.parts = ['@foo', 'bar', 'baz'];
47+
48+
assert.deepEqual(path.original, '@foo.bar.baz', 'path.original should include @');
49+
assert.deepEqual(path.head.type, 'AtHead', 'path.head should be a AtHead');
50+
assert.deepEqual(path.parts, ['foo', 'bar', 'baz'], 'path.parts should not include this');
51+
});

0 commit comments

Comments
 (0)