@gtkx/cli 1.3.0 → 1.5.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.
Files changed (299) hide show
  1. package/README.md +5 -4
  2. package/dist/builder.d.ts +1 -1
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +6 -6
  5. package/dist/builder.js.map +1 -1
  6. package/dist/codegen/run-codegen.d.ts +3 -2
  7. package/dist/codegen/run-codegen.d.ts.map +1 -1
  8. package/dist/codegen/run-codegen.js +41 -12
  9. package/dist/codegen/run-codegen.js.map +1 -1
  10. package/dist/commands/build.d.ts +0 -4
  11. package/dist/commands/build.d.ts.map +1 -1
  12. package/dist/commands/build.js +0 -5
  13. package/dist/commands/build.js.map +1 -1
  14. package/dist/commands/codegen.d.ts.map +1 -1
  15. package/dist/commands/codegen.js +2 -4
  16. package/dist/commands/codegen.js.map +1 -1
  17. package/dist/deploy/depends.d.ts +2 -2
  18. package/dist/deploy/depends.d.ts.map +1 -1
  19. package/dist/deploy/depends.js +30 -15
  20. package/dist/deploy/depends.js.map +1 -1
  21. package/dist/deploy/freedesktop/localize.d.ts +6 -0
  22. package/dist/deploy/freedesktop/localize.d.ts.map +1 -0
  23. package/dist/deploy/freedesktop/localize.js +107 -0
  24. package/dist/deploy/freedesktop/localize.js.map +1 -0
  25. package/dist/deploy/install-hints.d.ts.map +1 -1
  26. package/dist/deploy/install-hints.js +5 -0
  27. package/dist/deploy/install-hints.js.map +1 -1
  28. package/dist/deploy/nfpm/config.js +1 -1
  29. package/dist/deploy/nfpm/config.js.map +1 -1
  30. package/dist/deploy/node-runtime/elf.d.ts +1 -1
  31. package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
  32. package/dist/deploy/node-runtime/elf.js +2 -2
  33. package/dist/deploy/node-runtime/elf.js.map +1 -1
  34. package/dist/deploy/node-runtime/index.js +2 -2
  35. package/dist/deploy/node-runtime/index.js.map +1 -1
  36. package/dist/deploy/notices/collect.d.ts +3 -1
  37. package/dist/deploy/notices/collect.d.ts.map +1 -1
  38. package/dist/deploy/notices/collect.js +2 -2
  39. package/dist/deploy/notices/collect.js.map +1 -1
  40. package/dist/deploy/notices/packages.d.ts +2 -1
  41. package/dist/deploy/notices/packages.d.ts.map +1 -1
  42. package/dist/deploy/notices/packages.js +4 -27
  43. package/dist/deploy/notices/packages.js.map +1 -1
  44. package/dist/deploy/payload/icons.d.ts +7 -3
  45. package/dist/deploy/payload/icons.d.ts.map +1 -1
  46. package/dist/deploy/payload/icons.js +46 -28
  47. package/dist/deploy/payload/icons.js.map +1 -1
  48. package/dist/deploy/payload/launcher.d.ts.map +1 -1
  49. package/dist/deploy/payload/launcher.js +2 -0
  50. package/dist/deploy/payload/launcher.js.map +1 -1
  51. package/dist/deploy/payload/stage.d.ts +1 -1
  52. package/dist/deploy/payload/stage.d.ts.map +1 -1
  53. package/dist/deploy/payload/stage.js +23 -13
  54. package/dist/deploy/payload/stage.js.map +1 -1
  55. package/dist/deploy/run-deploy.d.ts.map +1 -1
  56. package/dist/deploy/run-deploy.js +149 -25
  57. package/dist/deploy/run-deploy.js.map +1 -1
  58. package/dist/deploy/settings/build-manifest.d.ts +9 -0
  59. package/dist/deploy/settings/build-manifest.d.ts.map +1 -0
  60. package/dist/deploy/settings/build-manifest.js +80 -0
  61. package/dist/deploy/settings/build-manifest.js.map +1 -0
  62. package/dist/deploy/settings/index.d.ts.map +1 -1
  63. package/dist/deploy/settings/index.js +9 -3
  64. package/dist/deploy/settings/index.js.map +1 -1
  65. package/dist/deploy/settings/libraries.d.ts +8 -0
  66. package/dist/deploy/settings/libraries.d.ts.map +1 -0
  67. package/dist/deploy/settings/libraries.js +39 -0
  68. package/dist/deploy/settings/libraries.js.map +1 -0
  69. package/dist/deploy/settings/paths.d.ts +3 -0
  70. package/dist/deploy/settings/paths.d.ts.map +1 -1
  71. package/dist/deploy/settings/paths.js +6 -32
  72. package/dist/deploy/settings/paths.js.map +1 -1
  73. package/dist/deploy/targets/appimage.d.ts.map +1 -1
  74. package/dist/deploy/targets/appimage.js +19 -13
  75. package/dist/deploy/targets/appimage.js.map +1 -1
  76. package/dist/deploy/targets/flatpak-manifest.d.ts +2 -1
  77. package/dist/deploy/targets/flatpak-manifest.d.ts.map +1 -1
  78. package/dist/deploy/targets/flatpak-manifest.js +5 -1
  79. package/dist/deploy/targets/flatpak-manifest.js.map +1 -1
  80. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  81. package/dist/deploy/targets/flatpak-source.js +30 -16
  82. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  83. package/dist/deploy/tools.d.ts +6 -1
  84. package/dist/deploy/tools.d.ts.map +1 -1
  85. package/dist/deploy/tools.js +26 -1
  86. package/dist/deploy/tools.js.map +1 -1
  87. package/dist/deploy/types.d.ts +4 -4
  88. package/dist/deploy/types.d.ts.map +1 -1
  89. package/dist/deploy/types.js.map +1 -1
  90. package/dist/dev/icon-dir.d.ts +1 -1
  91. package/dist/dev/icon-dir.d.ts.map +1 -1
  92. package/dist/dev/icon-dir.js +20 -7
  93. package/dist/dev/icon-dir.js.map +1 -1
  94. package/dist/dev/locale-dir.d.ts +3 -0
  95. package/dist/dev/locale-dir.d.ts.map +1 -0
  96. package/dist/dev/locale-dir.js +17 -0
  97. package/dist/dev/locale-dir.js.map +1 -0
  98. package/dist/dev/runner-deps.d.ts.map +1 -1
  99. package/dist/dev/runner-deps.js +5 -1
  100. package/dist/dev/runner-deps.js.map +1 -1
  101. package/dist/dev/runner-main.d.ts.map +1 -1
  102. package/dist/dev/runner-main.js +6 -4
  103. package/dist/dev/runner-main.js.map +1 -1
  104. package/dist/dev/runner.d.ts +1 -1
  105. package/dist/dev/runner.d.ts.map +1 -1
  106. package/dist/dev/runner.js +7 -1
  107. package/dist/dev/runner.js.map +1 -1
  108. package/dist/dev/schema-dir.d.ts +1 -1
  109. package/dist/dev/schema-dir.d.ts.map +1 -1
  110. package/dist/dev/schema-dir.js +3 -1
  111. package/dist/dev/schema-dir.js.map +1 -1
  112. package/dist/dev/vite-dev-server.d.ts +1 -0
  113. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  114. package/dist/dev/vite-dev-server.js.map +1 -1
  115. package/dist/i18n/binding-extractor.d.ts +30 -0
  116. package/dist/i18n/binding-extractor.d.ts.map +1 -0
  117. package/dist/i18n/binding-extractor.js +1324 -0
  118. package/dist/i18n/binding-extractor.js.map +1 -0
  119. package/dist/i18n/catalog-template.d.ts +3 -0
  120. package/dist/i18n/catalog-template.d.ts.map +1 -0
  121. package/dist/i18n/catalog-template.js +18 -0
  122. package/dist/i18n/catalog-template.js.map +1 -0
  123. package/dist/i18n/catalogs.d.ts +21 -0
  124. package/dist/i18n/catalogs.d.ts.map +1 -0
  125. package/dist/i18n/catalogs.js +139 -0
  126. package/dist/i18n/catalogs.js.map +1 -0
  127. package/dist/i18n/extractor-plugin.d.ts +8 -0
  128. package/dist/i18n/extractor-plugin.d.ts.map +1 -0
  129. package/dist/i18n/extractor-plugin.js +247 -0
  130. package/dist/i18n/extractor-plugin.js.map +1 -0
  131. package/dist/i18n/metadata-templates.d.ts +11 -0
  132. package/dist/i18n/metadata-templates.d.ts.map +1 -0
  133. package/dist/i18n/metadata-templates.js +11 -0
  134. package/dist/i18n/metadata-templates.js.map +1 -0
  135. package/dist/i18n/source-messages.d.ts +23 -0
  136. package/dist/i18n/source-messages.d.ts.map +1 -0
  137. package/dist/i18n/source-messages.js +403 -0
  138. package/dist/i18n/source-messages.js.map +1 -0
  139. package/dist/i18n/types.d.ts +10 -0
  140. package/dist/i18n/types.d.ts.map +1 -0
  141. package/dist/i18n/types.js +108 -0
  142. package/dist/i18n/types.js.map +1 -0
  143. package/dist/internal/build-manifest.d.ts +20 -0
  144. package/dist/internal/build-manifest.d.ts.map +1 -0
  145. package/dist/internal/build-manifest.js +6 -0
  146. package/dist/internal/build-manifest.js.map +1 -0
  147. package/dist/internal/icon-path.d.ts +13 -0
  148. package/dist/internal/icon-path.d.ts.map +1 -0
  149. package/dist/internal/icon-path.js +86 -0
  150. package/dist/internal/icon-path.js.map +1 -0
  151. package/dist/internal/source-imports.d.ts +12 -0
  152. package/dist/internal/source-imports.d.ts.map +1 -0
  153. package/dist/internal/source-imports.js +123 -0
  154. package/dist/internal/source-imports.js.map +1 -0
  155. package/dist/mcp/client.d.ts +0 -1
  156. package/dist/mcp/client.d.ts.map +1 -1
  157. package/dist/mcp/client.js +11 -39
  158. package/dist/mcp/client.js.map +1 -1
  159. package/dist/mcp/handlers.d.ts +2 -1
  160. package/dist/mcp/handlers.d.ts.map +1 -1
  161. package/dist/mcp/handlers.js.map +1 -1
  162. package/dist/mcp/widget-properties.d.ts.map +1 -1
  163. package/dist/mcp/widget-properties.js +3 -12
  164. package/dist/mcp/widget-properties.js.map +1 -1
  165. package/dist/settings/render.d.ts +10 -1
  166. package/dist/settings/render.d.ts.map +1 -1
  167. package/dist/settings/render.js +78 -20
  168. package/dist/settings/render.js.map +1 -1
  169. package/dist/settings/schema.d.ts +4 -3
  170. package/dist/settings/schema.d.ts.map +1 -1
  171. package/dist/settings/schema.js +124 -15
  172. package/dist/settings/schema.js.map +1 -1
  173. package/dist/vite-plugins/asset-emitter.d.ts +1 -1
  174. package/dist/vite-plugins/asset-emitter.d.ts.map +1 -1
  175. package/dist/vite-plugins/asset-emitter.js.map +1 -1
  176. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  177. package/dist/vite-plugins/asset-extensions.js +1 -0
  178. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  179. package/dist/vite-plugins/asset-imports.d.ts +2 -1
  180. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  181. package/dist/vite-plugins/asset-imports.js +39 -28
  182. package/dist/vite-plugins/asset-imports.js.map +1 -1
  183. package/dist/vite-plugins/asset-specifier.d.ts +13 -1
  184. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
  185. package/dist/vite-plugins/asset-specifier.js +39 -1
  186. package/dist/vite-plugins/asset-specifier.js.map +1 -1
  187. package/dist/vite-plugins/build-manifest.d.ts +5 -0
  188. package/dist/vite-plugins/build-manifest.d.ts.map +1 -0
  189. package/dist/vite-plugins/{bundled-packages.js → build-manifest.js} +20 -14
  190. package/dist/vite-plugins/build-manifest.js.map +1 -0
  191. package/dist/vite-plugins/built-url.d.ts +1 -1
  192. package/dist/vite-plugins/built-url.d.ts.map +1 -1
  193. package/dist/vite-plugins/built-url.js +37 -24
  194. package/dist/vite-plugins/built-url.js.map +1 -1
  195. package/dist/vite-plugins/i18n.d.ts +5 -0
  196. package/dist/vite-plugins/i18n.d.ts.map +1 -0
  197. package/dist/vite-plugins/i18n.js +88 -0
  198. package/dist/vite-plugins/i18n.js.map +1 -0
  199. package/dist/vite-plugins/icons.d.ts +2 -1
  200. package/dist/vite-plugins/icons.d.ts.map +1 -1
  201. package/dist/vite-plugins/icons.js +25 -12
  202. package/dist/vite-plugins/icons.js.map +1 -1
  203. package/dist/vite-plugins/index.d.ts +2 -1
  204. package/dist/vite-plugins/index.d.ts.map +1 -1
  205. package/dist/vite-plugins/index.js +9 -5
  206. package/dist/vite-plugins/index.js.map +1 -1
  207. package/dist/vite-plugins/native.d.ts.map +1 -1
  208. package/dist/vite-plugins/native.js +23 -4
  209. package/dist/vite-plugins/native.js.map +1 -1
  210. package/dist/vite-plugins/resource-init-module.d.ts +7 -3
  211. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
  212. package/dist/vite-plugins/resource-init-module.js +39 -14
  213. package/dist/vite-plugins/resource-init-module.js.map +1 -1
  214. package/dist/vite-plugins/resource-shared.d.ts +3 -1
  215. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  216. package/dist/vite-plugins/resource-shared.js +3 -1
  217. package/dist/vite-plugins/resource-shared.js.map +1 -1
  218. package/dist/vite-plugins/resources.d.ts +1 -1
  219. package/dist/vite-plugins/resources.d.ts.map +1 -1
  220. package/dist/vite-plugins/resources.js +877 -86
  221. package/dist/vite-plugins/resources.js.map +1 -1
  222. package/dist/vite-plugins/self-contained.d.ts.map +1 -1
  223. package/dist/vite-plugins/self-contained.js +128 -135
  224. package/dist/vite-plugins/self-contained.js.map +1 -1
  225. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  226. package/dist/vite-plugins/settings-worker-env.js +6 -3
  227. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  228. package/dist/vite-plugins/settings.d.ts +3 -1
  229. package/dist/vite-plugins/settings.d.ts.map +1 -1
  230. package/dist/vite-plugins/settings.js +63 -23
  231. package/dist/vite-plugins/settings.js.map +1 -1
  232. package/env.d.ts +11 -192
  233. package/package.json +11 -10
  234. package/src/builder.ts +7 -7
  235. package/src/codegen/run-codegen.ts +64 -15
  236. package/src/commands/build.ts +0 -5
  237. package/src/commands/codegen.ts +2 -4
  238. package/src/deploy/depends.ts +47 -18
  239. package/src/deploy/freedesktop/localize.ts +144 -0
  240. package/src/deploy/install-hints.ts +5 -0
  241. package/src/deploy/nfpm/config.ts +1 -1
  242. package/src/deploy/node-runtime/elf.ts +3 -3
  243. package/src/deploy/node-runtime/index.ts +2 -2
  244. package/src/deploy/notices/collect.ts +4 -2
  245. package/src/deploy/notices/packages.ts +5 -43
  246. package/src/deploy/payload/icons.ts +64 -34
  247. package/src/deploy/payload/launcher.ts +2 -0
  248. package/src/deploy/payload/stage.ts +40 -12
  249. package/src/deploy/run-deploy.ts +214 -24
  250. package/src/deploy/settings/build-manifest.ts +122 -0
  251. package/src/deploy/settings/index.ts +9 -4
  252. package/src/deploy/settings/libraries.ts +57 -0
  253. package/src/deploy/settings/paths.ts +10 -47
  254. package/src/deploy/targets/appimage.ts +32 -15
  255. package/src/deploy/targets/flatpak-manifest.ts +7 -1
  256. package/src/deploy/targets/flatpak-source.ts +42 -20
  257. package/src/deploy/tools.ts +35 -0
  258. package/src/deploy/types.ts +4 -4
  259. package/src/dev/icon-dir.ts +31 -7
  260. package/src/dev/locale-dir.ts +22 -0
  261. package/src/dev/runner-deps.ts +5 -1
  262. package/src/dev/runner-main.ts +6 -4
  263. package/src/dev/runner.ts +10 -2
  264. package/src/dev/schema-dir.ts +3 -1
  265. package/src/dev/vite-dev-server.ts +1 -0
  266. package/src/i18n/binding-extractor.ts +1969 -0
  267. package/src/i18n/catalog-template.ts +24 -0
  268. package/src/i18n/catalogs.ts +216 -0
  269. package/src/i18n/extractor-plugin.ts +413 -0
  270. package/src/i18n/metadata-templates.ts +29 -0
  271. package/src/i18n/source-messages.ts +608 -0
  272. package/src/i18n/types.ts +154 -0
  273. package/src/internal/build-manifest.ts +32 -0
  274. package/src/internal/icon-path.ts +127 -0
  275. package/src/internal/source-imports.ts +171 -0
  276. package/src/mcp/client.ts +17 -44
  277. package/src/mcp/handlers.ts +7 -6
  278. package/src/mcp/widget-properties.ts +3 -14
  279. package/src/settings/render.ts +113 -21
  280. package/src/settings/schema.ts +192 -17
  281. package/src/vite-plugins/asset-emitter.ts +1 -1
  282. package/src/vite-plugins/asset-extensions.ts +1 -0
  283. package/src/vite-plugins/asset-imports.ts +62 -33
  284. package/src/vite-plugins/asset-specifier.ts +73 -1
  285. package/src/vite-plugins/{bundled-packages.ts → build-manifest.ts} +30 -19
  286. package/src/vite-plugins/built-url.ts +49 -28
  287. package/src/vite-plugins/i18n.ts +146 -0
  288. package/src/vite-plugins/icons.ts +33 -14
  289. package/src/vite-plugins/index.ts +15 -5
  290. package/src/vite-plugins/native.ts +31 -4
  291. package/src/vite-plugins/resource-init-module.ts +44 -15
  292. package/src/vite-plugins/resource-shared.ts +4 -0
  293. package/src/vite-plugins/resources.ts +1397 -100
  294. package/src/vite-plugins/self-contained.ts +150 -169
  295. package/src/vite-plugins/settings-worker-env.ts +7 -3
  296. package/src/vite-plugins/settings.ts +89 -21
  297. package/dist/vite-plugins/bundled-packages.d.ts +0 -5
  298. package/dist/vite-plugins/bundled-packages.d.ts.map +0 -1
  299. package/dist/vite-plugins/bundled-packages.js.map +0 -1
