@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.
- package/README.md +5 -4
- package/dist/builder.d.ts +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +6 -6
- package/dist/builder.js.map +1 -1
- package/dist/codegen/run-codegen.d.ts +3 -2
- package/dist/codegen/run-codegen.d.ts.map +1 -1
- package/dist/codegen/run-codegen.js +41 -12
- package/dist/codegen/run-codegen.js.map +1 -1
- package/dist/commands/build.d.ts +0 -4
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +0 -5
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/codegen.d.ts.map +1 -1
- package/dist/commands/codegen.js +2 -4
- package/dist/commands/codegen.js.map +1 -1
- package/dist/deploy/depends.d.ts +2 -2
- package/dist/deploy/depends.d.ts.map +1 -1
- package/dist/deploy/depends.js +30 -15
- package/dist/deploy/depends.js.map +1 -1
- package/dist/deploy/freedesktop/localize.d.ts +6 -0
- package/dist/deploy/freedesktop/localize.d.ts.map +1 -0
- package/dist/deploy/freedesktop/localize.js +107 -0
- package/dist/deploy/freedesktop/localize.js.map +1 -0
- package/dist/deploy/install-hints.d.ts.map +1 -1
- package/dist/deploy/install-hints.js +5 -0
- package/dist/deploy/install-hints.js.map +1 -1
- package/dist/deploy/nfpm/config.js +1 -1
- package/dist/deploy/nfpm/config.js.map +1 -1
- package/dist/deploy/node-runtime/elf.d.ts +1 -1
- package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
- package/dist/deploy/node-runtime/elf.js +2 -2
- package/dist/deploy/node-runtime/elf.js.map +1 -1
- package/dist/deploy/node-runtime/index.js +2 -2
- package/dist/deploy/node-runtime/index.js.map +1 -1
- package/dist/deploy/notices/collect.d.ts +3 -1
- package/dist/deploy/notices/collect.d.ts.map +1 -1
- package/dist/deploy/notices/collect.js +2 -2
- package/dist/deploy/notices/collect.js.map +1 -1
- package/dist/deploy/notices/packages.d.ts +2 -1
- package/dist/deploy/notices/packages.d.ts.map +1 -1
- package/dist/deploy/notices/packages.js +4 -27
- package/dist/deploy/notices/packages.js.map +1 -1
- package/dist/deploy/payload/icons.d.ts +7 -3
- package/dist/deploy/payload/icons.d.ts.map +1 -1
- package/dist/deploy/payload/icons.js +46 -28
- package/dist/deploy/payload/icons.js.map +1 -1
- package/dist/deploy/payload/launcher.d.ts.map +1 -1
- package/dist/deploy/payload/launcher.js +2 -0
- package/dist/deploy/payload/launcher.js.map +1 -1
- package/dist/deploy/payload/stage.d.ts +1 -1
- package/dist/deploy/payload/stage.d.ts.map +1 -1
- package/dist/deploy/payload/stage.js +23 -13
- package/dist/deploy/payload/stage.js.map +1 -1
- package/dist/deploy/run-deploy.d.ts.map +1 -1
- package/dist/deploy/run-deploy.js +149 -25
- package/dist/deploy/run-deploy.js.map +1 -1
- package/dist/deploy/settings/build-manifest.d.ts +9 -0
- package/dist/deploy/settings/build-manifest.d.ts.map +1 -0
- package/dist/deploy/settings/build-manifest.js +80 -0
- package/dist/deploy/settings/build-manifest.js.map +1 -0
- package/dist/deploy/settings/index.d.ts.map +1 -1
- package/dist/deploy/settings/index.js +9 -3
- package/dist/deploy/settings/index.js.map +1 -1
- package/dist/deploy/settings/libraries.d.ts +8 -0
- package/dist/deploy/settings/libraries.d.ts.map +1 -0
- package/dist/deploy/settings/libraries.js +39 -0
- package/dist/deploy/settings/libraries.js.map +1 -0
- package/dist/deploy/settings/paths.d.ts +3 -0
- package/dist/deploy/settings/paths.d.ts.map +1 -1
- package/dist/deploy/settings/paths.js +6 -32
- package/dist/deploy/settings/paths.js.map +1 -1
- package/dist/deploy/targets/appimage.d.ts.map +1 -1
- package/dist/deploy/targets/appimage.js +19 -13
- package/dist/deploy/targets/appimage.js.map +1 -1
- package/dist/deploy/targets/flatpak-manifest.d.ts +2 -1
- package/dist/deploy/targets/flatpak-manifest.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak-manifest.js +5 -1
- package/dist/deploy/targets/flatpak-manifest.js.map +1 -1
- package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak-source.js +30 -16
- package/dist/deploy/targets/flatpak-source.js.map +1 -1
- package/dist/deploy/tools.d.ts +6 -1
- package/dist/deploy/tools.d.ts.map +1 -1
- package/dist/deploy/tools.js +26 -1
- package/dist/deploy/tools.js.map +1 -1
- package/dist/deploy/types.d.ts +4 -4
- package/dist/deploy/types.d.ts.map +1 -1
- package/dist/deploy/types.js.map +1 -1
- package/dist/dev/icon-dir.d.ts +1 -1
- package/dist/dev/icon-dir.d.ts.map +1 -1
- package/dist/dev/icon-dir.js +20 -7
- package/dist/dev/icon-dir.js.map +1 -1
- package/dist/dev/locale-dir.d.ts +3 -0
- package/dist/dev/locale-dir.d.ts.map +1 -0
- package/dist/dev/locale-dir.js +17 -0
- package/dist/dev/locale-dir.js.map +1 -0
- package/dist/dev/runner-deps.d.ts.map +1 -1
- package/dist/dev/runner-deps.js +5 -1
- package/dist/dev/runner-deps.js.map +1 -1
- package/dist/dev/runner-main.d.ts.map +1 -1
- package/dist/dev/runner-main.js +6 -4
- package/dist/dev/runner-main.js.map +1 -1
- package/dist/dev/runner.d.ts +1 -1
- package/dist/dev/runner.d.ts.map +1 -1
- package/dist/dev/runner.js +7 -1
- package/dist/dev/runner.js.map +1 -1
- package/dist/dev/schema-dir.d.ts +1 -1
- package/dist/dev/schema-dir.d.ts.map +1 -1
- package/dist/dev/schema-dir.js +3 -1
- package/dist/dev/schema-dir.js.map +1 -1
- package/dist/dev/vite-dev-server.d.ts +1 -0
- package/dist/dev/vite-dev-server.d.ts.map +1 -1
- package/dist/dev/vite-dev-server.js.map +1 -1
- package/dist/i18n/binding-extractor.d.ts +30 -0
- package/dist/i18n/binding-extractor.d.ts.map +1 -0
- package/dist/i18n/binding-extractor.js +1324 -0
- package/dist/i18n/binding-extractor.js.map +1 -0
- package/dist/i18n/catalog-template.d.ts +3 -0
- package/dist/i18n/catalog-template.d.ts.map +1 -0
- package/dist/i18n/catalog-template.js +18 -0
- package/dist/i18n/catalog-template.js.map +1 -0
- package/dist/i18n/catalogs.d.ts +21 -0
- package/dist/i18n/catalogs.d.ts.map +1 -0
- package/dist/i18n/catalogs.js +139 -0
- package/dist/i18n/catalogs.js.map +1 -0
- package/dist/i18n/extractor-plugin.d.ts +8 -0
- package/dist/i18n/extractor-plugin.d.ts.map +1 -0
- package/dist/i18n/extractor-plugin.js +247 -0
- package/dist/i18n/extractor-plugin.js.map +1 -0
- package/dist/i18n/metadata-templates.d.ts +11 -0
- package/dist/i18n/metadata-templates.d.ts.map +1 -0
- package/dist/i18n/metadata-templates.js +11 -0
- package/dist/i18n/metadata-templates.js.map +1 -0
- package/dist/i18n/source-messages.d.ts +23 -0
- package/dist/i18n/source-messages.d.ts.map +1 -0
- package/dist/i18n/source-messages.js +403 -0
- package/dist/i18n/source-messages.js.map +1 -0
- package/dist/i18n/types.d.ts +10 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +108 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/internal/build-manifest.d.ts +20 -0
- package/dist/internal/build-manifest.d.ts.map +1 -0
- package/dist/internal/build-manifest.js +6 -0
- package/dist/internal/build-manifest.js.map +1 -0
- package/dist/internal/icon-path.d.ts +13 -0
- package/dist/internal/icon-path.d.ts.map +1 -0
- package/dist/internal/icon-path.js +86 -0
- package/dist/internal/icon-path.js.map +1 -0
- package/dist/internal/source-imports.d.ts +12 -0
- package/dist/internal/source-imports.d.ts.map +1 -0
- package/dist/internal/source-imports.js +123 -0
- package/dist/internal/source-imports.js.map +1 -0
- package/dist/mcp/client.d.ts +0 -1
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +11 -39
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/handlers.d.ts +2 -1
- package/dist/mcp/handlers.d.ts.map +1 -1
- package/dist/mcp/handlers.js.map +1 -1
- package/dist/mcp/widget-properties.d.ts.map +1 -1
- package/dist/mcp/widget-properties.js +3 -12
- package/dist/mcp/widget-properties.js.map +1 -1
- package/dist/settings/render.d.ts +10 -1
- package/dist/settings/render.d.ts.map +1 -1
- package/dist/settings/render.js +78 -20
- package/dist/settings/render.js.map +1 -1
- package/dist/settings/schema.d.ts +4 -3
- package/dist/settings/schema.d.ts.map +1 -1
- package/dist/settings/schema.js +124 -15
- package/dist/settings/schema.js.map +1 -1
- package/dist/vite-plugins/asset-emitter.d.ts +1 -1
- package/dist/vite-plugins/asset-emitter.d.ts.map +1 -1
- package/dist/vite-plugins/asset-emitter.js.map +1 -1
- package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
- package/dist/vite-plugins/asset-extensions.js +1 -0
- package/dist/vite-plugins/asset-extensions.js.map +1 -1
- package/dist/vite-plugins/asset-imports.d.ts +2 -1
- package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
- package/dist/vite-plugins/asset-imports.js +39 -28
- package/dist/vite-plugins/asset-imports.js.map +1 -1
- package/dist/vite-plugins/asset-specifier.d.ts +13 -1
- package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
- package/dist/vite-plugins/asset-specifier.js +39 -1
- package/dist/vite-plugins/asset-specifier.js.map +1 -1
- package/dist/vite-plugins/build-manifest.d.ts +5 -0
- package/dist/vite-plugins/build-manifest.d.ts.map +1 -0
- package/dist/vite-plugins/{bundled-packages.js → build-manifest.js} +20 -14
- package/dist/vite-plugins/build-manifest.js.map +1 -0
- package/dist/vite-plugins/built-url.d.ts +1 -1
- package/dist/vite-plugins/built-url.d.ts.map +1 -1
- package/dist/vite-plugins/built-url.js +37 -24
- package/dist/vite-plugins/built-url.js.map +1 -1
- package/dist/vite-plugins/i18n.d.ts +5 -0
- package/dist/vite-plugins/i18n.d.ts.map +1 -0
- package/dist/vite-plugins/i18n.js +88 -0
- package/dist/vite-plugins/i18n.js.map +1 -0
- package/dist/vite-plugins/icons.d.ts +2 -1
- package/dist/vite-plugins/icons.d.ts.map +1 -1
- package/dist/vite-plugins/icons.js +25 -12
- package/dist/vite-plugins/icons.js.map +1 -1
- package/dist/vite-plugins/index.d.ts +2 -1
- package/dist/vite-plugins/index.d.ts.map +1 -1
- package/dist/vite-plugins/index.js +9 -5
- package/dist/vite-plugins/index.js.map +1 -1
- package/dist/vite-plugins/native.d.ts.map +1 -1
- package/dist/vite-plugins/native.js +23 -4
- package/dist/vite-plugins/native.js.map +1 -1
- package/dist/vite-plugins/resource-init-module.d.ts +7 -3
- package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
- package/dist/vite-plugins/resource-init-module.js +39 -14
- package/dist/vite-plugins/resource-init-module.js.map +1 -1
- package/dist/vite-plugins/resource-shared.d.ts +3 -1
- package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
- package/dist/vite-plugins/resource-shared.js +3 -1
- package/dist/vite-plugins/resource-shared.js.map +1 -1
- package/dist/vite-plugins/resources.d.ts +1 -1
- package/dist/vite-plugins/resources.d.ts.map +1 -1
- package/dist/vite-plugins/resources.js +877 -86
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/self-contained.d.ts.map +1 -1
- package/dist/vite-plugins/self-contained.js +128 -135
- package/dist/vite-plugins/self-contained.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +6 -3
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/settings.d.ts +3 -1
- package/dist/vite-plugins/settings.d.ts.map +1 -1
- package/dist/vite-plugins/settings.js +63 -23
- package/dist/vite-plugins/settings.js.map +1 -1
- package/env.d.ts +11 -192
- package/package.json +11 -10
- package/src/builder.ts +7 -7
- package/src/codegen/run-codegen.ts +64 -15
- package/src/commands/build.ts +0 -5
- package/src/commands/codegen.ts +2 -4
- package/src/deploy/depends.ts +47 -18
- package/src/deploy/freedesktop/localize.ts +144 -0
- package/src/deploy/install-hints.ts +5 -0
- package/src/deploy/nfpm/config.ts +1 -1
- package/src/deploy/node-runtime/elf.ts +3 -3
- package/src/deploy/node-runtime/index.ts +2 -2
- package/src/deploy/notices/collect.ts +4 -2
- package/src/deploy/notices/packages.ts +5 -43
- package/src/deploy/payload/icons.ts +64 -34
- package/src/deploy/payload/launcher.ts +2 -0
- package/src/deploy/payload/stage.ts +40 -12
- package/src/deploy/run-deploy.ts +214 -24
- package/src/deploy/settings/build-manifest.ts +122 -0
- package/src/deploy/settings/index.ts +9 -4
- package/src/deploy/settings/libraries.ts +57 -0
- package/src/deploy/settings/paths.ts +10 -47
- package/src/deploy/targets/appimage.ts +32 -15
- package/src/deploy/targets/flatpak-manifest.ts +7 -1
- package/src/deploy/targets/flatpak-source.ts +42 -20
- package/src/deploy/tools.ts +35 -0
- package/src/deploy/types.ts +4 -4
- package/src/dev/icon-dir.ts +31 -7
- package/src/dev/locale-dir.ts +22 -0
- package/src/dev/runner-deps.ts +5 -1
- package/src/dev/runner-main.ts +6 -4
- package/src/dev/runner.ts +10 -2
- package/src/dev/schema-dir.ts +3 -1
- package/src/dev/vite-dev-server.ts +1 -0
- package/src/i18n/binding-extractor.ts +1969 -0
- package/src/i18n/catalog-template.ts +24 -0
- package/src/i18n/catalogs.ts +216 -0
- package/src/i18n/extractor-plugin.ts +413 -0
- package/src/i18n/metadata-templates.ts +29 -0
- package/src/i18n/source-messages.ts +608 -0
- package/src/i18n/types.ts +154 -0
- package/src/internal/build-manifest.ts +32 -0
- package/src/internal/icon-path.ts +127 -0
- package/src/internal/source-imports.ts +171 -0
- package/src/mcp/client.ts +17 -44
- package/src/mcp/handlers.ts +7 -6
- package/src/mcp/widget-properties.ts +3 -14
- package/src/settings/render.ts +113 -21
- package/src/settings/schema.ts +192 -17
- package/src/vite-plugins/asset-emitter.ts +1 -1
- package/src/vite-plugins/asset-extensions.ts +1 -0
- package/src/vite-plugins/asset-imports.ts +62 -33
- package/src/vite-plugins/asset-specifier.ts +73 -1
- package/src/vite-plugins/{bundled-packages.ts → build-manifest.ts} +30 -19
- package/src/vite-plugins/built-url.ts +49 -28
- package/src/vite-plugins/i18n.ts +146 -0
- package/src/vite-plugins/icons.ts +33 -14
- package/src/vite-plugins/index.ts +15 -5
- package/src/vite-plugins/native.ts +31 -4
- package/src/vite-plugins/resource-init-module.ts +44 -15
- package/src/vite-plugins/resource-shared.ts +4 -0
- package/src/vite-plugins/resources.ts +1397 -100
- package/src/vite-plugins/self-contained.ts +150 -169
- package/src/vite-plugins/settings-worker-env.ts +7 -3
- package/src/vite-plugins/settings.ts +89 -21
- package/dist/vite-plugins/bundled-packages.d.ts +0 -5
- package/dist/vite-plugins/bundled-packages.d.ts.map +0 -1
- package/dist/vite-plugins/bundled-packages.js.map +0 -1
package/src/settings/render.ts
CHANGED
|
@@ -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
|
-
*
|
|
6
|
-
*
|
|
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 =>
|
|
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
|
|
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 ${
|
|
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 ${
|
|
94
|
+
lines.push(`export const ${exportName} = { id: ${id}, path: null, keys: ${keysName} };`);
|
|
53
95
|
}
|
|
54
96
|
}
|
|
55
97
|
|
|
56
|
-
const first =
|
|
98
|
+
const first = named[0];
|
|
57
99
|
|
|
58
100
|
if (first !== undefined) {
|
|
59
|
-
lines.push(`export default ${
|
|
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:
|
|
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
|
|
173
|
+
const lines = [`declare module ${toJsStringLiteral(file.fileName)} {`];
|
|
134
174
|
const exportNames: string[] = [];
|
|
135
175
|
|
|
136
|
-
for (const [index,
|
|
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(
|
|
143
|
-
exportNames.push(
|
|
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
|
|
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
|
|
238
|
+
const schemas = files
|
|
161
239
|
.filter((file) => file.schemas.length > 0)
|
|
162
240
|
.map((file) => renderFileModule(file, usedNames).join("\n"));
|
|
163
241
|
|
|
164
|
-
|
|
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 };
|
package/src/settings/schema.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { sortStrings, warn } from "@gtkx/utils";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import {
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const schemaFiles =
|
|
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,
|
|
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[],
|
|
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,
|
|
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 = (
|
|
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
|
|
153
|
-
const
|
|
154
|
-
|
|
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
|
-
|
|
339
|
+
assertUniqueSchemaBasenames,
|
|
340
|
+
projectRelativeSchemaPath,
|
|
166
341
|
stageAndCompileProjectSchemas,
|
|
167
342
|
emitSchemaEnv,
|
|
168
343
|
};
|
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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) =>
|
|
91
|
+
const unbackedBinding = (parsed: ParsedModule, isV2: boolean): NamedBinding | undefined =>
|
|
92
|
+
bindings(parsed).find((binding) => isCheckedSpecifier(binding.source) && !isBacked(binding, isV2));
|
|
84
93
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
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 =
|
|
126
|
+
const lang = sourceLanguage(path);
|
|
105
127
|
|
|
106
|
-
if (lang === undefined || !isCheckedSource(path) || !
|
|
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
|
}
|