@gtkx/cli 2.0.0-beta.6 → 2.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +43 -40
  2. package/dist/cli.js +1 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/codegen/freshness.d.ts.map +1 -1
  5. package/dist/codegen/freshness.js +5 -1
  6. package/dist/codegen/freshness.js.map +1 -1
  7. package/dist/deploy/settings/libraries.d.ts.map +1 -1
  8. package/dist/deploy/settings/libraries.js +2 -1
  9. package/dist/deploy/settings/libraries.js.map +1 -1
  10. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  11. package/dist/deploy/targets/flatpak-source.js +2 -0
  12. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  13. package/dist/dev/font-dir.d.ts +3 -0
  14. package/dist/dev/font-dir.d.ts.map +1 -0
  15. package/dist/dev/font-dir.js +12 -0
  16. package/dist/dev/font-dir.js.map +1 -0
  17. package/dist/dev/runner-main.d.ts.map +1 -1
  18. package/dist/dev/runner-main.js +2 -0
  19. package/dist/dev/runner-main.js.map +1 -1
  20. package/dist/internal/agent-rules.d.ts.map +1 -1
  21. package/dist/internal/agent-rules.js +6 -2
  22. package/dist/internal/agent-rules.js.map +1 -1
  23. package/dist/internal/banner.d.ts.map +1 -1
  24. package/dist/internal/banner.js +3 -0
  25. package/dist/internal/banner.js.map +1 -1
  26. package/dist/internal/font-path.d.ts +4 -0
  27. package/dist/internal/font-path.d.ts.map +1 -0
  28. package/dist/internal/font-path.js +12 -0
  29. package/dist/internal/font-path.js.map +1 -0
  30. package/dist/internal/font-staging.d.ts +3 -0
  31. package/dist/internal/font-staging.d.ts.map +1 -0
  32. package/dist/internal/font-staging.js +43 -0
  33. package/dist/internal/font-staging.js.map +1 -0
  34. package/dist/internal/source-imports.d.ts +2 -1
  35. package/dist/internal/source-imports.d.ts.map +1 -1
  36. package/dist/internal/source-imports.js +7 -2
  37. package/dist/internal/source-imports.js.map +1 -1
  38. package/dist/internal/xdg-banner.d.ts +4 -0
  39. package/dist/internal/xdg-banner.d.ts.map +1 -0
  40. package/dist/internal/xdg-banner.js +11 -0
  41. package/dist/internal/xdg-banner.js.map +1 -0
  42. package/dist/internal/xdg-data-dirs.d.ts +2 -1
  43. package/dist/internal/xdg-data-dirs.d.ts.map +1 -1
  44. package/dist/internal/xdg-data-dirs.js +1 -1
  45. package/dist/internal/xdg-data-dirs.js.map +1 -1
  46. package/dist/settings/schema.d.ts.map +1 -1
  47. package/dist/settings/schema.js +1 -6
  48. package/dist/settings/schema.js.map +1 -1
  49. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  50. package/dist/vite-plugins/asset-extensions.js +2 -0
  51. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  52. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  53. package/dist/vite-plugins/asset-imports.js +7 -2
  54. package/dist/vite-plugins/asset-imports.js.map +1 -1
  55. package/dist/vite-plugins/asset-specifier.d.ts +5 -1
  56. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
  57. package/dist/vite-plugins/asset-specifier.js +10 -1
  58. package/dist/vite-plugins/asset-specifier.js.map +1 -1
  59. package/dist/vite-plugins/css.d.ts.map +1 -1
  60. package/dist/vite-plugins/css.js +3 -2
  61. package/dist/vite-plugins/css.js.map +1 -1
  62. package/dist/vite-plugins/font-name.d.ts +3 -0
  63. package/dist/vite-plugins/font-name.d.ts.map +1 -0
  64. package/dist/vite-plugins/font-name.js +406 -0
  65. package/dist/vite-plugins/font-name.js.map +1 -0
  66. package/dist/vite-plugins/font-worker-env.d.ts +4 -0
  67. package/dist/vite-plugins/font-worker-env.d.ts.map +1 -0
  68. package/dist/vite-plugins/font-worker-env.js +22 -0
  69. package/dist/vite-plugins/font-worker-env.js.map +1 -0
  70. package/dist/vite-plugins/font.d.ts +4 -0
  71. package/dist/vite-plugins/font.d.ts.map +1 -0
  72. package/dist/vite-plugins/font.js +87 -0
  73. package/dist/vite-plugins/font.js.map +1 -0
  74. package/dist/vite-plugins/icons.d.ts.map +1 -1
  75. package/dist/vite-plugins/icons.js +3 -8
  76. package/dist/vite-plugins/icons.js.map +1 -1
  77. package/dist/vite-plugins/index.d.ts.map +1 -1
  78. package/dist/vite-plugins/index.js +2 -0
  79. package/dist/vite-plugins/index.js.map +1 -1
  80. package/dist/vite-plugins/resources.js +1 -1
  81. package/dist/vite-plugins/resources.js.map +1 -1
  82. package/dist/vite-plugins/undeclared-library.js +3 -3
  83. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  84. package/dist/vitest-plugin.d.ts.map +1 -1
  85. package/dist/vitest-plugin.js +2 -0
  86. package/dist/vitest-plugin.js.map +1 -1
  87. package/env.d.ts +9 -0
  88. package/package.json +14 -12
  89. package/src/cli.ts +1 -1
  90. package/src/codegen/freshness.ts +5 -1
  91. package/src/deploy/settings/libraries.ts +2 -1
  92. package/src/deploy/targets/flatpak-source.ts +2 -0
  93. package/src/dev/font-dir.ts +16 -0
  94. package/src/dev/runner-main.ts +2 -0
  95. package/src/internal/agent-rules.ts +6 -2
  96. package/src/internal/banner.ts +4 -0
  97. package/src/internal/font-path.ts +15 -0
  98. package/src/internal/font-staging.ts +57 -0
  99. package/src/internal/source-imports.ts +17 -2
  100. package/src/internal/xdg-banner.ts +13 -0
  101. package/src/internal/xdg-data-dirs.ts +1 -1
  102. package/src/settings/schema.ts +1 -8
  103. package/src/vite-plugins/asset-extensions.ts +2 -0
  104. package/src/vite-plugins/asset-imports.ts +9 -1
  105. package/src/vite-plugins/asset-specifier.ts +17 -0
  106. package/src/vite-plugins/css.ts +4 -2
  107. package/src/vite-plugins/font-name.ts +582 -0
  108. package/src/vite-plugins/font-worker-env.ts +29 -0
  109. package/src/vite-plugins/font.ts +147 -0
  110. package/src/vite-plugins/icons.ts +4 -10
  111. package/src/vite-plugins/index.ts +2 -0
  112. package/src/vite-plugins/resources.ts +1 -1
  113. package/src/vite-plugins/undeclared-library.ts +3 -3
  114. package/src/vitest-plugin.ts +2 -0