@@ -1,19 +1,60 @@
1
- import { upperFirst } from "@gtkx/utils";
1
+ import { camelCase, sanitizeIdentifier, upperFirst } from "@gtkx/utils";
2
2
  import type { ParsedKey, ParsedSchema, ParsedSchemaFile } from "./parser.js";
3
3
 
4
+ type NamedSchema = {
5
+ schema: ParsedSchema;
6
+ exportName: string;
7
+ };
8
+
9
+ type EnvAssetDeclarations = {
10
+ blocked: string[];
11
+ icons: string[];
12
+ legacy: string[];
13
+ resources: string[];
14
+ };
15
+
16
+ type EnvModuleOptions = {
17
+ references?: string[];
18
+ };
19
+
4
20
  const GTKX_ENV_MODULE_HEADER = `/**
5
- * GSettings schema modules generated by GTKX from the project's
6
- * \`.gschema.xml\` files. Regenerated by \`gtkx codegen\`, \`gtkx dev\`, and
7
- * \`gtkx build\`; do not edit.
21
+ * Project import declarations generated by GTKX. Regenerated by
22
+ * \`gtkx codegen\`, \`gtkx dev\`, and \`gtkx build\`; do not edit.
8
23
  */`;
9
24
 
10
25
  const ENUM_KIND = "enum";
