@dbx-tools/projen 0.9.12 → 0.9.18

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/README.md CHANGED
@@ -184,8 +184,10 @@ Foreign callback adapters must first be wrapped in an object created by their
184
184
  own native library (`createStorageHandle` for auth), because callback registries
185
185
  are library-local. Release wheels replace sibling Git requirements with matching
186
186
  native-wheel versions, and dependent publishers wait for their dependencies.
187
- Each crate builds its own `<crate>-uniffi-bindgen` executable so a workspace
188
- build has no colliding binary outputs. Packaging runs that prebuilt executable.
187
+ Each crate builds its own `<crate>-uniffi-bindgen` executable so one target row
188
+ has no colliding binary outputs. The executable requires the generated
189
+ `uniffi-bindgen` feature, which enables `uniffi/cli` only in the UniFFI matrix.
190
+ Packaging runs that prebuilt executable.
189
191
  Cargo manifests, target config, and UniFFI config are generated from structured
190
192
  Projen `TomlFile` objects. Local and release Python generation share one
191
193
  dependency-free helper for generator arguments, target-specific executable
@@ -231,13 +233,14 @@ branch that already contains released `main`, and merges `main` into a diverged
231
233
  branch when the merge is conflict-free. Missing branches and conflicted merges
232
234
  are left untouched.
233
235
 
234
- The Rust matrix has one row per target. Each row installs native dependencies,
235
- builds the Cargo workspace once, then packages every discovered output from
236
- that shared build. Set a source-only crate's or
237
- release-enabled binary's `releaseExcludeOs` package option to omit it from
238
- incompatible rows through Cargo `--exclude`. Release binary packaging and
239
- artifact upload are skipped in those rows. UniFFI crates cannot use this option
240
- because every configured target must produce their artifacts.
236
+ Rust release generation creates one uncached matrix with one row per target.
237
+ Each row builds all discovered bindings and selected release binaries together
238
+ with the union of their required features, then packages every native artifact
239
+ from that one Cargo output. Set a source-only crate's or release-enabled
240
+ binary's `releaseExcludeOs` package option to omit it from incompatible rows.
241
+ Release binary packaging and artifact upload are skipped in those rows. UniFFI
242
+ crates cannot use this option because every configured target must produce
243
+ their artifacts.
241
244
  Set a release binary's `cli` package option and the workspace
242
245
  `cliRegistryPath` to generate a typed `dbx` command registry from the same
243
246
  selected targets. The generated entries carry only the archives that the
@@ -249,18 +252,12 @@ archives and Python wheels; they do not install Bun or UBRN and do not build
249
252
  Node facades. A binary-only row therefore installs no language package tool.
250
253
  `rustVersion` remains the MSRV recorded in package manifests, while
251
254
  `releaseRustVersion` independently defaults release compilation to `stable`.
252
- Stable Windows rows verify and use the hosted runner's installed Rust toolchain
253
- and select `rust-lld` for the workspace build. Rust release rows restore and
254
- update dependency-only Cargo caches in the release branch's cache scope. The
255
- cache key excludes workspace version changes, and manual tag recovery restores
256
- without saving a tag-scoped copy. There is no separate cache workflow or
257
- sccache layer. After publishing the current raw Rust bundles and build manifests,
258
- the GitHub release job deletes those internal assets from published
259
- `vMAJOR.MINOR.PATCH` releases strictly lower than the current version while
260
- leaving versioned consumer binaries in place. Phase timings are written to each
261
- build log. Python generation executes the already-built
262
- `target/<triple>/release/<crate>-uniffi-bindgen` directly. Artifact packaging therefore
263
- does no Rust compilation after the main workspace build.
255
+ Rows use the target runner's standard Rust toolchain without sccache, Cargo
256
+ cache actions, source fingerprints, or reusable raw bundles. Phase timings are
257
+ written to each build log. GitHub-hosted Python generation executes the
258
+ already-built `target/<triple>/release/<crate>-uniffi-bindgen` directly. A local
259
+ macOS build compiles one host generator and reuses it while packaging the
260
+ Darwin, Linux, and Windows libraries.
264
261
 
265
262
  Artifacts identify their crate, target, and type. Rust jobs publish non-private
266
263
  Cargo crates with `cargo publish --no-verify` and upload requested binary assets
@@ -277,6 +274,16 @@ architecture. Omit both filters to regenerate the complete maintained matrix.
277
274
  `DBX_TOOLS_RELEASE_PLATFORMS` can select the generated matrix without repeating
