@gtkx/cli 2.0.0-beta.7 → 2.0.0-beta.9
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/dist/commands/deploy.d.ts +4 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +6 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/deploy/depends.d.ts.map +1 -1
- package/dist/deploy/depends.js +24 -2
- package/dist/deploy/depends.js.map +1 -1
- package/dist/deploy/download.d.ts +7 -3
- package/dist/deploy/download.d.ts.map +1 -1
- package/dist/deploy/download.js +19 -15
- package/dist/deploy/download.js.map +1 -1
- package/dist/deploy/native-addon.d.ts +5 -0
- package/dist/deploy/native-addon.d.ts.map +1 -0
- package/dist/deploy/native-addon.js +134 -0
- package/dist/deploy/native-addon.js.map +1 -0
- package/dist/deploy/node-runtime/download.js +2 -2
- package/dist/deploy/node-runtime/download.js.map +1 -1
- package/dist/deploy/node-runtime/elf.d.ts +3 -1
- package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
- package/dist/deploy/node-runtime/elf.js +3 -1
- package/dist/deploy/node-runtime/elf.js.map +1 -1
- package/dist/deploy/node-runtime/guard.d.ts.map +1 -1
- package/dist/deploy/node-runtime/guard.js +7 -14
- package/dist/deploy/node-runtime/guard.js.map +1 -1
- package/dist/deploy/node-runtime/index.d.ts +2 -1
- package/dist/deploy/node-runtime/index.d.ts.map +1 -1
- package/dist/deploy/node-runtime/index.js +29 -6
- package/dist/deploy/node-runtime/index.js.map +1 -1
- package/dist/deploy/node-runtime/sonames.d.ts +5 -0
- package/dist/deploy/node-runtime/sonames.d.ts.map +1 -0
- package/dist/deploy/node-runtime/sonames.js +13 -0
- package/dist/deploy/node-runtime/sonames.js.map +1 -0
- package/dist/deploy/payload/stage.d.ts +2 -1
- package/dist/deploy/payload/stage.d.ts.map +1 -1
- package/dist/deploy/payload/stage.js +22 -2
- package/dist/deploy/payload/stage.js.map +1 -1
- package/dist/deploy/run-deploy.d.ts +1 -0
- package/dist/deploy/run-deploy.d.ts.map +1 -1
- package/dist/deploy/run-deploy.js +139 -80
- package/dist/deploy/run-deploy.js.map +1 -1
- package/dist/deploy/settings/arch.d.ts +9 -3
- package/dist/deploy/settings/arch.d.ts.map +1 -1
- package/dist/deploy/settings/arch.js +27 -6
- package/dist/deploy/settings/arch.js.map +1 -1
- package/dist/deploy/settings/index.d.ts +2 -1
- package/dist/deploy/settings/index.d.ts.map +1 -1
- package/dist/deploy/settings/index.js +2 -1
- package/dist/deploy/settings/index.js.map +1 -1
- package/dist/deploy/settings/paths.d.ts +2 -1
- package/dist/deploy/settings/paths.d.ts.map +1 -1
- package/dist/deploy/settings/paths.js +6 -5
- 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 +1 -0
- package/dist/deploy/targets/appimage.js.map +1 -1
- package/dist/deploy/targets/flatpak-pnpm.js +4 -4
- package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
- package/dist/deploy/targets/flatpak.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak.js +1 -0
- package/dist/deploy/targets/flatpak.js.map +1 -1
- package/dist/deploy/targets/nfpm-target.d.ts.map +1 -1
- package/dist/deploy/targets/nfpm-target.js +1 -0
- package/dist/deploy/targets/nfpm-target.js.map +1 -1
- package/dist/deploy/types.d.ts +4 -2
- package/dist/deploy/types.d.ts.map +1 -1
- package/dist/deploy/types.js.map +1 -1
- package/dist/deploy/vendored/appimagetool.js +2 -2
- package/dist/deploy/vendored/appimagetool.js.map +1 -1
- package/dist/deploy/vendored/nfpm.js +1 -1
- package/dist/deploy/vendored/nfpm.js.map +1 -1
- package/dist/dev/font-dir.d.ts +1 -1
- package/dist/dev/font-dir.d.ts.map +1 -1
- package/dist/dev/font-dir.js +0 -3
- package/dist/dev/font-dir.js.map +1 -1
- package/dist/dev/runner.d.ts.map +1 -1
- package/dist/dev/runner.js +19 -6
- package/dist/dev/runner.js.map +1 -1
- package/dist/internal/font-staging.d.ts +5 -2
- package/dist/internal/font-staging.d.ts.map +1 -1
- package/dist/internal/font-staging.js +76 -27
- package/dist/internal/font-staging.js.map +1 -1
- package/dist/internal/icon-staging.d.ts +3 -0
- package/dist/internal/icon-staging.d.ts.map +1 -0
- package/dist/internal/icon-staging.js +40 -0
- package/dist/internal/icon-staging.js.map +1 -0
- package/dist/internal/source-imports.js +1 -1
- package/dist/internal/source-imports.js.map +1 -1
- package/dist/vite-plugins/font-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/font-worker-env.js +2 -5
- package/dist/vite-plugins/font-worker-env.js.map +1 -1
- package/dist/vite-plugins/font.d.ts.map +1 -1
- package/dist/vite-plugins/font.js +16 -4
- package/dist/vite-plugins/font.js.map +1 -1
- package/dist/vite-plugins/icon-worker-env.d.ts +4 -0
- package/dist/vite-plugins/icon-worker-env.d.ts.map +1 -0
- package/dist/vite-plugins/icon-worker-env.js +23 -0
- package/dist/vite-plugins/icon-worker-env.js.map +1 -0
- package/dist/vite-plugins/icons.js +2 -2
- package/dist/vite-plugins/icons.js.map +1 -1
- package/dist/vite-plugins/react-compiler.js +2 -2
- package/dist/vite-plugins/react-compiler.js.map +1 -1
- package/dist/vite-plugins/resources.js +2 -2
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +2 -2
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/store-links.d.ts.map +1 -1
- package/dist/vite-plugins/store-links.js +2 -1
- package/dist/vite-plugins/store-links.js.map +1 -1
- package/dist/vite-plugins/undeclared-library.js +2 -2
- package/dist/vite-plugins/undeclared-library.js.map +1 -1
- package/dist/vite-plugins/worker.d.ts.map +1 -1
- package/dist/vite-plugins/worker.js +21 -13
- package/dist/vite-plugins/worker.js.map +1 -1
- package/dist/vitest-plugin.d.ts +2 -2
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +4 -2
- package/dist/vitest-plugin.js.map +1 -1
- package/package.json +13 -13
- package/src/commands/deploy.ts +6 -0
- package/src/deploy/depends.ts +30 -3
- package/src/deploy/download.ts +33 -17
- package/src/deploy/native-addon.ts +183 -0
- package/src/deploy/node-runtime/download.ts +2 -2
- package/src/deploy/node-runtime/elf.ts +4 -1
- package/src/deploy/node-runtime/guard.ts +10 -14
- package/src/deploy/node-runtime/index.ts +42 -7
- package/src/deploy/node-runtime/sonames.ts +17 -0
- package/src/deploy/payload/stage.ts +34 -2
- package/src/deploy/run-deploy.ts +209 -94
- package/src/deploy/settings/arch.ts +40 -8
- package/src/deploy/settings/index.ts +4 -1
- package/src/deploy/settings/paths.ts +8 -6
- package/src/deploy/targets/appimage.ts +1 -0
- package/src/deploy/targets/flatpak-pnpm.ts +4 -4
- package/src/deploy/targets/flatpak.ts +1 -0
- package/src/deploy/targets/nfpm-target.ts +1 -0
- package/src/deploy/types.ts +4 -1
- package/src/deploy/vendored/appimagetool.ts +2 -2
- package/src/deploy/vendored/nfpm.ts +1 -1
- package/src/dev/font-dir.ts +1 -6
- package/src/dev/runner.ts +24 -6
- package/src/internal/font-staging.ts +99 -27
- package/src/internal/icon-staging.ts +58 -0
- package/src/internal/source-imports.ts +1 -1
- package/src/vite-plugins/font-worker-env.ts +2 -6
- package/src/vite-plugins/font.ts +21 -3
- package/src/vite-plugins/icon-worker-env.ts +36 -0
- package/src/vite-plugins/icons.ts +2 -2
- package/src/vite-plugins/react-compiler.ts +2 -2
- package/src/vite-plugins/resources.ts +2 -2
- package/src/vite-plugins/settings-worker-env.ts +2 -2
- package/src/vite-plugins/store-links.ts +2 -1
- package/src/vite-plugins/undeclared-library.ts +2 -2
- package/src/vite-plugins/worker.ts +31 -15
- package/src/vitest-plugin.ts +4 -2
package/src/dev/font-dir.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { stageProjectFonts } from "../internal/font-staging.js";
|
|
2
2
|
import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
|
|
3
3
|
|
|
4
|
-
const prepareDevFontDir = (root: string): string
|
|
4
|
+
const prepareDevFontDir = (root: string): string => {
|
|
5
5
|
const shareDir = stageProjectFonts(root);
|
|
6
|
-
|
|
7
|
-
if (shareDir === null) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
6
|
process.env.XDG_DATA_DIRS = prependXdgDataDir(shareDir, process.env.XDG_DATA_DIRS);
|
|
12
7
|
|
|
13
8
|
return shareDir;
|
package/src/dev/runner.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ApplicationInstance } from "@gtkx/runtime/internal";
|
|
|
2
2
|
import type { InlineConfig, Plugin } from "vite";
|
|
3
3
|
import { error, warn } from "@gtkx/utils";
|
|
4
4
|
import { isCatalogSource } from "../i18n/catalogs.js";
|
|
5
|
+
import { hasUnstagedFontImport } from "../internal/font-staging.js";
|
|
5
6
|
import { loadModuleExclusively, withExclusiveLoad } from "../internal/module-loads.js";
|
|
6
7
|
import { createChangeQueue, type WatchedChange } from "./change-queue.js";
|
|
7
8
|
import { createFailureTracker, type FailureTracker } from "./failure-tracker.js";
|
|
@@ -371,6 +372,11 @@ const restartForServerConfig = async (session: DevSession, changedPath: string):
|
|
|
371
372
|
await requestRestart(session);
|
|
372
373
|
};
|
|
373
374
|
|
|
375
|
+
const restartForFont = async (session: DevSession, changedPath: string): Promise<void> => {
|
|
376
|
+
session.deps.log(`Font import added: ${changedPath}`);
|
|
377
|
+
await requestRestart(session);
|
|
378
|
+
};
|
|
379
|
+
|
|
374
380
|
const restartForCatalog = async (session: DevSession, changedPath: string): Promise<void> => {
|
|
375
381
|
if (session.deps.hasWrittenCatalog(changedPath)) {
|
|
376
382
|
return;
|
|
@@ -380,20 +386,32 @@ const restartForCatalog = async (session: DevSession, changedPath: string): Prom
|
|
|
380
386
|
await requestRestart(session);
|
|
381
387
|
};
|
|
382
388
|
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
389
|
+
const didRestartForChange = async (session: DevSession, change: WatchedChange): Promise<boolean> => {
|
|
390
|
+
const { root } = session.server.config;
|
|
387
391
|
|
|
388
|
-
if (isCatalogSource(
|
|
392
|
+
if (isCatalogSource(root, change.path)) {
|
|
389
393
|
await restartForCatalog(session, change.path);
|
|
390
394
|
|
|
391
|
-
return;
|
|
395
|
+
return true;
|
|
392
396
|
}
|
|
393
397
|
|
|
394
398
|
if (isServerConfigFile(session.server.config, change.path)) {
|
|
395
399
|
await restartForServerConfig(session, change.path);
|
|
396
400
|
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (change.event !== "unlink" && hasUnstagedFontImport(root, change.path)) {
|
|
405
|
+
await restartForFont(session, change.path);
|
|
406
|
+
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return false;
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const applyChange = async (session: DevSession, change: WatchedChange): Promise<void> => {
|
|
414
|
+
if (session.controller.isShuttingDown() || await didRestartForChange(session, change)) {
|
|
397
415
|
return;
|
|
398
416
|
}
|
|
399
417
|
|
|
@@ -1,57 +1,129 @@
|
|
|
1
1
|
import { sortStrings } from "@gtkx/utils";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
|
+
import { lstatSync, mkdirSync, readFileSync, symlinkSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { parseFontSpecifier } from "../vite-plugins/asset-specifier.js";
|
|
6
6
|
import { fontFileName, FONTS_DIR } from "./font-path.js";
|
|
7
|
-
import { discoverSourceImports,
|
|
8
|
-
import {
|
|
7
|
+
import { discoverSourceImports, type SourceImport, sourceLanguage } from "./source-imports.js";
|
|
8
|
+
import { createRetainedStagingDir } from "./staging-dir.js";
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
type FontStagingStatus = "absent" | "staged" | "unmanaged";
|
|
11
|
+
|
|
12
|
+
const FONT_DIR_ENV = "GTKX_DEV_FONT_DIR";
|
|
13
|
+
const FONT_QUERY = "?font";
|
|
14
|
+
const fontStaging = createRetainedStagingDir("fonts");
|
|
11
15
|
|
|
12
16
|
const isRelativeImport = (source: string): boolean => source.startsWith("./") || source.startsWith("../");
|
|
13
17
|
|
|
14
|
-
const
|
|
18
|
+
const existingPath = (path: string): string | null =>
|
|
19
|
+
lstatSync(path, { throwIfNoEntry: false }) === undefined ? null : path;
|
|
20
|
+
|
|
21
|
+
const resolveRelativeImport = (importer: string, assetSource: string): string | null =>
|
|
22
|
+
existingPath(resolve(dirname(importer), assetSource));
|
|
23
|
+
|
|
24
|
+
const resolveAbsoluteImport = (root: string, assetSource: string): string | null =>
|
|
25
|
+
existingPath(assetSource) ?? existingPath(join(root, assetSource));
|
|
26
|
+
|
|
27
|
+
const resolvePackageImport = (importer: string, assetSource: string): string | null => {
|
|
28
|
+
try {
|
|
29
|
+
return createRequire(importer).resolve(assetSource);
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resolveFontImport = (root: string, importer: string, assetSource: string): string | null => {
|
|
36
|
+
if (isRelativeImport(assetSource)) {
|
|
37
|
+
return resolveRelativeImport(importer, assetSource);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isAbsolute(assetSource)) {
|
|
41
|
+
return resolveAbsoluteImport(root, assetSource);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return resolvePackageImport(importer, assetSource);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const fontFileFor = (root: string, { importer, source }: SourceImport): string | null => {
|
|
15
48
|
const specifier = parseFontSpecifier(source);
|
|
16
49
|
|
|
17
|
-
return specifier === null
|
|
18
|
-
? null
|
|
19
|
-
: resolve(dirname(importer), specifier.assetSource);
|
|
50
|
+
return specifier === null ? null : resolveFontImport(root, importer, specifier.assetSource);
|
|
20
51
|
};
|
|
21
52
|
|
|
22
|
-
const
|
|
23
|
-
const files =
|
|
24
|
-
.map((entry) => fontFileFor(entry))
|
|
53
|
+
const projectFontFiles = (root: string): string[] => {
|
|
54
|
+
const files = discoverSourceImports(root)
|
|
55
|
+
.map((entry) => fontFileFor(root, entry))
|
|
25
56
|
.filter((path): path is string => path !== null);
|
|
26
57
|
|
|
27
58
|
return sortStrings(new Set(files));
|
|
28
59
|
};
|
|
29
60
|
|
|
61
|
+
const stagedPath = (fontsDir: string, sourcePath: string, content: Buffer): string =>
|
|
62
|
+
join(fontsDir, fontFileName(sourcePath, content));
|
|
63
|
+
|
|
30
64
|
const stageFont = (fontsDir: string, sourcePath: string): void => {
|
|
31
|
-
const
|
|
65
|
+
const target = stagedPath(fontsDir, sourcePath, readFileSync(sourcePath));
|
|
66
|
+
|
|
67
|
+
if (existingPath(target) !== null) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
32
70
|
|
|
33
|
-
symlinkSync(sourcePath,
|
|
71
|
+
symlinkSync(sourcePath, target, "file");
|
|
34
72
|
};
|
|
35
73
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
74
|
+
const stagedFontsDir = (): string | null => {
|
|
75
|
+
const shareDir = process.env[FONT_DIR_ENV];
|
|
38
76
|
|
|
39
|
-
|
|
40
|
-
|
|
77
|
+
return shareDir === undefined || shareDir.length === 0 ? null : join(shareDir, FONTS_DIR);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const stagedFontStatus = (sourcePath: string, content: Buffer): FontStagingStatus => {
|
|
81
|
+
const fontsDir = stagedFontsDir();
|
|
82
|
+
|
|
83
|
+
if (fontsDir === null) {
|
|
84
|
+
return "unmanaged";
|
|
41
85
|
}
|
|
42
86
|
|
|
43
|
-
|
|
44
|
-
|
|
87
|
+
return existingPath(stagedPath(fontsDir, sourcePath, content)) === null ? "absent" : "staged";
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const hasFontImportMention = (filePath: string): boolean => {
|
|
91
|
+
if (sourceLanguage(filePath) === undefined) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
return readFileSync(filePath, "utf8").includes(FONT_QUERY);
|
|
97
|
+
} catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isUnstagedFont = (fontsDir: string, sourcePath: string): boolean =>
|
|
103
|
+
existingPath(stagedPath(fontsDir, sourcePath, readFileSync(sourcePath))) === null;
|
|
104
|
+
|
|
105
|
+
const hasUnstagedFontImport = (root: string, filePath: string): boolean => {
|
|
106
|
+
const fontsDir = stagedFontsDir();
|
|
107
|
+
|
|
108
|
+
if (fontsDir === null || !hasFontImportMention(filePath)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return projectFontFiles(root).some((sourcePath) => isUnstagedFont(fontsDir, sourcePath));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const stageProjectFonts = (root: string): string => {
|
|
116
|
+
const shareDir = fontStaging.retain();
|
|
117
|
+
const fontsDir = join(shareDir, FONTS_DIR);
|
|
118
|
+
mkdirSync(fontsDir, { recursive: true });
|
|
45
119
|
|
|
46
|
-
for (const sourcePath of
|
|
47
|
-
stageFont(
|
|
120
|
+
for (const sourcePath of projectFontFiles(root)) {
|
|
121
|
+
stageFont(fontsDir, sourcePath);
|
|
48
122
|
}
|
|
49
123
|
|
|
50
|
-
process.
|
|
51
|
-
removeTempDir(shareDir);
|
|
52
|
-
});
|
|
124
|
+
process.env[FONT_DIR_ENV] = shareDir;
|
|
53
125
|
|
|
54
126
|
return shareDir;
|
|
55
127
|
};
|
|
56
128
|
|
|
57
|
-
export { stageProjectFonts };
|
|
129
|
+
export { hasUnstagedFontImport, stagedFontStatus, stageProjectFonts };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mkdirSync, rmSync, symlinkSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { relativeIconPath, resolveApplicationIcon, type ResolvedApplicationIcon } from "./icon-path.js";
|
|
4
|
+
import { createRetainedStagingDir, type RetainedStagingDir } from "./staging-dir.js";
|
|
5
|
+
|
|
6
|
+
const ICONS_DIR = "icons";
|
|
7
|
+
const stagingDirs: Map<string, RetainedStagingDir> = new Map();
|
|
8
|
+
|
|
9
|
+
const stagingFor = (root: string): RetainedStagingDir => {
|
|
10
|
+
const existing = stagingDirs.get(root);
|
|
11
|
+
|
|
12
|
+
if (existing !== undefined) {
|
|
13
|
+
return existing;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const staging = createRetainedStagingDir("icons");
|
|
17
|
+
stagingDirs.set(root, staging);
|
|
18
|
+
|
|
19
|
+
return staging;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const resetIconsDir = (shareDir: string): string => {
|
|
23
|
+
const iconsDir = join(shareDir, ICONS_DIR);
|
|
24
|
+
rmSync(iconsDir, { recursive: true, force: true });
|
|
25
|
+
|
|
26
|
+
return iconsDir;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const stageIconSource = (
|
|
30
|
+
iconsDir: string,
|
|
31
|
+
applicationId: string,
|
|
32
|
+
source: Exclude<ResolvedApplicationIcon, { kind: "none" }>,
|
|
33
|
+
): void => {
|
|
34
|
+
if (source.kind === "theme") {
|
|
35
|
+
symlinkSync(source.path, iconsDir, "dir");
|
|
36
|
+
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const target = join(iconsDir, relativeIconPath(applicationId, source.path));
|
|
41
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
42
|
+
symlinkSync(source.path, target, "file");
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const stageProjectIcons = (root: string, applicationId: string, configured: string | undefined): string | null => {
|
|
46
|
+
const source = resolveApplicationIcon(root, applicationId, configured);
|
|
47
|
+
|
|
48
|
+
if (source.kind === "none") {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const shareDir = stagingFor(root).retain();
|
|
53
|
+
stageIconSource(resetIconsDir(shareDir), applicationId, source);
|
|
54
|
+
|
|
55
|
+
return shareDir;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { stageProjectIcons };
|
|
@@ -41,7 +41,7 @@ const discoverSourceFiles = (dir: string): string[] =>
|
|
|
41
41
|
sortStringsBy(
|
|
42
42
|
globSync("**/{*,.*}", {
|
|
43
43
|
cwd: dir,
|
|
44
|
-
exclude: ["**/{build,coverage,dist,node_modules,out-tsc}/**", "**/.gtkx-output-*/**"],
|
|
44
|
+
exclude: ["**/{build,coverage,dist,node_modules,out-tsc}/**", "**/.gtkx-output-*/**", "**/.git/**"],
|
|
45
45
|
withFileTypes: true,
|
|
46
46
|
})
|
|
47
47
|
.filter((entry) => entry.isFile())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { UserConfig } from "vite";
|
|
2
2
|
import type { Plugin } from "vitest/config";
|
|
3
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
3
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
4
4
|
import { stageProjectFonts } from "../internal/font-staging.js";
|
|
5
5
|
import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
|
|
6
6
|
|
|
@@ -12,13 +12,9 @@ function gtkxFontWorkerEnv(configFile?: string): Plugin {
|
|
|
12
12
|
enforce: "pre",
|
|
13
13
|
|
|
14
14
|
async config(config: UserConfig) {
|
|
15
|
-
const loaded = await loadConfig.load(config
|
|
15
|
+
const loaded = await loadConfig.load(viteProjectRoot(config));
|
|
16
16
|
const shareDir = stageProjectFonts(loaded.root);
|
|
17
17
|
|
|
18
|
-
if (shareDir === null) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
18
|
return {
|
|
23
19
|
test: { env: { XDG_DATA_DIRS: prependXdgDataDir(shareDir, process.env.XDG_DATA_DIRS) } },
|
|
24
20
|
};
|
package/src/vite-plugins/font.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { parseSync } from "vite";
|
|
|
4
4
|
import type { AssetEmitter } from "./asset-emitter.js";
|
|
5
5
|
import { prependBanner } from "../internal/banner.js";
|
|
6
6
|
import { fontFileName, FONTS_DIR } from "../internal/font-path.js";
|
|
7
|
+
import { stagedFontStatus } from "../internal/font-staging.js";
|
|
7
8
|
import { sourceLanguage } from "../internal/source-imports.js";
|
|
8
9
|
import { xdgDataDirsBanner } from "../internal/xdg-banner.js";
|
|
9
10
|
import { parseFontSpecifier } from "./asset-specifier.js";
|
|
@@ -13,7 +14,9 @@ import { createVirtualNamespace } from "./virtual-module.js";
|
|
|
13
14
|
|
|
14
15
|
type PluginState = {
|
|
15
16
|
isBuild: boolean;
|
|
17
|
+
root: string;
|
|
16
18
|
emitted: Set<string>;
|
|
19
|
+
importers: Map<string, string>;
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
type ResolveContext = Parameters<typeof resolveToVirtual>[0];
|
|
@@ -36,8 +39,14 @@ const unreadableFontError = (filePath: string): string =>
|
|
|
36
39
|
`Cannot read a font family name from ${filePath}; ?font expects a TrueType, OpenType, ` +
|
|
37
40
|
"TrueType Collection, WOFF, or WOFF2 font";
|
|
38
41
|
|
|
42
|
+
const unstagedFontError = (filePath: string, importer: string): string =>
|
|
43
|
+
`${filePath} was not staged before the toolkit started, so ${importer} would resolve its family to a ` +
|
|
44
|
+
"fallback font. Fonts are staged from ?font imports found in source files under the project root; move " +
|
|
45
|
+
"the import there, or restart to pick it up.";
|
|
46
|
+
|
|
39
47
|
const resolveFontId = async (
|
|
40
48
|
ctx: ResolveContext,
|
|
49
|
+
state: PluginState,
|
|
41
50
|
request: ResolveRequest,
|
|
42
51
|
): Promise<RetainedFontModuleId | undefined> => {
|
|
43
52
|
if (parseFontSpecifier(request.source) === null) {
|
|
@@ -46,7 +55,13 @@ const resolveFontId = async (
|
|
|
46
55
|
|
|
47
56
|
const virtualId = await resolveToVirtual(ctx, request);
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
if (virtualId === undefined) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
state.importers.set(virtualId, request.importer ?? state.root);
|
|
63
|
+
|
|
64
|
+
return { id: virtualId, moduleSideEffects: true };
|
|
50
65
|
};
|
|
51
66
|
|
|
52
67
|
const emitFont = (ctx: LoadContext, state: PluginState, filePath: string, content: Buffer): void => {
|
|
@@ -77,6 +92,8 @@ const loadFontModule = (ctx: LoadContext, state: PluginState, id: string): strin
|
|
|
77
92
|
|
|
78
93
|
if (state.isBuild) {
|
|
79
94
|
emitFont(ctx, state, filePath, content);
|
|
95
|
+
} else if (stagedFontStatus(filePath, content) === "absent") {
|
|
96
|
+
return ctx.error(unstagedFontError(filePath, state.importers.get(id) ?? state.root));
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
return `export default ${JSON.stringify(family)};`;
|
|
@@ -112,7 +129,7 @@ const fontBanner = (state: PluginState) => (chunk: Rollup.RenderedChunk): string
|
|
|
112
129
|
state.emitted.size === 0 ? "" : xdgDataDirsBanner(chunk);
|
|
113
130
|
|
|
114
131
|
function gtkxFont(): Plugin {
|
|
115
|
-
const state: PluginState = { isBuild: false, emitted: new Set() };
|
|
132
|
+
const state: PluginState = { isBuild: false, root: "", emitted: new Set(), importers: new Map() };
|
|
116
133
|
|
|
117
134
|
return {
|
|
118
135
|
name: "gtkx:font",
|
|
@@ -120,10 +137,11 @@ function gtkxFont(): Plugin {
|
|
|
120
137
|
|
|
121
138
|
configResolved(config) {
|
|
122
139
|
state.isBuild = config.command === "build";
|
|
140
|
+
state.root = config.root;
|
|
123
141
|
},
|
|
124
142
|
|
|
125
143
|
resolveId(source, importer, options) {
|
|
126
|
-
return resolveFontId(this, { source, importer, options });
|
|
144
|
+
return resolveFontId(this, state, { source, importer, options });
|
|
127
145
|
},
|
|
128
146
|
|
|
129
147
|
load(id) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UserConfig } from "vite";
|
|
2
|
+
import type { Plugin } from "vitest/config";
|
|
3
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
4
|
+
import { stageProjectIcons } from "../internal/icon-staging.js";
|
|
5
|
+
import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
|
|
6
|
+
|
|
7
|
+
function gtkxIconWorkerEnv(configFile?: string): Plugin {
|
|
8
|
+
const loadConfig = createConfigLoader({ configFile });
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
name: "gtkx:icon-worker-env",
|
|
12
|
+
enforce: "pre",
|
|
13
|
+
|
|
14
|
+
async config(config: UserConfig) {
|
|
15
|
+
const loaded = await loadConfig.load(viteProjectRoot(config));
|
|
16
|
+
|
|
17
|
+
const shareDir = stageProjectIcons(
|
|
18
|
+
loaded.root,
|
|
19
|
+
loaded.config.applicationId,
|
|
20
|
+
loaded.config.applicationIcon,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (shareDir === null) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const existing = config.test?.env?.XDG_DATA_DIRS ?? process.env.XDG_DATA_DIRS;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
test: { env: { XDG_DATA_DIRS: prependXdgDataDir(shareDir, existing) } },
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { gtkxIconWorkerEnv };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConfigLoader } from "@gtkx/config";
|
|
2
2
|
import type { Plugin, UserConfig } from "vite";
|
|
3
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
3
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
4
4
|
import { info } from "@gtkx/utils";
|
|
5
5
|
import { readFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
@@ -37,7 +37,7 @@ const findIconFiles = (state: PluginState): ListedFile[] => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const applyUserConfig = async (state: PluginState, config: UserConfig, loadConfig: ConfigLoader): Promise<void> => {
|
|
40
|
-
const { config: gtkxConfig, root } = await loadConfig.load(config
|
|
40
|
+
const { config: gtkxConfig, root } = await loadConfig.load(viteProjectRoot(config));
|
|
41
41
|
state.applicationId = gtkxConfig.applicationId;
|
|
42
42
|
state.source = resolveApplicationIcon(root, gtkxConfig.applicationId, gtkxConfig.applicationIcon);
|
|
43
43
|
};
|
|
@@ -3,7 +3,7 @@ import type { ResolvedReactCompilerOptions } from "@gtkx/config/internal";
|
|
|
3
3
|
import type { Plugin, ResolvedConfig, UserConfig } from "vite";
|
|
4
4
|
import { transformAsync } from "@babel/core";
|
|
5
5
|
import babelPresetTypescriptNs from "@babel/preset-typescript";
|
|
6
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
6
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
7
7
|
import babelPluginReactCompilerNs from "babel-plugin-react-compiler";
|
|
8
8
|
|
|
9
9
|
type ReactCompilerState = {
|
|
@@ -62,7 +62,7 @@ function gtkxReactCompiler(loadConfig: ConfigLoader = createConfigLoader()): Plu
|
|
|
62
62
|
enforce: "pre",
|
|
63
63
|
|
|
64
64
|
async config(config: UserConfig) {
|
|
65
|
-
const resolved = await loadConfig.resolve(config
|
|
65
|
+
const resolved = await loadConfig.resolve(viteProjectRoot(config));
|
|
66
66
|
state.options = resolved.reactCompiler;
|
|
67
67
|
},
|
|
68
68
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConfigLoader } from "@gtkx/config";
|
|
2
2
|
import type { ModuleNode, Plugin, ResolvedConfig, Rolldown, UserConfig, ViteDevServer } from "vite";
|
|
3
|
-
import { createConfigLoader, resourceBasePath } from "@gtkx/config/internal";
|
|
3
|
+
import { createConfigLoader, resourceBasePath, viteProjectRoot } from "@gtkx/config/internal";
|
|
4
4
|
import { error, info, isPathInside, isRecord, sortStrings, toPosixPath } from "@gtkx/utils";
|
|
5
5
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { basename, dirname, extname, isAbsolute, join, posix, relative, sep } from "node:path";
|
|
@@ -1283,7 +1283,7 @@ const reconcileImporter = async (ctx: ResolveContext, state: PluginState, id: st
|
|
|
1283
1283
|
};
|
|
1284
1284
|
|
|
1285
1285
|
const resolveResourceConfig = async (state: PluginState, config: UserConfig, loadConfig: ConfigLoader) => {
|
|
1286
|
-
const loaded = await loadConfig.load(config
|
|
1286
|
+
const loaded = await loadConfig.load(viteProjectRoot(config));
|
|
1287
1287
|
state.prefix = resourceBasePath(loaded.config.applicationId);
|
|
1288
1288
|
state.root = loaded.root;
|
|
1289
1289
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { UserConfig } from "vite";
|
|
2
2
|
import type { Plugin } from "vitest/config";
|
|
3
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
3
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
4
4
|
import { prependSchemaDir, stageAndCompileProjectSchemas } from "../settings/schema.js";
|
|
5
5
|
|
|
6
6
|
function gtkxSettingsWorkerEnv(configFile?: string): Plugin {
|
|
@@ -11,7 +11,7 @@ function gtkxSettingsWorkerEnv(configFile?: string): Plugin {
|
|
|
11
11
|
enforce: "pre",
|
|
12
12
|
|
|
13
13
|
async config(config: UserConfig) {
|
|
14
|
-
const loaded = await loadConfig.load(config
|
|
14
|
+
const loaded = await loadConfig.load(viteProjectRoot(config));
|
|
15
15
|
const dir = stageAndCompileProjectSchemas(loaded.root);
|
|
16
16
|
|
|
17
17
|
if (dir === null) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Plugin, UserConfig } from "vite";
|
|
2
2
|
import { ensureStoreLinks } from "@gtkx/codegen/internal";
|
|
3
|
+
import { viteProjectRoot } from "@gtkx/config/internal";
|
|
3
4
|
|
|
4
5
|
const GENERATED_MODULE_PREFIX = /^@gtkx\/(?:gi\/|jsx(?:\/|$))/;
|
|
5
6
|
|
|
@@ -11,7 +12,7 @@ function gtkxStoreLinks(): Plugin {
|
|
|
11
12
|
enforce: "pre",
|
|
12
13
|
|
|
13
14
|
config(config: UserConfig) {
|
|
14
|
-
state.root = config
|
|
15
|
+
state.root = viteProjectRoot(config);
|
|
15
16
|
},
|
|
16
17
|
|
|
17
18
|
resolveId(source) {
|
|
@@ -2,7 +2,7 @@ import type { StoreOptions } from "@gtkx/codegen";
|
|
|
2
2
|
import type { ConfigLoader } from "@gtkx/config";
|
|
3
3
|
import type { Plugin, UserConfig } from "vite";
|
|
4
4
|
import { discoverGirNamespaces, resolveGirPath, resolveStore } from "@gtkx/codegen";
|
|
5
|
-
import { createConfigLoader } from "@gtkx/config/internal";
|
|
5
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
|
|
@@ -129,7 +129,7 @@ function gtkxUndeclaredLibrary(loadConfig: ConfigLoader = createConfigLoader()):
|
|
|
129
129
|
enforce: "pre",
|
|
130
130
|
|
|
131
131
|
config(config: UserConfig) {
|
|
132
|
-
state.root = config
|
|
132
|
+
state.root = viteProjectRoot(config);
|
|
133
133
|
},
|
|
134
134
|
|
|
135
135
|
async resolveId(source, importer, options) {
|
|
@@ -7,12 +7,17 @@ import { stripQuery } from "./strip-query.js";
|
|
|
7
7
|
type WorkerReplacement = {
|
|
8
8
|
start: number;
|
|
9
9
|
end: number;
|
|
10
|
-
|
|
10
|
+
referenceId: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type WorkerReferences = {
|
|
14
|
+
byModule: Map<string, string>;
|
|
15
|
+
claimed: Set<string>;
|
|
11
16
|
};
|
|
12
17
|
|
|
13
18
|
type EmitContext = {
|
|
14
19
|
context: Rollup.PluginContext;
|
|
15
|
-
|
|
20
|
+
references: WorkerReferences;
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
type SourceRange = {
|
|
@@ -83,10 +88,12 @@ const isWorkerConstruction = (code: string, matchIndex: number): boolean =>
|
|
|
83
88
|
|
|
84
89
|
const hasWorkerCandidate = (code: string): boolean => code.includes("import.meta.url") && code.includes("Worker");
|
|
85
90
|
|
|
86
|
-
const
|
|
87
|
-
|
|
91
|
+
const workerUrlReference = (referenceId: string): string => `import.meta.ROLLUP_FILE_URL_${referenceId}`;
|
|
92
|
+
|
|
93
|
+
const workerUrlExpression = (relativePath: string): string => {
|
|
94
|
+
const specifier = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
88
95
|
|
|
89
|
-
return `new URL(${specifier}, import.meta.url)`;
|
|
96
|
+
return `new URL(${JSON.stringify(specifier)}, import.meta.url)`;
|
|
90
97
|
};
|
|
91
98
|
|
|
92
99
|
const inlineWorkerExample = (specifier: string): string =>
|
|
@@ -125,17 +132,22 @@ const suggestionFor = async (emit: EmitContext, scan: ScanContext, specifier: st
|
|
|
125
132
|
};
|
|
126
133
|
|
|
127
134
|
const claimWorker = (emit: EmitContext, resolvedId: string): string => {
|
|
128
|
-
const existing = emit.
|
|
135
|
+
const existing = emit.references.byModule.get(resolvedId);
|
|
129
136
|
|
|
130
137
|
if (existing !== undefined) {
|
|
131
138
|
return existing;
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
const referenceId = emit.context.emitFile({
|
|
142
|
+
type: "chunk",
|
|
143
|
+
id: resolvedId,
|
|
144
|
+
fileName: workerFileName(resolvedId),
|
|
145
|
+
});
|
|
137
146
|
|
|
138
|
-
|
|
147
|
+
emit.references.byModule.set(resolvedId, referenceId);
|
|
148
|
+
emit.references.claimed.add(referenceId);
|
|
149
|
+
|
|
150
|
+
return referenceId;
|
|
139
151
|
};
|
|
140
152
|
|
|
141
153
|
const isRewritableUrl = (scan: ScanContext, match: RegExpExecArray): boolean =>
|
|
@@ -158,7 +170,7 @@ const replacementFor = async (
|
|
|
158
170
|
throw unresolvedWorkerError(scan, specifier, await suggestionFor(emit, scan, specifier));
|
|
159
171
|
}
|
|
160
172
|
|
|
161
|
-
return { start: match.index, end: match.index + match[0].length,
|
|
173
|
+
return { start: match.index, end: match.index + match[0].length, referenceId: claimWorker(emit, resolved.id) };
|
|
162
174
|
};
|
|
163
175
|
|
|
164
176
|
const collectReplacements = async (emit: EmitContext, scan: ScanContext): Promise<WorkerReplacement[]> => {
|
|
@@ -196,8 +208,8 @@ const applyReplacements = (code: string, replacements: WorkerReplacement[]): str
|
|
|
196
208
|
let output = "";
|
|
197
209
|
let cursor = 0;
|
|
198
210
|
|
|
199
|
-
for (const { start, end,
|
|
200
|
-
output += code.slice(cursor, start) +
|
|
211
|
+
for (const { start, end, referenceId } of replacements) {
|
|
212
|
+
output += code.slice(cursor, start) + workerUrlReference(referenceId);
|
|
201
213
|
cursor = end;
|
|
202
214
|
}
|
|
203
215
|
|
|
@@ -222,14 +234,18 @@ const transformWorkerUrls = async (emit: EmitContext, code: string, id: string):
|
|
|
222
234
|
};
|
|
223
235
|
|
|
224
236
|
function gtkxWorker(): Plugin {
|
|
225
|
-
const
|
|
237
|
+
const references: WorkerReferences = { byModule: new Map(), claimed: new Set() };
|
|
226
238
|
|
|
227
239
|
return {
|
|
228
240
|
name: "gtkx:worker",
|
|
229
241
|
apply: "build",
|
|
230
242
|
|
|
231
243
|
transform(code, id) {
|
|
232
|
-
return transformWorkerUrls({ context: this,
|
|
244
|
+
return transformWorkerUrls({ context: this, references }, code, id);
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
resolveFileUrl({ referenceId, relativePath }) {
|
|
248
|
+
return references.claimed.has(referenceId) ? workerUrlExpression(relativePath) : null;
|
|
233
249
|
},
|
|
234
250
|
};
|
|
235
251
|
}
|