@webpieces/nx-webpieces-rules 0.3.346 → 0.3.348

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 (40) hide show
  1. package/executors.json +0 -5
  2. package/package.json +6 -6
  3. package/src/executors/generate/executor.js +17 -9
  4. package/src/executors/generate/executor.js.map +1 -1
  5. package/src/executors/validate-runtime-architecture/executor.js +16 -7
  6. package/src/executors/validate-runtime-architecture/executor.js.map +1 -1
  7. package/src/lib/draw-on-graph-resolver.d.ts +33 -0
  8. package/src/lib/draw-on-graph-resolver.js +56 -0
  9. package/src/lib/draw-on-graph-resolver.js.map +1 -0
  10. package/src/lib/graph-loader.js +15 -1
  11. package/src/lib/graph-loader.js.map +1 -1
  12. package/src/lib/graph-metadata.js +10 -0
  13. package/src/lib/graph-metadata.js.map +1 -1
  14. package/src/lib/graph-responsibilities.js +4 -0
  15. package/src/lib/graph-responsibilities.js.map +1 -1
  16. package/src/lib/graph-sorter.d.ts +7 -0
  17. package/src/lib/graph-sorter.js.map +1 -1
  18. package/src/lib/graph-visualizer.d.ts +6 -0
  19. package/src/lib/graph-visualizer.js +23 -2
  20. package/src/lib/graph-visualizer.js.map +1 -1
  21. package/src/lib/runtime-config.d.ts +0 -3
  22. package/src/lib/runtime-config.js +0 -3
  23. package/src/lib/runtime-config.js.map +1 -1
  24. package/src/lib/runtime-graph.d.ts +22 -9
  25. package/src/lib/runtime-graph.js +0 -0
  26. package/src/lib/runtime-graph.js.map +1 -1
  27. package/src/lib/runtime-visualizer.js +7 -0
  28. package/src/lib/runtime-visualizer.js.map +1 -1
  29. package/src/plugin.js +1 -6
  30. package/src/plugin.js.map +1 -1
  31. package/src/runtime-targets.d.ts +0 -2
  32. package/src/runtime-targets.js +1 -14
  33. package/src/runtime-targets.js.map +1 -1
  34. package/src/executors/validate-runtime-markers/executor.d.ts +0 -25
  35. package/src/executors/validate-runtime-markers/executor.js +0 -91
  36. package/src/executors/validate-runtime-markers/executor.js.map +0 -1
  37. package/src/executors/validate-runtime-markers/schema.json +0 -8
  38. package/src/lib/runtime-markers.d.ts +0 -58
  39. package/src/lib/runtime-markers.js +0 -130
  40. package/src/lib/runtime-markers.js.map +0 -1
