gestament 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +20 -5
  2. package/dist/displaySession.d.ts +2 -2
  3. package/dist/displaySession.d.ts.map +1 -1
  4. package/dist/element.d.ts +2 -2
  5. package/dist/errors.d.ts +2 -2
  6. package/dist/generated/packageMetadata.d.ts +4 -4
  7. package/dist/gestament-config.d.ts +2 -2
  8. package/dist/gestament-launcher-driver.cjs +91 -5
  9. package/dist/gestament-launcher-driver.cjs.map +1 -1
  10. package/dist/gestament-launcher-driver.d.ts +2 -2
  11. package/dist/gestament-launcher-driver.mjs +91 -5
  12. package/dist/gestament-launcher-driver.mjs.map +1 -1
  13. package/dist/gestament-tray-host.cjs +9 -1
  14. package/dist/gestament-tray-host.cjs.map +1 -1
  15. package/dist/gestament-tray-host.d.ts +2 -2
  16. package/dist/gestament-tray-host.mjs +9 -1
  17. package/dist/gestament-tray-host.mjs.map +1 -1
  18. package/dist/gestament-xvfb-pool-probe.cjs +1 -1
  19. package/dist/gestament-xvfb-pool-probe.d.ts +2 -2
  20. package/dist/gestament-xvfb-pool-probe.mjs +1 -1
  21. package/dist/gestament-xvfb-worker.d.ts +2 -2
  22. package/dist/gestament-xvfb.d.ts +2 -2
  23. package/dist/gestament.cjs +279 -0
  24. package/dist/gestament.cjs.map +1 -0
  25. package/dist/gestament.d.ts +29 -0
  26. package/dist/gestament.d.ts.map +1 -0
  27. package/dist/gestament.mjs +278 -0
  28. package/dist/gestament.mjs.map +1 -0
  29. package/dist/index.cjs +1 -1
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.mjs +1 -1
  32. package/dist/{launchGtkApp-BfELuV-H.cjs → launchGtkApp-CzYcrc9f.cjs} +693 -76
  33. package/dist/launchGtkApp-CzYcrc9f.cjs.map +1 -0
  34. package/dist/{launchGtkApp-Bst1BFbD.js → launchGtkApp-EI6OIpPI.js} +691 -74
  35. package/dist/launchGtkApp-EI6OIpPI.js.map +1 -0
  36. package/dist/launchGtkApp.d.ts +2 -2
  37. package/dist/launchGtkApp.d.ts.map +1 -1
  38. package/dist/launcherDriverProtocol.d.ts +26 -4
  39. package/dist/launcherDriverProtocol.d.ts.map +1 -1
  40. package/dist/{native-C6MsIBNF.js → native-DlCBBWlV.js} +2 -2
  41. package/dist/native-DlCBBWlV.js.map +1 -0
  42. package/dist/{native-BUWDWMBB.cjs → native-Kfm95Uxw.cjs} +6 -6
  43. package/dist/native-Kfm95Uxw.cjs.map +1 -0
  44. package/dist/native.d.ts +2 -2
  45. package/dist/output.d.ts +27 -0
  46. package/dist/output.d.ts.map +1 -0
  47. package/dist/packageMetadata-CewXH0iF.cjs +4 -0
  48. package/dist/packageMetadata-CewXH0iF.cjs.map +1 -0
  49. package/dist/packageMetadata-DjxyJCJm.js +5 -0
  50. package/dist/packageMetadata-DjxyJCJm.js.map +1 -0
  51. package/dist/prerequisites.d.ts +2 -2
  52. package/dist/testing.d.ts +2 -2
  53. package/dist/tray.d.ts +2 -2
  54. package/dist/types.d.ts +183 -3
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/wait.d.ts +2 -2
  57. package/package.json +8 -7
  58. package/prebuilds/linux-arm/gtk3/node.napi.armv7.glibc.node +0 -0
  59. package/prebuilds/linux-arm/gtk4/node.napi.armv7.glibc.node +0 -0
  60. package/prebuilds/linux-arm64/gtk3/node.napi.glibc.node +0 -0
  61. package/prebuilds/linux-arm64/gtk4/node.napi.glibc.node +0 -0
  62. package/prebuilds/linux-ia32/gtk3/node.napi.glibc.node +0 -0
  63. package/prebuilds/linux-ia32/gtk4/node.napi.glibc.node +0 -0
  64. package/prebuilds/linux-riscv64/gtk3/node.napi.glibc.node +0 -0
  65. package/prebuilds/linux-riscv64/gtk4/node.napi.glibc.node +0 -0
  66. package/prebuilds/linux-x64/gtk3/node.napi.glibc.node +0 -0
  67. package/prebuilds/linux-x64/gtk4/node.napi.glibc.node +0 -0
  68. package/dist/launchGtkApp-BfELuV-H.cjs.map +0 -1
  69. package/dist/launchGtkApp-Bst1BFbD.js.map +0 -1
  70. package/dist/native-BUWDWMBB.cjs.map +0 -1
  71. package/dist/native-C6MsIBNF.js.map +0 -1
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
+ const node_fs = require("node:fs");
5
+ const promises = require("node:fs/promises");
6
+ const node_path = require("node:path");
7
+ const node_url = require("node:url");
8
+ const packageMetadata = require("./packageMetadata-CewXH0iF.cjs");
9
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
10
+ const fallbackPackageName = "gestament-tests";
11
+ const packageNamePattern = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
12
+ const usageText = [
13
+ "Usage: gestament init [directory] [--name <package-name>] [--force]",
14
+ " gestament init --help",
15
+ " gestament --help",
16
+ "",
17
+ "Creates a minimal Vitest project for gestament GTK tests.",
18
+ ""
19
+ ].join("\n");
20
+ const gitIgnoreExampleText = [
21
+ "node_modules/",
22
+ "test-results/",
23
+ "coverage/",
24
+ "*.log",
25
+ ""
26
+ ].join("\n");
27
+ const tsconfigText = `${JSON.stringify(
28
+ {
29
+ compilerOptions: {
30
+ target: "ES2020",
31
+ module: "ESNext",
32
+ lib: ["ES2020"],
33
+ moduleResolution: "Bundler",
34
+ strict: true,
35
+ skipLibCheck: true,
36
+ noEmit: true
37
+ },
38
+ include: ["tests", "vitest.config.ts"]
39
+ },
40
+ void 0,
41
+ 2
42
+ )}
43
+ `;
44
+ const vitestConfigText = [
45
+ "import { defineConfig } from 'vitest/config';",
46
+ "",
47
+ "export default defineConfig({",
48
+ " test: {",
49
+ " globals: true,",
50
+ " environment: 'node',",
51
+ " include: ['tests/**/*.test.ts'],",
52
+ " coverage: {",
53
+ " enabled: false,",
54
+ " },",
55
+ " },",
56
+ "});",
57
+ ""
58
+ ].join("\n");
59
+ const isNotFoundError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
60
+ const statIfExists = async (path) => {
61
+ try {
62
+ return await promises.stat(path);
63
+ } catch (error) {
64
+ if (isNotFoundError(error)) {
65
+ return void 0;
66
+ }
67
+ throw error;
68
+ }
69
+ };
70
+ const normalizePackageName = (value) => {
71
+ const normalized = value.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu, "-").replace(/^[._-]+|[._-]+$/gu, "");
72
+ return normalized.length === 0 ? fallbackPackageName : normalized;
73
+ };
74
+ const isValidPackageName = (value) => value.length <= 214 && !value.startsWith(".") && !value.startsWith("_") && packageNamePattern.test(value);
75
+ const createPackageJsonText = (name) => `${JSON.stringify(
76
+ {
77
+ name,
78
+ version: "0.0.1",
79
+ private: true,
80
+ scripts: {
81
+ test: "vitest run"
82
+ },
83
+ devDependencies: {
84
+ "@types/node": ">=20.0.0",
85
+ gestament: `^${packageMetadata.version}`,
86
+ typescript: ">=5.7.0",
87
+ vitest: ">=3.2.0"
88
+ }
89
+ },
90
+ void 0,
91
+ 2
92
+ )}
93
+ `;
94
+ const createScaffoldFiles = (name) => [
95
+ {
96
+ content: createPackageJsonText(name),
97
+ path: "package.json"
98
+ },
99
+ {
100
+ content: tsconfigText,
101
+ path: "tsconfig.json"
102
+ },
103
+ {
104
+ content: vitestConfigText,
105
+ path: "vitest.config.ts"
106
+ },
107
+ {
108
+ content: gitIgnoreExampleText,
109
+ path: ".gitignore.gestament-example"
110
+ }
111
+ ];
112
+ const createHelpOutput = () => ({
113
+ exitCode: 0,
114
+ stderr: "",
115
+ stdout: usageText
116
+ });
117
+ const createUsageError = (message) => ({
118
+ exitCode: 2,
119
+ stderr: `${message}
120
+ Run "gestament --help" for usage.
121
+ `,
122
+ stdout: ""
123
+ });
124
+ const parseInitOptions = (args) => {
125
+ let directory;
126
+ let force = false;
127
+ let name;
128
+ let index = 0;
129
+ while (index < args.length) {
130
+ const argument = args[index];
131
+ if (argument === void 0) {
132
+ break;
133
+ }
134
+ if (argument === "--help" || argument === "-h") {
135
+ return createHelpOutput();
136
+ }
137
+ if (argument === "--force") {
138
+ force = true;
139
+ index += 1;
140
+ continue;
141
+ }
142
+ if (argument === "--name") {
143
+ const value = args[index + 1];
144
+ if (value === void 0) {
145
+ return createUsageError("gestament init: --name requires a value.");
146
+ }
147
+ name = value;
148
+ index += 2;
149
+ continue;
150
+ }
151
+ if (argument.startsWith("--name=")) {
152
+ name = argument.slice("--name=".length);
153
+ index += 1;
154
+ continue;
155
+ }
156
+ if (argument.startsWith("-")) {
157
+ return createUsageError(`gestament init: unknown option: ${argument}`);
158
+ }
159
+ if (directory !== void 0) {
160
+ return createUsageError(
161
+ `gestament init: unexpected argument: ${argument}`
162
+ );
163
+ }
164
+ directory = argument;
165
+ index += 1;
166
+ }
167
+ return {
168
+ directory,
169
+ force,
170
+ name
171
+ };
172
+ };
173
+ const createRelativePathList = (cwd, paths) => paths.map((path) => {
174
+ const relativePath = node_path.relative(cwd, path);
175
+ return relativePath.length === 0 ? "." : relativePath;
176
+ });
177
+ const collectCollisions = async (targetDirectory, files) => {
178
+ const collisions = [];
179
+ for (const file of files) {
180
+ const filePath = node_path.join(targetDirectory, file.path);
181
+ if (await statIfExists(filePath) !== void 0) {
182
+ collisions.push(filePath);
183
+ }
184
+ }
185
+ const testsPath = node_path.join(targetDirectory, "tests");
186
+ const testsStat = await statIfExists(testsPath);
187
+ if (testsStat !== void 0 && !testsStat.isDirectory()) {
188
+ collisions.push(testsPath);
189
+ }
190
+ return collisions;
191
+ };
192
+ const writeScaffold = async (targetDirectory, files) => {
193
+ await promises.mkdir(targetDirectory, { recursive: true });
194
+ await promises.mkdir(node_path.join(targetDirectory, "tests"), { recursive: true });
195
+ for (const file of files) {
196
+ await promises.writeFile(node_path.join(targetDirectory, file.path), file.content);
197
+ }
198
+ };
199
+ const runInitCommand = async (args, cwd) => {
200
+ const parsed = parseInitOptions(args);
201
+ if ("exitCode" in parsed) {
202
+ return parsed;
203
+ }
204
+ if (parsed.name !== void 0 && !isValidPackageName(parsed.name)) {
205
+ return createUsageError(
206
+ `gestament init: invalid package name: ${parsed.name}`
207
+ );
208
+ }
209
+ const directoryArgument = parsed.directory ?? ".";
210
+ const targetDirectory = node_path.resolve(cwd, directoryArgument);
211
+ const packageName = parsed.name ?? normalizePackageName(node_path.basename(targetDirectory));
212
+ const files = createScaffoldFiles(packageName);
213
+ await promises.mkdir(targetDirectory, { recursive: true });
214
+ if (!parsed.force) {
215
+ const collisions = await collectCollisions(targetDirectory, files);
216
+ if (collisions.length > 0) {
217
+ return {
218
+ exitCode: 2,
219
+ stderr: [
220
+ "gestament init: refusing to overwrite existing scaffold paths:",
221
+ ...createRelativePathList(cwd, collisions).map((path) => ` ${path}`),
222
+ 'Run "gestament init --force" to overwrite generated files.',
223
+ ""
224
+ ].join("\n"),
225
+ stdout: ""
226
+ };
227
+ }
228
+ }
229
+ await writeScaffold(targetDirectory, files);
230
+ return {
231
+ exitCode: 0,
232
+ stderr: "",
233
+ stdout: [
234
+ `Created a gestament test project in ${directoryArgument}.`,
235
+ "",
236
+ "Next steps:",
237
+ ` cd ${directoryArgument}`,
238
+ " npm install",
239
+ " npm test",
240
+ ""
241
+ ].join("\n")
242
+ };
243
+ };
244
+ const runGestamentCli = async (args, cwd) => {
245
+ const command = args[0];
246
+ if (command === void 0) {
247
+ return createUsageError("gestament: missing command.");
248
+ }
249
+ if (command === "--help" || command === "-h") {
250
+ return createHelpOutput();
251
+ }
252
+ if (command !== "init") {
253
+ return createUsageError(`gestament: unknown command: ${command}`);
254
+ }
255
+ return await runInitCommand(args.slice(1), cwd);
256
+ };
257
+ const isMainModule = () => {
258
+ const executablePath = process.argv[1];
259
+ if (executablePath === void 0) {
260
+ return false;
261
+ }
262
+ return node_fs.realpathSync(executablePath) === node_fs.realpathSync(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("gestament.cjs", document.baseURI).href));
263
+ };
264
+ const run = async () => {
265
+ const output = await runGestamentCli(process.argv.slice(2), process.cwd());
266
+ process.stdout.write(output.stdout);
267
+ process.stderr.write(output.stderr);
268
+ process.exitCode = output.exitCode;
269
+ };
270
+ if (isMainModule()) {
271
+ run().catch((error) => {
272
+ const message = error instanceof Error ? error.message : String(error);
273
+ process.stderr.write(`gestament: ${message}
274
+ `);
275
+ process.exitCode = 2;
276
+ });
277
+ }
278
+ exports.runGestamentCli = runGestamentCli;
279
+ //# sourceMappingURL=gestament.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gestament.cjs","sources":["../src/gestament.ts"],"sourcesContent":["#!/usr/bin/env node\n// gestament - TypeScript based test driver for GTK.\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/gestament\n\nimport { realpathSync } from 'node:fs';\nimport { mkdir, stat, writeFile } from 'node:fs/promises';\nimport { basename, join, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { version as packageVersion } from './generated/packageMetadata';\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/** Result returned by the gestament CLI runner. */\nexport interface GestamentCliOutput {\n /** Process exit code. */\n readonly exitCode: 0 | 2;\n\n /** Text to write to stderr. */\n readonly stderr: string;\n\n /** Text to write to stdout. */\n readonly stdout: string;\n}\n\ninterface InitOptions {\n readonly directory: string | undefined;\n readonly force: boolean;\n readonly name: string | undefined;\n}\n\ninterface ScaffoldFile {\n readonly content: string;\n readonly path: string;\n}\n\nconst fallbackPackageName = 'gestament-tests';\nconst packageNamePattern =\n /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/u;\n\nconst usageText = [\n 'Usage: gestament init [directory] [--name <package-name>] [--force]',\n ' gestament init --help',\n ' gestament --help',\n '',\n 'Creates a minimal Vitest project for gestament GTK tests.',\n '',\n].join('\\n');\n\nconst gitIgnoreExampleText = [\n 'node_modules/',\n 'test-results/',\n 'coverage/',\n '*.log',\n '',\n].join('\\n');\n\nconst tsconfigText = `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n lib: ['ES2020'],\n moduleResolution: 'Bundler',\n strict: true,\n skipLibCheck: true,\n noEmit: true,\n },\n include: ['tests', 'vitest.config.ts'],\n },\n undefined,\n 2\n)}\\n`;\n\nconst vitestConfigText = [\n \"import { defineConfig } from 'vitest/config';\",\n '',\n 'export default defineConfig({',\n ' test: {',\n ' globals: true,',\n \" environment: 'node',\",\n \" include: ['tests/**/*.test.ts'],\",\n ' coverage: {',\n ' enabled: false,',\n ' },',\n ' },',\n '});',\n '',\n].join('\\n');\n\nconst isNotFoundError = (error: unknown): boolean =>\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n (error as { readonly code?: string }).code === 'ENOENT';\n\nconst statIfExists = async (\n path: string\n): Promise<\n | {\n readonly isDirectory: () => boolean;\n }\n | undefined\n> => {\n try {\n return await stat(path);\n } catch (error) {\n if (isNotFoundError(error)) {\n return undefined;\n }\n throw error;\n }\n};\n\nconst normalizePackageName = (value: string): string => {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/gu, '-')\n .replace(/^[._-]+|[._-]+$/gu, '');\n return normalized.length === 0 ? fallbackPackageName : normalized;\n};\n\nconst isValidPackageName = (value: string): boolean =>\n value.length <= 214 &&\n !value.startsWith('.') &&\n !value.startsWith('_') &&\n packageNamePattern.test(value);\n\nconst createPackageJsonText = (name: string): string =>\n `${JSON.stringify(\n {\n name,\n version: '0.0.1',\n private: true,\n scripts: {\n test: 'vitest run',\n },\n devDependencies: {\n '@types/node': '>=20.0.0',\n gestament: `^${packageVersion}`,\n typescript: '>=5.7.0',\n vitest: '>=3.2.0',\n },\n },\n undefined,\n 2\n )}\\n`;\n\nconst createScaffoldFiles = (name: string): readonly ScaffoldFile[] => [\n {\n content: createPackageJsonText(name),\n path: 'package.json',\n },\n {\n content: tsconfigText,\n path: 'tsconfig.json',\n },\n {\n content: vitestConfigText,\n path: 'vitest.config.ts',\n },\n {\n content: gitIgnoreExampleText,\n path: '.gitignore.gestament-example',\n },\n];\n\nconst createHelpOutput = (): GestamentCliOutput => ({\n exitCode: 0,\n stderr: '',\n stdout: usageText,\n});\n\nconst createUsageError = (message: string): GestamentCliOutput => ({\n exitCode: 2,\n stderr: `${message}\\nRun \"gestament --help\" for usage.\\n`,\n stdout: '',\n});\n\nconst parseInitOptions = (\n args: readonly string[]\n): InitOptions | GestamentCliOutput => {\n let directory: string | undefined;\n let force = false;\n let name: string | undefined;\n let index = 0;\n\n while (index < args.length) {\n const argument = args[index];\n if (argument === undefined) {\n break;\n }\n\n if (argument === '--help' || argument === '-h') {\n return createHelpOutput();\n }\n\n if (argument === '--force') {\n force = true;\n index += 1;\n continue;\n }\n\n if (argument === '--name') {\n const value = args[index + 1];\n if (value === undefined) {\n return createUsageError('gestament init: --name requires a value.');\n }\n name = value;\n index += 2;\n continue;\n }\n\n if (argument.startsWith('--name=')) {\n name = argument.slice('--name='.length);\n index += 1;\n continue;\n }\n\n if (argument.startsWith('-')) {\n return createUsageError(`gestament init: unknown option: ${argument}`);\n }\n\n if (directory !== undefined) {\n return createUsageError(\n `gestament init: unexpected argument: ${argument}`\n );\n }\n\n directory = argument;\n index += 1;\n }\n\n return {\n directory,\n force,\n name,\n };\n};\n\nconst createRelativePathList = (\n cwd: string,\n paths: readonly string[]\n): readonly string[] =>\n paths.map((path) => {\n const relativePath = relative(cwd, path);\n return relativePath.length === 0 ? '.' : relativePath;\n });\n\nconst collectCollisions = async (\n targetDirectory: string,\n files: readonly ScaffoldFile[]\n): Promise<readonly string[]> => {\n const collisions: string[] = [];\n\n for (const file of files) {\n const filePath = join(targetDirectory, file.path);\n if ((await statIfExists(filePath)) !== undefined) {\n collisions.push(filePath);\n }\n }\n\n const testsPath = join(targetDirectory, 'tests');\n const testsStat = await statIfExists(testsPath);\n if (testsStat !== undefined && !testsStat.isDirectory()) {\n collisions.push(testsPath);\n }\n\n return collisions;\n};\n\nconst writeScaffold = async (\n targetDirectory: string,\n files: readonly ScaffoldFile[]\n): Promise<void> => {\n await mkdir(targetDirectory, { recursive: true });\n await mkdir(join(targetDirectory, 'tests'), { recursive: true });\n\n for (const file of files) {\n await writeFile(join(targetDirectory, file.path), file.content);\n }\n};\n\nconst runInitCommand = async (\n args: readonly string[],\n cwd: string\n): Promise<GestamentCliOutput> => {\n const parsed = parseInitOptions(args);\n if ('exitCode' in parsed) {\n return parsed;\n }\n\n if (parsed.name !== undefined && !isValidPackageName(parsed.name)) {\n return createUsageError(\n `gestament init: invalid package name: ${parsed.name}`\n );\n }\n\n const directoryArgument = parsed.directory ?? '.';\n const targetDirectory = resolve(cwd, directoryArgument);\n const packageName =\n parsed.name ?? normalizePackageName(basename(targetDirectory));\n const files = createScaffoldFiles(packageName);\n\n await mkdir(targetDirectory, { recursive: true });\n\n if (!parsed.force) {\n const collisions = await collectCollisions(targetDirectory, files);\n if (collisions.length > 0) {\n return {\n exitCode: 2,\n stderr: [\n 'gestament init: refusing to overwrite existing scaffold paths:',\n ...createRelativePathList(cwd, collisions).map((path) => ` ${path}`),\n 'Run \"gestament init --force\" to overwrite generated files.',\n '',\n ].join('\\n'),\n stdout: '',\n };\n }\n }\n\n await writeScaffold(targetDirectory, files);\n\n return {\n exitCode: 0,\n stderr: '',\n stdout: [\n `Created a gestament test project in ${directoryArgument}.`,\n '',\n 'Next steps:',\n ` cd ${directoryArgument}`,\n ' npm install',\n ' npm test',\n '',\n ].join('\\n'),\n };\n};\n\n/**\n * Runs the gestament command line interface.\n *\n * @param args Command line arguments after the executable name.\n * @param cwd Current working directory used to resolve generated paths.\n * @returns CLI output and exit code.\n */\nexport const runGestamentCli = async (\n args: readonly string[],\n cwd: string\n): Promise<GestamentCliOutput> => {\n const command = args[0];\n if (command === undefined) {\n return createUsageError('gestament: missing command.');\n }\n\n if (command === '--help' || command === '-h') {\n return createHelpOutput();\n }\n\n if (command !== 'init') {\n return createUsageError(`gestament: unknown command: ${command}`);\n }\n\n return await runInitCommand(args.slice(1), cwd);\n};\n\nconst isMainModule = (): boolean => {\n const executablePath = process.argv[1];\n if (executablePath === undefined) {\n return false;\n }\n\n return (\n realpathSync(executablePath) ===\n realpathSync(fileURLToPath(import.meta.url))\n );\n};\n\nconst run = async (): Promise<void> => {\n const output = await runGestamentCli(process.argv.slice(2), process.cwd());\n process.stdout.write(output.stdout);\n process.stderr.write(output.stderr);\n process.exitCode = output.exitCode;\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\nif (isMainModule()) {\n run().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`gestament: ${message}\\n`);\n process.exitCode = 2;\n });\n}\n"],"names":["stat","packageVersion","relative","join","mkdir","writeFile","resolve","basename","realpathSync","fileURLToPath"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ /*!
3
+ * name: gestament
4
+ * version: 0.5.0
5
+ * description: TypeScript based test driver for GTK
6
+ * author: Kouji Matsui (@kekyo@mi.kekyo.net)
7
+ * license: MIT
8
+ * repository.url: https://github.com/kekyo/gestament.git
9
+ * git.commit.hash: 368fd995a6a10f20aea97cb0389ac3e12cfbedb3
10
+ */
11
+
12
+ /** Result returned by the gestament CLI runner. */
13
+ export interface GestamentCliOutput {
14
+ /** Process exit code. */
15
+ readonly exitCode: 0 | 2;
16
+ /** Text to write to stderr. */
17
+ readonly stderr: string;
18
+ /** Text to write to stdout. */
19
+ readonly stdout: string;
20
+ }
21
+ /**
22
+ * Runs the gestament command line interface.
23
+ *
24
+ * @param args Command line arguments after the executable name.
25
+ * @param cwd Current working directory used to resolve generated paths.
26
+ * @returns CLI output and exit code.
27
+ */
28
+ export declare const runGestamentCli: (args: readonly string[], cwd: string) => Promise<GestamentCliOutput>;
29
+ //# sourceMappingURL=gestament.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gestament.d.ts","sourceRoot":"","sources":["../src/gestament.ts"],"names":[],"mappings":";;;;;;;;;;AAeA,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IACjC,yBAAyB;IACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAEzB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AA6TD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,SAAS,MAAM,EAAE,EACvB,KAAK,MAAM,KACV,OAAO,CAAC,kBAAkB,CAe5B,CAAC"}
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { mkdir, writeFile, stat } from "node:fs/promises";
4
+ import { resolve, basename, join, relative } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { v as version } from "./packageMetadata-DjxyJCJm.js";
7
+ const fallbackPackageName = "gestament-tests";
8
+ const packageNamePattern = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
9
+ const usageText = [
10
+ "Usage: gestament init [directory] [--name <package-name>] [--force]",
11
+ " gestament init --help",
12
+ " gestament --help",
13
+ "",
14
+ "Creates a minimal Vitest project for gestament GTK tests.",
15
+ ""
16
+ ].join("\n");
17
+ const gitIgnoreExampleText = [
18
+ "node_modules/",
19
+ "test-results/",
20
+ "coverage/",
21
+ "*.log",
22
+ ""
23
+ ].join("\n");
24
+ const tsconfigText = `${JSON.stringify(
25
+ {
26
+ compilerOptions: {
27
+ target: "ES2020",
28
+ module: "ESNext",
29
+ lib: ["ES2020"],
30
+ moduleResolution: "Bundler",
31
+ strict: true,
32
+ skipLibCheck: true,
33
+ noEmit: true
34
+ },
35
+ include: ["tests", "vitest.config.ts"]
36
+ },
37
+ void 0,
38
+ 2
39
+ )}
40
+ `;
41
+ const vitestConfigText = [
42
+ "import { defineConfig } from 'vitest/config';",
43
+ "",
44
+ "export default defineConfig({",
45
+ " test: {",
46
+ " globals: true,",
47
+ " environment: 'node',",
48
+ " include: ['tests/**/*.test.ts'],",
49
+ " coverage: {",
50
+ " enabled: false,",
51
+ " },",
52
+ " },",
53
+ "});",
54
+ ""
55
+ ].join("\n");
56
+ const isNotFoundError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
57
+ const statIfExists = async (path) => {
58
+ try {
59
+ return await stat(path);
60
+ } catch (error) {
61
+ if (isNotFoundError(error)) {
62
+ return void 0;
63
+ }
64
+ throw error;
65
+ }
66
+ };
67
+ const normalizePackageName = (value) => {
68
+ const normalized = value.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu, "-").replace(/^[._-]+|[._-]+$/gu, "");
69
+ return normalized.length === 0 ? fallbackPackageName : normalized;
70
+ };
71
+ const isValidPackageName = (value) => value.length <= 214 && !value.startsWith(".") && !value.startsWith("_") && packageNamePattern.test(value);
72
+ const createPackageJsonText = (name) => `${JSON.stringify(
73
+ {
74
+ name,
75
+ version: "0.0.1",
76
+ private: true,
77
+ scripts: {
78
+ test: "vitest run"
79
+ },
80
+ devDependencies: {
81
+ "@types/node": ">=20.0.0",
82
+ gestament: `^${version}`,
83
+ typescript: ">=5.7.0",
84
+ vitest: ">=3.2.0"
85
+ }
86
+ },
87
+ void 0,
88
+ 2
89
+ )}
90
+ `;
91
+ const createScaffoldFiles = (name) => [
92
+ {
93
+ content: createPackageJsonText(name),
94
+ path: "package.json"
95
+ },
96
+ {
97
+ content: tsconfigText,
98
+ path: "tsconfig.json"
99
+ },
100
+ {
101
+ content: vitestConfigText,
102
+ path: "vitest.config.ts"
103
+ },
104
+ {
105
+ content: gitIgnoreExampleText,
106
+ path: ".gitignore.gestament-example"
107
+ }
108
+ ];
109
+ const createHelpOutput = () => ({
110
+ exitCode: 0,
111
+ stderr: "",
112
+ stdout: usageText
113
+ });
114
+ const createUsageError = (message) => ({
115
+ exitCode: 2,
116
+ stderr: `${message}
117
+ Run "gestament --help" for usage.
118
+ `,
119
+ stdout: ""
120
+ });
121
+ const parseInitOptions = (args) => {
122
+ let directory;
123
+ let force = false;
124
+ let name;
125
+ let index = 0;
126
+ while (index < args.length) {
127
+ const argument = args[index];
128
+ if (argument === void 0) {
129
+ break;
130
+ }
131
+ if (argument === "--help" || argument === "-h") {
132
+ return createHelpOutput();
133
+ }
134
+ if (argument === "--force") {
135
+ force = true;
136
+ index += 1;
137
+ continue;
138
+ }
139
+ if (argument === "--name") {
140
+ const value = args[index + 1];
141
+ if (value === void 0) {
142
+ return createUsageError("gestament init: --name requires a value.");
143
+ }
144
+ name = value;
145
+ index += 2;
146
+ continue;
147
+ }
148
+ if (argument.startsWith("--name=")) {
149
+ name = argument.slice("--name=".length);
150
+ index += 1;
151
+ continue;
152
+ }
153
+ if (argument.startsWith("-")) {
154
+ return createUsageError(`gestament init: unknown option: ${argument}`);
155
+ }
156
+ if (directory !== void 0) {
157
+ return createUsageError(
158
+ `gestament init: unexpected argument: ${argument}`
159
+ );
160
+ }
161
+ directory = argument;
162
+ index += 1;
163
+ }
164
+ return {
165
+ directory,
166
+ force,
167
+ name
168
+ };
169
+ };
170
+ const createRelativePathList = (cwd, paths) => paths.map((path) => {
171
+ const relativePath = relative(cwd, path);
172
+ return relativePath.length === 0 ? "." : relativePath;
173
+ });
174
+ const collectCollisions = async (targetDirectory, files) => {
175
+ const collisions = [];
176
+ for (const file of files) {
177
+ const filePath = join(targetDirectory, file.path);
178
+ if (await statIfExists(filePath) !== void 0) {
179
+ collisions.push(filePath);
180
+ }
181
+ }
182
+ const testsPath = join(targetDirectory, "tests");
183
+ const testsStat = await statIfExists(testsPath);
184
+ if (testsStat !== void 0 && !testsStat.isDirectory()) {
185
+ collisions.push(testsPath);
186
+ }
187
+ return collisions;
188
+ };
189
+ const writeScaffold = async (targetDirectory, files) => {
190
+ await mkdir(targetDirectory, { recursive: true });
191
+ await mkdir(join(targetDirectory, "tests"), { recursive: true });
192
+ for (const file of files) {
193
+ await writeFile(join(targetDirectory, file.path), file.content);
194
+ }
195
+ };
196
+ const runInitCommand = async (args, cwd) => {
197
+ const parsed = parseInitOptions(args);
198
+ if ("exitCode" in parsed) {
199
+ return parsed;
200
+ }
201
+ if (parsed.name !== void 0 && !isValidPackageName(parsed.name)) {
202
+ return createUsageError(
203
+ `gestament init: invalid package name: ${parsed.name}`
204
+ );
205
+ }
206
+ const directoryArgument = parsed.directory ?? ".";
207
+ const targetDirectory = resolve(cwd, directoryArgument);
208
+ const packageName = parsed.name ?? normalizePackageName(basename(targetDirectory));
209
+ const files = createScaffoldFiles(packageName);
210
+ await mkdir(targetDirectory, { recursive: true });
211
+ if (!parsed.force) {
212
+ const collisions = await collectCollisions(targetDirectory, files);
213
+ if (collisions.length > 0) {
214
+ return {
215
+ exitCode: 2,
216
+ stderr: [
217
+ "gestament init: refusing to overwrite existing scaffold paths:",
218
+ ...createRelativePathList(cwd, collisions).map((path) => ` ${path}`),
219
+ 'Run "gestament init --force" to overwrite generated files.',
220
+ ""
221
+ ].join("\n"),
222
+ stdout: ""
223
+ };
224
+ }
225
+ }
226
+ await writeScaffold(targetDirectory, files);
227
+ return {
228
+ exitCode: 0,
229
+ stderr: "",
230
+ stdout: [
231
+ `Created a gestament test project in ${directoryArgument}.`,
232
+ "",
233
+ "Next steps:",
234
+ ` cd ${directoryArgument}`,
235
+ " npm install",
236
+ " npm test",
237
+ ""
238
+ ].join("\n")
239
+ };
240
+ };
241
+ const runGestamentCli = async (args, cwd) => {
242
+ const command = args[0];
243
+ if (command === void 0) {
244
+ return createUsageError("gestament: missing command.");
245
+ }
246
+ if (command === "--help" || command === "-h") {
247
+ return createHelpOutput();
248
+ }
249
+ if (command !== "init") {
250
+ return createUsageError(`gestament: unknown command: ${command}`);
251
+ }
252
+ return await runInitCommand(args.slice(1), cwd);
253
+ };
254
+ const isMainModule = () => {
255
+ const executablePath = process.argv[1];
256
+ if (executablePath === void 0) {
257
+ return false;
258
+ }
259
+ return realpathSync(executablePath) === realpathSync(fileURLToPath(import.meta.url));
260
+ };
261
+ const run = async () => {
262
+ const output = await runGestamentCli(process.argv.slice(2), process.cwd());
263
+ process.stdout.write(output.stdout);
264
+ process.stderr.write(output.stderr);
265
+ process.exitCode = output.exitCode;
266
+ };
267
+ if (isMainModule()) {
268
+ run().catch((error) => {
269
+ const message = error instanceof Error ? error.message : String(error);
270
+ process.stderr.write(`gestament: ${message}
271
+ `);
272
+ process.exitCode = 2;
273
+ });
274
+ }
275
+ export {
276
+ runGestamentCli
277
+ };
278
+ //# sourceMappingURL=gestament.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gestament.mjs","sources":["../src/gestament.ts"],"sourcesContent":["#!/usr/bin/env node\n// gestament - TypeScript based test driver for GTK.\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/gestament\n\nimport { realpathSync } from 'node:fs';\nimport { mkdir, stat, writeFile } from 'node:fs/promises';\nimport { basename, join, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { version as packageVersion } from './generated/packageMetadata';\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/** Result returned by the gestament CLI runner. */\nexport interface GestamentCliOutput {\n /** Process exit code. */\n readonly exitCode: 0 | 2;\n\n /** Text to write to stderr. */\n readonly stderr: string;\n\n /** Text to write to stdout. */\n readonly stdout: string;\n}\n\ninterface InitOptions {\n readonly directory: string | undefined;\n readonly force: boolean;\n readonly name: string | undefined;\n}\n\ninterface ScaffoldFile {\n readonly content: string;\n readonly path: string;\n}\n\nconst fallbackPackageName = 'gestament-tests';\nconst packageNamePattern =\n /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/u;\n\nconst usageText = [\n 'Usage: gestament init [directory] [--name <package-name>] [--force]',\n ' gestament init --help',\n ' gestament --help',\n '',\n 'Creates a minimal Vitest project for gestament GTK tests.',\n '',\n].join('\\n');\n\nconst gitIgnoreExampleText = [\n 'node_modules/',\n 'test-results/',\n 'coverage/',\n '*.log',\n '',\n].join('\\n');\n\nconst tsconfigText = `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n lib: ['ES2020'],\n moduleResolution: 'Bundler',\n strict: true,\n skipLibCheck: true,\n noEmit: true,\n },\n include: ['tests', 'vitest.config.ts'],\n },\n undefined,\n 2\n)}\\n`;\n\nconst vitestConfigText = [\n \"import { defineConfig } from 'vitest/config';\",\n '',\n 'export default defineConfig({',\n ' test: {',\n ' globals: true,',\n \" environment: 'node',\",\n \" include: ['tests/**/*.test.ts'],\",\n ' coverage: {',\n ' enabled: false,',\n ' },',\n ' },',\n '});',\n '',\n].join('\\n');\n\nconst isNotFoundError = (error: unknown): boolean =>\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n (error as { readonly code?: string }).code === 'ENOENT';\n\nconst statIfExists = async (\n path: string\n): Promise<\n | {\n readonly isDirectory: () => boolean;\n }\n | undefined\n> => {\n try {\n return await stat(path);\n } catch (error) {\n if (isNotFoundError(error)) {\n return undefined;\n }\n throw error;\n }\n};\n\nconst normalizePackageName = (value: string): string => {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/gu, '-')\n .replace(/^[._-]+|[._-]+$/gu, '');\n return normalized.length === 0 ? fallbackPackageName : normalized;\n};\n\nconst isValidPackageName = (value: string): boolean =>\n value.length <= 214 &&\n !value.startsWith('.') &&\n !value.startsWith('_') &&\n packageNamePattern.test(value);\n\nconst createPackageJsonText = (name: string): string =>\n `${JSON.stringify(\n {\n name,\n version: '0.0.1',\n private: true,\n scripts: {\n test: 'vitest run',\n },\n devDependencies: {\n '@types/node': '>=20.0.0',\n gestament: `^${packageVersion}`,\n typescript: '>=5.7.0',\n vitest: '>=3.2.0',\n },\n },\n undefined,\n 2\n )}\\n`;\n\nconst createScaffoldFiles = (name: string): readonly ScaffoldFile[] => [\n {\n content: createPackageJsonText(name),\n path: 'package.json',\n },\n {\n content: tsconfigText,\n path: 'tsconfig.json',\n },\n {\n content: vitestConfigText,\n path: 'vitest.config.ts',\n },\n {\n content: gitIgnoreExampleText,\n path: '.gitignore.gestament-example',\n },\n];\n\nconst createHelpOutput = (): GestamentCliOutput => ({\n exitCode: 0,\n stderr: '',\n stdout: usageText,\n});\n\nconst createUsageError = (message: string): GestamentCliOutput => ({\n exitCode: 2,\n stderr: `${message}\\nRun \"gestament --help\" for usage.\\n`,\n stdout: '',\n});\n\nconst parseInitOptions = (\n args: readonly string[]\n): InitOptions | GestamentCliOutput => {\n let directory: string | undefined;\n let force = false;\n let name: string | undefined;\n let index = 0;\n\n while (index < args.length) {\n const argument = args[index];\n if (argument === undefined) {\n break;\n }\n\n if (argument === '--help' || argument === '-h') {\n return createHelpOutput();\n }\n\n if (argument === '--force') {\n force = true;\n index += 1;\n continue;\n }\n\n if (argument === '--name') {\n const value = args[index + 1];\n if (value === undefined) {\n return createUsageError('gestament init: --name requires a value.');\n }\n name = value;\n index += 2;\n continue;\n }\n\n if (argument.startsWith('--name=')) {\n name = argument.slice('--name='.length);\n index += 1;\n continue;\n }\n\n if (argument.startsWith('-')) {\n return createUsageError(`gestament init: unknown option: ${argument}`);\n }\n\n if (directory !== undefined) {\n return createUsageError(\n `gestament init: unexpected argument: ${argument}`\n );\n }\n\n directory = argument;\n index += 1;\n }\n\n return {\n directory,\n force,\n name,\n };\n};\n\nconst createRelativePathList = (\n cwd: string,\n paths: readonly string[]\n): readonly string[] =>\n paths.map((path) => {\n const relativePath = relative(cwd, path);\n return relativePath.length === 0 ? '.' : relativePath;\n });\n\nconst collectCollisions = async (\n targetDirectory: string,\n files: readonly ScaffoldFile[]\n): Promise<readonly string[]> => {\n const collisions: string[] = [];\n\n for (const file of files) {\n const filePath = join(targetDirectory, file.path);\n if ((await statIfExists(filePath)) !== undefined) {\n collisions.push(filePath);\n }\n }\n\n const testsPath = join(targetDirectory, 'tests');\n const testsStat = await statIfExists(testsPath);\n if (testsStat !== undefined && !testsStat.isDirectory()) {\n collisions.push(testsPath);\n }\n\n return collisions;\n};\n\nconst writeScaffold = async (\n targetDirectory: string,\n files: readonly ScaffoldFile[]\n): Promise<void> => {\n await mkdir(targetDirectory, { recursive: true });\n await mkdir(join(targetDirectory, 'tests'), { recursive: true });\n\n for (const file of files) {\n await writeFile(join(targetDirectory, file.path), file.content);\n }\n};\n\nconst runInitCommand = async (\n args: readonly string[],\n cwd: string\n): Promise<GestamentCliOutput> => {\n const parsed = parseInitOptions(args);\n if ('exitCode' in parsed) {\n return parsed;\n }\n\n if (parsed.name !== undefined && !isValidPackageName(parsed.name)) {\n return createUsageError(\n `gestament init: invalid package name: ${parsed.name}`\n );\n }\n\n const directoryArgument = parsed.directory ?? '.';\n const targetDirectory = resolve(cwd, directoryArgument);\n const packageName =\n parsed.name ?? normalizePackageName(basename(targetDirectory));\n const files = createScaffoldFiles(packageName);\n\n await mkdir(targetDirectory, { recursive: true });\n\n if (!parsed.force) {\n const collisions = await collectCollisions(targetDirectory, files);\n if (collisions.length > 0) {\n return {\n exitCode: 2,\n stderr: [\n 'gestament init: refusing to overwrite existing scaffold paths:',\n ...createRelativePathList(cwd, collisions).map((path) => ` ${path}`),\n 'Run \"gestament init --force\" to overwrite generated files.',\n '',\n ].join('\\n'),\n stdout: '',\n };\n }\n }\n\n await writeScaffold(targetDirectory, files);\n\n return {\n exitCode: 0,\n stderr: '',\n stdout: [\n `Created a gestament test project in ${directoryArgument}.`,\n '',\n 'Next steps:',\n ` cd ${directoryArgument}`,\n ' npm install',\n ' npm test',\n '',\n ].join('\\n'),\n };\n};\n\n/**\n * Runs the gestament command line interface.\n *\n * @param args Command line arguments after the executable name.\n * @param cwd Current working directory used to resolve generated paths.\n * @returns CLI output and exit code.\n */\nexport const runGestamentCli = async (\n args: readonly string[],\n cwd: string\n): Promise<GestamentCliOutput> => {\n const command = args[0];\n if (command === undefined) {\n return createUsageError('gestament: missing command.');\n }\n\n if (command === '--help' || command === '-h') {\n return createHelpOutput();\n }\n\n if (command !== 'init') {\n return createUsageError(`gestament: unknown command: ${command}`);\n }\n\n return await runInitCommand(args.slice(1), cwd);\n};\n\nconst isMainModule = (): boolean => {\n const executablePath = process.argv[1];\n if (executablePath === undefined) {\n return false;\n }\n\n return (\n realpathSync(executablePath) ===\n realpathSync(fileURLToPath(import.meta.url))\n );\n};\n\nconst run = async (): Promise<void> => {\n const output = await runGestamentCli(process.argv.slice(2), process.cwd());\n process.stdout.write(output.stdout);\n process.stderr.write(output.stderr);\n process.exitCode = output.exitCode;\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\nif (isMainModule()) {\n run().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`gestament: ${message}\\n`);\n process.exitCode = 2;\n });\n}\n"],"names":["packageVersion"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const launchGtkApp = require("./launchGtkApp-BfELuV-H.cjs");
3
+ const launchGtkApp = require("./launchGtkApp-CzYcrc9f.cjs");
4
4
  exports.createGtkAppEnvironment = launchGtkApp.createGtkAppEnvironment;
5
5
  exports.createGtkAppLauncher = launchGtkApp.createGtkAppLauncher;
6
6
  exports.launchGtkApp = launchGtkApp.launchGtkApp;