@supacloud/compiler 0.3.1 → 0.4.1

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/dist/compile.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- import type { CompileOptions, CompileResult } from "./types";
1
+ import type { CheckProjectResult, CompileOptions, CompileResult } from "./types";
2
2
  /**
3
- * 完整编译流程:AST 分析 → 校验 → 生成静态工厂代码与 manifest。
4
- * 即使存在 error 级诊断也会照常写出文件,由调用方根据 diagnostics 决定是否采用。
3
+ * Complete compilation pipeline: AST analysis -> validation -> generate static factory code and manifest.
4
+ * Files are emitted even when error-level diagnostics exist; caller decides adoption based on diagnostics.
5
5
  */
6
6
  export declare function compileProject(options: CompileOptions): Promise<CompileResult>;
7
+ /**
8
+ * Check generated artifacts without writing files to disk.
9
+ * Analyze the AST, run governance checks, and compare application.ts and app.manifest.json.
10
+ */
11
+ export declare function checkProject(options: CompileOptions): Promise<CheckProjectResult>;
@@ -3,8 +3,14 @@ export interface GenerateOptions {
3
3
  rootDir: string;
4
4
  outDir: string;
5
5
  }
6
+ export interface RenderedArtifacts {
7
+ applicationCode: string;
8
+ manifestJson: string;
9
+ }
10
+ /** Render application.ts and app.manifest.json content without file I/O. */
11
+ export declare function renderApplication(graph: ApplicationGraph, options: GenerateOptions): RenderedArtifacts;
6
12
  /**
7
- * 生成静态工厂代码(application.ts)与 app.manifest.json,返回写入的绝对路径。
8
- * 生成代码只 import 业务类/schema,不 import @supacloud/app,运行期无反射、无容器。
13
+ * Generate static factory code (application.ts) and app.manifest.json.
14
+ * Generated code imports only application classes and schemas, with no runtime reflection or container lookup.
9
15
  */
10
16
  export declare function generateApplication(graph: ApplicationGraph, options: GenerateOptions): Promise<string[]>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export { analyzeProject } from "./analyze";
2
- export { compileProject } from "./compile";
3
- export { generateApplication } from "./generate";
4
- export type { GenerateOptions } from "./generate";
2
+ export { checkProject, compileProject } from "./compile";
3
+ export { generateApplication, renderApplication } from "./generate";
4
+ export type { GenerateOptions, RenderedArtifacts } from "./generate";
5
5
  export { validateGraph } from "./validate";
6
6
  export { camelName } from "./util";
7
- export type { ApplicationGraph, CommandNode, CompileOptions, CompileResult, ControllerNode, Diagnostic, ModuleBoundaryRule, ModuleNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, } from "./types";
7
+ export { ANGULAR_ENTERPRISE_RULES, CLEAN_ARCHITECTURE_RULES, MODULAR_MONOLITH_RULES, MODULE_BOUNDARY_PROFILES, getModuleBoundaryPreset, getModuleBoundaryProfile, resolveModuleBoundaries, } from "./profiles";
8
+ export type { ApplicationGraph, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, CompileResult, ControllerNode, Diagnostic, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, ValidateOptions, } from "./types";
package/dist/index.js CHANGED
@@ -12,7 +12,9 @@ var ROUTE_DECORATORS = {
12
12
  Post: "POST",
13
13
  Put: "PUT",
14
14
  Patch: "PATCH",
15
- Delete: "DELETE"
15
+ Delete: "DELETE",
16
+ Head: "HEAD",
17
+ Options: "OPTIONS"
16
18
  };
17
19
  var SCOPES = ["application", "request", "job"];
