@gjsify/vite-plugin-blueprint 0.56.0 → 0.57.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/README.md CHANGED
@@ -52,6 +52,11 @@ import windowXml from './window.blp';
52
52
  const builder = Gtk.Builder.new_from_string(windowXml, -1);
53
53
  ```
54
54
 
55
+ `import Template from './window.blp?template'` is the exit for `registerClass` (ADR 0096 § 4): the same XML string on
56
+ `--app gjs` / `--app node`, and under `--gi-renderer` on `--app browser` / `--app nativescript` the projected tree,
57
+ checked against that target's renderer capability table (a refused construct fails the build naming file and line).
58
+ It is typed as an opaque `BlueprintTemplate`. On those two targets without `--gi-renderer` it is refused, naming the flag.
59
+
55
60
  Add type declarations by including `"@gjsify/vite-plugin-blueprint/types"` in your `tsconfig.json` `compilerOptions.types`.
56
61
 
57
62
  ## License
package/lib/index.d.ts CHANGED
@@ -10,6 +10,19 @@ export interface BlueprintPluginOptions {
10
10
  * A `.blp` under `node_modules` is never written, whatever this says — see `writeSidecar`.
11
11
  */
12
12
  sidecars?: boolean;
13
+ /**
14
+ * What `./x.blp?template` is on this build (ADR 0096 § 4). Unset, it is the module `./x.blp`
15
+ * is: the GtkBuilder XML, which is what `--app gjs` and `--app node` want. `renderer` makes
16
+ * it the projected tree checked against that renderer's capability table, as
17
+ * `?shared-tree&for=<renderer>` would be, so the import site names no renderer. `refusal`
18
+ * fails the build with that text: a target whose renderer is not composed has no value to
19
+ * give, and the XML string would be the one-specifier-two-meanings ADR 0070 § 1 forbids.
20
+ */
21
+ template?: {
22
+ renderer: string;
23
+ } | {
24
+ refusal: string;
25
+ };
13
26
  }
14
27
  export { BlueprintProjectionError, RendererRefusalError } from './projection-error.js';
15
28
  export type { RefusedUse } from './projection-error.js';
package/lib/index.js CHANGED
@@ -72,6 +72,13 @@ const SHARED_TREE_PARAM = 'shared-tree';
72
72
  * import site for ADR 0070 § 1's reason — a target does not determine a renderer.
73
73
  */
74
74
  const RENDERER_PARAM = 'for';
75
+ /**
76
+ * `./x.blp?template`: the exit a `registerClass` template comes through (ADR 0096 § 4). What it
77
+ * is depends on `BlueprintPluginOptions.template`, which the build target sets, because the same
78
+ * line has to mean "the template" on every target and not "the XML" on one and "the tree" on
79
+ * another.
80
+ */
81
+ const TEMPLATE_PARAM = 'template';
75
82
  /** The specifier an import site writes: `./x.blp?shared-tree`. */
76
83
  export const SHARED_TREE_QUERY = `?${SHARED_TREE_PARAM}`;
77
84
  /**
@@ -92,10 +99,15 @@ function readId(id) {
92
99
  if (!file.endsWith('.blp'))
93
100
  return undefined;
94
101
  if (queryAt === -1)
95
- return { file, sharedTree: false };
102
+ return { file, sharedTree: false, template: false };
96
103
  const params = new URLSearchParams(id.slice(queryAt + 1));
97
104
  const renderer = params.get(RENDERER_PARAM) ?? undefined;
98
- return { file, sharedTree: params.has(SHARED_TREE_PARAM), ...(renderer === undefined ? {} : { renderer }) };
105
+ return {
106
+ file,
107
+ sharedTree: params.has(SHARED_TREE_PARAM),
108
+ template: params.has(TEMPLATE_PARAM),
109
+ ...(renderer === undefined ? {} : { renderer }),
110
+ };
99
111
  }
100
112
  /**
101
113
  * Write the sidecar beside its `.blp`, unless nothing would change.
@@ -177,7 +189,7 @@ async function refuseForRenderer(context, file, renderer, uses) {
177
189
  throw new RendererRefusalError(file, renderer, refused);
178
190
  }
179
191
  export default function blueprintPlugin(options = {}) {
180
- const { minify = false, verbose = false, sidecars = true } = options;
192
+ const { minify = false, verbose = false, sidecars = true, template } = options;
181
193
  return {
182
194
  name: 'vite-plugin-blueprint',
183
195
  // The query has to be resolved by hand: the default resolver stats the specifier, and
@@ -187,7 +199,7 @@ export default function blueprintPlugin(options = {}) {
187
199
  // the XML and the tree rather than whichever was loaded first.
188
200
  async resolveId(source, importer) {
189
201
  const asked = readId(source);
190
- if (asked === undefined || !asked.sharedTree)
202
+ if (asked === undefined || !(asked.sharedTree || asked.template))
191
203
  return null;
192
204
  const resolved = await this.resolve(asked.file, importer, { skipSelf: true });
193
205
  // The WHOLE query goes back on, not just ours: anything the host added to the
@@ -210,9 +222,22 @@ export default function blueprintPlugin(options = {}) {
210
222
  // the construct, the file and the line: `BlueprintSyntaxError` before an AST
211
223
  // exists, `BlueprintEmitError` after. That is clause 3's declared trade against
212
224
  // output that looks plausible and means something else.
225
+ // `?template` is decided before anything is read, so a refusal names the flag and
226
+ // not a parse. It is then one of the two exits below, reusing their code rather than
227
+ // a copy: the tree with the `for=` check, or the XML module.
228
+ let { sharedTree, renderer } = asked;
229
+ if (asked.template) {
230
+ if (template !== undefined && 'refusal' in template) {
231
+ throw new Error(`${asked.file}: \`?template\` has no value on this build. ${template.refusal}`);
232
+ }
233
+ if (template !== undefined) {
234
+ sharedTree = true;
235
+ renderer ??= template.renderer;
236
+ }
237
+ }
213
238
  const source = await readFile(asked.file, 'utf8');
