@smoothbricks/cli 0.10.2 → 0.10.4

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 (133) hide show
  1. package/README.md +31 -23
  2. package/dist/bun/preload.d.ts +13 -0
  3. package/dist/bun/preload.d.ts.map +1 -0
  4. package/dist/bun/preload.js +12 -0
  5. package/dist/cli.js +36 -4
  6. package/dist/generate/index.d.ts.map +1 -1
  7. package/dist/generate/index.js +0 -6
  8. package/dist/github-ci/index.d.ts +17 -2
  9. package/dist/github-ci/index.d.ts.map +1 -1
  10. package/dist/github-ci/index.js +192 -26
  11. package/dist/github-ci/outputs.d.ts +22 -0
  12. package/dist/github-ci/outputs.d.ts.map +1 -0
  13. package/dist/github-ci/outputs.js +648 -0
  14. package/dist/lib/cli-package.js +2 -2
  15. package/dist/lib/json.d.ts +118 -11
  16. package/dist/lib/json.d.ts.map +1 -1
  17. package/dist/lib/json.js +317 -29
  18. package/dist/lib/workspace.d.ts +7 -14
  19. package/dist/lib/workspace.d.ts.map +1 -1
  20. package/dist/lib/workspace.js +76 -82
  21. package/dist/monorepo/ci-workflow.d.ts +2 -0
  22. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  23. package/dist/monorepo/ci-workflow.js +28 -2
  24. package/dist/monorepo/git-config.js +2 -2
  25. package/dist/monorepo/index.d.ts +3 -1
  26. package/dist/monorepo/index.d.ts.map +1 -1
  27. package/dist/monorepo/index.js +6 -2
  28. package/dist/monorepo/lockfile.d.ts +13 -1
  29. package/dist/monorepo/lockfile.d.ts.map +1 -1
  30. package/dist/monorepo/lockfile.js +33 -21
  31. package/dist/monorepo/managed-files.d.ts +12 -0
  32. package/dist/monorepo/managed-files.d.ts.map +1 -1
  33. package/dist/monorepo/managed-files.js +86 -28
  34. package/dist/monorepo/package-policy.d.ts.map +1 -1
  35. package/dist/monorepo/package-policy.js +78 -45
  36. package/dist/monorepo/packed-manifest.d.ts +5 -2
  37. package/dist/monorepo/packed-manifest.d.ts.map +1 -1
  38. package/dist/monorepo/packed-manifest.js +16 -47
  39. package/dist/monorepo/packed-package.d.ts.map +1 -1
  40. package/dist/monorepo/packed-package.js +28 -16
  41. package/dist/monorepo/packs/index.d.ts +3 -0
  42. package/dist/monorepo/packs/index.d.ts.map +1 -1
  43. package/dist/monorepo/packs/index.js +18 -6
  44. package/dist/monorepo/publish-workflow.d.ts +1 -0
  45. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  46. package/dist/monorepo/publish-workflow.js +242 -3
  47. package/dist/monorepo/runtime.d.ts +15 -0
  48. package/dist/monorepo/runtime.d.ts.map +1 -1
  49. package/dist/monorepo/runtime.js +66 -12
  50. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  51. package/dist/monorepo/tool-validation.js +32 -23
  52. package/dist/monorepo/wrangler.d.ts.map +1 -1
  53. package/dist/monorepo/wrangler.js +13 -13
  54. package/dist/nx/index.d.ts +12 -4
  55. package/dist/nx/index.d.ts.map +1 -1
  56. package/dist/nx/index.js +86 -19
  57. package/dist/pr/index.d.ts.map +1 -1
  58. package/dist/pr/index.js +28 -32
  59. package/dist/release/candidates.d.ts +3 -2
  60. package/dist/release/candidates.d.ts.map +1 -1
  61. package/dist/release/candidates.js +4 -5
  62. package/dist/release/github-release.d.ts +3 -0
  63. package/dist/release/github-release.d.ts.map +1 -1
  64. package/dist/release/github-release.js +11 -0
  65. package/dist/release/index.d.ts +20 -1
  66. package/dist/release/index.d.ts.map +1 -1
  67. package/dist/release/index.js +221 -89
  68. package/dist/release/orchestration.d.ts +8 -1
  69. package/dist/release/orchestration.d.ts.map +1 -1
  70. package/dist/release/orchestration.js +38 -1
  71. package/dist/wrangler/prepare-env.d.ts +0 -1
  72. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  73. package/dist/wrangler/prepare-env.js +100 -51
  74. package/dist/wrangler/scaffold.d.ts.map +1 -1
  75. package/dist/wrangler/scaffold.js +12 -12
  76. package/managed/raw/git-format-staged.yml +19 -1
  77. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +6 -0
  78. package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
  79. package/managed/raw/tooling/direnv/setup-environment.ts +187 -19
  80. package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
  81. package/managed/templates/github/actions/cache-nix-devenv/action.yml +12 -10
  82. package/managed/templates/github/actions/cache-node-modules/action.yml +6 -2
  83. package/managed/templates/github/actions/cache-nx/action.yml +2 -2
  84. package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
  85. package/managed/templates/github/actions/save-nix-devenv/action.yml +11 -3
  86. package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
  87. package/managed/templates/github/workflows/managed-files.yml +80 -0
  88. package/package.json +18 -4
  89. package/src/bun/preload.ts +12 -0
  90. package/src/cli.ts +49 -11
  91. package/src/generate/index.ts +0 -6
  92. package/src/github-ci/index.test.ts +486 -0
  93. package/src/github-ci/index.ts +220 -30
  94. package/src/github-ci/outputs.ts +505 -0
  95. package/src/lib/cli-package.ts +2 -2
  96. package/src/lib/json.ts +291 -32
  97. package/src/lib/workspace.ts +88 -100
  98. package/src/monorepo/__tests__/ci-workflow.test.ts +14 -3
  99. package/src/monorepo/__tests__/publish-workflow.test.ts +222 -1
  100. package/src/monorepo/ci-workflow.ts +28 -2
  101. package/src/monorepo/git-config.ts +2 -2
  102. package/src/monorepo/index.ts +6 -2
  103. package/src/monorepo/lockfile.test.ts +35 -36
  104. package/src/monorepo/lockfile.ts +48 -24
  105. package/src/monorepo/managed-files.test.ts +63 -0
  106. package/src/monorepo/managed-files.ts +94 -34
  107. package/src/monorepo/package-policy.test.ts +70 -51
  108. package/src/monorepo/package-policy.ts +104 -59
  109. package/src/monorepo/packed-manifest.ts +18 -52
  110. package/src/monorepo/packed-package.ts +43 -22
  111. package/src/monorepo/packs/index.test.ts +18 -1
  112. package/src/monorepo/packs/index.ts +20 -7
  113. package/src/monorepo/publish-workflow.ts +482 -3
  114. package/src/monorepo/runtime.test.ts +42 -3
  115. package/src/monorepo/runtime.ts +90 -12
  116. package/src/monorepo/tool-validation.ts +35 -25
  117. package/src/monorepo/wrangler.test.ts +11 -15
  118. package/src/monorepo/wrangler.ts +15 -15
  119. package/src/nx/index.test.ts +43 -0
  120. package/src/nx/index.ts +110 -23
  121. package/src/pr/index.ts +42 -36
  122. package/src/release/__tests__/candidates.test.ts +5 -4
  123. package/src/release/__tests__/fixture-repo.test.ts +18 -16
  124. package/src/release/__tests__/github-release.test.ts +11 -0
  125. package/src/release/__tests__/orchestration.test.ts +57 -2
  126. package/src/release/__tests__/trust-publisher.test.ts +98 -2
  127. package/src/release/candidates.ts +10 -17
  128. package/src/release/github-release.ts +12 -0
  129. package/src/release/index.ts +321 -112
  130. package/src/release/orchestration.ts +55 -3
  131. package/src/wrangler/prepare-env.ts +75 -54
  132. package/src/wrangler/scaffold.test.ts +9 -12
  133. package/src/wrangler/scaffold.ts +13 -13
