@dbx-tools/projen 0.9.40 → 0.9.43

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
@@ -58,8 +58,8 @@ workflow.
58
58
  Repository policy stays in the consuming `.projenrc.ts`:
59
59
 
60
60
  - `releaseDocs` supplies repository-defined preparation and build steps plus
61
- the Pages artifact path. The engine adds release checkout, Bun caching,
62
- artifact upload, and deployment without naming a docs script or output tree.
61
+ the Pages artifact path. The engine adds release checkout, artifact upload,
62
+ and deployment without naming a docs script or output tree.
63
63
  - `releasePythonRoot` passes the actual Python package root to local release
64
64
  preparation. Omit it when the workspace has no standard Python packages.
65
65
  - `releaseValidationTasks` names repository tasks that must pass in tag CI
@@ -68,8 +68,6 @@ Repository policy stays in the consuming `.projenrc.ts`:
68
68
  shared release job before the validation tasks run.
69
69
  - `pullRequestTitlePolicy` configures semantic title types and scope policy.
70
70
  Omit it or pass `false` to disable the title job.
71
- - `workflowCacheIgnorePaths` excludes generated output trees that may contain
72
- package manifests from the dependency-only Bun cache key.
73
71
  - `extraWorkspaceMembers` declares self-synthesizing tooling packages outside
74
72
  `packageRoots`. Their version, generated entrypoint, formatting, linting, and
75
73
  workspace membership are derived from that declaration.
@@ -389,10 +387,10 @@ diverged. From `main`, it calls the existing `bump` task, commits the generated
389
387
  version changes, pushes `main`, and pushes the matching annotated `vX.Y.Z` tag.
390
388
  Pass `--no-bump` only to release an existing synchronized local bump. The tag
391
389
  workflow verifies that the tag points at the exact `origin/main` commit. One
392
- `build-release` job restores the Bun cache and installs workspace dependencies,
393
- runs validation, packs the npm archives, builds all Python distributions, and
394
- builds the documentation site. Install validation prerequisites through
395
- `releaseSetupSteps`; `releaseDocs.prepareSteps` runs after validation.
390
+ `build-release` job installs workspace dependencies, runs validation, packs the
391
+ npm archives, builds all Python distributions, and builds the documentation
392
+ site. Install validation prerequisites through `releaseSetupSteps`;
393
+ `releaseDocs.prepareSteps` runs after validation.
396
394
 
397
395
  Publication jobs download the resulting artifacts rather than rebuilding the
398
396
  workspace. Each Python package retains its own publishing environment and waits
@@ -458,33 +456,32 @@ workflow order without introducing another version owner.
458
456
 
459
457
  ### `release`
460
458
 
