@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
|
@@ -1,20 +1,167 @@
|
|
|
1
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
2
|
-
import { error, info, sortStrings } from "@gtkx/utils";
|
|
3
|
-
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
1
|
+
import { createConfigLoader, resourceBasePath } from "@gtkx/config/internal";
|
|
2
|
+
import { error, info, isRecord, sortStrings } from "@gtkx/utils";
|
|
3
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, extname, isAbsolute, join, posix, relative, sep } from "node:path";
|
|
5
|
+
import { parseSync } from "vite";
|
|
5
6
|
import { resolveDataDir } from "../internal/data-dir.js";
|
|
6
7
|
import { listFilesRecursive } from "../internal/list-files.js";
|
|
7
|
-
import { loadModuleExclusively } from "../internal/module-loads.js";
|
|
8
8
|
import { runCliTool } from "../internal/run-cli-tool.js";
|
|
9
|
+
import { parseRuntimeImportsIn, sourceLanguage } from "../internal/source-imports.js";
|
|
9
10
|
import { createRetainedStagingDir, withStagingDir } from "../internal/staging-dir.js";
|
|
10
11
|
import { ASSET_RE } from "./asset-extensions.js";
|
|
11
|
-
import { DATA_PREFIX, isDataAsset } from "./asset-specifier.js";
|
|
12
|
+
import { DATA_PREFIX, isBareRelativeAsset, isDataAsset, parseIconSpecifier, parseResourceSpecifier, } from "./asset-specifier.js";
|
|
12
13
|
import { renderInitModule } from "./resource-init-module.js";
|
|
13
|
-
import { BUNDLE_FILENAME, escapeXml, fromVirtualId, isVirtual, REFRESH_EXPORT, REL_SEPARATOR, RESOURCE_PATH_EXPORT, toVirtualId, VIRTUAL_INIT, } from "./resource-shared.js";
|
|
14
|
+
import { BUNDLE_FILENAME, escapeXml, fromVirtualId, ICON_NAME_SEPARATOR, isVirtual, REFRESH_EXPORT, REGISTER_REFRESH_EXPORT, REL_SEPARATOR, RESOURCE_PATH_EXPORT, toVirtualId, VIRTUAL_INIT, } from "./resource-shared.js";
|
|
15
|
+
import { stripQuery } from "./strip-query.js";
|
|
14
16
|
const RESOURCE_COMPILER = "glib-compile-resources";
|
|
15
17
|
const MANIFEST_PREFIX = "/";
|
|
16
18
|
const DEV_STAGING_PREFIX = "resources-dev";
|
|
17
|
-
const
|
|
19
|
+
const MANIFEST_FILENAME = "package.json";
|
|
20
|
+
const BUNDLED_QUERY_MENTION_RE = /[?&](?:icon|resource)(?:[=&]|$)/;
|
|
21
|
+
const ICON_EXTENSIONS = new Set([".png", ".svg", ".xpm"]);
|
|
22
|
+
const ICON_CONTEXTS = new Set([
|
|
23
|
+
"actions",
|
|
24
|
+
"animations",
|
|
25
|
+
"apps",
|
|
26
|
+
"categories",
|
|
27
|
+
"devices",
|
|
28
|
+
"emblems",
|
|
29
|
+
"emotes",
|
|
30
|
+
"filesystems",
|
|
31
|
+
"intl",
|
|
32
|
+
"mimetypes",
|
|
33
|
+
"places",
|
|
34
|
+
"status",
|
|
35
|
+
]);
|
|
36
|
+
const STOCK_ICON_CONTEXTS = new Set([
|
|
37
|
+
"chart",
|
|
38
|
+
"code",
|
|
39
|
+
"data",
|
|
40
|
+
"form",
|
|
41
|
+
"image",
|
|
42
|
+
"io",
|
|
43
|
+
"media",
|
|
44
|
+
"navigation",
|
|
45
|
+
"net",
|
|
46
|
+
"object",
|
|
47
|
+
"table",
|
|
48
|
+
"text",
|
|
49
|
+
]);
|
|
50
|
+
const ICON_SIZE_RE = /^([1-9]\d*)x\1(?:@[1-9]\d*)?$/;
|
|
51
|
+
const RESERVED_ICON_NAMES = new Set(["", ".", ".."]);
|
|
52
|
+
const toForwardSlashes = (value) => value.replaceAll(/[/\\]/g, "/");
|
|
53
|
+
const isWithin = (root, path) => {
|
|
54
|
+
const rel = relative(root, path);
|
|
55
|
+
return rel.length > 0 && !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
|
|
56
|
+
};
|
|
57
|
+
const isDependencyFile = (root, path) => isWithin(root, path) && relative(root, path).split(sep).includes("node_modules");
|
|
58
|
+
const packageIdentityIn = (dir) => {
|
|
59
|
+
try {
|
|
60
|
+
const manifest = JSON.parse(readFileSync(join(dir, MANIFEST_FILENAME), "utf8"));
|
|
61
|
+
return isRecord(manifest) && typeof manifest.name === "string" ? manifest.name : null;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const packageIn = (dir) => {
|
|
68
|
+
const name = packageIdentityIn(dir);
|
|
69
|
+
if (name !== null) {
|
|
70
|
+
return { dir, name };
|
|
71
|
+
}
|
|
72
|
+
const parent = dirname(dir);
|
|
73
|
+
return parent === dir ? null : packageIn(parent);
|
|
74
|
+
};
|
|
75
|
+
const packageForFile = (file) => packageIn(dirname(file));
|
|
76
|
+
const validateResourcePath = (resourcePath) => {
|
|
77
|
+
if (resourcePath === "/" ||
|
|
78
|
+
!resourcePath.startsWith("/") ||
|
|
79
|
+
resourcePath.endsWith("/") ||
|
|
80
|
+
resourcePath.includes("\0") ||
|
|
81
|
+
posix.normalize(resourcePath) !== resourcePath) {
|
|
82
|
+
throw new Error(`${JSON.stringify(resourcePath)} is not a valid GResource path; use an absolute normalized path`);
|
|
83
|
+
}
|
|
84
|
+
return resourcePath;
|
|
85
|
+
};
|
|
86
|
+
const derivedResourcePath = (state, sourcePath) => {
|
|
87
|
+
if (isWithin(state.root, sourcePath) && !isDependencyFile(state.root, sourcePath)) {
|
|
88
|
+
return validateResourcePath(`${state.prefix}/${toForwardSlashes(relative(state.root, sourcePath))}`);
|
|
89
|
+
}
|
|
90
|
+
const owner = packageForFile(sourcePath);
|
|
91
|
+
if (owner === null || !isWithin(owner.dir, sourcePath)) {
|
|
92
|
+
throw new Error(`${sourcePath} is outside the application and does not belong to a named package`);
|
|
93
|
+
}
|
|
94
|
+
const packagePath = toForwardSlashes(relative(owner.dir, sourcePath));
|
|
95
|
+
return validateResourcePath(`${state.prefix}/${owner.name}/${packagePath}`);
|
|
96
|
+
};
|
|
97
|
+
const iconExtension = (sourcePath) => {
|
|
98
|
+
const extension = extname(sourcePath).toLowerCase();
|
|
99
|
+
if (!ICON_EXTENSIONS.has(extension)) {
|
|
100
|
+
throw new Error(`${sourcePath} is not a supported themed icon; use an SVG, PNG, or XPM file`);
|
|
101
|
+
}
|
|
102
|
+
return extension;
|
|
103
|
+
};
|
|
104
|
+
const hasIconNamePathSeparator = (value) => value.includes("\0") || value.includes("/") || value.includes("\\");
|
|
105
|
+
const validateIconName = (value) => {
|
|
106
|
+
if (RESERVED_ICON_NAMES.has(value) ||
|
|
107
|
+
hasIconNamePathSeparator(value) ||
|
|
108
|
+
ICON_EXTENSIONS.has(extname(value).toLowerCase())) {
|
|
109
|
+
throw new Error(`${JSON.stringify(value)} is not a valid icon name; use an extensionless filename without slashes`);
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
};
|
|
113
|
+
const isIconContext = (parts) => {
|
|
114
|
+
const [first, second] = parts;
|
|
115
|
+
if (parts.length === 1) {
|
|
116
|
+
return first !== undefined && ICON_CONTEXTS.has(first);
|
|
117
|
+
}
|
|
118
|
+
return parts.length === 2 && first === "stock" && second !== undefined && STOCK_ICON_CONTEXTS.has(second);
|
|
119
|
+
};
|
|
120
|
+
const isIconLayout = (parts) => {
|
|
121
|
+
const [size, ...context] = parts;
|
|
122
|
+
if (size === "symbolic") {
|
|
123
|
+
return context.length === 1 && context[0] === "apps";
|
|
124
|
+
}
|
|
125
|
+
return size !== undefined && (size === "scalable" || ICON_SIZE_RE.test(size)) && isIconContext(context);
|
|
126
|
+
};
|
|
127
|
+
const iconLayoutInParts = (parts, beforeIndex) => {
|
|
128
|
+
const index = parts.lastIndexOf("icons", beforeIndex);
|
|
129
|
+
if (index === -1) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const treePath = parts.slice(index + 1, -1);
|
|
133
|
+
const layout = treePath[0] === "hicolor" ? treePath.slice(1) : treePath;
|
|
134
|
+
return isIconLayout(layout) ? layout.join("/") : iconLayoutInParts(parts, index - 1);
|
|
135
|
+
};
|
|
136
|
+
const iconLayoutFromTree = (sourcePath) => {
|
|
137
|
+
const parts = toForwardSlashes(sourcePath).split("/");
|
|
138
|
+
return iconLayoutInParts(parts, parts.length - 2);
|
|
139
|
+
};
|
|
140
|
+
const derivedIconEntry = (state, sourcePath, requestedName) => {
|
|
141
|
+
const extension = iconExtension(sourcePath);
|
|
142
|
+
const sourceName = basename(sourcePath, extname(sourcePath));
|
|
143
|
+
const iconName = validateIconName(requestedName ?? sourceName);
|
|
144
|
+
const layout = iconLayoutFromTree(sourcePath);
|
|
145
|
+
const iconIdentity = layout === null
|
|
146
|
+
? `${state.prefix}/icons/${iconName}`
|
|
147
|
+
: `${state.prefix}/icons/${layout}/${iconName}`;
|
|
148
|
+
const resourcePath = validateResourcePath(`${iconIdentity}${extension}`);
|
|
149
|
+
return { iconIdentity, iconName, resourcePath };
|
|
150
|
+
};
|
|
151
|
+
const hasSideEffectIconImport = (code, id) => {
|
|
152
|
+
const lang = sourceLanguage(stripQuery(id));
|
|
153
|
+
if (lang === undefined || !code.includes("?icon")) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
const parsed = parseSync(id, code, { lang });
|
|
157
|
+
if (parsed.errors.length > 0) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return parsed.module.staticImports.some((statement) => statement.entries.length === 0 && parseIconSpecifier(statement.moduleRequest.value) !== null);
|
|
161
|
+
};
|
|
162
|
+
const retainSideEffectIconImport = (state, code, id) => state.isV2 && hasSideEffectIconImport(code, id)
|
|
163
|
+
? { code, moduleSideEffects: true }
|
|
164
|
+
: null;
|
|
18
165
|
const compileBundle = (state, outputPath) => withStagingDir("resources", (dir) => {
|
|
19
166
|
const manifest = stageBundle(dir, state.entries);
|
|
20
167
|
return runCompiler(dir, manifest, outputPath);
|
|
@@ -56,29 +203,30 @@ const releaseStagingDir = (state) => {
|
|
|
56
203
|
state.devBundlePath = "";
|
|
57
204
|
state.compiledSignature = "";
|
|
58
205
|
};
|
|
59
|
-
const entriesSignature = (state) => sortStrings(state.entries.
|
|
206
|
+
const entriesSignature = (state) => sortStrings([...state.entries].map(([resourcePath, entry]) => `${resourcePath}\0${entry.sourcePath}`)).join("\0");
|
|
60
207
|
const compileDevBundle = (state) => {
|
|
61
208
|
ensureStagingDir(state);
|
|
62
209
|
if (state.entries.size === 0) {
|
|
210
|
+
rmSync(state.devBundlePath, { force: true });
|
|
211
|
+
state.compiledSignature = "";
|
|
63
212
|
return;
|
|
64
213
|
}
|
|
65
214
|
compileBundle(state, state.devBundlePath);
|
|
66
215
|
state.compiledSignature = entriesSignature(state);
|
|
67
216
|
};
|
|
68
217
|
const isRefreshHook = (value) => typeof value === "function";
|
|
69
|
-
const
|
|
218
|
+
const refreshRegisteredDevBundle = (state) => {
|
|
70
219
|
const server = state.server;
|
|
71
220
|
if (!server) {
|
|
72
221
|
return;
|
|
73
222
|
}
|
|
74
|
-
const
|
|
75
|
-
const refresh = mod[REFRESH_EXPORT];
|
|
223
|
+
const refresh = server.moduleGraph.getModuleById(VIRTUAL_INIT)?.ssrModule?.[REFRESH_EXPORT];
|
|
76
224
|
if (isRefreshHook(refresh)) {
|
|
77
225
|
refresh();
|
|
78
226
|
}
|
|
79
227
|
};
|
|
80
228
|
const scanDataAssets = (dataDir) => listFilesRecursive(dataDir, (name) => ASSET_RE.test(name));
|
|
81
|
-
const
|
|
229
|
+
const primeLegacyDevBundle = (state) => {
|
|
82
230
|
if (state.dataDir === null) {
|
|
83
231
|
return;
|
|
84
232
|
}
|
|
@@ -92,102 +240,650 @@ const registerDevAsset = (state) => {
|
|
|
92
240
|
compileDevBundle(state);
|
|
93
241
|
}
|
|
94
242
|
};
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
if (
|
|
243
|
+
const importerKey = (importer) => stripQuery(importer);
|
|
244
|
+
const trackBundledSpecifier = (state, importer, source) => {
|
|
245
|
+
if (importer === undefined) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const key = importerKey(importer);
|
|
249
|
+
const specifiers = state.bundledSpecifiers.get(key) ?? new Set();
|
|
250
|
+
specifiers.add(source);
|
|
251
|
+
state.bundledSpecifiers.set(key, specifiers);
|
|
252
|
+
};
|
|
253
|
+
const createResourceEntry = (sourcePath, resourcePath) => ({
|
|
254
|
+
sourcePath,
|
|
255
|
+
stagedRelPath: resourcePath.replace(/^\/+/, ""),
|
|
256
|
+
resourcePath,
|
|
257
|
+
});
|
|
258
|
+
const activateEntry = (state, entry) => {
|
|
259
|
+
const existing = state.entries.get(entry.resourcePath);
|
|
260
|
+
if (existing !== undefined) {
|
|
261
|
+
if (existing.sourcePath !== entry.sourcePath) {
|
|
262
|
+
throw new Error(`${existing.sourcePath} and ${entry.sourcePath} both resolve to the GResource path ` +
|
|
263
|
+
entry.resourcePath);
|
|
264
|
+
}
|
|
98
265
|
return existing;
|
|
99
266
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
267
|
+
state.entries.set(entry.resourcePath, entry);
|
|
268
|
+
state.sourcePaths.add(entry.sourcePath);
|
|
269
|
+
return entry;
|
|
270
|
+
};
|
|
271
|
+
const isDeclarativeImporter = (state, importer) => !state.isBuild && state.isV2 && importer !== undefined;
|
|
272
|
+
const setSourceAvailability = (state, file, isAvailable) => {
|
|
273
|
+
if (isAvailable) {
|
|
274
|
+
state.missingSourcePaths.delete(file);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
state.missingSourcePaths.add(file);
|
|
278
|
+
};
|
|
279
|
+
const isDeclaredSourceAvailable = (state, sourcePath) => {
|
|
280
|
+
const isAvailable = existsSync(sourcePath);
|
|
281
|
+
setSourceAvailability(state, sourcePath, isAvailable);
|
|
282
|
+
return isAvailable;
|
|
283
|
+
};
|
|
284
|
+
const declareEntry = (state, importer, entry) => {
|
|
285
|
+
const key = importerKey(importer);
|
|
286
|
+
const declarations = state.declaredEntries.get(key) ?? new Map();
|
|
287
|
+
const existing = declarations.get(entry.resourcePath);
|
|
288
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
289
|
+
throw new Error(`${existing.sourcePath} and ${entry.sourcePath} both resolve to the GResource path ` +
|
|
290
|
+
entry.resourcePath);
|
|
291
|
+
}
|
|
292
|
+
const declared = existing ?? entry;
|
|
293
|
+
declarations.set(entry.resourcePath, declared);
|
|
294
|
+
state.declaredEntries.set(key, declarations);
|
|
295
|
+
state.server?.watcher.add(dirname(declared.sourcePath));
|
|
296
|
+
return declared;
|
|
297
|
+
};
|
|
298
|
+
const declareIcon = (state, importer, iconIdentity, entry) => {
|
|
299
|
+
const key = importerKey(importer);
|
|
300
|
+
const declarations = state.declaredIcons.get(key) ?? new Map();
|
|
301
|
+
const existing = declarations.get(iconIdentity);
|
|
302
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
303
|
+
throw new Error(`${existing.sourcePath} and ${entry.sourcePath} both claim the themed icon ${iconIdentity}`);
|
|
304
|
+
}
|
|
305
|
+
declarations.set(iconIdentity, existing ?? entry);
|
|
306
|
+
state.declaredIcons.set(key, declarations);
|
|
307
|
+
};
|
|
308
|
+
const assertIconIdentityAvailable = (state, iconIdentity, sourcePath) => {
|
|
309
|
+
const existing = state.iconOwners.get(iconIdentity);
|
|
310
|
+
if (existing !== undefined && existing.sourcePath !== sourcePath) {
|
|
311
|
+
throw new Error(`${existing.sourcePath} and ${sourcePath} both claim the themed icon ${iconIdentity}`);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
const declareResolvedIcon = (state, importer, iconIdentity, entry) => {
|
|
315
|
+
if (isDeclarativeImporter(state, importer)) {
|
|
316
|
+
declareIcon(state, importer, iconIdentity, entry);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const registerEntry = (state, absPath, rel, importer) => {
|
|
320
|
+
const resourcePath = validateResourcePath(rel.startsWith("/") ? rel : `${state.prefix}/${rel}`);
|
|
321
|
+
let entry = createResourceEntry(absPath, resourcePath);
|
|
322
|
+
if (isDeclarativeImporter(state, importer)) {
|
|
323
|
+
entry = declareEntry(state, importer, entry);
|
|
324
|
+
if (!isImporterActive(state, importer) || !isDeclaredSourceAvailable(state, absPath)) {
|
|
325
|
+
return entry;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return activateEntry(state, entry);
|
|
329
|
+
};
|
|
330
|
+
const registerIconEntry = (state, sourcePath, derived, importer) => {
|
|
331
|
+
const shouldActivate = !isDeclarativeImporter(state, importer) ||
|
|
332
|
+
(isImporterActive(state, importer) && isDeclaredSourceAvailable(state, sourcePath));
|
|
333
|
+
if (shouldActivate) {
|
|
334
|
+
assertIconIdentityAvailable(state, derived.iconIdentity, sourcePath);
|
|
335
|
+
}
|
|
336
|
+
const entry = registerEntry(state, sourcePath, derived.resourcePath, importer);
|
|
337
|
+
declareResolvedIcon(state, importer, derived.iconIdentity, entry);
|
|
338
|
+
if (shouldActivate) {
|
|
339
|
+
state.iconOwners.set(derived.iconIdentity, entry);
|
|
340
|
+
}
|
|
108
341
|
return entry;
|
|
109
342
|
};
|
|
110
343
|
const isTrackedSource = (state, file) => state.sourcePaths.has(file);
|
|
111
|
-
const
|
|
344
|
+
const hasSourceEntry = (entries, file) => {
|
|
345
|
+
for (const entry of entries.values()) {
|
|
346
|
+
if (entry.sourcePath === file) {
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
};
|
|
352
|
+
const hasDeclaredSource = (declarations, file) => {
|
|
353
|
+
for (const entries of declarations.values()) {
|
|
354
|
+
if (hasSourceEntry(entries, file)) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return false;
|
|
359
|
+
};
|
|
360
|
+
const isDeclaredSource = (state, file) => hasDeclaredSource(state.declaredEntries, file) || hasDeclaredSource(state.declaredIcons, file);
|
|
361
|
+
const virtualAssetId = (entry) => toVirtualId(entry.sourcePath) + REL_SEPARATOR + entry.resourcePath;
|
|
362
|
+
const virtualIconId = ({ entry, iconName }) => virtualAssetId(entry) + ICON_NAME_SEPARATOR + iconName;
|
|
363
|
+
const resolveAssetSource = async (ctx, request) => {
|
|
364
|
+
const resolved = await ctx.resolve(request.assetSource, request.importer, {
|
|
365
|
+
...request.options,
|
|
366
|
+
skipSelf: true,
|
|
367
|
+
});
|
|
112
368
|
if (!resolved || resolved.external) {
|
|
113
369
|
return undefined;
|
|
114
370
|
}
|
|
115
|
-
|
|
371
|
+
const sourcePath = stripQuery(resolved.id);
|
|
372
|
+
if (!isAbsolute(sourcePath)) {
|
|
373
|
+
throw new Error(`${JSON.stringify(request.assetSource)} did not resolve to a file-backed asset`);
|
|
374
|
+
}
|
|
375
|
+
return sourcePath;
|
|
376
|
+
};
|
|
377
|
+
const resolveAssetEntry = async (ctx, state, request) => {
|
|
378
|
+
const sourcePath = await resolveAssetSource(ctx, request);
|
|
379
|
+
if (sourcePath === undefined) {
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
return registerEntry(state, sourcePath, request.resourcePath === null
|
|
383
|
+
? derivedResourcePath(state, sourcePath)
|
|
384
|
+
: validateResourcePath(request.resourcePath), request.importer);
|
|
385
|
+
};
|
|
386
|
+
const resolveIconEntry = async (ctx, state, request) => {
|
|
387
|
+
const sourcePath = await resolveAssetSource(ctx, request);
|
|
388
|
+
if (sourcePath === undefined) {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
const derived = derivedIconEntry(state, sourcePath, request.iconName);
|
|
392
|
+
return {
|
|
393
|
+
entry: registerIconEntry(state, sourcePath, derived, request.importer),
|
|
394
|
+
iconName: derived.iconName,
|
|
395
|
+
};
|
|
396
|
+
};
|
|
397
|
+
const resolveLegacyAssetEntry = async (ctx, state, request) => {
|
|
398
|
+
const resolved = await ctx.resolve(request.source, request.importer, { ...request.options, skipSelf: true });
|
|
399
|
+
if (!resolved || resolved.external) {
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
const sourcePath = stripQuery(resolved.id);
|
|
403
|
+
if (!isAbsolute(sourcePath)) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
return registerEntry(state, sourcePath, request.source.slice(DATA_PREFIX.length));
|
|
116
407
|
};
|
|
117
408
|
const loadInitModule = (state) => {
|
|
118
|
-
if (
|
|
119
|
-
|
|
409
|
+
if (state.isBuild) {
|
|
410
|
+
if (state.bundleReferenceId === null) {
|
|
411
|
+
throw new Error("Cannot render the GResource loader before its bundle has been emitted");
|
|
412
|
+
}
|
|
413
|
+
return renderInitModule({ isBuild: true, bundleReferenceId: state.bundleReferenceId });
|
|
120
414
|
}
|
|
121
|
-
|
|
415
|
+
ensureStagingDir(state);
|
|
416
|
+
return renderInitModule({ isBuild: false, devBundlePath: state.devBundlePath });
|
|
122
417
|
};
|
|
123
|
-
const
|
|
418
|
+
const virtualAssetMetadata = (virtualId) => {
|
|
124
419
|
const rest = fromVirtualId(virtualId);
|
|
125
420
|
const separatorIndex = rest.indexOf(REL_SEPARATOR);
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
421
|
+
const relAndMetadata = rest.slice(separatorIndex + REL_SEPARATOR.length);
|
|
422
|
+
const iconSeparatorIndex = relAndMetadata.indexOf(ICON_NAME_SEPARATOR);
|
|
423
|
+
return {
|
|
424
|
+
absPath: rest.slice(0, separatorIndex),
|
|
425
|
+
iconName: iconSeparatorIndex === -1
|
|
426
|
+
? null
|
|
427
|
+
: relAndMetadata.slice(iconSeparatorIndex + ICON_NAME_SEPARATOR.length),
|
|
428
|
+
rel: iconSeparatorIndex === -1 ? relAndMetadata : relAndMetadata.slice(0, iconSeparatorIndex),
|
|
429
|
+
};
|
|
430
|
+
};
|
|
431
|
+
const resourcePathExport = (entry, iconName) => iconName === null ? [`export const ${RESOURCE_PATH_EXPORT} = ${JSON.stringify(entry.resourcePath)};`] : [];
|
|
432
|
+
const assetModuleImports = (iconName) => {
|
|
433
|
+
const initBindings = iconName === null
|
|
434
|
+
? "ensureRegistered"
|
|
435
|
+
: `ensureRegistered, ${REGISTER_REFRESH_EXPORT}`;
|
|
436
|
+
return [
|
|
437
|
+
`import { ${initBindings} } from ${JSON.stringify(VIRTUAL_INIT)};`,
|
|
438
|
+
...(iconName === null
|
|
439
|
+
? []
|
|
440
|
+
: [
|
|
441
|
+
"import { Display } from \"@gtkx/gi/gdk\";",
|
|
442
|
+
"import { IconTheme } from \"@gtkx/gi/gtk\";",
|
|
443
|
+
]),
|
|
444
|
+
];
|
|
445
|
+
};
|
|
446
|
+
const iconThemeRegistration = (state, iconName) => {
|
|
447
|
+
if (iconName === null) {
|
|
448
|
+
return [];
|
|
449
|
+
}
|
|
450
|
+
const resourceIconPath = `${state.prefix}/icons`;
|
|
451
|
+
return [
|
|
452
|
+
`const resourceIconPath = ${JSON.stringify(resourceIconPath)};`,
|
|
453
|
+
"function refreshIconTheme() {",
|
|
454
|
+
" const display = Display.getDefault();",
|
|
455
|
+
" if (!display) return;",
|
|
456
|
+
" const theme = IconTheme.getForDisplay(display);",
|
|
457
|
+
" const paths = theme.getResourcePath() ?? [];",
|
|
458
|
+
" theme.setResourcePath(paths.includes(resourceIconPath) ? [...paths] : [...paths, resourceIconPath]);",
|
|
459
|
+
"}",
|
|
460
|
+
`${REGISTER_REFRESH_EXPORT}(resourceIconPath, refreshIconTheme);`,
|
|
461
|
+
];
|
|
462
|
+
};
|
|
463
|
+
const loadedResourceEntry = (state, sourcePath, resourcePath) => {
|
|
464
|
+
const registered = state.entries.get(resourcePath);
|
|
465
|
+
if (registered === undefined) {
|
|
466
|
+
return { entry: createResourceEntry(sourcePath, resourcePath), isRegistered: false };
|
|
467
|
+
}
|
|
468
|
+
if (registered.sourcePath !== sourcePath) {
|
|
469
|
+
throw new Error(`${registered.sourcePath} and ${sourcePath} both resolve to the GResource path ${resourcePath}`);
|
|
470
|
+
}
|
|
471
|
+
return { entry: registered, isRegistered: true };
|
|
472
|
+
};
|
|
473
|
+
const compileLoadedDevAsset = (state, isRegistered) => {
|
|
474
|
+
if (isRegistered && !state.isBuild) {
|
|
131
475
|
registerDevAsset(state);
|
|
132
476
|
}
|
|
477
|
+
};
|
|
478
|
+
const loadAssetModule = (state, virtualId) => {
|
|
479
|
+
const { absPath, iconName, rel } = virtualAssetMetadata(virtualId);
|
|
480
|
+
const resourcePath = validateResourcePath(rel);
|
|
481
|
+
const { entry, isRegistered } = loadedResourceEntry(state, absPath, resourcePath);
|
|
482
|
+
const uri = `resource://${entry.resourcePath}`;
|
|
483
|
+
const defaultValue = iconName ?? (state.isV2 ? entry.resourcePath : uri);
|
|
484
|
+
compileLoadedDevAsset(state, isRegistered);
|
|
133
485
|
return [
|
|
134
|
-
|
|
486
|
+
...assetModuleImports(iconName),
|
|
135
487
|
"ensureRegistered();",
|
|
136
|
-
|
|
137
|
-
`export
|
|
488
|
+
...iconThemeRegistration(state, iconName),
|
|
489
|
+
`export default ${JSON.stringify(defaultValue)};`,
|
|
490
|
+
...resourcePathExport(entry, iconName),
|
|
138
491
|
].join("\n");
|
|
139
492
|
};
|
|
140
|
-
const
|
|
141
|
-
if (!state.isBuild || state.
|
|
493
|
+
const finalizeBuildBundle = (ctx, bundle, state) => {
|
|
494
|
+
if (!state.isBuild || state.bundleReferenceId === null) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const fileName = ctx.getFileName(state.bundleReferenceId);
|
|
498
|
+
const output = bundle[fileName];
|
|
499
|
+
if (output?.type !== "asset") {
|
|
500
|
+
throw new Error(`Cannot find the emitted ${BUNDLE_FILENAME} asset`);
|
|
501
|
+
}
|
|
502
|
+
if (state.entries.size === 0) {
|
|
503
|
+
Reflect.deleteProperty(bundle, fileName);
|
|
142
504
|
return;
|
|
143
505
|
}
|
|
144
506
|
const compiled = withStagingDir("resources-out", (outDir) => compileBundle(state, join(outDir, BUNDLE_FILENAME)));
|
|
145
|
-
|
|
507
|
+
output.source = compiled;
|
|
146
508
|
info(`Compiled ${String(state.entries.size)} resource(s) into ${BUNDLE_FILENAME}`);
|
|
147
509
|
};
|
|
148
|
-
const refreshDevRegistration =
|
|
510
|
+
const refreshDevRegistration = (state) => {
|
|
149
511
|
compileDevBundle(state);
|
|
150
512
|
try {
|
|
151
|
-
|
|
513
|
+
refreshRegisteredDevBundle(state);
|
|
152
514
|
}
|
|
153
515
|
catch (error_) {
|
|
154
516
|
error("Failed to refresh GResource bundle:", error_);
|
|
155
517
|
}
|
|
156
518
|
};
|
|
519
|
+
const isSameSpecifiers = (left, right) => left === undefined
|
|
520
|
+
? right.size === 0
|
|
521
|
+
: left.size === right.size && [...right].every((source) => left.has(source));
|
|
522
|
+
const bundledSpecifiersIn = (imports) => new Set(imports
|
|
523
|
+
.filter((entry) => parseResourceSpecifier(entry.source) !== null || parseIconSpecifier(entry.source) !== null)
|
|
524
|
+
.map((entry) => entry.source));
|
|
525
|
+
const isSourceModule = (file) => sourceLanguage(file) !== undefined;
|
|
526
|
+
const isBundledSource = (source) => parseResourceSpecifier(source) !== null || parseIconSpecifier(source) !== null;
|
|
527
|
+
const validateUnbundledV2Source = (source) => {
|
|
528
|
+
if (isLegacyDataSpecifier(source)) {
|
|
529
|
+
throw new Error(`${JSON.stringify(source)} uses the legacy #data asset form`);
|
|
530
|
+
}
|
|
531
|
+
rejectInvalidV2Specifier(source);
|
|
532
|
+
};
|
|
533
|
+
const resolvedModuleDependency = async (ctx, source, importer) => {
|
|
534
|
+
if (isBundledSource(source)) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
validateUnbundledV2Source(source);
|
|
538
|
+
const resolved = await ctx.resolve(source, importer, { skipSelf: true });
|
|
539
|
+
if (resolved === null) {
|
|
540
|
+
throw new Error(`${JSON.stringify(source)} could not be resolved from ${importer}`);
|
|
541
|
+
}
|
|
542
|
+
return resolved.external ? null : importerKey(resolved.id);
|
|
543
|
+
};
|
|
544
|
+
const resolvedModuleDependencies = async (ctx, imports, importer) => {
|
|
545
|
+
const dependencies = new Set();
|
|
546
|
+
for (const entry of imports) {
|
|
547
|
+
const dependency = await resolvedModuleDependency(ctx, entry.source, importer);
|
|
548
|
+
if (dependency !== null) {
|
|
549
|
+
dependencies.add(dependency);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return dependencies;
|
|
553
|
+
};
|
|
554
|
+
const importerReconciliation = async (ctx, state, id) => {
|
|
555
|
+
const file = stripQuery(id);
|
|
556
|
+
const key = importerKey(file);
|
|
557
|
+
if (!state.isV2 || state.isBuild || !isSourceModule(file)) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
const imports = parseRuntimeImportsIn(file);
|
|
561
|
+
if (imports === null) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
return {
|
|
565
|
+
currentBundled: bundledSpecifiersIn(imports),
|
|
566
|
+
currentDependencies: await resolvedModuleDependencies(ctx, imports, file),
|
|
567
|
+
file,
|
|
568
|
+
imports,
|
|
569
|
+
key,
|
|
570
|
+
previousBundled: state.bundledSpecifiers.get(key),
|
|
571
|
+
previousDependencies: state.moduleDependencies.get(key),
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
const moduleNodeKey = (module) => importerKey(module.id ?? module.file ?? module.url);
|
|
575
|
+
const moduleNodeFor = (state, id) => {
|
|
576
|
+
const server = state.server;
|
|
577
|
+
if (server === null) {
|
|
578
|
+
return undefined;
|
|
579
|
+
}
|
|
580
|
+
return server.moduleGraph.getModuleById(id) ?? server.moduleGraph.getModuleById(importerKey(id));
|
|
581
|
+
};
|
|
582
|
+
const restoreDependencies = (pruned, current) => {
|
|
583
|
+
for (const dependency of current) {
|
|
584
|
+
pruned.delete(dependency);
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
const pruneRemovedDependencies = (pruned, previous, current) => {
|
|
588
|
+
if (previous === undefined) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
for (const dependency of previous) {
|
|
592
|
+
if (!current.has(dependency)) {
|
|
593
|
+
pruned.add(dependency);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const storePrunedDependencies = (state, key, pruned) => {
|
|
598
|
+
if (pruned.size === 0) {
|
|
599
|
+
state.prunedDependencies.delete(key);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
state.prunedDependencies.set(key, pruned);
|
|
603
|
+
};
|
|
604
|
+
const updatePrunedDependencies = (state, key, previous, current) => {
|
|
605
|
+
const pruned = state.prunedDependencies.get(key) ?? new Set();
|
|
606
|
+
restoreDependencies(pruned, current);
|
|
607
|
+
pruneRemovedDependencies(pruned, previous, current);
|
|
608
|
+
storePrunedDependencies(state, key, pruned);
|
|
609
|
+
};
|
|
610
|
+
const isPrunedDependency = (state, importer, imported) => state.prunedDependencies.get(moduleNodeKey(importer))?.has(moduleNodeKey(imported)) === true;
|
|
611
|
+
const fallbackRootModules = (state) => {
|
|
612
|
+
const roots = [];
|
|
613
|
+
for (const key of state.moduleDependencies.keys()) {
|
|
614
|
+
if (moduleNodeFor(state, key)?.importers.size === 0) {
|
|
615
|
+
roots.push(key);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return roots;
|
|
619
|
+
};
|
|
620
|
+
const enqueueCurrentDependencies = (state, key, pending) => {
|
|
621
|
+
const dependencies = state.moduleDependencies.get(key) ?? [];
|
|
622
|
+
for (const dependency of dependencies) {
|
|
623
|
+
pending.push(dependency);
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
const enqueueGraphDependencies = (state, key, pending) => {
|
|
627
|
+
const module = moduleNodeFor(state, key);
|
|
628
|
+
if (module === undefined) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
for (const imported of module.importedModules) {
|
|
632
|
+
if (!isPrunedDependency(state, module, imported)) {
|
|
633
|
+
pending.push(moduleNodeKey(imported));
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
const visitActiveImporter = (state, active, pending, key) => {
|
|
638
|
+
if (active.has(key)) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
active.add(key);
|
|
642
|
+
enqueueCurrentDependencies(state, key, pending);
|
|
643
|
+
enqueueGraphDependencies(state, key, pending);
|
|
644
|
+
};
|
|
645
|
+
const activeImporterKeys = (state) => {
|
|
646
|
+
const active = new Set();
|
|
647
|
+
const roots = state.entryModule === null ? fallbackRootModules(state) : [state.entryModule];
|
|
648
|
+
const pending = [...roots];
|
|
649
|
+
while (pending.length > 0) {
|
|
650
|
+
const key = pending.pop();
|
|
651
|
+
if (key === undefined || active.has(key)) {
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
visitActiveImporter(state, active, pending, key);
|
|
655
|
+
}
|
|
656
|
+
return active;
|
|
657
|
+
};
|
|
658
|
+
const isImporterActive = (state, importer) => activeImporterKeys(state).has(importerKey(importer));
|
|
659
|
+
const activateDeclaredIcon = (state, iconIdentity, entry) => {
|
|
660
|
+
const existing = state.iconOwners.get(iconIdentity);
|
|
661
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
662
|
+
throw new Error(`${existing.sourcePath} and ${entry.sourcePath} both claim the themed icon ${iconIdentity}`);
|
|
663
|
+
}
|
|
664
|
+
state.iconOwners.set(iconIdentity, activateEntry(state, entry));
|
|
665
|
+
};
|
|
666
|
+
const activateDeclaredEntries = (state, importer) => {
|
|
667
|
+
const entries = state.declaredEntries.get(importer)?.values() ?? [];
|
|
668
|
+
for (const entry of entries) {
|
|
669
|
+
if (isDeclaredSourceAvailable(state, entry.sourcePath)) {
|
|
670
|
+
activateEntry(state, entry);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
const activateDeclaredIcons = (state, importer) => {
|
|
675
|
+
const icons = state.declaredIcons.get(importer) ?? [];
|
|
676
|
+
for (const [iconIdentity, entry] of icons) {
|
|
677
|
+
if (isDeclaredSourceAvailable(state, entry.sourcePath)) {
|
|
678
|
+
activateDeclaredIcon(state, iconIdentity, entry);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
const activateDeclaredClaims = (state, active) => {
|
|
683
|
+
for (const importer of sortStrings(active)) {
|
|
684
|
+
activateDeclaredEntries(state, importer);
|
|
685
|
+
activateDeclaredIcons(state, importer);
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
const rebuildActiveClaims = (state) => {
|
|
689
|
+
const previous = {
|
|
690
|
+
entries: state.entries,
|
|
691
|
+
iconOwners: state.iconOwners,
|
|
692
|
+
sourcePaths: state.sourcePaths,
|
|
693
|
+
};
|
|
694
|
+
state.entries = new Map();
|
|
695
|
+
state.iconOwners = new Map();
|
|
696
|
+
state.sourcePaths = new Set();
|
|
697
|
+
try {
|
|
698
|
+
activateDeclaredClaims(state, activeImporterKeys(state));
|
|
699
|
+
}
|
|
700
|
+
catch (error_) {
|
|
701
|
+
state.entries = previous.entries;
|
|
702
|
+
state.iconOwners = previous.iconOwners;
|
|
703
|
+
state.sourcePaths = previous.sourcePaths;
|
|
704
|
+
throw error_;
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
const forgetImporterDeclarations = (state, importer) => {
|
|
708
|
+
state.declaredEntries.delete(importer);
|
|
709
|
+
state.declaredIcons.delete(importer);
|
|
710
|
+
};
|
|
711
|
+
const cloneStringSetMap = (source) => {
|
|
712
|
+
const clone = new Map();
|
|
713
|
+
for (const [key, values] of source) {
|
|
714
|
+
clone.set(key, new Set(values));
|
|
715
|
+
}
|
|
716
|
+
return clone;
|
|
717
|
+
};
|
|
718
|
+
const cloneDeclarationMap = (source) => {
|
|
719
|
+
const clone = new Map();
|
|
720
|
+
for (const [key, declarations] of source) {
|
|
721
|
+
clone.set(key, new Map(declarations));
|
|
722
|
+
}
|
|
723
|
+
return clone;
|
|
724
|
+
};
|
|
725
|
+
const reconciliationCandidate = (state) => ({
|
|
726
|
+
...state,
|
|
727
|
+
bundledSpecifiers: cloneStringSetMap(state.bundledSpecifiers),
|
|
728
|
+
moduleDependencies: cloneStringSetMap(state.moduleDependencies),
|
|
729
|
+
prunedDependencies: cloneStringSetMap(state.prunedDependencies),
|
|
730
|
+
declaredEntries: cloneDeclarationMap(state.declaredEntries),
|
|
731
|
+
declaredIcons: cloneDeclarationMap(state.declaredIcons),
|
|
732
|
+
missingSourcePaths: new Set(state.missingSourcePaths),
|
|
733
|
+
});
|
|
734
|
+
const storeBundledSpecifiers = (state, importer, specifiers) => {
|
|
735
|
+
if (specifiers.size === 0) {
|
|
736
|
+
state.bundledSpecifiers.delete(importer);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
state.bundledSpecifiers.set(importer, specifiers);
|
|
740
|
+
};
|
|
741
|
+
const applyImporterGraph = (state, reconciliation) => {
|
|
742
|
+
updatePrunedDependencies(state, reconciliation.key, reconciliation.previousDependencies, reconciliation.currentDependencies);
|
|
743
|
+
state.moduleDependencies.set(reconciliation.key, reconciliation.currentDependencies);
|
|
744
|
+
storeBundledSpecifiers(state, reconciliation.key, reconciliation.currentBundled);
|
|
745
|
+
};
|
|
746
|
+
const declareReconciledResource = async (ctx, state, importer, source) => {
|
|
747
|
+
const resourceSpecifier = parseResourceSpecifier(source);
|
|
748
|
+
if (resourceSpecifier === null) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const entry = await resolveAssetEntry(ctx, state, {
|
|
752
|
+
assetSource: resourceSpecifier.assetSource,
|
|
753
|
+
importer,
|
|
754
|
+
resourcePath: resourceSpecifier.resourcePath,
|
|
755
|
+
options: undefined,
|
|
756
|
+
});
|
|
757
|
+
if (entry === undefined || state.missingSourcePaths.has(entry.sourcePath)) {
|
|
758
|
+
throw new Error(`${JSON.stringify(source)} did not resolve to a bundled resource`);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
const declareReconciledIcon = async (ctx, state, importer, source) => {
|
|
762
|
+
const iconSpecifier = parseIconSpecifier(source);
|
|
763
|
+
if (iconSpecifier === null) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const entry = await resolveIconEntry(ctx, state, {
|
|
767
|
+
assetSource: iconSpecifier.assetSource,
|
|
768
|
+
iconName: iconSpecifier.iconName,
|
|
769
|
+
importer,
|
|
770
|
+
options: undefined,
|
|
771
|
+
});
|
|
772
|
+
if (entry === undefined || state.missingSourcePaths.has(entry.entry.sourcePath)) {
|
|
773
|
+
throw new Error(`${JSON.stringify(source)} did not resolve to a bundled icon`);
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
const declareReconciledSource = async (ctx, state, importer, source) => {
|
|
777
|
+
await declareReconciledResource(ctx, state, importer, source);
|
|
778
|
+
await declareReconciledIcon(ctx, state, importer, source);
|
|
779
|
+
};
|
|
780
|
+
const declareReconciledImports = async (ctx, state, reconciliation) => {
|
|
781
|
+
for (const entry of reconciliation.imports) {
|
|
782
|
+
if (isBundledSource(entry.source)) {
|
|
783
|
+
await declareReconciledSource(ctx, state, reconciliation.file, entry.source);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
const prepareReconciliation = async (ctx, state, reconciliation) => {
|
|
788
|
+
const candidate = reconciliationCandidate(state);
|
|
789
|
+
const isBundledChanged = !isSameSpecifiers(reconciliation.previousBundled, reconciliation.currentBundled);
|
|
790
|
+
if (isBundledChanged) {
|
|
791
|
+
forgetImporterDeclarations(candidate, reconciliation.key);
|
|
792
|
+
}
|
|
793
|
+
applyImporterGraph(candidate, reconciliation);
|
|
794
|
+
rebuildActiveClaims(candidate);
|
|
795
|
+
if (isBundledChanged) {
|
|
796
|
+
await declareReconciledImports(ctx, candidate, reconciliation);
|
|
797
|
+
}
|
|
798
|
+
return candidate;
|
|
799
|
+
};
|
|
800
|
+
const commitReconciliation = (state, candidate) => {
|
|
801
|
+
state.entries = candidate.entries;
|
|
802
|
+
state.bundledSpecifiers = candidate.bundledSpecifiers;
|
|
803
|
+
state.moduleDependencies = candidate.moduleDependencies;
|
|
804
|
+
state.prunedDependencies = candidate.prunedDependencies;
|
|
805
|
+
state.declaredEntries = candidate.declaredEntries;
|
|
806
|
+
state.declaredIcons = candidate.declaredIcons;
|
|
807
|
+
state.missingSourcePaths = candidate.missingSourcePaths;
|
|
808
|
+
state.sourcePaths = candidate.sourcePaths;
|
|
809
|
+
state.iconOwners = candidate.iconOwners;
|
|
810
|
+
};
|
|
811
|
+
const reconcileV2Importer = async (ctx, state, id) => {
|
|
812
|
+
const reconciliation = await importerReconciliation(ctx, state, id);
|
|
813
|
+
if (reconciliation === null) {
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
const previousSignature = entriesSignature(state);
|
|
817
|
+
const candidate = await prepareReconciliation(ctx, state, reconciliation);
|
|
818
|
+
commitReconciliation(state, candidate);
|
|
819
|
+
if (entriesSignature(state) !== previousSignature) {
|
|
820
|
+
refreshDevRegistration(state);
|
|
821
|
+
}
|
|
822
|
+
};
|
|
157
823
|
const resolveResourceConfig = async (state, config, loadConfig) => {
|
|
158
|
-
const
|
|
159
|
-
state.prefix =
|
|
824
|
+
const loaded = await loadConfig.load(config.root ?? process.cwd());
|
|
825
|
+
state.prefix = resourceBasePath(loaded.config.applicationId);
|
|
826
|
+
state.root = loaded.root;
|
|
827
|
+
state.isV2 = loaded.config.future?.v2ResourceImports === true;
|
|
160
828
|
return {
|
|
161
829
|
assetsInclude: [ASSET_RE],
|
|
162
830
|
};
|
|
163
831
|
};
|
|
164
|
-
const refreshTrackedSource =
|
|
832
|
+
const refreshTrackedSource = (state, file) => {
|
|
165
833
|
if (!isTrackedSource(state, file)) {
|
|
166
834
|
return;
|
|
167
835
|
}
|
|
168
836
|
try {
|
|
169
|
-
|
|
837
|
+
refreshDevRegistration(state);
|
|
170
838
|
}
|
|
171
839
|
catch (error_) {
|
|
172
840
|
error("GResource refresh failed:", error_);
|
|
173
841
|
}
|
|
174
842
|
};
|
|
843
|
+
const rebuildForSourceAvailability = (state, previousSignature) => {
|
|
844
|
+
try {
|
|
845
|
+
rebuildActiveClaims(state);
|
|
846
|
+
if (entriesSignature(state) !== previousSignature) {
|
|
847
|
+
refreshDevRegistration(state);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
catch (error_) {
|
|
851
|
+
error("GResource source update failed:", error_);
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
const updateTrackedSourceAvailability = (state, file, isAvailable) => {
|
|
855
|
+
if (!isTrackedSource(state, file) && !state.missingSourcePaths.has(file) && !isDeclaredSource(state, file)) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const previousSignature = entriesSignature(state);
|
|
859
|
+
setSourceAvailability(state, file, isAvailable);
|
|
860
|
+
rebuildForSourceAvailability(state, previousSignature);
|
|
861
|
+
};
|
|
175
862
|
const attachResourceWatcher = (state, server) => {
|
|
176
863
|
state.server = server;
|
|
177
|
-
const
|
|
178
|
-
|
|
864
|
+
const onChange = (file) => {
|
|
865
|
+
refreshTrackedSource(state, file);
|
|
866
|
+
};
|
|
867
|
+
const onAdd = (file) => {
|
|
868
|
+
updateTrackedSourceAvailability(state, file, true);
|
|
869
|
+
};
|
|
870
|
+
const onUnlink = (file) => {
|
|
871
|
+
updateTrackedSourceAvailability(state, file, false);
|
|
179
872
|
};
|
|
180
873
|
const onClose = () => {
|
|
181
874
|
releaseStagingDir(state);
|
|
182
875
|
};
|
|
183
876
|
server.httpServer?.once("close", onClose);
|
|
184
877
|
server.watcher.once("close", onClose);
|
|
185
|
-
server.watcher.on("change",
|
|
186
|
-
server.watcher.on("add",
|
|
878
|
+
server.watcher.on("change", onChange);
|
|
879
|
+
server.watcher.on("add", onAdd);
|
|
880
|
+
server.watcher.on("unlink", onUnlink);
|
|
187
881
|
};
|
|
188
882
|
const applyResolvedConfig = (state, config) => {
|
|
189
883
|
state.isBuild = config.command === "build";
|
|
190
|
-
|
|
884
|
+
state.root = config.root;
|
|
885
|
+
state.dataDir = null;
|
|
886
|
+
if (state.isBuild || state.isV2) {
|
|
191
887
|
return;
|
|
192
888
|
}
|
|
193
889
|
const relativeDataDir = resolveDataDir(config.root);
|
|
@@ -202,51 +898,146 @@ const loadResourceModule = (state, id) => {
|
|
|
202
898
|
}
|
|
203
899
|
return loadAssetModule(state, id);
|
|
204
900
|
};
|
|
205
|
-
|
|
901
|
+
const isLegacyDataSpecifier = (source) => source.startsWith(DATA_PREFIX) && ASSET_RE.test(stripQuery(source));
|
|
902
|
+
const rejectInvalidV2Specifier = (source) => {
|
|
903
|
+
if (BUNDLED_QUERY_MENTION_RE.test(source)) {
|
|
904
|
+
throw new Error(`${JSON.stringify(source)} is not a valid bundled asset import; use ?resource, ` +
|
|
905
|
+
"?resource=/absolute/path, ?icon, or ?icon=name");
|
|
906
|
+
}
|
|
907
|
+
if (isBareRelativeAsset(source)) {
|
|
908
|
+
throw new Error(`${JSON.stringify(source)} must choose ?resource for a GResource, ?icon for a themed icon, ` +
|
|
909
|
+
"or ?url for an emitted file");
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
const resolveExplicitResourceId = async (ctx, state, request) => {
|
|
913
|
+
const specifier = parseResourceSpecifier(request.source);
|
|
914
|
+
if (specifier === null) {
|
|
915
|
+
return undefined;
|
|
916
|
+
}
|
|
917
|
+
const entry = await resolveAssetEntry(ctx, state, {
|
|
918
|
+
assetSource: specifier.assetSource,
|
|
919
|
+
importer: request.importer,
|
|
920
|
+
resourcePath: specifier.resourcePath,
|
|
921
|
+
options: request.options,
|
|
922
|
+
});
|
|
923
|
+
return entry === undefined ? undefined : virtualAssetId(entry);
|
|
924
|
+
};
|
|
925
|
+
const resolveIconResourceId = async (ctx, state, request) => {
|
|
926
|
+
const specifier = parseIconSpecifier(request.source);
|
|
927
|
+
if (specifier === null) {
|
|
928
|
+
return undefined;
|
|
929
|
+
}
|
|
930
|
+
const resolved = await resolveIconEntry(ctx, state, {
|
|
931
|
+
assetSource: specifier.assetSource,
|
|
932
|
+
iconName: specifier.iconName,
|
|
933
|
+
importer: request.importer,
|
|
934
|
+
options: request.options,
|
|
935
|
+
});
|
|
936
|
+
return resolved === undefined
|
|
937
|
+
? undefined
|
|
938
|
+
: { id: virtualIconId(resolved), moduleSideEffects: true };
|
|
939
|
+
};
|
|
940
|
+
const resolveV2ResourceId = async (ctx, state, request) => {
|
|
941
|
+
if (isLegacyDataSpecifier(request.source)) {
|
|
942
|
+
throw new Error(`${JSON.stringify(request.source)} uses the legacy #data asset form; import it relatively with ` +
|
|
943
|
+
"?resource or ?url");
|
|
944
|
+
}
|
|
945
|
+
if (parseResourceSpecifier(request.source) !== null) {
|
|
946
|
+
const resolved = await resolveExplicitResourceId(ctx, state, request);
|
|
947
|
+
trackBundledSpecifier(state, request.importer, request.source);
|
|
948
|
+
return resolved;
|
|
949
|
+
}
|
|
950
|
+
if (parseIconSpecifier(request.source) !== null) {
|
|
951
|
+
const resolved = await resolveIconResourceId(ctx, state, request);
|
|
952
|
+
trackBundledSpecifier(state, request.importer, request.source);
|
|
953
|
+
return resolved;
|
|
954
|
+
}
|
|
955
|
+
rejectInvalidV2Specifier(request.source);
|
|
956
|
+
return undefined;
|
|
957
|
+
};
|
|
958
|
+
const resolveLegacyResourceId = async (ctx, state, request) => {
|
|
959
|
+
if (BUNDLED_QUERY_MENTION_RE.test(request.source)) {
|
|
960
|
+
throw new Error(`${JSON.stringify(request.source)} requires future.v2ResourceImports`);
|
|
961
|
+
}
|
|
962
|
+
if (!isDataAsset(request.source)) {
|
|
963
|
+
return undefined;
|
|
964
|
+
}
|
|
965
|
+
const entry = await resolveLegacyAssetEntry(ctx, state, request);
|
|
966
|
+
return entry === undefined ? undefined : virtualAssetId(entry);
|
|
967
|
+
};
|
|
968
|
+
const resolveResourceId = (ctx, state, request) => {
|
|
969
|
+
if (request.source === VIRTUAL_INIT) {
|
|
970
|
+
return Promise.resolve(VIRTUAL_INIT);
|
|
971
|
+
}
|
|
972
|
+
return state.isV2
|
|
973
|
+
? resolveV2ResourceId(ctx, state, request)
|
|
974
|
+
: resolveLegacyResourceId(ctx, state, request);
|
|
975
|
+
};
|
|
976
|
+
const configureResourceServer = (state, server) => {
|
|
977
|
+
attachResourceWatcher(state, server);
|
|
978
|
+
primeLegacyDevBundle(state);
|
|
979
|
+
};
|
|
980
|
+
const createResourcesPlugin = (state, loadConfig) => ({
|
|
981
|
+
name: "gtkx:resources",
|
|
982
|
+
enforce: "pre",
|
|
983
|
+
perEnvironmentStartEndDuringDev: true,
|
|
984
|
+
config: (config) => resolveResourceConfig(state, config, loadConfig),
|
|
985
|
+
configResolved: (config) => {
|
|
986
|
+
applyResolvedConfig(state, config);
|
|
987
|
+
},
|
|
988
|
+
configureServer: (server) => {
|
|
989
|
+
configureResourceServer(state, server);
|
|
990
|
+
},
|
|
991
|
+
buildStart() {
|
|
992
|
+
if (state.isBuild && state.bundleReferenceId === null) {
|
|
993
|
+
state.bundleReferenceId = this.emitFile({
|
|
994
|
+
type: "asset",
|
|
995
|
+
fileName: BUNDLE_FILENAME,
|
|
996
|
+
source: "",
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
resolveId(source, importer, options) {
|
|
1001
|
+
return resolveResourceId(this, state, { source, importer, options });
|
|
1002
|
+
},
|
|
1003
|
+
load(id) {
|
|
1004
|
+
return loadResourceModule(state, id);
|
|
1005
|
+
},
|
|
1006
|
+
async transform(code, id) {
|
|
1007
|
+
await reconcileV2Importer(this, state, id);
|
|
1008
|
+
return retainSideEffectIconImport(state, code, id);
|
|
1009
|
+
},
|
|
1010
|
+
generateBundle(_options, bundle) {
|
|
1011
|
+
finalizeBuildBundle(this, bundle, state);
|
|
1012
|
+
},
|
|
1013
|
+
closeBundle() {
|
|
1014
|
+
releaseStagingDir(state);
|
|
1015
|
+
},
|
|
1016
|
+
});
|
|
1017
|
+
function gtkxResources(loadConfig = createConfigLoader(), entryPath) {
|
|
206
1018
|
const state = {
|
|
207
1019
|
prefix: "",
|
|
1020
|
+
root: "",
|
|
208
1021
|
isBuild: false,
|
|
1022
|
+
isV2: false,
|
|
209
1023
|
entries: new Map(),
|
|
1024
|
+
bundledSpecifiers: new Map(),
|
|
1025
|
+
moduleDependencies: new Map(),
|
|
1026
|
+
prunedDependencies: new Map(),
|
|
1027
|
+
declaredEntries: new Map(),
|
|
1028
|
+
declaredIcons: new Map(),
|
|
1029
|
+
entryModule: entryPath === undefined ? null : importerKey(entryPath),
|
|
210
1030
|
sourcePaths: new Set(),
|
|
1031
|
+
missingSourcePaths: new Set(),
|
|
211
1032
|
stagingDir: createRetainedStagingDir(DEV_STAGING_PREFIX),
|
|
212
1033
|
devBundlePath: "",
|
|
213
1034
|
server: null,
|
|
214
1035
|
compiledSignature: "",
|
|
215
1036
|
dataDir: null,
|
|
1037
|
+
bundleReferenceId: null,
|
|
1038
|
+
iconOwners: new Map(),
|
|
216
1039
|
};
|
|
217
|
-
return
|
|
218
|
-
name: "gtkx:resources",
|
|
219
|
-
enforce: "pre",
|
|
220
|
-
config(config) {
|
|
221
|
-
return resolveResourceConfig(state, config, loadConfig);
|
|
222
|
-
},
|
|
223
|
-
configResolved(config) {
|
|
224
|
-
applyResolvedConfig(state, config);
|
|
225
|
-
},
|
|
226
|
-
configureServer(server) {
|
|
227
|
-
attachResourceWatcher(state, server);
|
|
228
|
-
primeDevBundle(state);
|
|
229
|
-
},
|
|
230
|
-
async resolveId(source, importer, opts) {
|
|
231
|
-
if (source === VIRTUAL_INIT) {
|
|
232
|
-
return VIRTUAL_INIT;
|
|
233
|
-
}
|
|
234
|
-
if (!isDataAsset(source)) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
const resolved = await this.resolve(source, importer, { ...opts, skipSelf: true });
|
|
238
|
-
return resolvedAssetId(resolved, source);
|
|
239
|
-
},
|
|
240
|
-
load(id) {
|
|
241
|
-
return loadResourceModule(state, id);
|
|
242
|
-
},
|
|
243
|
-
buildEnd() {
|
|
244
|
-
emitBuildBundle(this, state);
|
|
245
|
-
},
|
|
246
|
-
closeBundle() {
|
|
247
|
-
releaseStagingDir(state);
|
|
248
|
-
},
|
|
249
|
-
};
|
|
1040
|
+
return createResourcesPlugin(state, loadConfig);
|
|
250
1041
|
}
|
|
251
1042
|
export { gtkxResources };
|
|
252
1043
|
//# sourceMappingURL=resources.js.map
|