@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,29 +1,38 @@
|
|
|
1
1
|
import type { ConfigLoader } from "@gtkx/config";
|
|
2
|
-
import type { Plugin, ResolvedConfig, UserConfig, ViteDevServer } from "vite";
|
|
3
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
4
|
-
import { error, info, sortStrings } from "@gtkx/utils";
|
|
5
|
-
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { dirname, join } from "node:path";
|
|
7
|
-
import
|
|
2
|
+
import type { ModuleNode, Plugin, ResolvedConfig, Rolldown, UserConfig, ViteDevServer } from "vite";
|
|
3
|
+
import { createConfigLoader, resourceBasePath } from "@gtkx/config/internal";
|
|
4
|
+
import { error, info, isRecord, sortStrings } from "@gtkx/utils";
|
|
5
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { basename, dirname, extname, isAbsolute, join, posix, relative, sep } from "node:path";
|
|
7
|
+
import { parseSync } from "vite";
|
|
8
8
|
import { resolveDataDir } from "../internal/data-dir.js";
|
|
9
9
|
import { type ListedFile, listFilesRecursive } from "../internal/list-files.js";
|
|
10
|
-
import { loadModuleExclusively } from "../internal/module-loads.js";
|
|
11
10
|
import { runCliTool } from "../internal/run-cli-tool.js";
|
|
11
|
+
import { parseRuntimeImportsIn, type SourceImport, sourceLanguage } from "../internal/source-imports.js";
|
|
12
12
|
import { createRetainedStagingDir, type RetainedStagingDir, withStagingDir } from "../internal/staging-dir.js";
|
|
13
13
|
import { ASSET_RE } from "./asset-extensions.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
DATA_PREFIX,
|
|
16
|
+
isBareRelativeAsset,
|
|
17
|
+
isDataAsset,
|
|
18
|
+
parseIconSpecifier,
|
|
19
|
+
parseResourceSpecifier,
|
|
20
|
+
} from "./asset-specifier.js";
|
|
15
21
|
import { renderInitModule } from "./resource-init-module.js";
|
|
16
22
|
import {
|
|
17
23
|
BUNDLE_FILENAME,
|
|
18
24
|
escapeXml,
|
|
19
25
|
fromVirtualId,
|
|
26
|
+
ICON_NAME_SEPARATOR,
|
|
20
27
|
isVirtual,
|
|
21
28
|
REFRESH_EXPORT,
|
|
29
|
+
REGISTER_REFRESH_EXPORT,
|
|
22
30
|
REL_SEPARATOR,
|
|
23
31
|
RESOURCE_PATH_EXPORT,
|
|
24
32
|
toVirtualId,
|
|
25
33
|
VIRTUAL_INIT,
|
|
26
34
|
} from "./resource-shared.js";
|
|
35
|
+
import { stripQuery } from "./strip-query.js";
|
|
27
36
|
|
|
28
37
|
type ResourceEntry = {
|
|
29
38
|
sourcePath: string;
|
|
@@ -33,21 +42,306 @@ type ResourceEntry = {
|
|
|
33
42
|
|
|
34
43
|
type PluginState = {
|
|
35
44
|
prefix: string;
|
|
45
|
+
root: string;
|
|
36
46
|
isBuild: boolean;
|
|
47
|
+
isV2: boolean;
|
|
37
48
|
entries: Map<string, ResourceEntry>;
|
|
49
|
+
bundledSpecifiers: Map<string, Set<string>>;
|
|
50
|
+
moduleDependencies: Map<string, Set<string>>;
|
|
51
|
+
prunedDependencies: Map<string, Set<string>>;
|
|
52
|
+
declaredEntries: Map<string, Map<string, ResourceEntry>>;
|
|
53
|
+
declaredIcons: Map<string, Map<string, ResourceEntry>>;
|
|
54
|
+
entryModule: string | null;
|
|
38
55
|
sourcePaths: Set<string>;
|
|
56
|
+
missingSourcePaths: Set<string>;
|
|
39
57
|
stagingDir: RetainedStagingDir;
|
|
40
58
|
devBundlePath: string;
|
|
41
59
|
server: ViteDevServer | null;
|
|
42
60
|
compiledSignature: string;
|
|
43
61
|
dataDir: string | null;
|
|
62
|
+
bundleReferenceId: string | null;
|
|
63
|
+
iconOwners: Map<string, ResourceEntry>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type ResolveContext = {
|
|
67
|
+
resolve: (
|
|
68
|
+
source: string,
|
|
69
|
+
importer?: string,
|
|
70
|
+
options?: Record<string, unknown>,
|
|
71
|
+
) => Promise<{ id: string; external?: boolean | string } | null>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type PackageOwner = {
|
|
75
|
+
dir: string;
|
|
76
|
+
name: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type AssetResolveRequest = {
|
|
80
|
+
assetSource: string;
|
|
81
|
+
importer: string | undefined;
|
|
82
|
+
resourcePath: string | null;
|
|
83
|
+
options: Record<string, unknown> | undefined;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
type IconResolveRequest = {
|
|
87
|
+
assetSource: string;
|
|
88
|
+
iconName: string | null;
|
|
89
|
+
importer: string | undefined;
|
|
90
|
+
options: Record<string, unknown> | undefined;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type ResolvedIconEntry = {
|
|
94
|
+
entry: ResourceEntry;
|
|
95
|
+
iconName: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type RetainedIconModuleId = {
|
|
99
|
+
id: string;
|
|
100
|
+
moduleSideEffects: true;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
type ResourceModuleId = string | RetainedIconModuleId;
|
|
104
|
+
|
|
105
|
+
type ImporterReconciliation = {
|
|
106
|
+
currentBundled: Set<string>;
|
|
107
|
+
currentDependencies: Set<string>;
|
|
108
|
+
file: string;
|
|
109
|
+
imports: SourceImport[];
|
|
110
|
+
key: string;
|
|
111
|
+
previousBundled: Set<string> | undefined;
|
|
112
|
+
previousDependencies: Set<string> | undefined;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
type DerivedIconEntry = {
|
|
116
|
+
iconIdentity: string;
|
|
117
|
+
iconName: string;
|
|
118
|
+
resourcePath: string;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
type LegacyResolveRequest = {
|
|
122
|
+
source: string;
|
|
123
|
+
importer: string | undefined;
|
|
124
|
+
options: Record<string, unknown> | undefined;
|
|
44
125
|
};
|
|
45
126
|
|
|
46
127
|
const RESOURCE_COMPILER = "glib-compile-resources";
|
|
47
128
|
const MANIFEST_PREFIX = "/";
|
|
48
129
|
const DEV_STAGING_PREFIX = "resources-dev";
|
|
130
|
+
const MANIFEST_FILENAME = "package.json";
|
|
131
|
+
const BUNDLED_QUERY_MENTION_RE = /[?&](?:icon|resource)(?:[=&]|$)/;
|
|
132
|
+
const ICON_EXTENSIONS: Set<string> = new Set([".png", ".svg", ".xpm"]);
|
|
133
|
+
|
|
134
|
+
const ICON_CONTEXTS: Set<string> = new Set([
|
|
135
|
+
"actions",
|
|
136
|
+
"animations",
|
|
137
|
+
"apps",
|
|
138
|
+
"categories",
|
|
139
|
+
"devices",
|
|
140
|
+
"emblems",
|
|
141
|
+
"emotes",
|
|
142
|
+
"filesystems",
|
|
143
|
+
"intl",
|
|
144
|
+
"mimetypes",
|
|
145
|
+
"places",
|
|
146
|
+
"status",
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
const STOCK_ICON_CONTEXTS: Set<string> = new Set([
|
|
150
|
+
"chart",
|
|
151
|
+
"code",
|
|
152
|
+
"data",
|
|
153
|
+
"form",
|
|
154
|
+
"image",
|
|
155
|
+
"io",
|
|
156
|
+
"media",
|
|
157
|
+
"navigation",
|
|
158
|
+
"net",
|
|
159
|
+
"object",
|
|
160
|
+
"table",
|
|
161
|
+
"text",
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
const ICON_SIZE_RE = /^([1-9]\d*)x\1(?:@[1-9]\d*)?$/;
|
|
165
|
+
const RESERVED_ICON_NAMES: Set<string> = new Set(["", ".", ".."]);
|
|
166
|
+
|
|
167
|
+
const toForwardSlashes = (value: string): string => value.replaceAll(/[/\\]/g, "/");
|
|
168
|
+
|
|
169
|
+
const isWithin = (root: string, path: string): boolean => {
|
|
170
|
+
const rel = relative(root, path);
|
|
171
|
+
|
|
172
|
+
return rel.length > 0 && !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const isDependencyFile = (root: string, path: string): boolean =>
|
|
176
|
+
isWithin(root, path) && relative(root, path).split(sep).includes("node_modules");
|
|
177
|
+
|
|
178
|
+
const packageIdentityIn = (dir: string): string | null => {
|
|
179
|
+
try {
|
|
180
|
+
const manifest: unknown = JSON.parse(readFileSync(join(dir, MANIFEST_FILENAME), "utf8"));
|
|
181
|
+
|
|
182
|
+
return isRecord(manifest) && typeof manifest.name === "string" ? manifest.name : null;
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const packageIn = (dir: string): PackageOwner | null => {
|
|
189
|
+
const name = packageIdentityIn(dir);
|
|
190
|
+
|
|
191
|
+
if (name !== null) {
|
|
192
|
+
return { dir, name };
|
|
193
|
+
}
|
|
49
194
|
|
|
50
|
-
const
|
|
195
|
+
const parent = dirname(dir);
|
|
196
|
+
|
|
197
|
+
return parent === dir ? null : packageIn(parent);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const packageForFile = (file: string): PackageOwner | null => packageIn(dirname(file));
|
|
201
|
+
|
|
202
|
+
const validateResourcePath = (resourcePath: string): string => {
|
|
203
|
+
if (
|
|
204
|
+
resourcePath === "/" ||
|
|
205
|
+
!resourcePath.startsWith("/") ||
|
|
206
|
+
resourcePath.endsWith("/") ||
|
|
207
|
+
resourcePath.includes("\0") ||
|
|
208
|
+
posix.normalize(resourcePath) !== resourcePath
|
|
209
|
+
) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`${JSON.stringify(resourcePath)} is not a valid GResource path; use an absolute normalized path`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return resourcePath;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const derivedResourcePath = (state: PluginState, sourcePath: string): string => {
|
|
219
|
+
if (isWithin(state.root, sourcePath) && !isDependencyFile(state.root, sourcePath)) {
|
|
220
|
+
return validateResourcePath(`${state.prefix}/${toForwardSlashes(relative(state.root, sourcePath))}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const owner = packageForFile(sourcePath);
|
|
224
|
+
|
|
225
|
+
if (owner === null || !isWithin(owner.dir, sourcePath)) {
|
|
226
|
+
throw new Error(`${sourcePath} is outside the application and does not belong to a named package`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const packagePath = toForwardSlashes(relative(owner.dir, sourcePath));
|
|
230
|
+
|
|
231
|
+
return validateResourcePath(`${state.prefix}/${owner.name}/${packagePath}`);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const iconExtension = (sourcePath: string): string => {
|
|
235
|
+
const extension = extname(sourcePath).toLowerCase();
|
|
236
|
+
|
|
237
|
+
if (!ICON_EXTENSIONS.has(extension)) {
|
|
238
|
+
throw new Error(`${sourcePath} is not a supported themed icon; use an SVG, PNG, or XPM file`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return extension;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const hasIconNamePathSeparator = (value: string): boolean =>
|
|
245
|
+
value.includes("\0") || value.includes("/") || value.includes("\\");
|
|
246
|
+
|
|
247
|
+
const validateIconName = (value: string): string => {
|
|
248
|
+
if (
|
|
249
|
+
RESERVED_ICON_NAMES.has(value) ||
|
|
250
|
+
hasIconNamePathSeparator(value) ||
|
|
251
|
+
ICON_EXTENSIONS.has(extname(value).toLowerCase())
|
|
252
|
+
) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`${JSON.stringify(value)} is not a valid icon name; use an extensionless filename without slashes`,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return value;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const isIconContext = (parts: string[]): boolean => {
|
|
262
|
+
const [first, second] = parts;
|
|
263
|
+
|
|
264
|
+
if (parts.length === 1) {
|
|
265
|
+
return first !== undefined && ICON_CONTEXTS.has(first);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return parts.length === 2 && first === "stock" && second !== undefined && STOCK_ICON_CONTEXTS.has(second);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const isIconLayout = (parts: string[]): boolean => {
|
|
272
|
+
const [size, ...context] = parts;
|
|
273
|
+
|
|
274
|
+
if (size === "symbolic") {
|
|
275
|
+
return context.length === 1 && context[0] === "apps";
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return size !== undefined && (size === "scalable" || ICON_SIZE_RE.test(size)) && isIconContext(context);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const iconLayoutInParts = (parts: string[], beforeIndex: number): string | null => {
|
|
282
|
+
const index = parts.lastIndexOf("icons", beforeIndex);
|
|
283
|
+
|
|
284
|
+
if (index === -1) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const treePath = parts.slice(index + 1, -1);
|
|
289
|
+
const layout = treePath[0] === "hicolor" ? treePath.slice(1) : treePath;
|
|
290
|
+
|
|
291
|
+
return isIconLayout(layout) ? layout.join("/") : iconLayoutInParts(parts, index - 1);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const iconLayoutFromTree = (sourcePath: string): string | null => {
|
|
295
|
+
const parts = toForwardSlashes(sourcePath).split("/");
|
|
296
|
+
|
|
297
|
+
return iconLayoutInParts(parts, parts.length - 2);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const derivedIconEntry = (
|
|
301
|
+
state: PluginState,
|
|
302
|
+
sourcePath: string,
|
|
303
|
+
requestedName: string | null,
|
|
304
|
+
): DerivedIconEntry => {
|
|
305
|
+
const extension = iconExtension(sourcePath);
|
|
306
|
+
const sourceName = basename(sourcePath, extname(sourcePath));
|
|
307
|
+
const iconName = validateIconName(requestedName ?? sourceName);
|
|
308
|
+
const layout = iconLayoutFromTree(sourcePath);
|
|
309
|
+
|
|
310
|
+
const iconIdentity = layout === null
|
|
311
|
+
? `${state.prefix}/icons/${iconName}`
|
|
312
|
+
: `${state.prefix}/icons/${layout}/${iconName}`;
|
|
313
|
+
|
|
314
|
+
const resourcePath = validateResourcePath(`${iconIdentity}${extension}`);
|
|
315
|
+
|
|
316
|
+
return { iconIdentity, iconName, resourcePath };
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const hasSideEffectIconImport = (code: string, id: string): boolean => {
|
|
320
|
+
const lang = sourceLanguage(stripQuery(id));
|
|
321
|
+
|
|
322
|
+
if (lang === undefined || !code.includes("?icon")) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const parsed = parseSync(id, code, { lang });
|
|
327
|
+
|
|
328
|
+
if (parsed.errors.length > 0) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return parsed.module.staticImports.some(
|
|
333
|
+
(statement) => statement.entries.length === 0 && parseIconSpecifier(statement.moduleRequest.value) !== null,
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const retainSideEffectIconImport = (
|
|
338
|
+
state: PluginState,
|
|
339
|
+
code: string,
|
|
340
|
+
id: string,
|
|
341
|
+
): { code: string; moduleSideEffects: true } | null =>
|
|
342
|
+
state.isV2 && hasSideEffectIconImport(code, id)
|
|
343
|
+
? { code, moduleSideEffects: true }
|
|
344
|
+
: null;
|
|
51
345
|
|
|
52
346
|
const compileBundle = (state: PluginState, outputPath: string): Buffer =>
|
|
53
347
|
withStagingDir("resources", (dir) => {
|
|
@@ -103,12 +397,16 @@ const releaseStagingDir = (state: PluginState): void => {
|
|
|
103
397
|
state.compiledSignature = "";
|
|
104
398
|
};
|
|
105
399
|
|
|
106
|
-
const entriesSignature = (state: PluginState): string =>
|
|
400
|
+
const entriesSignature = (state: PluginState): string =>
|
|
401
|
+
sortStrings([...state.entries].map(([resourcePath, entry]) => `${resourcePath}\0${entry.sourcePath}`)).join("\0");
|
|
107
402
|
|
|
108
403
|
const compileDevBundle = (state: PluginState): void => {
|
|
109
404
|
ensureStagingDir(state);
|
|
110
405
|
|
|
111
406
|
if (state.entries.size === 0) {
|
|
407
|
+
rmSync(state.devBundlePath, { force: true });
|
|
408
|
+
state.compiledSignature = "";
|
|
409
|
+
|
|
112
410
|
return;
|
|
113
411
|
}
|
|
114
412
|
|
|
@@ -118,15 +416,14 @@ const compileDevBundle = (state: PluginState): void => {
|
|
|
118
416
|
|
|
119
417
|
const isRefreshHook = (value: unknown): value is () => void => typeof value === "function";
|
|
120
418
|
|
|
121
|
-
const
|
|
419
|
+
const refreshRegisteredDevBundle = (state: PluginState): void => {
|
|
122
420
|
const server = state.server;
|
|
123
421
|
|
|
124
422
|
if (!server) {
|
|
125
423
|
return;
|
|
126
424
|
}
|
|
127
425
|
|
|
128
|
-
const
|
|
129
|
-
const refresh: unknown = mod[REFRESH_EXPORT];
|
|
426
|
+
const refresh: unknown = server.moduleGraph.getModuleById(VIRTUAL_INIT)?.ssrModule?.[REFRESH_EXPORT];
|
|
130
427
|
|
|
131
428
|
if (isRefreshHook(refresh)) {
|
|
132
429
|
refresh();
|
|
@@ -135,7 +432,7 @@ const reregisterDevBundle = async (state: PluginState): Promise<void> => {
|
|
|
135
432
|
|
|
136
433
|
const scanDataAssets = (dataDir: string): ListedFile[] => listFilesRecursive(dataDir, (name) => ASSET_RE.test(name));
|
|
137
434
|
|
|
138
|
-
const
|
|
435
|
+
const primeLegacyDevBundle = (state: PluginState): void => {
|
|
139
436
|
if (state.dataDir === null) {
|
|
140
437
|
return;
|
|
141
438
|
}
|
|
@@ -153,114 +450,963 @@ const registerDevAsset = (state: PluginState): void => {
|
|
|
153
450
|
}
|
|
154
451
|
};
|
|
155
452
|
|
|
156
|
-
const
|
|
157
|
-
|
|
453
|
+
const importerKey = (importer: string): string => stripQuery(importer);
|
|
454
|
+
|
|
455
|
+
const trackBundledSpecifier = (state: PluginState, importer: string | undefined, source: string): void => {
|
|
456
|
+
if (importer === undefined) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const key = importerKey(importer);
|
|
461
|
+
const specifiers = state.bundledSpecifiers.get(key) ?? new Set<string>();
|
|
462
|
+
specifiers.add(source);
|
|
463
|
+
state.bundledSpecifiers.set(key, specifiers);
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const createResourceEntry = (sourcePath: string, resourcePath: string): ResourceEntry => ({
|
|
467
|
+
sourcePath,
|
|
468
|
+
stagedRelPath: resourcePath.replace(/^\/+/, ""),
|
|
469
|
+
resourcePath,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const activateEntry = (state: PluginState, entry: ResourceEntry): ResourceEntry => {
|
|
473
|
+
const existing = state.entries.get(entry.resourcePath);
|
|
474
|
+
|
|
475
|
+
if (existing !== undefined) {
|
|
476
|
+
if (existing.sourcePath !== entry.sourcePath) {
|
|
477
|
+
throw new Error(
|
|
478
|
+
`${existing.sourcePath} and ${entry.sourcePath} both resolve to the GResource path ` +
|
|
479
|
+
entry.resourcePath,
|
|
480
|
+
);
|
|
481
|
+
}
|
|
158
482
|
|
|
159
|
-
if (existing) {
|
|
160
483
|
return existing;
|
|
161
484
|
}
|
|
162
485
|
|
|
163
|
-
|
|
486
|
+
state.entries.set(entry.resourcePath, entry);
|
|
487
|
+
state.sourcePaths.add(entry.sourcePath);
|
|
164
488
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
489
|
+
return entry;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const isDeclarativeImporter = (state: PluginState, importer: string | undefined): importer is string =>
|
|
493
|
+
!state.isBuild && state.isV2 && importer !== undefined;
|
|
494
|
+
|
|
495
|
+
const setSourceAvailability = (state: PluginState, file: string, isAvailable: boolean): void => {
|
|
496
|
+
if (isAvailable) {
|
|
497
|
+
state.missingSourcePaths.delete(file);
|
|
498
|
+
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
state.missingSourcePaths.add(file);
|
|
503
|
+
};
|
|
170
504
|
|
|
171
|
-
|
|
172
|
-
|
|
505
|
+
const isDeclaredSourceAvailable = (state: PluginState, sourcePath: string): boolean => {
|
|
506
|
+
const isAvailable = existsSync(sourcePath);
|
|
507
|
+
setSourceAvailability(state, sourcePath, isAvailable);
|
|
508
|
+
|
|
509
|
+
return isAvailable;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const declareEntry = (state: PluginState, importer: string, entry: ResourceEntry): ResourceEntry => {
|
|
513
|
+
const key = importerKey(importer);
|
|
514
|
+
const declarations = state.declaredEntries.get(key) ?? new Map<string, ResourceEntry>();
|
|
515
|
+
const existing = declarations.get(entry.resourcePath);
|
|
516
|
+
|
|
517
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
518
|
+
throw new Error(
|
|
519
|
+
`${existing.sourcePath} and ${entry.sourcePath} both resolve to the GResource path ` +
|
|
520
|
+
entry.resourcePath,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const declared = existing ?? entry;
|
|
525
|
+
declarations.set(entry.resourcePath, declared);
|
|
526
|
+
state.declaredEntries.set(key, declarations);
|
|
527
|
+
state.server?.watcher.add(dirname(declared.sourcePath));
|
|
528
|
+
|
|
529
|
+
return declared;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const declareIcon = (
|
|
533
|
+
state: PluginState,
|
|
534
|
+
importer: string,
|
|
535
|
+
iconIdentity: string,
|
|
536
|
+
entry: ResourceEntry,
|
|
537
|
+
): void => {
|
|
538
|
+
const key = importerKey(importer);
|
|
539
|
+
const declarations = state.declaredIcons.get(key) ?? new Map<string, ResourceEntry>();
|
|
540
|
+
const existing = declarations.get(iconIdentity);
|
|
541
|
+
|
|
542
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
`${existing.sourcePath} and ${entry.sourcePath} both claim the themed icon ${iconIdentity}`,
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
declarations.set(iconIdentity, existing ?? entry);
|
|
549
|
+
state.declaredIcons.set(key, declarations);
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
const assertIconIdentityAvailable = (
|
|
553
|
+
state: PluginState,
|
|
554
|
+
iconIdentity: string,
|
|
555
|
+
sourcePath: string,
|
|
556
|
+
): void => {
|
|
557
|
+
const existing = state.iconOwners.get(iconIdentity);
|
|
558
|
+
|
|
559
|
+
if (existing !== undefined && existing.sourcePath !== sourcePath) {
|
|
560
|
+
throw new Error(
|
|
561
|
+
`${existing.sourcePath} and ${sourcePath} both claim the themed icon ${iconIdentity}`,
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const declareResolvedIcon = (
|
|
567
|
+
state: PluginState,
|
|
568
|
+
importer: string | undefined,
|
|
569
|
+
iconIdentity: string,
|
|
570
|
+
entry: ResourceEntry,
|
|
571
|
+
): void => {
|
|
572
|
+
if (isDeclarativeImporter(state, importer)) {
|
|
573
|
+
declareIcon(state, importer, iconIdentity, entry);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
const registerEntry = (
|
|
578
|
+
state: PluginState,
|
|
579
|
+
absPath: string,
|
|
580
|
+
rel: string,
|
|
581
|
+
importer?: string,
|
|
582
|
+
): ResourceEntry => {
|
|
583
|
+
const resourcePath = validateResourcePath(rel.startsWith("/") ? rel : `${state.prefix}/${rel}`);
|
|
584
|
+
let entry = createResourceEntry(absPath, resourcePath);
|
|
585
|
+
|
|
586
|
+
if (isDeclarativeImporter(state, importer)) {
|
|
587
|
+
entry = declareEntry(state, importer, entry);
|
|
588
|
+
|
|
589
|
+
if (!isImporterActive(state, importer) || !isDeclaredSourceAvailable(state, absPath)) {
|
|
590
|
+
return entry;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return activateEntry(state, entry);
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
const registerIconEntry = (
|
|
598
|
+
state: PluginState,
|
|
599
|
+
sourcePath: string,
|
|
600
|
+
derived: DerivedIconEntry,
|
|
601
|
+
importer: string | undefined,
|
|
602
|
+
): ResourceEntry => {
|
|
603
|
+
const shouldActivate = !isDeclarativeImporter(state, importer) ||
|
|
604
|
+
(isImporterActive(state, importer) && isDeclaredSourceAvailable(state, sourcePath));
|
|
605
|
+
|
|
606
|
+
if (shouldActivate) {
|
|
607
|
+
assertIconIdentityAvailable(state, derived.iconIdentity, sourcePath);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const entry = registerEntry(state, sourcePath, derived.resourcePath, importer);
|
|
611
|
+
declareResolvedIcon(state, importer, derived.iconIdentity, entry);
|
|
612
|
+
|
|
613
|
+
if (shouldActivate) {
|
|
614
|
+
state.iconOwners.set(derived.iconIdentity, entry);
|
|
615
|
+
}
|
|
173
616
|
|
|
174
617
|
return entry;
|
|
175
618
|
};
|
|
176
619
|
|
|
177
620
|
const isTrackedSource = (state: PluginState, file: string): boolean => state.sourcePaths.has(file);
|
|
178
621
|
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
622
|
+
const hasSourceEntry = (entries: Map<string, ResourceEntry>, file: string): boolean => {
|
|
623
|
+
for (const entry of entries.values()) {
|
|
624
|
+
if (entry.sourcePath === file) {
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return false;
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
const hasDeclaredSource = (
|
|
633
|
+
declarations: Map<string, Map<string, ResourceEntry>>,
|
|
634
|
+
file: string,
|
|
635
|
+
): boolean => {
|
|
636
|
+
for (const entries of declarations.values()) {
|
|
637
|
+
if (hasSourceEntry(entries, file)) {
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return false;
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
const isDeclaredSource = (state: PluginState, file: string): boolean =>
|
|
646
|
+
hasDeclaredSource(state.declaredEntries, file) || hasDeclaredSource(state.declaredIcons, file);
|
|
647
|
+
|
|
648
|
+
const virtualAssetId = (entry: ResourceEntry): string =>
|
|
649
|
+
toVirtualId(entry.sourcePath) + REL_SEPARATOR + entry.resourcePath;
|
|
650
|
+
|
|
651
|
+
const virtualIconId = ({ entry, iconName }: ResolvedIconEntry): string =>
|
|
652
|
+
virtualAssetId(entry) + ICON_NAME_SEPARATOR + iconName;
|
|
653
|
+
|
|
654
|
+
const resolveAssetSource = async (
|
|
655
|
+
ctx: ResolveContext,
|
|
656
|
+
request: { assetSource: string; importer: string | undefined; options: Record<string, unknown> | undefined },
|
|
657
|
+
): Promise<string | undefined> => {
|
|
658
|
+
const resolved = await ctx.resolve(request.assetSource, request.importer, {
|
|
659
|
+
...request.options,
|
|
660
|
+
skipSelf: true,
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
if (!resolved || resolved.external) {
|
|
664
|
+
return undefined;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const sourcePath = stripQuery(resolved.id);
|
|
668
|
+
|
|
669
|
+
if (!isAbsolute(sourcePath)) {
|
|
670
|
+
throw new Error(`${JSON.stringify(request.assetSource)} did not resolve to a file-backed asset`);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return sourcePath;
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const resolveAssetEntry = async (
|
|
677
|
+
ctx: ResolveContext,
|
|
678
|
+
state: PluginState,
|
|
679
|
+
request: AssetResolveRequest,
|
|
680
|
+
): Promise<ResourceEntry | undefined> => {
|
|
681
|
+
const sourcePath = await resolveAssetSource(ctx, request);
|
|
682
|
+
|
|
683
|
+
if (sourcePath === undefined) {
|
|
684
|
+
return undefined;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return registerEntry(
|
|
688
|
+
state,
|
|
689
|
+
sourcePath,
|
|
690
|
+
request.resourcePath === null
|
|
691
|
+
? derivedResourcePath(state, sourcePath)
|
|
692
|
+
: validateResourcePath(request.resourcePath),
|
|
693
|
+
request.importer,
|
|
694
|
+
);
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
const resolveIconEntry = async (
|
|
698
|
+
ctx: ResolveContext,
|
|
699
|
+
state: PluginState,
|
|
700
|
+
request: IconResolveRequest,
|
|
701
|
+
): Promise<ResolvedIconEntry | undefined> => {
|
|
702
|
+
const sourcePath = await resolveAssetSource(ctx, request);
|
|
703
|
+
|
|
704
|
+
if (sourcePath === undefined) {
|
|
705
|
+
return undefined;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const derived = derivedIconEntry(state, sourcePath, request.iconName);
|
|
709
|
+
|
|
710
|
+
return {
|
|
711
|
+
entry: registerIconEntry(state, sourcePath, derived, request.importer),
|
|
712
|
+
iconName: derived.iconName,
|
|
713
|
+
};
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
const resolveLegacyAssetEntry = async (
|
|
717
|
+
ctx: ResolveContext,
|
|
718
|
+
state: PluginState,
|
|
719
|
+
request: LegacyResolveRequest,
|
|
720
|
+
): Promise<ResourceEntry | undefined> => {
|
|
721
|
+
const resolved = await ctx.resolve(request.source, request.importer, { ...request.options, skipSelf: true });
|
|
722
|
+
|
|
183
723
|
if (!resolved || resolved.external) {
|
|
184
724
|
return undefined;
|
|
185
725
|
}
|
|
186
726
|
|
|
187
|
-
|
|
727
|
+
const sourcePath = stripQuery(resolved.id);
|
|
728
|
+
|
|
729
|
+
if (!isAbsolute(sourcePath)) {
|
|
730
|
+
return undefined;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
return registerEntry(state, sourcePath, request.source.slice(DATA_PREFIX.length));
|
|
188
734
|
};
|
|
189
735
|
|
|
190
736
|
const loadInitModule = (state: PluginState): string => {
|
|
191
|
-
if (
|
|
192
|
-
|
|
737
|
+
if (state.isBuild) {
|
|
738
|
+
if (state.bundleReferenceId === null) {
|
|
739
|
+
throw new Error("Cannot render the GResource loader before its bundle has been emitted");
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return renderInitModule({ isBuild: true, bundleReferenceId: state.bundleReferenceId });
|
|
193
743
|
}
|
|
194
744
|
|
|
195
|
-
|
|
745
|
+
ensureStagingDir(state);
|
|
746
|
+
|
|
747
|
+
return renderInitModule({ isBuild: false, devBundlePath: state.devBundlePath });
|
|
196
748
|
};
|
|
197
749
|
|
|
198
|
-
const
|
|
750
|
+
const virtualAssetMetadata = (virtualId: string): { absPath: string; iconName: string | null; rel: string } => {
|
|
199
751
|
const rest = fromVirtualId(virtualId);
|
|
200
752
|
const separatorIndex = rest.indexOf(REL_SEPARATOR);
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
753
|
+
const relAndMetadata = rest.slice(separatorIndex + REL_SEPARATOR.length);
|
|
754
|
+
const iconSeparatorIndex = relAndMetadata.indexOf(ICON_NAME_SEPARATOR);
|
|
755
|
+
|
|
756
|
+
return {
|
|
757
|
+
absPath: rest.slice(0, separatorIndex),
|
|
758
|
+
iconName: iconSeparatorIndex === -1
|
|
759
|
+
? null
|
|
760
|
+
: relAndMetadata.slice(iconSeparatorIndex + ICON_NAME_SEPARATOR.length),
|
|
761
|
+
rel: iconSeparatorIndex === -1 ? relAndMetadata : relAndMetadata.slice(0, iconSeparatorIndex),
|
|
762
|
+
};
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
const resourcePathExport = (entry: ResourceEntry, iconName: string | null): string[] =>
|
|
766
|
+
iconName === null ? [`export const ${RESOURCE_PATH_EXPORT} = ${JSON.stringify(entry.resourcePath)};`] : [];
|
|
767
|
+
|
|
768
|
+
const assetModuleImports = (iconName: string | null): string[] => {
|
|
769
|
+
const initBindings = iconName === null
|
|
770
|
+
? "ensureRegistered"
|
|
771
|
+
: `ensureRegistered, ${REGISTER_REFRESH_EXPORT}`;
|
|
772
|
+
|
|
773
|
+
return [
|
|
774
|
+
`import { ${initBindings} } from ${JSON.stringify(VIRTUAL_INIT)};`,
|
|
775
|
+
...(iconName === null
|
|
776
|
+
? []
|
|
777
|
+
: [
|
|
778
|
+
"import { Display } from \"@gtkx/gi/gdk\";",
|
|
779
|
+
"import { IconTheme } from \"@gtkx/gi/gtk\";",
|
|
780
|
+
]),
|
|
781
|
+
];
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
const iconThemeRegistration = (state: PluginState, iconName: string | null): string[] => {
|
|
785
|
+
if (iconName === null) {
|
|
786
|
+
return [];
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const resourceIconPath = `${state.prefix}/icons`;
|
|
790
|
+
|
|
791
|
+
return [
|
|
792
|
+
`const resourceIconPath = ${JSON.stringify(resourceIconPath)};`,
|
|
793
|
+
"function refreshIconTheme() {",
|
|
794
|
+
" const display = Display.getDefault();",
|
|
795
|
+
" if (!display) return;",
|
|
796
|
+
" const theme = IconTheme.getForDisplay(display);",
|
|
797
|
+
" const paths = theme.getResourcePath() ?? [];",
|
|
798
|
+
" theme.setResourcePath(paths.includes(resourceIconPath) ? [...paths] : [...paths, resourceIconPath]);",
|
|
799
|
+
"}",
|
|
800
|
+
`${REGISTER_REFRESH_EXPORT}(resourceIconPath, refreshIconTheme);`,
|
|
801
|
+
];
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
const loadedResourceEntry = (
|
|
805
|
+
state: PluginState,
|
|
806
|
+
sourcePath: string,
|
|
807
|
+
resourcePath: string,
|
|
808
|
+
): { entry: ResourceEntry; isRegistered: boolean } => {
|
|
809
|
+
const registered = state.entries.get(resourcePath);
|
|
810
|
+
|
|
811
|
+
if (registered === undefined) {
|
|
812
|
+
return { entry: createResourceEntry(sourcePath, resourcePath), isRegistered: false };
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if (registered.sourcePath !== sourcePath) {
|
|
816
|
+
throw new Error(
|
|
817
|
+
`${registered.sourcePath} and ${sourcePath} both resolve to the GResource path ${resourcePath}`,
|
|
818
|
+
);
|
|
819
|
+
}
|
|
205
820
|
|
|
206
|
-
|
|
821
|
+
return { entry: registered, isRegistered: true };
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
const compileLoadedDevAsset = (state: PluginState, isRegistered: boolean): void => {
|
|
825
|
+
if (isRegistered && !state.isBuild) {
|
|
207
826
|
registerDevAsset(state);
|
|
208
827
|
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
const loadAssetModule = (state: PluginState, virtualId: string): string => {
|
|
831
|
+
const { absPath, iconName, rel } = virtualAssetMetadata(virtualId);
|
|
832
|
+
const resourcePath = validateResourcePath(rel);
|
|
833
|
+
const { entry, isRegistered } = loadedResourceEntry(state, absPath, resourcePath);
|
|
834
|
+
const uri = `resource://${entry.resourcePath}`;
|
|
835
|
+
const defaultValue = iconName ?? (state.isV2 ? entry.resourcePath : uri);
|
|
836
|
+
compileLoadedDevAsset(state, isRegistered);
|
|
209
837
|
|
|
210
838
|
return [
|
|
211
|
-
|
|
839
|
+
...assetModuleImports(iconName),
|
|
212
840
|
"ensureRegistered();",
|
|
213
|
-
|
|
214
|
-
`export
|
|
841
|
+
...iconThemeRegistration(state, iconName),
|
|
842
|
+
`export default ${JSON.stringify(defaultValue)};`,
|
|
843
|
+
...resourcePathExport(entry, iconName),
|
|
215
844
|
].join("\n");
|
|
216
845
|
};
|
|
217
846
|
|
|
218
|
-
const
|
|
219
|
-
|
|
847
|
+
const finalizeBuildBundle = (
|
|
848
|
+
ctx: Pick<Rolldown.PluginContext, "getFileName">,
|
|
849
|
+
bundle: Rolldown.OutputBundle,
|
|
850
|
+
state: PluginState,
|
|
851
|
+
): void => {
|
|
852
|
+
if (!state.isBuild || state.bundleReferenceId === null) {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const fileName = ctx.getFileName(state.bundleReferenceId);
|
|
857
|
+
const output = bundle[fileName];
|
|
858
|
+
|
|
859
|
+
if (output?.type !== "asset") {
|
|
860
|
+
throw new Error(`Cannot find the emitted ${BUNDLE_FILENAME} asset`);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (state.entries.size === 0) {
|
|
864
|
+
Reflect.deleteProperty(bundle, fileName);
|
|
865
|
+
|
|
220
866
|
return;
|
|
221
867
|
}
|
|
222
868
|
|
|
223
869
|
const compiled = withStagingDir("resources-out", (outDir) => compileBundle(state, join(outDir, BUNDLE_FILENAME)));
|
|
224
|
-
|
|
870
|
+
output.source = compiled;
|
|
225
871
|
info(`Compiled ${String(state.entries.size)} resource(s) into ${BUNDLE_FILENAME}`);
|
|
226
872
|
};
|
|
227
873
|
|
|
228
|
-
const refreshDevRegistration =
|
|
874
|
+
const refreshDevRegistration = (state: PluginState): void => {
|
|
229
875
|
compileDevBundle(state);
|
|
230
876
|
|
|
231
877
|
try {
|
|
232
|
-
|
|
878
|
+
refreshRegisteredDevBundle(state);
|
|
233
879
|
} catch (error_) {
|
|
234
880
|
error("Failed to refresh GResource bundle:", error_);
|
|
235
881
|
}
|
|
236
882
|
};
|
|
237
883
|
|
|
884
|
+
const isSameSpecifiers = (left: Set<string> | undefined, right: Set<string>): boolean =>
|
|
885
|
+
left === undefined
|
|
886
|
+
? right.size === 0
|
|
887
|
+
: left.size === right.size && [...right].every((source) => left.has(source));
|
|
888
|
+
|
|
889
|
+
const bundledSpecifiersIn = (imports: SourceImport[]): Set<string> =>
|
|
890
|
+
new Set(
|
|
891
|
+
imports
|
|
892
|
+
.filter((entry) =>
|
|
893
|
+
parseResourceSpecifier(entry.source) !== null || parseIconSpecifier(entry.source) !== null)
|
|
894
|
+
.map((entry) => entry.source),
|
|
895
|
+
);
|
|
896
|
+
|
|
897
|
+
const isSourceModule = (file: string): boolean => sourceLanguage(file) !== undefined;
|
|
898
|
+
|
|
899
|
+
const isBundledSource = (source: string): boolean =>
|
|
900
|
+
parseResourceSpecifier(source) !== null || parseIconSpecifier(source) !== null;
|
|
901
|
+
|
|
902
|
+
const validateUnbundledV2Source = (source: string): void => {
|
|
903
|
+
if (isLegacyDataSpecifier(source)) {
|
|
904
|
+
throw new Error(`${JSON.stringify(source)} uses the legacy #data asset form`);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
rejectInvalidV2Specifier(source);
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
const resolvedModuleDependency = async (
|
|
911
|
+
ctx: ResolveContext,
|
|
912
|
+
source: string,
|
|
913
|
+
importer: string,
|
|
914
|
+
): Promise<string | null> => {
|
|
915
|
+
if (isBundledSource(source)) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
validateUnbundledV2Source(source);
|
|
920
|
+
const resolved = await ctx.resolve(source, importer, { skipSelf: true });
|
|
921
|
+
|
|
922
|
+
if (resolved === null) {
|
|
923
|
+
throw new Error(`${JSON.stringify(source)} could not be resolved from ${importer}`);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return resolved.external ? null : importerKey(resolved.id);
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
const resolvedModuleDependencies = async (
|
|
930
|
+
ctx: ResolveContext,
|
|
931
|
+
imports: SourceImport[],
|
|
932
|
+
importer: string,
|
|
933
|
+
): Promise<Set<string>> => {
|
|
934
|
+
const dependencies: Set<string> = new Set();
|
|
935
|
+
|
|
936
|
+
for (const entry of imports) {
|
|
937
|
+
const dependency = await resolvedModuleDependency(ctx, entry.source, importer);
|
|
938
|
+
|
|
939
|
+
if (dependency !== null) {
|
|
940
|
+
dependencies.add(dependency);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return dependencies;
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
const importerReconciliation = async (
|
|
948
|
+
ctx: ResolveContext,
|
|
949
|
+
state: PluginState,
|
|
950
|
+
id: string,
|
|
951
|
+
): Promise<ImporterReconciliation | null> => {
|
|
952
|
+
const file = stripQuery(id);
|
|
953
|
+
const key = importerKey(file);
|
|
954
|
+
|
|
955
|
+
if (!state.isV2 || state.isBuild || !isSourceModule(file)) {
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const imports = parseRuntimeImportsIn(file);
|
|
960
|
+
|
|
961
|
+
if (imports === null) {
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
return {
|
|
966
|
+
currentBundled: bundledSpecifiersIn(imports),
|
|
967
|
+
currentDependencies: await resolvedModuleDependencies(ctx, imports, file),
|
|
968
|
+
file,
|
|
969
|
+
imports,
|
|
970
|
+
key,
|
|
971
|
+
previousBundled: state.bundledSpecifiers.get(key),
|
|
972
|
+
previousDependencies: state.moduleDependencies.get(key),
|
|
973
|
+
};
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
const moduleNodeKey = (module: ModuleNode): string => importerKey(module.id ?? module.file ?? module.url);
|
|
977
|
+
|
|
978
|
+
const moduleNodeFor = (state: PluginState, id: string): ModuleNode | undefined => {
|
|
979
|
+
const server = state.server;
|
|
980
|
+
|
|
981
|
+
if (server === null) {
|
|
982
|
+
return undefined;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
return server.moduleGraph.getModuleById(id) ?? server.moduleGraph.getModuleById(importerKey(id));
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
const restoreDependencies = (pruned: Set<string>, current: Set<string>): void => {
|
|
989
|
+
for (const dependency of current) {
|
|
990
|
+
pruned.delete(dependency);
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
const pruneRemovedDependencies = (
|
|
995
|
+
pruned: Set<string>,
|
|
996
|
+
previous: Set<string> | undefined,
|
|
997
|
+
current: Set<string>,
|
|
998
|
+
): void => {
|
|
999
|
+
if (previous === undefined) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
for (const dependency of previous) {
|
|
1004
|
+
if (!current.has(dependency)) {
|
|
1005
|
+
pruned.add(dependency);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
const storePrunedDependencies = (state: PluginState, key: string, pruned: Set<string>): void => {
|
|
1011
|
+
if (pruned.size === 0) {
|
|
1012
|
+
state.prunedDependencies.delete(key);
|
|
1013
|
+
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
state.prunedDependencies.set(key, pruned);
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
const updatePrunedDependencies = (
|
|
1021
|
+
state: PluginState,
|
|
1022
|
+
key: string,
|
|
1023
|
+
previous: Set<string> | undefined,
|
|
1024
|
+
current: Set<string>,
|
|
1025
|
+
): void => {
|
|
1026
|
+
const pruned = state.prunedDependencies.get(key) ?? new Set<string>();
|
|
1027
|
+
restoreDependencies(pruned, current);
|
|
1028
|
+
pruneRemovedDependencies(pruned, previous, current);
|
|
1029
|
+
storePrunedDependencies(state, key, pruned);
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
const isPrunedDependency = (state: PluginState, importer: ModuleNode, imported: ModuleNode): boolean =>
|
|
1033
|
+
state.prunedDependencies.get(moduleNodeKey(importer))?.has(moduleNodeKey(imported)) === true;
|
|
1034
|
+
|
|
1035
|
+
const fallbackRootModules = (state: PluginState): string[] => {
|
|
1036
|
+
const roots: string[] = [];
|
|
1037
|
+
|
|
1038
|
+
for (const key of state.moduleDependencies.keys()) {
|
|
1039
|
+
if (moduleNodeFor(state, key)?.importers.size === 0) {
|
|
1040
|
+
roots.push(key);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return roots;
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
const enqueueCurrentDependencies = (state: PluginState, key: string, pending: string[]): void => {
|
|
1048
|
+
const dependencies = state.moduleDependencies.get(key) ?? [];
|
|
1049
|
+
|
|
1050
|
+
for (const dependency of dependencies) {
|
|
1051
|
+
pending.push(dependency);
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
const enqueueGraphDependencies = (state: PluginState, key: string, pending: string[]): void => {
|
|
1056
|
+
const module = moduleNodeFor(state, key);
|
|
1057
|
+
|
|
1058
|
+
if (module === undefined) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
for (const imported of module.importedModules) {
|
|
1063
|
+
if (!isPrunedDependency(state, module, imported)) {
|
|
1064
|
+
pending.push(moduleNodeKey(imported));
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
const visitActiveImporter = (
|
|
1070
|
+
state: PluginState,
|
|
1071
|
+
active: Set<string>,
|
|
1072
|
+
pending: string[],
|
|
1073
|
+
key: string,
|
|
1074
|
+
): void => {
|
|
1075
|
+
if (active.has(key)) {
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
active.add(key);
|
|
1080
|
+
enqueueCurrentDependencies(state, key, pending);
|
|
1081
|
+
enqueueGraphDependencies(state, key, pending);
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
const activeImporterKeys = (state: PluginState): Set<string> => {
|
|
1085
|
+
const active: Set<string> = new Set();
|
|
1086
|
+
const roots = state.entryModule === null ? fallbackRootModules(state) : [state.entryModule];
|
|
1087
|
+
const pending = [...roots];
|
|
1088
|
+
|
|
1089
|
+
while (pending.length > 0) {
|
|
1090
|
+
const key = pending.pop();
|
|
1091
|
+
|
|
1092
|
+
if (key === undefined || active.has(key)) {
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
visitActiveImporter(state, active, pending, key);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return active;
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
const isImporterActive = (state: PluginState, importer: string): boolean =>
|
|
1103
|
+
activeImporterKeys(state).has(importerKey(importer));
|
|
1104
|
+
|
|
1105
|
+
const activateDeclaredIcon = (
|
|
1106
|
+
state: PluginState,
|
|
1107
|
+
iconIdentity: string,
|
|
1108
|
+
entry: ResourceEntry,
|
|
1109
|
+
): void => {
|
|
1110
|
+
const existing = state.iconOwners.get(iconIdentity);
|
|
1111
|
+
|
|
1112
|
+
if (existing !== undefined && existing.sourcePath !== entry.sourcePath) {
|
|
1113
|
+
throw new Error(
|
|
1114
|
+
`${existing.sourcePath} and ${entry.sourcePath} both claim the themed icon ${iconIdentity}`,
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
state.iconOwners.set(iconIdentity, activateEntry(state, entry));
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
const activateDeclaredEntries = (state: PluginState, importer: string): void => {
|
|
1122
|
+
const entries = state.declaredEntries.get(importer)?.values() ?? [];
|
|
1123
|
+
|
|
1124
|
+
for (const entry of entries) {
|
|
1125
|
+
if (isDeclaredSourceAvailable(state, entry.sourcePath)) {
|
|
1126
|
+
activateEntry(state, entry);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
const activateDeclaredIcons = (state: PluginState, importer: string): void => {
|
|
1132
|
+
const icons = state.declaredIcons.get(importer) ?? [];
|
|
1133
|
+
|
|
1134
|
+
for (const [iconIdentity, entry] of icons) {
|
|
1135
|
+
if (isDeclaredSourceAvailable(state, entry.sourcePath)) {
|
|
1136
|
+
activateDeclaredIcon(state, iconIdentity, entry);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
|
|
1141
|
+
const activateDeclaredClaims = (state: PluginState, active: Set<string>): void => {
|
|
1142
|
+
for (const importer of sortStrings(active)) {
|
|
1143
|
+
activateDeclaredEntries(state, importer);
|
|
1144
|
+
activateDeclaredIcons(state, importer);
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
const rebuildActiveClaims = (state: PluginState): void => {
|
|
1149
|
+
const previous = {
|
|
1150
|
+
entries: state.entries,
|
|
1151
|
+
iconOwners: state.iconOwners,
|
|
1152
|
+
sourcePaths: state.sourcePaths,
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
state.entries = new Map();
|
|
1156
|
+
state.iconOwners = new Map();
|
|
1157
|
+
state.sourcePaths = new Set();
|
|
1158
|
+
|
|
1159
|
+
try {
|
|
1160
|
+
activateDeclaredClaims(state, activeImporterKeys(state));
|
|
1161
|
+
} catch (error_) {
|
|
1162
|
+
state.entries = previous.entries;
|
|
1163
|
+
state.iconOwners = previous.iconOwners;
|
|
1164
|
+
state.sourcePaths = previous.sourcePaths;
|
|
1165
|
+
throw error_;
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
|
|
1169
|
+
const forgetImporterDeclarations = (state: PluginState, importer: string): void => {
|
|
1170
|
+
state.declaredEntries.delete(importer);
|
|
1171
|
+
state.declaredIcons.delete(importer);
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
const cloneStringSetMap = (source: Map<string, Set<string>>): Map<string, Set<string>> => {
|
|
1175
|
+
const clone: Map<string, Set<string>> = new Map();
|
|
1176
|
+
|
|
1177
|
+
for (const [key, values] of source) {
|
|
1178
|
+
clone.set(key, new Set(values));
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
return clone;
|
|
1182
|
+
};
|
|
1183
|
+
|
|
1184
|
+
const cloneDeclarationMap = (
|
|
1185
|
+
source: Map<string, Map<string, ResourceEntry>>,
|
|
1186
|
+
): Map<string, Map<string, ResourceEntry>> => {
|
|
1187
|
+
const clone: Map<string, Map<string, ResourceEntry>> = new Map();
|
|
1188
|
+
|
|
1189
|
+
for (const [key, declarations] of source) {
|
|
1190
|
+
clone.set(key, new Map(declarations));
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
return clone;
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1196
|
+
const reconciliationCandidate = (state: PluginState): PluginState => ({
|
|
1197
|
+
...state,
|
|
1198
|
+
bundledSpecifiers: cloneStringSetMap(state.bundledSpecifiers),
|
|
1199
|
+
moduleDependencies: cloneStringSetMap(state.moduleDependencies),
|
|
1200
|
+
prunedDependencies: cloneStringSetMap(state.prunedDependencies),
|
|
1201
|
+
declaredEntries: cloneDeclarationMap(state.declaredEntries),
|
|
1202
|
+
declaredIcons: cloneDeclarationMap(state.declaredIcons),
|
|
1203
|
+
missingSourcePaths: new Set(state.missingSourcePaths),
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
const storeBundledSpecifiers = (state: PluginState, importer: string, specifiers: Set<string>): void => {
|
|
1207
|
+
if (specifiers.size === 0) {
|
|
1208
|
+
state.bundledSpecifiers.delete(importer);
|
|
1209
|
+
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
state.bundledSpecifiers.set(importer, specifiers);
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
const applyImporterGraph = (state: PluginState, reconciliation: ImporterReconciliation): void => {
|
|
1217
|
+
updatePrunedDependencies(
|
|
1218
|
+
state,
|
|
1219
|
+
reconciliation.key,
|
|
1220
|
+
reconciliation.previousDependencies,
|
|
1221
|
+
reconciliation.currentDependencies,
|
|
1222
|
+
);
|
|
1223
|
+
|
|
1224
|
+
state.moduleDependencies.set(reconciliation.key, reconciliation.currentDependencies);
|
|
1225
|
+
storeBundledSpecifiers(state, reconciliation.key, reconciliation.currentBundled);
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
const declareReconciledResource = async (
|
|
1229
|
+
ctx: ResolveContext,
|
|
1230
|
+
state: PluginState,
|
|
1231
|
+
importer: string,
|
|
1232
|
+
source: string,
|
|
1233
|
+
): Promise<void> => {
|
|
1234
|
+
const resourceSpecifier = parseResourceSpecifier(source);
|
|
1235
|
+
|
|
1236
|
+
if (resourceSpecifier === null) {
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
const entry = await resolveAssetEntry(ctx, state, {
|
|
1241
|
+
assetSource: resourceSpecifier.assetSource,
|
|
1242
|
+
importer,
|
|
1243
|
+
resourcePath: resourceSpecifier.resourcePath,
|
|
1244
|
+
options: undefined,
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
if (entry === undefined || state.missingSourcePaths.has(entry.sourcePath)) {
|
|
1248
|
+
throw new Error(`${JSON.stringify(source)} did not resolve to a bundled resource`);
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1252
|
+
const declareReconciledIcon = async (
|
|
1253
|
+
ctx: ResolveContext,
|
|
1254
|
+
state: PluginState,
|
|
1255
|
+
importer: string,
|
|
1256
|
+
source: string,
|
|
1257
|
+
): Promise<void> => {
|
|
1258
|
+
const iconSpecifier = parseIconSpecifier(source);
|
|
1259
|
+
|
|
1260
|
+
if (iconSpecifier === null) {
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const entry = await resolveIconEntry(ctx, state, {
|
|
1265
|
+
assetSource: iconSpecifier.assetSource,
|
|
1266
|
+
iconName: iconSpecifier.iconName,
|
|
1267
|
+
importer,
|
|
1268
|
+
options: undefined,
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
if (entry === undefined || state.missingSourcePaths.has(entry.entry.sourcePath)) {
|
|
1272
|
+
throw new Error(`${JSON.stringify(source)} did not resolve to a bundled icon`);
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
const declareReconciledSource = async (
|
|
1277
|
+
ctx: ResolveContext,
|
|
1278
|
+
state: PluginState,
|
|
1279
|
+
importer: string,
|
|
1280
|
+
source: string,
|
|
1281
|
+
): Promise<void> => {
|
|
1282
|
+
await declareReconciledResource(ctx, state, importer, source);
|
|
1283
|
+
await declareReconciledIcon(ctx, state, importer, source);
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1286
|
+
const declareReconciledImports = async (
|
|
1287
|
+
ctx: ResolveContext,
|
|
1288
|
+
state: PluginState,
|
|
1289
|
+
reconciliation: ImporterReconciliation,
|
|
1290
|
+
): Promise<void> => {
|
|
1291
|
+
for (const entry of reconciliation.imports) {
|
|
1292
|
+
if (isBundledSource(entry.source)) {
|
|
1293
|
+
await declareReconciledSource(ctx, state, reconciliation.file, entry.source);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
const prepareReconciliation = async (
|
|
1299
|
+
ctx: ResolveContext,
|
|
1300
|
+
state: PluginState,
|
|
1301
|
+
reconciliation: ImporterReconciliation,
|
|
1302
|
+
): Promise<PluginState> => {
|
|
1303
|
+
const candidate = reconciliationCandidate(state);
|
|
1304
|
+
|
|
1305
|
+
const isBundledChanged = !isSameSpecifiers(
|
|
1306
|
+
reconciliation.previousBundled,
|
|
1307
|
+
reconciliation.currentBundled,
|
|
1308
|
+
);
|
|
1309
|
+
|
|
1310
|
+
if (isBundledChanged) {
|
|
1311
|
+
forgetImporterDeclarations(candidate, reconciliation.key);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
applyImporterGraph(candidate, reconciliation);
|
|
1315
|
+
rebuildActiveClaims(candidate);
|
|
1316
|
+
|
|
1317
|
+
if (isBundledChanged) {
|
|
1318
|
+
await declareReconciledImports(ctx, candidate, reconciliation);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
return candidate;
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
const commitReconciliation = (state: PluginState, candidate: PluginState): void => {
|
|
1325
|
+
state.entries = candidate.entries;
|
|
1326
|
+
state.bundledSpecifiers = candidate.bundledSpecifiers;
|
|
1327
|
+
state.moduleDependencies = candidate.moduleDependencies;
|
|
1328
|
+
state.prunedDependencies = candidate.prunedDependencies;
|
|
1329
|
+
state.declaredEntries = candidate.declaredEntries;
|
|
1330
|
+
state.declaredIcons = candidate.declaredIcons;
|
|
1331
|
+
state.missingSourcePaths = candidate.missingSourcePaths;
|
|
1332
|
+
state.sourcePaths = candidate.sourcePaths;
|
|
1333
|
+
state.iconOwners = candidate.iconOwners;
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
const reconcileV2Importer = async (ctx: ResolveContext, state: PluginState, id: string): Promise<void> => {
|
|
1337
|
+
const reconciliation = await importerReconciliation(ctx, state, id);
|
|
1338
|
+
|
|
1339
|
+
if (reconciliation === null) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
const previousSignature = entriesSignature(state);
|
|
1344
|
+
const candidate = await prepareReconciliation(ctx, state, reconciliation);
|
|
1345
|
+
commitReconciliation(state, candidate);
|
|
1346
|
+
|
|
1347
|
+
if (entriesSignature(state) !== previousSignature) {
|
|
1348
|
+
refreshDevRegistration(state);
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
|
|
238
1352
|
const resolveResourceConfig = async (state: PluginState, config: UserConfig, loadConfig: ConfigLoader) => {
|
|
239
|
-
const
|
|
240
|
-
state.prefix =
|
|
1353
|
+
const loaded = await loadConfig.load(config.root ?? process.cwd());
|
|
1354
|
+
state.prefix = resourceBasePath(loaded.config.applicationId);
|
|
1355
|
+
state.root = loaded.root;
|
|
1356
|
+
state.isV2 = loaded.config.future?.v2ResourceImports === true;
|
|
241
1357
|
|
|
242
1358
|
return {
|
|
243
1359
|
assetsInclude: [ASSET_RE],
|
|
244
1360
|
};
|
|
245
1361
|
};
|
|
246
1362
|
|
|
247
|
-
const refreshTrackedSource =
|
|
1363
|
+
const refreshTrackedSource = (state: PluginState, file: string): void => {
|
|
248
1364
|
if (!isTrackedSource(state, file)) {
|
|
249
1365
|
return;
|
|
250
1366
|
}
|
|
251
1367
|
|
|
252
1368
|
try {
|
|
253
|
-
|
|
1369
|
+
refreshDevRegistration(state);
|
|
254
1370
|
} catch (error_) {
|
|
255
1371
|
error("GResource refresh failed:", error_);
|
|
256
1372
|
}
|
|
257
1373
|
};
|
|
258
1374
|
|
|
1375
|
+
const rebuildForSourceAvailability = (state: PluginState, previousSignature: string): void => {
|
|
1376
|
+
try {
|
|
1377
|
+
rebuildActiveClaims(state);
|
|
1378
|
+
|
|
1379
|
+
if (entriesSignature(state) !== previousSignature) {
|
|
1380
|
+
refreshDevRegistration(state);
|
|
1381
|
+
}
|
|
1382
|
+
} catch (error_) {
|
|
1383
|
+
error("GResource source update failed:", error_);
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
|
|
1387
|
+
const updateTrackedSourceAvailability = (state: PluginState, file: string, isAvailable: boolean): void => {
|
|
1388
|
+
if (!isTrackedSource(state, file) && !state.missingSourcePaths.has(file) && !isDeclaredSource(state, file)) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
const previousSignature = entriesSignature(state);
|
|
1393
|
+
setSourceAvailability(state, file, isAvailable);
|
|
1394
|
+
rebuildForSourceAvailability(state, previousSignature);
|
|
1395
|
+
};
|
|
1396
|
+
|
|
259
1397
|
const attachResourceWatcher = (state: PluginState, server: ViteDevServer): void => {
|
|
260
1398
|
state.server = server;
|
|
261
1399
|
|
|
262
|
-
const
|
|
263
|
-
|
|
1400
|
+
const onChange = (file: string): void => {
|
|
1401
|
+
refreshTrackedSource(state, file);
|
|
1402
|
+
};
|
|
1403
|
+
|
|
1404
|
+
const onAdd = (file: string): void => {
|
|
1405
|
+
updateTrackedSourceAvailability(state, file, true);
|
|
1406
|
+
};
|
|
1407
|
+
|
|
1408
|
+
const onUnlink = (file: string): void => {
|
|
1409
|
+
updateTrackedSourceAvailability(state, file, false);
|
|
264
1410
|
};
|
|
265
1411
|
|
|
266
1412
|
const onClose = (): void => {
|
|
@@ -269,14 +1415,17 @@ const attachResourceWatcher = (state: PluginState, server: ViteDevServer): void
|
|
|
269
1415
|
|
|
270
1416
|
server.httpServer?.once("close", onClose);
|
|
271
1417
|
server.watcher.once("close", onClose);
|
|
272
|
-
server.watcher.on("change",
|
|
273
|
-
server.watcher.on("add",
|
|
1418
|
+
server.watcher.on("change", onChange);
|
|
1419
|
+
server.watcher.on("add", onAdd);
|
|
1420
|
+
server.watcher.on("unlink", onUnlink);
|
|
274
1421
|
};
|
|
275
1422
|
|
|
276
1423
|
const applyResolvedConfig = (state: PluginState, config: ResolvedConfig): void => {
|
|
277
1424
|
state.isBuild = config.command === "build";
|
|
1425
|
+
state.root = config.root;
|
|
1426
|
+
state.dataDir = null;
|
|
278
1427
|
|
|
279
|
-
if (state.isBuild) {
|
|
1428
|
+
if (state.isBuild || state.isV2) {
|
|
280
1429
|
return;
|
|
281
1430
|
}
|
|
282
1431
|
|
|
@@ -296,62 +1445,210 @@ const loadResourceModule = (state: PluginState, id: string): string | undefined
|
|
|
296
1445
|
return loadAssetModule(state, id);
|
|
297
1446
|
};
|
|
298
1447
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
prefix: "",
|
|
302
|
-
isBuild: false,
|
|
303
|
-
entries: new Map(),
|
|
304
|
-
sourcePaths: new Set(),
|
|
305
|
-
stagingDir: createRetainedStagingDir(DEV_STAGING_PREFIX),
|
|
306
|
-
devBundlePath: "",
|
|
307
|
-
server: null,
|
|
308
|
-
compiledSignature: "",
|
|
309
|
-
dataDir: null,
|
|
310
|
-
};
|
|
1448
|
+
const isLegacyDataSpecifier = (source: string): boolean =>
|
|
1449
|
+
source.startsWith(DATA_PREFIX) && ASSET_RE.test(stripQuery(source));
|
|
311
1450
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
1451
|
+
const rejectInvalidV2Specifier = (source: string): void => {
|
|
1452
|
+
if (BUNDLED_QUERY_MENTION_RE.test(source)) {
|
|
1453
|
+
throw new Error(
|
|
1454
|
+
`${JSON.stringify(source)} is not a valid bundled asset import; use ?resource, ` +
|
|
1455
|
+
"?resource=/absolute/path, ?icon, or ?icon=name",
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if (isBareRelativeAsset(source)) {
|
|
1460
|
+
throw new Error(
|
|
1461
|
+
`${JSON.stringify(source)} must choose ?resource for a GResource, ?icon for a themed icon, ` +
|
|
1462
|
+
"or ?url for an emitted file",
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
const resolveExplicitResourceId = async (
|
|
1468
|
+
ctx: ResolveContext,
|
|
1469
|
+
state: PluginState,
|
|
1470
|
+
request: LegacyResolveRequest,
|
|
1471
|
+
): Promise<string | undefined> => {
|
|
1472
|
+
const specifier = parseResourceSpecifier(request.source);
|
|
1473
|
+
|
|
1474
|
+
if (specifier === null) {
|
|
1475
|
+
return undefined;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
const entry = await resolveAssetEntry(ctx, state, {
|
|
1479
|
+
assetSource: specifier.assetSource,
|
|
1480
|
+
importer: request.importer,
|
|
1481
|
+
resourcePath: specifier.resourcePath,
|
|
1482
|
+
options: request.options,
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
return entry === undefined ? undefined : virtualAssetId(entry);
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
const resolveIconResourceId = async (
|
|
1489
|
+
ctx: ResolveContext,
|
|
1490
|
+
state: PluginState,
|
|
1491
|
+
request: LegacyResolveRequest,
|
|
1492
|
+
): Promise<RetainedIconModuleId | undefined> => {
|
|
1493
|
+
const specifier = parseIconSpecifier(request.source);
|
|
1494
|
+
|
|
1495
|
+
if (specifier === null) {
|
|
1496
|
+
return undefined;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
const resolved = await resolveIconEntry(ctx, state, {
|
|
1500
|
+
assetSource: specifier.assetSource,
|
|
1501
|
+
iconName: specifier.iconName,
|
|
1502
|
+
importer: request.importer,
|
|
1503
|
+
options: request.options,
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
return resolved === undefined
|
|
1507
|
+
? undefined
|
|
1508
|
+
: { id: virtualIconId(resolved), moduleSideEffects: true };
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
const resolveV2ResourceId = async (
|
|
1512
|
+
ctx: ResolveContext,
|
|
1513
|
+
state: PluginState,
|
|
1514
|
+
request: LegacyResolveRequest,
|
|
1515
|
+
): Promise<ResourceModuleId | undefined> => {
|
|
1516
|
+
if (isLegacyDataSpecifier(request.source)) {
|
|
1517
|
+
throw new Error(
|
|
1518
|
+
`${JSON.stringify(request.source)} uses the legacy #data asset form; import it relatively with ` +
|
|
1519
|
+
"?resource or ?url",
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
if (parseResourceSpecifier(request.source) !== null) {
|
|
1524
|
+
const resolved = await resolveExplicitResourceId(ctx, state, request);
|
|
1525
|
+
trackBundledSpecifier(state, request.importer, request.source);
|
|
1526
|
+
|
|
1527
|
+
return resolved;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
if (parseIconSpecifier(request.source) !== null) {
|
|
1531
|
+
const resolved = await resolveIconResourceId(ctx, state, request);
|
|
1532
|
+
trackBundledSpecifier(state, request.importer, request.source);
|
|
1533
|
+
|
|
1534
|
+
return resolved;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
rejectInvalidV2Specifier(request.source);
|
|
315
1538
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
1539
|
+
return undefined;
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
const resolveLegacyResourceId = async (
|
|
1543
|
+
ctx: ResolveContext,
|
|
1544
|
+
state: PluginState,
|
|
1545
|
+
request: LegacyResolveRequest,
|
|
1546
|
+
): Promise<string | undefined> => {
|
|
1547
|
+
if (BUNDLED_QUERY_MENTION_RE.test(request.source)) {
|
|
1548
|
+
throw new Error(`${JSON.stringify(request.source)} requires future.v2ResourceImports`);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
if (!isDataAsset(request.source)) {
|
|
1552
|
+
return undefined;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
const entry = await resolveLegacyAssetEntry(ctx, state, request);
|
|
1556
|
+
|
|
1557
|
+
return entry === undefined ? undefined : virtualAssetId(entry);
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1560
|
+
const resolveResourceId = (
|
|
1561
|
+
ctx: ResolveContext,
|
|
1562
|
+
state: PluginState,
|
|
1563
|
+
request: LegacyResolveRequest,
|
|
1564
|
+
): Promise<ResourceModuleId | undefined> => {
|
|
1565
|
+
if (request.source === VIRTUAL_INIT) {
|
|
1566
|
+
return Promise.resolve(VIRTUAL_INIT);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
return state.isV2
|
|
1570
|
+
? resolveV2ResourceId(ctx, state, request)
|
|
1571
|
+
: resolveLegacyResourceId(ctx, state, request);
|
|
1572
|
+
};
|
|
1573
|
+
|
|
1574
|
+
const configureResourceServer = (state: PluginState, server: ViteDevServer): void => {
|
|
1575
|
+
attachResourceWatcher(state, server);
|
|
1576
|
+
primeLegacyDevBundle(state);
|
|
1577
|
+
};
|
|
319
1578
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
1579
|
+
const createResourcesPlugin = (state: PluginState, loadConfig: ConfigLoader): Plugin => ({
|
|
1580
|
+
name: "gtkx:resources",
|
|
1581
|
+
enforce: "pre",
|
|
1582
|
+
perEnvironmentStartEndDuringDev: true,
|
|
323
1583
|
|
|
324
|
-
|
|
325
|
-
attachResourceWatcher(state, server);
|
|
326
|
-
primeDevBundle(state);
|
|
327
|
-
},
|
|
1584
|
+
config: (config: UserConfig) => resolveResourceConfig(state, config, loadConfig),
|
|
328
1585
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
1586
|
+
configResolved: (config: ResolvedConfig) => {
|
|
1587
|
+
applyResolvedConfig(state, config);
|
|
1588
|
+
},
|
|
333
1589
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
1590
|
+
configureServer: (server) => {
|
|
1591
|
+
configureResourceServer(state, server);
|
|
1592
|
+
},
|
|
337
1593
|
|
|
338
|
-
|
|
1594
|
+
buildStart() {
|
|
1595
|
+
if (state.isBuild && state.bundleReferenceId === null) {
|
|
1596
|
+
state.bundleReferenceId = this.emitFile({
|
|
1597
|
+
type: "asset",
|
|
1598
|
+
fileName: BUNDLE_FILENAME,
|
|
1599
|
+
source: "",
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
},
|
|
339
1603
|
|
|
340
|
-
|
|
341
|
-
}
|
|
1604
|
+
resolveId(source, importer, options) {
|
|
1605
|
+
return resolveResourceId(this, state, { source, importer, options });
|
|
1606
|
+
},
|
|
342
1607
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
1608
|
+
load(id) {
|
|
1609
|
+
return loadResourceModule(state, id);
|
|
1610
|
+
},
|
|
346
1611
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
},
|
|
1612
|
+
async transform(code, id) {
|
|
1613
|
+
await reconcileV2Importer(this, state, id);
|
|
350
1614
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
1615
|
+
return retainSideEffectIconImport(state, code, id);
|
|
1616
|
+
},
|
|
1617
|
+
|
|
1618
|
+
generateBundle(_options, bundle) {
|
|
1619
|
+
finalizeBuildBundle(this, bundle, state);
|
|
1620
|
+
},
|
|
1621
|
+
|
|
1622
|
+
closeBundle() {
|
|
1623
|
+
releaseStagingDir(state);
|
|
1624
|
+
},
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
function gtkxResources(loadConfig: ConfigLoader = createConfigLoader(), entryPath?: string): Plugin {
|
|
1628
|
+
const state: PluginState = {
|
|
1629
|
+
prefix: "",
|
|
1630
|
+
root: "",
|
|
1631
|
+
isBuild: false,
|
|
1632
|
+
isV2: false,
|
|
1633
|
+
entries: new Map(),
|
|
1634
|
+
bundledSpecifiers: new Map(),
|
|
1635
|
+
moduleDependencies: new Map(),
|
|
1636
|
+
prunedDependencies: new Map(),
|
|
1637
|
+
declaredEntries: new Map(),
|
|
1638
|
+
declaredIcons: new Map(),
|
|
1639
|
+
entryModule: entryPath === undefined ? null : importerKey(entryPath),
|
|
1640
|
+
sourcePaths: new Set(),
|
|
1641
|
+
missingSourcePaths: new Set(),
|
|
1642
|
+
stagingDir: createRetainedStagingDir(DEV_STAGING_PREFIX),
|
|
1643
|
+
devBundlePath: "",
|
|
1644
|
+
server: null,
|
|
1645
|
+
compiledSignature: "",
|
|
1646
|
+
dataDir: null,
|
|
1647
|
+
bundleReferenceId: null,
|
|
1648
|
+
iconOwners: new Map(),
|
|
354
1649
|
};
|
|
1650
|
+
|
|
1651
|
+
return createResourcesPlugin(state, loadConfig);
|
|
355
1652
|
}
|
|
356
1653
|
|
|
357
1654
|
export { gtkxResources };
|