Skip to content

Commit c8eeeb5

Browse files
committed
refactor(linter/plugins): remove build-time dependency on napi/parser (#14374)
Refactor. Previously build script for `oxlint` package copied files from `napi/parser`. Remove this dependency, by instead making `oxc_ast_tools` generate the files in `apps/oxlint/src-js/generated`, and then copy the files from there to `dist/generated` in the build script. This ends up with the same result, but divorces `oxlint` package from `oxc-parser`, which is cleaner.
1 parent fb1a067 commit c8eeeb5

File tree

7 files changed

+207
-26
lines changed

7 files changed

+207
-26
lines changed

.github/generated/ast_changes_watch_list.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
src:
55
- '.github/generated/ast_changes_watch_list.yml'
66
- 'apps/oxlint/src-js/generated/constants.js'
7+
- 'apps/oxlint/src-js/generated/deserialize.js'
8+
- 'apps/oxlint/src-js/generated/keys.js'
79
- 'apps/oxlint/src-js/generated/types.d.ts'
810
- 'apps/oxlint/src-js/generated/types.js'
911
- 'apps/oxlint/src-js/generated/visitor.d.ts'
@@ -78,7 +80,6 @@ src:
7880
- 'napi/parser/generated/deserialize/ts.js'
7981
- 'napi/parser/generated/deserialize/ts_parent.js'
8082
- 'napi/parser/generated/deserialize/ts_range.js'
81-
- 'napi/parser/generated/deserialize/ts_range_loc_parent_no_parens.js'
8283
- 'napi/parser/generated/deserialize/ts_range_parent.js'
8384
- 'napi/parser/generated/lazy/constructors.js'
8485
- 'napi/parser/generated/lazy/types.js'

apps/oxlint/scripts/build.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { copyFileSync, mkdirSync, readdirSync, readFileSync, writeFileSync } fro
33
import { join } from 'node:path';
44

55
const oxlintDirPath = join(import.meta.dirname, '..'),
6-
distDirPath = join(oxlintDirPath, 'dist'),
7-
parserDirPath = join(oxlintDirPath, '../../napi/parser');
6+
distDirPath = join(oxlintDirPath, 'dist');
87

98
// Modify `bindings.js` to use correct package names
109
console.log('Modifying bindings.js...');
@@ -20,25 +19,35 @@ writeFileSync(bindingsPath, bindingsJs);
2019
console.log('Building with tsdown...');
2120
execSync('pnpm tsdown', { stdio: 'inherit', cwd: oxlintDirPath });
2221

22+
// Lazy implementation
23+
/*
2324
// Copy files from `napi/parser` to `apps/oxlint/dist`
2425
console.log('Copying files from parser...');
2526
27+
const parserDirPath = join(oxlintDirPath, '../../napi/parser');
28+
2629
const parserFilePaths = [
27-
// Lazy implementation
28-
/*
2930
'src-js/raw-transfer/lazy-common.js',
3031
'src-js/raw-transfer/node-array.js',
3132
'generated/lazy/constructors.js',
3233
'generated/lazy/types.js',
3334
'generated/lazy/walk.js',
34-
*/
3535
'generated/deserialize/ts_range_loc_parent_no_parens.js',
3636
'generated/visit/keys.js',
3737
];
3838
3939
for (const parserFilePath of parserFilePaths) {
4040
copyFile(join(parserDirPath, parserFilePath), join(distDirPath, parserFilePath));
4141
}
42+
*/
43+
44+
// Copy files from `src-js/generated` to `dist/generated`
45+
console.log('Copying generated files...');
46+
47+
const generatedFilePaths = ['deserialize.js', 'keys.js'];
48+
for (const filePath of generatedFilePaths) {
49+
copyFile(join(oxlintDirPath, 'src-js/generated', filePath), join(distDirPath, 'generated', filePath));
50+
}
4251