11
26
  const FLAGS_KIND = "flags";
27
+ const ID_SEPARATOR = /[._]/;
28
+ const NAME_SEPARATOR = "_";
12
29
 
13
30
  const toJsStringLiteral = (value: string): string =>
14
31
  JSON.stringify(value).replaceAll("\u{2028}", String.raw`\u2028`).replaceAll("\u{2029}", String.raw`\u2029`);
15
32
 
16
- const getExportName = (schemaId: string): string => schemaId.replaceAll(".", "_");
33
+ const getExportName = (schemaId: string): string =>
34
+ sanitizeIdentifier(schemaId.split(ID_SEPARATOR).map((part) => camelCase(part)).join(NAME_SEPARATOR));
35
+
36
+ const collisionError = (file: ParsedSchemaFile, taken: string, schemaId: string, name: string): Error =>
37
+ new Error(
38
+ `${file.fileName} declares ${taken} and ${schemaId}, which both export \`${name}\`. ` +
39
+ "Rename one of the schema ids so that every schema in the file gets an export of its own.",
40
+ );
41
+
42
+ const getNamedSchemas = (file: ParsedSchemaFile): NamedSchema[] => {
43
+ const owners: Map<string, string> = new Map();
44
+
45
+ return file.schemas.map((schema) => {
46
+ const exportName = getExportName(schema.id);
47
+ const taken = owners.get(exportName);
48
+
49
+ if (taken !== undefined) {
50
+ throw collisionError(file, taken, schema.id, exportName);
51
+ }
52
+
53
+ owners.set(exportName, schema.id);
54
+
55
+ return { schema, exportName };
56
+ });
57
+ };
17
58
 