@@ -0,0 +1,147 @@
1
+ import type { Plugin, Rollup } from "vite";
2
+ import { readFileSync } from "node:fs";
3
+ import { parseSync } from "vite";
4
+ import type { AssetEmitter } from "./asset-emitter.js";
5
+ import { prependBanner } from "../internal/banner.js";
6
+ import { fontFileName, FONTS_DIR } from "../internal/font-path.js";
7
+ import { sourceLanguage } from "../internal/source-imports.js";
8
+ import { xdgDataDirsBanner } from "../internal/xdg-banner.js";
9
+ import { parseFontSpecifier } from "./asset-specifier.js";
10
+ import { fontFamilyNames } from "./font-name.js";
11
+ import { stripQuery } from "./strip-query.js";
12
+ import { createVirtualNamespace } from "./virtual-module.js";
13
+
14
+ type PluginState = {
15
+ isBuild: boolean;
16
+ emitted: Set<string>;
17
+ };
18
+
19
+ type ResolveContext = Parameters<typeof resolveToVirtual>[0];
20
+ type ResolveRequest = Parameters<typeof resolveToVirtual>[1];
21
+
22
+ type RetainedFontModuleId = {
23
+ id: string;
24
+ moduleSideEffects: true;
25
+ };
26
+
27
+ type LoadContext = AssetEmitter & {
28
+ addWatchFile: (file: string) => void;
29
+ error: (message: string) => never;
30
+ };
31
+
32
+ const VIRTUAL_PREFIX = "\0gtkx-font:";
33
+ const { isVirtual, fromVirtualId, resolveToVirtual } = createVirtualNamespace(VIRTUAL_PREFIX);
34
+
35
+ const unreadableFontError = (filePath: string): string =>
36
+ `Cannot read a font family name from ${filePath}; ?font expects a TrueType, OpenType, ` +
37
+ "TrueType Collection, WOFF, or WOFF2 font";
38
+
39
+ const resolveFontId = async (
40
+ ctx: ResolveContext,
41
+ request: ResolveRequest,
42
+ ): Promise<RetainedFontModuleId | undefined> => {
43
+ if (parseFontSpecifier(request.source) === null) {
44
+ return undefined;
45
+ }
46
+
47
+ const virtualId = await resolveToVirtual(ctx, request);
48
+
49
+ return virtualId === undefined ? undefined : { id: virtualId, moduleSideEffects: true };
50
+ };
51
+
52
+ const emitFont = (ctx: LoadContext, state: PluginState, filePath: string, content: Buffer): void => {
53
+ const fileName = `${FONTS_DIR}/${fontFileName(filePath, content)}`;
54
+
55
+ if (state.emitted.has(fileName)) {
56
+ return;
57
+ }
58
+
59
+ state.emitted.add(fileName);
60
+ ctx.emitFile({ type: "asset", fileName, source: content });
61
+ };
62
+
63
+ const loadFontModule = (ctx: LoadContext, state: PluginState, id: string): string | undefined => {
64
+ if (!isVirtual(id)) {
65
+ return undefined;
66
+ }
67
+
68
+ const filePath = stripQuery(fromVirtualId(id));
69
+ const content = readFileSync(filePath);
70
+ const [family] = fontFamilyNames(content);
71
+
72
+ if (family === undefined) {
73
+ return ctx.error(unreadableFontError(filePath));
74
+ }
75
+
76
+ ctx.addWatchFile(filePath);
77
+
78
+ if (state.isBuild) {
79
+ emitFont(ctx, state, filePath, content);
80
+ }
81
+
82
+ return `export default ${JSON.stringify(family)};`;
83
+ };
84
+
85
+ const hasSideEffectFontImport = (code: string, id: string): boolean => {
86
+ const lang = sourceLanguage(stripQuery(id));
87
+
88
+ if (lang === undefined || !code.includes("?font")) {
89
+ return false;
90
+ }
91
+
92
+ const parsed = parseSync(id, code, { lang });
93
+
94
+ if (parsed.errors.length > 0) {
95
+ return false;
96
+ }
97
+
98
+ return parsed.module.staticImports.some(
99
+ (statement) => statement.entries.length === 0 && parseFontSpecifier(statement.moduleRequest.value) !== null,
100
+ );
101
+ };
102
+
103
+ const retainSideEffectFontImport = (
104
+ code: string,
105
+ id: string,
106
+ ): { code: string; moduleSideEffects: true } | null =>
107
+ hasSideEffectFontImport(code, id)
108
+ ? { code, moduleSideEffects: true }
109
+ : null;
110
+
111
+ const fontBanner = (state: PluginState) => (chunk: Rollup.RenderedChunk): string =>
112
+ state.emitted.size === 0 ? "" : xdgDataDirsBanner(chunk);
113
+
114
+ function gtkxFont(): Plugin {
115
+ const state: PluginState = { isBuild: false, emitted: new Set() };
116
+
117
+ return {
118
+ name: "gtkx:font",
119
+ enforce: "pre",
120
+
121
+ configResolved(config) {
122
+ state.isBuild = config.command === "build";
123
+ },
124
+
125
+ resolveId(source, importer, options) {
126
+ return resolveFontId(this, { source, importer, options });
127
+ },
128
+
129
+ load(id) {
130
+ return loadFontModule(this, state, id);
131
+ },
132
+
133
+ transform(code, id) {
134
+ return retainSideEffectFontImport(code, id);
135
+ },
136
+
137
+ outputOptions(options) {
138
+ if (!state.isBuild) {
139
+ return;
140
+ }
141
+
142
+ return prependBanner(options, fontBanner(state));
143
+ },
144
+ };
145
+ }
146
+
147
+ export { gtkxFont };
@@ -1,17 +1,18 @@
1
1
  import type { ConfigLoader } from "@gtkx/config";
