-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathindex.ts
137 lines (116 loc) · 3.16 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { traverse, Walker, print as glimmerPrint } from '@glimmer/syntax';
import type { ASTv1 as AST, NodeVisitor } from '@glimmer/syntax';
import ParseResult, { NodeInfo } from './parse-result';
import { builders } from './custom-nodes';
const NODE_INFO = new WeakMap<AST.Node, NodeInfo>();
export function parse(template: string): AST.Template {
return new ParseResult(template, NODE_INFO).ast;
}
export function print(ast: AST.Node): string {
return glimmerPrint(ast, {
entityEncoding: 'raw',
override: (ast) => {
let info = NODE_INFO.get(ast);
if (info) {
return info.parse_result.print(ast);
}
},
});
}
export interface Syntax {
parse: typeof parse;
builders: typeof builders;
print: typeof print;
traverse: typeof traverse;
Walker: typeof Walker;
}
export interface TransformPluginEnv {
syntax: Syntax;
contents: string;
filePath?: string;
parseOptions: {
srcName?: string;
};
}
export interface TransformPluginBuilder {
(env: TransformPluginEnv): NodeVisitor;
}
export interface ASTPlugin {
name: string;
visitor: NodeVisitor;
}
export interface TransformResult {
ast: AST.Template;
code: string;
}
export interface TransformOptions {
/**
The template to transform (either as a string or a pre-parsed AST.Template).
*/
template: string | AST.Template;
/**
The plugin to use for transformation.
*/
plugin: TransformPluginBuilder;
/**
The path (relative to the current working directory) to the file being transformed.
This is useful when a given transform need to have differing behavior based on the
location of the file (e.g. a component template should be modified differently than
a route template).
*/
filePath?: string;
}
export function transform(
template: string | AST.Template,
plugin: TransformPluginBuilder
): TransformResult;
export function transform(options: TransformOptions): TransformResult;
export function transform(
templateOrOptions: string | AST.Template | TransformOptions,
plugin?: TransformPluginBuilder
): TransformResult {
let ast: AST.Template;
let contents: string;
let filePath: undefined | string;
let template: string | AST.Template;
if (plugin === undefined) {
let options = templateOrOptions as TransformOptions;
// TransformOptions invocation style
template = options.template;
plugin = options.plugin;
filePath = options.filePath;
} else {
template = templateOrOptions as AST.Template;
filePath = undefined;
}
if (typeof template === 'string') {
ast = parse(template);
contents = template;
} else {
// assume we were passed an ast
ast = template;
contents = print(ast);
}
const syntax = {
parse,
builders,
print,
traverse,
Walker,
};
const env: TransformPluginEnv = {
contents,
filePath,
syntax,
parseOptions: {
srcName: filePath,
},
};
const visitor = plugin(env);
traverse(ast, visitor);
return { ast, code: print(ast) };
}
export type { AST, NodeVisitor } from '@glimmer/syntax';
export { traverse } from '@glimmer/syntax';
export { builders } from './custom-nodes';
export { sourceForLoc } from './utils';