Skip to content

Commit a35e891

Browse files
Merge pull request #363 from ijlee2/refactor-code
Refactored code
2 parents 7b5bc87 + 68083ae commit a35e891

File tree

5 files changed

+94
-83
lines changed

5 files changed

+94
-83
lines changed

src/parse/index.ts

Lines changed: 38 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,15 @@ import type {
66
ObjectExpression,
77
StaticBlock,
88
} from '@babel/types';
9-
import { Preprocessor } from 'content-tag';
109
import type { Parser } from 'prettier';
1110
import { parsers as babelParsers } from 'prettier/plugins/babel.js';
1211

1312
import { PRINTER_NAME } from '../config.js';
1413
import type { Options } from '../options.js';
15-
import { assert } from '../utils/index.js';
16-
import {
17-
byteToCharIndex,
18-
preprocessTemplateRange,
19-
type Template,
20-
} from './preprocess.js';
14+
import { assert } from '../utils/assert.js';
15+
import { preprocess, type Template } from './preprocess.js';
2116

2217
const typescript = babelParsers['babel-ts'] as Parser<Node | undefined>;
23-
const p = new Preprocessor();
2418

2519
/** Converts a node into a GlimmerTemplate node */
2620
function convertNode(
@@ -36,104 +30,78 @@ function convertNode(
3630

3731
/** Traverses the AST and replaces the transformed template parts with other AST */
3832
function convertAst(ast: File, templates: Template[]): void {
39-
const unprocessedTemplates = [...templates];
40-
4133
traverse(ast, {
4234
enter(path) {
4335
const { node } = path;
44-
if (
45-
node.type === 'BlockStatement' ||
46-
node.type === 'ObjectExpression' ||
47-
node.type === 'StaticBlock'
48-
) {
49-
const { range } = node;
50-
assert('expected range', range);
51-
const [start, end] = range;
52-
53-
const templateIndex = unprocessedTemplates.findIndex(
54-
(t) =>
55-
(t.utf16Range.start === start && t.utf16Range.end === end) ||
56-
(node.type === 'ObjectExpression' &&
57-
t.utf16Range.start === start - 1 &&
58-
t.utf16Range.end === end + 1),
59-
);
60-
if (templateIndex > -1) {
61-
const rawTemplate = unprocessedTemplates.splice(templateIndex, 1)[0];
36+
37+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
38+
switch (node.type) {
39+
case 'BlockStatement':
40+
case 'ObjectExpression':
41+
case 'StaticBlock': {
42+
assert('expected range', node.range);
43+
const [start, end] = node.range;
44+
45+
const templateIndex = templates.findIndex((template) => {
46+
const { utf16Range } = template;
47+
48+
if (utf16Range.start === start && utf16Range.end === end) {
49+
return true;
50+
}
51+
52+
return (
53+
node.type === 'ObjectExpression' &&
54+
utf16Range.start === start - 1 &&
55+
utf16Range.end === end + 1
56+
);
57+
});
58+
59+
if (templateIndex === -1) {
60+
return null;
61+
}
62+
63+
const rawTemplate = templates.splice(templateIndex, 1)[0];
64+
6265
if (!rawTemplate) {
6366
throw new Error(
6467
'expected raw template because splice index came from findIndex',
6568
);
6669
}
70+
6771
const index =
6872
node.innerComments?.[0] &&
6973
ast.comments?.indexOf(node.innerComments[0]);
74+
7075
if (ast.comments && index !== undefined && index >= 0) {
7176
ast.comments.splice(index, 1);
7277
}
78+
7379
convertNode(node, rawTemplate);
74-
} else {
75-
return null;
7680
}
7781
}
7882

7983
return null;
8084
},
8185
});
8286

83-
if (unprocessedTemplates.length > 0) {
87+
if (templates.length > 0) {
8488
throw new Error(
85-
`failed to process all templates, ${unprocessedTemplates.length} remaining`,
89+
`failed to process all templates, ${templates.length} remaining`,
8690
);
8791
}
8892
}
8993

90-
/**
91-
* Pre-processes the template info, parsing the template content to Glimmer AST,
92-
* fixing the offsets and locations of all nodes also calculates the block
93-
* params locations & ranges and adding it to the info
94-
*/
95-
export function preprocess(
96-
code: string,
97-
fileName: string,
98-
): {
99-
code: string;
100-
templates: Template[];
101-
} {
102-
const templates = codeToGlimmerAst(code, fileName);
103-
104-
for (const template of templates) {
105-
code = preprocessTemplateRange(template, code);
106-
}
107-
108-
return { templates, code };
109-
}
110-
11194
export const parser: Parser<Node | undefined> = {
11295
...typescript,
11396
astFormat: PRINTER_NAME,
11497

11598
async parse(code: string, options: Options): Promise<Node> {
11699
const preprocessed = preprocess(code, options.filepath);
100+
117101
const ast = await typescript.parse(preprocessed.code, options);
118102
assert('expected ast', ast);
119103
convertAst(ast as File, preprocessed.templates);
104+
120105
return ast;
121106
},
122107
};
123-
124-
/** Pre-processes the template info, parsing the template content to Glimmer AST. */
125-
export function codeToGlimmerAst(code: string, filename: string): Template[] {
126-
const rawTemplates = p.parse(code, { filename });
127-
const templates: Template[] = rawTemplates.map((r) => ({
128-
type: r.type,
129-
range: r.range,
130-
contentRange: r.contentRange,
131-
contents: r.contents,
132-
utf16Range: {
133-
start: byteToCharIndex(code, r.range.start),
134-
end: byteToCharIndex(code, r.range.end),
135-
},
136-
}));
137-
138-
return templates;
139-
}

src/parse/preprocess.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Preprocessor } from 'content-tag';
2+
13
export interface Template {
24
contents: string;
35
type: string;
@@ -13,7 +15,7 @@ export interface Template {
1315

1416
const BufferMap: Map<string, Buffer> = new Map();
1517

16-
export const PLACEHOLDER = '~';
18+
const PLACEHOLDER = '~';
1719

1820
function getBuffer(s: string): Buffer {
1921
let buf = BufferMap.get(s);
@@ -25,19 +27,19 @@ function getBuffer(s: string): Buffer {
2527
}
2628

2729
/** Slice string using byte range */
28-
export function sliceByteRange(s: string, a: number, b?: number): string {
30+
function sliceByteRange(s: string, a: number, b?: number): string {
2931
const buf = getBuffer(s);
3032
return buf.subarray(a, b).toString();
3133
}
3234

3335
/** Converts byte index to js char index (utf16) */
34-
export function byteToCharIndex(s: string, byteOffset: number): number {
36+
function byteToCharIndex(s: string, byteOffset: number): number {
3537
const buf = getBuffer(s);
3638
return buf.subarray(0, byteOffset).toString().length;
3739
}
3840

3941
/** Calculate byte length */
40-
export function byteLength(s: string): number {
42+
function byteLength(s: string): number {
4143
return getBuffer(s).length;
4244
}
4345

@@ -71,6 +73,7 @@ export function preprocessTemplateRange(
7173
suffix = '*/}';
7274

7375
const nextToken = code.slice(template.range.end).toString().match(/\S+/);
76+
7477
if (nextToken && (nextToken[0] === 'as' || nextToken[0] === 'satisfies')) {
7578
// Replace with parenthesized ObjectExpression
7679
prefix = '(' + prefix;
@@ -81,9 +84,52 @@ export function preprocessTemplateRange(
8184
// We need to replace forward slash with _something else_, because
8285
// forward slash breaks the parsed templates.
8386
const content = template.contents.replaceAll('/', PLACEHOLDER);
87+
8488
const tplLength = template.range.end - template.range.start;
8589
const spaces =
8690
tplLength - byteLength(content) - prefix.length - suffix.length;
8791
const total = prefix + content + ' '.repeat(spaces) + suffix;
92+
8893
return replaceRange(code, template.range.start, template.range.end, total);
8994
}
95+
96+
const p = new Preprocessor();
97+
98+
/** Pre-processes the template info, parsing the template content to Glimmer AST. */
99+
export function codeToGlimmerAst(code: string, filename: string): Template[] {
100+
const rawTemplates = p.parse(code, { filename });
101+
102+
const templates: Template[] = rawTemplates.map((r) => ({
103+
type: r.type,
104+
range: r.range,
105+
contentRange: r.contentRange,
106+
contents: r.contents,
107+
utf16Range: {
108+
start: byteToCharIndex(code, r.range.start),
109+
end: byteToCharIndex(code, r.range.end),
110+
},
111+
}));
112+
113+
return templates;
114+
}
115+
116+
/**
117+
* Pre-processes the template info, parsing the template content to Glimmer AST,
118+
* fixing the offsets and locations of all nodes also calculates the block
119+
* params locations & ranges and adding it to the info
120+
*/
121+
export function preprocess(
122+
code: string,
123+
fileName: string,
124+
): {
125+
code: string;
126+
templates: Template[];
127+
} {
128+
const templates = codeToGlimmerAst(code, fileName);
129+
130+
for (const template of templates) {
131+
code = preprocessTemplateRange(template, code);
132+
}
133+
134+
return { templates, code };
135+
}

src/print/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
isGlimmerTemplate,
1414
isGlimmerTemplateParent,
1515
} from '../types/glimmer.js';
16-
import { assert } from '../utils/index.js';
16+
import { assert } from '../utils/assert.js';
1717
import {
1818
fixPreviousPrint,
1919
saveCurrentPrintOnSiblingNode,
File renamed without changes.

tests/unit-tests/preprocess.test.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { describe, expect, test } from 'vitest';
22

3-
import { codeToGlimmerAst } from '../../src/parse/index.js';
43
import {
5-
PLACEHOLDER,
4+
codeToGlimmerAst,
65
preprocessTemplateRange,
76
} from '../../src/parse/preprocess.js';
87

@@ -13,21 +12,19 @@ const TEST_CASES = [
1312
},
1413
{
1514
code: '<template>/* hi */</template>',
16-
expected: [`{/*${PLACEHOLDER}* hi *${PLACEHOLDER} */}`],
15+
expected: [`{/*~* hi *~ */}`],
1716
},
1817
{
1918
code: '<template><div>hi</div></template>',
20-
expected: [`{/*<div>hi<${PLACEHOLDER}div> */}`],
19+
expected: [`{/*<div>hi<~div> */}`],
2120
},
2221
{
2322
code: '<template>{{#if true}}hi{{/if}}</template>',
24-
expected: [`{/*{{#if true}}hi{{${PLACEHOLDER}if}} */}`],
23+
expected: [`{/*{{#if true}}hi{{~if}} */}`],
2524
},
2625
{
2726
code: '<template>////////////////</template>',
28-
expected: [
29-
`{/*${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER}${PLACEHOLDER} */}`,
30-
],
27+
expected: [`{/*~~~~~~~~~~~~~~~~ */}`],
3128
},
3229
{
3330
code: '<template>💩</template>',

0 commit comments

Comments
 (0)