461
- ```text
462
- Usage: release [options]
463
-
464
459
  Prepare an annotated release and select its build and publication steps
465
460
 
466
- Options:
467
- --root <path> repository root
468
- --branch <name> release branch (default: "main")
469
- --prefix <prefix> release tag prefix (default: "v")
470
- --remote <name> git remote (default: "origin")
471
- --python-root <path> Python package root for local publish (default: "packages/py")
472
- --validate <task> task to run before pushing (default: [])
473
- --no-bump use an existing synchronized local version bump
474
- --publish <target> publication scope (choices: "auto", "npm", "pypi", "local",
475
- "none", default: "auto")
476
- --install <mode> local workspace dependency installation (choices: "auto",
477
- "always", "never", default: "auto")
478
- --no-npm skip npm build and publication, including local npm publication
479
- --no-pypi skip Python build and publication, including local Python
480
- publication
481
- --docs build and deploy docs for a selected scope
482
- --no-docs skip documentation build and deployment
483
- --no-validation skip optional release validation tasks; version/source checks
484
- remain mandatory
485
- --no-local-publish skip publishing to configured local registries
486
- --local-registry <auto|false|url> local npm registry selection (default: "auto")
487
- --local-pypi <auto|false|url> local devpi registry selection (default: "auto")
461
+ ```sh
462
+ release [options]
488
463
  ```
489
464
 
465
+ #### Options
466
+
467
+ | Option | Description |
468
+ | ------------------------------------- | --------------------------------------------------------------------------------------------- |
469
+ | `--root <path>` | repository root |
470
+ | `--branch <name>` | release branch (default: "main") |
471
+ | `--prefix <prefix>` | release tag prefix (default: "v") |
472
+ | `--remote <name>` | git remote (default: "origin") |
473
+ | `--python-root <path>` | Python package root for local publish (default: "packages/py") |
474
+ | `--validate <task>` | task to run before pushing (default: []) |
475
+ | `--no-bump` | use an existing synchronized local version bump |
476
+ | `--publish <target>` | publication scope (choices: "auto", "npm", "pypi", "local", "none", default: "auto") |
477
+ | `--install <mode>` | local workspace dependency installation (choices: "auto", "always", "never", default: "auto") |
478
+ | `--no-npm` | skip npm build and publication, including local npm publication |
479
+ | `--no-pypi` | skip Python build and publication, including local Python publication |
480
+ | `--docs` | build and deploy docs for a selected scope |
481
+ | `--no-docs` | skip documentation build and deployment |
482
+ | `--no-validation` | skip optional release validation tasks; version/source checks remain mandatory |
483
+ | `--no-local-publish` | skip publishing to configured local registries |
484
+ | `--local-registry <auto\|false\|url>` | local npm registry selection (default: "auto") |
485
+ | `--local-pypi <auto\|false\|url>` | local devpi registry selection (default: "auto") |
486
+
490
487
  <!-- cli-reference:end -->
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.40";
6
+ export const PACKAGE_VERSION = "0.9.43";
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";
@@ -37,7 +37,6 @@ export * as workspaceLock from "./src/workspace-lock.ts";
37
37
  export * as workspaceVersion from "./src/workspace-version.ts";
38
38
  export { BUN_DEV_OVERRIDE, BUN_BUILD_OVERRIDE, BUN_APP_OVERRIDES, RootBunfigFile, BunfigFile, BunDevServerFile, BunBuildFile } from "./src/bun-app.ts";
39
39
  export { BUN_VERSION } from "./src/bun-workflow.ts";
40
- export type { BunWorkflowCacheOptions } from "./src/bun-workflow.ts";
41
40
  export { DBXToolsConfig } from "./src/dbx-tools-config.ts";
42
41
  export type { DBXToolsConfigOptions } from "./src/dbx-tools-config.ts";
43
42
  export { resolvePkgRoot } from "./src/engine-root.ts";
package/package.json CHANGED
@@ -32,9 +32,9 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@clack/prompts": "^1.7.0",
35
- "@dbx-tools/core": "^0.9.40",
36
- "@dbx-tools/path": "^0.9.40",
37
- "@dbx-tools/shared-core": "^0.9.40",
35
+ "@dbx-tools/core": "^0.9.43",
36
+ "@dbx-tools/path": "^0.9.43",
37
+ "@dbx-tools/shared-core": "^0.9.43",
38
38
  "commander": "^15.0.0",
39
39
  "concurrently": "^10.0.3",
40
40
  "constructs": "^10.6.0",
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "main": "index.ts",
58
58
  "license": "Apache-2.0",
59
- "version": "0.9.40",
59
+ "version": "0.9.43",
60
60
  "types": "index.ts",
61
61
  "type": "module",
62
62
  "exports": {
@@ -1,172 +1,12 @@
1
- /** Shared Bun setup and package-cache steps for generated workflows. */
2
- import { stringUtils } from "@dbx-tools/shared-core";
3
- import { TextFile, javascript } from "projen";
1
+ /** Shared Bun setup for generated workflows. */
4
2
 
5
3
  export const BUN_VERSION = "1.3.14";
6
4
 
7
- const DEFAULT_CACHE_IGNORE_PATHS = [
8
- ".git",
9
- ".venv",
10
- ".worktrees",
11
- "coverage",
12
- "dist",
13
- "lib",
14
- "node_modules",
15
- "target",
16
- ] as const;
17
-
18
- function cacheKeyScript(extraIgnorePaths: readonly string[]): string {
19
- const ignorePaths = [...new Set(extraIgnorePaths)].sort();
20
- // prettier-ignore
21
- const source = (
22
- // ============================================================================
23
- /*js*/`
24
- #!/usr/bin/env node
25
- import { createHash } from "node:crypto";
26
- import { readdirSync, readFileSync } from "node:fs";
27
- import { join, sep } from "node:path";
28
-
29
- const root = process.cwd();
30
- const ignoredNames = new Set(${JSON.stringify(DEFAULT_CACHE_IGNORE_PATHS)});
31
- const ignoredPaths = new Set(${JSON.stringify(ignorePaths)});
32
- const manifests = [];
33
- const walk = (directory) => {
34
- for (const entry of readdirSync(directory, { withFileTypes: true })) {
35
- const path = join(directory, entry.name);
36
- const relativePath = path.slice(root.length + 1).split(sep).join("/");
37
- if (ignoredNames.has(entry.name) || ignoredPaths.has(relativePath)) continue;
38
- if (entry.isDirectory()) walk(path);
39
- else if (entry.name === "package.json") manifests.push(path);
40
- }
41
- };
42
- walk(root);
43
-
44
- const dependencyFields = [
45
- "catalog",
46
- "dependencies",
47
- "devDependencies",
48
- "optionalDependencies",
49
- "overrides",
50
- "peerDependencies",
51
- "peerDependenciesMeta",
52
- "resolutions",
53
- "trustedDependencies",
54
- ];
55
- const canonical = (value) => {
56
- if (Array.isArray(value)) return value.map(canonical);
57
- if (!value || typeof value !== "object") return value;
58
- return Object.fromEntries(
59
- Object.entries(value)
60
- .sort(([left], [right]) => left.localeCompare(right))
61
- .map(([key, child]) => [key, canonical(child)]),
62
- );
63
- };
64
- const dependencies = manifests
65
- .sort()
66
- .map((path) => {
67
- const manifest = JSON.parse(readFileSync(path, "utf8"));
68
- return [
69
- path.slice(root.length + 1),
70
- Object.fromEntries(
71
- dependencyFields
72
- .filter((field) => manifest[field] !== undefined)
73
- .map((field) => [field, canonical(manifest[field])]),
74
- ),
75
- ];
76
- });
77
- process.stdout.write(createHash("sha256").update(JSON.stringify(dependencies)).digest("hex"));
78
- `
79
- // ============================================================================
80
- );
81
- return stringUtils.dedent(source, { trimEnd: false });
82
- }
83
-
84
- const configured = new WeakMap<javascript.NodeProject, string>();
85
-
86
- function ensureCacheKeyScript(
87
- project: javascript.NodeProject,
88
- ignorePaths: readonly string[],
89
- ): void {
90
- const root = project.root as javascript.NodeProject;
91
- const key = JSON.stringify([...new Set(ignorePaths)].sort());
92
- const existing = configured.get(root);
93
- if (existing !== undefined) {
94
- if (existing !== key) {
95
- throw new Error("Bun workflow cache ignore paths must be consistent across one project");
96
- }
97
- return;
98
- }
99
- new TextFile(root, ".projen/bun-cache-key.mjs", {
100
- lines: cacheKeyScript(ignorePaths).trimEnd().split("\n"),
101
- });
102
- configured.set(root, key);
103
- }
104
-
105
- function stepCondition(condition: string | undefined, cacheMiss = false): string | undefined {
106
- const expressions = [
107
- condition,
108
- ...(cacheMiss ? ["steps.bun_cache.outputs.cache-hit != 'true'"] : []),
109
- ].filter(Boolean);
110
- return expressions.length ? `\${{ ${expressions.join(" && ")} }}` : undefined;
111
- }
112
-
113
- export interface BunWorkflowCacheOptions {
114
- readonly setupCondition?: string;
115
- readonly condition?: string;
116
- /** Repository-relative output paths excluded from dependency manifest hashing. */
117
- readonly ignorePaths?: readonly string[];
118
- }
119
-
120
- /** Set up Bun and restore its global package cache. */
121
- export function bunCacheRestoreSteps(
122
- project: javascript.NodeProject,
123
- options: BunWorkflowCacheOptions = {},
124
- ): readonly Record<string, unknown>[] {
125
- ensureCacheKeyScript(project, options.ignorePaths ?? []);
126
- const condition = stepCondition(options.condition);
127
- const setupCondition = stepCondition(options.setupCondition);
128
- return [
129
- {
130
- name: "Setup Bun",
131
- ...(setupCondition ? { if: setupCondition } : {}),
132
- uses: "oven-sh/setup-bun@v2",
133
- with: { "bun-version": "${{ env.BUN_VERSION }}" },
134
- },
135
- {
136
- name: "Resolve Bun cache",
137
- id: "bun_cache_metadata",
138
- ...(condition ? { if: condition } : {}),
139
- shell: "bash",
140
- run: [
141
- 'echo "path=$(bun pm cache)" >> "$GITHUB_OUTPUT"',
142
- 'echo "dependency_hash=$(node .projen/bun-cache-key.mjs)" >> "$GITHUB_OUTPUT"',
143
- ].join("\n"),
144
- },
145
- {
146
- name: "Restore Bun cache",
147
- id: "bun_cache",
148
- ...(condition ? { if: condition } : {}),
149
- uses: "actions/cache/restore@v5",
150
- with: {
151
- path: "${{ steps.bun_cache_metadata.outputs.path }}",
152
- key: `bun-\${{ runner.os }}-\${{ runner.arch }}-\${{ env.BUN_VERSION }}-\${{ steps.bun_cache_metadata.outputs.dependency_hash }}`,
153
- "restore-keys": `bun-\${{ runner.os }}-\${{ runner.arch }}-\${{ env.BUN_VERSION }}-`,
154
- },
155
- },
156
- ];
157
- }
158
-
159
- /** Save Bun's global package cache immediately after installation. */
160
- export function bunCacheSaveStep(
161
- options: BunWorkflowCacheOptions = {},
162
- ): Readonly<Record<string, unknown>> {
5
+ /** Install the pinned Bun version. */
6
+ export function bunSetupStep(): Readonly<Record<string, unknown>> {
163
7
  return {
164
- name: "Save Bun cache",
165
- if: stepCondition(options.condition, true),
166
- uses: "actions/cache/save@v5",
167
- with: {
168
- path: "${{ steps.bun_cache_metadata.outputs.path }}",
169
- key: "${{ steps.bun_cache.outputs.cache-primary-key }}",
170
- },
8
+ name: "Setup Bun",
9
+ uses: "oven-sh/setup-bun@v2",
10
+ with: { "bun-version": "${{ env.BUN_VERSION }}" },
171
11
  };
172
12
  }
package/src/codegen.ts CHANGED
@@ -316,9 +316,9 @@ function generatePackage(
316
316
  const sourceText = preprocess(stripImports(tsRuntime, sourcePath));
317
317
  const { getZodSchemasFile, getInferredTypes, errors } = generate({
318
318
  sourceText,
319
- // Carry JSDoc through so the `@description` tag stays visible alongside
320
- // the matching `.describe(...)`.
321
- keepComments: true,
319
+ // JSDoc is rewritten to `@description` so ts-to-zod emits `.describe()`.
320
+ // Keep the generated module comment-free; Zod owns the prose.
321
+ keepComments: false,
322
322
  });
323
323
  if (errors.length) {
324
324
  for (const err of errors) logger.warn(`${destination} from ${source}: ${err}`);
package/src/project-js.ts CHANGED
@@ -18,7 +18,7 @@ import type { ReleaseProjectOptions } from "projen/lib/release";
18
18
  import { generateBarrels } from "./barrels.ts";
19
19
 
20
20
  import { BUN_APP_OVERRIDES, RootBunfigFile } from "./bun-app.ts";
21
- import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workflow.ts";
21
+ import { BUN_VERSION, bunSetupStep } from "./bun-workflow.ts";
22
22
  import { codegenModulePaths, generateCodegen } from "./codegen.ts";
23
23
  import { DBXToolsConfig, type DBXToolsConfigOptions } from "./dbx-tools-config.ts";
24
24
  import { resolvePkgRoot } from "./engine-root.ts";
@@ -61,8 +61,6 @@ export interface DBXToolsJavaScriptProject extends DBXToolsProject, javascript.N
61
61
  pnpmWorkspace?: PnpmWorkspaceState;
62
62
  /** Root projenrc tsconfigs - only a tree ROOT has one. */
63
63
  rootTsconfig?: DBXToolsRootTsconfig;
64
- /** Repository outputs excluded from generated workflow dependency-cache hashing. */
65
- readonly workflowCacheIgnorePaths: readonly string[];
66
64
  }
67
65
 
68
66
  /** Parsed npm package identifier: optional scope plus the unscoped package name. */
@@ -581,8 +579,6 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
581
579
  readonly releaseMode?: DBXToolsReleaseMode;
582
580
  /** Prefix for generated release tags. Defaults to `v`. */
583
581
  readonly releaseTagPrefix?: string;
584
- /** Repository output paths excluded from generated workflow dependency-cache hashing. */
585
- readonly workflowCacheIgnorePaths?: readonly string[];
586
582
  /**
587
583
  * Extra workspace member paths (repo-relative, POSIX) to list in the workspace
588
584
  * config ALONGSIDE the discovered `packageRoots` members - for a package that
@@ -609,16 +605,6 @@ export type DBXToolsTypeScriptProjectOptions = Partial<
609
605
  > &
610
606
  DBXToolsJavaScriptProjectOptions;
611
607
 
612
- const initializingWorkflowCachePaths = new Map<string, readonly string[]>();
613
-
614
- function configuredOutdir(
615
- options: Pick<DBXToolsJavaScriptProjectOptions, "parent" | "outdir">,
616
- ): string {
617
- return options.parent
618
- ? resolve(options.parent.outdir, options.outdir ?? ".")
619
- : resolve(options.outdir ?? process.cwd());
620
- }
621
-
622
608
  /**
623
609
  * A monorepo root. Scans `packageRoots` and appends a
624
610
  * {@link DBXToolsTypeScriptProject} per `src`-bearing folder, then emits the
@@ -635,7 +621,6 @@ export class DBXToolsNodeProject
635
621
  rootTsconfig?: DBXToolsRootTsconfig;
636
622
  readonly extraWorkspaceMembers: readonly string[];
637
623
  readonly releaseBranch: string;
638
- readonly workflowCacheIgnorePaths: readonly string[];
639
624
  private readonly rootInstallOnly: boolean;
640
625
 
641
626
  constructor(options: DBXToolsJavaScriptProjectOptions = {}) {
@@ -648,8 +633,6 @@ export class DBXToolsNodeProject
648
633
  // into `package.json` (`workspaces`/`catalog`) for bun to read. The
649
634
  // `pnpm-workspace.yaml` is still emitted for the Databricks Apps pnpm install.
650
635
  const pnpmWorkspace = new PnpmWorkspaceState(options);
651
- const outdir = configuredOutdir(options);
652
- initializingWorkflowCachePaths.set(outdir, options.workflowCacheIgnorePaths ?? []);
653
636
  super({
654
637
  ...defaultProjectOptions(options),
655
638
  pnpmOptions: {
@@ -668,8 +651,6 @@ export class DBXToolsNodeProject
668
651
  this.scope = scope;
669
652
  this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
670
653
  this.releaseBranch = options.defaultReleaseBranch ?? "main";
671
- this.workflowCacheIgnorePaths = options.workflowCacheIgnorePaths ?? [];
672
- initializingWorkflowCachePaths.delete(outdir);
673
654
  this.rootInstallOnly = options.rootInstallOnly !== false;
674
655
  this.dbxToolsConfig = new DBXToolsConfig(this, options);
675
656
  initProject(this, options);
@@ -678,28 +659,10 @@ export class DBXToolsNodeProject
678
659
  public override renderWorkflowSetup(options?: javascript.RenderWorkflowSetupOptions): JobStep[] {
679
660
  const steps = super.renderWorkflowSetup(options);
680
661
  if (this.parent) return steps;
681
- return steps.flatMap((step) => {
682
- if (step.uses?.startsWith("oven-sh/setup-bun@")) {
683
- return [
684
- ...bunCacheRestoreSteps(this, {
685
- ignorePaths:
686
- this.workflowCacheIgnorePaths ??
687
- initializingWorkflowCachePaths.get(resolve(this.outdir)) ??
688
- [],
689
- }),
690
- ];
691
- }
692
- if (step.run?.startsWith("bun install")) {
693
- return [
694
- step,
695
- bunCacheSaveStep({
696
- condition:
697
- "github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository",
698
- }),
699
- ];
700
- }
701
- return [step];
702
- }) as JobStep[];
662
+ return [
663
+ bunSetupStep() as JobStep,
664
+ ...steps.filter((step) => !step.uses?.startsWith("oven-sh/setup-bun@")),
665
+ ];
703
666
  }
704
667
 
705
668
  public override preSynthesize(): void {
@@ -754,7 +717,6 @@ export class DBXToolsTypeScriptProject
754
717
  rootTsconfig?: DBXToolsRootTsconfig;
755
718
  readonly extraWorkspaceMembers: readonly string[];
756
719
  readonly releaseBranch: string;
757
- readonly workflowCacheIgnorePaths: readonly string[];
758
720
  private readonly rootInstallOnly: boolean;
759
721
 
760
722
  constructor(options: DBXToolsTypeScriptProjectOptions) {
@@ -795,7 +757,6 @@ export class DBXToolsTypeScriptProject
795
757
  this.scope = scope;
796
758
  this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
797
759
  this.releaseBranch = options.defaultReleaseBranch ?? "main";
798
- this.workflowCacheIgnorePaths = options.workflowCacheIgnorePaths ?? [];
799
760
  this.rootInstallOnly = options.rootInstallOnly !== false;
800
761
  // Pairs with `jsx` in SHARED_COMPILER_OPTIONS: projen's default `include` is
801
762
  // `src/**/*.ts` only, which silently omits a `.tsx` file from the program
package/src/project-py.ts CHANGED
@@ -87,6 +87,8 @@ export interface DBXToolsPythonWorkspaceOptions {
87
87
  readonly devDependencies?: readonly string[];
88
88
  readonly testPaths?: readonly string[];
89
89
  readonly lintPaths?: readonly string[];
90
+ /** Repository-relative paths Ruff must not lint or format. */
91
+ readonly ruffExcludes?: readonly string[];
90
92
  readonly ruffPerFileIgnores?: Readonly<Record<string, readonly string[]>>;
91
93
  /** Generated Python implementation files Pyrefly should resolve but not type-check. */
92
94
  readonly pyreflyProjectExcludes?: readonly string[];
@@ -347,6 +349,17 @@ export class DBXToolsPythonWorkspace extends Component {
347
349
  if (options.indexStrategy) {
348
350
  file.addOverride("tool.uv.index-strategy", options.indexStrategy);
349
351
  }
352
+ const ruffExcludes = [
353
+ ...(options.ruffExcludes ?? []),
354
+ ...options.packages.flatMap((pkg) =>
355
+ pythonNodeGeneratedSources(pkg).map(
356
+ (source) => `${this.repository.root}/${pkg.directory}/${source}`,
357
+ ),
358
+ ),
359
+ ];
360
+ if (ruffExcludes.length) {
361
+ file.addOverride("tool.ruff.exclude", [...new Set(ruffExcludes)]);
362
+ }
350
363
  file.addOverride("tool.pyrefly.ignore-errors-in-generated-code", true);
351
364
  const projectExcludes = [
352
365
  ...(options.pyreflyProjectExcludes ?? []),
package/src/release.ts CHANGED
@@ -92,15 +92,11 @@ export function nodeReleaseSetupSteps(): readonly JobStep[] {
92
92
  ];
93
93
  }
94
94
 
95
- /** Install uv and restore its download/build cache using Python manifests. */
95
+ /** Install uv for Python release builds. */
96
96
  export function uvSetupStep(): JobStep {
97
97
  return {
98
98
  name: "Setup uv",
99
99
  uses: "astral-sh/setup-uv@v7",
100
- with: {
101
- "enable-cache": true,
102
- "cache-dependency-glob": "**/pyproject.toml",
103
- },
104
100
  };
105
101
  }
106
102
 
@@ -299,7 +295,7 @@ export class DBXToolsRelease extends Component {
299
295
  super(project);
300
296
  project.addGitIgnore(".release/");
301
297
  const installCondition =
302
- 'node -e "process.exit(process.env.DBX_TOOLS_RELEASE_INSTALL === \'never\' ? 1 : 0)"';
298
+ "node -e \"process.exit(process.env.DBX_TOOLS_RELEASE_INSTALL === 'never' ? 1 : 0)\"";
303
299
  project.package.installTask.addCondition(installCondition);
304
300
  project.package.installCiTask.addCondition(installCondition);
305
301
  const tagPrefix = options.tagPrefix ?? "v";
@@ -270,6 +270,11 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
270
270
  };
271
271
  });
272
272
  build.onResolve({ filter: /.*/ }, ({ path }) => {
273
+ if (path === "zod") {
274
+ return {
275
+ path: resolve(dirname(Bun.resolveSync("zod/package.json", root)), "index.cjs"),
276
+ };
277
+ }
273
278
  if (overridesByModule.has(path)) {
274
279
  return { path, namespace: functionOverrideNamespace };
275
280
  }
@@ -586,7 +591,13 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
586
591
  }
587
592
  const parameterType = withoutUndefined(checker.getTypeAtLocation(parameter));
588
593
  const path = `${exported.sourceName}.${parameter.name.text}`;
589
- const record = pythonRecordType(checker, parameterType, records, path);
594
+ const record = pythonRecordType(
595
+ checker,
596
+ parameterType,
597
+ records,
598
+ path,
599
+ declaredTypeName(parameter.type),
600
+ );
590
601
  const required = !parameter.questionToken && !parameter.initializer;
591
602
  return {
592
603
  javascriptName: parameter.name.text,
@@ -606,6 +617,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
606
617
  responses,
607
618
  protocols,
608
619
  `${exported.sourceName}.return`,
620
+ declaredTypeName(declaration.type),
609
621
  );
610
622
  typesByFunction.set(`${exported.sourceFile}#${exported.sourceName}`, {