214
239
  const ast = parseBlueprint(source, asked.file);
215
- if (asked.sharedTree) {
240
+ if (sharedTree) {
216
241
  // THE LOSSY EXIT REFUSES ITS LOSSES RATHER THAN SHIPPING THEM.
217
242
  //
218
243
  // `projectToSharedNode` declares what it dropped — ADR 0053 clause 1 calls the
@@ -229,8 +254,8 @@ export default function blueprintPlugin(options = {}) {
229
254
  const { node, lost, uses } = projectToSharedNode(ast, { gtypeName });
230
255
  if (lost.length > 0)
231
256
  throw new BlueprintProjectionError(asked.file, lost);
232
- if (asked.renderer !== undefined)
233
- await refuseForRenderer(this, asked.file, asked.renderer, uses);
257
+ if (renderer !== undefined)
258
+ await refuseForRenderer(this, asked.file, renderer, uses);
234
259
  if (verbose)
235
260
  console.log(`Projected ${asked.file} (@gjsify/blueprint)`);
236
261
  return `export default ${JSON.stringify(node)};`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/vite-plugin-blueprint",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "description": "Compile GNOME Blueprint .blp templates to GtkBuilder-XML strings with the in-repo @gjsify/blueprint parser: no blueprint-compiler, no spawn. Vite / Rollup / Rolldown compatible.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -47,7 +47,7 @@
47
47
  ],
48
48
  "license": "MIT",
49
49
  "dependencies": {
50
- "@gjsify/blueprint": "^0.56.0",
50
+ "@gjsify/blueprint": "^0.57.0",
51
51
  "minify-xml": "^4.5.2"
52
52
  },
53
53
  "peerDependencies": {
@@ -63,8 +63,8 @@
63
63
  }
64
64
  },
65
65
  "devDependencies": {
66
- "@gjsify/cli": "^0.56.0",
67
- "@gjsify/unit": "^0.56.0",
66
+ "@gjsify/cli": "^0.57.0",
67
+ "@gjsify/unit": "^0.57.0",
68
68
  "@types/node": "^25.9.2",
69
69
  "typescript": "^6.0.3",
70
70
  "vite": "^8.1.3"
@@ -32,3 +32,16 @@ declare module '*.blp?shared-tree' {
32
32
  const tree: import('@gjsify/blueprint').SharedNode;
33
33
  export default tree;
34
34
  }
35
+
36
+ /**
37
+ * The template a `registerClass` takes (ADR 0096 § 4): the XML string on `--app gjs`, the projected
38
+ * tree under `--gi-renderer`. Opaque, so application code cannot depend on which one it is.
39
+ */
40
+ declare module '*.blp?template' {
41
+ const brand: unique symbol;
42
+ export interface BlueprintTemplate {
43
+ readonly [brand]: true;
44
+ }
45
+ const template: BlueprintTemplate;
46
+ export default template;
47
+ }