278
275
  environment parsing in a consumer.
279
276
 
277
+ `bun run release --build auto` is the default. It selects a local build when
278
+ the chosen GitHub CLI account has maintain/admin access, the host is macOS, and
279
+ Cargo, Zig, cargo-zigbuild, cargo-xwin, LLVM, uv, and zip are available.
280
+ Otherwise it selects the GitHub matrix. `--build local` and `--build remote`
281
+ force the choice. Local mode builds the exact merged release SHA and uploads
282
+ the archives plus a checksum manifest to the draft GitHub Release before
283
+ registry publication continues. A manager can rerun an interrupted upload with
284
+ `bun run release:assets --version <version> --tag <tag> --upload` from the
285
+ matching release source.
286
+
280
287
  Public UniFFI facades are marked with `dbxToolsConfig.uniffi = true` in Node
281
288
  manifests and `[tool.dbx_tools.config] uniffi = true` in Python manifests. The
282
289
  Node jobs consume same-run artifacts, publish native archives first with npm
@@ -478,14 +485,15 @@ bootstrap a folder that has no `.projenrc.ts` or toolchain yet.
478
485
 
479
486
  ## Run Tasks From The ROOT
480
487
 
481
- Every repo-wide task lives on the root, and the root's `compile` / `test`
482
- delegate with `bun run --filter '*'` rather than emitting a step per member - so
483
- a new package is covered without a re-synth. Work from the root:
488
+ Every repo-wide task lives on the root. `compile` batches ordinary TypeScript
489
+ packages in up to four `tsc --build` processes and runs custom compile tasks alongside them;
490
+ `test` delegates with `bun run --filter '*'`. Both read the current workspace
491
+ list, so a new package is covered without a re-synth. Work from the root:
484
492
 
485
493
  | Task | What it does |
486
494
  | ------------------------------ | ---------------------------------------------------- |
487
495
  | `bun run build` | synth + workspace compile and tests |
488
- | `bun run compile` | `tsc --build` in each member, in parallel |
496
+ | `bun run compile` | Batched `tsc --build` plus custom member compiles |
489
497
  | `bun run test` | `eslint` once, then each member's tests |
490
498
  | `bun run sync` | re-synth (`--watch` to keep synthing) |
491
499
  | `bun run barrels` | regenerate the read-only `index.ts` barrels |
package/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
 
5
5
  export const PACKAGE_IDENTIFIER = "@dbx-tools/projen";
6
- export const PACKAGE_VERSION = "0.9.12";
6
+ export const PACKAGE_VERSION = "0.9.18";
7
7
  export * as barrels from "./src/barrels.ts";
8
8
  export * as bunApp from "./src/bun-app.ts";
9
9
  export * as bunWorkflow from "./src/bun-workflow.ts";