611
623
  parameters,
@@ -636,8 +648,10 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
636
648
  type: ts.Type,
637
649
  records: Map<string, PythonRecord>,
638
650
  path: string,
651
+ preferredName?: string,
639
652
  ): PythonRecord {
640
- const name = type.aliasSymbol?.getName() ?? type.getSymbol()?.getName();
653
+ const symbolName = type.aliasSymbol?.getName() ?? type.getSymbol()?.getName();
654
+ const name = symbolName && symbolName !== "__type" ? symbolName : preferredName;
641
655
  if (!name || name === "__type") throw new Error(`${path} must reference a named object type`);
642
656
  const existing = records.get(name);
643
657
  if (existing) return existing;
@@ -665,13 +679,23 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
665
679
  type: ts.Type,
666
680
  records: Map<string, PythonRecord>,
667
681
  path: string,
682
+ preferredName?: string,
668
683
  ): PythonRecord | undefined {
669
684
  if (!(type.flags & ts.TypeFlags.Object)) return undefined;
670
685
  if (checker.isArrayType(type) || type.getCallSignatures().length > 0) return undefined;
671
686
  if (checker.getIndexTypeOfType(type, ts.IndexKind.String)) return undefined;
672
- const name = type.aliasSymbol?.getName() ?? type.getSymbol()?.getName();
687
+ const symbolName = type.aliasSymbol?.getName() ?? type.getSymbol()?.getName();
688
+ const name = symbolName && symbolName !== "__type" ? symbolName : preferredName;
673
689
  if (!name || name === "__type") return undefined;
674
- return pythonRecord(checker, type, records, path);
690
+ return pythonRecord(checker, type, records, path, preferredName);
691
+ }
692
+
693
+ function declaredTypeName(node: ts.TypeNode | undefined): string | undefined {
694
+ if (!node) return undefined;
695
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
696
+ return node.typeName.text;
697
+ }
698
+ return undefined;
675
699
  }
