@sungen/driver-api 3.1.2-beta.117 → 3.1.2-beta.119
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/package.json +2 -2
- package/src/api-context.ts +52 -0
- package/src/index.ts +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sungen/driver-api",
|
|
3
|
-
"version": "3.1.2-beta.
|
|
3
|
+
"version": "3.1.2-beta.119",
|
|
4
4
|
"description": "Sungen API capability — the @api annotation, API catalog, OpenAPI import + `sungen api import`, and the specs/api.ts runtime template. Plugs into @sun-asterisk/sungen via the capability SPI.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"author": "eqe team (engineer & quality) — Sun Asterisk",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@sun-asterisk/sungen": "3.1.2-beta.
|
|
16
|
+
"@sun-asterisk/sungen": "3.1.2-beta.119",
|
|
17
17
|
"commander": "^14.0.2",
|
|
18
18
|
"yaml": "^2.8.2"
|
|
19
19
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API discovery + context-mapping (AO-3) — the `api` capability's Discover → Contextualize hooks.
|
|
3
|
+
*
|
|
4
|
+
* Discovery reads the reviewed catalog (apis.yaml) + notes the spec source; context-mapping turns
|
|
5
|
+
* the endpoints into generation units by method-profile: every endpoint → a `matrix` unit (contract
|
|
6
|
+
* + error), each mutating endpoint → also an `async` unit (idempotency), and an api flow → a `flow`
|
|
7
|
+
* unit (the ordered journey). The orchestration loop (`sungen context` → `/sungen:design`) consumes
|
|
8
|
+
* these to know WHAT to author before writing scenarios. Type-only on core.
|
|
9
|
+
*/
|
|
10
|
+
import type { Context, DiscoveryProvider, ContextMapper, GenerationUnit } from '@sun-asterisk/sungen';
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { lintApiCatalog } from './api-catalog';
|
|
14
|
+
|
|
15
|
+
interface EndpointFact { name: string; method: string; path: string; datasource?: string; expectStatus?: number | string }
|
|
16
|
+
|
|
17
|
+
const MUTATING = /^(POST|PUT|PATCH|DELETE)$/;
|
|
18
|
+
|
|
19
|
+
export const apiDiscovery: DiscoveryProvider = {
|
|
20
|
+
appliesTo: (t) => t.kind === 'api',
|
|
21
|
+
discover: async (target, scope) => {
|
|
22
|
+
const cwd = (scope as { cwd?: string } | undefined)?.cwd ?? process.cwd();
|
|
23
|
+
const unitId = target.id; // `api/<area>` | `api/flows/<flow>`
|
|
24
|
+
let endpoints: EndpointFact[] = [];
|
|
25
|
+
try {
|
|
26
|
+
endpoints = lintApiCatalog(unitId, null, cwd).entries.map((e) => ({
|
|
27
|
+
name: e.name, method: e.method, path: e.path, datasource: e.datasource, expectStatus: e.expect?.status,
|
|
28
|
+
}));
|
|
29
|
+
} catch { /* no catalog → the verification gate reports it */ }
|
|
30
|
+
|
|
31
|
+
const sources: Record<string, unknown> = {};
|
|
32
|
+
const specPath = path.join(cwd, 'qa', unitId, 'requirements', 'spec.md');
|
|
33
|
+
if (fs.existsSync(specPath)) sources.spec = path.relative(cwd, specPath);
|
|
34
|
+
|
|
35
|
+
return { target: { ...target, capability: 'api' }, sources, facts: { endpoints } };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const apiContextMapper: ContextMapper = {
|
|
40
|
+
decompose: (ctx: Context): GenerationUnit[] => {
|
|
41
|
+
const endpoints = ((ctx.facts ?? {}) as { endpoints?: EndpointFact[] }).endpoints ?? [];
|
|
42
|
+
const units: GenerationUnit[] = [];
|
|
43
|
+
const isFlow = typeof ctx.target.id === 'string' && ctx.target.id.includes('/flows/');
|
|
44
|
+
if (isFlow) units.push({ mode: 'flow', targetSlice: ctx.target }); // the ordered journey is one unit
|
|
45
|
+
for (const e of endpoints) {
|
|
46
|
+
units.push({ mode: 'matrix', targetSlice: e }); // contract + error matrix (70%)
|
|
47
|
+
if (MUTATING.test(e.method)) units.push({ mode: 'async', targetSlice: e }); // idempotency/concurrency (10%)
|
|
48
|
+
}
|
|
49
|
+
if (!units.length) units.push({ mode: 'matrix', targetSlice: ctx.target });
|
|
50
|
+
return units;
|
|
51
|
+
},
|
|
52
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type { CapabilityRegistry, Sensor, GateInput } from '@sun-asterisk/sungen
|
|
|
20
20
|
import { resolveApi, apiParamNames, lintApiCatalog } from './api-catalog';
|
|
21
21
|
import { registerApiCommand } from './cli-import';
|
|
22
22
|
import { apiViewpoints, apiGateProvider } from './api-harness';
|
|
23
|
+
import { apiDiscovery, apiContextMapper } from './api-context';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Parse `name(a={{x}},b="lit",c=3)` annotation overrides → JS expressions. Inlined from core
|
|
@@ -187,6 +188,8 @@ export function register(registry: CapabilityRegistry): void {
|
|
|
187
188
|
sensors: [apiVerificationSensor, apiViewpointSensor],
|
|
188
189
|
viewpoints: apiViewpoints as () => unknown, // AO-2: API viewpoint catalog
|
|
189
190
|
gateProvider: apiGateProvider as (i: unknown) => unknown, // AO-2: API coverage + businessDepth
|
|
191
|
+
discovery: apiDiscovery, // AO-3: catalog/spec → Context slice
|
|
192
|
+
contextMapper: apiContextMapper, // AO-3: endpoints → matrix/async/flow generation units
|
|
190
193
|
cliCommands: [registerApiCommand as (program: unknown) => void], // `sungen api import <openapi>`
|
|
191
194
|
});
|
|
192
195
|
}
|