@@ -57,7 +57,7 @@ export type { DBXToolsJavaScriptProject, DBXToolsReleaseMode, PullRequestTitlePo
57
57
  export { DBXToolsPythonProject, DBXToolsPythonWorkspace } from "./src/project-py.ts";
58
58
  export type { PythonRepositoryOptions, PythonPackageOptions, PythonTrustedPublisherOptions, DBXToolsPythonProjectOptions, PythonReleaseOptions, DBXToolsPythonWorkspaceOptions } from "./src/project-py.ts";
59
59
  export { DBXToolsRustProject, RustReleaseOs, RustReleaseCpu, UNIFFI_RELEASE_TARGETS, DBXToolsRustWorkspace } from "./src/project-rs.ts";
60
- export type { CargoDependency, CargoDependencyOptions, CargoExampleOptions, DBXToolsRustProjectOptions, RustCrateOptions, RustCliOptions, DBXToolsRustWorkspaceOptions, RustReleasePlatform, UniFFIReleaseTarget, RustBindingMapping, RustWorkspaceMapping, RustReleaseBinaryAssetMapping, RustReleaseBinaryMapping } from "./src/project-rs.ts";
60
+ export type { CargoDependency, CargoDependencyOptions, CargoExampleOptions, DBXToolsRustProjectOptions, RustCrateOptions, RustCliOptions, RustOpenApiOptions, DBXToolsRustWorkspaceOptions, RustReleasePlatform, UniFFIReleaseTarget, RustBindingMapping, RustOpenApiMapping, RustWorkspaceMapping, RustReleaseBinaryAssetMapping, RustReleaseBinaryMapping } from "./src/project-rs.ts";
61
61
  export { PROJEN_VERSION } from "./src/projen-version.ts";
62
62
  export { COMPILED_DIR, COMPILED_COMPILER_OPTIONS } from "./src/publish.ts";
63
63
  export { DBXToolsRelease } from "./src/release.ts";
@@ -66,7 +66,7 @@ export { DBXToolsReleaseCatalog } from "./src/release-catalog.ts";
66
66
  export type { DBXToolsVersioningMode, ReleaseProjectLanguage, ReleaseArtifactKind, ReleaseEdgeKind, ReleasePropagation, ReleaseUnitRule, DBXToolsReleaseCatalogOptions, ReleaseDependencyInput, ReleaseProjectRegistration, ExternalReleaseProjectRegistration, ReleaseArtifactRegistration, ReleaseProjectNode, ReleaseArtifact, ReleaseDependencyEdge, ReleaseUnit, ReleaseUnitGraph } from "./src/release-catalog.ts";
67
67
  export { RELEASE_TAG, RELEASE_SHA, RELEASE_VERSION, RELEASE_SUMMARY_DIRECTORY, RELEASE_SUMMARY_PROVIDER_NAMES, RELEASE_SUMMARY_FILE } from "./src/release-dispatch.ts";
68
68
  export type { ReleaseSummaryProviderName } from "./src/release-dispatch.ts";
69
- export type { GithubRepositoryIdentity, GithubAuthenticatedAccount } from "./src/release-github.ts";
69
+ export type { GithubRepositoryIdentity, GithubAuthenticatedAccount, GithubRepositoryPermissions } from "./src/release-github.ts";
70
70
  export type { ReleaseReason, PlannedReleaseUnit, PlannedPackage, PlannedArtifact, PlannedRustTarget, ReleasePlan } from "./src/release-plan.ts";
71
71
  export { ReleaseUnitWorkspacePlugin } from "./src/release-please.ts";
72
72
  export type { ReleaseUnitWorkspacePluginOptions } from "./src/release-please.ts";
@@ -76,6 +76,7 @@ export { DBXToolsRootTsconfig } from "./src/tsconfig.ts";
76
76
  export { makeDefaultedInterfaceParametersOptional, removeObsoleteInterfaceAliases, addTypeScriptExtensionsToBindingImports, addExplicitInterfaceReexports } from "./src/uniffi.ts";
77
77
  export type { TypeScriptBindingModule } from "./src/uniffi.ts";
78
78
  export { DBXToolsVsCode } from "./src/vscode.ts";
79
- export type { IgnoreGroupOptions } from "./src/watch.ts";
79
+ export type { IgnoreGroupOptions, WatchLoopOptions } from "./src/watch.ts";
80
+ export type { WorkspaceMutationLockOptions } from "./src/workspace-lock.ts";
80
81
  export { VERSION_FILE, DEFAULT_VERSION } from "./src/workspace-version.ts";
81
82
  export type { Semver, VersionLevel } from "./src/workspace-version.ts";
package/package.json CHANGED
@@ -2,7 +2,6 @@
2
2
  "name": "@dbx-tools/projen",
3
3
  "scripts": {
4
4
  "build": "projen build",
5
- "bundle:rust-release": "projen bundle:rust-release",
6
5
  "clobber": "projen clobber",
7
6
  "compile": "projen compile",
8
7
  "default": "projen default",
@@ -30,9 +29,9 @@
30
29
  },
31
30
  "dependencies": {
32
31
  "@clack/prompts": "^1.7.0",
33
- "@dbx-tools/core": "^0.9.12",
34
- "@dbx-tools/path": "^0.9.12",
35
- "@dbx-tools/shared-core": "^0.9.12",
32
+ "@dbx-tools/core": "^0.9.18",
33
+ "@dbx-tools/path": "^0.9.18",
34
+ "@dbx-tools/shared-core": "^0.9.18",
36
35
  "commander": "^15.0.0",
37
36
  "concurrently": "^10.0.3",
38
37
  "constructs": "^10.6.0",
@@ -53,7 +52,7 @@
53
52
  },
54
53
  "main": "index.ts",
55
54
  "license": "Apache-2.0",
56
- "version": "0.9.12",
55
+ "version": "0.9.18",
57
56
  "types": "index.ts",
58
57
  "type": "module",
59
58
  "exports": {
@@ -22,6 +22,16 @@ export type ReleaseArch = (typeof RELEASE_ARCHES)[number];
22
22
 
23
23
  export type { VersionLevel } from "./workspace-version.ts";
24
24
 
25
+ /** Stable archive name for one native release binary. */
26
+ export function releaseBinaryAssetName(
27
+ binaryName: string,
28
+ nodeTarget: string,
29
+ operatingSystem: ReleaseOs,
30
+ ): string {
31
+ const extension = operatingSystem === "win32" ? "zip" : "tar.gz";
32
+ return `${binaryName}-${nodeTarget}.${extension}`;
33
+ }
34
+
25
35
  function collectValue<T extends string>(value: T, previous: T[]): T[] {
26
36
  return [...previous, value];
27
37
  }
@@ -2,13 +2,15 @@
2
2
  import { existsSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { basename, join, resolve } from "node:path";
4
4
  import * as projectUtils from "@dbx-tools/core/project-utils";
5
- import { stringUtils } from "@dbx-tools/shared-core";
5
+ import { object, stringUtils } from "@dbx-tools/shared-core";
6
6
  import { License, Project, TextFile, TomlFile, javascript, type Task } from "projen";
7
7
  import { DBX_TOOLS_LICENSE, projectRepositoryUrl } from "./project-js.ts";
8
8
  import type { RustReleaseOs } from "./project-rs.ts";
9
9
  import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
10
10
  import { readWorkspaceVersion } from "./workspace-version.ts";
11
11
 
12
+ export const UNIFFI_BINDGEN_FEATURE = "uniffi-bindgen";
13
+
12
14
  export interface CargoDependencyOptions {
13
15
  readonly version?: string;
14
16
  readonly workspace?: boolean;
@@ -50,6 +52,16 @@ export interface CargoExampleOptions {
50
52
  readonly requiredFeatures?: readonly string[];
51
53
  }
52
54
 
55
+ /** Rust code-first OpenAPI producer consumed by the shared generator. */
56
+ export interface RustOpenApiOptions {
57
+ /** Cargo binary that handles `--generate-spec` when the package has multiple binaries. */
58
+ readonly binary?: string;
59
+ /** Features enabled while running the OpenAPI export command. */
60
+ readonly features?: readonly string[];
61
+ /** Disable the crate's default features while running the export command. */
62
+ readonly noDefaultFeatures?: boolean;
63
+ }
64
+
53
65
  /** Cargo package, target, binding, and release behavior shared by every Rust project. */
54
66
  export interface RustCrateOptions {
55
67
  readonly description?: string;
@@ -59,6 +71,8 @@ export interface RustCrateOptions {
59
71
  readonly release?: boolean;
60
72
  /** Omit this crate and any release binary artifact from these operating systems. */
61
73
  readonly releaseExcludeOs?: readonly RustReleaseOs[];
74
+ /** Cargo features used only by the macOS cross-platform release builder. */
75
+ readonly releaseLocalFeatures?: readonly string[];
62
76
  readonly dependencies?: Readonly<Record<string, CargoDependency>>;
63
77
  /** Cargo dependencies scoped by a target cfg expression. */
64
78
  readonly targetDependencies?: Readonly<Record<string, Readonly<Record<string, CargoDependency>>>>;
@@ -67,6 +81,8 @@ export interface RustCrateOptions {
67
81
  readonly defaultFeatures?: readonly string[];
68
82
  /** Explicit example targets, including optional Cargo feature gates. */
69
83
  readonly examples?: readonly CargoExampleOptions[];
84
+ /** Generate an OpenAPI client package from this crate's aide document. */
85
+ readonly openapi?: boolean | RustOpenApiOptions;
70
86
  /** Cargo and release executable name. Defaults to the generated package name. */
71
87
  readonly binaryName?: string;
72
88
  /** Additional Cargo binary targets owned by this crate. */
@@ -106,29 +122,31 @@ export interface DBXToolsRustProjectOptions extends DBXToolsProjectOptions, Rust
106
122
  readonly repository?: string;
107
123
  }
108
124
 
109
- function rustSources(directory: string): string[] {
110
- if (!existsSync(directory)) return [];
111
- const files: string[] = [];
125
+ function* rustSources(directory: string): Generator<string> {
126
+ if (!existsSync(directory)) return;
112
127
  for (const entry of readdirSync(directory, { withFileTypes: true })) {
113
128
  const path = join(directory, entry.name);
114
- if (entry.isDirectory()) files.push(...rustSources(path));
115
- else if (entry.isFile() && entry.name.endsWith(".rs")) files.push(path);
129
+ if (entry.isDirectory()) yield* rustSources(path);
130
+ else if (entry.isFile() && entry.name.endsWith(".rs")) yield path;
116
131
  }
117
- return files;
118
132
  }
119
133
 
120
134
  /** Whether a Rust crate embeds the UniFFI proc-macro scaffolding marker. */
121
135
  export function hasUniFFIBindings(directory: string): boolean {
122
- return rustSources(join(directory, "src")).some((path) =>
123
- /\buniffi\s*::\s*setup_scaffolding\s*!\s*\(/.test(readFileSync(path, "utf8")),
124
- );
136
+ return object
137
+ .sequence(rustSources(join(directory, "src")))
138
+ .some((path) => /\buniffi\s*::\s*setup_scaffolding\s*!\s*\(/.test(readFileSync(path, "utf8")));
139
+ }
140
+
141
+ function hasRustSources(directory: string): boolean {
142
+ return object.sequence(rustSources(directory)).some(() => true);
125
143
  }
126
144
 
127
145
  export function discoverRustCrates(root: string): string[] {
128
146
  if (!existsSync(root)) return [];
129
147
  return readdirSync(root, { withFileTypes: true })
130
148
  .filter((entry) => entry.isDirectory())
131
- .filter((entry) => rustSources(join(root, entry.name, "src")).length > 0)
149
+ .filter((entry) => hasRustSources(join(root, entry.name, "src")))
132
150
  .map((entry) => entry.name)
133
151
  .sort();
134
152
  }
@@ -205,11 +223,13 @@ function packageOptions(
205
223
  ...(options.private !== undefined ? { private: options.private } : {}),
206
224
  ...(options.release !== undefined ? { release: options.release } : {}),
207
225
  ...(options.releaseExcludeOs ? { releaseExcludeOs: options.releaseExcludeOs } : {}),
226
+ ...(options.releaseLocalFeatures ? { releaseLocalFeatures: options.releaseLocalFeatures } : {}),
208
227
  ...(options.dependencies ? { dependencies: options.dependencies } : {}),
209
228
  ...(options.targetDependencies ? { targetDependencies: options.targetDependencies } : {}),
210
229
  ...(options.devDependencies ? { devDependencies: options.devDependencies } : {}),
211
230
  ...(options.features ? { features: options.features } : {}),
212
231
  ...(options.defaultFeatures ? { defaultFeatures: options.defaultFeatures } : {}),
232
+ ...(options.openapi !== undefined ? { openapi: options.openapi } : {}),
213
233
  ...(options.binaryName ? { binaryName: options.binaryName } : {}),
214
234
  ...(options.binaries ? { binaries: options.binaries } : {}),
215
235
  ...(options.cli !== undefined ? { cli: options.cli } : {}),
@@ -291,7 +311,13 @@ export class RustProject extends Project implements DBXToolsProject {
291
311
  ? {
292
312
  bin: [
293
313
  ...(this.uniffi
294
- ? [{ name: `${this.crateName}-uniffi-bindgen`, path: "uniffi-bindgen.rs" }]
314
+ ? [
315
+ {
316
+ name: `${this.crateName}-uniffi-bindgen`,
317
+ path: "uniffi-bindgen.rs",
318
+ "required-features": [UNIFFI_BINDGEN_FEATURE],
319
+ },
320
+ ]
295
321
  : []),
296
322
  ...(binary ? [{ name: binaryName, path: "src/main.rs" }] : []),
297
323
  ...(options.binaries ?? []).map((target) => ({
@@ -304,11 +330,12 @@ export class RustProject extends Project implements DBXToolsProject {
304
330
  ],
305
331
  }
306
332
  : {}),
307
- ...(options.features || options.defaultFeatures
333
+ ...(this.uniffi || options.features || options.defaultFeatures
308
334
  ? {
309
335
  features: {
310
336
  ...(options.defaultFeatures ? { default: [...options.defaultFeatures] } : {}),
311
337
  ...options.features,
338
+ ...(this.uniffi ? { [UNIFFI_BINDGEN_FEATURE]: ["uniffi/cli"] } : {}),
312
339
  },
313
340
  }
314
341
  : {}),