package/src/lib/json.ts CHANGED
@@ -1,29 +1,232 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { hasOwn, hasOwnString, isRecord } from '@smoothbricks/validation';
2
+ import typia from 'typia';
3
3
 
4
- export { hasOwn, hasOwnString, isRecord };
4
+ /** String-keyed dependency / script / engine maps. */
5
+ export type StringMap = Record<string, string>;
5
6
 
6
- export function stringProperty(record: Record<string, unknown>, key: string): string | null {
7
- const value = record[key];
8
- return typeof value === 'string' && value.length > 0 ? value : null;
7
+ export interface PackageRepository {
8
+ type?: string;
9
+ url?: string;
10
+ directory?: string;
9
11
  }
10
12
 
11
- export function recordProperty(record: Record<string, unknown>, key: string): Record<string, unknown> | null {
12
- const value = record[key];
13
- return isRecord(value) ? value : null;
13
+ export interface PackageNxConfig {
14
+ name?: string;
15
+ tags?: string[];
16
+ includedScripts?: string[];
17
+ targets?: Record<string, NxTargetConfig>;
14
18
  }
15
19
 
16
- export function getOrCreateRecord(record: Record<string, unknown>, key: string): Record<string, unknown> {
17
- const value = record[key];
18
- if (isRecord(value)) {
19
- return value;
20
+ export interface PackagePublishConfig {
21
+ access?: string;
22
+ }
23
+
24
+ export interface PackageSmooGithub {
25
+ pushBranches?: string[];
26
+ }
27
+
28
+ export interface PackageSmooConfig {
29
+ github?: PackageSmooGithub;
30
+ }
31
+
32
+ export interface PackageWorkspacesObject {
33
+ packages?: string[];
34
+ }
35
+
36
+ /**
37
+ * package.json shape used by smoo. Optional fields stay optional so partial
38
+ * manifests parse; mutation helpers create nested objects on demand.
39
+ */
40
+ export interface PackageJson {
41
+ name?: string;
42
+ version?: string;
43
+ private?: boolean;
44
+ license?: string;
45
+ types?: string;
46
+ packageManager?: string;
47
+ files?: string[];
48
+ bin?: string | StringMap;
49
+ exports?: PackageExports;
50
+ workspaces?: string[] | PackageWorkspacesObject;
51
+ dependencies?: StringMap;
52
+ devDependencies?: StringMap;
53
+ peerDependencies?: StringMap;
54
+ optionalDependencies?: StringMap;
55
+ engines?: StringMap;
56
+ scripts?: StringMap;
57
+ publishConfig?: PackagePublishConfig;
58
+ repository?: string | PackageRepository;
59
+ nx?: PackageNxConfig;
60
+ smoo?: PackageSmooConfig;
61
+ }
62
+
63
+ /** Recursive package exports map (conditions nest arbitrarily). */
64
+ export type PackageExports = string | PackageExportMap | null | undefined;
65
+ export interface PackageExportMap {
66
+ [condition: string]: PackageExports;
67
+ }
68
+
69
+ export interface NxDependsOnObject {
70
+ target: string;
71
+ projects?: string | string[];
72
+ }
73
+
74
+ export type NxDependsOn = string | NxDependsOnObject;
75
+
76
+ /** Nx target options are executor-specific open bags. */
77
+ export type NxTargetOptions = Record<string, unknown>;
78
+
79
+ export type NxInput = string | Record<string, unknown>;
80
+
81
+ export interface NxTargetConfig {
82
+ executor?: string;
83
+ dependsOn?: NxDependsOn[];
84
+ outputs?: string[];
85
+ inputs?: NxInput[];
86
+ options?: NxTargetOptions;
87
+ configurations?: Record<string, NxTargetConfig>;
88
+ cache?: boolean;
89
+ command?: string;
90
+ parallelism?: boolean;
91
+ }
92
+
93
+ export interface NxProjectJson {
94
+ name?: string;
95
+ root?: string;
96
+ targets?: Record<string, NxTargetConfig>;
97
+ }
98
+
99
+ export interface NxJson {
100
+ namedInputs?: Record<string, Array<string | Record<string, unknown>> | string>;
101
+ }
102
+
103
+ /** Parse package.json text. Invalid JSON throws; wrong shape returns null. */
104
+ export const parsePackageJsonText = typia.json.createIsParse<PackageJson>();
105
+
106
+ /** Parse `nx show project --json` output. Invalid JSON throws; wrong shape returns null. */
107
+ export const parseNxProjectJsonText = typia.json.createIsParse<NxProjectJson>();
108
+
109
+ /** Parse nx.json text. Invalid JSON throws; wrong shape returns null. */
110
+ export const parseNxJsonText = typia.json.createIsParse<NxJson>();
111
+
112
+ /** Parse a JSON string array. Invalid JSON throws; non-arrays return null. */
113
+ export const parseStringArrayText = typia.json.createIsParse<string[]>();
114
+
115
+ const isPackageJsonValue = typia.createIs<PackageJson>();
116
+
117
+ export function readJsonObject(path: string): PackageJson | null {
118
+ if (!existsSync(path)) {
119
+ return null;
20
120
  }
21
- const next: Record<string, unknown> = {};
22
- record[key] = next;
121
+ try {
122
+ return parsePackageJsonText(readFileSync(path, 'utf8'));
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
128
+ export function requiredJsonObject(path: string): PackageJson {
129
+ const json = readJsonObject(path);
130
+ if (!json) {
131
+ throw new Error(`${path} not found or invalid`);
132
+ }
133
+ return json;
134
+ }
135
+
136
+ export function writeJsonObject(path: string, value: object): void {
137
+ writeFileSync(path, jsonObjectText(value));
138
+ }
139
+
140
+ export function jsonObjectText(value: object): string {
141
+ return `${JSON.stringify(value, null, 2)}\n`;
142
+ }
143
+
144
+ export function readJson(path: string): unknown {
145
+ if (!existsSync(path)) {
146
+ return null;
147
+ }
148
+ return JSON.parse(readFileSync(path, 'utf8'));
149
+ }
150
+
151
+ export function isPackageJson(value: unknown): value is PackageJson {
152
+ return isPackageJsonValue(value);
153
+ }
154
+
155
+ /** Ensure package.json.scripts exists. */
156
+ export function ensureScripts(pkg: PackageJson): StringMap {
157
+ if (isStringMap(pkg.scripts)) {
158
+ return pkg.scripts;
159
+ }
160
+ const next: StringMap = {};
161
+ pkg.scripts = next;
23
162
  return next;
24
163
  }
25
164
 
26
- export function setStringProperty(record: Record<string, unknown>, key: string, value: string): boolean {
165
+ /** Ensure package.json.dependencies (or other string-map dep field) exists. */
166
+ export function ensureDependencyMap(
167
+ pkg: PackageJson,
168
+ key: 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies',
169
+ ): StringMap {
170
+ const current = pkg[key];
171
+ if (isStringMap(current)) {
172
+ return current;
173
+ }
174
+ const next: StringMap = {};
175
+ pkg[key] = next;
176
+ return next;
177
+ }
178
+
179
+ /** Ensure package.json.engines exists. */
180
+ export function ensureEngines(pkg: PackageJson): StringMap {
181
+ if (isStringMap(pkg.engines)) {
182
+ return pkg.engines;
183
+ }
184
+ const next: StringMap = {};
185
+ pkg.engines = next;
186
+ return next;
187
+ }
188
+
189
+ /** Ensure package.json.nx exists. */
190
+ export function ensureNx(pkg: PackageJson): PackageNxConfig {
191
+ if (isPackageNxConfig(pkg.nx)) {
192
+ return pkg.nx;
193
+ }
194
+ const next: PackageNxConfig = {};
195
+ pkg.nx = next;
196
+ return next;
197
+ }
198
+
199
+ /** Ensure package.json.nx.targets exists. */
200
+ export function ensureNxTargets(nx: PackageNxConfig): Record<string, NxTargetConfig> {
201
+ if (isNxTargets(nx.targets)) {
202
+ return nx.targets;
203
+ }
204
+ const next: Record<string, NxTargetConfig> = {};
205
+ nx.targets = next;
206
+ return next;
207
+ }
208
+
209
+ /** Ensure package.json.publishConfig exists. */
210
+ export function ensurePublishConfig(pkg: PackageJson): PackagePublishConfig {
211
+ if (isPublishConfig(pkg.publishConfig)) {
212
+ return pkg.publishConfig;
213
+ }
214
+ const next: PackagePublishConfig = {};
215
+ pkg.publishConfig = next;
216
+ return next;
217
+ }
218
+
219
+ /** Ensure package.json.repository is an object (not a string URL). */
220
+ export function ensureRepositoryObject(pkg: PackageJson): PackageRepository {
221
+ if (isRepositoryObject(pkg.repository)) {
222
+ return pkg.repository;
223
+ }
224
+ const next: PackageRepository = {};
225
+ pkg.repository = next;
226
+ return next;
227
+ }
228
+
229
+ export function setStringProperty(record: StringMap, key: string, value: string): boolean {
27
230
  if (record[key] === value) {
28
231
  return false;
29
232
  }
@@ -31,7 +234,7 @@ export function setStringProperty(record: Record<string, unknown>, key: string,
31
234
  return true;
32
235
  }
33
236
 
34
- export function setMissingStringProperty(record: Record<string, unknown>, key: string, value: string): boolean {
237
+ export function setMissingStringProperty(record: StringMap, key: string, value: string): boolean {
35
238
  if (typeof record[key] === 'string') {
36
239
  return false;
37
240
  }
@@ -39,30 +242,86 @@ export function setMissingStringProperty(record: Record<string, unknown>, key: s
39
242
  return true;
40
243
  }
41
244
 
42
- export function requiredJsonObject(path: string): Record<string, unknown> {
43
- const json = readJsonObject(path);
44
- if (!json) {
45
- throw new Error(`${path} not found or invalid`);
245
+ export function setPackageStringField(
246
+ pkg: PackageJson,
247
+ key: 'name' | 'version' | 'license' | 'types' | 'packageManager',
248
+ value: string,
249
+ ): boolean {
250
+ if (pkg[key] === value) {
251
+ return false;
46
252
  }
47
- return json;
253
+ pkg[key] = value;
254
+ return true;
48
255
  }
49
256
 
50
- export function readJsonObject(path: string): Record<string, unknown> | null {
51
- const json = readJson(path);
52
- return isRecord(json) ? json : null;
257
+ export function setMissingPackageStringField(
258
+ pkg: PackageJson,
259
+ key: 'name' | 'version' | 'license' | 'types' | 'packageManager',
260
+ value: string,
261
+ ): boolean {
262
+ if (typeof pkg[key] === 'string') {
263
+ return false;
264
+ }
265
+ pkg[key] = value;
266
+ return true;
53
267
  }
54
268
 
55
- export function writeJsonObject(path: string, value: Record<string, unknown>): void {
56
- writeFileSync(path, jsonObjectText(value));
269
+ export function setNxName(nx: PackageNxConfig, value: string): boolean {
270
+ if (nx.name === value) {
271
+ return false;
272
+ }
273
+ nx.name = value;
274
+ return true;
57
275
  }
58
276
 
59
- export function jsonObjectText(value: Record<string, unknown>): string {
60
- return `${JSON.stringify(value, null, 2)}\n`;
277
+ export function setPublishAccess(publishConfig: PackagePublishConfig, value: string): boolean {
278
+ if (publishConfig.access === value) {
279
+ return false;
280
+ }
281
+ publishConfig.access = value;
282
+ return true;
61
283
  }
62
284
 
63
- export function readJson(path: string): unknown {
64
- if (!existsSync(path)) {
65
- return null;
285
+ export function setRepositoryField(
286
+ repository: PackageRepository,
287
+ key: 'type' | 'url' | 'directory',
288
+ value: string,
289
+ ): boolean {
290
+ if (repository[key] === value) {
291
+ return false;
66
292
  }
67
- return JSON.parse(readFileSync(path, 'utf8'));
293
+ repository[key] = value;
294
+ return true;
295
+ }
296
+
297
+ export function setMissingRepositoryField(
298
+ repository: PackageRepository,
299
+ key: 'type' | 'url' | 'directory',
300
+ value: string,
301
+ ): boolean {
302
+ if (typeof repository[key] === 'string') {
303
+ return false;
304
+ }
305
+ repository[key] = value;
306
+ return true;
307
+ }
308
+
309
+ function isStringMap(value: unknown): value is StringMap {
310
+ return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
311
+ }
312
+
313
+ function isPackageNxConfig(value: unknown): value is PackageNxConfig {
314
+ return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
315
+ }
316
+
317
+ function isNxTargets(value: unknown): value is Record<string, NxTargetConfig> {
318
+ return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
319
+ }
320
+
321
+ function isPublishConfig(value: unknown): value is PackagePublishConfig {
322
+ return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
323
+ }
324
+
325
+ function isRepositoryObject(value: unknown): value is PackageRepository {
326
+ return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
68
327
  }