@clamator/codegen 0.1.0
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 +82 -0
- package/dist/case.d.ts +4 -0
- package/dist/case.d.ts.map +1 -0
- package/dist/case.js +18 -0
- package/dist/case.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +62 -0
- package/dist/cli.js.map +1 -0
- package/dist/emit-py.d.ts +12 -0
- package/dist/emit-py.d.ts.map +1 -0
- package/dist/emit-py.js +137 -0
- package/dist/emit-py.js.map +1 -0
- package/dist/emit-ts.d.ts +7 -0
- package/dist/emit-ts.d.ts.map +1 -0
- package/dist/emit-ts.js +60 -0
- package/dist/emit-ts.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/ir.d.ts +18 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +2 -0
- package/dist/ir.js.map +1 -0
- package/dist/load.d.ts +10 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +30 -0
- package/dist/load.js.map +1 -0
- package/dist/lower.d.ts +7 -0
- package/dist/lower.d.ts.map +1 -0
- package/dist/lower.js +27 -0
- package/dist/lower.js.map +1 -0
- package/dist/manifest.d.ts +10 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +19 -0
- package/dist/manifest.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# @clamator/codegen
|
|
2
|
+
|
|
3
|
+
CLI plus library that turns a Zod contract module into TypeScript and Python client/server wrappers for clamator.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @clamator/codegen
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## CLI usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @clamator/codegen \
|
|
15
|
+
--src <contracts-dir> \
|
|
16
|
+
--out-ts <ts-output-dir> \
|
|
17
|
+
--out-py <py-output-dir> \
|
|
18
|
+
--manifest <manifest.json> \
|
|
19
|
+
--ts-contract-import <import-path>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The interop test runner invokes the CLI like this:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const args = [
|
|
26
|
+
codegenCli,
|
|
27
|
+
'--src', contractsSrc,
|
|
28
|
+
'--out-ts', outTs,
|
|
29
|
+
'--out-py', outPy,
|
|
30
|
+
'--manifest', manifestPath,
|
|
31
|
+
'--ts-contract-import', '../../contracts/index.js',
|
|
32
|
+
];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
(Verbatim from `tests/interop/lib/runner.ts`. `codegenCli` is the path to `dist/cli.js` of this package.)
|
|
36
|
+
|
|
37
|
+
Pass `--out-py` only when you want Python output. The Python emitter requires the [`datamodel-code-generator`](https://pypi.org/project/datamodel-code-generator/) Python tool on `PATH`.
|
|
38
|
+
|
|
39
|
+
## Contract input shape
|
|
40
|
+
|
|
41
|
+
A contract module exports one or more contracts via `defineContract` from `@clamator/protocol`:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
import { defineContract, defineMethod } from '@clamator/protocol';
|
|
46
|
+
|
|
47
|
+
export const arithContract = defineContract('arith', {
|
|
48
|
+
add: defineMethod({
|
|
49
|
+
params: z.object({ a: z.number().int(), b: z.number().int() }),
|
|
50
|
+
result: z.object({ sum: z.number().int() }),
|
|
51
|
+
}),
|
|
52
|
+
divide: defineMethod({
|
|
53
|
+
params: z.object({ a: z.number().int(), b: z.number().int() }),
|
|
54
|
+
result: z.object({ q: z.number(), r: z.number().int() }),
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
(Verbatim from `ts/packages/codegen/tests/fixtures/contracts/arith.ts`.)
|
|
60
|
+
|
|
61
|
+
The codegen scans every `.ts` file in `--src` for `defineContract` calls and emits one wrapper file per contract.
|
|
62
|
+
|
|
63
|
+
## Output layout
|
|
64
|
+
|
|
65
|
+
Given a `--src` directory containing contract modules and an `--out-ts <dir>` and `--out-py <dir>`:
|
|
66
|
+
|
|
67
|
+
- `<out-ts>/<service>.ts` — typed client and server wrappers for each contract; importable from a TS package.
|
|
68
|
+
- `<out-py>/<service>.py` — typed client and server wrappers for each contract; importable from a Python package.
|
|
69
|
+
- `<manifest>.json` — content-addressed schema hashes per method/notification, used by interop tests to detect drift.
|
|
70
|
+
|
|
71
|
+
The `--ts-contract-import` flag controls the import path written into the emitted TS wrappers — supply the path that resolves to your contract module from the directory the wrappers will be imported from.
|
|
72
|
+
|
|
73
|
+
## Links
|
|
74
|
+
|
|
75
|
+
- Protocol packages: [`@clamator/protocol`](https://www.npmjs.com/package/@clamator/protocol), [`clamator-protocol`](https://pypi.org/project/clamator-protocol/)
|
|
76
|
+
- Transports:
|
|
77
|
+
- [`@clamator/over-memory`](https://www.npmjs.com/package/@clamator/over-memory)
|
|
78
|
+
- [`@clamator/over-redis`](https://www.npmjs.com/package/@clamator/over-redis)
|
|
79
|
+
- [`clamator-over-memory`](https://pypi.org/project/clamator-over-memory/)
|
|
80
|
+
- [`clamator-over-redis`](https://pypi.org/project/clamator-over-redis/)
|
|
81
|
+
- Design spec: [`docs/2026-05-07-clamator-design.md`](../../../docs/2026-05-07-clamator-design.md)
|
|
82
|
+
- Agent rules: [`AGENTS.md`](./AGENTS.md)
|
package/dist/case.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case.d.ts","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAS9C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGvD"}
|
package/dist/case.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function camelToSnake(s) {
|
|
2
|
+
// Insert underscore between lowercase/digit and uppercase: aB -> a_B
|
|
3
|
+
// Insert underscore between uppercase letters: ABC -> A_B_C
|
|
4
|
+
// Handle transition from multiple uppercase to uppercase followed by lowercase: ABc -> A_Bc
|
|
5
|
+
return s
|
|
6
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
7
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')
|
|
8
|
+
.replace(/([A-Z])([A-Z])/g, '$1_$2')
|
|
9
|
+
.toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
export function snakeToCamel(s) {
|
|
12
|
+
return s.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
13
|
+
}
|
|
14
|
+
export function kebabAndCamelToPascal(s) {
|
|
15
|
+
// Split on hyphens, then PascalCase each segment (preserving inner caps if camelCase).
|
|
16
|
+
return s.split('-').map(seg => seg.charAt(0).toUpperCase() + seg.slice(1)).join('');
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=case.js.map
|
package/dist/case.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case.js","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,qEAAqE;IACrE,4DAA4D;IAC5D,4FAA4F;IAC5F,OAAO,CAAC;SACL,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC;SACxC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;SACnC,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,CAAS;IAC7C,uFAAuF;IACvF,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtF,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface CliOptions {
|
|
3
|
+
src: string;
|
|
4
|
+
outTs?: string;
|
|
5
|
+
outPy?: string;
|
|
6
|
+
manifest?: string;
|
|
7
|
+
jsonSchemaTarget?: 'jsonSchema7' | 'openApi3';
|
|
8
|
+
tsContractImport?: string;
|
|
9
|
+
watch?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function runCli(opts: CliOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,UAAU,UAAU;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,aAAa,GAAG,UAAU,CAAC;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB5D"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { loadContracts } from './load.js';
|
|
4
|
+
import { lowerContracts } from './lower.js';
|
|
5
|
+
import { emitTs } from './emit-ts.js';
|
|
6
|
+
import { emitPy } from './emit-py.js';
|
|
7
|
+
import { writeManifest } from './manifest.js';
|
|
8
|
+
export async function runCli(opts) {
|
|
9
|
+
if (opts.watch) {
|
|
10
|
+
console.warn('--watch is not implemented in v0.1; performing a single run and exiting');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const loaded = await loadContracts(opts.src);
|
|
14
|
+
if (loaded.length === 0) {
|
|
15
|
+
console.warn(`[clamator-codegen] no contracts found in ${opts.src}`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const ir = lowerContracts(loaded, { jsonSchemaTarget: opts.jsonSchemaTarget ?? 'jsonSchema7' });
|
|
19
|
+
if (opts.outTs) {
|
|
20
|
+
if (!opts.tsContractImport)
|
|
21
|
+
throw new Error('--out-ts requires --ts-contract-import');
|
|
22
|
+
await emitTs(ir, { outDir: opts.outTs, contractImportPath: opts.tsContractImport });
|
|
23
|
+
}
|
|
24
|
+
if (opts.outPy) {
|
|
25
|
+
await emitPy(ir, { outDir: opts.outPy });
|
|
26
|
+
}
|
|
27
|
+
if (opts.manifest) {
|
|
28
|
+
await writeManifest(ir, opts.manifest);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const program = new Command();
|
|
32
|
+
program
|
|
33
|
+
.name('clamator-codegen')
|
|
34
|
+
.description('Generate TS + Py wrappers from Zod contracts')
|
|
35
|
+
.requiredOption('--src <dir>', 'directory containing *.ts files exporting defineContract calls')
|
|
36
|
+
.option('--out-ts <dir>', 'output dir for generated TS wrappers')
|
|
37
|
+
.option('--out-py <dir>', 'output dir for generated Py wrappers')
|
|
38
|
+
.option('--manifest <path>', 'optional cross-side manifest output')
|
|
39
|
+
.option('--json-schema-target <name>', 'jsonSchema7 | openApi3', 'jsonSchema7')
|
|
40
|
+
.option('--ts-contract-import <path>', 'how generated TS imports the source contract')
|
|
41
|
+
.option('--watch', 'rebuild on src changes')
|
|
42
|
+
.action(async (opts) => {
|
|
43
|
+
const cliOpts = { src: opts.src };
|
|
44
|
+
if (opts['outTs'])
|
|
45
|
+
cliOpts.outTs = opts['outTs'];
|
|
46
|
+
if (opts['outPy'])
|
|
47
|
+
cliOpts.outPy = opts['outPy'];
|
|
48
|
+
if (opts.manifest)
|
|
49
|
+
cliOpts.manifest = opts.manifest;
|
|
50
|
+
if (opts['jsonSchemaTarget'])
|
|
51
|
+
cliOpts.jsonSchemaTarget = opts['jsonSchemaTarget'];
|
|
52
|
+
if (opts['tsContractImport'])
|
|
53
|
+
cliOpts.tsContractImport = opts['tsContractImport'];
|
|
54
|
+
if (opts.watch)
|
|
55
|
+
cliOpts.watch = opts.watch;
|
|
56
|
+
await runCli(cliOpts);
|
|
57
|
+
});
|
|
58
|
+
const isMain = import.meta.url === `file://${process.argv[1]}`;
|
|
59
|
+
if (isMain) {
|
|
60
|
+
program.parseAsync().catch(err => { console.error(err); process.exit(1); });
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IrContract } from './ir.js';
|
|
2
|
+
export interface EmitPyOptions {
|
|
3
|
+
outDir: string;
|
|
4
|
+
/** Path to `datamodel-codegen` CLI; defaults to "datamodel-codegen". */
|
|
5
|
+
datamodelCodegenBin?: string;
|
|
6
|
+
}
|
|
7
|
+
/** datamodel-codegen invocation result captured for tests. */
|
|
8
|
+
export interface PyEmitResult {
|
|
9
|
+
filesWritten: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function emitPy(contracts: IrContract[], opts: EmitPyOptions): Promise<PyEmitResult>;
|
|
12
|
+
//# sourceMappingURL=emit-py.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-py.d.ts","sourceRoot":"","sources":["../src/emit-py.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,wBAAsB,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAqDhG"}
|
package/dist/emit-py.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { camelToSnake, kebabAndCamelToPascal } from './case.js';
|
|
5
|
+
const VERSION = '0.1.0';
|
|
6
|
+
export async function emitPy(contracts, opts) {
|
|
7
|
+
await fs.mkdir(opts.outDir, { recursive: true });
|
|
8
|
+
const filesWritten = [];
|
|
9
|
+
const bin = opts.datamodelCodegenBin ?? 'datamodel-codegen';
|
|
10
|
+
for (const c of contracts) {
|
|
11
|
+
// Combine all params/result schemas into one root JSON Schema with $defs, then run datamodel-codegen.
|
|
12
|
+
const defs = {};
|
|
13
|
+
const ordered = [];
|
|
14
|
+
for (const m of c.methods) {
|
|
15
|
+
const N = upperFirst(m.name);
|
|
16
|
+
defs[`${N}Params`] = m.params.jsonSchema;
|
|
17
|
+
ordered.push({ defName: `${N}Params`, modelName: `${N}Params` });
|
|
18
|
+
if (m.result) {
|
|
19
|
+
defs[`${N}Result`] = m.result.jsonSchema;
|
|
20
|
+
ordered.push({ defName: `${N}Result`, modelName: `${N}Result` });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const wrapper = {
|
|
24
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
25
|
+
type: 'object',
|
|
26
|
+
$defs: defs,
|
|
27
|
+
};
|
|
28
|
+
// Write a temp wrapper schema file.
|
|
29
|
+
const tmp = await fs.mkdtemp(path.join(opts.outDir, '.tmp-'));
|
|
30
|
+
const schemaPath = path.join(tmp, 'schema.json');
|
|
31
|
+
await fs.writeFile(schemaPath, JSON.stringify(wrapper, null, 2));
|
|
32
|
+
const modelsPath = path.join(tmp, 'models.py');
|
|
33
|
+
await runDatamodelCodegen(bin, schemaPath, modelsPath);
|
|
34
|
+
let modelsBody = await fs.readFile(modelsPath, 'utf-8');
|
|
35
|
+
// Strip datamodel-codegen header (comment block + from __future__ imports)
|
|
36
|
+
// to avoid duplicates with our own header.
|
|
37
|
+
modelsBody = modelsBody
|
|
38
|
+
.replace(/^(#[^\n]*\n)*/m, '') // leading comment lines
|
|
39
|
+
.replace(/^from __future__[^\n]*\n/gm, '') // __future__ imports (already in our header)
|
|
40
|
+
.trim();
|
|
41
|
+
await fs.rm(tmp, { recursive: true });
|
|
42
|
+
const tail = renderPyTail(c);
|
|
43
|
+
// Note: pydantic imports come from modelsBody (datamodel-codegen output);
|
|
44
|
+
// we only add imports that modelsBody won't provide.
|
|
45
|
+
const header = `# AUTO-GENERATED by @clamator/codegen v${VERSION} from ${path.basename(c.sourceFile)}.
|
|
46
|
+
# DO NOT EDIT. Re-run codegen to update.
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
from abc import ABC, abstractmethod
|
|
49
|
+
from clamator_protocol import ClamatorClient, Contract, MethodEntry
|
|
50
|
+
|
|
51
|
+
`;
|
|
52
|
+
const file = path.join(opts.outDir, `${c.service}.py`);
|
|
53
|
+
await fs.writeFile(file, header + modelsBody + '\n\n' + tail, 'utf-8');
|
|
54
|
+
filesWritten.push(file);
|
|
55
|
+
}
|
|
56
|
+
return { filesWritten };
|
|
57
|
+
}
|
|
58
|
+
function runDatamodelCodegen(bin, schemaPath, outPath) {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const args = [
|
|
61
|
+
'--input', schemaPath,
|
|
62
|
+
'--input-file-type', 'jsonschema',
|
|
63
|
+
'--output', outPath,
|
|
64
|
+
'--output-model-type', 'pydantic_v2.BaseModel',
|
|
65
|
+
'--target-python-version', '3.11',
|
|
66
|
+
'--field-constraints',
|
|
67
|
+
'--use-double-quotes',
|
|
68
|
+
'--snake-case-field',
|
|
69
|
+
'--enum-field-as-literal', 'all',
|
|
70
|
+
'--reuse-model',
|
|
71
|
+
'--skip-root-model',
|
|
72
|
+
];
|
|
73
|
+
const child = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
74
|
+
let stderr = '';
|
|
75
|
+
child.stderr.on('data', chunk => { stderr += chunk.toString(); });
|
|
76
|
+
child.on('error', reject);
|
|
77
|
+
child.on('exit', code => {
|
|
78
|
+
if (code === 0)
|
|
79
|
+
resolve();
|
|
80
|
+
else
|
|
81
|
+
reject(new Error(`datamodel-codegen exited ${code}: ${stderr}`));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function upperFirst(s) {
|
|
86
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
87
|
+
}
|
|
88
|
+
function renderPyTail(c) {
|
|
89
|
+
const Pascal = kebabAndCamelToPascal(c.service);
|
|
90
|
+
const clientLines = c.methods.map(m => {
|
|
91
|
+
const N = upperFirst(m.name);
|
|
92
|
+
const snake = camelToSnake(m.name);
|
|
93
|
+
if (m.isNotification) {
|
|
94
|
+
return ` async def ${snake}(self, params: ${N}Params) -> None:
|
|
95
|
+
await self._client.notify("${c.service}", "${m.name}", params.model_dump(by_alias=True))`;
|
|
96
|
+
}
|
|
97
|
+
return ` async def ${snake}(self, params: ${N}Params) -> ${N}Result:
|
|
98
|
+
raw = await self._client.call("${c.service}", "${m.name}", params.model_dump(by_alias=True))
|
|
99
|
+
return ${N}Result.model_validate(raw)`;
|
|
100
|
+
}).join('\n\n');
|
|
101
|
+
const abcLines = c.methods.map(m => {
|
|
102
|
+
const N = upperFirst(m.name);
|
|
103
|
+
const snake = camelToSnake(m.name);
|
|
104
|
+
if (m.isNotification) {
|
|
105
|
+
return ` @abstractmethod\n async def ${snake}(self, params: ${N}Params) -> None: ...`;
|
|
106
|
+
}
|
|
107
|
+
return ` @abstractmethod\n async def ${snake}(self, params: ${N}Params) -> ${N}Result: ...`;
|
|
108
|
+
}).join('\n\n');
|
|
109
|
+
const methodsEntries = c.methods.map(m => {
|
|
110
|
+
const N = upperFirst(m.name);
|
|
111
|
+
const snake = camelToSnake(m.name);
|
|
112
|
+
const result = m.isNotification ? 'None' : `${N}Result`;
|
|
113
|
+
return ` "${m.name}": MethodEntry(params_model=${N}Params, result_model=${result}, handler_attr="${snake}"),`;
|
|
114
|
+
}).join('\n');
|
|
115
|
+
const serviceVar = camelToSnake(c.service.replace(/-/g, '_')) + '_contract';
|
|
116
|
+
return `class ${Pascal}Client:
|
|
117
|
+
def __init__(self, client: ClamatorClient) -> None:
|
|
118
|
+
self._client = client
|
|
119
|
+
|
|
120
|
+
${clientLines}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class ${Pascal}Service(ABC):
|
|
124
|
+
${abcLines}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
METHODS = {
|
|
128
|
+
${methodsEntries}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
${serviceVar} = Contract(
|
|
132
|
+
service="${c.service}",
|
|
133
|
+
methods=METHODS,
|
|
134
|
+
)
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=emit-py.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-py.js","sourceRoot":"","sources":["../src/emit-py.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAEhE,MAAM,OAAO,GAAG,OAAO,CAAC;AAaxB,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,SAAuB,EAAE,IAAmB;IACvE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,IAAI,mBAAmB,CAAC;IAE5D,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,sGAAsG;QACtG,MAAM,IAAI,GAA4B,EAAE,CAAC;QACzC,MAAM,OAAO,GAA6C,EAAE,CAAC;QAC7D,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,yCAAyC;YAClD,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,IAAI;SACZ,CAAC;QACF,oCAAoC;QACpC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QACjD,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC/C,MAAM,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QACvD,IAAI,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACxD,2EAA2E;QAC3E,2CAA2C;QAC3C,UAAU,GAAG,UAAU;aACpB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAY,wBAAwB;aACjE,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC,6CAA6C;aACvF,IAAI,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,0EAA0E;QAC1E,qDAAqD;QACrD,MAAM,MAAM,GAAG,0CAA0C,OAAO,SAAS,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;CAMvG,CAAC;QACE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC;QACvD,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACvE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAW,EAAE,UAAkB,EAAE,OAAe;IAC3E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG;YACX,SAAS,EAAE,UAAU;YACrB,mBAAmB,EAAE,YAAY;YACjC,UAAU,EAAE,OAAO;YACnB,qBAAqB,EAAE,uBAAuB;YAC9C,yBAAyB,EAAE,MAAM;YACjC,qBAAqB;YACrB,qBAAqB;YACrB,oBAAoB;YACpB,yBAAyB,EAAE,KAAK;YAChC,eAAe;YACf,mBAAmB;SACpB,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACtE,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE;YACtB,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,YAAY,CAAC,CAAa;IACjC,MAAM,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAEhD,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACpC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO,iBAAiB,KAAK,kBAAkB,CAAC;qCACjB,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,IAAI,sCAAsC,CAAC;QAC9F,CAAC;QACD,OAAO,iBAAiB,KAAK,kBAAkB,CAAC,cAAc,CAAC;yCAC1B,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,IAAI;iBAC9C,CAAC,4BAA4B,CAAC;IAC7C,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACjC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO,sCAAsC,KAAK,kBAAkB,CAAC,sBAAsB,CAAC;QAC9F,CAAC;QACD,OAAO,sCAAsC,KAAK,kBAAkB,CAAC,cAAc,CAAC,aAAa,CAAC;IACpG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,cAAc,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACvC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QACxD,OAAO,QAAQ,CAAC,CAAC,IAAI,+BAA+B,CAAC,wBAAwB,MAAM,mBAAmB,KAAK,KAAK,CAAC;IACnH,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;IAE5E,OAAO,SAAS,MAAM;;;;EAItB,WAAW;;;QAGL,MAAM;EACZ,QAAQ;;;;EAIR,cAAc;;;EAGd,UAAU;eACG,CAAC,CAAC,OAAO;;;CAGvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IrContract } from './ir.js';
|
|
2
|
+
export interface EmitTsOptions {
|
|
3
|
+
outDir: string;
|
|
4
|
+
contractImportPath: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function emitTs(contracts: IrContract[], opts: EmitTsOptions): Promise<string[]>;
|
|
7
|
+
//# sourceMappingURL=emit-ts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-ts.d.ts","sourceRoot":"","sources":["../src/emit-ts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAsB,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAS5F"}
|
package/dist/emit-ts.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { kebabAndCamelToPascal } from './case.js';
|
|
4
|
+
const VERSION = '0.1.0';
|
|
5
|
+
export async function emitTs(contracts, opts) {
|
|
6
|
+
await fs.mkdir(opts.outDir, { recursive: true });
|
|
7
|
+
const written = [];
|
|
8
|
+
for (const c of contracts) {
|
|
9
|
+
const file = path.join(opts.outDir, `${c.service}.ts`);
|
|
10
|
+
await fs.writeFile(file, renderTsFile(c, opts), 'utf-8');
|
|
11
|
+
written.push(file);
|
|
12
|
+
}
|
|
13
|
+
return written;
|
|
14
|
+
}
|
|
15
|
+
function renderTsFile(c, opts) {
|
|
16
|
+
const Pascal = kebabAndCamelToPascal(c.service);
|
|
17
|
+
const sourceBase = path.basename(c.sourceFile);
|
|
18
|
+
const exportName = `${c.service.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase())}Contract`;
|
|
19
|
+
const typeAliases = c.methods.map(m => {
|
|
20
|
+
const N = upperFirst(m.name);
|
|
21
|
+
const params = `export type ${N}Params = z.infer<typeof ${exportName}.methods.${m.name}.params>;`;
|
|
22
|
+
if (m.isNotification)
|
|
23
|
+
return params;
|
|
24
|
+
return `${params}\nexport type ${N}Result = z.infer<typeof ${exportName}.methods.${m.name}.result>;`;
|
|
25
|
+
}).join('\n');
|
|
26
|
+
const clientMethods = c.methods.map(m => {
|
|
27
|
+
const N = upperFirst(m.name);
|
|
28
|
+
if (m.isNotification) {
|
|
29
|
+
return ` ${m.name}(params: ${N}Params): Promise<void> {\n return this.client.notify('${c.service}', '${m.name}', params);\n }`;
|
|
30
|
+
}
|
|
31
|
+
return ` ${m.name}(params: ${N}Params): Promise<${N}Result> {\n return this.client.call('${c.service}', '${m.name}', params);\n }`;
|
|
32
|
+
}).join('\n');
|
|
33
|
+
const serviceMethods = c.methods.map(m => {
|
|
34
|
+
const N = upperFirst(m.name);
|
|
35
|
+
if (m.isNotification)
|
|
36
|
+
return ` ${m.name}(params: ${N}Params): Promise<void>;`;
|
|
37
|
+
return ` ${m.name}(params: ${N}Params): Promise<${N}Result>;`;
|
|
38
|
+
}).join('\n');
|
|
39
|
+
return `// AUTO-GENERATED by @clamator/codegen v${VERSION} from ${sourceBase}.
|
|
40
|
+
// DO NOT EDIT. Re-run codegen to update.
|
|
41
|
+
import { ${exportName} } from '${opts.contractImportPath}';
|
|
42
|
+
import type { ClamatorClient } from '@clamator/protocol';
|
|
43
|
+
import type { z } from 'zod';
|
|
44
|
+
|
|
45
|
+
${typeAliases}
|
|
46
|
+
|
|
47
|
+
export class ${Pascal}Client {
|
|
48
|
+
constructor(private client: ClamatorClient) {}
|
|
49
|
+
${clientMethods}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ${Pascal}Service {
|
|
53
|
+
${serviceMethods}
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
function upperFirst(s) {
|
|
58
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=emit-ts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-ts.js","sourceRoot":"","sources":["../src/emit-ts.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadContracts, type LoadedContract } from './load.js';
|
|
2
|
+
export { lowerContracts, type LowerOptions } from './lower.js';
|
|
3
|
+
export type { IrContract, IrMethod, IrSchema } from './ir.js';
|
|
4
|
+
export { emitTs, type EmitTsOptions } from './emit-ts.js';
|
|
5
|
+
export { emitPy, type EmitPyOptions } from './emit-py.js';
|
|
6
|
+
export { writeManifest, type Manifest } from './manifest.js';
|
|
7
|
+
export { runCli } from './cli.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { loadContracts } from './load.js';
|
|
2
|
+
export { lowerContracts } from './lower.js';
|
|
3
|
+
export { emitTs } from './emit-ts.js';
|
|
4
|
+
export { emitPy } from './emit-py.js';
|
|
5
|
+
export { writeManifest } from './manifest.js';
|
|
6
|
+
export { runCli } from './cli.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuB,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAqB,MAAM,YAAY,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAsB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAsB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/ir.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface IrSchema {
|
|
2
|
+
/** JSON Schema draft 7 (or OpenAPI 3 if configured). */
|
|
3
|
+
jsonSchema: Record<string, unknown>;
|
|
4
|
+
/** Stable hash of the JSON-Schema string. */
|
|
5
|
+
hash: string;
|
|
6
|
+
}
|
|
7
|
+
export interface IrMethod {
|
|
8
|
+
name: string;
|
|
9
|
+
isNotification: boolean;
|
|
10
|
+
params: IrSchema;
|
|
11
|
+
result: IrSchema | null;
|
|
12
|
+
}
|
|
13
|
+
export interface IrContract {
|
|
14
|
+
service: string;
|
|
15
|
+
sourceFile: string;
|
|
16
|
+
methods: IrMethod[];
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=ir.d.ts.map
|
package/dist/ir.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB"}
|
package/dist/ir.js
ADDED
package/dist/ir.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.js","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":""}
|
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Contract } from '@clamator/protocol';
|
|
2
|
+
export interface LoadedContract {
|
|
3
|
+
contract: Contract<string, Record<string, never>> | {
|
|
4
|
+
service: string;
|
|
5
|
+
methods: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
sourceFile: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadContracts(srcDir: string): Promise<LoadedContract[]>;
|
|
10
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAC1G,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAmB7E"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { tsImport } from 'tsx/esm/api';
|
|
5
|
+
function isContract(v) {
|
|
6
|
+
return typeof v === 'object' && v !== null
|
|
7
|
+
&& typeof v.service === 'string'
|
|
8
|
+
&& typeof v.methods === 'object'
|
|
9
|
+
&& v.methods !== null;
|
|
10
|
+
}
|
|
11
|
+
export async function loadContracts(srcDir) {
|
|
12
|
+
const entries = readdirSync(srcDir, { withFileTypes: true })
|
|
13
|
+
.filter(e => e.isFile() && e.name.endsWith('.ts'));
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const e of entries) {
|
|
16
|
+
const full = path.join(srcDir, e.name);
|
|
17
|
+
const mod = await tsImport(pathToFileURL(full).href, import.meta.url);
|
|
18
|
+
for (const exportName of Object.keys(mod)) {
|
|
19
|
+
const v = mod[exportName];
|
|
20
|
+
if (isContract(v)) {
|
|
21
|
+
out.push({ contract: v, sourceFile: full });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Deterministic order: by service name, then by source file.
|
|
26
|
+
out.sort((a, b) => a.contract.service.localeCompare(b.contract.service)
|
|
27
|
+
|| a.sourceFile.localeCompare(b.sourceFile));
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQvC,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;WACrC,OAAQ,CAA2B,CAAC,OAAO,KAAK,QAAQ;WACxD,OAAQ,CAA2B,CAAC,OAAO,KAAK,QAAQ;WACvD,CAA0B,CAAC,OAAO,KAAK,IAAI,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACzD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtE,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAI,GAA+B,CAAC,UAAU,CAAC,CAAC;YACvD,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClB,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAA+B,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC;IACD,6DAA6D;IAC7D,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;WACjD,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/C,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/lower.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IrContract } from './ir.js';
|
|
2
|
+
import type { LoadedContract } from './load.js';
|
|
3
|
+
export interface LowerOptions {
|
|
4
|
+
jsonSchemaTarget: 'jsonSchema7' | 'openApi3';
|
|
5
|
+
}
|
|
6
|
+
export declare function lowerContracts(loaded: LoadedContract[], opts: LowerOptions): IrContract[];
|
|
7
|
+
//# sourceMappingURL=lower.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lower.d.ts","sourceRoot":"","sources":["../src/lower.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,aAAa,GAAG,UAAU,CAAC;CAC9C;AAUD,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,EAAE,CAgBzF"}
|
package/dist/lower.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
function lowerSchema(z, opts) {
|
|
4
|
+
const z2jOpts = { target: opts.jsonSchemaTarget, $refStrategy: 'none' };
|
|
5
|
+
const jsonSchema = zodToJsonSchema(z, z2jOpts);
|
|
6
|
+
const serialized = JSON.stringify(jsonSchema);
|
|
7
|
+
const hash = createHash('sha256').update(serialized).digest('hex');
|
|
8
|
+
return { jsonSchema, hash };
|
|
9
|
+
}
|
|
10
|
+
export function lowerContracts(loaded, opts) {
|
|
11
|
+
return loaded.map(({ contract, sourceFile }) => {
|
|
12
|
+
const methods = Object.entries(contract.methods)
|
|
13
|
+
.map(([name, def]) => {
|
|
14
|
+
const d = def;
|
|
15
|
+
const isNotification = d.notification === true;
|
|
16
|
+
return {
|
|
17
|
+
name,
|
|
18
|
+
isNotification,
|
|
19
|
+
params: lowerSchema(d.params, opts),
|
|
20
|
+
result: isNotification ? null : lowerSchema(d.result, opts),
|
|
21
|
+
};
|
|
22
|
+
})
|
|
23
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
24
|
+
return { service: contract.service, sourceFile, methods };
|
|
25
|
+
}).sort((a, b) => a.service.localeCompare(b.service));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=lower.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lower.js","sourceRoot":"","sources":["../src/lower.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAA0D,MAAM,oBAAoB,CAAC;AAS7G,SAAS,WAAW,CAAC,CAAa,EAAE,IAAkB;IACpD,MAAM,OAAO,GAAoC,EAAE,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IACzG,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,EAAE,OAAO,CAA4B,CAAC;IAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAwB,EAAE,IAAkB;IACzE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAe,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;aACzD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE;YACnB,MAAM,CAAC,GAAG,GAA0E,CAAC;YACrF,MAAM,cAAc,GAAG,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC;YAC/C,OAAO;gBACL,IAAI;gBACJ,cAAc;gBACd,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC;gBACnC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAO,EAAE,IAAI,CAAC;aAC7D,CAAC;QACJ,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IrContract } from './ir.js';
|
|
2
|
+
export interface Manifest {
|
|
3
|
+
generatedBy: string;
|
|
4
|
+
contracts: Record<string, Record<string, {
|
|
5
|
+
paramsHash: string;
|
|
6
|
+
resultHash: string | null;
|
|
7
|
+
}>>;
|
|
8
|
+
}
|
|
9
|
+
export declare function writeManifest(contracts: IrContract[], outPath: string): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC,CAAC;CAC9F;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB3F"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
export async function writeManifest(contracts, outPath) {
|
|
3
|
+
const manifest = {
|
|
4
|
+
generatedBy: '@clamator/codegen v0.1.0',
|
|
5
|
+
contracts: {},
|
|
6
|
+
};
|
|
7
|
+
for (const c of contracts) {
|
|
8
|
+
const entry = {};
|
|
9
|
+
manifest.contracts[c.service] = entry;
|
|
10
|
+
for (const m of c.methods) {
|
|
11
|
+
entry[m.name] = {
|
|
12
|
+
paramsHash: m.params.hash,
|
|
13
|
+
resultHash: m.result?.hash ?? null,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
await fs.writeFile(outPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQlC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAuB,EAAE,OAAe;IAC1E,MAAM,QAAQ,GAAa;QACzB,WAAW,EAAE,0BAA0B;QACvC,SAAS,EAAE,EAAE;KACd,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAsE,EAAE,CAAC;QACpF,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;gBACd,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI;gBACzB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI;aACnC,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACjF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clamator/codegen",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Codegen CLI: Zod contracts → TS + Py wrappers (pre-1.0).",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"bin": {
|
|
11
|
+
"clamator-codegen": "./dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"commander": "^12.1.0",
|
|
28
|
+
"tsx": "^4.19.0",
|
|
29
|
+
"zod": "^3.23.0",
|
|
30
|
+
"zod-to-json-schema": "^3.23.0",
|
|
31
|
+
"@clamator/protocol": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.6.0",
|
|
35
|
+
"vitest": "^2.1.0"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/cli.js",
|
|
39
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
40
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
}
|
|
43
|
+
}
|