2
- import type { Plugin, Rollup, UserConfig } from "vite";
2
+ import type { Plugin, UserConfig } from "vite";
3
3
  import { createConfigLoader } 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";
7
7
  import type { AssetEmitter } from "./asset-emitter.js";
8
- import { outputRootUrlExpression, prependBanner } from "../internal/banner.js";
8
+ import { prependBanner } from "../internal/banner.js";
9
9
  import {
10
10
  relativeIconPath,
11
11
  resolveApplicationIcon,
12
12
  type ResolvedApplicationIcon,
13
13
  } from "../internal/icon-path.js";
14
14
  import { type ListedFile, listFilesRecursive } from "../internal/list-files.js";
15
+ import { xdgDataDirsBanner } from "../internal/xdg-banner.js";
15
16
 
16
17
  type PluginState = {
17
18
  applicationId: string;
@@ -20,13 +21,6 @@ type PluginState = {
20
21
 
21
22
  const ICONS_DIR = "icons";
22
23
 
23
- const xdgEnvBanner = (chunk: Rollup.RenderedChunk): string => [
24
- "globalThis.process.env.XDG_DATA_DIRS = [",
25
- ` ${outputRootUrlExpression(chunk)},`,
26
- " globalThis.process.env.XDG_DATA_DIRS || \"/usr/local/share:/usr/share\",",
27
- "].join(\":\");",
28
- ].join("\n");
29
-
30
24
  const findIconFiles = (state: PluginState): ListedFile[] => {
31
25
  if (state.source.kind === "theme") {
32
26
  return listFilesRecursive(state.source.path);
@@ -78,7 +72,7 @@ function gtkxIcons(loadConfig: ConfigLoader = createConfigLoader()): Plugin {
78
72
  return;
79
73
  }
80
74
 
81
- return prependBanner(options, xdgEnvBanner);
75
+ return prependBanner(options, xdgDataDirsBanner);
82
76
  },
83
77
 
84
78
  buildEnd() {
@@ -5,6 +5,7 @@ import type { BuildManifestCollector } from "../internal/build-manifest.js";
5
5
  import { gtkxAssetImports } from "./asset-imports.js";
6
6
  import { gtkxBuiltUrl } from "./built-url.js";
7
7
  import { gtkxCss } from "./css.js";
8
+ import { gtkxFont } from "./font.js";
8
9
  import { type CatalogWriteListener, gtkxI18n } from "./i18n.js";
9
10
  import { gtkxIcons } from "./icons.js";
10
11
  import { gtkxReactCompiler } from "./react-compiler.js";
@@ -53,6 +54,7 @@ const gtkxVitePlugins = (options: GtkxVitePluginOptions = {}): Plugin[] => {
53
54
  gtkxIcons(loadConfig),
54
55
  gtkxAssetImports(),
55
56
  gtkxBuiltUrl(),
57
+ gtkxFont(),
56
58
  gtkxResources(loadConfig, entryPath),
57
59
  gtkxCss(),
58
60
  gtkxReactCompiler(loadConfig),
@@ -1383,7 +1383,7 @@ const rejectInvalidSpecifier = (source: string): void => {
1383
1383
  if (isBareRelativeAsset(source)) {
1384
1384
  throw new Error(
1385
1385
  `${JSON.stringify(source)} must choose ?resource for a GResource, ?icon for a themed icon, ` +
1386
- "or ?url for an emitted file",
1386
+ "?font for a bundled font, or ?url for an emitted file",
1387
1387
  );
1388
1388
  }
1389
1389
  };
@@ -20,7 +20,7 @@ type GeneratedModule = {
20
20
  };
21
21
 
22
22
  const GENERATED_MODULE_PATTERN = /^@gtkx\/(gi|jsx)\/([a-z0-9]+)$/;
23
- const DEFAULT_LIBRARY_NAMESPACES: Set<string> = new Set(["gtk", "adw"]);
23
+ const DEFAULT_LIBRARY_NAMESPACES: Set<string> = new Set(["adw", "gtk"]);
24
24
 
25
25
  const girSearchPaths = async (state: PluginState): Promise<string[]> => {
26
26
  if (state.girPath === null) {
@@ -88,7 +88,7 @@ const undeclaredLibraryError = (source: string, namespace: string, girPath: stri
88
88
  return new Error(
89
89
  `Cannot resolve "${source}": the binding store has no "${namespace}" module, and no ` +
90
90
  `GIR data for it was found in [${girPath.join(", ")}]. If "${namespace}" is a library, install ` +
91
- "its gobject-introspection data package. Gtk-4.0 and Adw-1 are bound by default; add only other " +
91
+ "its gobject-introspection data package. Adw-1 is bound by default and pulls in Gtk-4.0; add only other " +
92
92
  "GIR identifiers to `libraries` in gtkx.config.ts. Otherwise run gtkx codegen to regenerate the store.",
93
93
  );
94
94
  }
@@ -96,7 +96,7 @@ const undeclaredLibraryError = (source: string, namespace: string, girPath: stri
96
96
  if (DEFAULT_LIBRARY_NAMESPACES.has(namespace)) {
97
97
  return new Error(
98
98
  `Cannot resolve "${source}": the "${identifier}" bindings have not been generated. ` +
99
- "The Gtk and Adwaita namespaces are bound by default; run gtkx dev or gtkx build again.",
99
+ "The Adwaita and GTK namespaces are generated implicitly; run gtkx dev or gtkx build again.",
100
100
  );
101
101
  }
102
102
 
@@ -1,6 +1,7 @@
1
1
  import type { Plugin } from "vite";
2
2
  import gtkxVitest, { type PluginOptions } from "@gtkx/vitest";
3
3
  import { gtkxEnsureStore } from "./vite-plugins/ensure-store.js";
4
+ import { gtkxFontWorkerEnv } from "./vite-plugins/font-worker-env.js";
4
5
  import { gtkxVitePlugins } from "./vite-plugins/index.js";
5
6
  import { gtkxSettingsWorkerEnv } from "./vite-plugins/settings-worker-env.js";
6
7
 
@@ -15,6 +16,7 @@ const gtkx = (options: PluginOptions = {}): Plugin[] => [
15
16
  gtkxEnsureStore(options.configFile),
16
17
  ...gtkxVitePlugins({ configFile: options.configFile }),
17
18
  gtkxSettingsWorkerEnv(options.configFile),
19
+ gtkxFontWorkerEnv(options.configFile),
18
20
  gtkxVitest(options),
19
21
  ];
20
22