-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathpreprocess.ts
More file actions
99 lines (83 loc) · 2.5 KB
/
preprocess.ts
File metadata and controls
99 lines (83 loc) · 2.5 KB
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
import { parse, type Range, sliceByteRange } from '../utils/content-tag.js';
export interface Template {
contentRange: Range;
contents: string;
range: Range;
type: 'class-member' | 'expression';
utf16Range: {
end: number;
start: number;
};
}
/**
* Replace the template with a parsable placeholder that takes up the same
* range.
*/
export function preprocessTemplateRange(
template: Template,
code: string,
): string {
const { start, end } = template.utf16Range;
const after = code.slice(end);
let prefix: string;
let suffix: string;
if (template.type === 'class-member') {
// Replace with StaticBlock
prefix = 'static{/*';
suffix = '*/}';
} else {
// Replace with BlockStatement or ObjectExpression
prefix = '{/*';
suffix = '*/}';
const nextToken = after.match(/\S+/);
if (nextToken && (nextToken[0] === 'as' || nextToken[0] === 'satisfies')) {
// Replace with parenthesized ObjectExpression
prefix = '(' + prefix;
suffix = suffix + ')';
}
}
const before = code.slice(0, start);
const spaces = code
.slice(start + prefix.length, end - suffix.length)
// Replace everything except `\n` with space, so the line and column remain correct
// Prettier normalized EOL to `\n`, so we don't need worry about `\r` and `\r\n`
.replaceAll(/[^\n]/g, ' ');
return before + prefix + spaces + suffix + after;
}
/** Pre-processes the template info, parsing the template content to Glimmer AST. */
export function codeToGlimmerAst(code: string, filename: string): Template[] {
const contentTags = parse(code, { filename });
const templates: Template[] = contentTags.map((contentTag) => {
const { contentRange, contents, range, type } = contentTag;
const utf16Range = {
end: sliceByteRange(code, 0, range.endByte).length,
start: sliceByteRange(code, 0, range.startByte).length,
};
return {
contentRange,
contents,
range,
type,
utf16Range,
};
});
return templates;
}
/**
* Pre-processes the template info, parsing the template content to Glimmer AST,
* fixing the offsets and locations of all nodes also calculates the block
* params locations & ranges and adding it to the info
*/
export function preprocess(
code: string,
fileName: string,
): {
code: string;
templates: Template[];
} {
const templates = codeToGlimmerAst(code, fileName);
for (const template of templates) {
code = preprocessTemplateRange(template, code);
}
return { code, templates };
}