@dbx-tools/projen 0.6.40 → 0.6.41
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/index.ts +2 -2
- package/package.json +22 -20
- package/src/bun-app.ts +164 -0
- package/src/packages.ts +6 -4
- package/src/pnpm-workspace.ts +73 -12
- package/src/project.ts +91 -46
- package/src/release.ts +114 -38
- package/src/tags.ts +28 -14
- package/tasks/bump.ts +41 -87
- package/tasks/publish.ts +156 -0
- package/src/vite.ts +0 -99
package/index.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export * as barrels from "./src/barrels.ts";
|
|
6
|
+
export * as bunApp from "./src/bun-app.ts";
|
|
6
7
|
export * as clean from "./src/clean.ts";
|
|
7
8
|
export * as codegen from "./src/codegen.ts";
|
|
8
9
|
export * as dbxToolsConfig from "./src/dbx-tools-config.ts";
|
|
@@ -20,7 +21,6 @@ export * as release from "./src/release.ts";
|
|
|
20
21
|
export * as scaffold from "./src/scaffold.ts";
|
|
21
22
|
export * as tags from "./src/tags.ts";
|
|
22
23
|
export * as tsconfig from "./src/tsconfig.ts";
|
|
23
|
-
export * as vite from "./src/vite.ts";
|
|
24
24
|
export * as vscode from "./src/vscode.ts";
|
|
25
25
|
export * as watch from "./src/watch.ts";
|
|
26
26
|
export { DBXToolsConfig } from "./src/dbx-tools-config.ts";
|
|
@@ -41,6 +41,6 @@ export type { StandaloneRelease, DBXToolsReleaseOptions } from "./src/release.ts
|
|
|
41
41
|
export { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS } from "./src/tags.ts";
|
|
42
42
|
export type { PackageTag } from "./src/tags.ts";
|
|
43
43
|
export { DBXToolsRootTsconfig } from "./src/tsconfig.ts";
|
|
44
|
-
export {
|
|
44
|
+
export { BUN_DEV_OVERRIDE, BUN_BUILD_OVERRIDE, BUN_APP_OVERRIDES, BunfigFile, BunDevServerFile, BunBuildFile } from "./src/bun-app.ts";
|
|
45
45
|
export { DBXToolsVsCode } from "./src/vscode.ts";
|
|
46
46
|
export type { IgnoreGroupOptions } from "./src/watch.ts";
|
package/package.json
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dbx-tools/projen",
|
|
3
|
+
"scripts": {
|
|
4
|
+
"build": "projen build",
|
|
5
|
+
"bump": "projen bump",
|
|
6
|
+
"clobber": "projen clobber",
|
|
7
|
+
"compile": "projen compile",
|
|
8
|
+
"default": "projen default",
|
|
9
|
+
"demo": "projen demo",
|
|
10
|
+
"eject": "projen eject",
|
|
11
|
+
"package": "projen package",
|
|
12
|
+
"post-compile": "projen post-compile",
|
|
13
|
+
"post-upgrade": "projen post-upgrade",
|
|
14
|
+
"pre-compile": "projen pre-compile",
|
|
15
|
+
"test": "projen test",
|
|
16
|
+
"upgrade": "projen upgrade",
|
|
17
|
+
"watch": "projen watch",
|
|
18
|
+
"projen": "projen"
|
|
19
|
+
},
|
|
3
20
|
"devDependencies": {
|
|
4
21
|
"@types/node": "^24.6.0",
|
|
5
22
|
"constructs": "^10.0.0",
|
|
@@ -23,6 +40,7 @@
|
|
|
23
40
|
"tsx": "^4.23.0",
|
|
24
41
|
"yaml": "^2.9.0"
|
|
25
42
|
},
|
|
43
|
+
"pnpm": {},
|
|
26
44
|
"devEngines": {
|
|
27
45
|
"packageManager": {
|
|
28
46
|
"name": "pnpm",
|
|
@@ -32,7 +50,8 @@
|
|
|
32
50
|
},
|
|
33
51
|
"main": "index.ts",
|
|
34
52
|
"license": "Apache-2.0",
|
|
35
|
-
"version": "0.6.
|
|
53
|
+
"version": "0.6.41",
|
|
54
|
+
"packageManager": "pnpm@10.33.0",
|
|
36
55
|
"types": "index.ts",
|
|
37
56
|
"type": "module",
|
|
38
57
|
"exports": {
|
|
@@ -44,22 +63,5 @@
|
|
|
44
63
|
"src",
|
|
45
64
|
"tasks"
|
|
46
65
|
],
|
|
47
|
-
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\"."
|
|
48
|
-
|
|
49
|
-
"build": "projen build",
|
|
50
|
-
"bump": "projen bump",
|
|
51
|
-
"clobber": "projen clobber",
|
|
52
|
-
"compile": "projen compile",
|
|
53
|
-
"default": "projen default",
|
|
54
|
-
"demo": "projen demo",
|
|
55
|
-
"eject": "projen eject",
|
|
56
|
-
"package": "projen package",
|
|
57
|
-
"post-compile": "projen post-compile",
|
|
58
|
-
"post-upgrade": "projen post-upgrade",
|
|
59
|
-
"pre-compile": "projen pre-compile",
|
|
60
|
-
"test": "projen test",
|
|
61
|
-
"upgrade": "projen upgrade",
|
|
62
|
-
"watch": "projen watch",
|
|
63
|
-
"projen": "projen"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\"."
|
|
67
|
+
}
|
package/src/bun-app.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun browser-app scaffolding as first-class projen file components.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the old Vite toolchain (`vite.ts`). An `app`-tagged package gets three
|
|
5
|
+
* generated, read-only files that stand in for `vite dev` / `vite build`:
|
|
6
|
+
*
|
|
7
|
+
* - {@link BunfigFile} - `bunfig.toml` wiring `bun-plugin-tailwind` into both the
|
|
8
|
+
* dev server (`[serve.static]`) and `Bun.build` (`[build]`) so Tailwind v4's
|
|
9
|
+
* `@import "tailwindcss"` + `@source` directives compile with no separate CLI.
|
|
10
|
+
* - {@link BunDevServerFile} - `dev.ts`: a `Bun.serve()` fullstack dev server that
|
|
11
|
+
* imports `index.html` and serves the SPA with React hot module reloading.
|
|
12
|
+
* - {@link BunBuildFile} - `build.ts`: a `Bun.build()` production bundle of
|
|
13
|
+
* `index.html` (the `bun-plugin-tailwind` plugin must run through the JS API,
|
|
14
|
+
* NOT the `bun build` CLI, which does not load it).
|
|
15
|
+
*
|
|
16
|
+
* Each file supports an unmanaged OVERRIDE beside it (`bunfig.override.toml`,
|
|
17
|
+
* `bun-dev.override.ts`, `bun-build.override.ts`): the dev/build scripts import
|
|
18
|
+
* the override's default export and merge it over the generated options, so a
|
|
19
|
+
* package tweaks its server/bundle WITHOUT editing the projen-owned file - the
|
|
20
|
+
* same escape hatch the Vite generator offered via `vite.config.override.*`.
|
|
21
|
+
*
|
|
22
|
+
* bun runs these `.ts` files directly. Being package-ROOT files (not under
|
|
23
|
+
* `src/`), they are outside the package's `tsconfig` include, so their `Bun.*`
|
|
24
|
+
* usage never trips the `app` package's DOM-only `compile`.
|
|
25
|
+
*/
|
|
26
|
+
import { type Project, TextFile } from "projen";
|
|
27
|
+
|
|
28
|
+
/** Unmanaged dev-server override module, merged over the generated options if present. */
|
|
29
|
+
export const BUN_DEV_OVERRIDE = "bun-dev.override.ts";
|
|
30
|
+
/** Unmanaged build override module, merged over the generated options if present. */
|
|
31
|
+
export const BUN_BUILD_OVERRIDE = "bun-build.override.ts";
|
|
32
|
+
/** Unmanaged bunfig override (documented; merging TOML is left to the user). */
|
|
33
|
+
export const BUN_APP_OVERRIDES = ["bunfig.override.toml", BUN_DEV_OVERRIDE, BUN_BUILD_OVERRIDE];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Root `bunfig.toml`: pin bun's HOISTED linker workspace-wide.
|
|
37
|
+
*
|
|
38
|
+
* bun's default (isolated) linker instantiates a peer dependency once PER
|
|
39
|
+
* distinct peer context, so a package with many peers (`@mastra/*`) resolves to
|
|
40
|
+
* two peer-hash variants of the SAME `@mastra/core` version - and TypeScript then
|
|
41
|
+
* rejects passing a value built against one to an API typed by the other
|
|
42
|
+
* ("separate declarations of a private property"). The hoisted linker de-dupes to
|
|
43
|
+
* a single flat copy (npm-style), which is what keeps identity-based singletons
|
|
44
|
+
* (AppKit `CacheManager`, Mastra classes, one React) coherent - the same coherence
|
|
45
|
+
* the old cross-workspace `.pnpmfile.cjs` bridge used to guarantee.
|
|
46
|
+
*/
|
|
47
|
+
export class RootBunfigFile extends TextFile {
|
|
48
|
+
constructor(project: Project) {
|
|
49
|
+
super(project, "bunfig.toml", {
|
|
50
|
+
marker: false,
|
|
51
|
+
readonly: true,
|
|
52
|
+
lines: [
|
|
53
|
+
'# ~~ Generated by projen. To modify, edit .projenrc.ts and run "bunx projen".',
|
|
54
|
+
"# Hoisted (flat) node_modules so a peer dep like @mastra/core resolves to ONE",
|
|
55
|
+
"# copy - the isolated default splits it into peer-hash variants and breaks",
|
|
56
|
+
"# identity-based singletons + cross-package types.",
|
|
57
|
+
"[install]",
|
|
58
|
+
'linker = "hoisted"',
|
|
59
|
+
"",
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* `bunfig.toml`: wire `bun-plugin-tailwind` into the DEV SERVER.
|
|
67
|
+
*
|
|
68
|
+
* Only `[serve.static]` is set - that is the one config bun reads for plugins. The
|
|
69
|
+
* `bun build` CLI does NOT load `bunfig.toml` plugins (a documented limitation),
|
|
70
|
+
* so the production build goes through `Bun.build()`'s JS API in `build.ts`, which
|
|
71
|
+
* passes the plugin directly. A `[build]` section here would be dead config that
|
|
72
|
+
* falsely implies `bun build ./index.html` applies Tailwind, so it is omitted.
|
|
73
|
+
*/
|
|
74
|
+
export class BunfigFile extends TextFile {
|
|
75
|
+
constructor(project: Project) {
|
|
76
|
+
super(project, "bunfig.toml", {
|
|
77
|
+
marker: true,
|
|
78
|
+
readonly: true,
|
|
79
|
+
lines: [
|
|
80
|
+
"# Tailwind v4 for the dev server (Bun.serve reads [serve.static] plugins).",
|
|
81
|
+
"# Production build applies the plugin via Bun.build's API in build.ts - the",
|
|
82
|
+
"# `bun build` CLI does not load bunfig plugins, so there is no [build] here.",
|
|
83
|
+
"[serve.static]",
|
|
84
|
+
'plugins = ["bun-plugin-tailwind"]',
|
|
85
|
+
"",
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** `dev.ts`: a `Bun.serve()` fullstack dev server with React HMR. */
|
|
92
|
+
export class BunDevServerFile extends TextFile {
|
|
93
|
+
constructor(project: Project) {
|
|
94
|
+
super(project, "dev.ts", {
|
|
95
|
+
marker: true,
|
|
96
|
+
readonly: true,
|
|
97
|
+
lines: String.raw`
|
|
98
|
+
import { existsSync } from "node:fs";
|
|
99
|
+
import index from "./index.html";
|
|
100
|
+
|
|
101
|
+
// Unmanaged override (${BUN_DEV_OVERRIDE}): its default export is merged over the
|
|
102
|
+
// generated serve options - later wins - so a package tweaks the dev server
|
|
103
|
+
// without editing this generated file.
|
|
104
|
+
let options: Bun.ServeFunctionOptions<unknown, {}> = {
|
|
105
|
+
port: Number(process.env.PORT ?? 5173),
|
|
106
|
+
development: { hmr: true, console: true },
|
|
107
|
+
routes: { "/*": index },
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const overrideUrl = new URL("./${BUN_DEV_OVERRIDE}", import.meta.url);
|
|
111
|
+
if (existsSync(overrideUrl)) {
|
|
112
|
+
const mod = await import(overrideUrl.href);
|
|
113
|
+
const override = typeof mod.default === "function" ? await mod.default() : mod.default;
|
|
114
|
+
options = { ...options, ...override };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const server = Bun.serve(options);
|
|
118
|
+
console.log("dev server running at " + server.url.href);
|
|
119
|
+
`
|
|
120
|
+
.trimStart()
|
|
121
|
+
.split("\n"),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** `build.ts`: a `Bun.build()` production bundle (Tailwind via the plugin API). */
|
|
127
|
+
export class BunBuildFile extends TextFile {
|
|
128
|
+
constructor(project: Project) {
|
|
129
|
+
super(project, "build.ts", {
|
|
130
|
+
marker: true,
|
|
131
|
+
readonly: true,
|
|
132
|
+
lines: String.raw`
|
|
133
|
+
import { existsSync } from "node:fs";
|
|
134
|
+
import tailwind from "bun-plugin-tailwind";
|
|
135
|
+
|
|
136
|
+
// Unmanaged override (${BUN_BUILD_OVERRIDE}): its default export is merged over
|
|
137
|
+
// the generated build options - later wins.
|
|
138
|
+
let options: Bun.BuildConfig = {
|
|
139
|
+
entrypoints: ["./index.html"],
|
|
140
|
+
outdir: "./dist",
|
|
141
|
+
minify: true,
|
|
142
|
+
sourcemap: "linked",
|
|
143
|
+
plugins: [tailwind],
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const overrideUrl = new URL("./${BUN_BUILD_OVERRIDE}", import.meta.url);
|
|
147
|
+
if (existsSync(overrideUrl)) {
|
|
148
|
+
const mod = await import(overrideUrl.href);
|
|
149
|
+
const override = typeof mod.default === "function" ? await mod.default() : mod.default;
|
|
150
|
+
options = { ...options, ...override, plugins: [...(options.plugins ?? []), ...(override.plugins ?? [])] };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = await Bun.build(options);
|
|
154
|
+
if (!result.success) {
|
|
155
|
+
for (const message of result.logs) console.error(message);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
console.log("built " + result.outputs.length + " files to " + options.outdir);
|
|
159
|
+
`
|
|
160
|
+
.trimStart()
|
|
161
|
+
.split("\n"),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
package/src/packages.ts
CHANGED
|
@@ -85,18 +85,20 @@ function nestingTagsFromSegments(segments: readonly string[]): string[] {
|
|
|
85
85
|
/** Matches a barrel `index.<ext>` (as a basename or a posix path tail). */
|
|
86
86
|
const BARREL_RE = /(^|\/)index\.(ts|tsx|js|jsx|mjs|cjs)$/;
|
|
87
87
|
|
|
88
|
-
/** Basenames this toolchain generates (projen manifests/tsconfigs +
|
|
88
|
+
/** Basenames this toolchain generates (projen manifests/tsconfigs + bun app scaffolding). */
|
|
89
89
|
const GENERATED_BASENAMES = new Set([
|
|
90
90
|
"package.json",
|
|
91
91
|
"tsconfig.json",
|
|
92
92
|
"tsconfig.dev.json",
|
|
93
|
-
"
|
|
93
|
+
"bunfig.toml",
|
|
94
|
+
"dev.ts",
|
|
95
|
+
"build.ts",
|
|
94
96
|
]);
|
|
95
97
|
|
|
96
98
|
/**
|
|
97
99
|
* True if the file matches the watcher's generated-file heuristic: projen manifest
|
|
98
|
-
* basenames, package-root barrels (`index.ts`),
|
|
99
|
-
* Other read-only toolchain output (e.g. openapi artifacts) is not covered here.
|
|
100
|
+
* basenames, package-root barrels (`index.ts`), bun app scaffolding, or declaration
|
|
101
|
+
* files. Other read-only toolchain output (e.g. openapi artifacts) is not covered here.
|
|
100
102
|
*/
|
|
101
103
|
export function isGeneratedFile(file: string): boolean {
|
|
102
104
|
const base = file.split(sep).pop() ?? "";
|
package/src/pnpm-workspace.ts
CHANGED
|
@@ -67,8 +67,8 @@ const DEFAULT_CATALOG: Catalog = {
|
|
|
67
67
|
"react-dom": "^19.2.4",
|
|
68
68
|
"@types/react": "^19.2.2",
|
|
69
69
|
"@types/react-dom": "^19.2.2",
|
|
70
|
-
|
|
71
|
-
"
|
|
70
|
+
// Tailwind v4 compiler for bun's dev server + `Bun.build` (the `app` tag).
|
|
71
|
+
"bun-plugin-tailwind": "^0.1.2",
|
|
72
72
|
"@types/node": "^24.6.0",
|
|
73
73
|
"@types/express": "^5.0.5",
|
|
74
74
|
express: "^5.1.0",
|
|
@@ -95,14 +95,26 @@ const DEFAULT_CATALOG: Catalog = {
|
|
|
95
95
|
};
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
* Build allowances every workspace needs
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* `eslint-import-resolver-typescript`, which projen's eslint
|
|
102
|
-
* every generated project
|
|
103
|
-
*
|
|
98
|
+
* Build allowances every workspace needs. These matter for the Databricks Apps
|
|
99
|
+
* pnpm install (which reads `pnpm-workspace.yaml`) and for bun (mirrored into the
|
|
100
|
+
* root `package.json` `trustedDependencies`): `unrs-resolver` is the native
|
|
101
|
+
* binding behind `eslint-import-resolver-typescript`, which projen's eslint
|
|
102
|
+
* component adds to every generated project, and `esbuild` is still pulled in by
|
|
103
|
+
* parts of the toolchain. Leaving either unlisted greets a freshly bootstrapped
|
|
104
|
+
* workspace with an "Ignored build scripts" warning on its first install.
|
|
104
105
|
*/
|
|
105
|
-
const DEFAULT_ALLOW_BUILDS: AllowBuilds = {
|
|
106
|
+
const DEFAULT_ALLOW_BUILDS: AllowBuilds = {
|
|
107
|
+
esbuild: true,
|
|
108
|
+
"unrs-resolver": true,
|
|
109
|
+
// The `bun` npm package (a peer of `bun-plugin-tailwind`) ships a `bun.exe`
|
|
110
|
+
// placeholder and downloads the real platform binary in its postinstall. Left
|
|
111
|
+
// unbuilt, that `.exe` shim lands in `node_modules/.bin/bun` and makes projen's
|
|
112
|
+
// dax PATH walk `spawn ENOEXEC` on macOS/Linux, breaking EVERY task. Building it
|
|
113
|
+
// replaces the shim with a runnable binary.
|
|
114
|
+
bun: true,
|
|
115
|
+
// fastembed's native ONNX runtime (via `@mastra/fastembed`).
|
|
116
|
+
"onnxruntime-node": true,
|
|
117
|
+
};
|
|
106
118
|
|
|
107
119
|
/**
|
|
108
120
|
* pnpm settings this engine applies to every workspace, beyond members, catalog,
|
|
@@ -207,17 +219,66 @@ export class PnpmWorkspaceState {
|
|
|
207
219
|
}
|
|
208
220
|
|
|
209
221
|
/**
|
|
210
|
-
*
|
|
222
|
+
* Emit `pnpm-workspace.yaml` directly.
|
|
223
|
+
*
|
|
224
|
+
* Under bun, projen's base `NodePackage` never runs `configurePnpm` (that call
|
|
225
|
+
* site is gated to `packageManager === PNPM`), so no `PnpmWorkspaceYaml`
|
|
226
|
+
* component is created. This engine still needs the file for the Databricks
|
|
227
|
+
* Apps platform, whose build phase installs with pnpm and reads the catalog +
|
|
228
|
+
* `allowBuilds`. The native component is just a `YamlFile` fed by a lazy
|
|
229
|
+
* `toJson(options)`, so constructing it directly (with the same options object
|
|
230
|
+
* whose arrays/objects are mutated in place up to synth) produces the identical
|
|
231
|
+
* file. Idempotent: skips if a `pnpm-workspace.yaml` component already exists
|
|
232
|
+
* (e.g. a future projen that DOES create it under bun).
|
|
233
|
+
*/
|
|
234
|
+
public attachWorkspaceFile(project: Project): void {
|
|
235
|
+
const exists = project.files.some((file) => file.path === "pnpm-workspace.yaml");
|
|
236
|
+
if (!exists) new javascript.PnpmWorkspaceYaml(project, this.options);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Fill `packages` from the project's attached subprojects, then mirror the
|
|
241
|
+
* workspace shape into the root `package.json` so bun (which reads
|
|
242
|
+
* `workspaces`/`catalog` from the manifest, not `pnpm-workspace.yaml`) resolves
|
|
243
|
+
* the same members + catalog. `trustedDependencies` (bun's `allowBuilds` analog)
|
|
244
|
+
* is rendered by projen from its own allowlist, so the build allowances are
|
|
245
|
+
* routed there via `addAllowedScripts`.
|
|
211
246
|
*
|
|
212
247
|
* Called from the root's `preSynthesize`, which is the earliest point every
|
|
213
248
|
* discovered package is attached - the list cannot be captured at
|
|
214
249
|
* construction, since the root's scan runs after it.
|
|
215
250
|
*/
|
|
216
|
-
public resolveMembers(project: Project): void {
|
|
251
|
+
public resolveMembers(project: Project, extraMembers: readonly string[] = []): void {
|
|
217
252
|
const members = project.subprojects
|
|
218
253
|
.map((sub) => toPosix(relative(project.outdir, sub.outdir)))
|
|
219
254
|
.filter(Boolean);
|
|
255
|
+
// `extraMembers` are workspace siblings NOT attached as subprojects (e.g. the
|
|
256
|
+
// self-synthesizing `projen/` engine), so they must be added explicitly.
|
|
257
|
+
const all = [...members, ...extraMembers.map((m) => toPosix(m)).filter(Boolean)];
|
|
220
258
|
// Replaces the array's CONTENTS, keeping the reference projen captured.
|
|
221
|
-
this.packages.splice(0, this.packages.length, ...new Set(
|
|
259
|
+
this.packages.splice(0, this.packages.length, ...new Set(all.sort()));
|
|
260
|
+
this.mirrorToPackageJson(project);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Write `workspaces` / `catalog` / `overrides` into the root `package.json`
|
|
265
|
+
* (bun's source of truth) and feed the build allowances into projen's
|
|
266
|
+
* allowlist so bun's native `trustedDependencies` renders them.
|
|
267
|
+
*/
|
|
268
|
+
private mirrorToPackageJson(project: Project): void {
|
|
269
|
+
const pkg = (project as { package?: javascript.NodePackage }).package;
|
|
270
|
+
if (!pkg) return;
|
|
271
|
+
pkg.addField("workspaces", [...this.packages]);
|
|
272
|
+
if (Object.keys(this.catalog).length > 0) {
|
|
273
|
+
pkg.addField("catalog", { ...this.catalog });
|
|
274
|
+
}
|
|
275
|
+
if (Object.keys(this.overrides).length > 0) {
|
|
276
|
+
pkg.addField("overrides", { ...this.overrides });
|
|
277
|
+
}
|
|
278
|
+
// projen renders bun's `trustedDependencies` from `allowedScripts`.
|
|
279
|
+
const allowed = Object.entries(this.allowBuilds)
|
|
280
|
+
.filter(([, on]) => on)
|
|
281
|
+
.map(([name]) => name);
|
|
282
|
+
if (allowed.length > 0) pkg.addAllowedScripts(...allowed);
|
|
222
283
|
}
|
|
223
284
|
}
|
package/src/project.ts
CHANGED
|
@@ -22,7 +22,13 @@ import { applyCompiledPublish } from "./publish.ts";
|
|
|
22
22
|
import { DBXToolsRelease, type StandaloneRelease } from "./release.ts";
|
|
23
23
|
import { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS, type PackageTag } from "./tags.ts";
|
|
24
24
|
import { DBXToolsRootTsconfig } from "./tsconfig.ts";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
BUN_APP_OVERRIDES,
|
|
27
|
+
BunBuildFile,
|
|
28
|
+
BunDevServerFile,
|
|
29
|
+
BunfigFile,
|
|
30
|
+
RootBunfigFile,
|
|
31
|
+
} from "./bun-app.ts";
|
|
26
32
|
import { DBXToolsVsCode } from "./vscode.ts";
|
|
27
33
|
import {
|
|
28
34
|
DEFAULT_PACKAGE_ROOTS,
|
|
@@ -147,11 +153,11 @@ function applyRepository(project: javascript.NodeProject, override?: string): vo
|
|
|
147
153
|
});
|
|
148
154
|
}
|
|
149
155
|
|
|
150
|
-
/** Inherit a parent's package manager, else
|
|
156
|
+
/** Inherit a parent's package manager, else bun. */
|
|
151
157
|
function inheritedPackageManager(
|
|
152
158
|
parent: javascript.NodeProject | undefined,
|
|
153
159
|
): javascript.NodePackageManager {
|
|
154
|
-
return parent?.package.packageManager ?? javascript.NodePackageManager.
|
|
160
|
+
return parent?.package.packageManager ?? javascript.NodePackageManager.BUN;
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
/** Override a package's generated tsconfig `compilerOptions` (later-wins per key). */
|
|
@@ -328,12 +334,19 @@ export const PROJEN_VERSION = "^0.101.16";
|
|
|
328
334
|
function defaultProjectOptions(options: DBXToolsProjectOptions): DBXToolsProjectOptions {
|
|
329
335
|
const isRoot = options.parent === undefined;
|
|
330
336
|
return {
|
|
331
|
-
|
|
337
|
+
// Bun owns install/run/build/test locally and in CI. projen renders
|
|
338
|
+
// `bun install`/`bunx` and a native `trustedDependencies` field from this.
|
|
339
|
+
// The engine still emits `pnpm-workspace.yaml` itself (see
|
|
340
|
+
// {@link PnpmWorkspaceState}) for the Databricks Apps platform, whose build
|
|
341
|
+
// phase installs with pnpm - so a deployed app keeps its catalog + build
|
|
342
|
+
// allowances even though the local/CI manager is bun.
|
|
343
|
+
packageManager: javascript.NodePackageManager.BUN,
|
|
332
344
|
// Pinned rather than left to projen's "latest": 0.101.16 is the first release
|
|
333
|
-
// whose `NodePackage`
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
//
|
|
345
|
+
// whose `NodePackage` renders bun's `trustedDependencies` natively. Under bun,
|
|
346
|
+
// projen does NOT create the `pnpm-workspace.yaml` component itself (that call
|
|
347
|
+
// site is gated to pnpm), so the engine constructs it directly ({@link
|
|
348
|
+
// PnpmWorkspaceState}). Floating would let an install cross that boundary
|
|
349
|
+
// silently, so the co-tested version is stated here and bumped deliberately.
|
|
337
350
|
projenVersion: PROJEN_VERSION,
|
|
338
351
|
defaultReleaseBranch: "main",
|
|
339
352
|
projenrcJs: false,
|
|
@@ -403,8 +416,8 @@ function copiedGitIgnoreOptions(
|
|
|
403
416
|
/**
|
|
404
417
|
* The engine's `TypeScriptProject` defaults - a superset of {@link defaultProjectOptions}.
|
|
405
418
|
* A DBXTools TS project can itself be the ROOT (a standalone compiling root), so the
|
|
406
|
-
* same parent-based root/child logic applies; this just layers on
|
|
407
|
-
* disables sample code.
|
|
419
|
+
* same parent-based root/child logic applies; this just layers on typescript +
|
|
420
|
+
* bun types and disables sample code. No `tsx`: bun runs `.ts` directly.
|
|
408
421
|
*/
|
|
409
422
|
function defaultTypeScriptProjectOptions(
|
|
410
423
|
options: DBXToolsTypeScriptProjectOptions,
|
|
@@ -417,15 +430,16 @@ function defaultTypeScriptProjectOptions(
|
|
|
417
430
|
// ESLint is configured once on the ROOT (see initProject) and lints the whole
|
|
418
431
|
// tree, so packages don't emit their own config. A caller can still override.
|
|
419
432
|
eslint: false,
|
|
420
|
-
devDeps: [...(base.devDeps ?? []), "
|
|
433
|
+
devDeps: [...(base.devDeps ?? []), "typescript@^5.9.3", "@types/bun@^1.3.14"],
|
|
421
434
|
...options,
|
|
422
435
|
...copiedGitIgnoreOptions(options),
|
|
423
436
|
};
|
|
424
437
|
}
|
|
425
438
|
|
|
426
|
-
// Pinned to match the subproject defaults so
|
|
439
|
+
// Pinned to match the subproject defaults so bun resolves a single typescript
|
|
427
440
|
// across the workspace (a bare name -> `*` could pull a second, newer major).
|
|
428
|
-
|
|
441
|
+
// `@types/bun` gives the `Bun.*` globals the server/app tags now use.
|
|
442
|
+
const DEV_DEPS_ROOT: string[] = ["typescript@^5.9.3", "@types/bun@^1.3.14"];
|
|
429
443
|
|
|
430
444
|
/** Options for {@link DBXToolsNodeProject} (the monorepo root). */
|
|
431
445
|
export interface DBXToolsProjectOptions
|
|
@@ -478,13 +492,22 @@ export interface DBXToolsProjectOptions
|
|
|
478
492
|
* `@dbx-tools/projen` engine in `projen/`, tagged `projen-v*`).
|
|
479
493
|
*/
|
|
480
494
|
readonly standaloneReleases?: readonly StandaloneRelease[];
|
|
495
|
+
/**
|
|
496
|
+
* Extra workspace member paths (repo-relative, POSIX) to list in the workspace
|
|
497
|
+
* config ALONGSIDE the discovered `packageRoots` members - for a package that
|
|
498
|
+
* is synthesized by its OWN `.projenrc.ts` (so it isn't a root subproject) but
|
|
499
|
+
* should still resolve as a workspace sibling. The `@dbx-tools/projen` engine in
|
|
500
|
+
* `projen/` is the case: it synthesizes itself (avoiding a dogfooding cycle) yet
|
|
501
|
+
* is a member of the single bun workspace, so the root links it from source.
|
|
502
|
+
*/
|
|
503
|
+
readonly extraWorkspaceMembers?: readonly string[];
|
|
481
504
|
}
|
|
482
505
|
|
|
483
506
|
/** Options for {@link DBXToolsTypeScriptProject} (a package, or a compiling root). */
|
|
484
507
|
export interface DBXToolsTypeScriptProjectOptions
|
|
485
508
|
extends Partial<typescript.TypeScriptProjectOptions>, DBXToolsProjectOptions {
|
|
486
|
-
/** Emit
|
|
487
|
-
readonly
|
|
509
|
+
/** Emit the projen-owned bun app scaffolding (`bunfig.toml`/`dev.ts`/`build.ts`). */
|
|
510
|
+
readonly bunApp?: boolean;
|
|
488
511
|
}
|
|
489
512
|
|
|
490
513
|
/**
|
|
@@ -498,6 +521,7 @@ export class DBXToolsNodeProject extends javascript.NodeProject implements DBXTo
|
|
|
498
521
|
pnpmWorkspace?: PnpmWorkspaceState;
|
|
499
522
|
rootTsconfig?: DBXToolsRootTsconfig;
|
|
500
523
|
vsCode?: DBXToolsVsCode;
|
|
524
|
+
private readonly extraWorkspaceMembers: readonly string[];
|
|
501
525
|
|
|
502
526
|
constructor(options: DBXToolsProjectOptions = {}) {
|
|
503
527
|
const { name, scope } = resolveIdentity(options);
|
|
@@ -505,11 +529,12 @@ export class DBXToolsNodeProject extends javascript.NodeProject implements DBXTo
|
|
|
505
529
|
options.release && options.releaseTrigger === undefined
|
|
506
530
|
? { releaseTrigger: ReleaseTrigger.tagged({ tags: ["v*"] }) }
|
|
507
531
|
: {};
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
// `
|
|
532
|
+
// Holds the workspace state (members/catalog/allowBuilds/overrides). Under
|
|
533
|
+
// bun, projen's base constructor does NOT create the `PnpmWorkspaceYaml`
|
|
534
|
+
// component (its `configurePnpm` call site is gated to pnpm), so this state's
|
|
535
|
+
// options are wired into a directly-constructed component below - AND mirrored
|
|
536
|
+
// into `package.json` (`workspaces`/`catalog`) for bun to read. The
|
|
537
|
+
// `pnpm-workspace.yaml` is still emitted for the Databricks Apps pnpm install.
|
|
513
538
|
const pnpmWorkspace = new PnpmWorkspaceState(options);
|
|
514
539
|
super({
|
|
515
540
|
...defaultProjectOptions(options),
|
|
@@ -522,7 +547,12 @@ export class DBXToolsNodeProject extends javascript.NodeProject implements DBXTo
|
|
|
522
547
|
});
|
|
523
548
|
|
|
524
549
|
this.pnpmWorkspace = pnpmWorkspace;
|
|
550
|
+
// Emit `pnpm-workspace.yaml` ourselves: under bun projen skips the native
|
|
551
|
+
// component, but the file is still required by the Databricks Apps platform
|
|
552
|
+
// (its build phase installs with pnpm and reads catalog + `allowBuilds`).
|
|
553
|
+
pnpmWorkspace.attachWorkspaceFile(this);
|
|
525
554
|
this.scope = scope;
|
|
555
|
+
this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
|
|
526
556
|
this.dbxToolsConfig = new DBXToolsConfig(this, options);
|
|
527
557
|
initProject(this, options);
|
|
528
558
|
}
|
|
@@ -531,7 +561,8 @@ export class DBXToolsNodeProject extends javascript.NodeProject implements DBXTo
|
|
|
531
561
|
super.preSynthesize();
|
|
532
562
|
// Members come from the attached subprojects, which the root's scan appends
|
|
533
563
|
// after construction - so the list is filled here, not in the constructor.
|
|
534
|
-
|
|
564
|
+
// `extraWorkspaceMembers` adds self-synthesizing siblings (e.g. `projen/`).
|
|
565
|
+
this.pnpmWorkspace?.resolveMembers(this, this.extraWorkspaceMembers);
|
|
535
566
|
preSynthesizeProject(this);
|
|
536
567
|
}
|
|
537
568
|
}
|
|
@@ -588,8 +619,19 @@ export class DBXToolsTypeScriptProject
|
|
|
588
619
|
"./package.json": "./package.json",
|
|
589
620
|
});
|
|
590
621
|
addPackageFiles(this, "index.ts", "src");
|
|
591
|
-
|
|
592
|
-
|
|
622
|
+
// `bun test` intercepts `node:test` (the suites keep using node:test) and
|
|
623
|
+
// runs it with bun's own fast runner. Args are FILTERS, not globs; a bare
|
|
624
|
+
// directory auto-discovers `*.test.ts` recursively. But `bun test` EXITS 1
|
|
625
|
+
// when it matches no files (unlike the old `tsx --test 'glob'`, which was a
|
|
626
|
+
// no-op), so guard it: only invoke when a `*.test.ts` exists, else succeed.
|
|
627
|
+
this.testTask.exec(
|
|
628
|
+
'find test -name "*.test.ts" 2>/dev/null | grep -q . && bun test test || true',
|
|
629
|
+
);
|
|
630
|
+
if (options.bunApp ?? false) {
|
|
631
|
+
new BunfigFile(this);
|
|
632
|
+
new BunDevServerFile(this);
|
|
633
|
+
new BunBuildFile(this);
|
|
634
|
+
}
|
|
593
635
|
initProject(this, options);
|
|
594
636
|
}
|
|
595
637
|
|
|
@@ -746,16 +788,17 @@ function registerRootTasks(project: javascript.NodeProject): void {
|
|
|
746
788
|
}
|
|
747
789
|
|
|
748
790
|
/**
|
|
749
|
-
* `
|
|
791
|
+
* `bun node_modules/@dbx-tools/projen/tasks/<script>` command for a projen task.
|
|
750
792
|
*
|
|
751
|
-
* Use the stable package symlink, never `require.resolve()`'s physical
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
793
|
+
* Use the stable package symlink, never `require.resolve()`'s physical store
|
|
794
|
+
* path. A later install can change the peer-hash directory while leaving the
|
|
795
|
+
* package symlink valid; persisting the physical path made every generated task
|
|
796
|
+
* fail with ERR_MODULE_NOT_FOUND after such an update. bun runs the `.ts`
|
|
797
|
+
* directly (no tsx, no build step).
|
|
755
798
|
*/
|
|
756
799
|
export function taskScript(_project: javascript.NodeProject, script: string, args = ""): string {
|
|
757
800
|
const scriptPath = toPosix(join("node_modules", "@dbx-tools", "projen", "tasks", script));
|
|
758
|
-
return args ? `
|
|
801
|
+
return args ? `bun ${scriptPath} ${args}` : `bun ${scriptPath}`;
|
|
759
802
|
}
|
|
760
803
|
|
|
761
804
|
/**
|
|
@@ -788,20 +831,21 @@ function initProject(
|
|
|
788
831
|
project.package.file.readonly = false;
|
|
789
832
|
|
|
790
833
|
// NodeProject has no built-in TS projenrc support (unlike TypeScriptProject), so
|
|
791
|
-
// wire `.projenrc.ts` through
|
|
792
|
-
//
|
|
834
|
+
// wire `.projenrc.ts` through a runner - this also populates the `default` task
|
|
835
|
+
// that `bunx projen` runs (and that the `sync` watcher invokes to re-synth).
|
|
836
|
+
// The runner choice is immaterial since the exec is reset to plain `bun` below;
|
|
837
|
+
// `nodejs()` avoids declaring a `ts-node`/`tsx` dependency.
|
|
793
838
|
new typescript.ProjenrcTs(project, {
|
|
794
|
-
runner: typescript.TypeScriptRunner.
|
|
839
|
+
runner: typescript.TypeScriptRunner.nodejs(),
|
|
795
840
|
});
|
|
796
|
-
//
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
//
|
|
802
|
-
//
|
|
803
|
-
|
|
804
|
-
project.defaultTask?.reset("tsx .projenrc.ts");
|
|
841
|
+
// bun runs `.projenrc.ts` directly (native TS, no loader to register). Reset to
|
|
842
|
+
// a plain `bun` exec rather than any wrapper: the default task is spawned by
|
|
843
|
+
// nested installs/synths, and a wrapper that exported `npm_config_*` broke them.
|
|
844
|
+
project.defaultTask?.reset("bun .projenrc.ts");
|
|
845
|
+
|
|
846
|
+
// Pin bun's hoisted linker workspace-wide (see RootBunfigFile) so a peer dep
|
|
847
|
+
// resolves to one copy and singletons/types stay coherent.
|
|
848
|
+
new RootBunfigFile(project);
|
|
805
849
|
|
|
806
850
|
// Only reached on a ROOT (early-returned above otherwise), so the root devDeps
|
|
807
851
|
// always apply; the self-dep is added only when the engine is an installed pkg.
|
|
@@ -864,11 +908,12 @@ function initProject(
|
|
|
864
908
|
eslint.addIgnorePattern(`${root}/openapi/**`);
|
|
865
909
|
eslint.addIgnorePattern(`${root}/**/index.ts`);
|
|
866
910
|
}
|
|
867
|
-
|
|
868
|
-
//
|
|
869
|
-
//
|
|
870
|
-
|
|
871
|
-
|
|
911
|
+
// The generated bun app scripts + unmanaged overrides live at the package root,
|
|
912
|
+
// outside any `src/**` tsconfig include, so the type-aware parser cannot resolve
|
|
913
|
+
// them to a project. ESLint still cannot parse them.
|
|
914
|
+
eslint.addIgnorePattern("**/dev.ts");
|
|
915
|
+
eslint.addIgnorePattern("**/build.ts");
|
|
916
|
+
for (const override of BUN_APP_OVERRIDES) {
|
|
872
917
|
eslint.addIgnorePattern(`**/${override}`);
|
|
873
918
|
}
|
|
874
919
|
// Codegen packages declare `codegen.inputs` via mixins after construction; ignore
|