@codedrifters/configulator 0.0.243 → 0.0.245

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/lib/index.mjs CHANGED
@@ -814,7 +814,12 @@ var baseBundle = {
814
814
  "- The docs site is monorepo-wide. Sub-project documentation belongs",
815
815
  " inside that single site (under `docs/content/`), not in a per-package",
816
816
  " `docs/` folder.",
817
- "- Configulator's `StarlightProject` defaults its `outdir` to `/docs`.",
817
+ "- Configulator's `StarlightProject` defaults its `outdir` to `/docs` and",
818
+ ' its `role` to `"docs"`. A second `StarlightProject` with `role: "docs"`',
819
+ " fails synth \u2014 the singleton rule is enforced at validate time.",
820
+ "- Additional Starlight sites (client-facing, marketing, etc.) must set",
821
+ ' `role: "site"`, which routes them under `sites/<scope>/<name>` just',
822
+ " like a plain `AstroProject`.",
818
823
  "- `/sites` is reserved for end-user-facing web front ends (marketing",
819
824
  " sites, SPAs, client-facing apps). It deliberately does not host the",
820
825
  " dev-docs site.",
@@ -830,7 +835,8 @@ var baseBundle = {
830
835
  "| `TypeScriptProject` | `packages/<scope>/<name>` |",
831
836
  "| `AwsCdkProject` | `apps/<scope>/<name>` |",
832
837
  "| `AstroProject` | `sites/<scope>/<name>` |",
833
- "| `StarlightProject` (role = docs) | `docs/` |",
838
+ "| `StarlightProject` (role = docs, default) | `docs/` |",
839
+ "| `StarlightProject` (role = site) | `sites/<scope>/<name>` |",
834
840
  "",
835
841
  "`<scope>` is parsed from the sub-project's package name (everything",
836
842
  "after `@` and before `/`). `<name>` is the unscoped part of the",
@@ -901,6 +907,28 @@ var baseBundle = {
901
907
 
902
908
  // src/agent/bundles/project-context.ts
903
909
  var PROJECT_CONTEXT_PATH = "docs/project-context.md";
910
+ var SUBPROJECT_ROLE_GUIDANCE = [
911
+ "### Sub-project roles",
912
+ "",
913
+ "When the repository follows the configulator monorepo layout,",
914
+ "every sub-project's role is derivable from the first segment of",
915
+ "its `outdir` path. No other lookup is required.",
916
+ "",
917
+ "- `apps/<scope>/<name>` \u2014 deployable application (CDK stack,",
918
+ " mobile app, backend service).",
919
+ "- `packages/<scope>/<name>` \u2014 shared library (published npm",
920
+ " package or workspace-internal library).",
921
+ "- `sites/<scope>/<name>` \u2014 user-facing web front end that is",
922
+ " not the monorepo-wide docs site.",
923
+ "- `docs/` \u2014 the single Starlight documentation site for the",
924
+ " whole monorepo (exactly one per repo; lives at `/docs`, not",
925
+ " under `sites/`).",
926
+ "",
927
+ "Repositories that have not adopted the layout contract may use a",
928
+ "different folder structure \u2014 in that case fall back to whatever",
929
+ `\`${PROJECT_CONTEXT_PATH}\` documents explicitly.`,
930
+ ""
931
+ ];
904
932
  var PROJECT_CONTEXT_READER_SECTION = [
905
933
  "## Project Context",
906
934
  "",
@@ -915,6 +943,7 @@ var PROJECT_CONTEXT_READER_SECTION = [
915
943
  "",
916
944
  "You are a **read-only consumer** of this file. Do not edit it.",
917
945
  "",
946
+ ...SUBPROJECT_ROLE_GUIDANCE,
918
947
  "---",
919
948
  ""
920
949
  ];
@@ -927,6 +956,7 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
927
956
  "key stakeholders. Use it to judge relevance when scanning source",
928
957
  "material in this session.",
929
958
  "",
959
+ ...SUBPROJECT_ROLE_GUIDANCE,
930
960
  "### Seed on first use",
931
961
  "",
932
962
  `If \`${PROJECT_CONTEXT_PATH}\` does not exist, create it from this`,
@@ -956,7 +986,7 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
956
986
  "",
957
987
  "## Key Stakeholders",
958
988
  "TODO: named people or teams and what they care about.",
959
- "",
989
+ "{{monorepoLayoutSeedBlock}}",
960
990
  "## References",
961
991
  "TODO: links to BCM docs, competitive analysis, product roadmap, and",
962
992
  "other authoritative sources.",
@@ -981,6 +1011,26 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
981
1011
  "---",
982
1012
  ""
983
1013
  ];
1014
+ var MONOREPO_LAYOUT_SEED_BLOCK = [
1015
+ "",
1016
+ "## Sub-Projects",
1017
+ "",
1018
+ "TODO: one bullet per sub-project, grouped by role. The role is",
1019
+ "derivable from the first segment of each sub-project's `outdir`.",
1020
+ "",
1021
+ "### Applications (`apps/`)",
1022
+ "TODO: deployable applications (CDK stacks, mobile apps, services).",
1023
+ "",
1024
+ "### Packages (`packages/`)",
1025
+ "TODO: shared libraries (published npm packages, workspace-internal libraries).",
1026
+ "",
1027
+ "### Sites (`sites/`)",
1028
+ "TODO: user-facing web front ends (marketing sites, SPAs, client apps).",
1029
+ "",
1030
+ "### Docs (`docs/`)",
1031
+ "TODO: the single monorepo-wide Starlight documentation site.",
1032
+ ""
1033
+ ].join("\n");
984
1034
 
985
1035
  // src/agent/bundles/bcm-writer.ts
986
1036
  var bcmWriterSubAgent = {
@@ -12507,9 +12557,30 @@ var ProjectMetadata = class _ProjectMetadata extends Component2 {
12507
12557
  labels: options.labels,
12508
12558
  milestones: options.milestones,
12509
12559
  docsPath: options.docsPath,
12510
- deployment: options.deployment
12560
+ deployment: options.deployment,
12561
+ monorepoLayoutSeedBlock: this.resolveMonorepoLayoutSeedBlock()
12511
12562
  };
12512
12563
  }
12564
+ /**
12565
+ * Return the maintainer-seed addendum for the `project-context`
12566
+ * bundle, or an empty string when the root project either has no
12567
+ * layout-enforcement opinion or has opted out (`layoutEnforcement:
12568
+ * "off"`).
12569
+ *
12570
+ * Uses duck-typing on the root project's `layoutEnforcement`
12571
+ * property to avoid a circular import with `MonorepoProject`. The
12572
+ * concrete `MonorepoProject` class exposes this property as a
12573
+ * string; anything else resolves to the empty string so repos that
12574
+ * predate the monorepo layout contract see no change.
12575
+ */
12576
+ resolveMonorepoLayoutSeedBlock() {
12577
+ const root = this.project.root;
12578
+ const enforcement = root.layoutEnforcement;
12579
+ if (typeof enforcement !== "string" || enforcement === "off") {
12580
+ return "";
12581
+ }
12582
+ return MONOREPO_LAYOUT_SEED_BLOCK;
12583
+ }
12513
12584
  /**
12514
12585
  * Attempts to auto-detect repository owner and name from the Projen
12515
12586
  * project's package.json repository field.
@@ -14529,7 +14600,12 @@ var FALLBACKS = {
14529
14600
  "githubProject.name": "<project-name>",
14530
14601
  "githubProject.number": "<project-number>",
14531
14602
  "githubProject.nodeId": "<project-node-id>",
14532
- docsPath: "<docs-path>"
14603
+ docsPath: "<docs-path>",
14604
+ // The monorepo-layout seed block is additive: when absent, the
14605
+ // seeded `project-context.md` template reads cleanly without it.
14606
+ // Fall back to an empty string so no placeholder text leaks into
14607
+ // rendered prompts for repos that predate the layout contract.
14608
+ monorepoLayoutSeedBlock: ""
14533
14609
  };
14534
14610
  var TEMPLATE_RE = /\{\{(\w+(?:\.\w+)*)\}\}/g;
14535
14611
  function getNestedValue(obj, path2) {
@@ -15574,7 +15650,7 @@ function validateMonorepoLayout(root) {
15574
15650
  const rootOutdir = toPosix(root.outdir);
15575
15651
  for (const sub of root.subprojects) {
15576
15652
  const className = sub.constructor.name;
15577
- const expectedRoot = LAYOUT_ROOT_BY_PROJECT_TYPE[className];
15653
+ const expectedRoot = expectedRootFor(sub, className);
15578
15654
  if (expectedRoot === void 0) {
15579
15655
  continue;
15580
15656
  }
@@ -15590,11 +15666,40 @@ function validateMonorepoLayout(root) {
15590
15666
  }
15591
15667
  return violations;
15592
15668
  }
15669
+ function validateStarlightSingleton(root) {
15670
+ const docsRoleProjects = [];
15671
+ for (const sub of root.subprojects) {
15672
+ if (sub.constructor.name !== "StarlightProject") {
15673
+ continue;
15674
+ }
15675
+ if (getStarlightRole(sub) === "docs") {
15676
+ docsRoleProjects.push(sub.name);
15677
+ }
15678
+ }
15679
+ if (docsRoleProjects.length <= 1) {
15680
+ return void 0;
15681
+ }
15682
+ return { projectNames: docsRoleProjects };
15683
+ }
15684
+ function expectedRootFor(sub, className) {
15685
+ if (className === "StarlightProject") {
15686
+ return getStarlightRole(sub) === "site" ? MONOREPO_LAYOUT.SITES : MONOREPO_LAYOUT.DOCS;
15687
+ }
15688
+ return LAYOUT_ROOT_BY_PROJECT_TYPE[className];
15689
+ }
15690
+ function getStarlightRole(sub) {
15691
+ const role = sub.role;
15692
+ return role === "site" ? "site" : "docs";
15693
+ }
15593
15694
  function formatLayoutViolation(violation) {
15594
15695
  const { projectName, projectType, outdir, expectedRoot } = violation;
15595
15696
  const expectedExample = expectedRoot === MONOREPO_LAYOUT.DOCS ? "docs/" : `${expectedRoot}/<scope>/<name>`;
15596
15697
  return `[monorepo-layout] ${projectType} "${projectName}" has outdir "${outdir}", which is outside the expected root "${expectedRoot}/" (expected e.g. "${expectedExample}"). See docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md.`;
15597
15698
  }
15699
+ function formatStarlightSingletonViolation(violation) {
15700
+ const names = violation.projectNames.map((n) => `"${n}"`).join(", ");
15701
+ return `[monorepo-layout] Multiple StarlightProject instances with role: "docs" found (${names}). ADR-006 allows exactly one docs-role Starlight project per MonorepoProject. Either remove the duplicates or set role: "site" on the additional ones so they land under sites/. See docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md.`;
15702
+ }
15598
15703
  function outdirMatchesRoot(relOutdir, expectedRoot) {
15599
15704
  const segments = relOutdir.split("/").filter((s) => s.length > 0);
15600
15705
  if (segments.length === 0) {
@@ -16409,10 +16514,20 @@ var MonorepoProject = class extends TypeScriptAppProject {
16409
16514
  * layout contract. Runs in `preSynthesize` so all sub-projects are
16410
16515
  * attached by the time we inspect the tree.
16411
16516
  *
16517
+ * Two checks run in sequence:
16518
+ *
16519
+ * 1. **Outdir-vs-root validation.** Every sub-project's `outdir` must
16520
+ * live under the root expected for its project type (ADR-006 §4).
16521
+ * 2. **Docs-singleton validation.** At most one `StarlightProject`
16522
+ * may carry `role: "docs"` (ADR-006 §3).
16523
+ *
16412
16524
  * Behavior is controlled by `layoutEnforcement`:
16413
- * - `"off"` — skip validation.
16414
- * - `"warn"` — log a `console.warn` per violation; continue.
16415
- * - `"error"` throw on the first violation.
16525
+ * - `"off"` — skip both checks.
16526
+ * - `"warn"` — log a `console.warn` per violation; continue. Singleton
16527
+ * violations also warn in this mode rather than throwing, so all
16528
+ * layout findings are surfaced consistently.
16529
+ * - `"error"` — throw on the first outdir violation, or on the
16530
+ * singleton violation if outdir validation passed.
16416
16531
  */
16417
16532
  preSynthesize() {
16418
16533
  super.preSynthesize();
@@ -16420,15 +16535,22 @@ var MonorepoProject = class extends TypeScriptAppProject {
16420
16535
  return;
16421
16536
  }
16422
16537
  const violations = validateMonorepoLayout(this);
16423
- if (violations.length === 0) {
16424
- return;
16425
- }
16538
+ const singletonViolation = validateStarlightSingleton(this);
16426
16539
  if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.ERROR) {
16427
- throw new Error(formatLayoutViolation(violations[0]));
16540
+ if (violations.length > 0) {
16541
+ throw new Error(formatLayoutViolation(violations[0]));
16542
+ }
16543
+ if (singletonViolation !== void 0) {
16544
+ throw new Error(formatStarlightSingletonViolation(singletonViolation));
16545
+ }
16546
+ return;
16428
16547
  }
16429
16548
  for (const violation of violations) {
16430
16549
  console.warn(formatLayoutViolation(violation));
16431
16550
  }
16551
+ if (singletonViolation !== void 0) {
16552
+ console.warn(formatStarlightSingletonViolation(singletonViolation));
16553
+ }
16432
16554
  }
16433
16555
  /**
16434
16556
  * Allows a sub project to request installation of dependency at the Monorepo root
@@ -17429,8 +17551,13 @@ var AwsCdkProject = class extends awscdk.AwsCdkTypeScriptApp {
17429
17551
 
17430
17552
  // src/projects/starlight-project.ts
17431
17553
  import { SampleFile as SampleFile2 } from "projen";
17554
+ var STARLIGHT_ROLE = {
17555
+ DOCS: "docs",
17556
+ SITE: "site"
17557
+ };
17432
17558
  var StarlightProject = class extends AstroProject {
17433
17559
  constructor(userOptions) {
17560
+ const role = userOptions.role ?? STARLIGHT_ROLE.DOCS;
17434
17561
  const starlightConfig = buildStarlightConfig(userOptions);
17435
17562
  const starlightSpec = {
17436
17563
  name: "starlight",
@@ -17438,8 +17565,10 @@ var StarlightProject = class extends AstroProject {
17438
17565
  defaultImport: true,
17439
17566
  args: JSON.stringify(starlightConfig, null, 2)
17440
17567
  };
17568
+ const resolvedOutdir = userOptions.outdir ?? (role === STARLIGHT_ROLE.DOCS ? MONOREPO_LAYOUT.DOCS : void 0);
17441
17569
  const mergedOptions = {
17442
17570
  ...userOptions,
17571
+ outdir: resolvedOutdir,
17443
17572
  integrations: [starlightSpec, ...userOptions.integrations ?? []],
17444
17573
  depsUpgradeOptions: {
17445
17574
  ...userOptions.depsUpgradeOptions,
@@ -17451,6 +17580,7 @@ var StarlightProject = class extends AstroProject {
17451
17580
  }
17452
17581
  };
17453
17582
  super(mergedOptions);
17583
+ this.role = role;
17454
17584
  const starlightVersion = userOptions.starlightVersion ?? VERSION.STARLIGHT_VERSION;
17455
17585
  const sharpVersion = userOptions.sharpVersion ?? VERSION.SHARP_VERSION;
17456
17586
  this.addDeps(
@@ -17577,6 +17707,7 @@ export {
17577
17707
  ROOT_CI_TASK_NAME,
17578
17708
  ROOT_TURBO_TASK_NAME,
17579
17709
  ResetTask,
17710
+ STARLIGHT_ROLE,
17580
17711
  StarlightProject,
17581
17712
  TestRunner,
17582
17713
  TurboRepo,
@@ -17596,6 +17727,7 @@ export {
17596
17727
  bcmWriterBundle,
17597
17728
  companyProfileBundle,
17598
17729
  formatLayoutViolation,
17730
+ formatStarlightSingletonViolation,
17599
17731
  getLatestEligibleVersion,
17600
17732
  githubWorkflowBundle,
17601
17733
  industryDiscoveryBundle,
@@ -17622,6 +17754,7 @@ export {
17622
17754
  turborepoBundle,
17623
17755
  typescriptBundle,
17624
17756
  validateMonorepoLayout,
17757
+ validateStarlightSingleton,
17625
17758
  vitestBundle
17626
17759
  };
17627
17760
  //# sourceMappingURL=index.mjs.map