@bensandee/tooling 0.14.0 → 0.14.1
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/CHANGELOG.md +10 -0
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +7 -7
- package/dist/docker-verify/index.d.mts +117 -0
- package/dist/index.d.mts +104 -0
- package/package.json +12 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @bensandee/tooling
|
|
2
2
|
|
|
3
|
+
## 0.14.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- caeebd8: Add d.ts declaration file output and types export conditions
|
|
8
|
+
- caeebd8: Bump tsdown from 0.21.0 to 0.21.2
|
|
9
|
+
- Updated dependencies [caeebd8]
|
|
10
|
+
- Updated dependencies [caeebd8]
|
|
11
|
+
- @bensandee/common@0.1.2
|
|
12
|
+
|
|
3
13
|
## 0.14.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/dist/bin.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/bin.mjs
CHANGED
|
@@ -595,8 +595,8 @@ function addReleaseDeps(deps, config) {
|
|
|
595
595
|
function getAddedDevDepNames(config) {
|
|
596
596
|
const deps = { ...ROOT_DEV_DEPS };
|
|
597
597
|
if (config.structure !== "monorepo") Object.assign(deps, PER_PACKAGE_DEV_DEPS);
|
|
598
|
-
deps["@bensandee/config"] = "0.8.
|
|
599
|
-
deps["@bensandee/tooling"] = "0.14.
|
|
598
|
+
deps["@bensandee/config"] = "0.8.1";
|
|
599
|
+
deps["@bensandee/tooling"] = "0.14.1";
|
|
600
600
|
if (config.formatter === "oxfmt") deps["oxfmt"] = "0.35.0";
|
|
601
601
|
if (config.formatter === "prettier") deps["prettier"] = "3.8.1";
|
|
602
602
|
addReleaseDeps(deps, config);
|
|
@@ -616,9 +616,9 @@ async function generatePackageJson(ctx) {
|
|
|
616
616
|
if (ctx.config.releaseStrategy !== "none" && ctx.config.releaseStrategy !== "changesets") allScripts["trigger-release"] = "pnpm exec tooling release:trigger";
|
|
617
617
|
const devDeps = { ...ROOT_DEV_DEPS };
|
|
618
618
|
if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
|
|
619
|
-
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.8.
|
|
620
|
-
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.14.
|
|
621
|
-
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.
|
|
619
|
+
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.8.1";
|
|
620
|
+
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.14.1";
|
|
621
|
+
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.2";
|
|
622
622
|
if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = "0.35.0";
|
|
623
623
|
if (ctx.config.formatter === "prettier") devDeps["prettier"] = "3.8.1";
|
|
624
624
|
addReleaseDeps(devDeps, ctx.config);
|
|
@@ -3690,7 +3690,7 @@ const runChecksCommand = defineCommand({
|
|
|
3690
3690
|
const main = defineCommand({
|
|
3691
3691
|
meta: {
|
|
3692
3692
|
name: "tooling",
|
|
3693
|
-
version: "0.14.
|
|
3693
|
+
version: "0.14.1",
|
|
3694
3694
|
description: "Bootstrap and maintain standardized TypeScript project tooling"
|
|
3695
3695
|
},
|
|
3696
3696
|
subCommands: {
|
|
@@ -3705,7 +3705,7 @@ const main = defineCommand({
|
|
|
3705
3705
|
"release:simple": releaseSimpleCommand
|
|
3706
3706
|
}
|
|
3707
3707
|
});
|
|
3708
|
-
console.log(`@bensandee/tooling v0.14.
|
|
3708
|
+
console.log(`@bensandee/tooling v0.14.1`);
|
|
3709
3709
|
runMain(main);
|
|
3710
3710
|
//#endregion
|
|
3711
3711
|
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/release/types.d.ts
|
|
4
|
+
/** Result of executing a shell command. */
|
|
5
|
+
interface ExecResult {
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
exitCode: number;
|
|
9
|
+
}
|
|
10
|
+
/** Options for executing a shell command. */
|
|
11
|
+
interface ExecOptions {
|
|
12
|
+
cwd?: string;
|
|
13
|
+
env?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/docker-verify/types.d.ts
|
|
17
|
+
/** Abstraction over side effects for testability. */
|
|
18
|
+
interface DockerVerifyExecutor {
|
|
19
|
+
/** Run a shell command and return the result (stdout/stderr captured). */
|
|
20
|
+
exec(command: string, options?: ExecOptions): ExecResult;
|
|
21
|
+
/** Run a shell command, streaming stdout/stderr to the console. */
|
|
22
|
+
execInherit(command: string, options?: ExecOptions): void;
|
|
23
|
+
/** Perform an HTTP request. */
|
|
24
|
+
fetch(url: string, init?: RequestInit): Promise<Response>;
|
|
25
|
+
/** Get current time in ms (mockable clock). */
|
|
26
|
+
now(): number;
|
|
27
|
+
/** Sleep for the given duration (mockable delay). */
|
|
28
|
+
sleep(ms: number): Promise<void>;
|
|
29
|
+
/** Register a process signal handler. Returns a dispose function. */
|
|
30
|
+
onSignal(signal: NodeJS.Signals, handler: () => void): () => void;
|
|
31
|
+
/** Log a message to the console. */
|
|
32
|
+
log(message: string): void;
|
|
33
|
+
/** Log an error to the console. */
|
|
34
|
+
logError(message: string): void;
|
|
35
|
+
}
|
|
36
|
+
/** A single HTTP health check definition. */
|
|
37
|
+
interface HttpHealthCheck {
|
|
38
|
+
/** Human-readable name for logging (e.g. "API", "Frontend"). */
|
|
39
|
+
name: string;
|
|
40
|
+
/** URL to fetch. */
|
|
41
|
+
url: string;
|
|
42
|
+
/** Validate the response. Return true if healthy. */
|
|
43
|
+
validate: (response: Response) => Promise<boolean>;
|
|
44
|
+
}
|
|
45
|
+
/** Docker compose configuration. */
|
|
46
|
+
interface ComposeConfig {
|
|
47
|
+
/** Working directory for docker compose commands. */
|
|
48
|
+
cwd: string;
|
|
49
|
+
/** Compose files to use (e.g. ["docker-compose.yaml", "docker-compose.verify.yaml"]). */
|
|
50
|
+
composeFiles: string[];
|
|
51
|
+
/** Optional env file for compose. */
|
|
52
|
+
envFile?: string;
|
|
53
|
+
/** Service names to monitor for container-level health. */
|
|
54
|
+
services: string[];
|
|
55
|
+
}
|
|
56
|
+
/** Full verification configuration. */
|
|
57
|
+
interface VerifyConfig {
|
|
58
|
+
/** Docker compose settings. */
|
|
59
|
+
compose: ComposeConfig;
|
|
60
|
+
/** Optional build command to run before starting compose (e.g. "pnpm image:build"). */
|
|
61
|
+
buildCommand?: string;
|
|
62
|
+
/** Working directory for the build command (defaults to compose.cwd). */
|
|
63
|
+
buildCwd?: string;
|
|
64
|
+
/** HTTP health checks to poll. All must pass for success. */
|
|
65
|
+
healthChecks: HttpHealthCheck[];
|
|
66
|
+
/** Maximum time to wait for all checks to pass, in ms. Default: 120000. */
|
|
67
|
+
timeoutMs?: number;
|
|
68
|
+
/** Interval between polling attempts, in ms. Default: 5000. */
|
|
69
|
+
pollIntervalMs?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Result of the verification run. */
|
|
72
|
+
type VerifyResult = {
|
|
73
|
+
success: true;
|
|
74
|
+
elapsedMs: number;
|
|
75
|
+
} | {
|
|
76
|
+
success: false;
|
|
77
|
+
reason: "timeout" | "unhealthy-container" | "error";
|
|
78
|
+
message: string;
|
|
79
|
+
elapsedMs: number;
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/docker-verify/executor.d.ts
|
|
83
|
+
/** Create an executor that runs real commands, fetches, and manages process signals. */
|
|
84
|
+
declare function createRealExecutor(): DockerVerifyExecutor;
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/docker-verify/verify.d.ts
|
|
87
|
+
/** Run the full Docker image verification lifecycle. */
|
|
88
|
+
declare function runVerification(executor: DockerVerifyExecutor, config: VerifyConfig): Promise<VerifyResult>;
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/docker-verify/compose.d.ts
|
|
91
|
+
/** Zod schema for a single container entry from `docker compose ps --format json`. */
|
|
92
|
+
declare const ContainerInfoSchema: z.ZodObject<{
|
|
93
|
+
Service: z.ZodString;
|
|
94
|
+
Health: z.ZodString;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
type ContainerInfo = z.infer<typeof ContainerInfoSchema>;
|
|
97
|
+
/** Build the `docker compose` base command string from config. */
|
|
98
|
+
declare function composeCommand(config: ComposeConfig): string;
|
|
99
|
+
/** Start the compose stack in detached mode. */
|
|
100
|
+
declare function composeUp(executor: DockerVerifyExecutor, config: ComposeConfig): void;
|
|
101
|
+
/** Tear down the compose stack, removing volumes and orphans. Swallows errors. */
|
|
102
|
+
declare function composeDown(executor: DockerVerifyExecutor, config: ComposeConfig): void;
|
|
103
|
+
/** Show logs for a specific service (or all services if not specified). Swallows errors. */
|
|
104
|
+
declare function composeLogs(executor: DockerVerifyExecutor, config: ComposeConfig, service?: string): void;
|
|
105
|
+
/**
|
|
106
|
+
* Query container status via `docker compose ps --format json`.
|
|
107
|
+
* Handles both JSON array and newline-delimited JSON (varies by docker compose version).
|
|
108
|
+
*/
|
|
109
|
+
declare function composePs(executor: DockerVerifyExecutor, config: ComposeConfig): ContainerInfo[];
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/docker-verify/health.d.ts
|
|
112
|
+
/** Look up the health status of a specific service from container info. */
|
|
113
|
+
declare function getContainerHealth(containers: ContainerInfo[], serviceName: string): string;
|
|
114
|
+
/** Run a single HTTP health check, returning true if the validator passes. */
|
|
115
|
+
declare function checkHttpHealth(executor: DockerVerifyExecutor, check: HttpHealthCheck): Promise<boolean>;
|
|
116
|
+
//#endregion
|
|
117
|
+
export { type ComposeConfig, type ContainerInfo, type DockerVerifyExecutor, type HttpHealthCheck, type VerifyConfig, type VerifyResult, checkHttpHealth, composeCommand, composeDown, composeLogs, composePs, composeUp, createRealExecutor, getContainerHealth, runVerification };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/json.d.ts
|
|
4
|
+
declare const PackageJsonSchema: z.ZodObject<{
|
|
5
|
+
name: z.ZodOptional<z.ZodString>;
|
|
6
|
+
version: z.ZodOptional<z.ZodString>;
|
|
7
|
+
private: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
type: z.ZodOptional<z.ZodString>;
|
|
9
|
+
scripts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
10
|
+
dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
11
|
+
devDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
12
|
+
bin: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
13
|
+
exports: z.ZodOptional<z.ZodUnknown>;
|
|
14
|
+
main: z.ZodOptional<z.ZodString>;
|
|
15
|
+
types: z.ZodOptional<z.ZodString>;
|
|
16
|
+
typings: z.ZodOptional<z.ZodString>;
|
|
17
|
+
engines: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
18
|
+
}, z.core.$loose>;
|
|
19
|
+
type PackageJson = z.infer<typeof PackageJsonSchema>;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/types.d.ts
|
|
22
|
+
type CiPlatform = "github" | "forgejo" | "none";
|
|
23
|
+
type ReleaseStrategy = "release-it" | "simple" | "changesets" | "none";
|
|
24
|
+
/** User's answers from the interactive prompt or CLI flags. */
|
|
25
|
+
interface ProjectConfig {
|
|
26
|
+
/** Project name (from package.json name or user input) */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Whether this is a new project or existing */
|
|
29
|
+
isNew: boolean;
|
|
30
|
+
/** Project structure */
|
|
31
|
+
structure: "single" | "monorepo";
|
|
32
|
+
/** Include @bensandee/eslint-plugin oxlint plugin */
|
|
33
|
+
useEslintPlugin: boolean;
|
|
34
|
+
/** Formatter choice */
|
|
35
|
+
formatter: "oxfmt" | "prettier";
|
|
36
|
+
/** Set up vitest with a starter test */
|
|
37
|
+
setupVitest: boolean;
|
|
38
|
+
/** CI platform choice */
|
|
39
|
+
ci: CiPlatform;
|
|
40
|
+
/** Set up Renovate for automated dependency updates */
|
|
41
|
+
setupRenovate: boolean;
|
|
42
|
+
/** Release management strategy */
|
|
43
|
+
releaseStrategy: ReleaseStrategy;
|
|
44
|
+
/** Project type determines tsconfig base configuration */
|
|
45
|
+
projectType: "default" | "node" | "react" | "library";
|
|
46
|
+
/** Auto-detect and configure tsconfig bases for monorepo packages */
|
|
47
|
+
detectPackageTypes: boolean;
|
|
48
|
+
/** Target directory (default: cwd) */
|
|
49
|
+
targetDir: string;
|
|
50
|
+
}
|
|
51
|
+
/** Result from a single generator: what file was written and how. */
|
|
52
|
+
interface GeneratorResult {
|
|
53
|
+
filePath: string;
|
|
54
|
+
action: "created" | "updated" | "skipped" | "archived";
|
|
55
|
+
/** Human-readable description of what changed */
|
|
56
|
+
description: string;
|
|
57
|
+
}
|
|
58
|
+
/** Context passed to each generator function. */
|
|
59
|
+
interface GeneratorContext {
|
|
60
|
+
config: ProjectConfig;
|
|
61
|
+
/** Absolute path to target directory */
|
|
62
|
+
targetDir: string;
|
|
63
|
+
/** Pre-parsed package.json from the target directory, or undefined if missing/invalid */
|
|
64
|
+
packageJson: PackageJson | undefined;
|
|
65
|
+
/** Check whether a file exists in the target directory */
|
|
66
|
+
exists: (relativePath: string) => boolean;
|
|
67
|
+
/** Read an existing file from the target directory, returns undefined if not found */
|
|
68
|
+
read: (relativePath: string) => string | undefined;
|
|
69
|
+
/** Write a file to the target directory (creating directories as needed) */
|
|
70
|
+
write: (relativePath: string, content: string) => void;
|
|
71
|
+
/** Remove a file from the target directory (no-op if not found) */
|
|
72
|
+
remove: (relativePath: string) => void;
|
|
73
|
+
/** Prompt user for conflict resolution on non-mergeable files */
|
|
74
|
+
confirmOverwrite: (relativePath: string) => Promise<"overwrite" | "skip">;
|
|
75
|
+
}
|
|
76
|
+
/** Generator function signature. */
|
|
77
|
+
type Generator = (ctx: GeneratorContext) => Promise<GeneratorResult>;
|
|
78
|
+
/** State detected from an existing project directory. */
|
|
79
|
+
interface DetectedProjectState {
|
|
80
|
+
hasPackageJson: boolean;
|
|
81
|
+
hasTsconfig: boolean;
|
|
82
|
+
hasOxlintConfig: boolean;
|
|
83
|
+
/** Legacy .oxlintrc.json found (should be migrated to oxlint.config.ts) */
|
|
84
|
+
hasLegacyOxlintJson: boolean;
|
|
85
|
+
hasGitignore: boolean;
|
|
86
|
+
hasVitestConfig: boolean;
|
|
87
|
+
hasTsdownConfig: boolean;
|
|
88
|
+
hasPnpmWorkspace: boolean;
|
|
89
|
+
hasKnipConfig: boolean;
|
|
90
|
+
hasRenovateConfig: boolean;
|
|
91
|
+
hasReleaseItConfig: boolean;
|
|
92
|
+
hasSimpleReleaseConfig: boolean;
|
|
93
|
+
hasChangesetsConfig: boolean;
|
|
94
|
+
/** Legacy tooling configs found */
|
|
95
|
+
legacyConfigs: LegacyConfig[];
|
|
96
|
+
}
|
|
97
|
+
declare const LEGACY_TOOLS: readonly ["eslint", "prettier", "jest", "webpack", "rollup"];
|
|
98
|
+
type LegacyTool = (typeof LEGACY_TOOLS)[number];
|
|
99
|
+
interface LegacyConfig {
|
|
100
|
+
tool: LegacyTool;
|
|
101
|
+
files: string[];
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { type DetectedProjectState, type Generator, type GeneratorContext, type GeneratorResult, type LegacyConfig, type ProjectConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bensandee/tooling",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tooling": "./dist/bin.mjs"
|
|
@@ -14,9 +14,15 @@
|
|
|
14
14
|
"#src/*.ts": "./src/*.ts"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
|
17
|
-
".":
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"default": "./dist/index.mjs"
|
|
20
|
+
},
|
|
18
21
|
"./bin": "./dist/bin.mjs",
|
|
19
|
-
"./docker-verify":
|
|
22
|
+
"./docker-verify": {
|
|
23
|
+
"types": "./dist/docker-verify/index.d.mts",
|
|
24
|
+
"default": "./dist/docker-verify/index.mjs"
|
|
25
|
+
},
|
|
20
26
|
"./package.json": "./package.json"
|
|
21
27
|
},
|
|
22
28
|
"publishConfig": {
|
|
@@ -29,14 +35,14 @@
|
|
|
29
35
|
"jsonc-parser": "^3.3.1",
|
|
30
36
|
"yaml": "^2.8.2",
|
|
31
37
|
"zod": "^4.3.6",
|
|
32
|
-
"@bensandee/common": "0.1.
|
|
38
|
+
"@bensandee/common": "0.1.2"
|
|
33
39
|
},
|
|
34
40
|
"devDependencies": {
|
|
35
41
|
"@types/node": "24.12.0",
|
|
36
|
-
"tsdown": "0.21.
|
|
42
|
+
"tsdown": "0.21.2",
|
|
37
43
|
"typescript": "5.9.3",
|
|
38
44
|
"vitest": "4.0.18",
|
|
39
|
-
"@bensandee/config": "0.8.
|
|
45
|
+
"@bensandee/config": "0.8.1"
|
|
40
46
|
},
|
|
41
47
|
"optionalDependencies": {
|
|
42
48
|
"@changesets/cli": "^2.29.4",
|