@gtkx/cli 2.0.0-beta.8 → 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/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/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 +15 -4
- 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/run-deploy.d.ts.map +1 -1
- package/dist/deploy/run-deploy.js +4 -1
- package/dist/deploy/run-deploy.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/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/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 +10 -10
- package/src/deploy/depends.ts +30 -3
- package/src/deploy/node-runtime/guard.ts +10 -14
- package/src/deploy/node-runtime/index.ts +19 -4
- package/src/deploy/node-runtime/sonames.ts +17 -0
- package/src/deploy/run-deploy.ts +6 -1
- package/src/internal/icon-staging.ts +58 -0
- package/src/vite-plugins/icon-worker-env.ts +36 -0
- package/src/vite-plugins/worker.ts +31 -15
- package/src/vitest-plugin.ts +4 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createConfigLoader, viteProjectRoot } from "@gtkx/config/internal";
|
|
2
|
+
import { stageProjectIcons } from "../internal/icon-staging.js";
|
|
3
|
+
import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
|
|
4
|
+
function gtkxIconWorkerEnv(configFile) {
|
|
5
|
+
const loadConfig = createConfigLoader({ configFile });
|
|
6
|
+
return {
|
|
7
|
+
name: "gtkx:icon-worker-env",
|
|
8
|
+
enforce: "pre",
|
|
9
|
+
async config(config) {
|
|
10
|
+
const loaded = await loadConfig.load(viteProjectRoot(config));
|
|
11
|
+
const shareDir = stageProjectIcons(loaded.root, loaded.config.applicationId, loaded.config.applicationIcon);
|
|
12
|
+
if (shareDir === null) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const existing = config.test?.env?.XDG_DATA_DIRS ?? process.env.XDG_DATA_DIRS;
|
|
16
|
+
return {
|
|
17
|
+
test: { env: { XDG_DATA_DIRS: prependXdgDataDir(shareDir, existing) } },
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export { gtkxIconWorkerEnv };
|
|
23
|
+
//# sourceMappingURL=icon-worker-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-worker-env.js","sourceRoot":"","sources":["../../src/vite-plugins/icon-worker-env.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,SAAS,iBAAiB,CAAC,UAAmB;IAC1C,MAAM,UAAU,GAAG,kBAAkB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtD,OAAO;QACH,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,KAAK;QAEd,KAAK,CAAC,MAAM,CAAC,MAAkB;YAC3B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;YAE9D,MAAM,QAAQ,GAAG,iBAAiB,CAC9B,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,MAAM,CAAC,aAAa,EAC3B,MAAM,CAAC,MAAM,CAAC,eAAe,CAChC,CAAC;YAEF,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAE9E,OAAO;gBACH,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE;aAC1E,CAAC;QACN,CAAC;KACJ,CAAC;AACN,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["import type { UserConfig } from \"vite\";\nimport type { Plugin } from \"vitest/config\";\nimport { createConfigLoader, viteProjectRoot } from \"@gtkx/config/internal\";\nimport { stageProjectIcons } from \"../internal/icon-staging.js\";\nimport { prependXdgDataDir } from \"../internal/xdg-data-dirs.js\";\n\nfunction gtkxIconWorkerEnv(configFile?: string): Plugin {\n const loadConfig = createConfigLoader({ configFile });\n\n return {\n name: \"gtkx:icon-worker-env\",\n enforce: \"pre\",\n\n async config(config: UserConfig) {\n const loaded = await loadConfig.load(viteProjectRoot(config));\n\n const shareDir = stageProjectIcons(\n loaded.root,\n loaded.config.applicationId,\n loaded.config.applicationIcon,\n );\n\n if (shareDir === null) {\n return;\n }\n\n const existing = config.test?.env?.XDG_DATA_DIRS ?? process.env.XDG_DATA_DIRS;\n\n return {\n test: { env: { XDG_DATA_DIRS: prependXdgDataDir(shareDir, existing) } },\n };\n },\n };\n}\n\nexport { gtkxIconWorkerEnv };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/vite-plugins/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/vite-plugins/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;AA2O3C,iBAAS,UAAU,IAAI,MAAM,CAe5B;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -33,9 +33,10 @@ const nonCodeRanges = (code) => code
|
|
|
33
33
|
const isCodePosition = (scan, index) => scan.nonCode.every((range) => index < range.start || index >= range.end);
|
|
34
34
|
const isWorkerConstruction = (code, matchIndex) => WORKER_CONSTRUCTION.test(code.slice(0, matchIndex));
|
|
35
35
|
const hasWorkerCandidate = (code) => code.includes("import.meta.url") && code.includes("Worker");
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const workerUrlReference = (referenceId) => `import.meta.ROLLUP_FILE_URL_${referenceId}`;
|
|
37
|
+
const workerUrlExpression = (relativePath) => {
|
|
38
|
+
const specifier = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
39
|
+
return `new URL(${JSON.stringify(specifier)}, import.meta.url)`;
|
|
39
40
|
};
|
|
40
41
|
const inlineWorkerExample = (specifier) => `new Worker(new URL(${JSON.stringify(specifier)}, import.meta.url))`;
|
|
41
42
|
const hoistedWorkerError = (scan, hoisted) => new Error(`${stripQuery(scan.id)}: the worker URL for ${JSON.stringify(hoisted.specifier)} is bound to ` +
|
|
@@ -59,14 +60,18 @@ const suggestionFor = async (emit, scan, specifier) => {
|
|
|
59
60
|
return null;
|
|
60
61
|
};
|
|
61
62
|
const claimWorker = (emit, resolvedId) => {
|
|
62
|
-
const existing = emit.
|
|
63
|
+
const existing = emit.references.byModule.get(resolvedId);
|
|
63
64
|
if (existing !== undefined) {
|
|
64
65
|
return existing;
|
|
65
66
|
}
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
const referenceId = emit.context.emitFile({
|
|
68
|
+
type: "chunk",
|
|
69
|
+
id: resolvedId,
|
|
70
|
+
fileName: workerFileName(resolvedId),
|
|
71
|
+
});
|
|
72
|
+
emit.references.byModule.set(resolvedId, referenceId);
|
|
73
|
+
emit.references.claimed.add(referenceId);
|
|
74
|
+
return referenceId;
|
|
70
75
|
};
|
|
71
76
|
const isRewritableUrl = (scan, match) => isCodePosition(scan, match.index) && isWorkerConstruction(scan.code, match.index);
|
|
72
77
|
const replacementFor = async (emit, scan, match) => {
|
|
@@ -78,7 +83,7 @@ const replacementFor = async (emit, scan, match) => {
|
|
|
78
83
|
if (resolved === null) {
|
|
79
84
|
throw unresolvedWorkerError(scan, specifier, await suggestionFor(emit, scan, specifier));
|
|
80
85
|
}
|
|
81
|
-
return { start: match.index, end: match.index + match[0].length,
|
|
86
|
+
return { start: match.index, end: match.index + match[0].length, referenceId: claimWorker(emit, resolved.id) };
|
|
82
87
|
};
|
|
83
88
|
const collectReplacements = async (emit, scan) => {
|
|
84
89
|
const pending = scan.code.matchAll(WORKER_URL).map((match) => replacementFor(emit, scan, match)).toArray();
|
|
@@ -105,8 +110,8 @@ const findHoistedWorkerUrl = (scan) => scan.code
|
|
|
105
110
|
const applyReplacements = (code, replacements) => {
|
|
106
111
|
let output = "";
|
|
107
112
|
let cursor = 0;
|
|
108
|
-
for (const { start, end,
|
|
109
|
-
output += code.slice(cursor, start) +
|
|
113
|
+
for (const { start, end, referenceId } of replacements) {
|
|
114
|
+
output += code.slice(cursor, start) + workerUrlReference(referenceId);
|
|
110
115
|
cursor = end;
|
|
111
116
|
}
|
|
112
117
|
return output + code.slice(cursor);
|
|
@@ -124,12 +129,15 @@ const transformWorkerUrls = async (emit, code, id) => {
|
|
|
124
129
|
return replacements.length === 0 ? null : { code: applyReplacements(code, replacements), map: null };
|
|
125
130
|
};
|
|
126
131
|
function gtkxWorker() {
|
|
127
|
-
const
|
|
132
|
+
const references = { byModule: new Map(), claimed: new Set() };
|
|
128
133
|
return {
|
|
129
134
|
name: "gtkx:worker",
|
|
130
135
|
apply: "build",
|
|
131
136
|
transform(code, id) {
|
|
132
|
-
return transformWorkerUrls({ context: this,
|
|
137
|
+
return transformWorkerUrls({ context: this, references }, code, id);
|
|
138
|
+
},
|
|
139
|
+
resolveFileUrl({ referenceId, relativePath }) {
|
|
140
|
+
return references.claimed.has(referenceId) ? workerUrlExpression(relativePath) : null;
|
|
133
141
|
},
|
|
134
142
|
};
|
|
135
143
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/vite-plugins/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Plugin, Rollup } from \"vite\";\nimport { createHash } from \"node:crypto\";\nimport { basename, extname } from \"node:path\";\nimport { ESM_EXTENSION } from \"./esm-extension.js\";\nimport { stripQuery } from \"./strip-query.js\";\n\ntype WorkerReplacement = {\n start: number;\n end: number;\n fileName: string;\n};\n\ntype EmitContext = {\n context: Rollup.PluginContext;\n emitted: Map<string, string>;\n};\n\ntype SourceRange = {\n start: number;\n end: number;\n};\n\ntype ScanContext = {\n code: string;\n id: string;\n nonCode: SourceRange[];\n};\n\ntype HoistedWorkerUrl = {\n name: string;\n specifier: string;\n};\n\ntype TransformResult = {\n code: string;\n map: null;\n} | null;\n\nconst RELATIVE_SPECIFIER = String.raw`(?<quote>[\"'])(?<specifier>\\.{1,2}\\/[^\"']+)\\k<quote>`;\nconst URL_CALL = String.raw`new\\s+URL\\s*\\(\\s*${RELATIVE_SPECIFIER}\\s*,\\s*import\\.meta\\.url\\s*\\)`;\nconst URL_DECLARATION = String.raw`(?:const|let|var)\\s+(?<name>[A-Za-z_$][\\w$]*)\\s*(?::[^=;\\n]+)?=\\s*`;\nconst BLOCK_COMMENT = String.raw`\\/\\*[\\s\\S]*?\\*\\/`;\nconst LINE_COMMENT = String.raw`\\/\\/[^\\n]*`;\nconst DOUBLE_QUOTED = String.raw`\"(?:[^\"\\\\\\n]|\\\\[\\s\\S])*\"`;\nconst SINGLE_QUOTED = String.raw`'(?:[^'\\\\\\n]|\\\\[\\s\\S])*'`;\nconst TEMPLATE_LITERAL = String.raw`\\`(?:[^\\`\\\\]|\\\\[\\s\\S])*\\``;\nconst WORKER_URL = new RegExp(URL_CALL, \"g\");\nconst HOISTED_WORKER_URL = new RegExp(URL_DECLARATION + URL_CALL, \"g\");\nconst WORKER_CONSTRUCTION = /new\\s+(?:\\w+\\.)?Worker\\s*\\(\\s*$/;\n\nconst NON_CODE = new RegExp(\n [BLOCK_COMMENT, LINE_COMMENT, DOUBLE_QUOTED, SINGLE_QUOTED, TEMPLATE_LITERAL].join(\"|\"),\n \"g\",\n);\n\nconst WORKER_DIR = \"workers\";\n\nconst SUGGESTED_EXTENSIONS: Record<string, string[]> = {\n \".js\": [\".ts\", \".tsx\"],\n \".jsx\": [\".tsx\"],\n \".mjs\": [\".mts\"],\n};\n\nconst workerFileName = (id: string): string => {\n const path = stripQuery(id);\n const stem = basename(path, extname(path));\n const digest = createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 8);\n\n return `${WORKER_DIR}/${stem}-${digest}${ESM_EXTENSION}`;\n};\n\nconst nonCodeRanges = (code: string): SourceRange[] =>\n code\n .matchAll(NON_CODE)\n .map((match) => ({ start: match.index, end: match.index + match[0].length }))\n .toArray();\n\nconst isCodePosition = (scan: ScanContext, index: number): boolean =>\n scan.nonCode.every((range) => index < range.start || index >= range.end);\n\nconst isWorkerConstruction = (code: string, matchIndex: number): boolean =>\n WORKER_CONSTRUCTION.test(code.slice(0, matchIndex));\n\nconst hasWorkerCandidate = (code: string): boolean => code.includes(\"import.meta.url\") && code.includes(\"Worker\");\n\nconst workerUrlExpression = (fileName: string): string => {\n const specifier = JSON.stringify(`./${fileName}`);\n\n return `new URL(${specifier}, import.meta.url)`;\n};\n\nconst inlineWorkerExample = (specifier: string): string =>\n `new Worker(new URL(${JSON.stringify(specifier)}, import.meta.url))`;\n\nconst hoistedWorkerError = (scan: ScanContext, hoisted: HoistedWorkerUrl): Error =>\n new Error(\n `${stripQuery(scan.id)}: the worker URL for ${JSON.stringify(hoisted.specifier)} is bound to ` +\n `\"${hoisted.name}\" before it reaches \"new Worker\". gtkx build emits a worker chunk only for a URL ` +\n `written inside the construction. Write ${inlineWorkerExample(hoisted.specifier)} instead.`,\n );\n\nconst unresolvedWorkerError = (scan: ScanContext, specifier: string, suggestion: string | null): Error =>\n new Error(\n `${stripQuery(scan.id)}: the worker specifier ${JSON.stringify(specifier)} does not resolve to a module, ` +\n \"so no worker chunk can be emitted. \" +\n (suggestion === null\n ? \"Correct the path so it names the worker source file as it exists on disk.\"\n : `Write ${inlineWorkerExample(suggestion)} instead.`),\n );\n\nconst suggestionFor = async (emit: EmitContext, scan: ScanContext, specifier: string): Promise<string | null> => {\n const extension = extname(specifier);\n const stem = specifier.slice(0, specifier.length - extension.length);\n const candidates = SUGGESTED_EXTENSIONS[extension] ?? [];\n\n for (const candidate of candidates) {\n const resolved = await emit.context.resolve(stem + candidate, scan.id);\n\n if (resolved !== null) {\n return stem + candidate;\n }\n }\n\n return null;\n};\n\nconst claimWorker = (emit: EmitContext, resolvedId: string): string => {\n const existing = emit.emitted.get(resolvedId);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const fileName = workerFileName(resolvedId);\n emit.emitted.set(resolvedId, fileName);\n emit.context.emitFile({ type: \"chunk\", id: resolvedId, fileName });\n\n return fileName;\n};\n\nconst isRewritableUrl = (scan: ScanContext, match: RegExpExecArray): boolean =>\n isCodePosition(scan, match.index) && isWorkerConstruction(scan.code, match.index);\n\nconst replacementFor = async (\n emit: EmitContext,\n scan: ScanContext,\n match: RegExpExecArray,\n): Promise<WorkerReplacement | null> => {\n const specifier = match.groups?.specifier;\n\n if (specifier === undefined || !isRewritableUrl(scan, match)) {\n return null;\n }\n\n const resolved = await emit.context.resolve(specifier, scan.id);\n\n if (resolved === null) {\n throw unresolvedWorkerError(scan, specifier, await suggestionFor(emit, scan, specifier));\n }\n\n return { start: match.index, end: match.index + match[0].length, fileName: claimWorker(emit, resolved.id) };\n};\n\nconst collectReplacements = async (emit: EmitContext, scan: ScanContext): Promise<WorkerReplacement[]> => {\n const pending = scan.code.matchAll(WORKER_URL).map((match) => replacementFor(emit, scan, match)).toArray();\n const found = await Promise.all(pending);\n\n return found.filter((entry) => entry !== null);\n};\n\nconst hasWorkerArgument = (scan: ScanContext, name: string): boolean => {\n const escaped = name.replaceAll(\"$\", String.raw`\\$`);\n const pattern = new RegExp(String.raw`new\\s+(?:\\w+\\.)?Worker\\s*\\(\\s*${escaped}\\s*[,)]`, \"g\");\n\n return scan.code.matchAll(pattern).some((match) => isCodePosition(scan, match.index));\n};\n\nconst hoistedUrlFor = (scan: ScanContext, match: RegExpExecArray): HoistedWorkerUrl | null => {\n const name = match.groups?.name;\n const specifier = match.groups?.specifier;\n\n if (name === undefined || specifier === undefined || !isCodePosition(scan, match.index)) {\n return null;\n }\n\n return { name, specifier };\n};\n\nconst findHoistedWorkerUrl = (scan: ScanContext): HoistedWorkerUrl | null =>\n scan.code\n .matchAll(HOISTED_WORKER_URL)\n .map((match) => hoistedUrlFor(scan, match))\n .find((entry) => entry !== null && hasWorkerArgument(scan, entry.name)) ?? null;\n\nconst applyReplacements = (code: string, replacements: WorkerReplacement[]): string => {\n let output = \"\";\n let cursor = 0;\n\n for (const { start, end, fileName } of replacements) {\n output += code.slice(cursor, start) + workerUrlExpression(fileName);\n cursor = end;\n }\n\n return output + code.slice(cursor);\n};\n\nconst transformWorkerUrls = async (emit: EmitContext, code: string, id: string): Promise<TransformResult> => {\n if (!hasWorkerCandidate(code)) {\n return null;\n }\n\n const scan: ScanContext = { code, id, nonCode: nonCodeRanges(code) };\n const hoisted = findHoistedWorkerUrl(scan);\n\n if (hoisted !== null) {\n throw hoistedWorkerError(scan, hoisted);\n }\n\n const replacements = await collectReplacements(emit, scan);\n\n return replacements.length === 0 ? null : { code: applyReplacements(code, replacements), map: null };\n};\n\nfunction gtkxWorker(): Plugin {\n const emitted: Map<string, string> = new Map();\n\n return {\n name: \"gtkx:worker\",\n apply: \"build\",\n\n transform(code, id) {\n return transformWorkerUrls({ context: this, emitted }, code, id);\n },\n };\n}\n\nexport { gtkxWorker };\n"]}
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/vite-plugins/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Plugin, Rollup } from \"vite\";\nimport { createHash } from \"node:crypto\";\nimport { basename, extname } from \"node:path\";\nimport { ESM_EXTENSION } from \"./esm-extension.js\";\nimport { stripQuery } from \"./strip-query.js\";\n\ntype WorkerReplacement = {\n start: number;\n end: number;\n referenceId: string;\n};\n\ntype WorkerReferences = {\n byModule: Map<string, string>;\n claimed: Set<string>;\n};\n\ntype EmitContext = {\n context: Rollup.PluginContext;\n references: WorkerReferences;\n};\n\ntype SourceRange = {\n start: number;\n end: number;\n};\n\ntype ScanContext = {\n code: string;\n id: string;\n nonCode: SourceRange[];\n};\n\ntype HoistedWorkerUrl = {\n name: string;\n specifier: string;\n};\n\ntype TransformResult = {\n code: string;\n map: null;\n} | null;\n\nconst RELATIVE_SPECIFIER = String.raw`(?<quote>[\"'])(?<specifier>\\.{1,2}\\/[^\"']+)\\k<quote>`;\nconst URL_CALL = String.raw`new\\s+URL\\s*\\(\\s*${RELATIVE_SPECIFIER}\\s*,\\s*import\\.meta\\.url\\s*\\)`;\nconst URL_DECLARATION = String.raw`(?:const|let|var)\\s+(?<name>[A-Za-z_$][\\w$]*)\\s*(?::[^=;\\n]+)?=\\s*`;\nconst BLOCK_COMMENT = String.raw`\\/\\*[\\s\\S]*?\\*\\/`;\nconst LINE_COMMENT = String.raw`\\/\\/[^\\n]*`;\nconst DOUBLE_QUOTED = String.raw`\"(?:[^\"\\\\\\n]|\\\\[\\s\\S])*\"`;\nconst SINGLE_QUOTED = String.raw`'(?:[^'\\\\\\n]|\\\\[\\s\\S])*'`;\nconst TEMPLATE_LITERAL = String.raw`\\`(?:[^\\`\\\\]|\\\\[\\s\\S])*\\``;\nconst WORKER_URL = new RegExp(URL_CALL, \"g\");\nconst HOISTED_WORKER_URL = new RegExp(URL_DECLARATION + URL_CALL, \"g\");\nconst WORKER_CONSTRUCTION = /new\\s+(?:\\w+\\.)?Worker\\s*\\(\\s*$/;\n\nconst NON_CODE = new RegExp(\n [BLOCK_COMMENT, LINE_COMMENT, DOUBLE_QUOTED, SINGLE_QUOTED, TEMPLATE_LITERAL].join(\"|\"),\n \"g\",\n);\n\nconst WORKER_DIR = \"workers\";\n\nconst SUGGESTED_EXTENSIONS: Record<string, string[]> = {\n \".js\": [\".ts\", \".tsx\"],\n \".jsx\": [\".tsx\"],\n \".mjs\": [\".mts\"],\n};\n\nconst workerFileName = (id: string): string => {\n const path = stripQuery(id);\n const stem = basename(path, extname(path));\n const digest = createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 8);\n\n return `${WORKER_DIR}/${stem}-${digest}${ESM_EXTENSION}`;\n};\n\nconst nonCodeRanges = (code: string): SourceRange[] =>\n code\n .matchAll(NON_CODE)\n .map((match) => ({ start: match.index, end: match.index + match[0].length }))\n .toArray();\n\nconst isCodePosition = (scan: ScanContext, index: number): boolean =>\n scan.nonCode.every((range) => index < range.start || index >= range.end);\n\nconst isWorkerConstruction = (code: string, matchIndex: number): boolean =>\n WORKER_CONSTRUCTION.test(code.slice(0, matchIndex));\n\nconst hasWorkerCandidate = (code: string): boolean => code.includes(\"import.meta.url\") && code.includes(\"Worker\");\n\nconst workerUrlReference = (referenceId: string): string => `import.meta.ROLLUP_FILE_URL_${referenceId}`;\n\nconst workerUrlExpression = (relativePath: string): string => {\n const specifier = relativePath.startsWith(\".\") ? relativePath : `./${relativePath}`;\n\n return `new URL(${JSON.stringify(specifier)}, import.meta.url)`;\n};\n\nconst inlineWorkerExample = (specifier: string): string =>\n `new Worker(new URL(${JSON.stringify(specifier)}, import.meta.url))`;\n\nconst hoistedWorkerError = (scan: ScanContext, hoisted: HoistedWorkerUrl): Error =>\n new Error(\n `${stripQuery(scan.id)}: the worker URL for ${JSON.stringify(hoisted.specifier)} is bound to ` +\n `\"${hoisted.name}\" before it reaches \"new Worker\". gtkx build emits a worker chunk only for a URL ` +\n `written inside the construction. Write ${inlineWorkerExample(hoisted.specifier)} instead.`,\n );\n\nconst unresolvedWorkerError = (scan: ScanContext, specifier: string, suggestion: string | null): Error =>\n new Error(\n `${stripQuery(scan.id)}: the worker specifier ${JSON.stringify(specifier)} does not resolve to a module, ` +\n \"so no worker chunk can be emitted. \" +\n (suggestion === null\n ? \"Correct the path so it names the worker source file as it exists on disk.\"\n : `Write ${inlineWorkerExample(suggestion)} instead.`),\n );\n\nconst suggestionFor = async (emit: EmitContext, scan: ScanContext, specifier: string): Promise<string | null> => {\n const extension = extname(specifier);\n const stem = specifier.slice(0, specifier.length - extension.length);\n const candidates = SUGGESTED_EXTENSIONS[extension] ?? [];\n\n for (const candidate of candidates) {\n const resolved = await emit.context.resolve(stem + candidate, scan.id);\n\n if (resolved !== null) {\n return stem + candidate;\n }\n }\n\n return null;\n};\n\nconst claimWorker = (emit: EmitContext, resolvedId: string): string => {\n const existing = emit.references.byModule.get(resolvedId);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const referenceId = emit.context.emitFile({\n type: \"chunk\",\n id: resolvedId,\n fileName: workerFileName(resolvedId),\n });\n\n emit.references.byModule.set(resolvedId, referenceId);\n emit.references.claimed.add(referenceId);\n\n return referenceId;\n};\n\nconst isRewritableUrl = (scan: ScanContext, match: RegExpExecArray): boolean =>\n isCodePosition(scan, match.index) && isWorkerConstruction(scan.code, match.index);\n\nconst replacementFor = async (\n emit: EmitContext,\n scan: ScanContext,\n match: RegExpExecArray,\n): Promise<WorkerReplacement | null> => {\n const specifier = match.groups?.specifier;\n\n if (specifier === undefined || !isRewritableUrl(scan, match)) {\n return null;\n }\n\n const resolved = await emit.context.resolve(specifier, scan.id);\n\n if (resolved === null) {\n throw unresolvedWorkerError(scan, specifier, await suggestionFor(emit, scan, specifier));\n }\n\n return { start: match.index, end: match.index + match[0].length, referenceId: claimWorker(emit, resolved.id) };\n};\n\nconst collectReplacements = async (emit: EmitContext, scan: ScanContext): Promise<WorkerReplacement[]> => {\n const pending = scan.code.matchAll(WORKER_URL).map((match) => replacementFor(emit, scan, match)).toArray();\n const found = await Promise.all(pending);\n\n return found.filter((entry) => entry !== null);\n};\n\nconst hasWorkerArgument = (scan: ScanContext, name: string): boolean => {\n const escaped = name.replaceAll(\"$\", String.raw`\\$`);\n const pattern = new RegExp(String.raw`new\\s+(?:\\w+\\.)?Worker\\s*\\(\\s*${escaped}\\s*[,)]`, \"g\");\n\n return scan.code.matchAll(pattern).some((match) => isCodePosition(scan, match.index));\n};\n\nconst hoistedUrlFor = (scan: ScanContext, match: RegExpExecArray): HoistedWorkerUrl | null => {\n const name = match.groups?.name;\n const specifier = match.groups?.specifier;\n\n if (name === undefined || specifier === undefined || !isCodePosition(scan, match.index)) {\n return null;\n }\n\n return { name, specifier };\n};\n\nconst findHoistedWorkerUrl = (scan: ScanContext): HoistedWorkerUrl | null =>\n scan.code\n .matchAll(HOISTED_WORKER_URL)\n .map((match) => hoistedUrlFor(scan, match))\n .find((entry) => entry !== null && hasWorkerArgument(scan, entry.name)) ?? null;\n\nconst applyReplacements = (code: string, replacements: WorkerReplacement[]): string => {\n let output = \"\";\n let cursor = 0;\n\n for (const { start, end, referenceId } of replacements) {\n output += code.slice(cursor, start) + workerUrlReference(referenceId);\n cursor = end;\n }\n\n return output + code.slice(cursor);\n};\n\nconst transformWorkerUrls = async (emit: EmitContext, code: string, id: string): Promise<TransformResult> => {\n if (!hasWorkerCandidate(code)) {\n return null;\n }\n\n const scan: ScanContext = { code, id, nonCode: nonCodeRanges(code) };\n const hoisted = findHoistedWorkerUrl(scan);\n\n if (hoisted !== null) {\n throw hoistedWorkerError(scan, hoisted);\n }\n\n const replacements = await collectReplacements(emit, scan);\n\n return replacements.length === 0 ? null : { code: applyReplacements(code, replacements), map: null };\n};\n\nfunction gtkxWorker(): Plugin {\n const references: WorkerReferences = { byModule: new Map(), claimed: new Set() };\n\n return {\n name: \"gtkx:worker\",\n apply: \"build\",\n\n transform(code, id) {\n return transformWorkerUrls({ context: this, references }, code, id);\n },\n\n resolveFileUrl({ referenceId, relativePath }) {\n return references.claimed.has(referenceId) ? workerUrlExpression(relativePath) : null;\n },\n };\n}\n\nexport { gtkxWorker };\n"]}
|
package/dist/vitest-plugin.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { Plugin } from "vite";
|
|
|
2
2
|
import { type PluginOptions } from "@gtkx/vitest";
|
|
3
3
|
/**
|
|
4
4
|
* Vite plugin stack for testing a GTKX application: the generated bindings the tests import,
|
|
5
|
-
* the plugins the app is built with, the project's compiled GSettings schemas
|
|
6
|
-
* test worker, and a headless display per worker.
|
|
5
|
+
* the plugins the app is built with, the project's compiled GSettings schemas and its configured
|
|
6
|
+
* application icon exposed to every test worker, and a headless display per worker.
|
|
7
7
|
*
|
|
8
8
|
* @returns The plugins to spread into a Vitest config.
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest-plugin.d.ts","sourceRoot":"","sources":["../src/vitest-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"vitest-plugin.d.ts","sourceRoot":"","sources":["../src/vitest-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAO9D;;;;;;GAMG;AACH,QAAA,MAAM,IAAI,GAAI,UAAS,aAAkB,KAAG,MAAM,EAOjD,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
package/dist/vitest-plugin.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import gtkxVitest, {} from "@gtkx/vitest";
|
|
2
2
|
import { gtkxEnsureStore } from "./vite-plugins/ensure-store.js";
|
|
3
3
|
import { gtkxFontWorkerEnv } from "./vite-plugins/font-worker-env.js";
|
|
4
|
+
import { gtkxIconWorkerEnv } from "./vite-plugins/icon-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
|
/**
|
|
7
8
|
* Vite plugin stack for testing a GTKX application: the generated bindings the tests import,
|
|
8
|
-
* the plugins the app is built with, the project's compiled GSettings schemas
|
|
9
|
-
* test worker, and a headless display per worker.
|
|
9
|
+
* the plugins the app is built with, the project's compiled GSettings schemas and its configured
|
|
10
|
+
* application icon exposed to every test worker, and a headless display per worker.
|
|
10
11
|
*
|
|
11
12
|
* @returns The plugins to spread into a Vitest config.
|
|
12
13
|
*/
|
|
@@ -15,6 +16,7 @@ const gtkx = (options = {}) => [
|
|
|
15
16
|
...gtkxVitePlugins({ configFile: options.configFile }),
|
|
16
17
|
gtkxSettingsWorkerEnv(options.configFile),
|
|
17
18
|
gtkxFontWorkerEnv(options.configFile),
|
|
19
|
+
gtkxIconWorkerEnv(options.configFile),
|
|
18
20
|
gtkxVitest(options),
|
|
19
21
|
];
|
|
20
22
|
export default gtkx;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest-plugin.js","sourceRoot":"","sources":["../src/vitest-plugin.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAsB,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,CAAC,UAAyB,EAAE,EAAY,EAAE,CAAC;IACpD,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC;IACnC,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;IACtD,qBAAqB,CAAC,OAAO,CAAC,UAAU,CAAC;IACzC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC;IACrC,UAAU,CAAC,OAAO,CAAC;CACtB,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import type { Plugin } from \"vite\";\nimport gtkxVitest, { type PluginOptions } from \"@gtkx/vitest\";\nimport { gtkxEnsureStore } from \"./vite-plugins/ensure-store.js\";\nimport { gtkxFontWorkerEnv } from \"./vite-plugins/font-worker-env.js\";\nimport { gtkxVitePlugins } from \"./vite-plugins/index.js\";\nimport { gtkxSettingsWorkerEnv } from \"./vite-plugins/settings-worker-env.js\";\n\n/**\n * Vite plugin stack for testing a GTKX application: the generated bindings the tests import,\n * the plugins the app is built with, the project's compiled GSettings schemas
|
|
1
|
+
{"version":3,"file":"vitest-plugin.js","sourceRoot":"","sources":["../src/vitest-plugin.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAsB,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,CAAC,UAAyB,EAAE,EAAY,EAAE,CAAC;IACpD,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC;IACnC,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;IACtD,qBAAqB,CAAC,OAAO,CAAC,UAAU,CAAC;IACzC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC;IACrC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC;IACrC,UAAU,CAAC,OAAO,CAAC;CACtB,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import type { Plugin } from \"vite\";\nimport gtkxVitest, { type PluginOptions } from \"@gtkx/vitest\";\nimport { gtkxEnsureStore } from \"./vite-plugins/ensure-store.js\";\nimport { gtkxFontWorkerEnv } from \"./vite-plugins/font-worker-env.js\";\nimport { gtkxIconWorkerEnv } from \"./vite-plugins/icon-worker-env.js\";\nimport { gtkxVitePlugins } from \"./vite-plugins/index.js\";\nimport { gtkxSettingsWorkerEnv } from \"./vite-plugins/settings-worker-env.js\";\n\n/**\n * Vite plugin stack for testing a GTKX application: the generated bindings the tests import,\n * the plugins the app is built with, the project's compiled GSettings schemas and its configured\n * application icon exposed to every test worker, and a headless display per worker.\n *\n * @returns The plugins to spread into a Vitest config.\n */\nconst gtkx = (options: PluginOptions = {}): Plugin[] => [\n gtkxEnsureStore(options.configFile),\n ...gtkxVitePlugins({ configFile: options.configFile }),\n gtkxSettingsWorkerEnv(options.configFile),\n gtkxFontWorkerEnv(options.configFile),\n gtkxIconWorkerEnv(options.configFile),\n gtkxVitest(options),\n];\n\nexport default gtkx;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/cli",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.9",
|
|
4
4
|
"description": "Adwaita-first GNOME app toolchain for React and TypeScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtkx",
|
|
@@ -72,18 +72,18 @@
|
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@babel/core": "^8.0.1",
|
|
74
74
|
"@babel/preset-typescript": "^8.0.1",
|
|
75
|
-
"@gtkx/codegen": "2.0.0-beta.
|
|
76
|
-
"@gtkx/config": "2.0.0-beta.
|
|
77
|
-
"@gtkx/mcp": "2.0.0-beta.
|
|
78
|
-
"@gtkx/native": "2.0.0-beta.
|
|
79
|
-
"@gtkx/runtime": "2.0.0-beta.
|
|
80
|
-
"@gtkx/utils": "2.0.0-beta.
|
|
81
|
-
"@gtkx/vitest": "2.0.0-beta.
|
|
75
|
+
"@gtkx/codegen": "2.0.0-beta.9",
|
|
76
|
+
"@gtkx/config": "2.0.0-beta.9",
|
|
77
|
+
"@gtkx/mcp": "2.0.0-beta.9",
|
|
78
|
+
"@gtkx/native": "2.0.0-beta.9",
|
|
79
|
+
"@gtkx/runtime": "2.0.0-beta.9",
|
|
80
|
+
"@gtkx/utils": "2.0.0-beta.9",
|
|
81
|
+
"@gtkx/vitest": "2.0.0-beta.9",
|
|
82
82
|
"@swc/core": "^1.16.2",
|
|
83
83
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
84
84
|
"citty": "^0.2.2",
|
|
85
85
|
"confbox": "^0.3.1",
|
|
86
|
-
"create-gtkx": "2.0.0-beta.
|
|
86
|
+
"create-gtkx": "2.0.0-beta.9",
|
|
87
87
|
"fast-xml-builder": "^1.3.1",
|
|
88
88
|
"fast-xml-parser": "^5.11.1",
|
|
89
89
|
"hosted-git-info": "^10.1.1",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"yaml": "^2.9.0"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
|
-
"@gtkx/testing": "2.0.0-beta.
|
|
97
|
+
"@gtkx/testing": "2.0.0-beta.9",
|
|
98
98
|
"@types/babel__core": "^7.20.5",
|
|
99
99
|
"@types/hosted-git-info": "^3.0.5",
|
|
100
100
|
"@types/react-refresh": "^0.14.7",
|
package/src/deploy/depends.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { DeploySettings } from "./types.js";
|
|
2
|
+
import { PACKAGED_SONAMES, type PackagedSoname } from "./node-runtime/sonames.js";
|
|
2
3
|
|
|
3
4
|
type Relations = {
|
|
4
5
|
deb: string[];
|
|
5
6
|
rpm: string[];
|
|
6
7
|
};
|
|
7
8
|
|
|
8
|
-
type
|
|
9
|
+
type PackageNames = {
|
|
9
10
|
deb: string;
|
|
10
11
|
rpm: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type LibraryPackages = PackageNames & {
|
|
11
15
|
extra: Relations;
|
|
12
16
|
};
|
|
13
17
|
|
|
@@ -25,6 +29,17 @@ const DEPENDS_BY_LIBRARY: Record<string, LibraryPackages> = {
|
|
|
25
29
|
"Gtk-4.0": { deb: "libgtk-4-1", rpm: "gtk4", extra: { deb: [], rpm: [GLES_SONAME] } },
|
|
26
30
|
};
|
|
27
31
|
|
|
32
|
+
const RUNTIME_PACKAGES: Record<PackagedSoname, PackageNames> = {
|
|
33
|
+
"libatomic.so.1": { deb: "libatomic1", rpm: `libatomic.so.1${SONAME_SUFFIX}` },
|
|
34
|
+
"libgcc_s.so.1": { deb: "libgcc-s1", rpm: `libgcc_s.so.1${SONAME_SUFFIX}` },
|
|
35
|
+
"libstdc++.so.6": { deb: "libstdc++6", rpm: `libstdc++.so.6${SONAME_SUFFIX}` },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const RUNTIME_DEPENDS: Relations = {
|
|
39
|
+
deb: PACKAGED_SONAMES.map((soname) => RUNTIME_PACKAGES[soname].deb),
|
|
40
|
+
rpm: PACKAGED_SONAMES.map((soname) => RUNTIME_PACKAGES[soname].rpm),
|
|
41
|
+
};
|
|
42
|
+
|
|
28
43
|
const debRelation = (name: string, minimum: string | undefined): string =>
|
|
29
44
|
minimum === undefined ? name : `${name} (>= ${minimum})`;
|
|
30
45
|
|
|
@@ -63,8 +78,20 @@ const resolveDepends = (settings: DeploySettings, glibcMinimum: string | null):
|
|
|
63
78
|
const extra = settings.deploy.depends ?? {};
|
|
64
79
|
|
|
65
80
|
return {
|
|
66
|
-
deb: dedupe([
|
|
67
|
-
|
|
81
|
+
deb: dedupe([
|
|
82
|
+
...fromLibraries.deb,
|
|
83
|
+
...BASE_DEPENDS.deb,
|
|
84
|
+
...fromGlibc.deb,
|
|
85
|
+
...RUNTIME_DEPENDS.deb,
|
|
86
|
+
...(extra.deb ?? []),
|
|
87
|
+
]),
|
|
88
|
+
rpm: dedupe([
|
|
89
|
+
...fromLibraries.rpm,
|
|
90
|
+
...BASE_DEPENDS.rpm,
|
|
91
|
+
...fromGlibc.rpm,
|
|
92
|
+
...RUNTIME_DEPENDS.rpm,
|
|
93
|
+
...(extra.rpm ?? []),
|
|
94
|
+
]),
|
|
68
95
|
};
|
|
69
96
|
};
|
|
70
97
|
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import type { ElfInfo } from "./elf.js";
|
|
2
|
+
import { RUNTIME_SONAMES } from "./sonames.js";
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"libpthread.so.0",
|
|
11
|
-
"librt.so.1",
|
|
12
|
-
"libstdc++.so.6",
|
|
13
|
-
]);
|
|
4
|
+
const DOWNLOAD_REMEDY =
|
|
5
|
+
"The packages GTKX generates declare the libraries an official release links against, and this release " +
|
|
6
|
+
"links against more. Report it to GTKX, and pin `deploy.node.version` to a release it already packages.";
|
|
7
|
+
|
|
8
|
+
const SOURCE_REMEDY = 'Use `deploy.node.source: "download"` to fetch an official self-contained build instead.';
|
|
9
|
+
|
|
10
|
+
const remedyFor = (source: string): string => (source === "download" ? DOWNLOAD_REMEDY : SOURCE_REMEDY);
|
|
14
11
|
|
|
15
12
|
const assertPortableNode = (info: ElfInfo, source: string): void => {
|
|
16
|
-
const foreign = info.needed.filter((library) => !
|
|
13
|
+
const foreign = info.needed.filter((library) => !RUNTIME_SONAMES.has(library));
|
|
17
14
|
|
|
18
15
|
if (foreign.length === 0) {
|
|
19
16
|
return;
|
|
@@ -21,8 +18,7 @@ const assertPortableNode = (info: ElfInfo, source: string): void => {
|
|
|
21
18
|
|
|
22
19
|
throw new Error(
|
|
23
20
|
`Cannot bundle this Node.js binary: \`deploy.node.source: "${source}"\` picked one linked against ` +
|
|
24
|
-
`${foreign.join(", ")}, which the
|
|
25
|
-
'Use `deploy.node.source: "download"` to fetch an official self-contained build instead.',
|
|
21
|
+
`${foreign.join(", ")}, which the packages GTKX generates do not require. ${remedyFor(source)}`,
|
|
26
22
|
);
|
|
27
23
|
};
|
|
28
24
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { MINIMUM_NODE_VERSION } from "@gtkx/config/internal";
|
|
2
2
|
import { info, tryResolveExecutable, warn } from "@gtkx/utils";
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
|
-
import { chmodSync, copyFileSync, mkdirSync, statSync } from "node:fs";
|
|
4
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, statSync } from "node:fs";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
6
|
import type { DeployConfig, DeploySettings, NodeRuntime } from "../types.js";
|
|
7
7
|
import { runCliTool } from "../../internal/run-cli-tool.js";
|
|
8
8
|
import { elfMachineFor, hostArchName } from "../settings/arch.js";
|
|
9
9
|
import { downloadNode } from "./download.js";
|
|
10
|
-
import { type ElfInfo, readElfInfo } from "./elf.js";
|
|
10
|
+
import { type ElfInfo, readElfInfo, readOptionalElfInfo } from "./elf.js";
|
|
11
11
|
import { assertPortableNode } from "./guard.js";
|
|
12
12
|
import { licenseBesideNode } from "./license.js";
|
|
13
13
|
|
|
@@ -114,6 +114,21 @@ const sourcePathFor = (settings: DeploySettings): string => {
|
|
|
114
114
|
return resolve(settings.paths.root, node.path);
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
+
const assertPortableRuntimeSource = (settings: DeploySettings): void => {
|
|
118
|
+
const source = nodeSourceFor(settings);
|
|
119
|
+
|
|
120
|
+
if (source === "download") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const sourcePath = sourcePathFor(settings);
|
|
125
|
+
const elf = existsSync(sourcePath) ? readOptionalElfInfo(sourcePath) : null;
|
|
126
|
+
|
|
127
|
+
if (elf !== null) {
|
|
128
|
+
assertPortableNode(elf, source);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
117
132
|
const resolveNodeVersion = (settings: DeploySettings): string => {
|
|
118
133
|
const node = settings.deploy.node ?? {};
|
|
119
134
|
const source = nodeSourceFor(settings);
|
|
@@ -167,7 +182,6 @@ const stageFromSource = async (
|
|
|
167
182
|
}
|
|
168
183
|
|
|
169
184
|
const sourcePath = sourcePathFor(settings);
|
|
170
|
-
assertPortableNode(readElfInfo(sourcePath), source);
|
|
171
185
|
|
|
172
186
|
return { path: stageNode(settings, sourcePath), licenseFile: licenseBesideNode(sourcePath) };
|
|
173
187
|
};
|
|
@@ -197,6 +211,7 @@ const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime
|
|
|
197
211
|
const version = resolveNodeVersion(settings);
|
|
198
212
|
const staged = await stageFromSource(settings, version, source);
|
|
199
213
|
const elf = readElfInfo(staged.path);
|
|
214
|
+
assertPortableNode(elf, source);
|
|
200
215
|
const isStripped = shouldStripRuntime(settings, node, elf) && didStripBinary(staged.path);
|
|
201
216
|
const glibcMinimum = elf.glibcMinimum ?? "unknown";
|
|
202
217
|
info(`Bundled Node.js v${version} (${megabytes(staged.path)} MiB, runtime glibc >= ${glibcMinimum})`);
|
|
@@ -204,4 +219,4 @@ const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime
|
|
|
204
219
|
return { ...staged, version, glibcMinimum: elf.glibcMinimum, isStripped };
|
|
205
220
|
};
|
|
206
221
|
|
|
207
|
-
export { resolveNodeRuntime, resolveNodeVersion, sourcePathFor };
|
|
222
|
+
export { assertPortableRuntimeSource, resolveNodeRuntime, resolveNodeVersion, sourcePathFor };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const GLIBC_SONAMES = [
|
|
2
|
+
"ld-linux-aarch64.so.1",
|
|
3
|
+
"ld-linux-x86-64.so.2",
|
|
4
|
+
"libc.so.6",
|
|
5
|
+
"libdl.so.2",
|
|
6
|
+
"libm.so.6",
|
|
7
|
+
"libpthread.so.0",
|
|
8
|
+
"librt.so.1",
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
const PACKAGED_SONAMES = ["libatomic.so.1", "libgcc_s.so.1", "libstdc++.so.6"] as const;
|
|
12
|
+
|
|
13
|
+
type PackagedSoname = (typeof PACKAGED_SONAMES)[number];
|
|
14
|
+
|
|
15
|
+
const RUNTIME_SONAMES: Set<string> = new Set([...GLIBC_SONAMES, ...PACKAGED_SONAMES]);
|
|
16
|
+
|
|
17
|
+
export { PACKAGED_SONAMES, type PackagedSoname, RUNTIME_SONAMES };
|
package/src/deploy/run-deploy.ts
CHANGED
|
@@ -32,7 +32,7 @@ import { renderMetainfo } from "./freedesktop/metainfo.js";
|
|
|
32
32
|
import { renderMimePackage } from "./freedesktop/mime-package.js";
|
|
33
33
|
import { validateDesktopEntry, validateMetainfo } from "./freedesktop/validate.js";
|
|
34
34
|
import { resolveStagedAddon } from "./native-addon.js";
|
|
35
|
-
import { resolveNodeRuntime } from "./node-runtime/index.js";
|
|
35
|
+
import { assertPortableRuntimeSource, resolveNodeRuntime } from "./node-runtime/index.js";
|
|
36
36
|
import { collectNotices } from "./notices/collect.js";
|
|
37
37
|
import { type StagedMetadata, stageOverlays, stagePayload } from "./payload/stage.js";
|
|
38
38
|
import { DEFAULT_TARGETS, parseTargetList, targetsFor } from "./registry.js";
|
|
@@ -319,6 +319,11 @@ const preflight = ({ plan, settings, shouldPrintManifests, shouldSkipBuild }: Pr
|
|
|
319
319
|
|
|
320
320
|
const report = probeTools([...required, ...packagerTools]);
|
|
321
321
|
assertTools(report);
|
|
322
|
+
|
|
323
|
+
if (isNodeRequired(targets, settings)) {
|
|
324
|
+
assertPortableRuntimeSource(settings);
|
|
325
|
+
}
|
|
326
|
+
|
|
322
327
|
warnMissingOptional(report);
|
|
323
328
|
warnFlatpakPermissions(targets, settings);
|
|
324
329
|
warnLibraryMinimums(targets, settings);
|
|
@@ -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 };
|
|
@@ -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 };
|