@gjsify/vite-plugin-blueprint 0.35.0 → 0.36.0
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/lib/index.d.ts +1 -0
- package/lib/index.js +21 -4
- package/lib/resolve-compiler.d.ts +27 -0
- package/lib/resolve-compiler.js +145 -0
- package/package.json +11 -2
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
2
|
import minifyXML from 'minify-xml';
|
|
3
|
+
import { formatMissingBlueprintCompiler, resolveBlueprintCompiler } from './resolve-compiler.js';
|
|
4
|
+
export { resolveBlueprintCompiler, formatMissingBlueprintCompiler } from './resolve-compiler.js';
|
|
3
5
|
export default function blueprintPlugin(options = {}) {
|
|
4
6
|
const { minify = false, verbose = false } = options;
|
|
5
7
|
return {
|
|
6
8
|
name: 'vite-plugin-blueprint',
|
|
7
9
|
async load(id) {
|
|
8
10
|
if (id.endsWith('.blp')) {
|
|
11
|
+
// Resolved per load rather than once at plugin construction, so a
|
|
12
|
+
// compiler installed mid-watch is picked up without a restart —
|
|
13
|
+
// and so the "missing" diagnostic names the .blp that wanted it.
|
|
14
|
+
const compiler = resolveBlueprintCompiler();
|
|
15
|
+
if (!compiler) {
|
|
16
|
+
throw new Error(`${id}: ${formatMissingBlueprintCompiler()}`);
|
|
17
|
+
}
|
|
9
18
|
try {
|
|
10
19
|
// Compile .blp file and get XML output directly
|
|
11
|
-
const { stdout } = await execa(
|
|
20
|
+
const { stdout } = await execa(compiler.file, [...compiler.prefixArgs, 'compile', id], {
|
|
21
|
+
// Only ever an overlay (an MSYS2 PATH prepend); undefined
|
|
22
|
+
// inherits the environment unchanged.
|
|
23
|
+
env: compiler.env,
|
|
24
|
+
});
|
|
12
25
|
if (verbose)
|
|
13
|
-
console.log(`Compiled ${id}`);
|
|
26
|
+
console.log(`Compiled ${id} (blueprint-compiler via ${compiler.source})`);
|
|
14
27
|
let xmlContent = stdout;
|
|
15
28
|
// Minify XML if option is enabled
|
|
16
29
|
if (minify) {
|
|
@@ -22,8 +35,12 @@ export default function blueprintPlugin(options = {}) {
|
|
|
22
35
|
return `export default ${JSON.stringify(xmlContent)};`;
|
|
23
36
|
}
|
|
24
37
|
catch (error) {
|
|
25
|
-
|
|
26
|
-
|
|
38
|
+
// The compiler EXISTS and refused the file, so this is a
|
|
39
|
+
// blueprint syntax/type error and its own stderr is the
|
|
40
|
+
// useful part — surface that, not an install hint the reader
|
|
41
|
+
// has already satisfied.
|
|
42
|
+
const detail = error instanceof Error ? error.stderr || error.message : String(error);
|
|
43
|
+
throw new Error(`${id}: blueprint-compiler failed (${compiler.file})\n${detail}`);
|
|
27
44
|
}
|
|
28
45
|
}
|
|
29
46
|
},
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A spawnable blueprint-compiler, plus how it was found (for `verbose`). */
|
|
2
|
+
export interface ResolvedBlueprintCompiler {
|
|
3
|
+
/** The executable to spawn. */
|
|
4
|
+
file: string;
|
|
5
|
+
/** Arguments that must precede blueprint-compiler's own (e.g. the script path). */
|
|
6
|
+
prefixArgs: string[];
|
|
7
|
+
/** Environment overlay to spawn with, or undefined to inherit unchanged. */
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
source: 'env' | 'path' | 'msys2';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Locate a usable blueprint-compiler, or null when there is none.
|
|
13
|
+
*
|
|
14
|
+
* Order: `BLUEPRINT_COMPILER` (an explicit answer always wins, and is the escape
|
|
15
|
+
* hatch for an install none of the probes below know about) → `PATH` → an MSYS2
|
|
16
|
+
* install on win32.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveBlueprintCompiler(): ResolvedBlueprintCompiler | null;
|
|
19
|
+
/**
|
|
20
|
+
* What to tell someone who has no blueprint-compiler.
|
|
21
|
+
*
|
|
22
|
+
* Names the install command for THIS platform rather than listing every one:
|
|
23
|
+
* the reader is on one host and the other two lines are noise they have to
|
|
24
|
+
* filter. `BLUEPRINT_COMPILER` is mentioned everywhere because it is the answer
|
|
25
|
+
* for any install the probes miss.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatMissingBlueprintCompiler(): string;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Where is `blueprint-compiler`, and what do we say when it is nowhere?
|
|
2
|
+
//
|
|
3
|
+
// Split out of the plugin so it is answerable in a test without a compiler
|
|
4
|
+
// installed, and because the answer is genuinely platform-shaped on Windows.
|
|
5
|
+
//
|
|
6
|
+
// The failure this replaces: the plugin called `execa('blueprint-compiler', …)`
|
|
7
|
+
// and rethrew whatever came back, so a host without it got an ExecaError stack
|
|
8
|
+
// naming the COMMAND THAT FAILED and nothing about what to install. Measured on
|
|
9
|
+
// the win11-gjsify VM, that error was read as "blueprint-compiler is a GNOME
|
|
10
|
+
// Python tool, so it is unavailable on Windows" — a conclusion that reached a
|
|
11
|
+
// docs file and stopped anyone building a `.blp` showcase there for a day. It is
|
|
12
|
+
// available; nothing said how to get it.
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
/**
|
|
16
|
+
* MSYS2 install roots to probe on win32, in order.
|
|
17
|
+
*
|
|
18
|
+
* MSYS2 is the ONLY way to get blueprint-compiler onto Windows today, and not
|
|
19
|
+
* for the reason the tool's Python-ness suggests: it is pure Python (PyPI ships
|
|
20
|
+
* a `py3-none-any` wheel), but `blueprintcompiler/gir.py` reads TYPELIBS through
|
|
21
|
+
* `GIRepository`, so it needs PyGObject — which publishes no Windows wheel, so
|
|
22
|
+
* `pip install blueprint-compiler` dies building it from source. MSYS2 is where
|
|
23
|
+
* Python, PyGObject and the typelibs arrive already fitted together.
|
|
24
|
+
*
|
|
25
|
+
* `C:\msys64` is the installer default; the `$USERPROFILE` entries cover the
|
|
26
|
+
* extracted-archive install, which is what a host without admin rights gets;
|
|
27
|
+
* `C:\tools\msys64` is Chocolatey's.
|
|
28
|
+
*/
|
|
29
|
+
const MSYS2_ROOTS = [
|
|
30
|
+
process.env.MSYS2_ROOT,
|
|
31
|
+
'C:\\msys64',
|
|
32
|
+
process.env.USERPROFILE && join(process.env.USERPROFILE, 'msys64'),
|
|
33
|
+
process.env.USERPROFILE && join(process.env.USERPROFILE, 'Tools', 'msys64'),
|
|
34
|
+
'C:\\tools\\msys64',
|
|
35
|
+
].filter((root) => typeof root === 'string' && root.length > 0);
|
|
36
|
+
/**
|
|
37
|
+
* MSYS2 environments, most-preferred first. `ucrt64` is MSYS2's own default for
|
|
38
|
+
* new installs and links the modern Universal CRT; the others are probed so an
|
|
39
|
+
* existing install is not rejected for being older.
|
|
40
|
+
*/
|
|
41
|
+
const MSYS2_ENVS = ['ucrt64', 'mingw64', 'clang64'];
|
|
42
|
+
/** Executable suffixes to try for a bare command name. Windows needs them; POSIX does not. */
|
|
43
|
+
const EXE_SUFFIXES = process.platform === 'win32' ? ['.exe', '.cmd', '.bat', ''] : [''];
|
|
44
|
+
/** First existing `<dir>/<cmd><suffix>`, or null. */
|
|
45
|
+
function findOnPath(cmd) {
|
|
46
|
+
const pathVar = process.env.PATH;
|
|
47
|
+
if (!pathVar)
|
|
48
|
+
return null;
|
|
49
|
+
const sep = process.platform === 'win32' ? ';' : ':';
|
|
50
|
+
for (const dir of pathVar.split(sep)) {
|
|
51
|
+
if (!dir)
|
|
52
|
+
continue;
|
|
53
|
+
for (const suffix of EXE_SUFFIXES) {
|
|
54
|
+
const candidate = join(dir, cmd + suffix);
|
|
55
|
+
try {
|
|
56
|
+
if (existsSync(candidate))
|
|
57
|
+
return candidate;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// An unreadable PATH entry is not an answer about `cmd`.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find an MSYS2-provided blueprint-compiler.
|
|
68
|
+
*
|
|
69
|
+
* MSYS2 installs it as a SHEBANG SCRIPT with no `.exe` beside it, which Windows
|
|
70
|
+
* cannot execute — so this returns MSYS2's own `python.exe` with the script as
|
|
71
|
+
* its first argument, rather than the script alone. `<env>/bin` is prepended to
|
|
72
|
+
* PATH because the script imports PyGObject, which loads MSYS2's libglib and its
|
|
73
|
+
* typelibs from there.
|
|
74
|
+
*
|
|
75
|
+
* Deliberately does NOT set `GI_TYPELIB_PATH` at the gjsify GTK runtime bundle:
|
|
76
|
+
* those typelibs are gvsbuild's and name `glib-2.0-0.dll` in their
|
|
77
|
+
* `shared_library` field while MSYS2 ships `libglib-2.0-0.dll`. Measured — it
|
|
78
|
+
* fails with "Failed to load shared library", and the obvious repair (put both
|
|
79
|
+
* on PATH) would load two GLib builds into one process, which is a worse problem
|
|
80
|
+
* than the one it solves.
|
|
81
|
+
*/
|
|
82
|
+
function findInMsys2() {
|
|
83
|
+
if (process.platform !== 'win32')
|
|
84
|
+
return null;
|
|
85
|
+
for (const root of MSYS2_ROOTS) {
|
|
86
|
+
for (const env of MSYS2_ENVS) {
|
|
87
|
+
const bin = join(root, env, 'bin');
|
|
88
|
+
const script = join(bin, 'blueprint-compiler');
|
|
89
|
+
const python = join(bin, 'python.exe');
|
|
90
|
+
try {
|
|
91
|
+
if (!existsSync(script) || !existsSync(python))
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
file: python,
|
|
99
|
+
prefixArgs: [script],
|
|
100
|
+
env: { PATH: `${bin};${process.env.PATH ?? ''}` },
|
|
101
|
+
source: 'msys2',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Locate a usable blueprint-compiler, or null when there is none.
|
|
109
|
+
*
|
|
110
|
+
* Order: `BLUEPRINT_COMPILER` (an explicit answer always wins, and is the escape
|
|
111
|
+
* hatch for an install none of the probes below know about) → `PATH` → an MSYS2
|
|
112
|
+
* install on win32.
|
|
113
|
+
*/
|
|
114
|
+
export function resolveBlueprintCompiler() {
|
|
115
|
+
const override = process.env.BLUEPRINT_COMPILER;
|
|
116
|
+
if (override) {
|
|
117
|
+
return { file: override, prefixArgs: [], source: 'env' };
|
|
118
|
+
}
|
|
119
|
+
const onPath = findOnPath('blueprint-compiler');
|
|
120
|
+
if (onPath) {
|
|
121
|
+
return { file: onPath, prefixArgs: [], source: 'path' };
|
|
122
|
+
}
|
|
123
|
+
return findInMsys2();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* What to tell someone who has no blueprint-compiler.
|
|
127
|
+
*
|
|
128
|
+
* Names the install command for THIS platform rather than listing every one:
|
|
129
|
+
* the reader is on one host and the other two lines are noise they have to
|
|
130
|
+
* filter. `BLUEPRINT_COMPILER` is mentioned everywhere because it is the answer
|
|
131
|
+
* for any install the probes miss.
|
|
132
|
+
*/
|
|
133
|
+
export function formatMissingBlueprintCompiler() {
|
|
134
|
+
const install = process.platform === 'win32'
|
|
135
|
+
? 'MSYS2 packages it prebuilt (it needs PyGObject, which has no Windows wheel, so pip cannot):\n' +
|
|
136
|
+
' pacman -S mingw-w64-ucrt-x86_64-blueprint-compiler mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-libadwaita\n' +
|
|
137
|
+
' An MSYS2 install under C:\\msys64, %USERPROFILE%\\msys64, %USERPROFILE%\\Tools\\msys64 or\n' +
|
|
138
|
+
' C:\\tools\\msys64 is found automatically — it does NOT need to be on PATH.'
|
|
139
|
+
: process.platform === 'darwin'
|
|
140
|
+
? 'brew install blueprint-compiler'
|
|
141
|
+
: 'sudo dnf install blueprint-compiler (Debian/Ubuntu: sudo apt install blueprint-compiler)';
|
|
142
|
+
return ('blueprint-compiler was not found, so a .blp template cannot be compiled.\n' +
|
|
143
|
+
` ${install}\n` +
|
|
144
|
+
' Or set BLUEPRINT_COMPILER to its full path.');
|
|
145
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/vite-plugin-blueprint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "Compile GNOME Blueprint .blp templates to XML strings via blueprint-compiler. Vite / Rollup / Rolldown compatible.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"types": "./lib/index.d.ts",
|
|
12
12
|
"default": "./lib/index.js"
|
|
13
13
|
},
|
|
14
|
+
"./resolve": {
|
|
15
|
+
"types": "./lib/resolve-compiler.d.ts",
|
|
16
|
+
"default": "./lib/resolve-compiler.js"
|
|
17
|
+
},
|
|
14
18
|
"./types": {
|
|
15
19
|
"types": "./types/blueprint.d.ts"
|
|
16
20
|
}
|
|
@@ -64,6 +68,11 @@
|
|
|
64
68
|
"vite": "^8.1.3"
|
|
65
69
|
},
|
|
66
70
|
"gjsify": {
|
|
67
|
-
"tier": 1
|
|
71
|
+
"tier": 1,
|
|
72
|
+
"os": {
|
|
73
|
+
"linux": "supported",
|
|
74
|
+
"darwin": "supported",
|
|
75
|
+
"win32": "supported"
|
|
76
|
+
}
|
|
68
77
|
}
|
|
69
78
|
}
|