@dbx-tools/projen 0.9.32 → 0.9.37

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 (55) hide show
  1. package/README.md +71 -65
  2. package/index.ts +5 -8
  3. package/package.json +8 -7
  4. package/src/_task-command.ts +0 -75
  5. package/src/barrels.ts +15 -23
  6. package/src/bun-app.ts +5 -6
  7. package/src/clean.ts +41 -15
  8. package/src/codegen.ts +2 -3
  9. package/src/dbx-tools-config.ts +23 -64
  10. package/src/generated.ts +7 -1
  11. package/src/module-exports.ts +35 -3
  12. package/src/openapi.ts +34 -38
  13. package/src/packages.ts +3 -30
  14. package/src/pnpm-workspace.ts +21 -26
  15. package/src/project-js.ts +152 -365
  16. package/src/project-predicate.ts +4 -5
  17. package/src/project-py.ts +55 -144
  18. package/src/publish.ts +1 -1
  19. package/src/python-node-bindings.ts +140 -67
  20. package/src/python-node-bundle.ts +6 -42
  21. package/src/release-context.ts +4 -4
  22. package/src/release.ts +47 -85
  23. package/src/tags.ts +20 -18
  24. package/src/tsconfig.ts +9 -5
  25. package/src/vscode.ts +47 -58
  26. package/src/watch.ts +2 -8
  27. package/src/workspace-version.ts +1 -6
  28. package/tasks/barrels.ts +43 -38
  29. package/tasks/bump.ts +24 -20
  30. package/tasks/clean.ts +54 -50
  31. package/tasks/compile-workspace.ts +2 -117
  32. package/tasks/lib/compile-workspace.ts +119 -0
  33. package/tasks/lib/local-publish.ts +122 -0
  34. package/tasks/lib/publish-npm.ts +458 -0
  35. package/tasks/lib/publish-python.ts +195 -0
  36. package/tasks/lib/publish.ts +264 -0
  37. package/tasks/lib/python-node-bindings.ts +1262 -0
  38. package/tasks/{python-registry.ts → lib/python-registry.ts} +21 -30
  39. package/tasks/{python-release.ts → lib/python-release.ts} +1 -0
  40. package/tasks/lib/release-version.ts +66 -0
  41. package/tasks/lib/release.ts +212 -0
  42. package/tasks/local-publish.ts +4 -118
  43. package/tasks/openapi.ts +25 -21
  44. package/tasks/projenrc.ts +14 -12
  45. package/tasks/publish-npm.ts +3 -364
  46. package/tasks/publish-python.ts +3 -184
  47. package/tasks/publish.ts +3 -279
  48. package/tasks/python-node-bindings.ts +3 -1014
  49. package/tasks/release-version.ts +3 -62
  50. package/tasks/release.ts +3 -121
  51. package/tasks/sync.ts +71 -70
  52. package/tasks/version-check.ts +3 -10
  53. package/src/release-catalog.ts +0 -684
  54. package/tasks/databricks-cli-assets.ts +0 -129
  55. package/tasks/python-node-bindings-watch.ts +0 -47
@@ -1,6 +1,5 @@
1
1
  import { Component, type Project, type Task } from "projen";
2
- import { taskScript } from "./project-js.ts";
3
- import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
2
+ import { taskCommand } from "./project-js.ts";
4
3
 
5
4
  /** One function replaced only in a generated PythonMonkey bundle. */
