Skip to content

Commit 21c1bf9

Browse files
committed
Deprecate Program in v1 AST
1 parent 1cb493b commit 21c1bf9

12 files changed

+148
-91
lines changed

packages/@glimmer/syntax/lib/generation/printer.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ export default class Printer {
113113
case 'PathExpression':
114114
case 'SubExpression':
115115
return this.Expression(node);
116-
case 'Program':
117-
return this.Block(node);
118116
case 'ConcatStatement':
119117
// should have an AttrNode parent
120118
return this.ConcatStatement(node);
@@ -174,15 +172,20 @@ export default class Printer {
174172
case 'ElementNode':
175173
return this.ElementNode(statement);
176174
case 'Block':
177-
case 'Template':
178175
return this.Block(statement);
176+
case 'Template':
177+
return this.Template(statement);
179178
case 'AttrNode':
180179
// should have element
181180
return this.AttrNode(statement);
182181
}
183182
}
184183

185-
Block(block: ASTv1.Block | ASTv1.Program | ASTv1.Template): void {
184+
Template(template: ASTv1.Template): void {
185+
this.TopLevelStatements(template.body);
186+
}
187+
188+
Block(block: ASTv1.Block): void {
186189
/*
187190
When processing a template like:
188191

packages/@glimmer/syntax/lib/parser.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ export abstract class Parser {
150150
}
151151

152152
acceptTemplate(node: HBS.Program): ASTv1.Template {
153-
return this[node.type as 'Program'](node) as ASTv1.Template;
153+
let result = this.Program(node);
154+
assert(result.type === 'Template', 'expected a template');
155+
return result;
154156
}
155157

156158
acceptNode(node: HBS.Program): ASTv1.Block | ASTv1.Template;

packages/@glimmer/syntax/lib/parser/handlebars-node-visitors.ts

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export abstract class HandlebarsNodeVisitors extends Parser {
3535
if (this.isTopLevel) {
3636
node = b.template({
3737
body,
38-
blockParams: program.blockParams,
3938
loc: this.source.spanFor(program.loc),
4039
});
4140
} else {

packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -461,21 +461,21 @@ export function preprocess(
461461
end: offsets.endPosition,
462462
};
463463

464-
let program = new TokenizerEventHandlers(source, entityParser, mode).acceptTemplate(ast);
464+
let template = new TokenizerEventHandlers(source, entityParser, mode).acceptTemplate(ast);
465465

466-
if (options.strictMode) {
467-
program.blockParams = options.locals ?? [];
466+
if (options.strictMode && options.locals?.length) {
467+
template = b.template({ ...template, locals: options.locals });
468468
}
469469

470-
if (options && options.plugins && options.plugins.ast) {
470+
if (options.plugins && options.plugins.ast) {
471471
for (const transform of options.plugins.ast) {
472472
let env: ASTPluginEnvironment = assign({}, options, { syntax }, { plugins: undefined });
473473

474474
let pluginResult = transform(env);
475475

476-
traverse(program, pluginResult.visitor);
476+
traverse(template, pluginResult.visitor);
477477
}
478478
}
479479

480-
return program;
480+
return template;
481481
}

packages/@glimmer/syntax/lib/traversal/traverse.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ function getNodeHandler<N extends ASTv1.Node>(
6767
visitor: NodeVisitor,
6868
nodeType: N['type']
6969
): NodeTraversal<ASTv1.Node> | undefined {
70-
if (nodeType === 'Template' || nodeType === 'Block') {
71-
if (visitor.Program) {
70+
if (visitor.Program) {
71+
if (
72+
(nodeType === 'Template' && !visitor.Template) ||
73+
(nodeType === 'Block' && !visitor.Block)
74+
) {
7275
deprecate(
7376
`The 'Program' visitor node is deprecated. Use 'Template' or 'Block' instead (node was '${nodeType}') `
7477
);

packages/@glimmer/syntax/lib/traversal/visitor.ts

+10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export type NodeTraversal<N extends ASTv1.Node> = FullNodeTraversal<N> | NodeHan
1313

1414
export type NodeVisitor = { [P in keyof ASTv1.Nodes]?: NodeTraversal<ASTv1.Nodes[P]> } & {
1515
All?: NodeTraversal<ASTv1.Node>;
16+
17+
/**
18+
* @deprecated use Template or Block instead
19+
*/
20+
Program?: NodeTraversal<ASTv1.Template | ASTv1.Block>;
1621
};
1722

1823
export interface FullKeyTraversal<N extends ASTv1.Node, K extends string> {
@@ -27,4 +32,9 @@ export type KeyTraversal<N extends ASTv1.Node, K extends VisitorKey<N>> =
2732

2833
export type KeysVisitor<N extends ASTv1.Node> = { [P in VisitorKey<N>]?: KeyTraversal<N, P> } & {
2934
All?: KeyTraversal<N, VisitorKey<N>>;
35+
36+
/**
37+
* @deprecated use Template or Block instead
38+
*/
39+
Program?: KeyTraversal<ASTv1.Template | ASTv1.Block, 'body'>;
3040
};

packages/@glimmer/syntax/lib/traversal/walker.ts

+7-26
Original file line numberDiff line numberDiff line change
@@ -33,40 +33,21 @@ export default class Walker {
3333
switch (node.type) {
3434
case 'Block':
3535
case 'Template':
36-
return visitors.Program(this, node as unknown as ASTv1.Program, callback);
36+
walkBody(this, node.body, callback);
37+
return;
3738
case 'ElementNode':
38-
return visitors.ElementNode(this, node, callback);
39+
walkBody(this, node.children, callback);
40+
return;
3941
case 'BlockStatement':
40-
return visitors.BlockStatement(this, node, callback);
42+
this.visit(node.program, callback);
43+
this.visit(node.inverse || null, callback);
44+
return;
4145
default:
4246
return;
4347
}
4448
}
4549
}
4650

47-
const visitors = {
48-
Program(walker: Walker, node: ASTv1.Program, callback: NodeCallback<ASTv1.Statement>) {
49-
walkBody(walker, node.body, callback);
50-
},
51-
52-
Template(walker: Walker, node: ASTv1.Template, callback: NodeCallback<ASTv1.Node>) {
53-
walkBody(walker, node.body, callback);
54-
},
55-
56-
Block(walker: Walker, node: ASTv1.Block, callback: NodeCallback<ASTv1.Node>) {
57-
walkBody(walker, node.body, callback);
58-
},
59-
60-
ElementNode(walker: Walker, node: ASTv1.ElementNode, callback: NodeCallback<ASTv1.Node>) {
61-
walkBody(walker, node.children, callback);
62-
},
63-
64-
BlockStatement(walker: Walker, node: ASTv1.BlockStatement, callback: NodeCallback<ASTv1.Block>) {
65-
walker.visit(node.program, callback);
66-
walker.visit(node.inverse || null, callback);
67-
},
68-
} as const;
69-
7051
function walkBody(
7152
walker: Walker,
7253
body: ASTv1.Statement[],

packages/@glimmer/syntax/lib/v1/nodes-v1.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,31 @@ export interface BaseNode {
1212

1313
export interface CommonProgram extends BaseNode {
1414
body: Statement[];
15-
blockParams: string[];
16-
chained?: boolean;
17-
}
18-
19-
export interface Program extends CommonProgram {
20-
type: 'Program';
2115
}
2216

2317
export interface Block extends CommonProgram {
2418
type: 'Block';
19+
blockParams: string[];
2520
blockParamNodes: BlockParam[];
21+
chained?: boolean;
2622
}
2723

2824
export type EntityEncodingState = 'transformed' | 'raw';
2925

3026
export interface Template extends CommonProgram {
3127
type: 'Template';
28+
readonly locals: readonly string[];
29+
30+
/**
31+
* @deprecated use locals instead
32+
*/
33+
readonly blockParams: readonly string[];
3234
}
3335

34-
export type PossiblyDeprecatedBlock = Block | Template;
36+
/**
37+
* @deprecated use Template or Block instead
38+
*/
39+
export type Program = Template | Block;
3540

3641
export interface CallParts {
3742
path: Expression;
@@ -320,7 +325,6 @@ export type Nodes = SharedNodes & {
320325
ElementStartNode: ElementStartNode;
321326
ElementPartNode: ElementPartNode;
322327
ElementNameNode: ElementNameNode;
323-
Program: Program;
324328
Template: Template;
325329
Block: Block;
326330
BlockStatement: BlockStatement;

packages/@glimmer/syntax/lib/v1/parser-builders.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Dict, Nullable, PresentArray } from '@glimmer/interfaces';
2-
import { assert } from '@glimmer/util';
2+
import { assert, deprecate } from '@glimmer/util';
33

44
import type { ParserNodeBuilder } from '../parser';
55
import type { SourceLocation } from '../source/location';
@@ -52,19 +52,35 @@ class Builders {
5252

5353
template({
5454
body,
55-
blockParams,
55+
locals = [],
5656
loc,
5757
}: {
5858
body?: ASTv1.Statement[];
59-
blockParams?: string[];
59+
locals?: string[];
6060
loc: SourceSpan;
6161
}): ASTv1.Template {
62-
return {
62+
const _locals = Object.freeze([...locals]);
63+
64+
const node = {
6365
type: 'Template',
66+
get locals() {
67+
return _locals;
68+
},
6469
body: body || [],
65-
blockParams: blockParams || [],
6670
loc,
6771
};
72+
73+
Object.defineProperty(node, 'blockParams', {
74+
enumerable: false,
75+
get() {
76+
deprecate(
77+
`Template nodes can never have block params, for in-scope variables, use locals instead`
78+
);
79+
return _locals;
80+
},
81+
});
82+
83+
return node as ASTv1.Template;
6884
}
6985

7086
mustache({

packages/@glimmer/syntax/lib/v1/public-builders.ts

+31-12
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ function buildMustache(
5050
};
5151
}
5252

53+
type PossiblyDeprecatedBlock = ASTv1.Block | ASTv1.Template;
54+
5355
function buildBlock(
5456
path: BuilderHead,
5557
params: Nullable<ASTv1.Expression[]>,
5658
hash: Nullable<ASTv1.Hash>,
57-
_defaultBlock: ASTv1.PossiblyDeprecatedBlock,
58-
_elseBlock?: Nullable<ASTv1.PossiblyDeprecatedBlock>,
59+
_defaultBlock: PossiblyDeprecatedBlock,
60+
_elseBlock?: Nullable<PossiblyDeprecatedBlock>,
5961
loc?: SourceLocation,
6062
openStrip?: ASTv1.StripFlags,
6163
inverseStrip?: ASTv1.StripFlags,
@@ -454,13 +456,14 @@ function buildProgram(
454456
body?: ASTv1.Statement[],
455457
blockParams?: string[],
456458
loc?: SourceLocation
457-
): ASTv1.Template {
458-
return {
459-
type: 'Template',
460-
body: body || [],
461-
blockParams: blockParams || [],
462-
loc: buildLoc(loc || null),
463-
};
459+
): ASTv1.Template | ASTv1.Block {
460+
deprecate(`b.program is deprecated. Use b.template or b.blockItself instead.`);
461+
462+
if (blockParams && blockParams.length) {
463+
return buildBlockItself(body, blockParams, false, loc);
464+
} else {
465+
return buildTemplate(body, [], loc);
466+
}
464467
}
465468

466469
function buildBlockItself(
@@ -482,15 +485,31 @@ function buildBlockItself(
482485

483486
function buildTemplate(
484487
body?: ASTv1.Statement[],
485-
blockParams?: string[],
488+
locals: string[] = [],
486489
loc?: SourceLocation
487490
): ASTv1.Template {
488-
return {
491+
const _locals = Object.freeze([...locals]);
492+
493+
const node = {
489494
type: 'Template',
495+
get locals() {
496+
return _locals;
497+
},
490498
body: body || [],
491-
blockParams: blockParams || [],
492499
loc: buildLoc(loc || null),
493500
};
501+
502+
Object.defineProperty(node, 'blockParams', {
503+
enumerable: false,
504+
get() {
505+
deprecate(
506+
`Template nodes can never have block params, for in-scope variables, use locals instead`
507+
);
508+
return _locals;
509+
},
510+
});
511+
512+
return node as ASTv1.Template;
494513
}
495514

496515
function buildPosition(line: number, column: number): SourcePosition {

packages/@glimmer/syntax/lib/v1/visitor-keys.ts

-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type * as ASTv1 from './api';
33
// ensure stays in sync with typing
44
// ParentNode and ChildKey types are derived from VisitorKeysMap
55
const visitorKeys = {
6-
Program: ['body'],
76
Template: ['body'],
87
Block: ['body'],
98

@@ -35,11 +34,6 @@ const visitorKeys = {
3534
Hash: ['pairs'],
3635
HashPair: ['value'],
3736
BlockParam: [],
38-
39-
// v2 new nodes
40-
NamedBlock: ['attributes', 'modifiers', 'children', 'comments'],
41-
SimpleElement: ['attributes', 'modifiers', 'children', 'comments'],
42-
Component: ['head', 'attributes', 'modifiers', 'children', 'comments'],
4337
} as const;
4438

4539
type VisitorKeysMap = typeof visitorKeys;

0 commit comments

Comments
 (0)