@dbx-tools/projen 0.9.43 → 0.9.46

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 (52) hide show
  1. package/README.md +28 -34
  2. package/index.ts +6 -7
  3. package/package.json +9 -10
  4. package/shims/python-node/bootstrap.ts +129 -0
  5. package/shims/python-node/child-process.ts +96 -0
  6. package/shims/python-node/crypto.ts +60 -0
  7. package/shims/python-node/fs-promises.ts +179 -0
  8. package/shims/python-node/fs.ts +173 -0
  9. package/shims/python-node/headers.ts +75 -0
  10. package/shims/python-node/host.ts +341 -0
  11. package/shims/python-node/os.ts +20 -0
  12. package/shims/python-node/process.ts +13 -0
  13. package/shims/python-node/readline.ts +37 -0
  14. package/shims/python-node/tsconfig.json +24 -0
  15. package/src/_lazy-require.ts +7 -25
  16. package/src/bun-app.ts +2 -2
  17. package/src/bun-workflow.ts +1 -9
  18. package/src/codegen.ts +20 -17
  19. package/src/dbx-tools-config.ts +52 -9
  20. package/src/generated.ts +4 -17
  21. package/src/mixin.ts +1 -5
  22. package/src/packages.ts +18 -15
  23. package/src/pnpm-workspace.ts +1 -4
  24. package/src/project-js.ts +65 -157
  25. package/src/project-predicate.ts +7 -3
  26. package/src/project-py.ts +120 -43
  27. package/src/publish.ts +13 -10
  28. package/src/python-node-bindings.ts +2 -0
  29. package/src/python-node-bundle.ts +6 -0
  30. package/src/release-options.ts +17 -17
  31. package/src/release.ts +30 -9
  32. package/src/scaffold.ts +4 -7
  33. package/src/tags.ts +6 -16
  34. package/src/vscode.ts +1 -1
  35. package/src/watch.ts +5 -5
  36. package/src/workspace-lock.ts +1 -0
  37. package/src/workspace-version.ts +4 -4
  38. package/tasks/barrels.ts +3 -5
  39. package/tasks/clean.ts +1 -0
  40. package/tasks/lib/compile-workspace.ts +41 -19
  41. package/tasks/lib/local-publish.ts +0 -28
  42. package/tasks/lib/publish-npm.ts +8 -0
  43. package/tasks/lib/publish-python.ts +4 -0
  44. package/tasks/lib/python-node-bindings.ts +77 -21
  45. package/tasks/lib/python-registry.ts +4 -0
  46. package/tasks/lib/python-release.ts +2 -0
  47. package/tasks/lib/release.ts +1 -1
  48. package/tasks/projenrc.ts +1 -0
  49. package/tasks/sync.ts +4 -4
  50. package/src/openapi.ts +0 -293
  51. package/tasks/local-publish.ts +0 -6
  52. package/tasks/openapi.ts +0 -35
package/src/project-js.ts CHANGED
@@ -12,13 +12,13 @@ import * as projectUtils from "@dbx-tools/core/project-utils";
12
12
  import { ignore, match } from "@dbx-tools/path";
13
13
  import { object, stringUtils, type OneOrMany } from "@dbx-tools/shared-core";
14
14
  import { type IConstruct } from "constructs";
15
- import { Component, IgnoreFile, Project, javascript, typescript } from "projen";
15
+ import { Component, LogLevel, Project, javascript, typescript } from "projen";
16
16
  import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
17
17
  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, bunSetupStep } from "./bun-workflow.ts";
21
+ import { BUN_VERSION } 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";
@@ -52,6 +52,8 @@ export interface DBXToolsJavaScriptProject extends DBXToolsProject, javascript.N
52
52
  readonly dbxToolsConfig: DBXToolsConfig;
53
53
  /** npm scope (the `@scope` in `@scope/pkg`), without the leading `@`. */
54
54
  readonly scope: string;
55
+ /** Branch that the repository's tag release must match. */
56
+ readonly releaseBranch: string;
55
57
 