18
20
  async function analyzeProject(rootDir, include) {
@@ -674,7 +676,7 @@ export interface CompiledModule {
674
676
  controllers: CompiledController[];
675
677
  commands: CompiledCommand[];
676
678
  }`;
677
- async function generateApplication(graph, options) {
679
+ function renderApplication(graph, options) {
678
680
  const modules = topoSortModules(graph.modules);
679
681
  const imports = new ImportManager;
680
682
  const factorySections = [];
@@ -706,12 +708,19 @@ async function generateApplication(graph, options) {
706
708
  modules: graph.modules,
707
709
  externalTokens: graph.externalTokens
708
710
  };
711
+ return {
712
+ applicationCode: code,
713
+ manifestJson: JSON.stringify(manifest, null, 2) + `
714
+ `
715
+ };
716
+ }
717
+ async function generateApplication(graph, options) {
718
+ const rendered = renderApplication(graph, options);
709
719
  await mkdir(options.outDir, { recursive: true });
710
720
  const applicationPath = join2(options.outDir, "application.ts");
711
721
  const manifestPath = join2(options.outDir, "app.manifest.json");
712
- await writeFile(applicationPath, code, "utf8");
713
- await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + `
714
- `, "utf8");
722
+ await writeFile(applicationPath, rendered.applicationCode, "utf8");
723
+ await writeFile(manifestPath, rendered.manifestJson, "utf8");
715
724
  return [applicationPath, manifestPath];
716
725
  }
717
726
  function factoryOfScope(scope) {
@@ -1008,6 +1017,173 @@ function orderProviders(providers) {
1008
1017
  return result;
1009
1018
  }
1010
1019
 
1020
+ // src/profiles.ts
1021
+ var MODULAR_MONOLITH_RULES = [
1022
+ {
1023
+ sourceTag: "type:feature",
1024
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1025
+ },
1026
+ {
1027
+ sourceTag: "type:root",
1028
+ onlyDependOnLibsWithTags: ["type:feature", "type:core", "type:shared", "type:domain"]
1029
+ },
1030
+ {
1031
+ sourceTag: "type:app",
1032
+ onlyDependOnLibsWithTags: ["type:feature", "type:core", "type:shared", "type:domain"]
1033
+ },
1034
+ {
1035
+ sourceTag: "type:core",
1036
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1037
+ },
1038
+ {
1039
+ sourceTag: "type:shared",
1040
+ bannedDependenciesWithTags: ["type:feature", "type:core", "type:root", "type:app"]
1041
+ }
1042
+ ];
1043
+ var ANGULAR_ENTERPRISE_RULES = [
1044
+ {
1045
+ sourceTag: "type:feature",
1046
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1047
+ },
1048
+ {
1049
+ sourceTag: "type:ui",
1050
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1051
+ },
1052
+ {
1053
+ sourceTag: "type:data-access",
1054
+ bannedDependenciesWithTags: ["type:feature", "type:ui", "type:root", "type:app"]
1055
+ },
1056
+ {
1057
+ sourceTag: "type:util",
1058
+ bannedDependenciesWithTags: ["type:feature", "type:ui", "type:data-access", "type:root", "type:app"]
1059
+ },
1060
+ {
1061
+ sourceTag: "type:shared",
1062
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1063
+ },
1064
+ {
1065
+ sourceTag: "type:core",
1066
+ bannedDependenciesWithTags: ["type:feature", "type:root", "type:app"]
1067
+ },
1068
+ {
1069
+ sourceTag: "type:root",
1070
+ onlyDependOnLibsWithTags: ["type:feature", "type:ui", "type:data-access", "type:core", "type:shared", "type:util"]
1071
+ },
1072
+ {
1073
+ sourceTag: "type:app",
1074
+ onlyDependOnLibsWithTags: ["type:feature", "type:ui", "type:data-access", "type:core", "type:shared", "type:util"]
1075
+ }
1076
+ ];
1077
+ var CLEAN_ARCHITECTURE_RULES = [
1078
+ {
1079
+ sourceTag: "type:api",
1080
+ onlyDependOnLibsWithTags: ["type:application", "type:domain", "type:shared", "type:common"]
1081
+ },
1082
+ {
1083
+ sourceTag: "type:controller",
1084
+ onlyDependOnLibsWithTags: ["type:application", "type:domain", "type:shared", "type:common"]
1085
+ },
1086
+ {
1087
+ sourceTag: "type:presentation",
1088
+ onlyDependOnLibsWithTags: ["type:application", "type:domain", "type:shared", "type:common"]
1089
+ },
1090
+ {
1091
+ sourceTag: "type:application",
1092
+ onlyDependOnLibsWithTags: ["type:domain", "type:shared", "type:common"]
1093
+ },
1094
+ {
1095
+ sourceTag: "type:service",
1096
+ onlyDependOnLibsWithTags: ["type:domain", "type:shared", "type:common"]
1097
+ },
1098
+ {
1099
+ sourceTag: "type:domain",
1100
+ bannedDependenciesWithTags: [
1101
+ "type:api",
1102
+ "type:controller",
1103
+ "type:presentation",
1104
+ "type:application",
1105
+ "type:service",
1106
+ "type:infrastructure",
1107
+ "type:infra",
1108
+ "type:root",
1109
+ "type:app"
1110
+ ]
1111
+ },
1112
+ {
1113
+ sourceTag: "type:infrastructure",
1114
+ onlyDependOnLibsWithTags: ["type:domain", "type:shared", "type:common"]
1115
+ },
1116
+ {
1117
+ sourceTag: "type:infra",
1118
+ onlyDependOnLibsWithTags: ["type:domain", "type:shared", "type:common"]
1119
+ }
1120
+ ];
1121
+ var MODULE_BOUNDARY_PROFILES = {
1122
+ "modular-monolith": {
1123
+ name: "modular-monolith",
1124
+ description: "Modular monolith / vertical slice preset (blocks cross-feature dependencies and limits root aggregation to feature/core/shared/domain)",
1125
+ rules: MODULAR_MONOLITH_RULES
1126
+ },
1127
+ "feature-slices": {
1128
+ name: "feature-slices",
1129
+ description: "Vertical slice preset (alias for modular-monolith)",
1130
+ rules: MODULAR_MONOLITH_RULES
1131
+ },
1132
+ "vertical-slices": {
1133
+ name: "vertical-slices",
1134
+ description: "Vertical slice architecture preset (alias for modular-monolith)",
1135
+ rules: MODULAR_MONOLITH_RULES
1136
+ },
1137
+ "angular-enterprise": {
1138
+ name: "angular-enterprise",
1139
+ description: "Angular / Nx enterprise monorepo preset (enforces one-way layering across feature, UI, data-access, util, shared, and root modules)",
1140
+ rules: ANGULAR_ENTERPRISE_RULES
1141
+ },
1142
+ angular: {
1143
+ name: "angular",
1144
+ description: "Angular enterprise layering preset (alias for angular-enterprise)",
1145
+ rules: ANGULAR_ENTERPRISE_RULES
1146
+ },
1147
+ "clean-architecture": {
1148
+ name: "clean-architecture",
1149
+ description: "Clean Architecture / DDD layering preset (API/presentation -> application -> domain <- infrastructure)",
1150
+ rules: CLEAN_ARCHITECTURE_RULES
1151
+ },
1152
+ "domain-driven": {
1153
+ name: "domain-driven",
1154
+ description: "DDD layering preset (alias for clean-architecture)",
1155
+ rules: CLEAN_ARCHITECTURE_RULES
1156
+ }
1157
+ };
1158
+ function getModuleBoundaryProfile(name) {
1159
+ const profile = MODULE_BOUNDARY_PROFILES[name];
1160
+ if (!profile) {
1161
+ throw new Error(`Unknown module boundary preset: '${name}'. Supported presets: ${Object.keys(MODULE_BOUNDARY_PROFILES).join(", ")}`);
1162
+ }
1163
+ return {
1164
+ ...profile,
1165
+ rules: profile.rules.map((rule) => ({
1166
+ ...rule,
1167
+ onlyDependOnLibsWithTags: rule.onlyDependOnLibsWithTags ? [...rule.onlyDependOnLibsWithTags] : undefined,
1168
+ bannedDependenciesWithTags: rule.bannedDependenciesWithTags ? [...rule.bannedDependenciesWithTags] : undefined
1169
+ }))
1170
+ };
1171
+ }
1172
+ function getModuleBoundaryPreset(name) {
1173
+ return getModuleBoundaryProfile(name).rules;
1174
+ }
1175
+ function resolveModuleBoundaries(options) {
1176
+ if (!options)
1177
+ return;
1178
+ const { preset, rules } = options;
1179
+ if (!preset && !rules)
1180
+ return;
1181
+ const presetRules = preset ? getModuleBoundaryPreset(preset) : [];
1182
+ const customRules = rules ?? [];
1183
+ const merged = [...presetRules, ...customRules];
1184
+ return merged.length > 0 ? merged : undefined;
1185
+ }
1186
+
1011
1187
  // src/validate.ts
1012
1188
  var SCOPE_LIFETIME_RANK = {
1013
1189
  application: 0,
@@ -1016,8 +1192,24 @@ var SCOPE_LIFETIME_RANK = {
1016
1192
  };
1017
1193
  function validateGraph(graph, options = false) {
1018
1194
  const strict = typeof options === "boolean" ? options : options.strict ?? false;
1019
- const moduleBoundaries = typeof options === "object" ? options.moduleBoundaries : undefined;
1020
1195
  const diagnostics = [];
1196
+ let moduleBoundaries;
1197
+ if (typeof options === "object") {
1198
+ try {
1199
+ moduleBoundaries = resolveModuleBoundaries({
1200
+ preset: options.moduleBoundaryPreset,
1201
+ rules: options.moduleBoundaries
1202
+ });
1203
+ } catch (err) {
1204
+ diagnostics.push({
1205
+ severity: "error",
1206
+ code: "invalid-boundary-preset",
1207
+ message: err instanceof Error ? err.message : String(err),
1208
+ file: graph.modules[0]?.file,
1209
+ line: graph.modules[0]?.line
1210
+ });
1211
+ }
1212
+ }
1021
1213
  const globalProviders = new Map;
1022
1214
  for (const module of graph.modules) {
1023
1215
  for (const provider of module.providers) {
@@ -1079,6 +1271,17 @@ function validateGraph(graph, options = false) {
1079
1271
  if (route.command && !module.commands.some((command) => command.className === route.command)) {
1080
1272
  error("route-command-unresolved", `路由 ${key} 绑定的 command 类 ${route.command} 未在模块 ${module.name} 声明`, controller.file);
1081
1273
  }
1274
+ if (typeof options === "object" && options.allowRouteCommandBindings === false && route.command) {
1275
+ error("route-command-binding-disallowed", `Route ${key} binds command ${route.command}, but route-level command bindings are disabled by policy. Use an application service (${controller.className}.${route.handler}, ${controller.file}).`, controller.file);
1276
+ }
1277
+ }
1278
+ if (typeof options === "object" && options.disallowControllerDirectDb) {
1279
+ for (const dep of controller.deps) {
1280
+ const isDbClient = dep === "DB_CLIENT" || dep === "DatabaseClient" || graph.tokenNames?.[dep] === "supacloud.db-client";
1281
+ if (isDbClient) {
1282
+ error("controller-direct-db-access", `Controller ${controller.className} directly injects database client '${dep}', violating presentation layer separation (${controller.file})`, controller.file);
1283
+ }
1284
+ }
1082
1285
  }
1083
1286
  }
1084
1287
  }
@@ -1115,6 +1318,26 @@ function validateGraph(graph, options = false) {
1115
1318
  if (!command.permission) {
1116
1319
  error("command-missing-permission", `模块 ${module.name} 的 command ${command.name} (${command.className}) 未声明 permission`, module.file, module.line);
1117
1320
  }
1321
+ if (typeof options === "object" && options.commandCapabilities) {
1322
+ const caps = options.commandCapabilities;
1323
+ const location = `${command.className} (${module.file})`;
1324
+ if (command.permission && caps.permission === false) {
1325
+ error("command-permission-unsupported", `Command ${command.name} declares permission, but runtime permission checks are unavailable (${location}).`, module.file, module.line);
1326
+ }
1327
+ if (command.audit && caps.audit === false) {
1328
+ error("command-audit-unsupported", `Command ${command.name} declares audit, but audit persistence is unavailable (${location}).`, module.file, module.line);
1329
+ }
1330
+ if (command.idempotency === "required" && caps.idempotency === false) {
1331
+ error("command-idempotency-unsupported", `Command ${command.name} declares idempotency, but idempotency receipt persistence is unavailable (${location}).`, module.file, module.line);
1332
+ }
1333
+ if (command.transaction === "required") {
1334
+ if (caps.transaction === "rpc-only") {
1335
+ warn2("command-transaction-rpc-only", `Command ${command.name} declares transaction: 'required', but only DB RPC transactions are available; multi-table writes must use one DB RPC (${location}).`, module.file, module.line);
1336
+ } else if (caps.transaction === false) {
1337
+ error("command-transaction-unsupported", `Command ${command.name} declares transaction: 'required', but transaction support is unavailable (${location}).`, module.file, module.line);
1338
+ }
1339
+ }
1340
+ }
1118
1341
  }
1119
1342
  }
1120
1343
  if (moduleBoundaries && moduleBoundaries.length > 0) {
@@ -1147,6 +1370,10 @@ function validateGraph(graph, options = false) {
1147
1370
  }
1148
1371
  }
1149
1372
  diagnostics.push(...detectCycles(graph, resolveDep));
1373
+ diagnostics.push(...detectModuleCycles(graph));
1374
+ if (typeof options === "object" && options.detectOrphanModules) {
1375
+ diagnostics.push(...detectOrphanModules(graph));
1376
+ }
1150
1377
  return diagnostics;
1151
1378
  }
1152
1379
  function joinRoutePaths(prefix, path) {
@@ -1196,15 +1423,102 @@ function detectCycles(graph, resolveDep) {
1196
1423
  visit(ref);
1197
1424
  return diagnostics;
1198
1425
  }
1426
+ function detectModuleCycles(graph) {
1427
+ const diagnostics = [];
1428
+ const moduleMap = new Map(graph.modules.map((m) => [m.name, m]));
1429
+ const state = new Map;
1430
+ const stack = [];
1431
+ const reported = new Set;
1432
+ const visit = (name) => {
1433
+ if (state.get(name) === "done")
1434
+ return;
1435
+ if (state.get(name) === "visiting") {
1436
+ const cycleStart = stack.indexOf(name);
1437
+ const cycle = [...stack.slice(cycleStart), name];
1438
+ const cycleKey = [...cycle].sort().join("|");
1439
+ if (!reported.has(cycleKey)) {
1440
+ reported.add(cycleKey);
1441
+ const mod2 = moduleMap.get(name);
1442
+ diagnostics.push({
1443
+ severity: "error",
1444
+ code: "circular-module-import",
1445
+ message: `Module circular import detected: ${cycle.join(" -> ")}`,
1446
+ file: mod2?.file,
1447
+ line: mod2?.line
1448
+ });
1449
+ }
1450
+ return;
1451
+ }
1452
+ state.set(name, "visiting");
1453
+ stack.push(name);
1454
+ const mod = moduleMap.get(name);
1455
+ if (mod) {
1456
+ for (const importName of mod.imports) {
1457
+ if (moduleMap.has(importName)) {
1458
+ visit(importName);
1459
+ }
1460
+ }
1461
+ }
1462
+ stack.pop();
1463
+ state.set(name, "done");
1464
+ };
1465
+ for (const mod of graph.modules) {
1466
+ visit(mod.name);
1467
+ }
1468
+ return diagnostics;
1469
+ }
1470
+ function detectOrphanModules(graph) {
1471
+ const diagnostics = [];
1472
+ const rootModules = graph.modules.filter((m) => m.tags && (m.tags.includes("type:root") || m.tags.includes("type:app")) || m.name === "app" || m.name === "root");
1473
+ if (rootModules.length === 0)
1474
+ return diagnostics;
1475
+ const reachable = new Set;
1476
+ const moduleMap = new Map(graph.modules.map((m) => [m.name, m]));
1477
+ const queue = rootModules.map((m) => m.name);
1478
+ for (const root of rootModules) {
1479
+ reachable.add(root.name);
1480
+ }
1481
+ while (queue.length > 0) {
1482
+ const current = queue.shift();
1483
+ const mod = moduleMap.get(current);
1484
+ if (!mod)
1485
+ continue;
1486
+ for (const imp of mod.imports) {
1487
+ if (!reachable.has(imp)) {
1488
+ reachable.add(imp);
1489
+ queue.push(imp);
1490
+ }
1491
+ }
1492
+ }
1493
+ for (const mod of graph.modules) {
1494
+ if (!reachable.has(mod.name)) {
1495
+ diagnostics.push({
1496
+ severity: "warn",
1497
+ code: "orphan-module",
1498
+ message: `Module '${mod.name}' is declared but not reachable from any root module (${rootModules.map((r) => r.name).join(", ")})`,
1499
+ file: mod.file,
1500
+ line: mod.line
1501
+ });
1502
+ }
1503
+ }
1504
+ return diagnostics;
1505
+ }
1199
1506
 
1200
1507
  // src/compile.ts
1508
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
1509
+ import { join as join3 } from "node:path";
1201
1510
  async function compileProject(options) {
1202
1511
  const graph = await analyzeProject(options.rootDir, options.include);
1203
1512
  const diagnostics = [
1204
1513
  ...graph.diagnostics ?? [],
1205
1514
  ...validateGraph(graph, {
1206
1515
  strict: options.strict,
1207
- moduleBoundaries: options.moduleBoundaries
1516
+ moduleBoundaryPreset: options.moduleBoundaryPreset,
1517
+ moduleBoundaries: options.moduleBoundaries,
1518
+ allowRouteCommandBindings: options.allowRouteCommandBindings,
1519
+ commandCapabilities: options.commandCapabilities,
1520
+ disallowControllerDirectDb: options.disallowControllerDirectDb,
1521
+ detectOrphanModules: options.detectOrphanModules
1208
1522
  })
1209
1523
  ];
1210
1524
  if (options.strict) {
@@ -1219,10 +1533,66 @@ async function compileProject(options) {
1219
1533
  });
1220
1534
  return { diagnostics, graph, written };
1221
1535
  }
1536
+ async function checkProject(options) {
1537
+ const graph = await analyzeProject(options.rootDir, options.include);
1538
+ const diagnostics = [
1539
+ ...graph.diagnostics ?? [],
1540
+ ...validateGraph(graph, {
1541
+ strict: options.strict,
1542
+ moduleBoundaryPreset: options.moduleBoundaryPreset,
1543
+ moduleBoundaries: options.moduleBoundaries,
1544
+ allowRouteCommandBindings: options.allowRouteCommandBindings,
1545
+ commandCapabilities: options.commandCapabilities,
1546
+ disallowControllerDirectDb: options.disallowControllerDirectDb,
1547
+ detectOrphanModules: options.detectOrphanModules
1548
+ })
1549
+ ];
1550
+ if (options.strict) {
1551
+ for (const diagnostic of diagnostics) {
1552
+ if (diagnostic.severity === "warn")
1553
+ diagnostic.severity = "error";
1554
+ }
1555
+ }
1556
+ const rendered = renderApplication(graph, {
1557
+ rootDir: options.rootDir,
1558
+ outDir: options.outDir
1559
+ });
1560
+ const expectedFiles = {
1561
+ "application.ts": rendered.applicationCode,
1562
+ "app.manifest.json": rendered.manifestJson
1563
+ };
1564
+ const mismatches = [];
1565
+ for (const [filename, expectedContent] of Object.entries(expectedFiles)) {
1566
+ const diskPath = join3(options.outDir, filename);
1567
+ if (!existsSync2(diskPath)) {
1568
+ mismatches.push(`${filename}: generated artifact is missing from disk`);
1569
+ continue;
1570
+ }
1571
+ const diskContent = readFileSync(diskPath, "utf8");
1572
+ if (diskContent !== expectedContent) {
1573
+ mismatches.push(`${filename}: disk artifact differs from current compiler output`);
1574
+ }
1575
+ }
1576
+ return {
1577
+ upToDate: mismatches.length === 0,
1578
+ mismatches,
1579
+ diagnostics,
1580
+ graph
1581
+ };
1582
+ }
1222
1583
  export {
1584
+ ANGULAR_ENTERPRISE_RULES,
1585
+ CLEAN_ARCHITECTURE_RULES,
1586
+ MODULAR_MONOLITH_RULES,
1587
+ MODULE_BOUNDARY_PROFILES,
1223
1588
  analyzeProject,
1224
1589
  camelName,
1590
+ checkProject,
1225
1591
  compileProject,
1226
1592
  generateApplication,
1593
+ getModuleBoundaryPreset,
1594
+ getModuleBoundaryProfile,
1595
+ renderApplication,
1596
+ resolveModuleBoundaries,
1227
1597
  validateGraph
1228
1598
  };
@@ -0,0 +1,36 @@
1
+ import type { ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule } from "./types";
2
+ /**
3
+ * Modular monolith / vertical slice architecture rules:
4
+ * - type:feature slices cannot depend on one another or on root/app modules;
5
+ * - type:root / type:app entry modules may aggregate feature, core, shared, and domain modules;
6
+ * - type:core foundational modules cannot depend upward on feature or root/app modules;
7
+ * - type:shared common utilities/components cannot depend on feature or root/app modules.
8
+ */
9
+ export declare const MODULAR_MONOLITH_RULES: ModuleBoundaryRule[];
10
+ /**
11
+ * Angular / Nx enterprise monorepo layering rules:
12
+ * follows the recommended Nx / Angular enterprise workspace conventions:
13
+ * - feature slices cannot directly depend on one another;
14
+ * - ui / data-access / util / shared libraries cannot depend upward on feature or root modules;
15
+ * - root / app modules serve only as composition entry points.
16
+ */
17
+ export declare const ANGULAR_ENTERPRISE_RULES: ModuleBoundaryRule[];
18
+ /**
19
+ * Clean Architecture / DDD layering rules (similar to Spring Boot DDD conventions):
20
+ * - presentation layers (api/controller/presentation) may depend only on application, domain, and shared layers;
21
+ * - application layers (application/service) orchestrate use cases and depend only on domain and shared layers;
22
+ * - the domain layer remains pure and cannot depend on presentation, application, infrastructure, or root modules;
23
+ * - infrastructure layers (infrastructure/infra) implement domain ports and may depend only on domain and shared layers.
24
+ */
25
+ export declare const CLEAN_ARCHITECTURE_RULES: ModuleBoundaryRule[];
26
+ /** Registry of built-in module boundary profiles. */
27
+ export declare const MODULE_BOUNDARY_PROFILES: Record<ModuleBoundaryPresetName, ModuleBoundaryProfile>;
28
+ /** Return the architecture governance rules for a preset name. */
29
+ export declare function getModuleBoundaryProfile(name: ModuleBoundaryPresetName): ModuleBoundaryProfile;
30
+ /** Return a copy of the rules included in a preset. */
31
+ export declare function getModuleBoundaryPreset(name: ModuleBoundaryPresetName): ModuleBoundaryRule[];
32
+ /** Resolve and merge preset rules with optional user-defined rules. */
33
+ export declare function resolveModuleBoundaries(options?: {
34
+ preset?: ModuleBoundaryPresetName;
35
+ rules?: ModuleBoundaryRule[];
36
+ }): ModuleBoundaryRule[] | undefined;