Code Generator
generate is the parser run backwards. Give it a Program and it gives you
source text.
generate(program: Program, options?: GenerateOptions): GenerateResultimport { generate, parse } from "yuku-tsrx";
const { program } = parse(source, { lang: "tsx" });
const { code, errors, map } = generate(program);The tree does not have to be the one you just parsed. You can walk it, change it, and print the result, which is what a codemod does.
What it accepts#
The first argument has to be a Program node from this parser. generate
checks that before doing anything and throws a TypeError reading
Expected a Program node from yuku-tsrx otherwise. It is not a printer for
arbitrary ESTree.
Internally the tree goes back across the native boundary the same way it came:
generate calls encode on the
program and hands the buffer to the addon. The generator itself is
src/dialect/codegen.zig.
GenerateOptions#
export interface GenerateOptions {
strip?: boolean;
minify?: boolean | { whitespace?: boolean; syntax?: boolean; quotes?: boolean };
format?: "pretty" | "compact";
indent?: number;
quotes?: "preserve" | "double" | "single" | "shortest";
comments?: boolean | "all" | "some" | "none" | "line" | "block";
}| Option | What it does |
|---|---|
strip |
Emit without the TypeScript-only syntax. |
minify |
Size-reducing output. true means all three modes; an object turns them on one at a time. |
format |
pretty is indented, with spaces around operators and after commas. compact emits no discretionary whitespace, only what the grammar requires. |
indent |
Spaces per indentation level. Used only when format is pretty. |
quotes |
preserve keeps each literal's original quote style, double and single force one, shortest picks the one that needs fewer escapes. |
comments |
Which comments survive. |
One current limitation: quotes: "shortest" and minify: true are declared in
npm/yuku-tsrx/index.d.ts but fail at the native boundary today, because the
Quotes enum in src/dialect/codegen.zig has only preserve, double, and
single, so the addon rejects the request with
invalid enum value for codegen.Quotes: 'shortest'. minify: true hits the
same wall because its quotes mode sets shortest. Until the enum gains the
value, use preserve, double, or single, and ask for
minify: { whitespace: true, syntax: true } instead of minify: true.
Every option in the table is a control below, and the output is what the generator in your browser returns for the settings you pick.
Source
import type { Item } from "./item";
import { format } from './format';
/* The cart list, one row per item. */
export function Cart({ items }: { items: Item[] }) {
// total is read by the attribute below
@{ const total = items.length; }
return (
<ul class="cart" data-empty={total === 0}>
@for (const item of items; key item.id) {
<li>{format(item.label)}</li>
}
</ul>
);
}Generated
The generator runs when this figure scrolls into view.
The figure parses with attachComments: true, because the comments option can
only act on comments the parse kept.
comments#
none drops all comments, all emits every one, line emits only // ...,
block emits only /* ... */, and some emits legal headers, JSDoc, and
tree-shaking annotations such as __PURE__ and __NO_SIDE_EFFECTS__. A boolean
is accepted as a shorthand: true becomes all and false becomes none.
Without the option, the generator's own default applies, which is some.
minify is three switches, not one#
minify: true is shorthand for { whitespace: true, syntax: true, quotes: true },
and npm/yuku-tsrx/index.js expands each of the three into the option it
actually controls:
| Mode | Effect |
|---|---|
syntax |
Turns on the print-time size-reducing substitutions. |
whitespace |
Sets format to compact. |
quotes |
Sets quotes to shortest. |
So { minify: { whitespace: true } } gives you compact output with ordinary
syntax and ordinary quotes, and { minify: true } gives you all three. Setting
format or quotes yourself alongside a minify mode that also sets them
means the mode wins.
GenerateResult#
export interface GenerateResult {
code: string;
errors: Array<{ message: string; start: number; end: number }>;
map: unknown | null;
}code is the source text. errors is empty when codegen ran cleanly; an entry
is a problem the generator found in the tree you handed it, with the offsets of
the node it found it on. map is a Source Map V3 object, and it is null
unless source maps were requested.
Round-tripping#
Printing a parsed tree and parsing the result again should give you the same
structure back. That is the property the repository's own tests hold the
generator to, across every valid fixture in test/parser/misc/tsrx/:
import { analyze, generate, parse } from "yuku-tsrx";
const analysis = analyze(source, { lang: "tsx" });
const generated = generate(analysis.program);
const reparsed = parse(generated.code, { lang: "tsx" });
// reparsed.diagnostics is empty, and the structure matchesThis is the check that keeps TSRX from quietly degrading on the way out. A
generator that printed a JSXCodeBlock as an ordinary expression would produce
text that still parses, just not into the same tree, so "it parses" is not the
bar. See TSRX Syntax Support for the constructs that have
to survive the trip.