@codedrifters/configulator 0.0.238 → 0.0.240
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.d.mts +103 -1
- package/lib/index.d.ts +104 -2
- package/lib/index.js +198 -0
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +193 -0
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -767,6 +767,91 @@ var baseBundle = {
|
|
|
767
767
|
].join("\n"),
|
|
768
768
|
tags: ["workflow"]
|
|
769
769
|
},
|
|
770
|
+
{
|
|
771
|
+
name: "monorepo-layout",
|
|
772
|
+
description: "Canonical monorepo top-level folders (docs, apps, packages, sites), the @ownerscope/<name> scoping rule, the docs-singleton carve-out, and the scaffolding skills that place new sub-projects",
|
|
773
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
774
|
+
content: [
|
|
775
|
+
"# Monorepo Layout",
|
|
776
|
+
"",
|
|
777
|
+
"Every monorepo built with `@codedrifters/configulator` uses a single,",
|
|
778
|
+
"fixed top-level folder layout. Agents, scaffolding skills, pnpm-workspace",
|
|
779
|
+
"globs, Turbo filters, and CI cache keys all assume these roots.",
|
|
780
|
+
"",
|
|
781
|
+
"## Four Canonical Top-Level Folders",
|
|
782
|
+
"",
|
|
783
|
+
"| Folder | Purpose | Examples |",
|
|
784
|
+
"|--------|---------|----------|",
|
|
785
|
+
"| `/docs` | **Single** Starlight site covering the entire monorepo. The one site that lives outside `/sites`. | Monorepo-wide developer docs, ADRs, how-to guides. |",
|
|
786
|
+
"| `/apps/@scope/<name>` | Deployable applications \u2014 anything that runs or ships as a running process. | AWS CDK stacks, mobile apps (iOS/Android), backend services. |",
|
|
787
|
+
"| `/packages/@scope/<name>` | Shared libraries \u2014 published npm packages and workspace-internal libraries. | `@codedrifters/configulator`, `@codedrifters/constructs`, `@codedrifters/utils`. |",
|
|
788
|
+
"| `/sites/@scope/<name>` | User-facing web front ends that are **not** the monorepo-wide docs site. | Marketing sites, SPAs, per-client static sites. |",
|
|
789
|
+
"",
|
|
790
|
+
"No other top-level folder is part of this contract. Generated roots",
|
|
791
|
+
"(`.projen/`, `.github/`, `node_modules/`, `.turbo/`, etc.) are orthogonal",
|
|
792
|
+
"and unchanged.",
|
|
793
|
+
"",
|
|
794
|
+
"## Scoping Rule",
|
|
795
|
+
"",
|
|
796
|
+
"Every sub-project under `apps/`, `packages/`, or `sites/` is named",
|
|
797
|
+
"`@ownerscope/<name>`, where **scope is the owning party** (not a category).",
|
|
798
|
+
"",
|
|
799
|
+
"- `@codedrifters/configulator` \u2014 a shared library owned by CodeDrifters \u2192 `packages/@codedrifters/configulator`",
|
|
800
|
+
"- `@codedrifters/infrastructure-stack` \u2014 an AWS CDK app owned by CodeDrifters \u2192 `apps/@codedrifters/infrastructure-stack`",
|
|
801
|
+
"- `@clientA/iphone-app` \u2014 a mobile app owned by Client A \u2192 `apps/@clientA/iphone-app`",
|
|
802
|
+
"- `@clientB/marketing-site` \u2014 a marketing site owned by Client B \u2192 `sites/@clientB/marketing-site`",
|
|
803
|
+
"",
|
|
804
|
+
"The scope identifies **who owns the sub-project**, not what kind of",
|
|
805
|
+
"sub-project it is. Kind is captured by the top-level folder (`apps/`,",
|
|
806
|
+
"`packages/`, `sites/`). Never scope by category (e.g. `@apps/foo`,",
|
|
807
|
+
"`@libs/bar`) \u2014 the top-level folder already carries that information.",
|
|
808
|
+
"",
|
|
809
|
+
"## Docs-Singleton Carve-Out",
|
|
810
|
+
"",
|
|
811
|
+
"There is **exactly one** Starlight docs site per monorepo, and it lives",
|
|
812
|
+
"at `/docs`. It is **not** `sites/@scope/docs`.",
|
|
813
|
+
"",
|
|
814
|
+
"- The docs site is monorepo-wide. Sub-project documentation belongs",
|
|
815
|
+
" inside that single site (under `docs/content/`), not in a per-package",
|
|
816
|
+
" `docs/` folder.",
|
|
817
|
+
"- Configulator's `StarlightProject` defaults its `outdir` to `/docs`.",
|
|
818
|
+
"- `/sites` is reserved for end-user-facing web front ends (marketing",
|
|
819
|
+
" sites, SPAs, client-facing apps). It deliberately does not host the",
|
|
820
|
+
" dev-docs site.",
|
|
821
|
+
"",
|
|
822
|
+
"## Project-Type \u2192 `outdir` Mapping",
|
|
823
|
+
"",
|
|
824
|
+
"Configulator project types default their `outdir` according to the",
|
|
825
|
+
"following table. Override `outdir` explicitly only when you have a",
|
|
826
|
+
"genuine reason \u2014 the defaults cover the common path.",
|
|
827
|
+
"",
|
|
828
|
+
"| Configulator project type | Default `outdir` |",
|
|
829
|
+
"|---------------------------|------------------|",
|
|
830
|
+
"| `TypeScriptProject` | `packages/<scope>/<name>` |",
|
|
831
|
+
"| `AwsCdkProject` | `apps/<scope>/<name>` |",
|
|
832
|
+
"| `AstroProject` | `sites/<scope>/<name>` |",
|
|
833
|
+
"| `StarlightProject` (role = docs) | `docs/` |",
|
|
834
|
+
"",
|
|
835
|
+
"`<scope>` is parsed from the sub-project's package name (everything",
|
|
836
|
+
"after `@` and before `/`). `<name>` is the unscoped part of the",
|
|
837
|
+
"package name.",
|
|
838
|
+
"",
|
|
839
|
+
"## Placing New Sub-Projects",
|
|
840
|
+
"",
|
|
841
|
+
"Never hand-roll a sub-project path. Use one of the scaffolding skills,",
|
|
842
|
+
"which take `@scope/<name>` as input, validate it, and place the new",
|
|
843
|
+
"project in the correct folder:",
|
|
844
|
+
"",
|
|
845
|
+
"- `/create-package` \u2014 scaffolds a new `TypeScriptProject` under `packages/<scope>/<name>`",
|
|
846
|
+
"- `/create-app` \u2014 scaffolds a new `AwsCdkProject` under `apps/<scope>/<name>`",
|
|
847
|
+
"- `/create-site` \u2014 scaffolds a new `AstroProject` under `sites/<scope>/<name>`",
|
|
848
|
+
"",
|
|
849
|
+
"The monorepo-wide docs site at `/docs` is a singleton and is created",
|
|
850
|
+
"once per repo via `StarlightProject` \u2014 it is not scaffolded per",
|
|
851
|
+
"sub-project."
|
|
852
|
+
].join("\n"),
|
|
853
|
+
tags: ["project"]
|
|
854
|
+
},
|
|
770
855
|
{
|
|
771
856
|
name: "issue-conventions",
|
|
772
857
|
description: "Issue title prefixes, GitHub issue type mapping, prerequisite issues",
|
|
@@ -15487,6 +15572,77 @@ import {
|
|
|
15487
15572
|
} from "projen/lib/typescript";
|
|
15488
15573
|
import { merge } from "ts-deepmerge";
|
|
15489
15574
|
|
|
15575
|
+
// src/projects/monorepo-layout.ts
|
|
15576
|
+
var MONOREPO_LAYOUT = {
|
|
15577
|
+
DOCS: "docs",
|
|
15578
|
+
APPS: "apps",
|
|
15579
|
+
PACKAGES: "packages",
|
|
15580
|
+
SITES: "sites"
|
|
15581
|
+
};
|
|
15582
|
+
var LAYOUT_ENFORCEMENT = {
|
|
15583
|
+
OFF: "off",
|
|
15584
|
+
WARN: "warn",
|
|
15585
|
+
ERROR: "error"
|
|
15586
|
+
};
|
|
15587
|
+
var LAYOUT_ROOT_BY_PROJECT_TYPE = {
|
|
15588
|
+
TypeScriptProject: MONOREPO_LAYOUT.PACKAGES,
|
|
15589
|
+
AwsCdkProject: MONOREPO_LAYOUT.APPS,
|
|
15590
|
+
AstroProject: MONOREPO_LAYOUT.SITES,
|
|
15591
|
+
StarlightProject: MONOREPO_LAYOUT.DOCS
|
|
15592
|
+
};
|
|
15593
|
+
function validateMonorepoLayout(root) {
|
|
15594
|
+
const violations = [];
|
|
15595
|
+
const rootOutdir = toPosix(root.outdir);
|
|
15596
|
+
for (const sub of root.subprojects) {
|
|
15597
|
+
const className = sub.constructor.name;
|
|
15598
|
+
const expectedRoot = LAYOUT_ROOT_BY_PROJECT_TYPE[className];
|
|
15599
|
+
if (expectedRoot === void 0) {
|
|
15600
|
+
continue;
|
|
15601
|
+
}
|
|
15602
|
+
const relOutdir = relativeOutdir(rootOutdir, toPosix(sub.outdir));
|
|
15603
|
+
if (!outdirMatchesRoot(relOutdir, expectedRoot)) {
|
|
15604
|
+
violations.push({
|
|
15605
|
+
projectName: sub.name,
|
|
15606
|
+
projectType: className,
|
|
15607
|
+
outdir: relOutdir,
|
|
15608
|
+
expectedRoot
|
|
15609
|
+
});
|
|
15610
|
+
}
|
|
15611
|
+
}
|
|
15612
|
+
return violations;
|
|
15613
|
+
}
|
|
15614
|
+
function formatLayoutViolation(violation) {
|
|
15615
|
+
const { projectName, projectType, outdir, expectedRoot } = violation;
|
|
15616
|
+
const expectedExample = expectedRoot === MONOREPO_LAYOUT.DOCS ? "docs/" : `${expectedRoot}/<scope>/<name>`;
|
|
15617
|
+
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.`;
|
|
15618
|
+
}
|
|
15619
|
+
function outdirMatchesRoot(relOutdir, expectedRoot) {
|
|
15620
|
+
const segments = relOutdir.split("/").filter((s) => s.length > 0);
|
|
15621
|
+
if (segments.length === 0) {
|
|
15622
|
+
return false;
|
|
15623
|
+
}
|
|
15624
|
+
if (segments[0] !== expectedRoot) {
|
|
15625
|
+
return false;
|
|
15626
|
+
}
|
|
15627
|
+
if (expectedRoot === MONOREPO_LAYOUT.DOCS) {
|
|
15628
|
+
return true;
|
|
15629
|
+
}
|
|
15630
|
+
return segments.length >= 2;
|
|
15631
|
+
}
|
|
15632
|
+
function toPosix(p) {
|
|
15633
|
+
return p.replace(/\\/g, "/");
|
|
15634
|
+
}
|
|
15635
|
+
function relativeOutdir(rootOutdir, subOutdir) {
|
|
15636
|
+
if (subOutdir === rootOutdir) {
|
|
15637
|
+
return "";
|
|
15638
|
+
}
|
|
15639
|
+
const prefix2 = rootOutdir.endsWith("/") ? rootOutdir : `${rootOutdir}/`;
|
|
15640
|
+
if (subOutdir.startsWith(prefix2)) {
|
|
15641
|
+
return subOutdir.slice(prefix2.length);
|
|
15642
|
+
}
|
|
15643
|
+
return subOutdir;
|
|
15644
|
+
}
|
|
15645
|
+
|
|
15490
15646
|
// src/tasks/reset-task.ts
|
|
15491
15647
|
import { Component as Component13 } from "projen";
|
|
15492
15648
|
var ResetTask = class _ResetTask extends Component13 {
|
|
@@ -15995,6 +16151,11 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
15995
16151
|
* By default treat as a registry consumer (upgrade workflow syncs configulator).
|
|
15996
16152
|
*/
|
|
15997
16153
|
configulatorRegistryConsumer: true,
|
|
16154
|
+
/**
|
|
16155
|
+
* ADR-006 layout enforcement defaults to "warn" during rollout so
|
|
16156
|
+
* legacy outdirs log actionable warnings but do not break synth.
|
|
16157
|
+
*/
|
|
16158
|
+
layoutEnforcement: LAYOUT_ENFORCEMENT.WARN,
|
|
15998
16159
|
/**
|
|
15999
16160
|
* We don't want sample code generated for the root project.
|
|
16000
16161
|
*/
|
|
@@ -16108,6 +16269,7 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
16108
16269
|
this.tsconfig?.removeInclude(`${this.srcdir}/**/*.ts`);
|
|
16109
16270
|
this.pnpmVersion = options.pnpmVersion;
|
|
16110
16271
|
this.configulatorRegistryConsumer = options.configulatorRegistryConsumer ?? true;
|
|
16272
|
+
this.layoutEnforcement = options.layoutEnforcement ?? LAYOUT_ENFORCEMENT.WARN;
|
|
16111
16273
|
new VSCodeConfig(this);
|
|
16112
16274
|
new PnpmWorkspace(this, options.pnpmOptions?.pnpmWorkspaceOptions);
|
|
16113
16275
|
if (options.turbo) {
|
|
@@ -16202,6 +16364,32 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
16202
16364
|
);
|
|
16203
16365
|
}
|
|
16204
16366
|
}
|
|
16367
|
+
/**
|
|
16368
|
+
* Validate sub-project `outdir` values against the ADR-006 monorepo
|
|
16369
|
+
* layout contract. Runs in `preSynthesize` so all sub-projects are
|
|
16370
|
+
* attached by the time we inspect the tree.
|
|
16371
|
+
*
|
|
16372
|
+
* Behavior is controlled by `layoutEnforcement`:
|
|
16373
|
+
* - `"off"` — skip validation.
|
|
16374
|
+
* - `"warn"` — log a `console.warn` per violation; continue.
|
|
16375
|
+
* - `"error"` — throw on the first violation.
|
|
16376
|
+
*/
|
|
16377
|
+
preSynthesize() {
|
|
16378
|
+
super.preSynthesize();
|
|
16379
|
+
if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.OFF) {
|
|
16380
|
+
return;
|
|
16381
|
+
}
|
|
16382
|
+
const violations = validateMonorepoLayout(this);
|
|
16383
|
+
if (violations.length === 0) {
|
|
16384
|
+
return;
|
|
16385
|
+
}
|
|
16386
|
+
if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.ERROR) {
|
|
16387
|
+
throw new Error(formatLayoutViolation(violations[0]));
|
|
16388
|
+
}
|
|
16389
|
+
for (const violation of violations) {
|
|
16390
|
+
console.warn(formatLayoutViolation(violation));
|
|
16391
|
+
}
|
|
16392
|
+
}
|
|
16205
16393
|
/**
|
|
16206
16394
|
* Allows a sub project to request installation of dependency at the Monorepo root
|
|
16207
16395
|
* They must provide a function that is executed after dependencies have been installed
|
|
@@ -17322,10 +17510,13 @@ export {
|
|
|
17322
17510
|
DEFAULT_TEARDOWN_BRANCH_PATTERNS,
|
|
17323
17511
|
DEFAULT_TYPE_LABELS,
|
|
17324
17512
|
JsiiFaker,
|
|
17513
|
+
LAYOUT_ENFORCEMENT,
|
|
17514
|
+
LAYOUT_ROOT_BY_PROJECT_TYPE,
|
|
17325
17515
|
MCP_TRANSPORT,
|
|
17326
17516
|
MERGE_METHODS,
|
|
17327
17517
|
MIMIMUM_RELEASE_AGE,
|
|
17328
17518
|
MINIMUM_RELEASE_AGE,
|
|
17519
|
+
MONOREPO_LAYOUT,
|
|
17329
17520
|
MonorepoProject,
|
|
17330
17521
|
PROD_DEPLOY_NAME,
|
|
17331
17522
|
PnpmWorkspace,
|
|
@@ -17352,6 +17543,7 @@ export {
|
|
|
17352
17543
|
baseBundle,
|
|
17353
17544
|
bcmWriterBundle,
|
|
17354
17545
|
companyProfileBundle,
|
|
17546
|
+
formatLayoutViolation,
|
|
17355
17547
|
getLatestEligibleVersion,
|
|
17356
17548
|
githubWorkflowBundle,
|
|
17357
17549
|
industryDiscoveryBundle,
|
|
@@ -17373,6 +17565,7 @@ export {
|
|
|
17373
17565
|
softwareProfileBundle,
|
|
17374
17566
|
turborepoBundle,
|
|
17375
17567
|
typescriptBundle,
|
|
17568
|
+
validateMonorepoLayout,
|
|
17376
17569
|
vitestBundle
|
|
17377
17570
|
};
|
|
17378
17571
|
//# sourceMappingURL=index.mjs.map
|