yuku-codegen 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # yuku-codegen
2
+
3
+ A high-performance JavaScript/TypeScript code generator written in Zig, powered by [Yuku](https://github.com/yuku-toolchain/yuku).
4
+
5
+ Renders an ESTree / TypeScript-ESTree AST back to source code, with optional Source Map V3 output. The input AST is exactly what [`yuku-parser`](https://www.npmjs.com/package/yuku-parser) produces.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install yuku-codegen
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```js
16
+ import { parse } from "yuku-parser";
17
+ import { print } from "yuku-codegen";
18
+
19
+ const { program } = parse("const x = 1 + 2;");
20
+ const { code } = print(program);
21
+
22
+ console.log(code); // "const x = 1 + 2;"
23
+ ```
24
+
25
+ ## API
26
+
27
+ Three entry points share the same options shape:
28
+
29
+ - `print(ast, options?)` renders verbatim, preserving TypeScript syntax.
30
+ - `strip(ast, options?)` drops type-only syntax and emits plain JavaScript.
31
+ - `minify(ast, options?)` applies size-reducing rewrites such as `true → !0` and shortest-numeric-form. Combine with `format: "compact"` for full minification.
32
+
33
+ All return the same `CodegenResult`:
34
+
35
+ ```ts
36
+ interface CodegenResult {
37
+ code: string;
38
+ errors: Diagnostic[];
39
+ map: SourceMap | null;
40
+ }
41
+ ```
42
+
43
+ `errors` is empty when codegen succeeded cleanly. `map` is populated only when `sourceMaps` is enabled.
44
+
45
+ ## Options
46
+
47
+ ```js
48
+ const result = print(ast, {
49
+ format: "pretty",
50
+ indent: 2,
51
+ quotes: "double",
52
+ sourceMaps: { source },
53
+ });
54
+ ```
55
+
56
+ | Option | Values | Default | Description |
57
+ | ------------ | ----------------------- | ---------- | ------------------------------------------------------------------------------------------ |
58
+ | `format` | `"pretty"`, `"compact"` | `"pretty"` | Whitespace mode. `"compact"` emits only the separators the grammar requires. |
59
+ | `indent` | `number` | `2` | Spaces per indentation level. Used only when `format` is `"pretty"`. |
60
+ | `quotes` | `"double"`, `"single"` | `"double"` | Quote style for emitted string literals. |
61
+ | `sourceMaps` | `SourceMapOptions` | _disabled_ | Pass an object to emit a Source Map V3 alongside the code. Omit (or set to `null`) to skip. |
62
+
63
+ ## Source maps
64
+
65
+ Pass `sourceMaps` to emit a Source Map V3 alongside the code. The original source text is required.
66
+
67
+ ```js
68
+ import { parse } from "yuku-parser";
69
+ import { print } from "yuku-codegen";
70
+
71
+ const source = `const greet = (name) => "Hello, " + name;`;
72
+ const { program } = parse(source);
73
+
74
+ const { code, map } = print(program, {
75
+ sourceMaps: {
76
+ source,
77
+ file: "out.js",
78
+ sourceFileName: "in.js",
79
+ sourcesContent: true,
80
+ },
81
+ });
82
+
83
+ await Bun.write("out.js", code + `\n//# sourceMappingURL=out.js.map`);
84
+ await Bun.write("out.js.map", JSON.stringify(map));
85
+ ```
86
+
87
+ ### `SourceMapOptions`
88
+
89
+ | Field | Type | Required | Description |
90
+ | ----------------- | --------- | -------- | ----------------------------------------------------------------- |
91
+ | `source` | `string` | yes | Original source the AST was parsed from. |
92
+ | `file` | `string` | no | Output filename, embedded as the map's `file`. |
93
+ | `sourceFileName` | `string` | no | Source filename, embedded as the single entry of `sources`. |
94
+ | `sourceRoot` | `string` | no | Prefix embedded as `sourceRoot`. |
95
+ | `sourcesContent` | `boolean` | no | When `true`, embeds `source` into the map's `sourcesContent`. |
96
+
97
+ ### Result
98
+
99
+ The returned `map` is a Source Map V3 object, ready to `JSON.stringify`:
100
+
101
+ ```ts
102
+ interface SourceMap {
103
+ version: 3;
104
+ file: string | null;
105
+ sourceRoot: string | null;
106
+ sources: string[];
107
+ sourcesContent: (string | null)[] | null;
108
+ names: string[];
109
+ mappings: string;
110
+ }
111
+ ```
112
+
113
+ Columns are 0-indexed UTF-16 code units, matching the convention used by Chrome DevTools and every consumer-side library (`@jridgewell/trace-mapping`, `source-map`, etc.).
114
+
115
+ ## TypeScript stripping
116
+
117
+ `strip` rewrites the AST as plain JavaScript:
118
+
119
+ ```js
120
+ import { parse } from "yuku-parser";
121
+ import { strip } from "yuku-codegen";
122
+
123
+ const { program } = parse(`const x: number = 1;`, { lang: "ts" });
124
+ console.log(strip(program).code); // "const x = 1;"
125
+ ```
126
+
127
+ Type annotations, type aliases, interfaces, and other type-only constructs are dropped. Constructs that don't have a clean JavaScript equivalent (`enum`, `namespace`, `import = require()`, `export =`) are reported in `errors` and elided. The output is always syntactically valid JavaScript.
128
+
129
+ ## Minification
130
+
131
+ `minify` applies size-reducing rewrites at print time:
132
+
133
+ - `true` / `false` → `!0` / `!1`
134
+ - `undefined` → `void 0` (in expression position)
135
+ - `Infinity` → `1/0`
136
+ - numeric literals shortened to their shortest form (`1000000` → `1e6`, `0.5` → `.5`, etc.)
137
+ - `obj["foo"]` → `obj.foo` when the key is a valid identifier
138
+ - `{ "foo": x }` → `{ foo: x }` when safe
139
+
140
+ Combine with `format: "compact"` for full minification:
141
+
142
+ ```js
143
+ import { minify } from "yuku-codegen";
144
+
145
+ const { code } = minify(program, { format: "compact" });
146
+ ```
147
+
148
+ ## License
149
+
150
+ MIT
package/binding.js ADDED
@@ -0,0 +1,63 @@
1
+ import { createRequire } from 'node:module';
2
+ import { readFileSync } from 'node:fs';
3
+ import { execSync } from 'node:child_process';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { dirname, join } from 'node:path';
6
+
7
+ const require = createRequire(import.meta.url);
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const { platform, arch } = process;
10
+
11
+ const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-');
12
+
13
+ function isMusl() {
14
+ if (platform !== 'linux') return false;
15
+
16
+ try {
17
+ if (readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')) return true;
18
+ } catch {}
19
+
20
+ try {
21
+ const report = typeof process.report?.getReport === 'function'
22
+ ? process.report.getReport()
23
+ : null;
24
+ if (report) {
25
+ const header = typeof report === 'string' ? JSON.parse(report).header : report.header;
26
+ if (header?.glibcVersionRuntime) return false;
27
+ if (Array.isArray(report.sharedObjects) && report.sharedObjects.some(isFileMusl)) return true;
28
+ }
29
+ } catch {}
30
+
31
+ try {
32
+ return execSync('ldd --version', { encoding: 'utf8' }).includes('musl');
33
+ } catch {}
34
+
35
+ return false;
36
+ }
37
+
38
+ function loadBinding() {
39
+ const errors = [];
40
+ const libc = platform === 'linux' ? (isMusl() ? '-musl' : '-gnu') : '';
41
+ const suffix = `${platform}-${arch}${libc}`;
42
+
43
+ try {
44
+ return require(join(__dirname, '@yuku-codegen', 'binding-' + suffix, 'yuku-codegen.node'));
45
+ } catch (e) {
46
+ errors.push(e);
47
+ }
48
+
49
+ try {
50
+ return require('@yuku-codegen/binding-' + suffix + '/yuku-codegen.node');
51
+ } catch (e) {
52
+ errors.push(e);
53
+ }
54
+
55
+ throw new Error(
56
+ `Failed to load native binding for ${platform}-${arch}.\n` +
57
+ `If this persists, try removing node_modules and reinstalling.\n` +
58
+ errors.map(e => ` - ${e.message}`).join('\n'),
59
+ { cause: errors[errors.length - 1] }
60
+ );
61
+ }
62
+
63
+ export default loadBinding();