Skip to content

Commit 08f14e6

Browse files
committed
refactor(ast_tools/raw_transfer): generate deserializers in loop (#14343)
Pure refactor. Generate the various deserializers with a loop, rather than specifying each individually. This makes it easier to add more deserializers (next PR).
1 parent a11bc9f commit 08f14e6

File tree

1 file changed

+55
-67
lines changed

1 file changed

+55
-67
lines changed

tasks/ast_tools/src/generators/raw_transfer.rs

Lines changed: 55 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -74,33 +74,19 @@ impl Generator for RawTransferGenerator {
7474
fn generate_many(&self, schema: &Schema, codegen: &Codegen) -> Vec<Output> {
7575
let consts = get_constants(schema);
7676

77-
let Codes { js, ts, js_range, ts_range, ts_range_no_parens } =
78-
generate_deserializers(consts, schema, codegen);
77+
let deserializers = generate_deserializers(consts, schema, codegen);
78+
7979
let (constants_js, constants_rust) = generate_constants(consts);
8080

81-
vec![
82-
Output::Javascript {
83-
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/js.js"),
84-
code: js,
85-
},
86-
Output::Javascript {
87-
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/ts.js"),
88-
code: ts,
89-
},
90-
Output::Javascript {
91-
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/js_range.js"),
92-
code: js_range,
93-
},
94-
Output::Javascript {
95-
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/ts_range.js"),
96-
code: ts_range,
97-
},
98-
Output::Javascript {
99-
path: format!(
100-
"{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/ts_range_no_parens.js"
101-
),
102-
code: ts_range_no_parens,
103-
},
81+
let mut outputs = deserializers
82+
.into_iter()
83+
.map(|(name, code)| Output::Javascript {
84+
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/deserialize/{name}.js"),
85+
code,
86+
})
87+
.collect::<Vec<_>>();
88+
89+
outputs.extend([
10490
Output::Javascript {
10591
path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/constants.js"),
10692
code: constants_js.clone(),
@@ -121,35 +107,29 @@ impl Generator for RawTransferGenerator {
121107
path: format!("{ALLOCATOR_CRATE_PATH}/src/generated/fixed_size_constants.rs"),
122108
tokens: constants_rust,
123109
},
124-
]
125-
}
126-
}
110+
]);
127111

128-
/// Container for generated code.
129-
struct Codes {
130-
/// Code for JS deserializer
131-
js: String,
132-
/// Code for TS deserializer
133-
ts: String,
134-
/// Code for JS deserializer with `range` fields
135-
js_range: String,
136-
/// Code for TS deserializer with `range` fields
137-
ts_range: String,
138-
/// Code for TS deserializer with `range` fields and no `ParenthesizedExpression` nodes (for linter)
139-
ts_range_no_parens: String,
112+
outputs
113+
}
140114
}
141115

142116
/// Generate deserializer functions for all types.
143117
///
144118
/// Generates a single file which is the base of both the JS and TS deserializers.
145-
/// Code which is specific to JS or TS deserializer is gated by the `IS_TS` const.
119+
/// Code which is specific to JS or TS deserializer is gated by the `IS_TS` const,
120+
/// code which adds `range` fields is gated by `RANGE` const.
146121
/// e.g.:
147122
/// * `if (IS_TS) node.typeAnnotation = null;`
148123
/// * `return { type: 'Function', id, params, ...(IS_TS && { typeAnnotation: null }) };`
124+
/// * `return { type: 'ThisExpression', start, end, ...(RANGE && { range: [start, end] }) };`
149125
///
150126
/// When printing the JS and TS deserializers, the value of `IS_TS` is set to `true` or `false`,
151127
/// and minifier then shakes out the dead code for each.
152-
fn generate_deserializers(consts: Constants, schema: &Schema, codegen: &Codegen) -> Codes {
128+
fn generate_deserializers(
129+
consts: Constants,
130+
schema: &Schema,
131+
codegen: &Codegen,
132+
) -> Vec<(/* name */ String, /* code */ String)> {
153133
let estree_derive_id = codegen.get_derive_id_by_name("ESTree");
154134
let span_type_id = schema.type_names["Span"];
155135

@@ -163,7 +143,7 @@ fn generate_deserializers(consts: Constants, schema: &Schema, codegen: &Codegen)
163143
164144
const IS_TS = false;
165145
const RANGE = false;
166-
const PRESERVE_PARENS = true;
146+
const PRESERVE_PARENS = false;
167147
168148
const textDecoder = new TextDecoder('utf-8', {{ ignoreBOM: true }}),
169149
decodeStr = textDecoder.decode.bind(textDecoder),
@@ -229,31 +209,39 @@ fn generate_deserializers(consts: Constants, schema: &Schema, codegen: &Codegen)
229209
let source_type = SourceType::mjs();
230210
let parser_ret = Parser::new(&allocator, &code, source_type).parse();
231211
assert!(parser_ret.errors.is_empty(), "Parse errors: {:#?}", parser_ret.errors);
232-
let mut program_js = parser_ret.program;
233-
234-
// Create clone of AST for TS deserializer with `const IS_TS = true;`
235-
let mut program_ts = program_js.clone_in(&allocator);
236-
replace_const(&mut program_ts, "IS_TS", true);
237-
238-
// Create clones of AST for with-`range` field deserializer with `const RANGE = true;`
239-
let mut program_js_range = program_js.clone_in(&allocator);
240-
replace_const(&mut program_js_range, "RANGE", true);
241-
let mut program_ts_range = program_ts.clone_in(&allocator);
242-
replace_const(&mut program_ts_range, "RANGE", true);
243-
244-
// Create clone of AST for with-`range` field and no-parentheses deserializer
245-
// with `const RANGE = true; const PRESERVE_PARENS = false;`
246-
let mut program_ts_range_no_parens = program_ts_range.clone_in(&allocator);
247-
replace_const(&mut program_ts_range_no_parens, "PRESERVE_PARENS", false);
248-
249-
// Print both deserializers, using minifier to shake out JS/TS-specific code from each
250-
Codes {
251-
js: print_minified(&mut program_js, &allocator),
252-
ts: print_minified(&mut program_ts, &allocator),
253-
js_range: print_minified(&mut program_js_range, &allocator),
254-
ts_range: print_minified(&mut program_ts_range, &allocator),
255-
ts_range_no_parens: print_minified(&mut program_ts_range_no_parens, &allocator),
212+
let program = parser_ret.program;
213+
214+
// Create deserializers with various settings, by setting `IS_TS`, `RANGE` and `PRESERVE_PARENS` consts,
215+
// and running through minifier to shake out irrelevant code
216+
let mut deserializers = vec![];
217+
let mut create_deserializer = |is_ts, range, preserve_parens| {
218+
let mut program = program.clone_in(&allocator);
219+
replace_const(&mut program, "IS_TS", is_ts);
220+
replace_const(&mut program, "RANGE", range);
221+
replace_const(&mut program, "PRESERVE_PARENS", preserve_parens);
222+
let code = print_minified(&mut program, &allocator);
223+
224+
let mut name = if is_ts { "ts" } else { "js" }.to_string();
225+
if range {
226+
name.push_str("_range");
227+
}
228+
if !preserve_parens {
229+
name.push_str("_no_parens");
230+
}
231+
232+
deserializers.push((name, code));
233+
};
234+
235+
for is_ts in [false, true] {
236+
for range in [false, true] {
237+
create_deserializer(is_ts, range, true);
238+
}
256239
}
240+
241+
// `PRESERVE_PARENS = false` is only required for linter
242+
create_deserializer(true, true, false);
243+
244+
deserializers
257245
}
258246

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

0 commit comments

Comments
 (0)