6
5
  export interface PythonNodeFunctionOverride {
@@ -20,12 +19,8 @@ export interface PythonNodeBindingsOptions {
20
19
  readonly package: string;
21
20
  /** Optional portable package subpath to bind. Defaults to {@link package}. */
22
21
  readonly entrypoint?: string;
23
- /** Generated bindings own the package or live under `_generated`. Defaults to `submodule`. */
24
- readonly layout?: "package" | "submodule";
25
- /** Keep generated symbols out of the generated package `__init__`. Defaults to false. */
26
- readonly private?: boolean;
27
- /** Repository-relative directory containing Node built-in shims. */
28
- readonly shimRoot?: string;
22
+ /** Automatically generated root namespace modules to bind independently. */
23
+ readonly modules?: readonly string[];
29
24
  /** Functions replaced only while generating the Python runtime. */
30
25
  readonly functionOverrides?: readonly PythonNodeFunctionOverride[];
31
26
  }
@@ -38,55 +33,24 @@ export interface PythonNodeBundleOptions {
38
33
  readonly projectDirectory: string;
39
34
  /** Add the freshness check to the project's test task. Defaults to true. */
40
35
  readonly test?: boolean;
41
- /** Regenerate during the root workspace watch loop. Defaults to false. */
42
- readonly watch?: boolean;
43
36
  }
44
37
 
45
38
  /** Owns paired generation and freshness-check tasks for one Python package. */
46
39
  export class PythonNodeBundle extends Component {
47
40
  readonly buildTask: Task;
48
41
  readonly checkTask: Task;
49
- readonly watchTask?: Task;
50
42
 
51
43
  constructor(project: Project, options: PythonNodeBundleOptions) {
52
44
  super(project);
53
- const command = taskScript(
54
- project,
55
- "python-node-bindings.ts",
56
- `--project ${shellQuote(options.projectDirectory)}`,
57
- );
45
+ const command = taskCommand("python-node-bindings.ts", "--project", options.projectDirectory);
58
46
  this.buildTask = project.addTask(`${options.name}:python-runtime`, {
59
47
  description: `Generate Node bindings for Python package ${options.name}`,
60
- exec: command,
48
+ execArgs: command,
61
49
  });
62
50
  this.checkTask = project.addTask(`${options.name}:python-runtime:check`, {
63
51
  description: `Verify generated Node bindings for Python package ${options.name}`,
64
- exec: `${command} --check`,
52
+ execArgs: [...command, "--check"],
65
53
  });
66
54
  if (options.test ?? true) project.testTask.spawn(this.checkTask);
67
- if (options.watch) {
68
- this.watchTask = project.addTask(`${options.name}:python-runtime:watch`, {
69
- description: `Regenerate Node bindings for Python package ${options.name} on changes`,
70
- exec: taskScript(
71
- project,
72
- "python-node-bindings-watch.ts",
73
- `--project ${shellQuote(options.projectDirectory)}`,
74
- ),
75
- });
76
- if (isDBXToolsJavaScriptProject()(project)) {
77
- const configured = project.dbxToolsConfig.pythonNodeBindings;
78
- const projects = Array.isArray(configured)
79
- ? configured.filter((value): value is string => typeof value === "string")
80
- : [];
81
- project.dbxToolsConfig.pythonNodeBindings = [
82
- ...new Set([...projects, options.projectDirectory]),
83
- ];
84
- }
85
- }
86
55
  }
87
56
  }
88
-
89
- function shellQuote(value: string): string {
90
- if (/^[A-Za-z0-9_./:@=+#-]+$/.test(value)) return value;
91
- return `'${value.replaceAll("'", `'\\''`)}'`;
92
- }
@@ -1,4 +1,5 @@
1
1
  /** Verified release context shared by every job in the unified workflow. */
2
+ import { github } from "projen";
2
3
  import type { JobStep } from "projen/lib/github/workflows-model";
3
4
 
4
5
  export const RELEASE_TAG = "${{ needs.verify-context.outputs.release_tag }}";
@@ -8,14 +9,13 @@ export const RELEASE_VERSION = "${{ needs.verify-context.outputs.release_version
8
9
  /** Check out and verify the immutable commit selected by the release tag. */
9
10
  export function releaseSourceSteps(): readonly JobStep[] {
10
11
  return [
11
- {
12
+ github.WorkflowSteps.checkout({
12
13
  name: "Checkout release commit",
13
- uses: "actions/checkout@v6",
14
14
  with: {
15
15
  ref: RELEASE_SHA,
16
- "fetch-depth": 1,
16
+ fetchDepth: 1,
17
17
  },
18
- },
18
+ }),
19
19
  {
20
20
  name: "Verify release source",
21
21
  shell: "bash",
package/src/release.ts CHANGED
@@ -1,23 +1,18 @@
1
1
  /** Unified default-branch release workflow generation. */
2
2
  import { stringUtils } from "@dbx-tools/shared-core";
3
- import { Component } from "projen";
3
+ import { Component, github } from "projen";
4
4
  import { GithubWorkflow } from "projen/lib/github";
5
5
  import { JobPermission, type Job, type JobStep } from "projen/lib/github/workflows-model";
6
- import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workflow.ts";
7
- import { projectReleaseBranch, type DBXToolsJavaScriptProject } from "./project-js.ts";
8
- import { applyTasks, taskScript } from "./project.ts";
6
+ import { BUN_VERSION } from "./bun-workflow.ts";
7
+ import { projectReleaseBranch, taskCommand, type DBXToolsJavaScriptProject } from "./project-js.ts";
9
8
  import { RELEASE_VERSION, releaseSourceSteps } from "./release-context.ts";
10
9
 
11
10
  const NODE_VERSION = "24";
12
11
  const NPM_VERSION = "11.4.2";
13
12
  const NPM_REGISTRY_URL = "https://registry.npmjs.org";
14
- const nodeReleaseProjects = new WeakSet<DBXToolsJavaScriptProject>();
15
13
  const releaseTagPrefixes = new WeakMap<DBXToolsJavaScriptProject, string>();
16
14
  const releaseWorkflows = new WeakMap<DBXToolsJavaScriptProject, GithubWorkflow>();
17
15
 
18
- /** Independently recoverable portions of the release workflow. */
19
- export type ReleaseStage = "all" | "node" | "python" | "docs";
20
-
21
16
  /** GitHub Pages configuration included in the unified release workflow. */
22
17
  export interface ReleaseDocsOptions {
23
18
  readonly siteUrl: string;
@@ -44,23 +39,11 @@ export interface DBXToolsReleaseOptions {
44
39
  readonly validationTasks?: readonly string[];
45
40
  }
46
41
 
47
- /** Locate the unified workflow so attached language workspaces can add jobs. */
48
- export function releaseWorkflow(project: DBXToolsJavaScriptProject): GithubWorkflow {
49
- const workflow = releaseWorkflows.get(project);
50
- if (!workflow) throw new Error("Release workflow is not configured");
51
- return workflow;
52
- }
53
-
54
42
  /** Locate the unified workflow when release generation is enabled. */
55
43
  export function tryReleaseWorkflow(project: DBXToolsJavaScriptProject): GithubWorkflow | undefined {
56
44
  return releaseWorkflows.get(project);
57
45
  }
58
46
 
59
- /** Whether the unified workflow publishes the normal npm workspace. */
60
- export function hasNodeRelease(project: DBXToolsJavaScriptProject): boolean {
61
- return nodeReleaseProjects.has(project);
62
- }
63
-
64
47
  /** Tag pattern created by release jobs and accepted by manual recovery. */
65
48
  export function releaseTagPattern(project: DBXToolsJavaScriptProject): string {
66
49
  const prefix = releaseTagPrefixes.get(project);
@@ -68,29 +51,17 @@ export function releaseTagPattern(project: DBXToolsJavaScriptProject): string {
68
51
  return `${prefix}*`;
69
52
  }
70
53
 
71
- /** Run a release stage after its prerequisite tag-build jobs succeed. */
72
- export function releaseStageCondition(
73
- _stage: Exclude<ReleaseStage, "all">,
74
- prerequisites: readonly string[] = [],
75
- ): string {
54
+ /** Run a release job after all explicit prerequisite results succeed. */
55
+ export function releaseCondition(prerequisites: readonly string[] = []): string {
76
56
  if (prerequisites.length === 0) return "${{ success() }}";
77
57
  return `\${{ always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} }}`;
78
58
  }
79
59
 
80
- /** Publish a release stage after its prerequisite tag-build jobs succeed. */
81
- export function releasePublishCondition(
82
- _stage: Exclude<ReleaseStage, "all">,
83
- prerequisites: readonly string[] = [],
84
- ): string {
85
- if (prerequisites.length === 0) return "${{ success() }}";
86
- return `\${{ always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} }}`;
87
- }
88
-
89
- /** Shared Bun, Node, cache, and install setup for Node release jobs. */
60
+ /** Native project setup plus npm publication authentication. */
90
61
  export function nodeReleaseSetupSteps(project: DBXToolsJavaScriptProject): readonly JobStep[] {
91
62
  return [
92
63
  ...releaseSourceSteps(),
93
- ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
64
+ ...project.renderWorkflowSetup({ mutable: false }),
94
65
  {
95
66
  name: "Setup Node.js",
96
67
  uses: "actions/setup-node@v6",
@@ -101,20 +72,9 @@ export function nodeReleaseSetupSteps(project: DBXToolsJavaScriptProject): reado
101
72
  },
102
73
  },
103
74
  { name: "Install npm CLI", run: `npm install --global npm@${NPM_VERSION}` },
104
- { name: "Install", run: "bun install" },
105
- bunCacheSaveStep(),
106
75
  ];
107
76
  }
108
77
 
109
- /** Token authentication, GitHub provenance, and dry-run values shared by npm publishers. */
110
- export function npmPublishEnvironment(): Record<string, string> {
111
- return {
112
- NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
113
- NPM_CONFIG_PROVENANCE: "true",
114
- DRY_RUN: "",
115
- };
116
- }
117
-
118
78
  /** Install uv and restore its download/build cache using Python manifests. */
119
79
  export function uvSetupStep(): JobStep {
120
80
  return {
@@ -141,7 +101,9 @@ function refreshDocsRegistryDependencies(workflow: GithubWorkflow): void {
141
101
  /** Keep documentation publication behind every configured package registry. */
142
102
  export function refreshReleaseDocsDependencies(project: DBXToolsJavaScriptProject): void {
143
103
  const workflow = releaseWorkflows.get(project);
144
- if (workflow) refreshDocsRegistryDependencies(workflow);
104
+ if (workflow) {
105
+ refreshDocsRegistryDependencies(workflow);
106
+ }
145
107
  }
146
108
 
147
109
  function verifyContextJob(
@@ -161,17 +123,14 @@ function verifyContextJob(
161
123
  release_version: { stepId: "release", outputName: "release_version" },
162
124
  },
163
125
  steps: [
164
- {
126
+ github.WorkflowSteps.checkout({
165
127
  name: "Checkout release source",
166
- uses: "actions/checkout@v6",
167
128
  with: {
168
129
  ref: "${{ github.ref_name }}",
169
- "fetch-depth": 0,
130
+ fetchDepth: 0,
170
131
  },
171
- },
172
- ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
173
- { name: "Install release validation dependencies", run: "bun install --frozen-lockfile" },
174
- bunCacheSaveStep(),
132
+ }),
133
+ ...project.renderWorkflowSetup({ mutable: false }),
175
134
  {
176
135
  name: "Verify release context",
177
136
  id: "release",
@@ -210,7 +169,7 @@ function verifyContextJob(
210
169
 
211
170
  function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
212
171
  return {
213
- if: releaseStageCondition("node"),
172
+ if: releaseCondition(),
214
173
  needs: ["verify-context"],
215
174
  runsOn: ["ubuntu-latest"],
216
175
  permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
@@ -220,7 +179,11 @@ function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
220
179
  ...nodeReleaseSetupSteps(project),
221
180
  {
222
181
  name: "Publish npm workspace",
223
- env: { RELEASE_VERSION, ...npmPublishEnvironment() },
182
+ env: {
183
+ RELEASE_VERSION,
184
+ NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
185
+ NPM_CONFIG_PROVENANCE: "true",
186
+ },
224
187
  run: 'bun node_modules/@dbx-tools/projen/tasks/publish.ts "$RELEASE_VERSION" $DRY_RUN',
225
188
  },
226
189
  ],
@@ -233,7 +196,7 @@ function addDocsJobs(
233
196
  options: ReleaseDocsOptions,
234
197
  ): void {
235
198
  workflow.addJob("build-docs", {
236
- if: releaseStageCondition("docs"),
199
+ if: releaseCondition(),
237
200
  needs: ["verify-context"],
238
201
  runsOn: ["ubuntu-latest"],
239
202
  permissions: {
@@ -249,9 +212,8 @@ function addDocsJobs(
249
212
  },
250
213
  steps: [
251
214
  ...releaseSourceSteps(),
252
- ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
215
+ ...project.renderWorkflowSetup({ mutable: false }),
253
216
  ...options.prepareSteps,
254
- bunCacheSaveStep(),
255
217
  ...options.buildSteps,
256
218
  {
257
219
  name: "Upload Pages artifact",
@@ -261,7 +223,7 @@ function addDocsJobs(
261
223
  ],
262
224
  });
263
225
  workflow.addJob("deploy-docs", {
264
- if: releasePublishCondition("docs"),
226
+ if: releaseCondition(),
265
227
  needs: ["build-docs"],
266
228
  environment: {
267
229
  name: "github-pages",
@@ -288,31 +250,30 @@ export class DBXToolsRelease extends Component {
288
250
  const tagPrefix = options.tagPrefix ?? "v";
289
251
  const releaseBranch = projectReleaseBranch(project);
290
252
  releaseTagPrefixes.set(project, tagPrefix);
291
- if (options.nodeRelease !== false) nodeReleaseProjects.add(project);
292
- applyTasks(project, {
293
- bump: {
294
- exec: taskScript(project, "bump.ts"),
295
- receiveArgs: true,
296
- description: "Increment VERSION and synchronize generated workspace versions",
297
- },
298
- "version:check": {
299
- exec: taskScript(project, "version-check.ts"),
300
- description: "Verify every package and generated barrel matches VERSION",
301
- },
302
- ...(project.github
303
- ? {
304
- release: {
305
- exec: taskScript(
306
- project,
307
- "release.ts",
308
- `--prefix ${tagPrefix} --branch ${releaseBranch}`,
309
- ),
310
- receiveArgs: true,
311
- description: "Run bump, commit it, and push an annotated release tag",
312
- },
313
- }
314
- : {}),
253
+ project.addTask("bump", {
254
+ execArgs: taskCommand("bump.ts"),
255
+ receiveArgs: true,
256
+ description: "Increment VERSION and synchronize generated workspace versions",
257
+ });
258
+ project.addTask("version:check", {
259
+ execArgs: taskCommand("version-check.ts"),
260
+ description: "Verify every package and generated barrel matches VERSION",
315
261
  });
262
+ if (project.github) {
263
+ project.addTask("release", {
264
+ execArgs: taskCommand(
265
+ "release.ts",
266
+ "--prefix",
267
+ tagPrefix,
268
+ "--branch",
269
+ releaseBranch,
270
+ ...(options.pythonRoot ? ["--python-root", options.pythonRoot] : []),
271
+ ...(options.validationTasks ?? []).flatMap((task) => ["--validate", task]),
272
+ ),
273
+ receiveArgs: true,
274
+ description: "Run bump, commit it, and push an annotated release tag",
275
+ });
276
+ }
316
277
  if (!project.github) return;
317
278
 
318
279
  const workflow = new GithubWorkflow(project.github, "release", {
@@ -336,5 +297,6 @@ export class DBXToolsRelease extends Component {
336
297
  if (options.docs) {
337
298
  addDocsJobs(workflow, project, options.docs);
338
299
  }
300
+ refreshReleaseDocsDependencies(project);
339
301
  }
340
302
  }
package/src/tags.ts CHANGED
@@ -14,18 +14,18 @@
14
14
  * callers add their own afterward.
15
15
  */
16
16
  import type { IMixin as ConstructsMixin } from "constructs";
17
- import { javascript } from "projen";
17
+ import { DependencyType, javascript } from "projen";
18
18
  import { BunBuildFile, BunDevServerFile, BunfigFile } from "./bun-app.ts";
19
+ import { BUN_VERSION } from "./bun-workflow.ts";
19
20
  import { create } from "./mixin.ts";
20
- import * as projectPredicate from "./project-predicate.ts";
21
21
  import {
22
22
  addPackageFiles,
23
23
  applyCompilerOptions,
24
24
  applyExports,
25
25
  applyIncludes,
26
- applyTasks,
27
26
  srcModuleExports,
28
- } from "./project.ts";
27
+ } from "./project-js.ts";
28
+ import * as projectPredicate from "./project-predicate.ts";
29
29
 
30
30
  /** Node compiler options: ES2022 lib + node types, deliberately no DOM. */
31
31
  const NODE_COMPILER_OPTIONS: javascript.TypeScriptCompilerOptions = {
@@ -37,6 +37,10 @@ const NODE_COMPILER_OPTIONS: javascript.TypeScriptCompilerOptions = {
37
37
  /** The DOM-capable lib list shared by the browser tags (`ui`, `openapi`). */
38
38
  const DOM_LIB = ["ES2022", "DOM", "DOM.Iterable"];
39
39
 
40
+ function removeNodeTypes(project: javascript.NodeProject): void {
41
+ project.deps.removeDependency("@types/node", DependencyType.BUILD);
42
+ }
43
+
40
44
  /**
41
45
  * The agnostic floor every package gets at construction: ES2022 stdlib plus the
42
46
  * web-platform globals available in every JS runtime (browser, workers, Node 18+)
@@ -64,6 +68,7 @@ export const PACKAGE_TAG_MIXINS = {
64
68
  // compile (typecheck). No app build / index.html: a full browser app is an
65
69
  // `app`-tagged package (see below) that layers Bun's build tooling on top.
66
70
  ui: create(projectPredicate.hasTag("ui"), (p) => {
71
+ removeNodeTypes(p);
67
72
  p.addPeerDeps("react@catalog:", "react-dom@catalog:");
68
73
  p.addDevDeps(
69
74
  "react@catalog:",
@@ -79,13 +84,10 @@ export const PACKAGE_TAG_MIXINS = {
79
84
  target: "ES2022",
80
85
  lib: [...DOM_LIB],
81
86
  });
82
- // A component library's standard subpath surface: `./react` (components),
83
- // `./styles.css` (Tailwind entry), and `./package.json`. A package that
84
- // ships more (e.g. ui-appkit's `./vite` preset) overrides this in its own
85
- // mixin; an `app`-tagged package replaces it with a `.` root (see below).
87
+ // UI libraries are subpath-only. Their React entrypoint, optional stylesheet,
88
+ // and any other public source modules are discovered from the source tree.
86
89
  applyExports(p, {
87
- "./react": "./src/react/index.ts",
88
- "./styles.css": "./src/styles.css",
90
+ ...srcModuleExports(p),
89
91
  "./package.json": "./package.json",
90
92
  });
91
93
  }),
@@ -95,8 +97,10 @@ export const PACKAGE_TAG_MIXINS = {
95
97
  // `Bun.build`). Tailwind v4 is compiled by `bun-plugin-tailwind` (wired in the
96
98
  // generated `bunfig.toml`). No Vite.
97
99
  app: create(projectPredicate.hasTag("app"), (p) => {
100
+ removeNodeTypes(p);
98
101
  p.addDeps("react@catalog:", "react-dom@catalog:");
99
102
  p.addDevDeps(
103
+ `@types/bun@${BUN_VERSION}`,
100
104
  "@types/react@catalog:",
101
105
  "@types/react-dom@catalog:",
102
106
  // The Tailwind plugin the dev server + build load. Tailwind itself is a
@@ -121,10 +125,8 @@ export const PACKAGE_TAG_MIXINS = {
121
125
  // and `preview` serves the already-built bundle. `Bun.serve` builds on request,
122
126
  // so `preview` could only be spelled the same as `dev` - two names for one
123
127
  // command, and a reader would reasonably assume the second one served `dist/`.
124
- applyTasks(p, {
125
- dev: { exec: "bun dev.ts" },
126
- build: { exec: "bun build.ts" },
127
- });
128
+ (p.tasks.tryFind("dev") ?? p.addTask("dev")).reset("bun dev.ts");
129
+ p.compileTask.reset("bun build.ts");
128
130
  new BunfigFile(p);
129
131
  new BunDevServerFile(p);
130
132
  new BunBuildFile(p);
@@ -172,19 +174,19 @@ export const PACKAGE_TAG_MIXINS = {
172
174
  });
173
175
  // bun runs the server `.ts` directly (native TS, no tsx). `--watch` restarts
174
176
  // on change - the tsx-watch replacement.
175
- applyTasks(p, {
176
- dev: { exec: "bun --watch src/server.ts" },
177
- start: { exec: "bun src/server.ts" },
178
- });
177
+ (p.tasks.tryFind("dev") ?? p.addTask("dev")).reset("bun --watch src/server.ts");
178
+ (p.tasks.tryFind("start") ?? p.addTask("start")).reset("bun src/server.ts");
179
179
  }),
180
180
  node: create(projectPredicate.hasTag("node"), (p) => {
181
181
  p.addDevDeps("@types/node@catalog:");
182
182
  applyCompilerOptions(p, NODE_COMPILER_OPTIONS);
183
183
  }),
184
184
  shared: create(projectPredicate.hasTag("shared"), (p) => {
185
+ removeNodeTypes(p);
185
186
  applyCompilerOptions(p, AGNOSTIC_COMPILER_OPTIONS);
186
187
  }),
187
188
  openapi: create(projectPredicate.hasTag("openapi"), (p) => {
189
+ removeNodeTypes(p);
188
190
  p.addDeps("openapi-fetch@catalog:");
189
191
  applyCompilerOptions(p, { target: "ES2022", lib: [...DOM_LIB], types: [] });
190
192
  addPackageFiles(p, "openapi.json");
package/src/tsconfig.ts CHANGED
@@ -34,6 +34,12 @@ const BASE_COMPILER_OPTIONS: javascript.TypeScriptCompilerOptions = {
34
34
  * Packages type-check against their own projen-generated tsconfigs via `compile`.
35
35
  */
36
36
  export class DBXToolsRootTsconfig extends Component {
37
+ /** Shared compiler floor inherited by the root program. */
38
+ readonly base?: javascript.TypescriptConfig;
39
+
40
+ /** Root program config inherited by the generated Projen config. */
41
+ readonly config?: javascript.TypescriptConfig;
42
+
37
43
  constructor(scope: Project) {
38
44
  super(scope);
39
45
 
@@ -41,13 +47,12 @@ export class DBXToolsRootTsconfig extends Component {
41
47
  return;
42
48
  }
43
49
 
44
- const base = new javascript.TypescriptConfig(scope, {
50
+ this.base = new javascript.TypescriptConfig(scope, {
45
51
  fileName: "tsconfig.base.json",
46
52
  compilerOptions: BASE_COMPILER_OPTIONS,
47
53
  });
48
- base.file.readonly = true;
49
- const root = new javascript.TypescriptConfig(scope, {
50
- extends: javascript.TypescriptConfigExtends.fromTypescriptConfigs([base]),
54
+ this.config = new javascript.TypescriptConfig(scope, {
55
+ extends: javascript.TypescriptConfigExtends.fromTypescriptConfigs([this.base]),
51
56
  compilerOptions: {
52
57
  lib: ["ESNext"],
53
58
  types: ["node"],
@@ -55,6 +60,5 @@ export class DBXToolsRootTsconfig extends Component {
55
60
  include: [".projenrc.ts"],
56
61
  exclude: ["node_modules", "**/dist", "**/node_modules"],
57
62
  });
58
- root.file.readonly = true;
59
63
  }
60
64
  }
package/src/vscode.ts CHANGED
@@ -5,65 +5,54 @@
5
5
  * is delivered by `.vscode/tasks.json` (`runOn: folderOpen`) - projen has no native
6
6
  * tasks.json component, so a `JsonFile` is the idiomatic emitter.
7
7
  */
8
- import { Component, JsonFile, javascript, vscode } from "projen";
8
+ import { JsonFile, javascript } from "projen";
9
9
 
10
- /**
11
- * Configures root `.vscode/settings.json`, `extensions.json`, and `tasks.json`.
12
- * Only a tree ROOT constructs this component (see {@link DBXToolsNodeProject}).
13
- */
14
- export class DBXToolsVsCode extends Component {
15
- /** projen's built-in VsCode component (settings + extension recommendations). */
16
- readonly vsCode: vscode.VsCode;
17
-
18
- constructor(scope: javascript.NodeProject) {
19
- super(scope);
10
+ /** Configure the native Projen VS Code component and the unsupported tasks file. */
11
+ export function configureVsCode(scope: javascript.NodeProject): void {
12
+ const editor = scope.vscode;
13
+ if (!editor) return;
14
+ editor.settings.addSettings({
15
+ "typescript.tsdk": "node_modules/typescript/lib",
16
+ "typescript.preferences.importModuleSpecifier": "non-relative",
17
+ "javascript.preferences.importModuleSpecifier": "non-relative",
18
+ "editor.formatOnSave": true,
19
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
20
+ "files.watcherExclude": {
21
+ "**/node_modules/**": true,
22
+ "**/dist/**": true,
23
+ },
24
+ });
25
+ editor.extensions.addRecommendations("esbenp.prettier-vscode");
20
26
 
21
- this.vsCode = scope.vscode ?? new vscode.VsCode(scope);
22
- this.vsCode.settings.addSettings({
23
- "typescript.tsdk": "node_modules/typescript/lib",
24
- "typescript.preferences.importModuleSpecifier": "non-relative",
25
- "javascript.preferences.importModuleSpecifier": "non-relative",
26
- "editor.formatOnSave": true,
27
- "editor.defaultFormatter": "esbenp.prettier-vscode",
28
- "files.watcherExclude": {
29
- "**/node_modules/**": true,
30
- "**/dist/**": true,
31
- },
32
- });
33
- this.vsCode.extensions.addRecommendations("esbenp.prettier-vscode");
34
- this.vsCode.settings.file.readonly = true;
35
- this.vsCode.extensions.file.readonly = true;
36
-
37
- new JsonFile(scope, ".vscode/tasks.json", {
38
- marker: false,
39
- readonly: true,
40
- obj: {
41
- version: "2.0.0",
42
- tasks: [
43
- {
44
- label: "sync",
45
- detail:
46
- "projen sync --watch - projenrc (.projenrc.ts + syncResynthPaths re-synth) + barrels + openapi watchers",
47
- type: "shell",
48
- command: "bun run sync -- --watch",
49
- isBackground: true,
50
- problemMatcher: [],
51
- runOptions: { runOn: "folderOpen" },
52
- presentation: {
53
- reveal: "always",
54
- panel: "dedicated",
55
- group: "projen",
56
- },
57
- },
58
- {
59
- label: "synth",
60
- detail: "projen - synthesize all generated config",
61
- type: "shell",
62
- command: "bun run default",
63
- problemMatcher: [],
27
+ new JsonFile(scope, ".vscode/tasks.json", {
28
+ marker: false,
29
+ readonly: true,
30
+ obj: {
31
+ version: "2.0.0",
32
+ tasks: [
33
+ {
34
+ label: "sync",
35
+ detail:
36
+ "projen sync --watch - projenrc (.projenrc.ts + syncResynthPaths re-synth) + barrels + openapi watchers",
37
+ type: "shell",
38
+ command: "bun run sync -- --watch",
39
+ isBackground: true,
40
+ problemMatcher: [],
41
+ runOptions: { runOn: "folderOpen" },
42
+ presentation: {
43
+ reveal: "always",
44
+ panel: "dedicated",
45
+ group: "projen",
64
46
  },
65
- ],
66
- },
67
- });
68
- }
47
+ },
48
+ {
49
+ label: "synth",
50
+ detail: "projen - synthesize all generated config",
51
+ type: "shell",
52
+ command: "bun run default",
53
+ problemMatcher: [],
54
+ },
55
+ ],
56
+ },
57
+ });
69
58
  }
package/src/watch.ts CHANGED
@@ -90,19 +90,13 @@ export interface WatchLoopOptions {
90
90
  check?: (changed: string[]) => boolean | Promise<boolean>;
91
91
  }
92
92
 
93
- function resolveWatchLoopOptions(config?: IgnoreGroupOptions | WatchLoopOptions): WatchLoopOptions {
94
- if (!config) return {};
95
- if ("check" in config || "ignoreOptions" in config) return config as WatchLoopOptions;
96
- return { ignoreOptions: config as IgnoreGroupOptions };
97
- }
98
-
99
93
  export function watchLoop(
100
94
  tag: string,
101
95
  paths: string[],
102
96
  onBatch: (changed: string[]) => void | Promise<void>,
103
- config?: IgnoreGroupOptions | WatchLoopOptions,
97
+ config: WatchLoopOptions = {},
104
98
  ): void {
105
- const { ignoreOptions, check } = resolveWatchLoopOptions(config);
99
+ const { ignoreOptions, check } = config;
106
100
  const pending = new Set<string>();
107
101
  let timer: ReturnType<typeof setTimeout> | undefined;
108
102
  let running = false;
@@ -110,17 +110,12 @@ export function syncWorkspaceManifestVersion(manifestPath: string, version: stri
110
110
  return true;
111
111
  }
112
112
 
113
- /** The checked-in version a release increment starts from. */
114
- export function resolveBaseVersion(root: string): string {
115
- return readWorkspaceVersion(root);
116
- }
117
-
118
113
  /** Resolve the next release version without mutating the workspace. */
119
114
  export function resolveNextVersion(
120
115
  root: string,
121
116
  level: VersionLevel,
122
117
  ): { base: string; version: string } {
123
- const base = resolveBaseVersion(root);
118
+ const base = readWorkspaceVersion(root);
124
119
  const parsed = parseSemver(base) ?? [0, 0, 1];
125
120
  return {
126
121
  base: parsed.join("."),