18
59
  const runtimeKindForKey = (key: ParsedKey): string => {
19
60
  if (key.enumId !== null) {
@@ -37,26 +78,27 @@ const getRuntimeKeys = (schema: ParsedSchema): string => {
37
78
 
38
79
  const renderRuntimeModule = (file: ParsedSchemaFile): string => {
39
80
  const lines: string[] = [];
81
+ const named = getNamedSchemas(file);
40
82
 
41
- for (const [index, schema] of file.schemas.entries()) {
83
+ for (const [index, { schema, exportName }] of named.entries()) {
42
84
  const keysName = `keys_${String(index)}`;
43
85
  const id = toJsStringLiteral(schema.id);
44
86
  lines.push(`const ${keysName} = ${getRuntimeKeys(schema)};`);
45
87
 
46
88
  if (schema.path === null) {
47
89
  lines.push(
48
- `export const ${getExportName(schema.id)} = { id: ${id}, keys: ${keysName}, ` +
90
+ `export const ${exportName} = { id: ${id}, keys: ${keysName}, ` +
49
91
  `at: (path) => ({ id: ${id}, path, keys: ${keysName} }) };`,
50
92
  );
51
93
  } else {
52
- lines.push(`export const ${getExportName(schema.id)} = { id: ${id}, path: null, keys: ${keysName} };`);
94
+ lines.push(`export const ${exportName} = { id: ${id}, path: null, keys: ${keysName} };`);
53
95
  }
54
96
  }
55
97
 
56
- const first = file.schemas[0];
98
+ const first = named[0];
57
99
 
58
100
  if (first !== undefined) {
59
- lines.push(`export default ${getExportName(first.id)};`);
101
+ lines.push(`export default ${first.exportName};`);
60
102
  }
61
103
 
62
104
  return lines.join("\n");
@@ -106,9 +148,7 @@ const boundRefTypeLines = (interfaceName: string, indent: string): string[] => [
106
148
  `${indent}keys: ${interfaceName};`,
107
149
  ];
108
150
 
109
- const renderSchemaConst = (schema: ParsedSchema, interfaceName: string): string[] => {
110
- const exportName = getExportName(schema.id);
111
-
151
+ const renderSchemaConst = ({ schema, exportName }: NamedSchema, interfaceName: string): string[] => {
112
152
  if (schema.path !== null) {
113
153
  return [
114
154
  ` const ${exportName}: {`,
@@ -130,17 +170,17 @@ const renderSchemaConst = (schema: ParsedSchema, interfaceName: string): string[
130
170
  };
131
171
 
132
172
  const renderFileModule = (file: ParsedSchemaFile, usedNames: Set<string>): string[] => {
133
- const lines = [`declare module "${file.fileName}" {`];
173
+ const lines = [`declare module ${toJsStringLiteral(file.fileName)} {`];
134
174
  const exportNames: string[] = [];
135
175
 
136
- for (const [index, schema] of file.schemas.entries()) {
176
+ for (const [index, named] of getNamedSchemas(file).entries()) {
137
177
  if (index > 0) {
138
178
  lines.push("");
139
179
  }
140
180
 
141
- const interfaceName = allocateInterfaceName(schema.id, usedNames);
142
- lines.push(...renderKeysType(interfaceName, schema), "", ...renderSchemaConst(schema, interfaceName));
143
- exportNames.push(getExportName(schema.id));
181
+ const interfaceName = allocateInterfaceName(named.schema.id, usedNames);
182
+ lines.push(...renderKeysType(interfaceName, named.schema), "", ...renderSchemaConst(named, interfaceName));
183
+ exportNames.push(named.exportName);
144
184
  }
145
185
 
146
186
  const [firstExport] = exportNames;
@@ -154,14 +194,66 @@ const renderFileModule = (file: ParsedSchemaFile, usedNames: Set<string>): strin
154
194
  return lines;
155
195
  };
156
196
 
157
- const renderEnvModule = (files: ParsedSchemaFile[]): string => {
197
+ const renderResourceModule = (specifier: string): string => [
198
+ `declare module ${toJsStringLiteral(specifier)} {`,
199
+ " const path: string;",
200
+ " export { path };",
201
+ " export default path;",
202
+ "}",
203
+ ].join("\n");
204
+
205
+ const renderIconModule = (specifier: string): string => [
206
+ `declare module ${toJsStringLiteral(specifier)} {`,
207
+ " const iconName: string;",
208
+ " export default iconName;",
209
+ "}",
210
+ ].join("\n");
211
+
212
+ const renderLegacyAssetModule = (specifier: string): string => [
213
+ `declare module ${toJsStringLiteral(specifier)} {`,
214
+ " const resourceUri: string;",
215
+ " const path: string;",
216
+ " export { path };",
217
+ " export default resourceUri;",
218
+ "}",
219
+ ].join("\n");
220
+
221
+ const renderBlockedAssetModule = (specifier: string): string => [
222
+ `declare module ${toJsStringLiteral(specifier)} {`,
223
+ " const assetImportRequiresResourceOrUrlQuery: {",
224
+ " readonly __gtkxAssetImportRequiresResourceOrUrlQuery: unique symbol;",
225
+ " };",
226
+ " export default assetImportRequiresResourceOrUrlQuery;",
227
+ "}",
228
+ ].join("\n");
229
+
230
+ const renderEnvModule = (
231
+ files: ParsedSchemaFile[],
232
+ assetDeclarations?: EnvAssetDeclarations,
233
+ options: EnvModuleOptions = {},
234
+ ): string => {
235
+ const assets = assetDeclarations ?? { blocked: [], icons: [], legacy: [], resources: [] };
158
236
  const usedNames: Set<string> = new Set();
159
237
 
160
- const blocks = files
238
+ const schemas = files
161
239
  .filter((file) => file.schemas.length > 0)
162
240
  .map((file) => renderFileModule(file, usedNames).join("\n"));
163
241
 
164
- return `${[GTKX_ENV_MODULE_HEADER, ...blocks].join("\n\n")}\n`;
242
+ const blocked = assets.blocked.map((specifier) => renderBlockedAssetModule(specifier));
243
+ const icons = assets.icons.map((specifier) => renderIconModule(specifier));
244
+ const legacy = assets.legacy.map((specifier) => renderLegacyAssetModule(specifier));
245
+ const resources = assets.resources.map((specifier) => renderResourceModule(specifier));
246
+ const references = (options.references ?? []).map((path) => `/// <reference path=${JSON.stringify(path)} />`);
247
+
248
+ return `${[
249
+ GTKX_ENV_MODULE_HEADER,
250
+ ...references,
251
+ ...blocked,
252
+ ...icons,
253
+ ...legacy,
254
+ ...resources,
255
+ ...schemas,
256
+ ].join("\n\n")}\n`;
165
257
  };
166
258
 
167
259
  export { renderRuntimeModule, renderEnvModule };
@@ -1,10 +1,28 @@
1
1
  import { sortStrings, warn } from "@gtkx/utils";
2
2
  import { createHash } from "node:crypto";
3
- import { copyFileSync, type Dirent, mkdirSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import {
4
+ copyFileSync,
5
+ type Dirent,
6
+ existsSync,
7
+ mkdirSync,
8
+ mkdtempSync,
9
+ readdirSync,
10
+ readFileSync,
11
+ realpathSync,
12
+ writeFileSync,
13
+ } from "node:fs";
4
14
  import { tmpdir } from "node:os";
5
- import { dirname, join, relative } from "node:path";
15
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
16
+ import { I18N_TYPES_FILENAME, i18nTypesPath } from "../i18n/types.js";
6
17
  import { DATA_IMPORT_PREFIX } from "../internal/data-dir.js";
18
+ import { discoverSourceImports, type SourceImport } from "../internal/source-imports.js";
7
19
  import { removeTempDir } from "../internal/staging-dir.js";
20
+ import {
21
+ isBareRelativeAsset,
22
+ isDataAsset,
23
+ parseIconSpecifier,
24
+ parseResourceSpecifier,
25
+ } from "../vite-plugins/asset-specifier.js";
8
26
  import { compileSchemas } from "./compile.js";
9
27
  import { type ParsedSchemaFile, parseSchemaXml, SchemaParseError } from "./parser.js";
10
28
  import { renderEnvModule } from "./render.js";
@@ -16,6 +34,9 @@ type SchemaEnvResult = {
16
34
 
17
35
  const SCHEMA_SUFFIX = ".gschema.xml";
18
36
  const STAGED_NAME_LENGTH = 16;
37
+ const SOURCE_DIR = "src";
38
+ const RESOURCE_QUERY = "?resource=";
39
+ const ICON_QUERY = "?icon=";
19
40
 
20
41
  const prependSchemaDir = (dir: string, existing: string | undefined): string => {
21
42
  if (existing === undefined || existing.length === 0) {
@@ -38,9 +59,150 @@ const stageSchema = (dir: string, filePath: string): void => {
38
59
 
39
60
  const toForwardSlashes = (value: string): string => value.replaceAll(/[/\\]/g, "/");
40
61
 
62
+ const projectRelativeSchemaPath = (root: string, filePath: string): string | null => {
63
+ let rel: string;
64
+
65
+ try {
66
+ rel = relative(realpathSync(root), realpathSync(filePath));
67
+ } catch {
68
+ return null;
69
+ }
70
+
71
+ if (rel === "" || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
72
+ return null;
73
+ }
74
+
75
+ return toForwardSlashes(rel);
76
+ };
77
+
41
78
  const getModuleSpecifier = (dataDirAbs: string, filePath: string): string =>
42
79
  `${DATA_IMPORT_PREFIX}/${toForwardSlashes(relative(dataDirAbs, filePath))}`;
43
80
 
81
+ const getRelativeModuleSpecifier = (filePath: string): string => `*/${basename(filePath)}`;
82
+
83
+ const sourceDirFor = (root: string): string => {
84
+ const sourceDir = join(root, SOURCE_DIR);
85
+
86
+ return existsSync(sourceDir) ? sourceDir : root;
87
+ };
88
+
89
+ const isRelativeImport = (source: string): boolean => source.startsWith("./") || source.startsWith("../");
90
+
91
+ const schemaFileFor = ({ importer, source }: SourceImport): string | null =>
92
+ isRelativeImport(source) && source.endsWith(SCHEMA_SUFFIX) ? resolve(dirname(importer), source) : null;
93
+
94
+ const findImportedSchemaFiles = (imports: SourceImport[]): string[] => {
95
+ const files = imports
96
+ .map((entry) => schemaFileFor(entry))
97
+ .filter((path): path is string => path !== null);
98
+
99
+ return sortStrings(new Set(files));
100
+ };
101
+
102
+ const legacyAssetSpecifier = (source: string): string | null =>
103
+ isDataAsset(source) ? source : null;
104
+
105
+ const blockedAssetSpecifier = (source: string): string | null => {
106
+ if (!isBareRelativeAsset(source)) {
107
+ return null;
108
+ }
109
+
110
+ const separator = source.lastIndexOf("/");
111
+ const name = source.slice(separator + 1);
112
+
113
+ if (name.includes("*")) {
114
+ throw new Error(
115
+ `Cannot generate an asset declaration for ${JSON.stringify(source)}: filenames cannot contain *`,
116
+ );
117
+ }
118
+
119
+ return `*/${name}`;
120
+ };
121
+
122
+ const resourceModuleSpecifier = (source: string): string | null => {
123
+ const parsed = parseResourceSpecifier(source);
124
+ const queryIndex = source.indexOf(RESOURCE_QUERY);
125
+
126
+ if (queryIndex === -1 || typeof parsed?.resourcePath !== "string") {
127
+ return null;
128
+ }
129
+
130
+ const query = source.slice(queryIndex);
131
+
132
+ if (query.includes("*")) {
133
+ throw new Error(
134
+ `Cannot generate an asset declaration for ${JSON.stringify(source)}: resource paths cannot contain *`,
135
+ );
136
+ }
137
+
138
+ return `*${query}`;
139
+ };
140
+
141
+ const iconModuleSpecifier = (source: string): string | null => {
142
+ const parsed = parseIconSpecifier(source);
143
+ const queryIndex = source.indexOf(ICON_QUERY);
144
+
145
+ if (queryIndex === -1 || typeof parsed?.iconName !== "string") {
146
+ return null;
147
+ }
148
+
149
+ const query = source.slice(queryIndex);
150
+
151
+ if (query.includes("*")) {
152
+ throw new Error(
153
+ `Cannot generate an asset declaration for ${JSON.stringify(source)}: icon names cannot contain *`,
154
+ );
155
+ }
156
+
157
+ return `*${query}`;
158
+ };
159
+
160
+ const findAssetModuleSpecifiers = (
161
+ imports: SourceImport[],
162
+ isV2ResourceImports: boolean,
163
+ ): { blocked: string[]; icons: string[]; legacy: string[]; resources: string[] } => {
164
+ const collect = (getSpecifier: (source: string) => string | null): string[] =>
165
+ sortStrings(new Set(imports.map((entry) => getSpecifier(entry.source)).filter((value) => value !== null)));
166
+
167
+ if (isV2ResourceImports) {
168
+ return {
169
+ blocked: collect(blockedAssetSpecifier),
170
+ icons: collect(iconModuleSpecifier),
171
+ legacy: [],
172
+ resources: collect(resourceModuleSpecifier),
173
+ };
174
+ }
175
+
176
+ return { blocked: [], icons: [], legacy: collect(legacyAssetSpecifier), resources: [] };
177
+ };
178
+
179
+ const canonicalPath = (path: string): string => {
180
+ try {
181
+ return realpathSync(path);
182
+ } catch {
183
+ return resolve(path);
184
+ }
185
+ };
186
+
187
+ const assertUniqueSchemaBasenames = (schemaFiles: string[]): void => {
188
+ const owners: Map<string, string> = new Map();
189
+ const canonicalFiles = sortStrings(new Set(schemaFiles.map((path) => canonicalPath(path))));
190
+
191
+ for (const filePath of canonicalFiles) {
192
+ const name = basename(filePath);
193
+ const owner = owners.get(name);
194
+
195
+ if (owner !== undefined && owner !== filePath) {
196
+ throw new Error(
197
+ `Cannot generate types for both ${owner} and ${filePath}: relative GSettings schema imports are ` +
198
+ `typed by basename, and both files are named ${name}. Rename one of them.`,
199
+ );
200
+ }
201
+
202
+ owners.set(name, filePath);
203
+ }
204
+ };
205
+
44
206
  const readVisibleEntries = (dir: string): Dirent[] => {
45
207
  try {
46
208
  return readdirSync(dir, { withFileTypes: true }).filter((entry) => !entry.name.startsWith("."));
@@ -71,11 +233,11 @@ const findSchemaFiles = (dataDir: string): string[] => {
71
233
  };
72
234
 
73
235
  const stageAndCompileProjectSchemas = (root: string, dataDir: string | null): string | null => {
74
- if (dataDir === null) {
75
- return null;
76
- }
77
-
78
- const schemaFiles = findSchemaFiles(join(root, dataDir));
236
+ const imports = discoverSourceImports(sourceDirFor(root));
237
+ const imported = findImportedSchemaFiles(imports);
238
+ assertUniqueSchemaBasenames(imported);
239
+ const legacy = dataDir === null ? [] : findSchemaFiles(join(root, dataDir));
240
+ const schemaFiles = sortStrings(new Set([...legacy, ...imported]));
79
241
 
80
242
  if (schemaFiles.length === 0) {
81
243
  return null;
@@ -98,9 +260,7 @@ const stageAndCompileProjectSchemas = (root: string, dataDir: string | null): st
98
260
 
99
261
  const schemaEnvPath = (rootDir: string): string => join(rootDir, "node_modules", ".gtkx", "env.d.ts");
100
262
 
101
- const parseSchemaFileOrWarn = (filePath: string, dataDirAbs: string): ParsedSchemaFile | null => {
102
- const specifier = getModuleSpecifier(dataDirAbs, filePath);
103
-
263
+ const parseSchemaFileOrWarn = (filePath: string, specifier: string): ParsedSchemaFile | null => {
104
264
  try {
105
265
  return parseSchemaXml(readFileSync(filePath, "utf8"), specifier);
106
266
  } catch (error) {
@@ -114,11 +274,11 @@ const parseSchemaFileOrWarn = (filePath: string, dataDirAbs: string): ParsedSche
114
274
  }
115
275
  };
116
276
 
117
- const parseProjectSchemas = (schemaFiles: string[], dataDirAbs: string): ParsedSchemaFile[] => {
277
+ const parseProjectSchemas = (schemaFiles: string[], specifierFor: (filePath: string) => string): ParsedSchemaFile[] => {
118
278
  const parsed: ParsedSchemaFile[] = [];
119
279
 
120
280
  for (const filePath of schemaFiles) {
121
- const result = parseSchemaFileOrWarn(filePath, dataDirAbs);
281
+ const result = parseSchemaFileOrWarn(filePath, specifierFor(filePath));
122
282
 
123
283
  if (result !== null) {
124
284
  parsed.push(result);
@@ -147,11 +307,25 @@ const didWriteChanges = (path: string, content: string): boolean => {
147
307
  return true;
148
308
  };
149
309
 
150
- const emitSchemaEnv = (rootDir: string, dataDir: string | null): SchemaEnvResult => {
310
+ const emitSchemaEnv = (
311
+ rootDir: string,
312
+ dataDir: string | null,
313
+ isV2ResourceImports = false,
314
+ ): SchemaEnvResult => {
151
315
  const dataDirAbs = dataDir === null ? null : join(rootDir, dataDir);
152
- const schemaFiles = dataDirAbs === null ? [] : findSchemaFiles(dataDirAbs);
153
- const parsed = dataDirAbs === null ? [] : parseProjectSchemas(schemaFiles, dataDirAbs);
154
- const content = renderEnvModule(parsed);
316
+ const legacyFiles = dataDirAbs === null ? [] : findSchemaFiles(dataDirAbs);
317
+ const imports = discoverSourceImports(sourceDirFor(rootDir));
318
+
319
+ const legacy = dataDirAbs === null
320
+ ? []
321
+ : parseProjectSchemas(legacyFiles, (filePath) => getModuleSpecifier(dataDirAbs, filePath));
322
+
323
+ const importedFiles = findImportedSchemaFiles(imports);
324
+ assertUniqueSchemaBasenames(importedFiles);
325
+ const imported = parseProjectSchemas(importedFiles, getRelativeModuleSpecifier);
326
+ const assets = findAssetModuleSpecifiers(imports, isV2ResourceImports);
327
+ const references = existsSync(i18nTypesPath(rootDir)) ? [`./${I18N_TYPES_FILENAME}`] : [];
328
+ const content = renderEnvModule([...legacy, ...imported], assets, { references });
155
329
  const path = schemaEnvPath(rootDir);
156
330
  const isWritten = didWriteChanges(path, content);
157
331
 
@@ -162,7 +336,8 @@ export {
162
336
  SCHEMA_SUFFIX,
163
337
  prependSchemaDir,
164
338
  stageSchema,
165
- findSchemaFiles,
339
+ assertUniqueSchemaBasenames,
340
+ projectRelativeSchemaPath,
166
341
  stageAndCompileProjectSchemas,
167
342
  emitSchemaEnv,
168
343
  };
@@ -1,5 +1,5 @@
1
1
  type AssetEmitter = {
2
- emitFile: (file: { type: "asset"; fileName: string; source: Buffer }) => void;
2
+ emitFile: (file: { type: "asset"; fileName: string; source: Buffer | string }) => void;
3
3
  };
4
4
 
5
5
  export { type AssetEmitter };
@@ -4,6 +4,7 @@ const ASSET_EXTENSIONS = [
4
4
  "jpeg",
5
5
  "gif",
6
6
  "svg",
7
+ "xpm",
7
8
  "webp",
8
9
  "webm",
9
10
  "mp4",
@@ -1,29 +1,27 @@
1
- import type { ParseResult, ParserOptions, Plugin } from "vite";
2
- import { extname } from "node:path";
1
+ import type { ConfigLoader } from "@gtkx/config";
2
+ import type { ParseResult, Plugin, UserConfig } from "vite";
3
+ import { createConfigLoader } from "@gtkx/config/internal";
3
4
  import { parseSync } from "vite";
5
+ import { sourceLanguage } from "../internal/source-imports.js";
4
6
  import { ASSET_MENTION_RE } from "./asset-extensions.js";
5
- import { DATA_PREFIX, isAssetSpecifier, isDataAsset } from "./asset-specifier.js";
7
+ import {
8
+ DATA_PREFIX,
9
+ isAssetSpecifier,
10
+ isDataAsset,
11
+ isUrlSpecifier,
12
+ parseIconSpecifier,
13
+ parseResourceSpecifier,
14
+ } from "./asset-specifier.js";
6
15
  import { RESOURCE_PATH_EXPORT } from "./resource-shared.js";
7
16
  import { stripQuery } from "./strip-query.js";
8
17
 
9
- type SourceLanguage = NonNullable<ParserOptions["lang"]>;
10
18
  type ParsedModule = ParseResult["module"];
11
19
  type ImportStatement = ParsedModule["staticImports"][number];
12
20
  type ExportStatement = ParsedModule["staticExports"][number];
13
21
  type ExportEntry = ExportStatement["entries"][number];
14
22
  type BindingEntry = { importName: { name: string | null }; isType: boolean };
15
23
  type NamedBinding = { name: string; source: string };
16
-
17
- const SOURCE_LANGUAGES: Map<string, SourceLanguage> = new Map([
18
- [".cjs", "jsx"],
19
- [".cts", "ts"],
20
- [".js", "jsx"],
21
- [".jsx", "jsx"],
22
- [".mjs", "jsx"],
23
- [".mts", "ts"],
24
- [".ts", "ts"],
25
- [".tsx", "tsx"],
26
- ]);
24
+ type PluginState = { isV2: boolean };
27
25
 
28
26
  const NODE_MODULES = /(?:^|\/)node_modules\//;
29
27
  const VIRTUAL_PREFIX = "\0";
@@ -37,8 +35,12 @@ const BUNDLE_ADVICE =
37
35
  "nothing else.";
38
36
 
39
37
  const QUERY_ADVICE =
40
- "A query suffix hands the import to the Vite asset pipeline instead of the GResource bundle; drop the " +
41
- `query to keep ${RESOURCE_BINDING}${URL_FALLBACK}`;
38
+ `A URL asset exports only its default filesystem path; import the default instead of ${RESOURCE_BINDING}.`;
39
+
40
+ const RESOURCE_ADVICE =
41
+ `A resource asset exports only its default GResource path and ${RESOURCE_BINDING}, and nothing else.`;
42
+
43
+ const ICON_ADVICE = "An icon asset exports only its default icon-theme name, and nothing else.";
42
44
 
43
45
  const RELATIVE_ADVICE =
44
46
  `Only assets imported through "${DATA_PREFIX}" are staged into the GResource bundle and export ` +
@@ -76,34 +78,54 @@ const bindings = (parsed: ParsedModule): NamedBinding[] => [
76
78
  ...parsed.staticExports.flatMap((statement) => exportBindings(statement)),
77
79
  ];
78
80
 
79
- const isBacked = ({ name, source }: NamedBinding): boolean =>
80
- isDataAsset(source) && name === RESOURCE_PATH_EXPORT;
81
+ const isBacked = ({ name, source }: NamedBinding, isV2: boolean): boolean => {
82
+ if (name !== RESOURCE_PATH_EXPORT) {
83
+ return false;
84
+ }
85
+
86
+ return isV2 ? parseResourceSpecifier(source) !== null : isDataAsset(source);
87
+ };
88
+
89
+ const isCheckedSpecifier = (source: string): boolean => isAssetSpecifier(source) || isUrlSpecifier(source);
81
90
 
82
- const unbackedBinding = (parsed: ParsedModule): NamedBinding | undefined =>
83
- bindings(parsed).find((binding) => isAssetSpecifier(binding.source) && !isBacked(binding));
91
+ const unbackedBinding = (parsed: ParsedModule, isV2: boolean): NamedBinding | undefined =>
92
+ bindings(parsed).find((binding) => isCheckedSpecifier(binding.source) && !isBacked(binding, isV2));
84
93
 
85
- const bundleAdvice = (source: string): string => {
86
- if (isDataAsset(source)) {
87
- return BUNDLE_ADVICE;
94
+ const isBundledResource = (source: string, isV2: boolean): boolean =>
95
+ isV2
96
+ ? parseResourceSpecifier(source) !== null || parseIconSpecifier(source) !== null
97
+ : isDataAsset(source);
98
+
99
+ const v2BundleAdvice = (source: string): string =>
100
+ parseIconSpecifier(source) === null ? RESOURCE_ADVICE : ICON_ADVICE;
101
+
102
+ const bundleAdvice = (source: string, isV2: boolean): string => {
103
+ if (isBundledResource(source, isV2)) {
104
+ return isV2 ? v2BundleAdvice(source) : BUNDLE_ADVICE;
105
+ }
106
+
107
+ if (isUrlSpecifier(source)) {
108
+ return QUERY_ADVICE;
88
109
  }
89
110
 
90
111
  return source.startsWith(DATA_PREFIX) ? QUERY_ADVICE : RELATIVE_ADVICE;
91
112
  };
92
113
 
93
- const unbackedBindingError = (path: string, binding: NamedBinding): Error =>
114
+ const unbackedBindingError = (path: string, binding: NamedBinding, isV2: boolean): Error =>
94
115
  new Error(
95
116
  `${path}: ${JSON.stringify(binding.source)} does not export ${JSON.stringify(binding.name)}, which ` +
96
117
  "gtkx build rejects and gtkx dev would bind as undefined. " +
97
- bundleAdvice(binding.source),
118
+ bundleAdvice(binding.source, isV2),
98
119
  );
99
120
 
100
121
  const isCheckedSource = (path: string): boolean => !path.startsWith(VIRTUAL_PREFIX) && !NODE_MODULES.test(path);
122
+ const hasCheckedAssetMention = (code: string): boolean => ASSET_MENTION_RE.test(code) || code.includes("?url");
101
123
 
102
- const checkAssetImports = (code: string, id: string): void => {
124
+ const checkAssetImports = (code: string, id: string, isV2: boolean): void => {
103
125
  const path = stripQuery(id);
104
- const lang = SOURCE_LANGUAGES.get(extname(path).toLowerCase());
126
+ const lang = sourceLanguage(path);
105
127
 
106
- if (lang === undefined || !isCheckedSource(path) || !ASSET_MENTION_RE.test(code)) {
128
+ if (lang === undefined || !isCheckedSource(path) || !hasCheckedAssetMention(code)) {
107
129
  return;
108
130
  }
109
131
 
@@ -113,20 +135,27 @@ const checkAssetImports = (code: string, id: string): void => {
113
135
  return;
114
136
  }
115
137
 
116
- const binding = unbackedBinding(parsed.module);
138
+ const binding = unbackedBinding(parsed.module, isV2);
117
139
 
118
140
  if (binding !== undefined) {
119
- throw unbackedBindingError(path, binding);
141
+ throw unbackedBindingError(path, binding, isV2);
120
142
  }
121
143
  };
122
144
 
123
- function gtkxAssetImports(): Plugin {
145
+ function gtkxAssetImports(loadConfig: ConfigLoader = createConfigLoader()): Plugin {
146
+ const state: PluginState = { isV2: false };
147
+
124
148
  return {
125
149
  name: "gtkx:asset-imports",
126
150
  enforce: "pre",
127
151
 
152
+ async config(config: UserConfig) {
153
+ const loaded = await loadConfig.load(config.root ?? process.cwd());
154
+ state.isV2 = loaded.config.future?.v2ResourceImports === true;
155
+ },
156
+
128
157
  transform(code, id) {
129
- checkAssetImports(code, id);
158
+ checkAssetImports(code, id, state.isV2);
130
159
  },
131
160
  };
132
161
  }