@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.js CHANGED
@@ -210,6 +210,7 @@ __export(index_exports, {
210
210
  ROOT_CI_TASK_NAME: () => ROOT_CI_TASK_NAME,
211
211
  ROOT_TURBO_TASK_NAME: () => ROOT_TURBO_TASK_NAME,
212
212
  ResetTask: () => ResetTask,
213
+ STARLIGHT_ROLE: () => STARLIGHT_ROLE,
213
214
  StarlightProject: () => StarlightProject,
214
215
  TestRunner: () => TestRunner,
215
216
  TurboRepo: () => TurboRepo,
@@ -229,6 +230,7 @@ __export(index_exports, {
229
230
  bcmWriterBundle: () => bcmWriterBundle,
230
231
  companyProfileBundle: () => companyProfileBundle,
231
232
  formatLayoutViolation: () => formatLayoutViolation,
233
+ formatStarlightSingletonViolation: () => formatStarlightSingletonViolation,
232
234
  getLatestEligibleVersion: () => getLatestEligibleVersion,
233
235
  githubWorkflowBundle: () => githubWorkflowBundle,
234
236
  industryDiscoveryBundle: () => industryDiscoveryBundle,
@@ -255,6 +257,7 @@ __export(index_exports, {
255
257
  turborepoBundle: () => turborepoBundle,
256
258
  typescriptBundle: () => typescriptBundle,
257
259
  validateMonorepoLayout: () => validateMonorepoLayout,
260
+ validateStarlightSingleton: () => validateStarlightSingleton,
258
261
  vitestBundle: () => vitestBundle
259
262
  });
260
263
  module.exports = __toCommonJS(index_exports);
@@ -901,7 +904,12 @@ var baseBundle = {
901
904
  "- The docs site is monorepo-wide. Sub-project documentation belongs",
902
905
  " inside that single site (under `docs/content/`), not in a per-package",
903
906
  " `docs/` folder.",
904
- "- Configulator's `StarlightProject` defaults its `outdir` to `/docs`.",
907
+ "- Configulator's `StarlightProject` defaults its `outdir` to `/docs` and",
908
+ ' its `role` to `"docs"`. A second `StarlightProject` with `role: "docs"`',
909
+ " fails synth \u2014 the singleton rule is enforced at validate time.",
910
+ "- Additional Starlight sites (client-facing, marketing, etc.) must set",
911
+ ' `role: "site"`, which routes them under `sites/<scope>/<name>` just',
912
+ " like a plain `AstroProject`.",
905
913
  "- `/sites` is reserved for end-user-facing web front ends (marketing",
906
914
  " sites, SPAs, client-facing apps). It deliberately does not host the",
907
915
  " dev-docs site.",
@@ -917,7 +925,8 @@ var baseBundle = {
917
925
  "| `TypeScriptProject` | `packages/<scope>/<name>` |",
918
926
  "| `AwsCdkProject` | `apps/<scope>/<name>` |",
919
927
  "| `AstroProject` | `sites/<scope>/<name>` |",
920
- "| `StarlightProject` (role = docs) | `docs/` |",
928
+ "| `StarlightProject` (role = docs, default) | `docs/` |",
929
+ "| `StarlightProject` (role = site) | `sites/<scope>/<name>` |",
921
930
  "",
922
931
  "`<scope>` is parsed from the sub-project's package name (everything",
923
932
  "after `@` and before `/`). `<name>` is the unscoped part of the",
@@ -988,6 +997,28 @@ var baseBundle = {
988
997
 
989
998
  // src/agent/bundles/project-context.ts
990
999
  var PROJECT_CONTEXT_PATH = "docs/project-context.md";
1000
+ var SUBPROJECT_ROLE_GUIDANCE = [
1001
+ "### Sub-project roles",
1002
+ "",
1003
+ "When the repository follows the configulator monorepo layout,",
1004
+ "every sub-project's role is derivable from the first segment of",
1005
+ "its `outdir` path. No other lookup is required.",
1006
+ "",
1007
+ "- `apps/<scope>/<name>` \u2014 deployable application (CDK stack,",
1008
+ " mobile app, backend service).",
1009
+ "- `packages/<scope>/<name>` \u2014 shared library (published npm",
1010
+ " package or workspace-internal library).",
1011
+ "- `sites/<scope>/<name>` \u2014 user-facing web front end that is",
1012
+ " not the monorepo-wide docs site.",
1013
+ "- `docs/` \u2014 the single Starlight documentation site for the",
1014
+ " whole monorepo (exactly one per repo; lives at `/docs`, not",
1015
+ " under `sites/`).",
1016
+ "",
1017
+ "Repositories that have not adopted the layout contract may use a",
1018
+ "different folder structure \u2014 in that case fall back to whatever",
1019
+ `\`${PROJECT_CONTEXT_PATH}\` documents explicitly.`,
1020
+ ""
1021
+ ];
991
1022
  var PROJECT_CONTEXT_READER_SECTION = [
992
1023
  "## Project Context",
993
1024
  "",
@@ -1002,6 +1033,7 @@ var PROJECT_CONTEXT_READER_SECTION = [
1002
1033
  "",
1003
1034
  "You are a **read-only consumer** of this file. Do not edit it.",
1004
1035
  "",
1036
+ ...SUBPROJECT_ROLE_GUIDANCE,
1005
1037
  "---",
1006
1038
  ""
1007
1039
  ];
@@ -1014,6 +1046,7 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
1014
1046
  "key stakeholders. Use it to judge relevance when scanning source",
1015
1047
  "material in this session.",
1016
1048
  "",
1049
+ ...SUBPROJECT_ROLE_GUIDANCE,
1017
1050
  "### Seed on first use",
1018
1051
  "",
1019
1052
  `If \`${PROJECT_CONTEXT_PATH}\` does not exist, create it from this`,
@@ -1043,7 +1076,7 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
1043
1076
  "",
1044
1077
  "## Key Stakeholders",
1045
1078
  "TODO: named people or teams and what they care about.",
1046
- "",
1079
+ "{{monorepoLayoutSeedBlock}}",
1047
1080
  "## References",
1048
1081
  "TODO: links to BCM docs, competitive analysis, product roadmap, and",
1049
1082
  "other authoritative sources.",
@@ -1068,6 +1101,26 @@ var PROJECT_CONTEXT_MAINTAINER_SECTION = [
1068
1101
  "---",
1069
1102
  ""
1070
1103
  ];
1104
+ var MONOREPO_LAYOUT_SEED_BLOCK = [
1105
+ "",
1106
+ "## Sub-Projects",
1107
+ "",
1108
+ "TODO: one bullet per sub-project, grouped by role. The role is",
1109
+ "derivable from the first segment of each sub-project's `outdir`.",
1110
+ "",
1111
+ "### Applications (`apps/`)",
1112
+ "TODO: deployable applications (CDK stacks, mobile apps, services).",
1113
+ "",
1114
+ "### Packages (`packages/`)",
1115
+ "TODO: shared libraries (published npm packages, workspace-internal libraries).",
1116
+ "",
1117
+ "### Sites (`sites/`)",
1118
+ "TODO: user-facing web front ends (marketing sites, SPAs, client apps).",
1119
+ "",
1120
+ "### Docs (`docs/`)",
1121
+ "TODO: the single monorepo-wide Starlight documentation site.",
1122
+ ""
1123
+ ].join("\n");
1071
1124
 
1072
1125
  // src/agent/bundles/bcm-writer.ts
1073
1126
  var bcmWriterSubAgent = {
@@ -12594,9 +12647,30 @@ var ProjectMetadata = class _ProjectMetadata extends import_projen2.Component {
12594
12647
  labels: options.labels,
12595
12648
  milestones: options.milestones,
12596
12649
  docsPath: options.docsPath,
12597
- deployment: options.deployment
12650
+ deployment: options.deployment,
12651
+ monorepoLayoutSeedBlock: this.resolveMonorepoLayoutSeedBlock()
12598
12652
  };
12599
12653
  }
12654
+ /**
12655
+ * Return the maintainer-seed addendum for the `project-context`
12656
+ * bundle, or an empty string when the root project either has no
12657
+ * layout-enforcement opinion or has opted out (`layoutEnforcement:
12658
+ * "off"`).
12659
+ *
12660
+ * Uses duck-typing on the root project's `layoutEnforcement`
12661
+ * property to avoid a circular import with `MonorepoProject`. The
12662
+ * concrete `MonorepoProject` class exposes this property as a
12663
+ * string; anything else resolves to the empty string so repos that
12664
+ * predate the monorepo layout contract see no change.
12665
+ */
12666
+ resolveMonorepoLayoutSeedBlock() {
12667
+ const root = this.project.root;
12668
+ const enforcement = root.layoutEnforcement;
12669
+ if (typeof enforcement !== "string" || enforcement === "off") {
12670
+ return "";
12671
+ }
12672
+ return MONOREPO_LAYOUT_SEED_BLOCK;
12673
+ }
12600
12674
  /**
12601
12675
  * Attempts to auto-detect repository owner and name from the Projen
12602
12676
  * project's package.json repository field.
@@ -14616,7 +14690,12 @@ var FALLBACKS = {
14616
14690
  "githubProject.name": "<project-name>",
14617
14691
  "githubProject.number": "<project-number>",
14618
14692
  "githubProject.nodeId": "<project-node-id>",
14619
- docsPath: "<docs-path>"
14693
+ docsPath: "<docs-path>",
14694
+ // The monorepo-layout seed block is additive: when absent, the
14695
+ // seeded `project-context.md` template reads cleanly without it.
14696
+ // Fall back to an empty string so no placeholder text leaks into
14697
+ // rendered prompts for repos that predate the layout contract.
14698
+ monorepoLayoutSeedBlock: ""
14620
14699
  };
14621
14700
  var TEMPLATE_RE = /\{\{(\w+(?:\.\w+)*)\}\}/g;
14622
14701
  function getNestedValue(obj, path2) {
@@ -15661,7 +15740,7 @@ function validateMonorepoLayout(root) {
15661
15740
  const rootOutdir = toPosix(root.outdir);
15662
15741
  for (const sub of root.subprojects) {
15663
15742
  const className = sub.constructor.name;
15664
- const expectedRoot = LAYOUT_ROOT_BY_PROJECT_TYPE[className];
15743
+ const expectedRoot = expectedRootFor(sub, className);
15665
15744
  if (expectedRoot === void 0) {
15666
15745
  continue;
15667
15746
  }
@@ -15677,11 +15756,40 @@ function validateMonorepoLayout(root) {
15677
15756
  }
15678
15757
  return violations;
15679
15758
  }
15759
+ function validateStarlightSingleton(root) {
15760
+ const docsRoleProjects = [];
15761
+ for (const sub of root.subprojects) {
15762
+ if (sub.constructor.name !== "StarlightProject") {
15763
+ continue;
15764
+ }
15765
+ if (getStarlightRole(sub) === "docs") {
15766
+ docsRoleProjects.push(sub.name);
15767
+ }
15768
+ }
15769
+ if (docsRoleProjects.length <= 1) {
15770
+ return void 0;
15771
+ }
15772
+ return { projectNames: docsRoleProjects };
15773
+ }
15774
+ function expectedRootFor(sub, className) {
15775
+ if (className === "StarlightProject") {
15776
+ return getStarlightRole(sub) === "site" ? MONOREPO_LAYOUT.SITES : MONOREPO_LAYOUT.DOCS;
15777
+ }
15778
+ return LAYOUT_ROOT_BY_PROJECT_TYPE[className];
15779
+ }
15780
+ function getStarlightRole(sub) {
15781
+ const role = sub.role;
15782
+ return role === "site" ? "site" : "docs";
15783
+ }
15680
15784
  function formatLayoutViolation(violation) {
15681
15785
  const { projectName, projectType, outdir, expectedRoot } = violation;
15682
15786
  const expectedExample = expectedRoot === MONOREPO_LAYOUT.DOCS ? "docs/" : `${expectedRoot}/<scope>/<name>`;
15683
15787
  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.`;
15684
15788
  }
15789
+ function formatStarlightSingletonViolation(violation) {
15790
+ const names = violation.projectNames.map((n) => `"${n}"`).join(", ");
15791
+ 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.`;
15792
+ }
15685
15793
  function outdirMatchesRoot(relOutdir, expectedRoot) {
15686
15794
  const segments = relOutdir.split("/").filter((s) => s.length > 0);
15687
15795
  if (segments.length === 0) {
@@ -16487,10 +16595,20 @@ var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
16487
16595
  * layout contract. Runs in `preSynthesize` so all sub-projects are
16488
16596
  * attached by the time we inspect the tree.
16489
16597
  *
16598
+ * Two checks run in sequence:
16599
+ *
16600
+ * 1. **Outdir-vs-root validation.** Every sub-project's `outdir` must
16601
+ * live under the root expected for its project type (ADR-006 §4).
16602
+ * 2. **Docs-singleton validation.** At most one `StarlightProject`
16603
+ * may carry `role: "docs"` (ADR-006 §3).
16604
+ *
16490
16605
  * Behavior is controlled by `layoutEnforcement`:
16491
- * - `"off"` — skip validation.
16492
- * - `"warn"` — log a `console.warn` per violation; continue.
16493
- * - `"error"` throw on the first violation.
16606
+ * - `"off"` — skip both checks.
16607
+ * - `"warn"` — log a `console.warn` per violation; continue. Singleton
16608
+ * violations also warn in this mode rather than throwing, so all
16609
+ * layout findings are surfaced consistently.
16610
+ * - `"error"` — throw on the first outdir violation, or on the
16611
+ * singleton violation if outdir validation passed.
16494
16612
  */
16495
16613
  preSynthesize() {
16496
16614
  super.preSynthesize();
@@ -16498,15 +16616,22 @@ var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
16498
16616
  return;
16499
16617
  }
16500
16618
  const violations = validateMonorepoLayout(this);
16501
- if (violations.length === 0) {
16502
- return;
16503
- }
16619
+ const singletonViolation = validateStarlightSingleton(this);
16504
16620
  if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.ERROR) {
16505
- throw new Error(formatLayoutViolation(violations[0]));
16621
+ if (violations.length > 0) {
16622
+ throw new Error(formatLayoutViolation(violations[0]));
16623
+ }
16624
+ if (singletonViolation !== void 0) {
16625
+ throw new Error(formatStarlightSingletonViolation(singletonViolation));
16626
+ }
16627
+ return;
16506
16628
  }
16507
16629
  for (const violation of violations) {
16508
16630
  console.warn(formatLayoutViolation(violation));
16509
16631
  }
16632
+ if (singletonViolation !== void 0) {
16633
+ console.warn(formatStarlightSingletonViolation(singletonViolation));
16634
+ }
16510
16635
  }
16511
16636
  /**
16512
16637
  * Allows a sub project to request installation of dependency at the Monorepo root
@@ -17503,8 +17628,13 @@ var AwsCdkProject = class extends import_projen20.awscdk.AwsCdkTypeScriptApp {
17503
17628
 
17504
17629
  // src/projects/starlight-project.ts
17505
17630
  var import_projen21 = require("projen");
17631
+ var STARLIGHT_ROLE = {
17632
+ DOCS: "docs",
17633
+ SITE: "site"
17634
+ };
17506
17635
  var StarlightProject = class extends AstroProject {
17507
17636
  constructor(userOptions) {
17637
+ const role = userOptions.role ?? STARLIGHT_ROLE.DOCS;
17508
17638
  const starlightConfig = buildStarlightConfig(userOptions);
17509
17639
  const starlightSpec = {
17510
17640
  name: "starlight",
@@ -17512,8 +17642,10 @@ var StarlightProject = class extends AstroProject {
17512
17642
  defaultImport: true,
17513
17643
  args: JSON.stringify(starlightConfig, null, 2)
17514
17644
  };
17645
+ const resolvedOutdir = userOptions.outdir ?? (role === STARLIGHT_ROLE.DOCS ? MONOREPO_LAYOUT.DOCS : void 0);
17515
17646
  const mergedOptions = {
17516
17647
  ...userOptions,
17648
+ outdir: resolvedOutdir,
17517
17649
  integrations: [starlightSpec, ...userOptions.integrations ?? []],
17518
17650
  depsUpgradeOptions: {
17519
17651
  ...userOptions.depsUpgradeOptions,
@@ -17525,6 +17657,7 @@ var StarlightProject = class extends AstroProject {
17525
17657
  }
17526
17658
  };
17527
17659
  super(mergedOptions);
17660
+ this.role = role;
17528
17661
  const starlightVersion = userOptions.starlightVersion ?? VERSION.STARLIGHT_VERSION;
17529
17662
  const sharpVersion = userOptions.sharpVersion ?? VERSION.SHARP_VERSION;
17530
17663
  this.addDeps(
@@ -17652,6 +17785,7 @@ var TypeScriptConfig = class extends import_projen22.Component {
17652
17785
  ROOT_CI_TASK_NAME,
17653
17786
  ROOT_TURBO_TASK_NAME,
17654
17787
  ResetTask,
17788
+ STARLIGHT_ROLE,
17655
17789
  StarlightProject,
17656
17790
  TestRunner,
17657
17791
  TurboRepo,
@@ -17671,6 +17805,7 @@ var TypeScriptConfig = class extends import_projen22.Component {
17671
17805
  bcmWriterBundle,
17672
17806
  companyProfileBundle,
17673
17807
  formatLayoutViolation,
17808
+ formatStarlightSingletonViolation,
17674
17809
  getLatestEligibleVersion,
17675
17810
  githubWorkflowBundle,
17676
17811
  industryDiscoveryBundle,
@@ -17697,6 +17832,7 @@ var TypeScriptConfig = class extends import_projen22.Component {
17697
17832
  turborepoBundle,
17698
17833
  typescriptBundle,
17699
17834
  validateMonorepoLayout,
17835
+ validateStarlightSingleton,
17700
17836
  vitestBundle
17701
17837
  });
17702
17838
  //# sourceMappingURL=index.js.map