Skip to content

Commit 25d0bbf

Browse files
committed
chore: update esrap
1 parent 5831535 commit 25d0bbf

File tree

7 files changed

+59
-139
lines changed

7 files changed

+59
-139
lines changed

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"dom-serializer": "^2.0.0",
5252
"domhandler": "^5.0.3",
5353
"domutils": "^3.2.2",
54-
"esrap": "^1.4.9",
54+
"esrap": "^2.0.0",
5555
"htmlparser2": "^9.1.0",
5656
"magic-string": "^0.30.17",
5757
"picocolors": "^1.1.1",

packages/core/tests/js/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ for (const categoryDirectory of categoryDirectories) {
1616

1717
const inputFilePath = join(testDirectoryPath, 'input.ts');
1818
const input = fs.existsSync(inputFilePath) ? fs.readFileSync(inputFilePath, 'utf8') : '';
19-
const ast = parseScript(input);
19+
const { ast, comments } = parseScript(input);
2020

2121
// dynamic imports always need to provide the path inline for static analysis
2222
const module = await import(`./${categoryDirectory}/${testName}/run.ts`);
2323
module.run(ast);
2424

25-
let output = serializeScript(ast, input);
25+
let output = serializeScript(ast, comments, input);
2626
if (!output.endsWith('\n')) output += '\n';
2727
await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.ts`);
2828
});

packages/core/tests/utils.ts

Lines changed: 6 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
parseScript,
55
serializeScript,
66
guessIndentString,
7-
guessQuoteStyle,
87
type AstTypes
98
} from '../tooling/index.ts';
109

@@ -48,57 +47,6 @@ test('guessIndentString - eight spaces', () => {
4847
expect(guessIndentString(code)).toBe(' ');
4948
});
5049

51-
test('guessQuoteStyle - single simple', () => {
52-
const code = dedent`
53-
console.log('asd');
54-
`;
55-
const ast = parseScript(code);
56-
57-
expect(guessQuoteStyle(ast)).toBe('single');
58-
});
59-
60-
test('guessQuoteStyle - single complex', () => {
61-
const code = dedent`
62-
import foo from 'bar';
63-
64-
console.log("bar");
65-
const foobar = 'foo';
66-
`;
67-
const ast = parseScript(code);
68-
69-
expect(guessQuoteStyle(ast)).toBe('single');
70-
});
71-
72-
test('guessQuoteStyle - double simple', () => {
73-
const code = dedent`
74-
console.log("asd");
75-
`;
76-
const ast = parseScript(code);
77-
78-
expect(guessQuoteStyle(ast)).toBe('double');
79-
});
80-
81-
test('guessQuoteStyle - double complex', () => {
82-
const code = dedent`
83-
import foo from 'bar';
84-
85-
console.log("bar");
86-
const foobar = "foo";
87-
`;
88-
const ast = parseScript(code);
89-
90-
expect(guessQuoteStyle(ast)).toBe('double');
91-
});
92-
93-
test('guessQuoteStyle - no quotes', () => {
94-
const code = dedent`
95-
const foo = true;
96-
`;
97-
const ast = parseScript(code);
98-
99-
expect(guessQuoteStyle(ast)).toBe(undefined);
100-
});
101-
10250
const newVariableDeclaration: AstTypes.VariableDeclaration = {
10351
type: 'VariableDeclaration',
10452
kind: 'const',
@@ -126,13 +74,13 @@ test('integration - simple', () => {
12674
const foobar = "foo";
12775
}
12876
`;
129-
const ast = parseScript(code);
77+
const { ast, comments } = parseScript(code);
13078
const method = ast.body[1] as AstTypes.FunctionDeclaration;
13179

13280
method.body.body.push(newVariableDeclaration);
13381

13482
// new variable is added with correct indentation and matching quotes
135-
expect(serializeScript(ast, code)).toMatchInlineSnapshot(`
83+
expect(serializeScript(ast, comments, code)).toMatchInlineSnapshot(`
13684
"import foo from 'bar';
13785
13886
function bar() {
@@ -153,13 +101,13 @@ test('integration - simple 2', () => {
153101
const foobar = 'foo';
154102
}
155103
`;
156-
const ast = parseScript(code);
104+
const { ast, comments } = parseScript(code);
157105
const method = ast.body[1] as AstTypes.FunctionDeclaration;
158106

159107
method.body.body.push(newVariableDeclaration);
160108

161109
// new variable is added with correct indentation and matching quotes
162-
expect(serializeScript(ast, code)).toMatchInlineSnapshot(`
110+
expect(serializeScript(ast, comments, code)).toMatchInlineSnapshot(`
163111
"import foo from 'bar';
164112
165113
function bar() {
@@ -176,9 +124,9 @@ test('integration - preserves comments', () => {
176124
/** @type {string} */
177125
let foo = 'bar';
178126
`;
179-
const ast = parseScript(code);
127+
const { ast, comments } = parseScript(code);
180128

181-
expect(serializeScript(ast, code)).toMatchInlineSnapshot(`
129+
expect(serializeScript(ast, comments, code)).toMatchInlineSnapshot(`
182130
"/** @type {string} */
183131
let foo = 'bar';"
184132
`);

packages/core/tooling/index.ts

Lines changed: 27 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from 'postcss';
1515
import * as fleece from 'silver-fleece';
1616
import { print as esrapPrint } from 'esrap';
17+
import ts from 'esrap/languages/ts';
1718
import * as acorn from 'acorn';
1819
import { tsPlugin } from '@sveltejs/acorn-typescript';
1920

@@ -47,19 +48,21 @@ export type {
4748

4849
/**
4950
* Parses as string to an AST. Code below is taken from `esrap` to ensure compatibilty.
50-
* https://github.com/sveltejs/esrap/blob/9daf5dd43b31f17f596aa7da91678f2650666dd0/test/common.js#L12
51+
* https://github.com/sveltejs/esrap/blob/920491535d31484ac5fae2327c7826839d851aed/test/common.js#L14
5152
*/
52-
export function parseScript(content: string): TsEstree.Program {
53+
export function parseScript(content: string): {
54+
ast: TsEstree.Program;
55+
comments: TsEstree.Comment[];
56+
} {
5357
const comments: TsEstree.Comment[] = [];
5458

5559
const acornTs = acorn.Parser.extend(tsPlugin());
5660

57-
// Acorn doesn't add comments to the AST by itself. This factory returns the capabilities to add them after the fact.
5861
const ast = acornTs.parse(content, {
5962
ecmaVersion: 'latest',
6063
sourceType: 'module',
6164
locations: true,
62-
onComment: (block, value, start, end) => {
65+
onComment: (block, value, start, end, startLoc, endLoc) => {
6366
if (block && /\n/.test(value)) {
6467
let a = start;
6568
while (a > 0 && content[a - 1] !== '\n') a -= 1;
@@ -71,38 +74,31 @@ export function parseScript(content: string): TsEstree.Program {
7174
value = value.replace(new RegExp(`^${indentation}`, 'gm'), '');
7275
}
7376

74-
comments.push({ type: block ? 'Block' : 'Line', value, start, end });
77+
comments.push({
78+
type: block ? 'Block' : 'Line',
79+
value,
80+
start,
81+
end,
82+
loc: { start: startLoc as TsEstree.Position, end: endLoc as TsEstree.Position }
83+
});
7584
}
7685
}) as TsEstree.Program;
7786

78-
Walker.walk(ast as TsEstree.Node, null, {
79-
_(commentNode, { next }) {
80-
let comment: TsEstree.Comment;
81-
82-
while (comments[0] && commentNode.start && comments[0].start! < commentNode.start) {
83-
comment = comments.shift()!;
84-
(commentNode.leadingComments ??= []).push(comment);
85-
}
86-
87-
next();
88-
89-
if (comments[0]) {
90-
const slice = content.slice(commentNode.end, comments[0].start);
91-
92-
if (/^[,) \t]*$/.test(slice)) {
93-
commentNode.trailingComments = [comments.shift()!];
94-
}
95-
}
96-
}
97-
});
98-
99-
return ast;
87+
return {
88+
ast,
89+
comments
90+
};
10091
}
10192

102-
export function serializeScript(ast: TsEstree.Node, previousContent?: string): string {
103-
const { code } = esrapPrint(ast, {
104-
indent: guessIndentString(previousContent),
105-
quotes: guessQuoteStyle(ast)
93+
export function serializeScript(
94+
ast: TsEstree.Node,
95+
comments: TsEstree.Comment[],
96+
previousContent?: string
97+
): string {
98+
// @ts-expect-error we are still using `estree` while `esrap` is using `@typescript-eslint/types`
99+
// which is causing these errors. But they are simmilar enough to work together.
100+
const { code } = esrapPrint(ast, ts({ comments }), {
101+
indent: guessIndentString(previousContent)
106102
});
107103
return code;
108104
}
@@ -205,36 +201,3 @@ export function guessIndentString(str: string | undefined): string {
205201
return '\t';
206202
}
207203
}
208-
209-
export function guessQuoteStyle(ast: TsEstree.Node): 'single' | 'double' | undefined {
210-
let singleCount = 0;
211-
let doubleCount = 0;
212-
213-
Walker.walk(ast, null, {
214-
Literal(node) {
215-
if (node.raw && node.raw.length >= 2) {
216-
// we have at least two characters in the raw string that could represent both quotes
217-
const quotes = [node.raw[0], node.raw[node.raw.length - 1]];
218-
for (const quote of quotes) {
219-
switch (quote) {
220-
case "'":
221-
singleCount++;
222-
break;
223-
case '"':
224-
doubleCount++;
225-
break;
226-
default:
227-
break;
228-
}
229-
}
230-
}
231-
}
232-
});
233-
234-
if (singleCount === 0 && doubleCount === 0) {
235-
// new file or file without any quotes
236-
return undefined;
237-
}
238-
239-
return singleCount > doubleCount ? 'single' : 'double';
240-
}

packages/core/tooling/js/common.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export function areNodesEqual(node: AstTypes.Node, otherNode: AstTypes.Node): bo
9393

9494
const nodeClone = stripAst(decircular(node), ['loc', 'raw']);
9595
const otherNodeClone = stripAst(decircular(otherNode), ['loc', 'raw']);
96-
return serializeScript(nodeClone) === serializeScript(otherNodeClone);
96+
return serializeScript(nodeClone, []) === serializeScript(otherNodeClone, []);
9797
}
9898

9999
export function createBlockStatement(): AstTypes.BlockStatement {
@@ -118,18 +118,18 @@ export function appendFromString(
118118
node: AstTypes.BlockStatement | AstTypes.Program,
119119
options: { code: string }
120120
): void {
121-
const program = parseScript(dedent(options.code));
121+
const { ast } = parseScript(dedent(options.code));
122122

123-
for (const childNode of program.body) {
123+
for (const childNode of ast.body) {
124124
// @ts-expect-error
125125
node.body.push(childNode);
126126
}
127127
}
128128

129129
export function parseExpression(code: string): AstTypes.Expression {
130-
const program = parseScript(dedent(code));
131-
stripAst(program, ['raw']);
132-
const statement = program.body[0]!;
130+
const { ast } = parseScript(dedent(code));
131+
stripAst(ast, ['raw']);
132+
const statement = ast.body[0]!;
133133
if (statement.type !== 'ExpressionStatement') {
134134
throw new Error('Code provided was not an expression');
135135
}
@@ -142,8 +142,8 @@ export function parseStatement(code: string): AstTypes.Statement {
142142
}
143143

144144
export function parseFromString<T extends AstTypes.Node>(code: string): T {
145-
const program = parseScript(dedent(code));
146-
const statement = program.body[0]!;
145+
const { ast } = parseScript(dedent(code));
146+
const statement = ast.body[0]!;
147147

148148
return statement as T;
149149
}

packages/core/tooling/parsers.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ type ParseBase = {
66
generateCode(): string;
77
};
88

9-
export function parseScript(source: string): { ast: utils.AstTypes.Program } & ParseBase {
10-
const ast = utils.parseScript(source);
11-
const generateCode = () => utils.serializeScript(ast, source);
9+
export function parseScript(
10+
source: string
11+
): { ast: utils.AstTypes.Program; comments: utils.AstTypes.Comment[] } & ParseBase {
12+
const { ast, comments } = utils.parseScript(source);
13+
const generateCode = () => utils.serializeScript(ast, comments, source);
1214

13-
return { ast, source, generateCode };
15+
return { ast, comments, source, generateCode };
1416
}
1517

1618
export function parseCss(source: string): { ast: utils.CssAst } & ParseBase {

pnpm-lock.yaml

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)