@gjsify/rolldown-plugin-gjsify 0.4.0 → 0.4.4

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.
@@ -1,29 +0,0 @@
1
- // For `--app browser`: redirect `@girs/*` and `gi://*` imports to an empty
2
- // module. These are GJS-specific (GObject introspection bindings / GI
3
- // protocol) with no browser equivalent. They appear transitively via
4
- // `@gjsify/unit` and similar packages that have GJS-specific code paths.
5
- //
6
- // Marking them external would leave bare specifiers in the bundle that the
7
- // browser cannot resolve at runtime; instead we resolve them to a virtual
8
- // empty ESM module so the bundle is self-contained.
9
-
10
- import type { Plugin } from 'rolldown';
11
-
12
- const GJSIMPORTS_VIRTUAL_ID = '\0gjsify-empty-gjs-import';
13
-
14
- export function gjsImportsEmptyPlugin(): Plugin {
15
- return {
16
- name: 'gjsify-gjs-imports-empty',
17
- resolveId: {
18
- order: 'pre' as const,
19
- filter: { id: /^(@girs\/|gi:\/\/)/ },
20
- handler(_source) {
21
- return { id: GJSIMPORTS_VIRTUAL_ID };
22
- },
23
- },
24
- load(id) {
25
- if (id !== GJSIMPORTS_VIRTUAL_ID) return null;
26
- return { code: 'export {}; export default {};', moduleSideEffects: false };
27
- },
28
- };
29
- }
@@ -1,91 +0,0 @@
1
- // Synchronous `globalThis.process` stub injected as a GJS bundle banner.
2
- //
3
- // Some npm packages (glob, path-scurry, readable-stream, …) access
4
- // `globalThis.process.platform` at their top-level during lazy `__esm`
5
- // initialisation — BEFORE any `import`-triggered side effects fire. A
6
- // banner runs before everything, including bundler helpers and all
7
- // bundled module code, making it the only reliable injection point for
8
- // a synchronous global that must exist from byte 1 of execution.
9
- //
10
- // Only installed if `process` is absent; the full @gjsify/process
11
- // implementation (with EventEmitter, real streams, etc.) is wired up
12
- // later via `--globals auto` (which injects @gjsify/node-globals/register/process).
13
- //
14
- // Kept as a single line: the banner runs before any source-map-aware
15
- // machinery, so newlines here would shift every line number by one. Single
16
- // line = zero source-map drift for the actual bundle code below.
17
- import type { Plugin } from 'rolldown';
18
-
19
- export const GJS_PROCESS_STUB =
20
- 'if(typeof globalThis.process==="undefined"){' +
21
- 'const _s=imports.system,_G=imports.gi.GLib;' +
22
- 'globalThis.process={' +
23
- 'platform:"linux",arch:"x64",version:"v20.0.0",' +
24
- 'env:new Proxy({},{' +
25
- 'get(_,p){return typeof p==="string"?(_G.getenv(p)??undefined):undefined},' +
26
- 'set(_,p,v){if(typeof p==="string")_G.setenv(p,String(v),true);return true},' +
27
- 'has(_,p){return typeof p==="string"&&_G.getenv(p)!==null},' +
28
- 'deleteProperty(_,p){if(typeof p==="string")_G.unsetenv(p);return true},' +
29
- 'ownKeys(){return _G.listenv()??[]},' +
30
- 'getOwnPropertyDescriptor(_,p){const v=_G.getenv(p);return v!==null?{value:v,writable:true,enumerable:true,configurable:true}:undefined}' +
31
- '}),' +
32
- 'argv:_s?.programArgs?["gjs",_s.programInvocationName||"",..._s.programArgs]:["gjs"],' +
33
- 'versions:{},config:{},' +
34
- 'cwd(){return _G.get_current_dir()||"/"},' +
35
- 'exit(c){_s.exit(c??0)},' +
36
- 'stderr:{write(s){printerr(s)}},stdout:{write(s){print(s)}},stdin:null,' +
37
- 'exitCode:undefined,' +
38
- 'nextTick(fn,...a){Promise.resolve().then(()=>fn(...a))},' +
39
- 'hrtime(t){return t?[0,0]:[0,0]},' +
40
- '};' +
41
- '}';
42
-
43
- /**
44
- * Compose the GJS process stub with the user-supplied banner so the result
45
- * is valid syntax for `gjs -m`. A leading `#!shebang` line in the user
46
- * banner is hoisted to byte 0 of the output. Any `#` character that appears
47
- * anywhere except byte 0 is a fatal SyntaxError under SpiderMonkey 128+ —
48
- * putting our process stub before the user's shebang would break the bundle.
49
- *
50
- * Output shape:
51
- * [#!shebang\n][<process-stub>\n<rest-of-user-banner>]
52
- *
53
- * Either side of the bracket may be empty; the result is always concatenated
54
- * without leading whitespace.
55
- */
56
- export function composeBanner(stub: string, userBanner: string): string {
57
- if (!userBanner) return stub;
58
- const shebangMatch = userBanner.match(/^#![^\n]*\n/);
59
- if (!shebangMatch) {
60
- return stub + '\n' + userBanner;
61
- }
62
- const shebang = shebangMatch[0];
63
- const rest = userBanner.slice(shebang.length);
64
- return shebang + stub + (rest ? '\n' + rest : '');
65
- }
66
-
67
- /**
68
- * Build a Rolldown plugin that injects the GJS process stub as a chunk
69
- * banner. Runs with `enforce: 'post'`-equivalent ordering so the stub
70
- * lands *after* any user `output.banner` value, except when the user
71
- * banner starts with a `#!shebang` line — which is hoisted to byte 0
72
- * by `composeBanner`.
73
- */
74
- export interface ProcessStubPluginOptions {
75
- /** User-supplied banner string. May contain a leading `#!shebang`. */
76
- userBanner?: string;
77
- }
78
-
79
- export function processStubPlugin(options: ProcessStubPluginOptions = {}): Plugin {
80
- const banner = composeBanner(GJS_PROCESS_STUB, options.userBanner ?? '');
81
- return {
82
- name: 'gjsify-process-stub',
83
- renderChunk: {
84
- order: 'post' as const,
85
- handler(code, chunk) {
86
- if (!chunk.isEntry) return null;
87
- return { code: banner + '\n' + code, map: null };
88
- },
89
- },
90
- };
91
- }
@@ -1,169 +0,0 @@
1
- // Per-source rewriter for node_modules files that reference
2
- // `import.meta.url`, `__dirname`, or `__filename`. Mirrors the esbuild
3
- // predecessor's logic — body is identical because the rewrite is purely
4
- // a string transform on already-loaded source. The only delta is the
5
- // host: a Rolldown `transform(code, id)` plugin instead of an esbuild
6
- // `onLoad` registered inside the PnP plugin.
7
- //
8
- // Why a separate plugin and not nested in the PnP loader, like esbuild?
9
- // Rolldown / Rollup's `transform` hooks all run in sequence on every
10
- // loaded module — there is no first-onLoad-wins race. So the PnP loader
11
- // (`@gjsify/rolldown-plugin-pnp`) is solely responsible for reading
12
- // zip-resident bytes; this plugin runs as a separate `transform` step
13
- // after the bytes have been loaded, regardless of which loader produced
14
- // them. No more F5-bug folklore.
15
-
16
- import { dirname, join, relative, resolve } from 'node:path';
17
- import type { Plugin } from 'rolldown';
18
-
19
- import { inlineStaticReads } from '../utils/inline-static-reads.js';
20
-
21
- export const REWRITE_FILTER = /\.(m?js|cjs|[cm]?tsx?)$/;
22
- const DIRNAME_DECL_RE = /(?:var|let|const)\s+__dirname\b|export\s+(?:var|let|const)\s+__dirname\b/;
23
- const FILENAME_DECL_RE = /(?:var|let|const)\s+__filename\b|export\s+(?:var|let|const)\s+__filename\b/;
24
-
25
- /** True when the rewriter wants to look at this path — node_modules + supported ext. */
26
- export function shouldRewrite(path: string): boolean {
27
- return path.includes('node_modules') && REWRITE_FILTER.test(path);
28
- }
29
-
30
- /**
31
- * Compute the directory the bundle's outfile lives in.
32
- *
33
- * For `import.meta.url` rewriting we emit a relative URL whose base is the
34
- * bundle's `import.meta.url` — so we need to know where the bundle will be
35
- * written. Both `output.file` and `output.dir` are accepted.
36
- */
37
- export function getBundleDirFromOutput(opts: { file?: string; dir?: string }): string {
38
- const outFile = opts.file ?? join(opts.dir ?? '.', 'bundle.mjs');
39
- return dirname(resolve(outFile));
40
- }
41
-
42
- /** Pick the per-file loader Rolldown should re-parse with. */
43
- function moduleTypeForPath(path: string): 'ts' | 'js' {
44
- const ext = path.split('.').pop() ?? 'js';
45
- return ['ts', 'mts', 'cts', 'tsx'].includes(ext) ? 'ts' : 'js';
46
- }
47
-
48
- interface PreambleArgs {
49
- needDirname: boolean;
50
- needFilename: boolean;
51
- dirnameDeclared: boolean;
52
- filenameDeclared: boolean;
53
- /** kind of rewrite: 'esm-relative' | 'esm-zip' | 'cjs-absolute' */
54
- kind: 'esm-relative' | 'esm-zip' | 'cjs-absolute';
55
- sourcePath: string;
56
- sourceDir: string;
57
- relDirWithSlash: string;
58
- relPath: string;
59
- }
60
-
61
- function buildDirFilenamePreamble(args: PreambleArgs): string[] {
62
- const lines: string[] = [];
63
- if (args.needDirname && !args.dirnameDeclared) {
64
- if (args.kind === 'esm-zip') {
65
- lines.push(`var __dirname = new URL(".", import.meta.url).pathname.replace(/\\/$/, "");`);
66
- } else if (args.kind === 'esm-relative') {
67
- lines.push(`var __dirname = new URL(${JSON.stringify(args.relDirWithSlash)}, import.meta.url).pathname.replace(/\\/$/, "");`);
68
- } else {
69
- lines.push(`var __dirname = ${JSON.stringify(args.sourceDir)};`);
70
- }
71
- }
72
- if (args.needFilename && !args.filenameDeclared) {
73
- if (args.kind === 'esm-zip') {
74
- lines.push(`var __filename = new URL(import.meta.url).pathname;`);
75
- } else if (args.kind === 'esm-relative') {
76
- lines.push(`var __filename = new URL(${JSON.stringify(args.relPath)}, import.meta.url).pathname;`);
77
- } else {
78
- lines.push(`var __filename = ${JSON.stringify(args.sourcePath)};`);
79
- }
80
- }
81
- return lines;
82
- }
83
-
84
- export interface RewriteResult {
85
- code: string;
86
- moduleType?: 'ts' | 'js';
87
- map?: null;
88
- }
89
-
90
- /**
91
- * Pure rewriter — same body as the esbuild predecessor. Returns the rewritten
92
- * code (and module type for re-parsing) or `null` if the file doesn't reference
93
- * any of the patterns we care about.
94
- */
95
- export function rewriteContents(
96
- args: { path: string },
97
- srcInput: string,
98
- bundleDir: string,
99
- ): RewriteResult | null {
100
- if (!shouldRewrite(args.path)) return null;
101
-
102
- // Step 1: inline statically-resolvable filesystem reads.
103
- const inlined = inlineStaticReads(srcInput, args.path);
104
- const src = inlined.contents;
105
-
106
- const hasMetaUrl = src.includes('import.meta.url');
107
- const hasDirname = src.includes('__dirname');
108
- const hasFilename = src.includes('__filename');
109
-
110
- if (!hasMetaUrl && !hasDirname && !hasFilename) {
111
- if (inlined.inlined === 0) return null;
112
- return { code: src, moduleType: moduleTypeForPath(args.path) };
113
- }
114
-
115
- // Step 2: classify rewrite kind.
116
- const dir = dirname(args.path);
117
- const relPath = hasMetaUrl ? relative(bundleDir, args.path) : '';
118
- const isZipResident = hasMetaUrl && relPath.includes('.zip/');
119
- const kind: 'esm-relative' | 'esm-zip' | 'cjs-absolute' =
120
- !hasMetaUrl ? 'cjs-absolute' : isZipResident ? 'esm-zip' : 'esm-relative';
121
-
122
- const preamble = buildDirFilenamePreamble({
123
- needDirname: hasDirname,
124
- needFilename: hasFilename,
125
- dirnameDeclared: DIRNAME_DECL_RE.test(src),
126
- filenameDeclared: FILENAME_DECL_RE.test(src),
127
- kind,
128
- sourcePath: args.path,
129
- sourceDir: dir,
130
- relPath,
131
- relDirWithSlash: (relative(bundleDir, dir) || '.') + '/',
132
- });
133
-
134
- // Step 3: rewrite import.meta.url for the regular esm-relative case.
135
- let code = src;
136
- if (kind === 'esm-relative') {
137
- const runtimeFileUrl = `new URL(${JSON.stringify(relPath)}, import.meta.url)`;
138
- code = code.replace(/\bimport\.meta\.url\b/g, `${runtimeFileUrl}.href`);
139
- }
140
- if (preamble.length > 0) code = preamble.join('\n') + '\n' + code;
141
-
142
- return { code, moduleType: moduleTypeForPath(args.path) };
143
- }
144
-
145
- export interface NodeModulesPathRewriteOptions {
146
- /** Bundle output directory, derived from `output.file` / `output.dir`. */
147
- bundleDir: string;
148
- }
149
-
150
- /**
151
- * Build a Rolldown plugin that runs the path rewriter as a `transform(code, id)`
152
- * hook with `order: 'post'` — runs after the deepkit/blueprint/css pre-transforms
153
- * but still during module loading, before chunking.
154
- */
155
- export function nodeModulesPathRewritePlugin(options: NodeModulesPathRewriteOptions): Plugin {
156
- return {
157
- name: 'gjsify-node-modules-path-rewrite',
158
- transform: {
159
- order: 'post' as const,
160
- filter: { id: REWRITE_FILTER },
161
- handler(code: string, id: string) {
162
- if (!id.includes('node_modules')) return null;
163
- const result = rewriteContents({ path: id }, code, options.bundleDir);
164
- if (!result) return null;
165
- return { code: result.code, map: null };
166
- },
167
- },
168
- };
169
- }
@@ -1,93 +0,0 @@
1
- // Inject a `#!/usr/bin/env -S gjs -m` shebang at byte 0 of entry chunks.
2
- //
3
- // Rolldown's `output.banner` would also work, but a renderChunk hook with
4
- // `order: 'post'` makes ordering declarative — the shebang lands AFTER all
5
- // other banner / process-stub plugins have run, which is required because
6
- // the `#` character is only valid as the very first byte of the file under
7
- // SpiderMonkey 128+.
8
-
9
- import type { Plugin } from 'rolldown';
10
-
11
- export const GJS_SHEBANG = '#!/usr/bin/env -S gjs -m';
12
-
13
- export interface ShebangPluginOptions {
14
- enabled?: boolean;
15
- /** Override the shebang line. Defaults to `GJS_SHEBANG`. */
16
- line?: string;
17
- }
18
-
19
- /**
20
- * Strip a leading `#!…\n` from a source module. Rolldown preserves input
21
- * shebangs verbatim, which ends up embedded mid-chunk after our process-stub
22
- * banner — acorn (used by the auto-globals detector) then rejects `#` because
23
- * it's not at byte 0 anymore. Stripping at the transform stage cleans both
24
- * the analysis bundle and the final bundle; the gjsify-shebang renderChunk
25
- * step then injects the correct line for the output target.
26
- */
27
- const SHEBANG_RE = /^#![^\n]*\n/;
28
-
29
- /** Always-on plugin half: strips input shebangs regardless of output options. */
30
- export function inputShebangStripPlugin(): Plugin {
31
- return {
32
- name: 'gjsify-input-shebang-strip',
33
- transform: {
34
- order: 'pre' as const,
35
- handler(code) {
36
- if (!code.startsWith('#!')) return null;
37
- return { code: code.replace(SHEBANG_RE, ''), map: null };
38
- },
39
- },
40
- };
41
- }
42
-
43
- export function shebangPlugin(options: ShebangPluginOptions = {}): Plugin | null {
44
- if (!options.enabled) return null;
45
- const line = options.line ?? GJS_SHEBANG;
46
- return {
47
- name: 'gjsify-shebang',
48
- renderChunk: {
49
- order: 'post' as const,
50
- handler(code, chunk) {
51
- if (!chunk.isEntry) return null;
52
- if (code.startsWith('#!')) return null;
53
- return { code: line + '\n' + code, map: null };
54
- },
55
- },
56
- };
57
- }
58
-
59
- /**
60
- * Expand `${env:NAME}` and `${env:NAME:-default}` placeholders against
61
- * `process.env`. Missing without default → `''`. Used to let the shebang
62
- * config field reference build-time env vars (e.g. `GJS_CONSOLE` set by
63
- * meson-driven Flatpak builds where the GJS interpreter lives at
64
- * `/usr/bin/gjs-console`).
65
- */
66
- export function expandEnvTemplate(input: string, env: Record<string, string | undefined> = process.env): string {
67
- return input.replace(/\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g, (_match, name: string, fallback?: string) => {
68
- const value = env[name];
69
- if (value !== undefined && value !== '') return value;
70
- return fallback ?? '';
71
- });
72
- }
73
-
74
- /**
75
- * Normalize the user-facing `shebang` config value into the literal line
76
- * that should be prepended to the bundle (without trailing newline), or
77
- * `null` when shebang injection is disabled.
78
- *
79
- * `true` → default GJS shebang
80
- * `false|undefined` → null (disabled)
81
- * `"…"` → string with `${env:NAME[:-default]}` expanded
82
- *
83
- * If the resolved string does not start with `#!`, it is prefixed
84
- * automatically so users can write `"shebang": "/usr/bin/gjs -m"` instead
85
- * of `"#!/usr/bin/gjs -m"`.
86
- */
87
- export function resolveShebangLine(value: boolean | string | undefined): string | null {
88
- if (value === undefined || value === false) return null;
89
- if (value === true) return GJS_SHEBANG;
90
- const expanded = expandEnvTemplate(value);
91
- if (!expanded.trim()) return null;
92
- return expanded.startsWith('#!') ? expanded : '#!' + expanded;
93
- }
@@ -1,54 +0,0 @@
1
- // Generic "load file as JS string default export" plugin.
2
- //
3
- // Mirrors `css-as-string` but lets the user opt-in arbitrary extensions
4
- // through `bundler.loaders` config, e.g.:
5
- //
6
- // "bundler": { "loaders": { ".ui": "text", ".asm": "text" } }
7
- //
8
- // — replaces the esbuild `loader: { '.ui': 'text' }` shorthand from the
9
- // pre-Rolldown era. Rolldown does not classify unknown extensions as text
10
- // by default; without a hook it tries to parse them as JS and fails.
11
-
12
- import { readFile } from 'node:fs/promises';
13
- import type { Plugin } from 'rolldown';
14
-
15
- export interface TextLoaderPluginOptions {
16
- /**
17
- * Map of file extension (with leading `.`) → loader kind. Currently only
18
- * `'text'` is implemented; the field is shaped this way to leave room
19
- * for `'json'` / `'binary'` later without a config break.
20
- */
21
- loaders?: Record<string, 'text'>;
22
- }
23
-
24
- export function textLoaderPlugin(options: TextLoaderPluginOptions = {}): Plugin | null {
25
- const exts = Object.entries(options.loaders ?? {})
26
- .filter(([, kind]) => kind === 'text')
27
- .map(([ext]) => ext);
28
-
29
- if (exts.length === 0) return null;
30
-
31
- // Build a single regex matching any of the configured extensions:
32
- // ['.ui', '.asm'] → /\.(ui|asm)$/
33
- const escaped = exts.map((e) => e.replace(/^\./, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
34
- const filter = new RegExp(`\\.(?:${escaped.join('|')})$`);
35
-
36
- // Use the function-form `load(id)` (Rollup-compatible) rather than the
37
- // newer `load: { filter, handler }` shape. The newer shape was observed
38
- // not to claim unknown-extension files reliably under Rolldown rc.18 —
39
- // Rolldown's parser ran BEFORE the filtered handler fired and rejected
40
- // `.ui`/`.asm` content as invalid JS/JSX. Using the function form (same
41
- // as `@gjsify/vite-plugin-blueprint`'s `.blp` hook) intercepts during
42
- // module-load lookup and works under both Vite and Rolldown.
43
- return {
44
- name: 'gjsify-text-loader',
45
- async load(id: string) {
46
- if (!filter.test(id)) return null;
47
- const code = await readFile(id, 'utf8');
48
- return {
49
- code: `export default ${JSON.stringify(code)};`,
50
- moduleType: 'js' as const,
51
- };
52
- },
53
- };
54
- }
@@ -1,25 +0,0 @@
1
- // GJS console shim — bundled into GJS user builds via Rolldown's `inject`.
2
- // Uses print()/printerr() on GJS, bypassing GLib.log_structured() — no
3
- // `Gjs-Console-Message:` prefix, ANSI escapes work, output goes to
4
- // stdout/stderr instead of GLib's logging stream.
5
- //
6
- // `@gjsify/console` is resolved by the user's `gjsify build` Rolldown
7
- // run, NOT by tsc here. The bare specifier survives compilation and only
8
- // gets followed at user-build time, where the CLI's `@gjsify/node-polyfills`
9
- // dep tree has the package. tsc on this package would otherwise need the
10
- // `@gjsify/console` lib to be pre-built (build-order coupling).
11
- //
12
- // We can't reassign `globalThis.console` on SpiderMonkey 128 — the
13
- // property is non-configurable. Rolldown's `inject` option rewrites bare
14
- // `console` references to a named import from this shim instead, leaving
15
- // `globalThis.console` untouched and routing user `console.log(…)` calls
16
- // through our object.
17
- // @ts-ignore — resolved by Rolldown at user-build time, not by tsc here.
18
- import { log, info, debug, warn, error, dir, dirxml, table, time, timeEnd, timeLog, trace, assert, clear, count, countReset, group, groupCollapsed, groupEnd, profile, profileEnd, timeStamp } from '@gjsify/console';
19
-
20
- export const console = {
21
- log, info, debug, warn, error, dir, dirxml, table,
22
- time, timeEnd, timeLog, trace, assert, clear,
23
- count, countReset, group, groupCollapsed, groupEnd,
24
- profile, profileEnd, timeStamp,
25
- };
@@ -1,75 +0,0 @@
1
- // Shim for `unicorn-magic` under --app gjs.
2
- //
3
- // The upstream package gates the full API (`toPath`, `traversePathUp`,
4
- // `rootDirectory`, `execFile`, `execFileSync`) behind the `"node"`
5
- // conditional exports entry. Under --app gjs we intentionally omit
6
- // the `node` resolve-condition (cross-fetch-ponyfill ships
7
- // Node-only code under that key — see `app/gjs.ts` conditionNames
8
- // comment), so a bare `import { toPath } from 'unicorn-magic'` falls
9
- // back to `default.js` which only exposes `delay`.
10
- //
11
- // This shim mirrors the node.js entry verbatim — the underlying
12
- // `node:url`/`node:path`/`node:child_process`/`node:util` imports
13
- // route through `@gjsify/{url,path,child_process,util}` under GJS
14
- // and through real Node-internals under Node. The aliasPlugin
15
- // points `unicorn-magic` here for --app gjs builds.
16
- //
17
- // Source-of-truth: refs/unicorn-magic/node.js (when added — for
18
- // now mirrored from node_modules/unicorn-magic@0.3.0).
19
-
20
- import { promisify } from 'node:util';
21
- import { execFile as execFileCallback, execFileSync as execFileSyncOriginal } from 'node:child_process';
22
- import path from 'node:path';
23
- import { fileURLToPath } from 'node:url';
24
-
25
- const execFileOriginal = promisify(execFileCallback);
26
-
27
- export function toPath(urlOrPath) {
28
- return urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
29
- }
30
-
31
- export function rootDirectory(pathInput) {
32
- return path.parse(toPath(pathInput)).root;
33
- }
34
-
35
- export function traversePathUp(startPath) {
36
- return {
37
- *[Symbol.iterator]() {
38
- let currentPath = path.resolve(toPath(startPath));
39
- let previousPath;
40
-
41
- while (previousPath !== currentPath) {
42
- yield currentPath;
43
- previousPath = currentPath;
44
- currentPath = path.resolve(currentPath, '..');
45
- }
46
- },
47
- };
48
- }
49
-
50
- const TEN_MEGABYTES_IN_BYTES = 10 * 1024 * 1024;
51
-
52
- export async function execFile(file, arguments_, options = {}) {
53
- return execFileOriginal(file, arguments_, {
54
- maxBuffer: TEN_MEGABYTES_IN_BYTES,
55
- ...options,
56
- });
57
- }
58
-
59
- export function execFileSync(file, arguments_ = [], options = {}) {
60
- return execFileSyncOriginal(file, arguments_, {
61
- maxBuffer: TEN_MEGABYTES_IN_BYTES,
62
- ...options,
63
- });
64
- }
65
-
66
- // Re-export from default.js so the union API (delay + node helpers)
67
- // stays intact for callers that import both.
68
- export async function delay(opts: { seconds?: number; milliseconds?: number } = {}): Promise<void> {
69
- const { seconds, milliseconds } = opts;
70
- let duration: number;
71
- if (typeof seconds === 'number') duration = seconds * 1000;
72
- else if (typeof milliseconds === 'number') duration = milliseconds;
73
- else throw new TypeError('Expected an object with either `seconds` or `milliseconds`.');
74
- return new Promise<void>((resolveFn) => setTimeout(resolveFn, duration));
75
- }
package/src/types/app.ts DELETED
@@ -1 +0,0 @@
1
- export type App = 'gjs' | 'node' | 'browser';
@@ -1,3 +0,0 @@
1
- export * from './app.js';
2
- export * from './resolve-alias-options.js';
3
- export * from './plugin-options.js';
@@ -1,48 +0,0 @@
1
- import type { App } from './app.js';
2
-
3
- /** CSS handling forwarded to Rolldown / Lightning CSS. */
4
- export interface GjsifyCssOptions {
5
- /** Browserslist-compatible target list. Defaults to `['firefox60']` for `--app gjs`. */
6
- target?: string[];
7
- /** Whether to minify the emitted CSS. Defaults to bundle-level `minify`. */
8
- minify?: boolean;
9
- }
10
-
11
- export interface PluginOptions {
12
- debug?: boolean;
13
- app?: App;
14
- aliases?: Record<string, string>;
15
- /** Glob patterns to exclude when expanding entry points. */
16
- exclude?: string[];
17
- jsExtension?: string;
18
- /** Override the bundle output format. */
19
- format?: 'esm' | 'cjs';
20
- /**
21
- * Library mode — `'esm' | 'cjs'`. When set, the plugin emits an
22
- * unbundled multi-entry library suitable for republication on npm
23
- * rather than a single application bundle.
24
- */
25
- library?: 'esm' | 'cjs';
26
- /**
27
- * Inject a console shim into GJS builds that uses print()/printerr() instead
28
- * of `GLib.log_structured()`. Removes the "Gjs-Console-Message:" prefix and
29
- * lets the terminal interpret ANSI escape codes correctly. Only applies to
30
- * `--app gjs`. Defaults to `true`.
31
- */
32
- consoleShim?: boolean;
33
- /** Enable Deepkit TypeScript reflection. Defaults to `false`. */
34
- reflection?: boolean;
35
- /** CSS pipeline options forwarded to the Rolldown / Lightning CSS layer. */
36
- css?: GjsifyCssOptions;
37
- /**
38
- * Path to a pre-computed globals stub file. The stub is an ESM file
39
- * containing one `import '<pkg>/register';` per entry from the user's
40
- * `--globals` CLI flag. When set, the plugin appends the stub path to
41
- * Rolldown's inject list alongside the console shim.
42
- *
43
- * The plugin does no scanning or inference at this layer — the CLI is the
44
- * sole source of truth for which `/register` modules get included. Only
45
- * applies to `--app gjs`.
46
- */
47
- autoGlobalsInject?: string;
48
- }
@@ -1 +0,0 @@
1
- export interface ResolveAliasOptions { }
@@ -1,46 +0,0 @@
1
- import {
2
- EXTERNALS_NODE,
3
- EXTERNALS_NPM,
4
- ALIASES_GENERAL_FOR_GJS,
5
- ALIASES_NODE_FOR_GJS,
6
- ALIASES_WEB_FOR_GJS,
7
- ALIASES_GENERAL_FOR_NODE,
8
- ALIASES_GJS_FOR_NODE,
9
- ALIASES_WEB_FOR_NODE
10
- } from "@gjsify/resolve-npm";
11
-
12
- import type { ResolveAliasOptions } from '../types/index.js';
13
-
14
- export const setNodeAliasPrefix = (ALIASES: Record<string, string>) => {
15
- // Also resolve alias names with `node:${ALIAS}`
16
- for (const ALIAS in ALIASES) {
17
- if(ALIAS.startsWith('node:')) {
18
- continue
19
- }
20
- const key = `node:${ALIAS}`;
21
- if(!ALIASES[key]) ALIASES[key] = ALIASES[ALIAS];
22
- }
23
- return ALIASES;
24
- }
25
-
26
- const getAliasesGeneralForGjs = (options: ResolveAliasOptions) => ALIASES_GENERAL_FOR_GJS;
27
- const getAliasesNodeForGjs = (options: ResolveAliasOptions) => setNodeAliasPrefix(ALIASES_NODE_FOR_GJS);
28
- const getAliasesWebForGjs = (options: ResolveAliasOptions) => ALIASES_WEB_FOR_GJS;
29
-
30
- const getAliasesGeneralForNode = (options: ResolveAliasOptions) => ALIASES_GENERAL_FOR_NODE;
31
- const getAliasesGjsForNode = (options: ResolveAliasOptions) => ALIASES_GJS_FOR_NODE;
32
- const getAliasesWebForNode = (options: ResolveAliasOptions) => ALIASES_WEB_FOR_NODE;
33
-
34
- export const getAliasesForGjs = (options: ResolveAliasOptions) => {
35
- return {...getAliasesGeneralForGjs(options), ...getAliasesNodeForGjs(options), ...getAliasesWebForGjs(options) }
36
- }
37
-
38
- export const getAliasesForNode = (options: ResolveAliasOptions) => {
39
- return {...getAliasesGeneralForNode(options), ...getAliasesGjsForNode(options), ...getAliasesWebForNode(options) }
40
- }
41
-
42
- /** Array of Node.js build in module names (also with node: prefix) */
43
- export const externalNode = [...EXTERNALS_NODE, ...EXTERNALS_NODE.map(E => `node:${E}`)];
44
-
45
- /** Array of NPM module names for which we have our own implementation */
46
- export const externalNPM = [...EXTERNALS_NPM];