@@ -1,130 +0,0 @@
1
- "use strict";
2
- /**
3
- * Runtime Markers
4
- *
5
- * Reads the per-service `service-contract.json` files and builds a workspace
6
- * model used to assemble the runtime microservice graph and to validate each
7
- * service independently.
8
- *
9
- * `service-contract.json` (at a service's project root) declares, at api-PROJECT
10
- * granularity (by package name), which api projects a service IMPLEMENTS (serves)
11
- * and which it USES (calls as a client):
12
- *
13
- * { "implements": ["@scope/checkout-api"], "uses": ["@scope/payments-api"] }
14
- *
15
- * Classification (from webpieces.config.json globs):
16
- * - api project: root matches `apiProjectPaths` (e.g. "libraries/apis/*").
17
- * - service: root matches `servicePaths` (e.g. "services/*") AND is not an
18
- * api project (api classification wins, so the lists may overlap
19
- * harmlessly). Every service must have a service-contract.json.
20
- */
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.SERVICE_CONTRACT_FILENAME = void 0;
23
- exports.buildWorkspaceModel = buildWorkspaceModel;
24
- exports.readServiceContract = readServiceContract;
25
- exports.resolvePackageNames = resolvePackageNames;
26
- const tslib_1 = require("tslib");
27
- const fs = tslib_1.__importStar(require("fs"));
28
- const path = tslib_1.__importStar(require("path"));
29
- const devkit_1 = require("@nx/devkit");
30
- const rules_config_1 = require("@webpieces/rules-config");
31
- const toError_1 = require("../toError");
32
- exports.SERVICE_CONTRACT_FILENAME = 'service-contract.json';
33
- /** True when a project root matches one of the given globs (segment/glob/dir-prefix). */
34
- function matchesGlobs(root, globs) {
35
- if (globs.length === 0)
36
- return false;
37
- return (0, rules_config_1.isPathExcluded)(root, globs);
38
- }
39
- function readPackageName(workspaceRoot, projectRoot) {
40
- const pkgPath = path.join(workspaceRoot, projectRoot, 'package.json');
41
- if (!fs.existsSync(pkgPath))
42
- return null;
43
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
44
- try {
45
- const raw = fs.readFileSync(pkgPath, 'utf-8');
46
- const parsed = JSON.parse(raw);
47
- return typeof parsed.name === 'string' ? parsed.name : null;
48
- }
49
- catch (err) {
50
- const error = (0, toError_1.toError)(err);
51
- void error;
52
- return null;
53
- }
54
- }
55
- function collectDeps(name, dependencies, workspaceNames) {
56
- const deps = [];
57
- for (const edge of dependencies[name] ?? []) {
58
- if (edge.target !== name && workspaceNames.has(edge.target)) {
59
- deps.push(edge.target);
60
- }
61
- }
62
- return Array.from(new Set(deps)).sort();
63
- }
64
- /**
65
- * Build the workspace model from the Nx project graph. Dependency edges come
66
- * from Nx (imports + package.json), the same source dependencies.json uses, so
67
- * this works whether or not a service has its own package.json.
68
- */
69
- async function buildWorkspaceModel(workspaceRoot, apiProjectPaths, servicePaths) {
70
- const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
71
- const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
72
- const projects = new Map();
73
- const byPackageName = new Map();
74
- const workspaceNames = new Set(Object.keys(projectGraph.nodes));
75
- for (const [name, cfg] of Object.entries(projectsConfig.projects)) {
76
- const root = cfg.root;
77
- if (root === '' || root === '.')
78
- continue;
79
- const packageName = readPackageName(workspaceRoot, root);
80
- const isApi = matchesGlobs(root, apiProjectPaths);
81
- projects.set(name, {
82
- name,
83
- root,
84
- packageName,
85
- isApi,
86
- // api classification wins, so servicePaths and apiProjectPaths may overlap.
87
- isService: !isApi && matchesGlobs(root, servicePaths),
88
- deps: collectDeps(name, projectGraph.dependencies, workspaceNames),
89
- });
90
- if (packageName)
91
- byPackageName.set(packageName, name);
92
- }
93
- return { projects, byPackageName };
94
- }
95
- /** Read and normalize a project's `service-contract.json`, or null if it has none. */
96
- function readServiceContract(workspaceRoot, projectRoot) {
97
- const fullPath = path.join(workspaceRoot, projectRoot, exports.SERVICE_CONTRACT_FILENAME);
98
- if (!fs.existsSync(fullPath))
99
- return null;
100
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
101
- try {
102
- const raw = fs.readFileSync(fullPath, 'utf-8');
103
- const parsed = JSON.parse(raw);
104
- return {
105
- implements: Array.isArray(parsed.implements) ? parsed.implements : [],
106
- uses: Array.isArray(parsed.uses) ? parsed.uses : [],
107
- };
108
- }
109
- catch (err) {
110
- const error = (0, toError_1.toError)(err);
111
- throw new Error(`Failed to parse ${projectRoot}/${exports.SERVICE_CONTRACT_FILENAME}`, { cause: error });
112
- }
113
- }
114
- /**
115
- * Map a list of api package names (from a service contract) to workspace project
116
- * names. Unknown names (not a workspace package) are returned in `unknown`.
117
- */
118
- function resolvePackageNames(model, packageNames) {
119
- const resolved = [];
120
- const unknown = [];
121
- for (const pkg of packageNames) {
122
- const project = model.byPackageName.get(pkg);
123
- if (project)
124
- resolved.push(project);
125
- else
126
- unknown.push(pkg);
127
- }
128
- return { projects: resolved, unknown };
129
- }
130
- //# sourceMappingURL=runtime-markers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-markers.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-markers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Runtime Markers\n *\n * Reads the per-service `service-contract.json` files and builds a workspace\n * model used to assemble the runtime microservice graph and to validate each\n * service independently.\n *\n * `service-contract.json` (at a service's project root) declares, at api-PROJECT\n * granularity (by package name), which api projects a service IMPLEMENTS (serves)\n * and which it USES (calls as a client):\n *\n * { \"implements\": [\"@scope/checkout-api\"], \"uses\": [\"@scope/payments-api\"] }\n *\n * Classification (from webpieces.config.json globs):\n * - api project: root matches `apiProjectPaths` (e.g. \"libraries/apis/*\").\n * - service: root matches `servicePaths` (e.g. \"services/*\") AND is not an\n * api project (api classification wins, so the lists may overlap\n * harmlessly). Every service must have a service-contract.json.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';\nimport { isPathExcluded } from '@webpieces/rules-config';\nimport { toError } from '../toError';\n\nexport const SERVICE_CONTRACT_FILENAME = 'service-contract.json';\n\n/** Parsed `service-contract.json` contents (api package names). */\nexport interface ServiceContract {\n implements: string[];\n uses: string[];\n}\n\n/** Everything we know about one workspace project for runtime analysis. */\nexport interface ProjectInfo {\n name: string;\n root: string;\n packageName: string | null;\n isApi: boolean;\n isService: boolean;\n /** Workspace project names this project depends on (from the Nx graph). */\n deps: string[];\n}\n\n/** The whole-workspace model used by the generator and validators. */\nexport interface WorkspaceModel {\n projects: Map<string, ProjectInfo>;\n byPackageName: Map<string, string>;\n}\n\n/** Result of mapping package names to workspace projects. */\nexport interface ResolvedNames {\n projects: string[];\n unknown: string[];\n}\n\n/** Minimal shapes for the JSON files we parse. */\ninterface PackageJsonShape {\n name?: string;\n}\ninterface ServiceContractShape {\n implements?: string[];\n uses?: string[];\n}\n/** One Nx project-graph dependency edge (the slice we use). */\ninterface GraphEdge {\n target: string;\n}\n\n/** True when a project root matches one of the given globs (segment/glob/dir-prefix). */\nfunction matchesGlobs(root: string, globs: string[]): boolean {\n if (globs.length === 0) return false;\n return isPathExcluded(root, globs);\n}\n\nfunction readPackageName(workspaceRoot: string, projectRoot: string): string | null {\n const pkgPath = path.join(workspaceRoot, projectRoot, 'package.json');\n if (!fs.existsSync(pkgPath)) return null;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const raw = fs.readFileSync(pkgPath, 'utf-8');\n const parsed = JSON.parse(raw) as PackageJsonShape;\n return typeof parsed.name === 'string' ? parsed.name : null;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n}\n\nfunction collectDeps(\n name: string,\n dependencies: Record<string, GraphEdge[]>,\n workspaceNames: Set<string>,\n): string[] {\n const deps: string[] = [];\n for (const edge of dependencies[name] ?? []) {\n if (edge.target !== name && workspaceNames.has(edge.target)) {\n deps.push(edge.target);\n }\n }\n return Array.from(new Set(deps)).sort();\n}\n\n/**\n * Build the workspace model from the Nx project graph. Dependency edges come\n * from Nx (imports + package.json), the same source dependencies.json uses, so\n * this works whether or not a service has its own package.json.\n */\nexport async function buildWorkspaceModel(\n workspaceRoot: string,\n apiProjectPaths: string[],\n servicePaths: string[],\n): Promise<WorkspaceModel> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n\n const projects = new Map<string, ProjectInfo>();\n const byPackageName = new Map<string, string>();\n const workspaceNames = new Set(Object.keys(projectGraph.nodes));\n\n for (const [name, cfg] of Object.entries(projectsConfig.projects)) {\n const root = cfg.root;\n if (root === '' || root === '.') continue;\n\n const packageName = readPackageName(workspaceRoot, root);\n const isApi = matchesGlobs(root, apiProjectPaths);\n projects.set(name, {\n name,\n root,\n packageName,\n isApi,\n // api classification wins, so servicePaths and apiProjectPaths may overlap.\n isService: !isApi && matchesGlobs(root, servicePaths),\n deps: collectDeps(name, projectGraph.dependencies, workspaceNames),\n });\n if (packageName) byPackageName.set(packageName, name);\n }\n\n return { projects, byPackageName };\n}\n\n/** Read and normalize a project's `service-contract.json`, or null if it has none. */\nexport function readServiceContract(workspaceRoot: string, projectRoot: string): ServiceContract | null {\n const fullPath = path.join(workspaceRoot, projectRoot, SERVICE_CONTRACT_FILENAME);\n if (!fs.existsSync(fullPath)) return null;\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const raw = fs.readFileSync(fullPath, 'utf-8');\n const parsed = JSON.parse(raw) as ServiceContractShape;\n return {\n implements: Array.isArray(parsed.implements) ? parsed.implements : [],\n uses: Array.isArray(parsed.uses) ? parsed.uses : [],\n };\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`Failed to parse ${projectRoot}/${SERVICE_CONTRACT_FILENAME}`, { cause: error });\n }\n}\n\n/**\n * Map a list of api package names (from a service contract) to workspace project\n * names. Unknown names (not a workspace package) are returned in `unknown`.\n */\nexport function resolvePackageNames(\n model: WorkspaceModel,\n packageNames: string[],\n): ResolvedNames {\n const resolved: string[] = [];\n const unknown: string[] = [];\n for (const pkg of packageNames) {\n const project = model.byPackageName.get(pkg);\n if (project) resolved.push(project);\n else unknown.push(pkg);\n }\n return { projects: resolved, unknown };\n}\n"]}