4352
// Copy native `.node` files from `src-js`
4453
console.log('Copying `.node` files...');
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Auto-generated code, DO NOT EDIT DIRECTLY!
2+
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/estree_visit.rs`.
3+
4+
export default Object.freeze({
5+
// Leaf nodes
6+
DebuggerStatement: [],
7+
EmptyStatement: [],
8+
Literal: [],
9+
PrivateIdentifier: [],
10+
Super: [],
11+
TemplateElement: [],
12+
ThisExpression: [],
13+
JSXClosingFragment: [],
14+
JSXEmptyExpression: [],
15+
JSXIdentifier: [],
16+
JSXOpeningFragment: [],
17+
JSXText: [],
18+
TSAnyKeyword: [],
19+
TSBigIntKeyword: [],
20+
TSBooleanKeyword: [],
21+
TSIntrinsicKeyword: [],
22+
TSJSDocUnknownType: [],
23+
TSNeverKeyword: [],
24+
TSNullKeyword: [],
25+
TSNumberKeyword: [],
26+
TSObjectKeyword: [],
27+
TSStringKeyword: [],
28+
TSSymbolKeyword: [],
29+
TSThisType: [],
30+
TSUndefinedKeyword: [],
31+
TSUnknownKeyword: [],
32+
TSVoidKeyword: [],
33+
// Non-leaf nodes
34+
AccessorProperty: ['decorators', 'key', 'typeAnnotation', 'value'],
35+
ArrayExpression: ['elements'],
36+
ArrayPattern: ['decorators', 'elements', 'typeAnnotation'],
37+
ArrowFunctionExpression: ['typeParameters', 'params', 'returnType', 'body'],
38+
AssignmentExpression: ['left', 'right'],
39+
AssignmentPattern: ['decorators', 'left', 'right', 'typeAnnotation'],
40+
AwaitExpression: ['argument'],
41+
BinaryExpression: ['left', 'right'],
42+
BlockStatement: ['body'],
43+
BreakStatement: ['label'],
44+
CallExpression: ['callee', 'typeArguments', 'arguments'],
45+
CatchClause: ['param', 'body'],
46+
ChainExpression: ['expression'],
47+
ClassBody: ['body'],
48+
ClassDeclaration: ['decorators', 'id', 'typeParameters', 'superClass', 'superTypeArguments', 'implements', 'body'],
49+
ClassExpression: ['decorators', 'id', 'typeParameters', 'superClass', 'superTypeArguments', 'implements', 'body'],
50+
ConditionalExpression: ['test', 'consequent', 'alternate'],
51+
ContinueStatement: ['label'],
52+
Decorator: ['expression'],
53+
DoWhileStatement: ['body', 'test'],
54+
ExportAllDeclaration: ['exported', 'source', 'attributes'],
55+
ExportDefaultDeclaration: ['declaration'],
56+
ExportNamedDeclaration: ['declaration', 'specifiers', 'source', 'attributes'],
57+
ExportSpecifier: ['local', 'exported'],
58+
ExpressionStatement: ['expression'],
59+
ForInStatement: ['left', 'right', 'body'],
60+
ForOfStatement: ['left', 'right', 'body'],
61+
ForStatement: ['init', 'test', 'update', 'body'],
62+
FunctionDeclaration: ['id', 'typeParameters', 'params', 'returnType', 'body'],
63+
FunctionExpression: ['id', 'typeParameters', 'params', 'returnType', 'body'],
64+
Identifier: ['decorators', 'typeAnnotation'],
65+
IfStatement: ['test', 'consequent', 'alternate'],
66+
ImportAttribute: ['key', 'value'],
67+
ImportDeclaration: ['specifiers', 'source', 'attributes'],
68+
ImportDefaultSpecifier: ['local'],
69+
ImportExpression: ['source', 'options'],
70+
ImportNamespaceSpecifier: ['local'],
71+
ImportSpecifier: ['imported', 'local'],
72+
LabeledStatement: ['label', 'body'],
73+
LogicalExpression: ['left', 'right'],
74+
MemberExpression: ['object', 'property'],
75+
MetaProperty: ['meta', 'property'],
76+
MethodDefinition: ['decorators', 'key', 'value'],
77+
NewExpression: ['callee', 'typeArguments', 'arguments'],
78+
ObjectExpression: ['properties'],
79+
ObjectPattern: ['decorators', 'properties', 'typeAnnotation'],
80+
ParenthesizedExpression: ['expression'],
81+
Program: ['body'],
82+
Property: ['key', 'value'],
83+
PropertyDefinition: ['decorators', 'key', 'typeAnnotation', 'value'],
84+
RestElement: ['decorators', 'argument', 'typeAnnotation'],
85+
ReturnStatement: ['argument'],
86+
SequenceExpression: ['expressions'],
87+
SpreadElement: ['argument'],
88+
StaticBlock: ['body'],
89+
SwitchCase: ['test', 'consequent'],
90+
SwitchStatement: ['discriminant', 'cases'],
91+
TaggedTemplateExpression: ['tag', 'typeArguments', 'quasi'],
92+
TemplateLiteral: ['quasis', 'expressions'],
93+
ThrowStatement: ['argument'],
94+
TryStatement: ['block', 'handler', 'finalizer'],
95+
UnaryExpression: ['argument'],
96+
UpdateExpression: ['argument'],
97+
V8IntrinsicExpression: ['name', 'arguments'],
98+
VariableDeclaration: ['declarations'],
99+
VariableDeclarator: ['id', 'init'],
100+
WhileStatement: ['test', 'body'],
101+
WithStatement: ['object', 'body'],
102+
YieldExpression: ['argument'],
103+
JSXAttribute: ['name', 'value'],
104+
JSXClosingElement: ['name'],
105+
JSXElement: ['openingElement', 'children', 'closingElement'],
106+
JSXExpressionContainer: ['expression'],
107+
JSXFragment: ['openingFragment', 'children', 'closingFragment'],
108+
JSXMemberExpression: ['object', 'property'],
109+
JSXNamespacedName: ['namespace', 'name'],
110+
JSXOpeningElement: ['name', 'typeArguments', 'attributes'],
111+
JSXSpreadAttribute: ['argument'],
112+
JSXSpreadChild: ['expression'],
113+
TSAbstractAccessorProperty: ['decorators', 'key', 'typeAnnotation'],
114+
TSAbstractMethodDefinition: ['key', 'value'],
115+
TSAbstractPropertyDefinition: ['decorators', 'key', 'typeAnnotation'],
116+
TSArrayType: ['elementType'],
117+
TSAsExpression: ['expression', 'typeAnnotation'],
118+
TSCallSignatureDeclaration: ['typeParameters', 'params', 'returnType'],
119+
TSClassImplements: ['expression', 'typeArguments'],
120+
TSConditionalType: ['checkType', 'extendsType', 'trueType', 'falseType'],
121+
TSConstructSignatureDeclaration: ['typeParameters', 'params', 'returnType'],
122+
TSConstructorType: ['typeParameters', 'params', 'returnType'],
123+
TSDeclareFunction: ['id', 'typeParameters', 'params', 'returnType', 'body'],
124+
TSEmptyBodyFunctionExpression: ['id', 'typeParameters', 'params', 'returnType'],
125+
TSEnumBody: ['members'],
126+
TSEnumDeclaration: ['id', 'body'],
127+
TSEnumMember: ['id', 'initializer'],
128+
TSExportAssignment: ['expression'],
129+
TSExternalModuleReference: ['expression'],
130+
TSFunctionType: ['typeParameters', 'params', 'returnType'],
131+
TSImportEqualsDeclaration: ['id', 'moduleReference'],
132+
TSImportType: ['argument', 'options', 'qualifier', 'typeArguments'],
133+
TSIndexSignature: ['parameters', 'typeAnnotation'],
134+
TSIndexedAccessType: ['objectType', 'indexType'],
135+
TSInferType: ['typeParameter'],
136+
TSInstantiationExpression: ['expression', 'typeArguments'],
137+
TSInterfaceBody: ['body'],
138+
TSInterfaceDeclaration: ['id', 'typeParameters', 'extends', 'body'],
139+
TSInterfaceHeritage: ['expression', 'typeArguments'],
140+
TSIntersectionType: ['types'],
141+
TSJSDocNonNullableType: ['typeAnnotation'],
142+
TSJSDocNullableType: ['typeAnnotation'],
143+
TSLiteralType: ['literal'],
144+
TSMappedType: ['key', 'constraint', 'nameType', 'typeAnnotation'],
145+
TSMethodSignature: ['key', 'typeParameters', 'params', 'returnType'],
146+
TSModuleBlock: ['body'],
147+
TSModuleDeclaration: ['id', 'body'],
148+
TSNamedTupleMember: ['label', 'elementType'],
149+
TSNamespaceExportDeclaration: ['id'],
150+
TSNonNullExpression: ['expression'],
151+
TSOptionalType: ['typeAnnotation'],
152+
TSParameterProperty: ['decorators', 'parameter'],
153+
TSParenthesizedType: ['typeAnnotation'],
154+
TSPropertySignature: ['key', 'typeAnnotation'],
155+
TSQualifiedName: ['left', 'right'],
156+
TSRestType: ['typeAnnotation'],
157+
TSSatisfiesExpression: ['expression', 'typeAnnotation'],
158+
TSTemplateLiteralType: ['quasis', 'types'],
159+
TSTupleType: ['elementTypes'],
160+
TSTypeAliasDeclaration: ['id', 'typeParameters', 'typeAnnotation'],
161+
TSTypeAnnotation: ['typeAnnotation'],
162+
TSTypeAssertion: ['typeAnnotation', 'expression'],
163+
TSTypeLiteral: ['members'],
164+
TSTypeOperator: ['typeAnnotation'],
165+
TSTypeParameter: ['name', 'constraint', 'default'],
166+
TSTypeParameterDeclaration: ['params'],
167+
TSTypeParameterInstantiation: ['params'],
168+
TSTypePredicate: ['parameterName', 'typeAnnotation'],
169+
TSTypeQuery: ['exprName', 'typeArguments'],
170+
TSTypeReference: ['typeName', 'typeArguments'],
171+
TSUnionType: ['types'],
172+
});

apps/oxlint/src-js/plugins/source_code.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
// @ts-expect-error we need to generate `.d.ts` file for this module
99
// We use the deserializer which removes `ParenthesizedExpression`s from AST,
1010
// and with `range`, `loc`, and `parent` properties on AST nodes, to match ESLint
11-
import { deserializeProgramOnly } from '../../dist/generated/deserialize/ts_range_loc_parent_no_parens.js';
11+
import { deserializeProgramOnly } from '../../dist/generated/deserialize.js';
1212

1313
import {
1414
getLineColumnFromOffset,
@@ -125,7 +125,7 @@ export const SOURCE_CODE = Object.freeze({
125125
// Get visitor keys to traverse this AST.
126126
get visitorKeys(): { [key: string]: string[] } {
127127
// This is the path relative to `plugins.js` file in `dist` directory
128-
if (visitorKeys === null) visitorKeys = require('./generated/visit/keys.js').default;
128+
if (visitorKeys === null) visitorKeys = require('./generated/keys.js').default;
129129
return visitorKeys;
130130
},
131131

tasks/ast_tools/src/generators/estree_visit.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl Generator for ESTreeVisitGenerator {
5555
},
5656
Output::Javascript {
5757
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/keys.js"),
58-
code: visitor_keys,
58+
code: visitor_keys.clone(),
5959
},
6060
Output::Javascript {
6161
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/types.js"),
@@ -69,6 +69,10 @@ impl Generator for ESTreeVisitGenerator {
6969
path: format!("{OXLINT_APP_PATH}/src-js/generated/walk.js"),
7070
code: walk,
7171
},
72+
Output::Javascript {
73+
path: format!("{OXLINT_APP_PATH}/src-js/generated/keys.js"),
74+
code: visitor_keys,
75+
},
7276
Output::Javascript {
7377
path: format!("{OXLINT_APP_PATH}/src-js/generated/types.js"),
7478
code: type_ids_map,

tasks/ast_tools/src/generators/raw_transfer.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,7 @@ impl Generator for RawTransferGenerator {
7777

7878
let mut outputs = deserializers
7979
.into_iter()
80-
.map(|(name, code)| Output::Javascript {
81-
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/{name}.js"),
82-
code,
83-
})
80+
.map(|(path, code)| Output::Javascript { path, code })
8481
.collect::<Vec<_>>();
8582

8683
outputs.extend([
@@ -127,7 +124,7 @@ fn generate_deserializers(
127124
consts: Constants,
128125
schema: &Schema,
129126
codegen: &Codegen,
130-
) -> Vec<(/* name */ String, /* code */ String)> {
127+
) -> Vec<(/* path */ String, /* code */ String)> {
131128
let estree_derive_id = codegen.get_derive_id_by_name("ESTree");
132129
let span_type_id = schema.type_names["Span"];
133130

@@ -206,7 +203,7 @@ fn generate_deserializers(
206203
// Create deserializers with various settings, by setting `IS_TS`, `RANGE`, `LOC`, `PARENT`
207204
// and `PRESERVE_PARENS` consts, and running through minifier to shake out irrelevant code
208205
struct VariantGen {
209-
variant_names: Vec<String>,
206+
variant_paths: Vec<String>,
210207
}
211208

212209
impl VariantGenerator<5> for VariantGen {
@@ -218,14 +215,12 @@ fn generate_deserializers(
218215
for is_ts in [false, true] {
219216
for range in [false, true] {
220217
for parent in [false, true] {
221-
let mut name = if is_ts { "ts" } else { "js" }.to_string();
222-
if range {
223-
name.push_str("_range");
224-
}
225-
if parent {
226-
name.push_str("_parent");
227-
}
228-
self.variant_names.push(name);
218+
self.variant_paths.push(format!(
219+
"{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/{}{}{}.js",
220+
if is_ts { "ts" } else { "js" },
221+
if range { "_range" } else { "" },
222+
if parent { "_parent" } else { "" },
223+
));
229224

230225
variants.push([
231226
is_ts, range, /* loc */ false, parent,
@@ -235,7 +230,7 @@ fn generate_deserializers(
235230
}
236231
}
237232

238-
self.variant_names.push("ts_range_loc_parent_no_parens".to_string());
233+
self.variant_paths.push(format!("{OXLINT_APP_PATH}/src-js/generated/deserialize.js"));
239234
variants.push([
240235
/* is_ts */ true, /* range */ true, /* loc */ true,
241236
/* parent */ true, /* preserve_parens */ false,
@@ -257,10 +252,10 @@ fn generate_deserializers(
257252
}
258253
}
259254

260-
let mut generator = VariantGen { variant_names: vec![] };
255+
let mut generator = VariantGen { variant_paths: vec![] };
261256
let codes = generator.generate(&code);
262257

263-
generator.variant_names.into_iter().zip(codes).collect()
258+
generator.variant_paths.into_iter().zip(codes).collect()
264259
}
265260

266261
/// Type of deserializer in which some code appears.

0 commit comments

Comments
 (0)