@cmflow/atlas 3.4.0-beta.2 → 3.4.0-beta.20
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/README.md +231 -5
- package/dist/bin/atlas.d.mts +2 -0
- package/dist/bin/atlas.mjs +29100 -3106
- package/dist/bin/atlas.mjs.map +1 -0
- package/dist/defineExpressionRule-GhkeHHT8.mjs +10 -0
- package/dist/defineExpressionRule-GhkeHHT8.mjs.map +1 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.mjs +1297 -0
- package/dist/index.mjs.map +1 -0
- package/dist/propertyExtractionService-8BjqpPFa.mjs +172 -0
- package/dist/propertyExtractionService-8BjqpPFa.mjs.map +1 -0
- package/dist/rolldown-runtime-CGR6nZuH.mjs +34 -0
- package/dist/routeBackendTopologyService-CkOLUfcj.mjs +8728 -0
- package/dist/routeBackendTopologyService-CkOLUfcj.mjs.map +1 -0
- package/dist/rules/lodashGetRule.d.mts +7 -0
- package/dist/rules/lodashGetRule.mjs +24 -0
- package/dist/rules/lodashGetRule.mjs.map +1 -0
- package/dist/rules/mappingUtilityRule.d.mts +7 -0
- package/dist/rules/mappingUtilityRule.mjs +38 -0
- package/dist/rules/mappingUtilityRule.mjs.map +1 -0
- package/dist/rules/memberGetFieldRule.d.mts +7 -0
- package/dist/rules/memberGetFieldRule.mjs +27 -0
- package/dist/rules/memberGetFieldRule.mjs.map +1 -0
- package/dist/taskProgressService-CAC_RIoa.mjs +1229 -0
- package/dist/taskProgressService-CAC_RIoa.mjs.map +1 -0
- package/dist/token-CiiblKFL.mjs +62 -0
- package/dist/token-CiiblKFL.mjs.map +1 -0
- package/dist/token-util-Br4-y5kE.mjs +7 -0
- package/dist/token-util-Dnzm6rU4.mjs +471 -0
- package/dist/token-util-Dnzm6rU4.mjs.map +1 -0
- package/dist/types-Af0_VOnh.d.mts +122 -0
- package/dist/workers/routeBackendTopologyWorker.d.mts +2 -0
- package/dist/workers/routeBackendTopologyWorker.mjs +34 -0
- package/dist/workers/routeBackendTopologyWorker.mjs.map +1 -0
- package/knowledges/cms-and-directus-indirect-routes.md +5 -3
- package/package.json +18 -13
- package/dist/defineRule-Dfvzj6n2.mjs +0 -2
- package/dist/defineRule-Dfvzj6n2.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -50,13 +50,238 @@ The configuration imports `defineConfig` from Atlas:
|
|
|
50
50
|
import { defineConfig } from "@cmflow/atlas";
|
|
51
51
|
|
|
52
52
|
export default defineConfig({
|
|
53
|
-
|
|
53
|
+
envs: {
|
|
54
|
+
XM_API_URL: "https://xm.example/openapi.json"
|
|
55
|
+
},
|
|
54
56
|
openapiUrl: "https://api.example.com/openapi.json",
|
|
55
57
|
openapiTimeoutMs: 60_000,
|
|
56
|
-
directusUrl: "https://cms.api.clubmed"
|
|
58
|
+
directusUrl: "https://cms.api.clubmed",
|
|
59
|
+
analysis: {
|
|
60
|
+
backends: ["ICC", "CMS", "CMS_B2C"]
|
|
61
|
+
}
|
|
57
62
|
});
|
|
58
63
|
```
|
|
59
64
|
|
|
65
|
+
Atlas reads `compilerOptions.paths` from the `tsconfig.json` in the directory where the command is run (`process.cwd()`) and uses them as module aliases. `repoRoot` only defines the source tree to analyze and may therefore point to a subdirectory. Add `resolver.alias` only to override or complement those aliases.
|
|
66
|
+
|
|
67
|
+
## Backend sources
|
|
68
|
+
|
|
69
|
+
Atlas extracts a candidate mapping from code, then optionally consolidates it against a strict backend field reference. Configure these references in the same `analysis.backends` list used to declare backends.
|
|
70
|
+
|
|
71
|
+
A backend can be either a string or a `BackendSource` created with `defineBackendSource`:
|
|
72
|
+
|
|
73
|
+
- a string (for example `"ICC"`) has no field reference; Atlas keeps the current code-analysis and optional inference flow;
|
|
74
|
+
- a `BackendSource` provides a `resolve` function that returns the backend's known properties. Atlas assigns its `name` as `backend` on every resolved property.
|
|
75
|
+
|
|
76
|
+
When a string and a source share the same name, the last declaration wins. This lets a source enrich a list of backend names, for example `[..., Object.values(BackendTypes), quableBackendSource]`.
|
|
77
|
+
|
|
78
|
+
The resolver returns one of the following shapes. Document-oriented backends have no route; REST backends have no document.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
type BackendProperty =
|
|
82
|
+
| {
|
|
83
|
+
document: string;
|
|
84
|
+
field: string;
|
|
85
|
+
description?: string;
|
|
86
|
+
}
|
|
87
|
+
| {
|
|
88
|
+
route: string;
|
|
89
|
+
method: string;
|
|
90
|
+
field: string;
|
|
91
|
+
description?: string;
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The generated mapping preserves this shape. In particular, `document` is a separate property: Atlas does not turn a Quable field into an artificial path such as `products.product_geographical_area`.
|
|
96
|
+
|
|
97
|
+
### Quable
|
|
98
|
+
|
|
99
|
+
Attach rules that are specific to Quable directly to its source. They inherit the source backend automatically and their candidates are validated by the Quable property list.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { defineBackendSource, httpClient } from "@cmflow/atlas";
|
|
103
|
+
import { quableI18nFieldRule } from "./atlas-rules";
|
|
104
|
+
|
|
105
|
+
export const quable = defineBackendSource({
|
|
106
|
+
name: "QUABLE",
|
|
107
|
+
rules: [quableI18nFieldRule],
|
|
108
|
+
resolve: async () => {
|
|
109
|
+
const documentTypes = await httpClient.get<QuableDocumentType[]>("https://quable.example/document-types");
|
|
110
|
+
|
|
111
|
+
return documentTypes.flatMap((document) =>
|
|
112
|
+
document.properties.map((property) => ({
|
|
113
|
+
document: document.code,
|
|
114
|
+
field: property.code,
|
|
115
|
+
description: "récupéré via le backend resolver"
|
|
116
|
+
}))
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For example, the resolver above may return:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
{
|
|
126
|
+
backend: "QUABLE",
|
|
127
|
+
document: "products",
|
|
128
|
+
field: "product_geographical_area",
|
|
129
|
+
description: "récupéré via le backend resolver"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### CMS Directus
|
|
134
|
+
|
|
135
|
+
CMS Directus follows the same document-oriented contract. Its `cmsI18nFieldRule` is owned by the CMS source rather than registered as a global expression rule.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { defineBackendSource } from "@cmflow/atlas";
|
|
139
|
+
import { cmsI18nFieldRule } from "./atlas-rules";
|
|
140
|
+
|
|
141
|
+
export const cmsDirectus = defineBackendSource({
|
|
142
|
+
name: "CMS",
|
|
143
|
+
rules: [cmsI18nFieldRule],
|
|
144
|
+
resolve: async () => directusResolver.listProperties()
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`directusResolver.listProperties()` returns items such as `{ document: "offers", field: "title", description: "…" }`.
|
|
149
|
+
|
|
150
|
+
### CMS Legacy
|
|
151
|
+
|
|
152
|
+
CMS Legacy is configured identically, with its own resolver and backend identifier. It may reuse `cmsI18nFieldRule` when the backend uses `CmsI18n` helpers.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { defineBackendSource } from "@cmflow/atlas";
|
|
156
|
+
import { cmsI18nFieldRule } from "./atlas-rules";
|
|
157
|
+
|
|
158
|
+
export const cmsLegacy = defineBackendSource({
|
|
159
|
+
name: "CMS_LEGACY",
|
|
160
|
+
rules: [cmsI18nFieldRule],
|
|
161
|
+
resolve: async () => cmsLegacyResolver.listProperties()
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Custom REST backend with OpenAPI
|
|
166
|
+
|
|
167
|
+
`openapiSource` reuses Atlas's OpenAPI parsing utilities: downloading the document, resolving references, traversing operations, and extracting field descriptions. A project therefore only supplies the URL.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { constant, defineBackendSource, openapiSource } from "@cmflow/atlas";
|
|
171
|
+
|
|
172
|
+
export const xm = defineBackendSource({
|
|
173
|
+
name: "XM",
|
|
174
|
+
resolve: () =>
|
|
175
|
+
openapiSource({
|
|
176
|
+
url: constant<string>("XM_API_URL", "https://xm.example/openapi.json")
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`constant` resolves a value declared in `envs`, falling back to its second argument. No resolver context is required.
|
|
182
|
+
|
|
183
|
+
### Environment constants
|
|
184
|
+
|
|
185
|
+
Use `constant` when a backend source needs a configurable value such as a URL or an access token. Declare injected values at the root of `atlas.config.ts`; the value is resolved when the source runs:
|
|
186
|
+
|
|
187
|
+
1. Atlas uses `envs[name]` when it is set.
|
|
188
|
+
2. Otherwise, it returns the supplied default value.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { constant, defineBackendSource, openapiSource } from "@cmflow/atlas";
|
|
192
|
+
|
|
193
|
+
export const xmBackendSource = defineBackendSource({
|
|
194
|
+
name: "XM",
|
|
195
|
+
resolve: () =>
|
|
196
|
+
openapiSource({
|
|
197
|
+
url: constant<string>("XM_API_URL", "https://xm.example/openapi.json")
|
|
198
|
+
})
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
For example, configure the endpoint used by the source:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
export default defineConfig({
|
|
206
|
+
envs: {
|
|
207
|
+
XM_API_URL: "https://xm.internal/openapi.json"
|
|
208
|
+
},
|
|
209
|
+
// …other Atlas options
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`envs` can itself be populated from `process.env` when appropriate for the project.
|
|
214
|
+
|
|
215
|
+
This returns entries such as:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
{
|
|
219
|
+
backend: "XM",
|
|
220
|
+
route: "/path/to",
|
|
221
|
+
method: "GET",
|
|
222
|
+
field: "path.to.field",
|
|
223
|
+
description: "Description extraite du Swagger"
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Register strings and sources together:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import { defineConfig } from "@cmflow/atlas";
|
|
231
|
+
import { cmsDirectus, cmsLegacy, quable, xm } from "./backend-sources";
|
|
232
|
+
|
|
233
|
+
export default defineConfig({
|
|
234
|
+
// …other Atlas options
|
|
235
|
+
analysis: {
|
|
236
|
+
backends: ["ICC", quable, cmsDirectus, cmsLegacy, xm]
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Custom expression rules
|
|
242
|
+
|
|
243
|
+
Use `defineExpressionRule` when a project-specific helper hides a backend field or wraps an expression that Atlas should follow. Define those rules in the analyzed project, add a cross-backend rule to `analysis.rules` in `atlas.config.ts`, and attach backend-specific rules to `defineBackendSource({ rules: [...] })` instead.
|
|
244
|
+
|
|
245
|
+
`match` is a cheap predicate that selects the `ts-morph` expression. `parse` returns the information Atlas should use: a backend field, a transparent wrapper, or both.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { defineConfig, defineExpressionRule } from "@cmflow/atlas";
|
|
249
|
+
import { Node } from "ts-morph";
|
|
250
|
+
|
|
251
|
+
const localizedFieldRule = defineExpressionRule({
|
|
252
|
+
name: "localized-field",
|
|
253
|
+
match: (expression) => Node.isCallExpression(expression) && expression.getExpression().getText() === "localizedField",
|
|
254
|
+
parse: (expression) => {
|
|
255
|
+
if (!Node.isCallExpression(expression)) return undefined;
|
|
256
|
+
|
|
257
|
+
const [source, field] = expression.getArguments();
|
|
258
|
+
if (!source || !Node.isExpression(source) || !Node.isStringLiteral(field)) return undefined;
|
|
259
|
+
|
|
260
|
+
return { backendField: `${source.getText()}.${field.getLiteralValue()}` };
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
export default defineConfig({
|
|
265
|
+
// …other Atlas options
|
|
266
|
+
analysis: {
|
|
267
|
+
// …other analysis options
|
|
268
|
+
rules: [localizedFieldRule]
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
For a wrapper that does not change the field path, return `transparent: true`:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
const unwrapRule = defineExpressionRule({
|
|
277
|
+
name: "unwrap-api-value",
|
|
278
|
+
match: (expression) => Node.isCallExpression(expression) && expression.getExpression().getText() === "unwrap",
|
|
279
|
+
parse: () => ({ transparent: true })
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
`parse` may also set `mapperType` to annotate the generated mapping, or `apiMapping: true` when the helper maps an API value rather than a backend value.
|
|
284
|
+
|
|
60
285
|
Create a `.env.local` in the target API project when pushing to Directus:
|
|
61
286
|
|
|
62
287
|
```dotenv
|
|
@@ -70,7 +295,7 @@ Generate the topology first, then the route catalogue:
|
|
|
70
295
|
|
|
71
296
|
```bash
|
|
72
297
|
atlas --project-root /path/to/api generate:graph
|
|
73
|
-
atlas --project-root /path/to/api generate:
|
|
298
|
+
atlas --project-root /path/to/api generate:catalog --output .tmp/datasource-catalogue
|
|
74
299
|
```
|
|
75
300
|
|
|
76
301
|
Each route produces a YAML document and a `.graph.yaml` topology artifact. The catalogue requires a valid graph and leaves ambiguous fields marked `needs_review`.
|
|
@@ -102,8 +327,9 @@ Without `--write`, the command performs a dry run. Use `clean-orphans` to inspec
|
|
|
102
327
|
|
|
103
328
|
```text
|
|
104
329
|
atlas init Create atlas.config.ts
|
|
330
|
+
atlas backend-sources Execute backend sources and display resolved metadata
|
|
105
331
|
atlas generate:graph Trace API routes to backends
|
|
106
|
-
atlas generate:
|
|
332
|
+
atlas generate:catalog [route] Generate route review documents
|
|
107
333
|
atlas generate:test Check configured coverage baselines
|
|
108
334
|
atlas needs-review Rank unresolved routes
|
|
109
335
|
atlas infer [route|directory] Optionally enrich unresolved mappings
|
|
@@ -114,7 +340,7 @@ atlas report:changed Report coverage for changed routes
|
|
|
114
340
|
|
|
115
341
|
## CI
|
|
116
342
|
|
|
117
|
-
The recommended static CI flow is `generate:graph`, `generate:
|
|
343
|
+
The recommended static CI flow is `generate:graph`, `generate:catalog`, then `push`. Do not run optional inference in CI. Supply `DIRECTUS_URL` and `DIRECTUS_TOKEN` through the CI secret context; skip the push if either value is absent.
|
|
118
344
|
|
|
119
345
|
## Development
|
|
120
346
|
|