676
700
 
677
701
  function pythonType(
@@ -715,6 +739,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
715
739
  responses: Map<string, PythonResponse>,
716
740
  protocols: Map<string, PythonProtocol>,
717
741
  path: string,
742
+ preferredName?: string,
718
743
  ): string {
719
744
  if (type.isUnion()) {
720
745
  return pythonUnion(
@@ -839,7 +864,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
839
864
  protocols.set(name, { name, methods: protocolMethods, properties: protocolProperties });
840
865
  return name;
841
866
  }
842
- const name = `${pythonObjectName(type, path, "Result")}Response`;
867
+ const name = `${preferredName ?? pythonObjectName(type, path, "Result")}Response`;
843
868
  if (responses.has(name)) return name;
844
869
  responses.set(name, { name, fields: [] });
845
870
  const fields = properties.map((property) => {
@@ -10,7 +10,6 @@ import {
10
10
  runTaskCommand,
11
11
  taskCommandSucceeds,
12
12
  } from "../../src/_task-command.ts";
13
- import { readWorkspaceVersion } from "../../src/workspace-version.ts";
14
13
  import {
15
14
  RELEASE_INSTALL_MODES,
16
15
  RELEASE_PUBLISH_TARGETS,
@@ -20,6 +19,7 @@ import {
20
19
  type ReleaseInstallMode,
21
20
  type ReleaseSelectionOptions,
22
21
  } from "../../src/release-options.ts";
22
+ import { readWorkspaceVersion } from "../../src/workspace-version.ts";
23
23
 
24
24
  const logger = log.logger("projen:release");
25
25