@dbx-tools/projen 0.9.31 → 0.9.36

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 +88 -86
  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 -105
  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 -96
  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";
9
- import { RELEASE_VERSION, releaseSourceSteps } from "./release-context.ts";
6
+ import { BUN_VERSION } from "./bun-workflow.ts";
7
+ import { projectReleaseBranch, taskCommand, type DBXToolsJavaScriptProject } from "./project-js.ts";
8
+ import { RELEASE_TAG, 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 {
@@ -138,10 +98,51 @@ function refreshDocsRegistryDependencies(workflow: GithubWorkflow): void {
138
98
  }
139
99
  }
140
100
 
101
+ function refreshGitHubReleaseDependencies(workflow: GithubWorkflow): void {
102
+ const release = workflow.getJob("publish-github-release") as Job | undefined;
103
+ if (!release) return;
104
+ const registryJobs = Object.keys(workflow.jobs).filter(
105
+ (name) => name === "publish-node" || name.startsWith("publish-pypi-"),
106
+ );
107
+ const needs = ["verify-context", ...registryJobs];
108
+ workflow.updateJob("publish-github-release", {
109
+ ...release,
110
+ needs,
111
+ if: releaseCondition([
112
+ "needs.verify-context.result == 'success'",
113
+ ...registryJobs.map((job) => `needs['${job}'].result == 'success'`),
114
+ ]),
115
+ });
116
+ }
117
+
141
118
  /** Keep documentation publication behind every configured package registry. */
142
119
  export function refreshReleaseDocsDependencies(project: DBXToolsJavaScriptProject): void {
143
120
  const workflow = releaseWorkflows.get(project);
144
- if (workflow) refreshDocsRegistryDependencies(workflow);
121
+ if (workflow) {
122
+ refreshDocsRegistryDependencies(workflow);
123
+ refreshGitHubReleaseDependencies(workflow);
124
+ }
125
+ }
126
+
127
+ function githubReleaseJob(): Job {
128
+ return {
129
+ runsOn: ["ubuntu-latest"],
130
+ permissions: { contents: JobPermission.WRITE },
131
+ timeoutMinutes: 10,
132
+ env: {
133
+ GH_TOKEN: "${{ github.token }}",
134
+ RELEASE_TAG,
135
+ },
136
+ steps: [
137
+ {
138
+ name: "Create GitHub release",
139
+ run: [
140
+ 'gh release view "$RELEASE_TAG" >/dev/null 2>&1 ||',
141
+ ' gh release create "$RELEASE_TAG" --verify-tag --title "$RELEASE_TAG" --generate-notes',
142
+ ].join("\n"),
143
+ },
144
+ ],
145
+ };
145
146
  }
146
147
 
147
148
  function verifyContextJob(
@@ -161,17 +162,14 @@ function verifyContextJob(
161
162
  release_version: { stepId: "release", outputName: "release_version" },
162
163
  },
163
164
  steps: [
164
- {
165
+ github.WorkflowSteps.checkout({
165
166
  name: "Checkout release source",
166
- uses: "actions/checkout@v6",
167
167
  with: {
168
168
  ref: "${{ github.ref_name }}",
169
- "fetch-depth": 0,
169
+ fetchDepth: 0,
170
170
  },
171
- },
172
- ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
173
- { name: "Install release validation dependencies", run: "bun install --frozen-lockfile" },
174
- bunCacheSaveStep(),
171
+ }),
172
+ ...project.renderWorkflowSetup({ mutable: false }),
175
173
  {
176
174
  name: "Verify release context",
177
175
  id: "release",
@@ -210,7 +208,7 @@ function verifyContextJob(
210
208
 
211
209
  function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
212
210
  return {
213
- if: releaseStageCondition("node"),
211
+ if: releaseCondition(),
214
212
  needs: ["verify-context"],
215
213
  runsOn: ["ubuntu-latest"],
216
214
  permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
@@ -220,7 +218,11 @@ function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
220
218
  ...nodeReleaseSetupSteps(project),
221
219
  {
222
220
  name: "Publish npm workspace",
223
- env: { RELEASE_VERSION, ...npmPublishEnvironment() },
221
+ env: {
222
+ RELEASE_VERSION,
223
+ NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
224
+ NPM_CONFIG_PROVENANCE: "true",
225
+ },
224
226
  run: 'bun node_modules/@dbx-tools/projen/tasks/publish.ts "$RELEASE_VERSION" $DRY_RUN',
225
227
  },
226
228
  ],
@@ -233,7 +235,7 @@ function addDocsJobs(
233
235
  options: ReleaseDocsOptions,
234
236
  ): void {
235
237
  workflow.addJob("build-docs", {
236
- if: releaseStageCondition("docs"),
238
+ if: releaseCondition(),
237
239
  needs: ["verify-context"],
238
240
  runsOn: ["ubuntu-latest"],
239
241
  permissions: {
@@ -249,9 +251,8 @@ function addDocsJobs(
249
251
  },
250
252
  steps: [
251
253
  ...releaseSourceSteps(),
252
- ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
254
+ ...project.renderWorkflowSetup({ mutable: false }),
253
255
  ...options.prepareSteps,
254
- bunCacheSaveStep(),
255
256
  ...options.buildSteps,
256
257
  {
257
258
  name: "Upload Pages artifact",
@@ -261,7 +262,7 @@ function addDocsJobs(
261
262
  ],
262
263
  });
263
264
  workflow.addJob("deploy-docs", {
264
- if: releasePublishCondition("docs"),
265
+ if: releaseCondition(),
265
266
  needs: ["build-docs"],
266
267
  environment: {
267
268
  name: "github-pages",
@@ -288,31 +289,30 @@ export class DBXToolsRelease extends Component {
288
289
  const tagPrefix = options.tagPrefix ?? "v";
289
290
  const releaseBranch = projectReleaseBranch(project);
290
291
  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
- : {}),
292
+ project.addTask("bump", {
293
+ execArgs: taskCommand("bump.ts"),
294
+ receiveArgs: true,
295
+ description: "Increment VERSION and synchronize generated workspace versions",
296
+ });
297
+ project.addTask("version:check", {
298
+ execArgs: taskCommand("version-check.ts"),
299
+ description: "Verify every package and generated barrel matches VERSION",
315
300
  });
301
+ if (project.github) {
302
+ project.addTask("release", {
303
+ execArgs: taskCommand(
304
+ "release.ts",
305
+ "--prefix",
306
+ tagPrefix,
307
+ "--branch",
308
+ releaseBranch,
309
+ ...(options.pythonRoot ? ["--python-root", options.pythonRoot] : []),
310
+ ...(options.validationTasks ?? []).flatMap((task) => ["--validate", task]),
311
+ ),
312
+ receiveArgs: true,
313
+ description: "Run bump, commit it, and push an annotated release tag",
314
+ });
315
+ }
316
316
  if (!project.github) return;
317
317
 
318
318
  const workflow = new GithubWorkflow(project.github, "release", {
@@ -336,5 +336,7 @@ export class DBXToolsRelease extends Component {
336
336
  if (options.docs) {
337
337
  addDocsJobs(workflow, project, options.docs);
338
338
  }
339
+ workflow.addJob("publish-github-release", githubReleaseJob());
340
+ refreshReleaseDocsDependencies(project);
339
341
  }
340
342
  }
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
  }