56
58
  /**
57
59
  * The `pnpm-workspace.yaml` catalog / member / build-allowance state - only a
@@ -251,11 +253,8 @@ export function projectRepositoryUrl(project: javascript.NodeProject): string |
251
253
  }
252
254
 
253
255
  /** Resolve the branch release workflows use for a generated project. */
254
- export function projectReleaseBranch(project: javascript.NodeProject): string {
255
- return (
256
- (project as javascript.NodeProject & { readonly releaseBranch?: string }).releaseBranch ??
257
- "main"
258
- );
256
+ export function projectReleaseBranch(project: DBXToolsJavaScriptProject): string {
257
+ return project.releaseBranch;
259
258
  }
260
259
 
261
260
  /**
@@ -367,19 +366,21 @@ const PRETTIER_SETTINGS: javascript.PrettierSettings = {
367
366
  export { PROJEN_VERSION } from "./projen-version.ts";
368
367
 
369
368
  /** SPDX license shared by generated JavaScript and Python packages. */
370
- export const DBX_TOOLS_LICENSE = "Apache-2.0";
369
+ export const LICENSE = "Apache-2.0";
371
370
 
372
371
  /**
373
372
  * The engine's opinionated `NodeProject` defaults. A caller's own options override
374
373
  * these (they are spread AFTER this). Root-only concerns key off `options.parent`,
375
374
  * NOT the class: only the tree ROOT (no parent) turns on projen's built-in Prettier
376
375
  * (the `prettier` devDep + `.prettierrc.json` + `.prettierignore`), so a child package
377
- * inherits the root's config rather than emitting its own. `name`/`defaultReleaseBranch`
378
- * are resolved/applied by the caller.
376
+ * inherits the root's config rather than emitting its own. Projen's informational
377
+ * status messages are hidden by default while task output, warnings, and errors
378
+ * remain visible. `name`/`defaultReleaseBranch` are resolved/applied by the caller.
379
379
  */
380
380
  function defaultProjectOptions(options: DBXToolsJavaScriptProjectOptions) {
381
381
  const isRoot = options.parent === undefined;
382
382
  return {
383
+ logging: { level: LogLevel.WARN },
383
384
  // Bun owns install/run/build/test locally and in CI. projen renders
384
385
  // `bun install`/`bunx` and a native `trustedDependencies` field from this.
385
386
  // The engine still emits `pnpm-workspace.yaml` itself (see
@@ -408,7 +409,7 @@ function defaultProjectOptions(options: DBXToolsJavaScriptProjectOptions) {
408
409
  // workflow opts in per run through `npm_config_provenance`, so local publishes
409
410
  // to Verdaccio still work without a CI OIDC provider. See
410
411
  // {@link DBXToolsRelease}.
411
- ...(isRoot ? {} : { npmAccess: javascript.NpmAccess.PUBLIC }),
412
+ ...(isRoot || options.publishable === false ? {} : { npmAccess: javascript.NpmAccess.PUBLIC }),
412
413
  workflowPackageCache: false,
413
414
  // The root build validates the whole workspace and must not also pack every
414
415
  // member into unused `dist/js` tarballs. Child projects keep projen's package
@@ -455,9 +456,8 @@ function defaultProjectOptions(options: DBXToolsJavaScriptProjectOptions) {
455
456
  /**
456
457
  * `gitIgnoreOptions` with its `ignorePatterns` array CLONED, for handing to a
457
458
  * projen `Project` constructor: projen's IgnoreFile ALIASES the array it is given
458
- * (every later addPatterns call mutates it), so the throwaway default-laden
459
- * `.gitignore` gets a copy - {@link swapChildGitignore} re-reads the caller's
460
- * pristine array to seed a child's fresh one. Spread AFTER `...options`.
459
+ * and every later `addPatterns` call mutates it. The caller's typed options must
460
+ * remain unchanged while Projen owns and extends the generated ignore file.
461
461
  */
462
462
  function copiedGitIgnoreOptions(
463
463
  options: DBXToolsJavaScriptProjectOptions,
@@ -514,11 +514,20 @@ function validateReleaseOptions(options: DBXToolsJavaScriptProjectOptions): void
514
514
  /** Options for {@link DBXToolsNodeProject} (the monorepo root). */
515
515
  export type DBXToolsReleaseMode = "dbx-tools" | "disabled";
516
516
 
517
+ /** Native constructor fields resolved for one filesystem-discovered package. */
518
+ export interface DiscoveredTypeScriptPackageOptions {
519
+ readonly name: string;
520
+ readonly description?: string;
521
+ readonly entrypoint?: string;
522
+ readonly publishable?: boolean;
523
+ }
524
+
517
525
  type SupportedWorkflowOptions = Pick<
518
526
  ReleaseProjectOptions,
519
527
  "postBuildSteps" | "workflowContainerImage" | "workflowRunsOn" | "workflowRunsOnGroup"
520
528
  >;
521
529
 
530
+ /** Options shared by discovered package roots and standalone JavaScript projects. */
522
531
  export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
523
532
  Partial<
524
533
  Omit<javascript.NodeProjectOptions, keyof ReleaseProjectOptions | "release" | "releaseToNpm">
@@ -546,8 +555,11 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
546
555
  * disable. Defaults to `"node"`.
547
556
  */
548
557
  readonly omitRelativePrefix?: OneOrMany<string>;
549
- /** Resolve a discovered package name before its project is constructed. */
550
- readonly resolvePackageName?: (pkg: DiscoveredPackage, defaultPackageName: string) => string;
558
+ /** Resolve native constructor fields before a discovered package is constructed. */
559
+ readonly resolvePackageOptions?: (
560
+ pkg: DiscoveredPackage,
561
+ defaults: DiscoveredTypeScriptPackageOptions,
562
+ ) => DiscoveredTypeScriptPackageOptions;
551
563
  /**
552
564
  * Maps a path token / relPath / glob to tag(s), unioned into a package's
553
565
  * path-derived tags. Defaults to an identity map over the known tag names; a
@@ -573,6 +585,8 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
573
585
  readonly releaseValidationTasks?: readonly string[];
574
586
  /** Release build prerequisites installed before repository validation tasks. */
575
587
  readonly releaseSetupSteps?: readonly JobStep[];
588
+ /** Repository-specific synthesis commands run before release source verification. */
589
+ readonly releaseSynthesisCommands?: readonly string[];
576
590
  /** Set to `false` to omit normal npm workspace publication. */
577
591
  readonly nodeRelease?: boolean;
578
592
  /** Unified dbx-tools release workflow, or no release surface. Defaults to `dbx-tools`. */
@@ -656,15 +670,6 @@ export class DBXToolsNodeProject
656
670
  initProject(this, options);
657
671
  }
658
672
 
659
- public override renderWorkflowSetup(options?: javascript.RenderWorkflowSetupOptions): JobStep[] {
660
- const steps = super.renderWorkflowSetup(options);
661
- if (this.parent) return steps;
662
- return [
663
- bunSetupStep() as JobStep,
664
- ...steps.filter((step) => !step.uses?.startsWith("oven-sh/setup-bun@")),
665
- ];
666
- }
667
-
668
673
  public override preSynthesize(): void {
669
674
  prepareRootSynthesis(this, this.rootInstallOnly);
670
675
  super.preSynthesize();
@@ -677,11 +682,11 @@ export class DBXToolsNodeProject
677
682
  * Root-owned workspace install policy.
678
683
  *
679
684
  * Every projen child has its own `NodePackage` post-synth hook, which otherwise
680
- * runs `bun install` against the same root workspace once per package. Clear the
681
- * child install tasks and suppress the package hook's install call and trigger
682
- * log while leaving dependency resolution and the root's real install/install:ci
683
- * tasks intact. Applied in root `preSynthesize` so manually attached late
684
- * children are included and repeated synths remain idempotent.
685
+ * runs the install task against the same root workspace once per package. Clear
686
+ * the public child install tasks while leaving dependency resolution and the
687
+ * root's real install/install:ci tasks intact. Applied in root `preSynthesize`
688
+ * so manually attached late children are included and repeated synths remain
689
+ * idempotent.
685
690
  */
686
691
  export const ROOT_INSTALL_ONLY_MIXIN = mixin.create(
687
692
  (construct: IConstruct): construct is DBXToolsNodeProject | DBXToolsTypeScriptProject =>
@@ -690,12 +695,6 @@ export const ROOT_INSTALL_ONLY_MIXIN = mixin.create(
690
695
  (child) => {
691
696
  child.package.installTask.reset();
692
697
  child.package.installCiTask.reset();
693
- const nodePackage = child.package as unknown as {
694
- installDependencies(trigger: unknown): void;
695
- logInstallTrigger(trigger: unknown): void;
696
- };
697
- nodePackage.installDependencies = () => {};
698
- nodePackage.logInstallTrigger = () => {};
699
698
  },
700
699
  );
701
700
 
@@ -823,10 +822,9 @@ class GeneratedSource extends Component {
823
822
  public override preSynthesize(): void {
824
823
  const root = resolve(this.project.outdir);
825
824
  for (const subproject of this.project.subprojects) {
826
- if (!(subproject instanceof javascript.NodeProject)) continue;
827
- const codegen = subproject.package.manifest.codegen as { inputs?: string[] } | undefined;
825
+ if (!(subproject instanceof DBXToolsTypeScriptProject)) continue;
828
826
  const packagePath = toPosix(relative(root, subproject.outdir));
829
- const modules = codegenModulePaths(codegen?.inputs ?? []);
827
+ const modules = codegenModulePaths(subproject.dbxToolsConfig.codegenInputs);
830
828
  for (const module of modules) {
831
829
  this.project.annotateGenerated(`/${packagePath}/${module}`);
832
830
  }
@@ -859,10 +857,10 @@ class GeneratedSource extends Component {
859
857
  *
860
858
  * projen gives a monorepo root empty `compile`/`test` tasks - a child's tasks
861
859
  * are the child's business - so `bun run build` at the root type-checked nothing
862
- * and ran no package tests. Compilation groups ordinary `tsc --build` members
863
- * into a few TypeScript processes and runs custom compile tasks alongside them. Tests
864
- * still use Bun's filtered workspace fan-out. Both read the current workspace
865
- * list from `package.json`, so a newly added member needs no re-synth.
860
+ * and ran no package tests. Compilation groups ordinary package tsconfigs into
861
+ * a few TypeScript processes and runs custom package lifecycles alongside them.
862
+ * Tests still use Bun's filtered workspace fan-out. Both read the current
863
+ * workspace list from `package.json`, so a newly added member needs no re-synth.
866
864
  *
867
865
  * `*` matches every workspace MEMBER and never the root itself, so the test
868
866
  * task delegating to it cannot recurse. Members declared outside the scanned
@@ -884,35 +882,9 @@ class WorkspaceValidationTasks extends Component {
884
882
  }
885
883
 
886
884
  /**
887
- * Apply bounded, read-only, supersedable defaults to validation workflows.
888
- *
889
- * Projen otherwise leaves jobs at GitHub's six-hour ceiling. Missing workflows
890
- * are a no-op, so roots that keep the engine defaults (`github`/build workflow
891
- * off) do not gain new files.
892
- */
893
- class WorkflowDefaults extends Component {
894
- public override preSynthesize(): void {
895
- const build = this.project.tryFindObjectFile(".github/workflows/build.yml");
896
- build?.addOverride("on.pull_request.types", ["opened", "synchronize", "reopened", "closed"]);
897
- build?.addOverride(
898
- "jobs.build.if",
899
- "${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}",
900
- );
901
- for (const job of ["build", "self-mutation"]) {
902
- build?.addOverride(`jobs.${job}.timeout-minutes`, 30);
903
- }
904
- build?.addOverride("permissions", { contents: "read" });
905
- build?.addOverride("concurrency", {
906
- group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}",
907
- "cancel-in-progress": true,
908
- });
909
- }
910
- }
911
-
912
- /**
913
- * Ignore each `codegen`-declaring package's `src/` from the root ESLint config.
885
+ * Ignore each codegen-declaring package's generated modules from root ESLint.
914
886
  * Those modules are read-only (ts-to-zod); lint `--fix` otherwise EACCES-crashes
915
- * on them. Runs in `preSynthesize` so mixin-added `codegen.inputs` are visible.
887
+ * on them. Runs in `preSynthesize` so mixin-added typed config is visible.
916
888
  */
917
889
  class EslintIgnoreCodegen extends Component {
918
890
  public override preSynthesize(): void {
@@ -920,16 +892,15 @@ class EslintIgnoreCodegen extends Component {
920
892
  if (!eslint) return;
921
893
  const rootAbs = resolve(this.project.outdir);
922
894
  for (const sub of this.project.subprojects) {
923
- if (!(sub instanceof javascript.NodeProject)) continue;
924
- const codegen = sub.package.manifest.codegen as { inputs?: string[] } | undefined;
925
- if (!codegen?.inputs?.length) continue;
895
+ if (!(sub instanceof DBXToolsTypeScriptProject)) continue;
896
+ if (sub.dbxToolsConfig.codegenInputs.length === 0) continue;
926
897
  const rel = toPosix(relative(rootAbs, sub.outdir));
927
898
  // Ignore the generated MODULES, not the package's whole `src/`. A codegen
928
899
  // package may hold hand-written modules next to its generated ones
929
900
  // (shared-genie generates `dashboards.ts` beside a hand-written
930
901
  // `genie-model.ts`), and a blanket `src/**` would silently stop linting
931
902
  // them - the failure mode being invisible, since ESLint just reports less.
932
- for (const module of codegenModulePaths(codegen.inputs)) {
903
+ for (const module of codegenModulePaths(sub.dbxToolsConfig.codegenInputs)) {
933
904
  eslint.addIgnorePattern(`${rel}/${module}`);
934
905
  }
935
906
  }
@@ -950,11 +921,10 @@ class PrettierIgnoreGenerated extends Component {
950
921
  prettier.addIgnorePattern("**/src/generated/**");
951
922
  const rootAbs = resolve(this.project.outdir);
952
923
  for (const sub of this.project.subprojects) {
953
- if (!(sub instanceof javascript.NodeProject)) continue;
924
+ if (!(sub instanceof DBXToolsTypeScriptProject)) continue;
954
925
  const rel = toPosix(relative(rootAbs, sub.outdir));
955
926
  prettier.addIgnorePattern(`${rel}/index.ts`);
956
- const codegen = sub.package.manifest.codegen as { inputs?: string[] } | undefined;
957
- for (const module of codegenModulePaths(codegen?.inputs ?? [])) {
927
+ for (const module of codegenModulePaths(sub.dbxToolsConfig.codegenInputs)) {
958
928
  prettier.addIgnorePattern(`${rel}/${module}`);
959
929
  }
960
930
  }
@@ -1070,7 +1040,6 @@ function resolveTags(p: DiscoveredPackage, tagPaths: Record<string, string[]>):
1070
1040
  /** Register the native projen tasks on the monorepo root. */
1071
1041
  function registerRootTasks(project: javascript.NodeProject): void {
1072
1042
  project.addTask("barrels", { execArgs: taskCommand("barrels.ts") });
1073
- project.addTask("openapi", { execArgs: taskCommand("openapi.ts") });
1074
1043
  project.addTask("clean", { execArgs: taskCommand("clean.ts"), receiveArgs: true });
1075
1044
  project.addTask("sync", {
1076
1045
  execArgs: taskCommand("sync.ts"),
@@ -1117,12 +1086,8 @@ function initProject(
1117
1086
  execArgs: [...packageStep.execArgs, "--ignore-scripts"],
1118
1087
  });
1119
1088
  }
1120
- // Only a ROOT configures the workspace; a child just swaps its default-laden
1121
- // `.gitignore` for a fresh one that carries package-specific patterns only.
1122
- swapChildGitignore(project, options);
1123
1089
  return;
1124
1090
  }
1125
- project.package.file.readonly = false;
1126
1091
 
1127
1092
  if (project instanceof DBXToolsNodeProject) {
1128
1093
  project.rootTsconfig = new DBXToolsRootTsconfig(project);
@@ -1138,7 +1103,6 @@ function initProject(
1138
1103
  // a plain `bun` exec rather than any wrapper: the default task is spawned by
1139
1104
  // nested installs/synths, and a wrapper that exported `npm_config_*` broke them.
1140
1105
  project.defaultTask?.reset("bun .projenrc.ts");
1141
- project.buildWorkflow?.workflow.file?.addOverride("jobs.build.env.BUN_VERSION", BUN_VERSION);
1142
1106
 
1143
1107
  // Pin bun's hoisted linker workspace-wide (see RootBunfigFile) so a peer dep
1144
1108
  // resolves to one copy and singletons/types stay coherent.
@@ -1150,6 +1114,9 @@ function initProject(
1150
1114
  if (selfDep) project.addDevDeps(selfDep);
1151
1115
  project.addDevDeps(...DEV_DEPS_ROOT);
1152
1116
  configureRootPackage(project);
1117
+ // Workspaces generated by this engine intentionally do not track local-registry
1118
+ // lockfiles, so the CI-named install task must resolve from manifests as well.
1119
+ project.package.installCiTask.reset("bun install");
1153
1120
  const roots = options.packageRoots ?? DEFAULT_PACKAGE_ROOTS;
1154
1121
  project.dbxToolsConfig.packageRoots = [...roots];
1155
1122
  if (options.syncResynthPaths?.length) {
@@ -1181,7 +1148,6 @@ function initProject(
1181
1148
  project.gitignore.addPatterns(".env", ".env.*", "!.env.example", "!.env.sample", ".idea/*");
1182
1149
  for (const root of roots) {
1183
1150
  project.annotateGenerated(`/${root}/**/index.ts`);
1184
- project.annotateGenerated(`/${root}/openapi/**`);
1185
1151
  project.annotateGenerated(`/${root}/**/src/generated/**`);
1186
1152
  }
1187
1153
  for (const member of project.extraWorkspaceMembers) {
@@ -1211,11 +1177,9 @@ function initProject(
1211
1177
  description: "Fix ESLint issues across the codebase",
1212
1178
  exec: "bun run eslint -- --fix",
1213
1179
  });
1214
- // Generated read-only outputs (barrels, openapi clients, app scripts, codegen).
1215
- // ESLint --fix cannot rewrite them; they are stamped by the barrel generator /
1216
- // openapi / codegen / projen.
1180
+ // Generated read-only outputs (barrels, app scripts, and codegen). ESLint
1181
+ // --fix cannot rewrite files owned by the barrel generator, codegen, or projen.
1217
1182
  for (const root of roots) {
1218
- eslint.addIgnorePattern(`${root}/openapi/**`);
1219
1183
  eslint.addIgnorePattern(`${root}/**/index.ts`);
1220
1184
  }
1221
1185
  eslint.addIgnorePattern("**/src/generated/**");
@@ -1227,14 +1191,11 @@ function initProject(
1227
1191
  // them to a project. ESLint still cannot parse them.
1228
1192
  eslint.addIgnorePattern("**/dev.ts");
1229
1193
  eslint.addIgnorePattern("**/build.ts");
1230
- // A deploy-staging helper that lives at a package root (outside any `src/**`
1231
- // tsconfig), same parse-resolution problem as the bun app scripts above.
1232
- eslint.addIgnorePattern("**/stage-deploy.ts");
1233
1194
  for (const override of BUN_APP_OVERRIDES) {
1234
1195
  eslint.addIgnorePattern(`**/${override}`);
1235
1196
  }
1236
- // Codegen packages declare `codegen.inputs` via mixins after construction; ignore
1237
- // their `src/` once manifests are known (preSynthesize), same reason as openapi.
1197
+ // Codegen inputs may be added by mixins after construction; ignore their
1198
+ // generated modules once typed package configuration is final.
1238
1199
  new EslintIgnoreCodegen(project);
1239
1200
  eslint.addRules({
1240
1201
  "import/no-relative-packages": "error",
@@ -1261,7 +1222,11 @@ function initProject(
1261
1222
  // cross-package imports.
1262
1223
  const tsResolver = eslint.config?.settings?.["import/resolver"]?.typescript;
1263
1224
  if (tsResolver) {
1264
- tsResolver.project = ["tsconfig.json", ...roots.map((r) => `${r}/**/tsconfig.json`)];
1225
+ tsResolver.project = [
1226
+ "tsconfig.json",
1227
+ ...roots.map((r) => `${r}/**/tsconfig.json`),
1228
+ ...project.extraWorkspaceMembers.map((member) => `${member}/tsconfig.json`),
1229
+ ];
1265
1230
  }
1266
1231
 
1267
1232
  const enabledTagMixins = resolveEnabledTagMixins(options.defaultTagMixins);
@@ -1295,10 +1260,13 @@ function initProject(
1295
1260
  continue;
1296
1261
  }
1297
1262
  const defaultPackageName = packageNameFor(project.scope, p.relPath, omitPrefixes);
1263
+ const packageOptions =
1264
+ options.resolvePackageOptions?.(p, { name: defaultPackageName }) ??
1265
+ ({ name: defaultPackageName } satisfies DiscoveredTypeScriptPackageOptions);
1298
1266
  new DBXToolsTypeScriptProject({
1299
1267
  parent: project,
1300
1268
  outdir: p.memberPath,
1301
- name: options.resolvePackageName?.(p, defaultPackageName) ?? defaultPackageName,
1269
+ ...packageOptions,
1302
1270
  tags,
1303
1271
  });
1304
1272
  }
@@ -1315,7 +1283,6 @@ function initProject(
1315
1283
  }
1316
1284
 
1317
1285
  new WorkspaceValidationTasks(project);
1318
- new WorkflowDefaults(project);
1319
1286
  new PrettierIgnoreGenerated(project);
1320
1287
  new GeneratedSource(project);
1321
1288
 
@@ -1329,56 +1296,11 @@ function initProject(
1329
1296
  pythonRoot: options.releasePythonRoot,
1330
1297
  validationTasks: options.releaseValidationTasks,
1331
1298
  setupSteps: options.releaseSetupSteps,
1299
+ synthesisCommands: options.releaseSynthesisCommands,
1332
1300
  });
1333
1301
  }
1334
1302
  }
1335
1303
 
1336
- /**
1337
- * A child's `.gitignore`, tracking whether any pattern was ever added so an
1338
- * untouched (empty) file can be dropped at presynth. `exclude`/`include` and
1339
- * constructor `ignorePatterns` all funnel through {@link addPatterns}, so the flag
1340
- * sees every route - but seed patterns must be added AFTER construction (see
1341
- * {@link swapChildGitignore}) because class fields initialize after `super()`.
1342
- */
1343
- class ChildGitignore extends IgnoreFile {
1344
- /** True once any pattern landed (custom patterns => the file is emitted). */
1345
- public hasPatterns = false;
1346
-
1347
- public override addPatterns(...patterns: string[]): void {
1348
- if (patterns.length) this.hasPatterns = true;
1349
- super.addPatterns(...patterns);
1350
- }
1351
- }
1352
-
1353
- /**
1354
- * Swap a CHILD's default `.gitignore` - pre-populated by `NodeProject` with the
1355
- * same defaults the root already carries (git applies the root's file to the whole
1356
- * tree) - for a FRESH {@link ChildGitignore}. Caller-supplied patterns
1357
- * (`gitignore` / `gitIgnoreOptions.ignorePatterns`) are re-seeded, and later
1358
- * `project.gitignore.addPatterns(...)` calls (tag/user mixins) land here too, so a
1359
- * package CAN carry package-specific ignores without inheriting the root noise.
1360
- * Left empty, the file is dropped by {@link preSynthesizeProject}. Safe because
1361
- * projen only writes gitignore defaults at construction time (`addDefaultGitIgnore`,
1362
- * yarn-berry config), never during synth.
1363
- */
1364
- function swapChildGitignore(
1365
- project: javascript.NodeProject,
1366
- options: DBXToolsJavaScriptProjectOptions,
1367
- ): void {
1368
- project.tryRemoveFile(".gitignore");
1369
- const fresh = new ChildGitignore(project, ".gitignore", {
1370
- ...options.gitIgnoreOptions,
1371
- // Re-added below so the custom-pattern flag sees them (not clobbered by the
1372
- // subclass field initializer running after super()).
1373
- ignorePatterns: undefined,
1374
- });
1375
- const seeds = [...(options.gitignore ?? []), ...(options.gitIgnoreOptions?.ignorePatterns ?? [])];
1376
- if (seeds.length) fresh.addPatterns(...seeds);
1377
- // `Project.gitignore` is readonly only at compile time; rebind it so every
1378
- // subsequent `project.gitignore.*` call reaches the fresh file.
1379
- (project as { gitignore: IgnoreFile }).gitignore = fresh;
1380
- }
1381
-
1382
1304
  function preSynthesizeProject(project: javascript.NodeProject): void {
1383
1305
  // `Project.files` is OWN-project only (its `components` getter filters on the
1384
1306
  // project's own node path), so reaching a child's files means walking the tree.
@@ -1400,19 +1322,5 @@ function preSynthesizeProject(project: javascript.NodeProject): void {
1400
1322
  // only. Runs here rather than in the constructor so the tags have already
1401
1323
  // installed their `exports` layouts for it to mirror.
1402
1324
  if (p instanceof javascript.NodeProject) applyCompiledPublish(p);
1403
- // A child's `.gitignore` survives ONLY when it carries custom patterns (see
1404
- // swapChildGitignore). `.gitattributes` is always dropped - the root's
1405
- // annotateGenerated globs cover the children. Runs once from the root's
1406
- // preSynthesize and again from each child's own; both passes agree, so the
1407
- // second is a no-op.
1408
- const keepGitignore = p.gitignore instanceof ChildGitignore && p.gitignore.hasPatterns;
1409
- for (const path of keepGitignore ? [".gitattributes"] : [".gitignore", ".gitattributes"]) {
1410
- if (p.tryRemoveFile(path)) {
1411
- const rootPath = resolve(p.outdir, path);
1412
- if (existsSync(rootPath)) {
1413
- p.logger.info(`Removed ${rootPath} from ${p.name}`);
1414
- }
1415
- }
1416
- }
1417
1325
  }
1418
1326
  }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Composable, runtime-safe predicates for selecting Projen projects by type,
3
+ * package identity, tags, and repository path.
4
+ */
1
5
  import { relative } from "node:path";
2
6
  import { match, PathMatchInput, PathMatchPredicate } from "@dbx-tools/path";
3
7
  import {
@@ -19,9 +23,9 @@ import type { DBXToolsProject } from "./project.ts";
19
23
  *
20
24
  * Uses projen's own `Project.isProject` rather than `instanceof`. It tests for
21
25
  * `Symbol.for("projen.Project")`, which every `Project` constructor stamps on
22
- * itself, so it still matches when a construct came from a SECOND resolved copy
23
- * of projen - the engine pins its own `projen` dependency separately from the
24
- * consuming root's, which is exactly the case `instanceof` fails silently.
26
+ * itself, so it still matches if an invalid consumer install resolves a second
27
+ * Projen copy despite the engine's peer dependency. An `instanceof` guard would
28
+ * silently reject that construct before the install problem can be diagnosed.
25
29
  */
26
30
  export function isProject(): Predicate<IConstruct, Project> {
27
31
  return predicate.create((c: IConstruct): c is Project => Project.isProject(c));