@adhd/apigen-engine-naming 0.2.2 → 0.2.4
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/CHANGELOG.md +22 -0
- package/README.md +21 -1
- package/index.d.ts +2 -1
- package/index.js +2 -3
- package/index.mjs +530 -137
- package/lib/emit.d.ts +77 -0
- package/lib/naming.d.ts +26 -0
- package/package.json +19 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 0.2.4 (2026-09-26)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **vite-plugins:** absorb perf/test-resolve-fix — test-time @adhd/* source resolution ([3e344506](https://github.com/PseudoSky/adhd/commit/3e344506))
|
|
6
|
+
|
|
7
|
+
### 🩹 Fixes
|
|
8
|
+
|
|
9
|
+
- **apigen-engine-naming:** close review doc/lint residuals ([c7c9fd45](https://github.com/PseudoSky/adhd/commit/c7c9fd45))
|
|
10
|
+
- **apigen:** close codegen-injection review residuals (cd9a5d6c) ([9acbe746](https://github.com/PseudoSky/adhd/commit/9acbe746))
|
|
11
|
+
- **apigen:** harden fastify/express codegen against injection (ff1b22ad, 61ecfab8) ([de2a5948](https://github.com/PseudoSky/adhd/commit/de2a5948))
|
|
12
|
+
- **vite:** restore import.meta.url in CJS output under vite 8 ([7916e639](https://github.com/PseudoSky/adhd/commit/7916e639))
|
|
13
|
+
- **nx:** finish the ESLint v9 flat-config migration and unblock the gate ([53f4ff3e](https://github.com/PseudoSky/adhd/commit/53f4ff3e))
|
|
14
|
+
|
|
15
|
+
### ❤️ Thank You
|
|
16
|
+
|
|
17
|
+
- pseudosky
|
|
18
|
+
|
|
19
|
+
## 0.2.3 (2026-09-24)
|
|
20
|
+
|
|
21
|
+
This was a version bump only for apigen-engine-naming to align it with other projects, there were no code changes.
|
|
22
|
+
|
|
1
23
|
## 0.2.2 (2026-08-07)
|
|
2
24
|
|
|
3
25
|
|
package/README.md
CHANGED
|
@@ -9,10 +9,30 @@ Part of [apigen](../README.md).
|
|
|
9
9
|
## Public API
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
toKebab, toCamel, toPascal, toSnake, normalizeFileName,
|
|
14
|
+
project, httpVerb, checkCollisions, CollisionDetectedError,
|
|
15
|
+
envelopeKey, envelopeCliFlag, envelopeEnvVar, envelopeMetaKey,
|
|
16
|
+
sanitizeIdentifier, uniqueSanitizedIdentifiers,
|
|
17
|
+
escapeStringLiteral, escapeLineTerminators, toPosixPath, coercePort,
|
|
18
|
+
} from '@adhd/apigen-engine-naming';
|
|
13
19
|
```
|
|
14
20
|
|
|
15
21
|
- **case helpers** — `toKebab` / `toCamel` / `toPascal` / `toSnake`, `normalizeFileName`.
|
|
16
22
|
- **`project(...)`** — derive the namespace/id for a source.
|
|
23
|
+
- **`httpVerb(...)`** — resolve the effective HTTP verb for a composed schema.
|
|
17
24
|
- **`checkCollisions(...)`** — detect duplicate export ids (throws `CollisionDetectedError`).
|
|
18
25
|
- **envelope keys** — map an envelope field to its CLI flag / env var / MCP `_meta` key.
|
|
26
|
+
- **codegen emit primitives** (the single, context-correct surface every generator splices a
|
|
27
|
+
dynamic value through — see `src/lib/emit.ts`):
|
|
28
|
+
- `sanitizeIdentifier(id)` — a discovered id → a valid identifier.
|
|
29
|
+
- `uniqueSanitizedIdentifiers(ids)` — a collision-free **set** of identifiers (a lossy
|
|
30
|
+
sanitisation can map distinct ids to the same name; this disambiguates with a stable
|
|
31
|
+
`_2`, `_3`, … suffix so generated `import * as …_ns` declarations never collide).
|
|
32
|
+
- `escapeStringLiteral(value)` — a complete, quoted JS/TS string literal (escapes quotes,
|
|
33
|
+
backslashes, control chars, and `U+2028`/`U+2029`).
|
|
34
|
+
- `escapeLineTerminators(text)` — the `U+2028`/`U+2029` escape applied to an already-
|
|
35
|
+
serialized blob (e.g. a `JSON.stringify`'d schema map) before it is spliced.
|
|
36
|
+
- `toPosixPath(p)` — normalise a path to `/` separators.
|
|
37
|
+
- `coercePort(value)` — a caller-supplied `port` option → a validated integer literal
|
|
38
|
+
(rejects blank/non-numeric/out-of-range values instead of splicing them).
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { toKebab, toCamel, toPascal, toSnake, normalizeFileName, project, httpVerb, checkCollisions, CollisionDetectedError, envelopeKey, envelopeCliFlag, envelopeEnvVar, envelopeMetaKey, sanitizeIdentifier, } from './lib/naming';
|
|
1
|
+
export { toKebab, toCamel, toPascal, toSnake, normalizeFileName, project, httpVerb, checkCollisions, CollisionDetectedError, envelopeKey, envelopeCliFlag, envelopeEnvVar, envelopeMetaKey, sanitizeIdentifier, uniqueSanitizedIdentifiers, } from './lib/naming';
|
|
2
|
+
export { escapeLineTerminators, escapeStringLiteral, toPosixPath, coercePort, } from './lib/emit';
|
|
2
3
|
export type { TransportProjection, HttpVerb, ProjectionConfig, CollisionError, } from './lib/naming';
|
package/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
${n.join(`
|
|
3
|
-
`)}`),this.name="CollisionDetectedError",this.collisions=t}}function M(e,t={}){const n=new Map,r=new Map,a=new Map,p=new Map,c=[];for(const o of e){const i=b(o,t),g=`${i.http.verb} ${i.http.route}`,f=n.get(g);f!==void 0&&f!==o.id?c.push({transport:"http",target:g,ids:[f,o.id]}):n.set(g,o.id);const d=r.get(i.mcp.name);d!==void 0&&d!==o.id?c.push({transport:"mcp",target:i.mcp.name,ids:[d,o.id]}):r.set(i.mcp.name,o.id);const l=`${i.grpc.package}.${i.grpc.service}/${i.grpc.method}`,u=a.get(l);u!==void 0&&u!==o.id?c.push({transport:"grpc",target:l,ids:[u,o.id]}):a.set(l,o.id);const s=i.cli.path.join(" "),m=p.get(s);m!==void 0&&m!==o.id?c.push({transport:"cli",target:s,ids:[m,o.id]}):p.set(s,o.id)}if(c.length>0)throw new j(c)}function S(e,t){return`x-${e}-${t}`}function O(e,t){return`--${e}-${t}`}function z(e,t){const n=r=>r.toUpperCase().replace(/-/g,"_");return e==="adhd"?`APIGEN_${n(t)}`:`APIGEN_${n(e)}_${n(t)}`}const A=S;function T(e){let t=e.replace(/[^a-zA-Z0-9_$]/g,"_");return(t===""||/^[0-9]/.test(t))&&(t=`_${t}`),t}function E(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}exports.CollisionDetectedError=j;exports.checkCollisions=M;exports.envelopeCliFlag=O;exports.envelopeEnvVar=z;exports.envelopeKey=S;exports.envelopeMetaKey=A;exports.httpVerb=K;exports.normalizeFileName=w;exports.project=b;exports.sanitizeIdentifier=T;exports.toCamel=k;exports.toKebab=h;exports.toPascal=v;exports.toSnake=$;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("node:fs");let e=require("node:module");require("node:path"),(0,e.createRequire)(require("node:url").pathToFileURL(__filename).href);var t={id:`date-time`,kind:`scalar`,schema:{type:`string`,format:`date-time`},matches(e){return e.type===`string`&&e.format===`date-time`},ownsValue(e){return e instanceof Date},encode(e,t,n){return e.toISOString()},decode(e,t,n){if(typeof e!=`string`){if(n.mode===`strict`)throw TypeError(`[date-time] expected a string on the wire at "${n.path}", got ${typeof e}`);return new Date(String(e))}if(n.mode===`strict`&&Number.isNaN(new Date(e).getTime()))throw TypeError(`[date-time] invalid date-time string at "${n.path}": ${JSON.stringify(e)}`);return new Date(e)}},n={id:`int64`,kind:`scalar`,schema:{type:`string`,format:`int64`},matches(e){return e.type===`string`&&e.format===`int64`},ownsValue(e){return typeof e==`bigint`},encode(e,t,n){return String(e)},decode(e,t,n){if(typeof e!=`string`){if(n.mode===`strict`)throw TypeError(`[int64] expected a string on the wire at "${n.path}", got ${typeof e}`);try{return BigInt(Math.trunc(Number(e)))}catch{return BigInt(0)}}if(n.mode===`strict`)return BigInt(e);if(/^-?\d+$/.test(e))try{return BigInt(e)}catch{return BigInt(0)}return BigInt(0)}};function r(e){return e}var i={id:`decimal`,kind:`scalar`,schema:{type:`string`,format:`decimal`},matches(e){return e.type===`string`&&e.format===`decimal`},encode(e,t,n){return e},decode(e,t,n){if(typeof e!=`string`){if(n.mode===`strict`)throw TypeError(`[decimal] expected a string on the wire at "${n.path}", got ${typeof e}`);return r(String(e))}if(n.mode===`strict`&&!/^-?\d+(\.\d+)?$/.test(e))throw TypeError(`[decimal] wire value "${e}" at "${n.path}" is not a valid decimal string`);return r(e)}},a={id:`byte`,kind:`scalar`,schema:{type:`string`,format:`byte`},matches(e){return e.type===`string`&&e.format===`byte`},ownsValue(e){return e instanceof Uint8Array},encode(e,t,n){return Buffer.from(e).toString(`base64`)},decode(e,t,n){if(typeof e!=`string`){if(n.mode===`strict`)throw TypeError(`[byte] expected a base64 string on the wire at "${n.path}", got ${typeof e}`);return new Uint8Array}if(n.mode===`strict`&&!/^[A-Za-z0-9+/]*={0,2}$/.test(e))throw TypeError(`[byte] wire value at "${n.path}" is not standard base64 (format:byte): "${e}"`);return new Uint8Array(Buffer.from(e,`base64`))}},o=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,s={id:`uuid`,kind:`scalar`,schema:{type:`string`,format:`uuid`},matches(e){return e.type===`string`&&e.format===`uuid`},encode(e,t,n){return e.toLowerCase()},decode(e,t,n){if(typeof e!=`string`){if(n.mode===`strict`)throw TypeError(`[uuid] expected a string on the wire at "${n.path}", got ${typeof e}`);return String(e).toLowerCase()}if(n.mode===`strict`&&!o.test(e))throw TypeError(`[uuid] wire value "${e}" at "${n.path}" is not a lowercase-hyphenated RFC 4122 UUID`);return e}},c=`NaN`,l=`Infinity`,u=`-Infinity`,d=new Set([c,l,u]);t.id,n.id,i.id,a.id,s.id,{id:`number-special`,kind:`scalar`,schema:{type:`number`},matches(e){return e.type===`number`&&e.format===void 0},ownsValue(e){return typeof e==`number`&&!Number.isFinite(e)},encode(e,t,n){return Number.isNaN(e)?c:e===1/0?l:e===-1/0?u:e},decode(e,t,n){if(typeof e==`number`)return e;if(typeof e==`string`){if(e===c)return NaN;if(e===l)return 1/0;if(e===u)return-1/0;let t=Number(e);if(!Number.isNaN(t))return t}if(n.mode===`strict`)throw TypeError(`[number-special] unrecognized wire value at "${n.path}": ${JSON.stringify(e)}. Expected a number or one of ${[...d].join(`, `)}.`);return NaN}}.id,Object.freeze({typescript:{"date-time":{encode:`$.toISOString()`,decode:`new Date($)`,mode:`native`},int64:{encode:`String($)`,decode:`BigInt($)`,mode:`native`},decimal:{encode:`$.toString()`,decode:`new Decimal($)`,imports:[],dep:{name:`decimal.js`,version:`^10`},mode:`branded`},byte:{encode:`Buffer.from($).toString('base64')`,decode:`new Uint8Array(Buffer.from($, 'base64'))`,mode:`native`},uuid:{encode:`$.toLowerCase()`,decode:`$`,mode:`native`},"number-special":{encode:`numToWire($)`,decode:`wireToNum($)`,mode:`native`}},python:{"date-time":{encode:`$.isoformat()`,decode:`datetime.fromisoformat($)`,imports:[`from datetime import datetime`],mode:`native`},int64:{encode:`str($)`,decode:`int($)`,mode:`native`},decimal:{encode:`str($)`,decode:`Decimal($)`,imports:[`from decimal import Decimal`],mode:`native`},byte:{encode:`b64encode($).decode()`,decode:`b64decode($)`,imports:[`from base64 import b64encode, b64decode`],mode:`native`},uuid:{encode:`str($)`,decode:`UUID($)`,imports:[`from uuid import UUID`],mode:`native`},"number-special":{encode:`num_to_wire($)`,decode:`wire_to_num($)`,mode:`native`}},rust:{"date-time":{encode:`__SCAFFOLD_RUST_DATETIME_ENCODE__`,decode:`__SCAFFOLD_RUST_DATETIME_DECODE__`,imports:[`use chrono::{DateTime, Utc};`],dep:{name:`chrono`,version:`^0.4`},mode:`lib`},int64:{encode:`__SCAFFOLD_RUST_INT64_ENCODE__`,decode:`__SCAFFOLD_RUST_INT64_DECODE__`,imports:[`use serde_with::DisplayFromStr;`],dep:{name:`serde_with`,version:`^3`},mode:`lib`},decimal:{encode:`__SCAFFOLD_RUST_DECIMAL_ENCODE__`,decode:`__SCAFFOLD_RUST_DECIMAL_DECODE__`,imports:[`use rust_decimal::Decimal;`],dep:{name:`rust_decimal`,version:`^1`},mode:`lib`},byte:{encode:`__SCAFFOLD_RUST_BYTE_ENCODE__`,decode:`__SCAFFOLD_RUST_BYTE_DECODE__`,imports:[`use serde_with::base64::Base64;`],dep:{name:`serde_with`,version:`^3`},mode:`lib`},uuid:{encode:`__SCAFFOLD_RUST_UUID_ENCODE__`,decode:`__SCAFFOLD_RUST_UUID_DECODE__`,imports:[`use uuid::Uuid;`],dep:{name:`uuid`,version:`^1`},mode:`lib`},"number-special":{encode:`__SCAFFOLD_RUST_NUMSPECIAL_ENCODE__`,decode:`__SCAFFOLD_RUST_NUMSPECIAL_DECODE__`,mode:`native`}},go:{"date-time":{encode:`__SCAFFOLD_GO_DATETIME_ENCODE__`,decode:`__SCAFFOLD_GO_DATETIME_DECODE__`,imports:[`"time"`],mode:`native`},int64:{encode:`__SCAFFOLD_GO_INT64_ENCODE__`,decode:`__SCAFFOLD_GO_INT64_DECODE__`,imports:[`"strconv"`],mode:`native`},decimal:{encode:`__SCAFFOLD_GO_DECIMAL_ENCODE__`,decode:`__SCAFFOLD_GO_DECIMAL_DECODE__`,imports:[`"github.com/shopspring/decimal"`],dep:{name:`github.com/shopspring/decimal`,version:`v1`},mode:`lib`},byte:{encode:`__SCAFFOLD_GO_BYTE_ENCODE__`,decode:`__SCAFFOLD_GO_BYTE_DECODE__`,imports:[`"encoding/base64"`],mode:`native`},uuid:{encode:`__SCAFFOLD_GO_UUID_ENCODE__`,decode:`__SCAFFOLD_GO_UUID_DECODE__`,imports:[`"github.com/google/uuid"`],dep:{name:`github.com/google/uuid`,version:`v1`},mode:`lib`},"number-special":{encode:`__SCAFFOLD_GO_NUMSPECIAL_ENCODE__`,decode:`__SCAFFOLD_GO_NUMSPECIAL_DECODE__`,mode:`native`}},java:{"date-time":{encode:`$.toString()`,decode:`Instant.parse($)`,imports:[`import java.time.Instant;`],dep:{name:`jackson-datatype-jsr310`,version:`2.x`},mode:`lib`},int64:{encode:`@JsonFormat(shape = JsonFormat.Shape.STRING)`,decode:`@JsonFormat(shape = JsonFormat.Shape.STRING)`,imports:[`import com.fasterxml.jackson.annotation.JsonFormat;`],mode:`native`},decimal:{encode:`@JsonSerialize(using = ToStringSerializer.class)`,decode:`new BigDecimal($)`,imports:[`import java.math.BigDecimal;`,`import com.fasterxml.jackson.databind.annotation.JsonSerialize;`,`import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;`],mode:`native`},byte:{encode:`$`,decode:`$`,mode:`native`},uuid:{encode:`$.toString()`,decode:`UUID.fromString($)`,imports:[`import java.util.UUID;`],mode:`native`},"number-special":{encode:`@JsonSerialize(using = NumberSpecialSerializer.class)`,decode:`@JsonDeserialize(using = NumberSpecialDeserializer.class)`,imports:[`import com.fasterxml.jackson.databind.annotation.JsonSerialize;`,`import com.fasterxml.jackson.databind.annotation.JsonDeserialize;`],mode:`native`}}});var f=new Set([`string`,`number`,`boolean`,`integer`]);function p(e){if(typeof e!=`object`||!e)return!1;let t=e;if(t.$ref!==void 0||t.oneOf||t.anyOf||t.allOf)return!1;let{type:n}=t;return typeof n==`string`?f.has(n):Array.isArray(n)?n.every(e=>f.has(e)||e===`null`):Array.isArray(t.enum)&&t.enum.length>0?t.enum.every(e=>[`string`,`number`,`boolean`].includes(typeof e)):!1}function m(e){if(!e||typeof e!=`object`)return!1;let t=e.properties;return t===void 0||typeof t!=`object`||!t?!1:Object.values(t).every(p)}var h={"decimal.js":`Decimal`};function g(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}Object.entries(h).map(([e,t])=>({pattern:RegExp(`import\\(["'][^"']*${g(e)}[^"']*["']\\)\\.\\w+`,`g`),key:t}));function _(e){return e.words.join(`-`)}function v(e){return e.words.map((e,t)=>t===0?e:M(e)).join(``)}function y(e){return e.words.map(M).join(``)}function b(e){return e.words.join(`_`)}function x(e){return e.replace(/\.[^.]+$/,``).replace(/[._]+/g,`-`)}function S(e,t={}){let n=[e.namespace,...e.path],r=e.safe||m(e.input)?`GET`:`POST`,i=t.http?.verb?.[e.id]??r,a=`/`+n.map(e=>_(e)).join(`/`),o=n.map(e=>b(e)).join(`_`),s=n.map(e=>b(e)).slice(0,-1).join(`.`),c=y(n[n.length-2]??n[0]),l=y(n[n.length-1]),u=n.map(e=>_(e));return{http:{verb:i,route:a},mcp:{name:o},grpc:{package:s,service:c,method:l},cli:{path:u}}}function C(e,t,n){let r=n.http?.verb?.[e];return r===`GET`||r===`POST`?r:t[`x-apigen-safe`]?`GET`:`POST`}var w=class extends Error{constructor(e){let t=e.map(e=>` [${e.transport}] "${e.target}" ← ${e.ids[0]} vs ${e.ids[1]}`);super(`apigen-naming: ${e.length} projection collision(s) detected:\n${t.join(`
|
|
2
|
+
`)}`),this.name=`CollisionDetectedError`,this.collisions=e}};function T(e,t={}){let n=new Map,r=new Map,i=new Map,a=new Map,o=[];for(let s of e){let e=S(s,t),c=`${e.http.verb} ${e.http.route}`,l=n.get(c);l!==void 0&&l!==s.id?o.push({transport:`http`,target:c,ids:[l,s.id]}):n.set(c,s.id);let u=r.get(e.mcp.name);u!==void 0&&u!==s.id?o.push({transport:`mcp`,target:e.mcp.name,ids:[u,s.id]}):r.set(e.mcp.name,s.id);let d=`${e.grpc.package}.${e.grpc.service}/${e.grpc.method}`,f=i.get(d);f!==void 0&&f!==s.id?o.push({transport:`grpc`,target:d,ids:[f,s.id]}):i.set(d,s.id);let p=e.cli.path.join(` `),m=a.get(p);m!==void 0&&m!==s.id?o.push({transport:`cli`,target:p,ids:[m,s.id]}):a.set(p,s.id)}if(o.length>0)throw new w(o)}function E(e,t){return`x-${e}-${t}`}function D(e,t){return`--${e}-${t}`}function O(e,t){let n=e=>e.toUpperCase().replace(/-/g,`_`);return e===`adhd`?`APIGEN_${n(t)}`:`APIGEN_${n(e)}_${n(t)}`}var k=E;function A(e){let t=e.replace(/[^a-zA-Z0-9_$]/g,`_`);return(t===``||/^[0-9]/.test(t))&&(t=`_${t}`),t}function j(e){let t=new Set,n=[];for(let r of e){let e=A(r),i=e,a=2;for(;t.has(i);)i=`${e}_${a}`,a+=1;t.add(i),n.push(i)}return n}function M(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function N(e){return e.replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`)}function P(e){return N(JSON.stringify(e))}function F(e,t=3e3){if(e==null)return t;if(typeof e!=`string`&&typeof e!=`number`||typeof e==`string`&&e.trim()===``)throw TypeError(`apigen: invalid port option ${JSON.stringify(e)} — expected an integer in [0, 65535]`);let n=Number(e);if(!Number.isInteger(n)||n<0||n>65535)throw TypeError(`apigen: invalid port option ${JSON.stringify(e)} — expected an integer in [0, 65535]`);return n}function I(e){return e.replace(/\\/g,`/`)}exports.CollisionDetectedError=w,exports.checkCollisions=T,exports.coercePort=F,exports.envelopeCliFlag=D,exports.envelopeEnvVar=O,exports.envelopeKey=E,exports.envelopeMetaKey=k,exports.escapeLineTerminators=N,exports.escapeStringLiteral=P,exports.httpVerb=C,exports.normalizeFileName=x,exports.project=S,exports.sanitizeIdentifier=A,exports.toCamel=v,exports.toKebab=_,exports.toPascal=y,exports.toPosixPath=I,exports.toSnake=b,exports.uniqueSanitizedIdentifiers=j;
|
package/index.mjs
CHANGED
|
@@ -1,148 +1,541 @@
|
|
|
1
|
-
import "ts-morph";
|
|
2
1
|
import "node:fs";
|
|
2
|
+
import { createRequire as e } from "node:module";
|
|
3
3
|
import "node:path";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
4
|
+
e(import.meta.url);
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region ../apigen-base-logical/src/lib/codecs/date-time.ts
|
|
7
|
+
var t = {
|
|
8
|
+
id: "date-time",
|
|
9
|
+
kind: "scalar",
|
|
10
|
+
schema: {
|
|
11
|
+
type: "string",
|
|
12
|
+
format: "date-time"
|
|
13
|
+
},
|
|
14
|
+
matches(e) {
|
|
15
|
+
return e.type === "string" && e.format === "date-time";
|
|
16
|
+
},
|
|
17
|
+
ownsValue(e) {
|
|
18
|
+
return e instanceof Date;
|
|
19
|
+
},
|
|
20
|
+
encode(e, t, n) {
|
|
21
|
+
return e.toISOString();
|
|
22
|
+
},
|
|
23
|
+
decode(e, t, n) {
|
|
24
|
+
if (typeof e != "string") {
|
|
25
|
+
if (n.mode === "strict") throw TypeError(`[date-time] expected a string on the wire at "${n.path}", got ${typeof e}`);
|
|
26
|
+
return new Date(String(e));
|
|
27
|
+
}
|
|
28
|
+
if (n.mode === "strict" && Number.isNaN(new Date(e).getTime())) throw TypeError(`[date-time] invalid date-time string at "${n.path}": ${JSON.stringify(e)}`);
|
|
29
|
+
return new Date(e);
|
|
30
|
+
}
|
|
31
|
+
}, n = {
|
|
32
|
+
id: "int64",
|
|
33
|
+
kind: "scalar",
|
|
34
|
+
schema: {
|
|
35
|
+
type: "string",
|
|
36
|
+
format: "int64"
|
|
37
|
+
},
|
|
38
|
+
matches(e) {
|
|
39
|
+
return e.type === "string" && e.format === "int64";
|
|
40
|
+
},
|
|
41
|
+
ownsValue(e) {
|
|
42
|
+
return typeof e == "bigint";
|
|
43
|
+
},
|
|
44
|
+
encode(e, t, n) {
|
|
45
|
+
return String(e);
|
|
46
|
+
},
|
|
47
|
+
decode(e, t, n) {
|
|
48
|
+
if (typeof e != "string") {
|
|
49
|
+
if (n.mode === "strict") throw TypeError(`[int64] expected a string on the wire at "${n.path}", got ${typeof e}`);
|
|
50
|
+
try {
|
|
51
|
+
return BigInt(Math.trunc(Number(e)));
|
|
52
|
+
} catch {
|
|
53
|
+
return BigInt(0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (n.mode === "strict") return BigInt(e);
|
|
57
|
+
if (/^-?\d+$/.test(e)) try {
|
|
58
|
+
return BigInt(e);
|
|
59
|
+
} catch {
|
|
60
|
+
return BigInt(0);
|
|
61
|
+
}
|
|
62
|
+
return BigInt(0);
|
|
63
|
+
}
|
|
25
64
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
|
|
31
|
-
// The module specifier appears inside an absolute path, so we allow any
|
|
32
|
-
// characters between the quote and the specifier, and between the specifier
|
|
33
|
-
// and the closing quote. The trailing member accessor (`.default`, `.Decimal`,
|
|
34
|
-
// …) is matched generically (`\w+`) rather than anchored to one spelling —
|
|
35
|
-
// see the doc comment above for why.
|
|
36
|
-
pattern: new RegExp(
|
|
37
|
-
`import\\(["'][^"']*${x(e)}[^"']*["']\\)\\.\\w+`,
|
|
38
|
-
"g"
|
|
39
|
-
),
|
|
40
|
-
key: t
|
|
41
|
-
}));
|
|
42
|
-
function $(e) {
|
|
43
|
-
return e.words.join("-");
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region ../apigen-base-logical/src/lib/codecs/decimal.ts
|
|
67
|
+
function r(e) {
|
|
68
|
+
return e;
|
|
44
69
|
}
|
|
45
|
-
|
|
46
|
-
|
|
70
|
+
var i = {
|
|
71
|
+
id: "decimal",
|
|
72
|
+
kind: "scalar",
|
|
73
|
+
schema: {
|
|
74
|
+
type: "string",
|
|
75
|
+
format: "decimal"
|
|
76
|
+
},
|
|
77
|
+
matches(e) {
|
|
78
|
+
return e.type === "string" && e.format === "decimal";
|
|
79
|
+
},
|
|
80
|
+
encode(e, t, n) {
|
|
81
|
+
return e;
|
|
82
|
+
},
|
|
83
|
+
decode(e, t, n) {
|
|
84
|
+
if (typeof e != "string") {
|
|
85
|
+
if (n.mode === "strict") throw TypeError(`[decimal] expected a string on the wire at "${n.path}", got ${typeof e}`);
|
|
86
|
+
return r(String(e));
|
|
87
|
+
}
|
|
88
|
+
if (n.mode === "strict" && !/^-?\d+(\.\d+)?$/.test(e)) throw TypeError(`[decimal] wire value "${e}" at "${n.path}" is not a valid decimal string`);
|
|
89
|
+
return r(e);
|
|
90
|
+
}
|
|
91
|
+
}, a = {
|
|
92
|
+
id: "byte",
|
|
93
|
+
kind: "scalar",
|
|
94
|
+
schema: {
|
|
95
|
+
type: "string",
|
|
96
|
+
format: "byte"
|
|
97
|
+
},
|
|
98
|
+
matches(e) {
|
|
99
|
+
return e.type === "string" && e.format === "byte";
|
|
100
|
+
},
|
|
101
|
+
ownsValue(e) {
|
|
102
|
+
return e instanceof Uint8Array;
|
|
103
|
+
},
|
|
104
|
+
encode(e, t, n) {
|
|
105
|
+
return Buffer.from(e).toString("base64");
|
|
106
|
+
},
|
|
107
|
+
decode(e, t, n) {
|
|
108
|
+
if (typeof e != "string") {
|
|
109
|
+
if (n.mode === "strict") throw TypeError(`[byte] expected a base64 string on the wire at "${n.path}", got ${typeof e}`);
|
|
110
|
+
return /* @__PURE__ */ new Uint8Array();
|
|
111
|
+
}
|
|
112
|
+
if (n.mode === "strict" && !/^[A-Za-z0-9+/]*={0,2}$/.test(e)) throw TypeError(`[byte] wire value at "${n.path}" is not standard base64 (format:byte): "${e}"`);
|
|
113
|
+
return new Uint8Array(Buffer.from(e, "base64"));
|
|
114
|
+
}
|
|
115
|
+
}, o = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/, s = {
|
|
116
|
+
id: "uuid",
|
|
117
|
+
kind: "scalar",
|
|
118
|
+
schema: {
|
|
119
|
+
type: "string",
|
|
120
|
+
format: "uuid"
|
|
121
|
+
},
|
|
122
|
+
matches(e) {
|
|
123
|
+
return e.type === "string" && e.format === "uuid";
|
|
124
|
+
},
|
|
125
|
+
encode(e, t, n) {
|
|
126
|
+
return e.toLowerCase();
|
|
127
|
+
},
|
|
128
|
+
decode(e, t, n) {
|
|
129
|
+
if (typeof e != "string") {
|
|
130
|
+
if (n.mode === "strict") throw TypeError(`[uuid] expected a string on the wire at "${n.path}", got ${typeof e}`);
|
|
131
|
+
return String(e).toLowerCase();
|
|
132
|
+
}
|
|
133
|
+
if (n.mode === "strict" && !o.test(e)) throw TypeError(`[uuid] wire value "${e}" at "${n.path}" is not a lowercase-hyphenated RFC 4122 UUID`);
|
|
134
|
+
return e;
|
|
135
|
+
}
|
|
136
|
+
}, c = "NaN", l = "Infinity", u = "-Infinity", d = /* @__PURE__ */ new Set([
|
|
137
|
+
c,
|
|
138
|
+
l,
|
|
139
|
+
u
|
|
140
|
+
]);
|
|
141
|
+
t.id, n.id, i.id, a.id, s.id, {
|
|
142
|
+
id: "number-special",
|
|
143
|
+
kind: "scalar",
|
|
144
|
+
schema: { type: "number" },
|
|
145
|
+
matches(e) {
|
|
146
|
+
return e.type === "number" && e.format === void 0;
|
|
147
|
+
},
|
|
148
|
+
ownsValue(e) {
|
|
149
|
+
return typeof e == "number" && !Number.isFinite(e);
|
|
150
|
+
},
|
|
151
|
+
encode(e, t, n) {
|
|
152
|
+
return Number.isNaN(e) ? c : e === Infinity ? l : e === -Infinity ? u : e;
|
|
153
|
+
},
|
|
154
|
+
decode(e, t, n) {
|
|
155
|
+
if (typeof e == "number") return e;
|
|
156
|
+
if (typeof e == "string") {
|
|
157
|
+
if (e === c) return NaN;
|
|
158
|
+
if (e === l) return Infinity;
|
|
159
|
+
if (e === u) return -Infinity;
|
|
160
|
+
let t = Number(e);
|
|
161
|
+
if (!Number.isNaN(t)) return t;
|
|
162
|
+
}
|
|
163
|
+
if (n.mode === "strict") throw TypeError(`[number-special] unrecognized wire value at "${n.path}": ${JSON.stringify(e)}. Expected a number or one of ${[...d].join(", ")}.`);
|
|
164
|
+
return NaN;
|
|
165
|
+
}
|
|
166
|
+
}.id, Object.freeze({
|
|
167
|
+
typescript: {
|
|
168
|
+
"date-time": {
|
|
169
|
+
encode: "$.toISOString()",
|
|
170
|
+
decode: "new Date($)",
|
|
171
|
+
mode: "native"
|
|
172
|
+
},
|
|
173
|
+
int64: {
|
|
174
|
+
encode: "String($)",
|
|
175
|
+
decode: "BigInt($)",
|
|
176
|
+
mode: "native"
|
|
177
|
+
},
|
|
178
|
+
decimal: {
|
|
179
|
+
encode: "$.toString()",
|
|
180
|
+
decode: "new Decimal($)",
|
|
181
|
+
imports: [],
|
|
182
|
+
dep: {
|
|
183
|
+
name: "decimal.js",
|
|
184
|
+
version: "^10"
|
|
185
|
+
},
|
|
186
|
+
mode: "branded"
|
|
187
|
+
},
|
|
188
|
+
byte: {
|
|
189
|
+
encode: "Buffer.from($).toString('base64')",
|
|
190
|
+
decode: "new Uint8Array(Buffer.from($, 'base64'))",
|
|
191
|
+
mode: "native"
|
|
192
|
+
},
|
|
193
|
+
uuid: {
|
|
194
|
+
encode: "$.toLowerCase()",
|
|
195
|
+
decode: "$",
|
|
196
|
+
mode: "native"
|
|
197
|
+
},
|
|
198
|
+
"number-special": {
|
|
199
|
+
encode: "numToWire($)",
|
|
200
|
+
decode: "wireToNum($)",
|
|
201
|
+
mode: "native"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
python: {
|
|
205
|
+
"date-time": {
|
|
206
|
+
encode: "$.isoformat()",
|
|
207
|
+
decode: "datetime.fromisoformat($)",
|
|
208
|
+
imports: ["from datetime import datetime"],
|
|
209
|
+
mode: "native"
|
|
210
|
+
},
|
|
211
|
+
int64: {
|
|
212
|
+
encode: "str($)",
|
|
213
|
+
decode: "int($)",
|
|
214
|
+
mode: "native"
|
|
215
|
+
},
|
|
216
|
+
decimal: {
|
|
217
|
+
encode: "str($)",
|
|
218
|
+
decode: "Decimal($)",
|
|
219
|
+
imports: ["from decimal import Decimal"],
|
|
220
|
+
mode: "native"
|
|
221
|
+
},
|
|
222
|
+
byte: {
|
|
223
|
+
encode: "b64encode($).decode()",
|
|
224
|
+
decode: "b64decode($)",
|
|
225
|
+
imports: ["from base64 import b64encode, b64decode"],
|
|
226
|
+
mode: "native"
|
|
227
|
+
},
|
|
228
|
+
uuid: {
|
|
229
|
+
encode: "str($)",
|
|
230
|
+
decode: "UUID($)",
|
|
231
|
+
imports: ["from uuid import UUID"],
|
|
232
|
+
mode: "native"
|
|
233
|
+
},
|
|
234
|
+
"number-special": {
|
|
235
|
+
encode: "num_to_wire($)",
|
|
236
|
+
decode: "wire_to_num($)",
|
|
237
|
+
mode: "native"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
rust: {
|
|
241
|
+
"date-time": {
|
|
242
|
+
encode: "__SCAFFOLD_RUST_DATETIME_ENCODE__",
|
|
243
|
+
decode: "__SCAFFOLD_RUST_DATETIME_DECODE__",
|
|
244
|
+
imports: ["use chrono::{DateTime, Utc};"],
|
|
245
|
+
dep: {
|
|
246
|
+
name: "chrono",
|
|
247
|
+
version: "^0.4"
|
|
248
|
+
},
|
|
249
|
+
mode: "lib"
|
|
250
|
+
},
|
|
251
|
+
int64: {
|
|
252
|
+
encode: "__SCAFFOLD_RUST_INT64_ENCODE__",
|
|
253
|
+
decode: "__SCAFFOLD_RUST_INT64_DECODE__",
|
|
254
|
+
imports: ["use serde_with::DisplayFromStr;"],
|
|
255
|
+
dep: {
|
|
256
|
+
name: "serde_with",
|
|
257
|
+
version: "^3"
|
|
258
|
+
},
|
|
259
|
+
mode: "lib"
|
|
260
|
+
},
|
|
261
|
+
decimal: {
|
|
262
|
+
encode: "__SCAFFOLD_RUST_DECIMAL_ENCODE__",
|
|
263
|
+
decode: "__SCAFFOLD_RUST_DECIMAL_DECODE__",
|
|
264
|
+
imports: ["use rust_decimal::Decimal;"],
|
|
265
|
+
dep: {
|
|
266
|
+
name: "rust_decimal",
|
|
267
|
+
version: "^1"
|
|
268
|
+
},
|
|
269
|
+
mode: "lib"
|
|
270
|
+
},
|
|
271
|
+
byte: {
|
|
272
|
+
encode: "__SCAFFOLD_RUST_BYTE_ENCODE__",
|
|
273
|
+
decode: "__SCAFFOLD_RUST_BYTE_DECODE__",
|
|
274
|
+
imports: ["use serde_with::base64::Base64;"],
|
|
275
|
+
dep: {
|
|
276
|
+
name: "serde_with",
|
|
277
|
+
version: "^3"
|
|
278
|
+
},
|
|
279
|
+
mode: "lib"
|
|
280
|
+
},
|
|
281
|
+
uuid: {
|
|
282
|
+
encode: "__SCAFFOLD_RUST_UUID_ENCODE__",
|
|
283
|
+
decode: "__SCAFFOLD_RUST_UUID_DECODE__",
|
|
284
|
+
imports: ["use uuid::Uuid;"],
|
|
285
|
+
dep: {
|
|
286
|
+
name: "uuid",
|
|
287
|
+
version: "^1"
|
|
288
|
+
},
|
|
289
|
+
mode: "lib"
|
|
290
|
+
},
|
|
291
|
+
"number-special": {
|
|
292
|
+
encode: "__SCAFFOLD_RUST_NUMSPECIAL_ENCODE__",
|
|
293
|
+
decode: "__SCAFFOLD_RUST_NUMSPECIAL_DECODE__",
|
|
294
|
+
mode: "native"
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
go: {
|
|
298
|
+
"date-time": {
|
|
299
|
+
encode: "__SCAFFOLD_GO_DATETIME_ENCODE__",
|
|
300
|
+
decode: "__SCAFFOLD_GO_DATETIME_DECODE__",
|
|
301
|
+
imports: ["\"time\""],
|
|
302
|
+
mode: "native"
|
|
303
|
+
},
|
|
304
|
+
int64: {
|
|
305
|
+
encode: "__SCAFFOLD_GO_INT64_ENCODE__",
|
|
306
|
+
decode: "__SCAFFOLD_GO_INT64_DECODE__",
|
|
307
|
+
imports: ["\"strconv\""],
|
|
308
|
+
mode: "native"
|
|
309
|
+
},
|
|
310
|
+
decimal: {
|
|
311
|
+
encode: "__SCAFFOLD_GO_DECIMAL_ENCODE__",
|
|
312
|
+
decode: "__SCAFFOLD_GO_DECIMAL_DECODE__",
|
|
313
|
+
imports: ["\"github.com/shopspring/decimal\""],
|
|
314
|
+
dep: {
|
|
315
|
+
name: "github.com/shopspring/decimal",
|
|
316
|
+
version: "v1"
|
|
317
|
+
},
|
|
318
|
+
mode: "lib"
|
|
319
|
+
},
|
|
320
|
+
byte: {
|
|
321
|
+
encode: "__SCAFFOLD_GO_BYTE_ENCODE__",
|
|
322
|
+
decode: "__SCAFFOLD_GO_BYTE_DECODE__",
|
|
323
|
+
imports: ["\"encoding/base64\""],
|
|
324
|
+
mode: "native"
|
|
325
|
+
},
|
|
326
|
+
uuid: {
|
|
327
|
+
encode: "__SCAFFOLD_GO_UUID_ENCODE__",
|
|
328
|
+
decode: "__SCAFFOLD_GO_UUID_DECODE__",
|
|
329
|
+
imports: ["\"github.com/google/uuid\""],
|
|
330
|
+
dep: {
|
|
331
|
+
name: "github.com/google/uuid",
|
|
332
|
+
version: "v1"
|
|
333
|
+
},
|
|
334
|
+
mode: "lib"
|
|
335
|
+
},
|
|
336
|
+
"number-special": {
|
|
337
|
+
encode: "__SCAFFOLD_GO_NUMSPECIAL_ENCODE__",
|
|
338
|
+
decode: "__SCAFFOLD_GO_NUMSPECIAL_DECODE__",
|
|
339
|
+
mode: "native"
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
java: {
|
|
343
|
+
"date-time": {
|
|
344
|
+
encode: "$.toString()",
|
|
345
|
+
decode: "Instant.parse($)",
|
|
346
|
+
imports: ["import java.time.Instant;"],
|
|
347
|
+
dep: {
|
|
348
|
+
name: "jackson-datatype-jsr310",
|
|
349
|
+
version: "2.x"
|
|
350
|
+
},
|
|
351
|
+
mode: "lib"
|
|
352
|
+
},
|
|
353
|
+
int64: {
|
|
354
|
+
encode: "@JsonFormat(shape = JsonFormat.Shape.STRING)",
|
|
355
|
+
decode: "@JsonFormat(shape = JsonFormat.Shape.STRING)",
|
|
356
|
+
imports: ["import com.fasterxml.jackson.annotation.JsonFormat;"],
|
|
357
|
+
mode: "native"
|
|
358
|
+
},
|
|
359
|
+
decimal: {
|
|
360
|
+
encode: "@JsonSerialize(using = ToStringSerializer.class)",
|
|
361
|
+
decode: "new BigDecimal($)",
|
|
362
|
+
imports: [
|
|
363
|
+
"import java.math.BigDecimal;",
|
|
364
|
+
"import com.fasterxml.jackson.databind.annotation.JsonSerialize;",
|
|
365
|
+
"import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;"
|
|
366
|
+
],
|
|
367
|
+
mode: "native"
|
|
368
|
+
},
|
|
369
|
+
byte: {
|
|
370
|
+
encode: "$",
|
|
371
|
+
decode: "$",
|
|
372
|
+
mode: "native"
|
|
373
|
+
},
|
|
374
|
+
uuid: {
|
|
375
|
+
encode: "$.toString()",
|
|
376
|
+
decode: "UUID.fromString($)",
|
|
377
|
+
imports: ["import java.util.UUID;"],
|
|
378
|
+
mode: "native"
|
|
379
|
+
},
|
|
380
|
+
"number-special": {
|
|
381
|
+
encode: "@JsonSerialize(using = NumberSpecialSerializer.class)",
|
|
382
|
+
decode: "@JsonDeserialize(using = NumberSpecialDeserializer.class)",
|
|
383
|
+
imports: ["import com.fasterxml.jackson.databind.annotation.JsonSerialize;", "import com.fasterxml.jackson.databind.annotation.JsonDeserialize;"],
|
|
384
|
+
mode: "native"
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region ../apigen-core-client/src/lib/get-safety.ts
|
|
390
|
+
var f = /* @__PURE__ */ new Set([
|
|
391
|
+
"string",
|
|
392
|
+
"number",
|
|
393
|
+
"boolean",
|
|
394
|
+
"integer"
|
|
395
|
+
]);
|
|
396
|
+
function p(e) {
|
|
397
|
+
if (typeof e != "object" || !e) return !1;
|
|
398
|
+
let t = e;
|
|
399
|
+
if (t.$ref !== void 0 || t.oneOf || t.anyOf || t.allOf) return !1;
|
|
400
|
+
let { type: n } = t;
|
|
401
|
+
return typeof n == "string" ? f.has(n) : Array.isArray(n) ? n.every((e) => f.has(e) || e === "null") : Array.isArray(t.enum) && t.enum.length > 0 ? t.enum.every((e) => [
|
|
402
|
+
"string",
|
|
403
|
+
"number",
|
|
404
|
+
"boolean"
|
|
405
|
+
].includes(typeof e)) : !1;
|
|
406
|
+
}
|
|
407
|
+
function m(e) {
|
|
408
|
+
if (!e || typeof e != "object") return !1;
|
|
409
|
+
let t = e.properties;
|
|
410
|
+
return t === void 0 || typeof t != "object" || !t ? !1 : Object.values(t).every(p);
|
|
411
|
+
}
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region ../apigen-core-client/src/lib/schema-builders/ts-json-schema.ts
|
|
414
|
+
var h = { "decimal.js": "Decimal" };
|
|
415
|
+
function g(e) {
|
|
416
|
+
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
417
|
+
}
|
|
418
|
+
Object.entries(h).map(([e, t]) => ({
|
|
419
|
+
pattern: RegExp(`import\\(["'][^"']*${g(e)}[^"']*["']\\)\\.\\w+`, "g"),
|
|
420
|
+
key: t
|
|
421
|
+
}));
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/lib/naming.ts
|
|
424
|
+
function _(e) {
|
|
425
|
+
return e.words.join("-");
|
|
47
426
|
}
|
|
48
427
|
function v(e) {
|
|
49
|
-
|
|
428
|
+
return e.words.map((e, t) => t === 0 ? e : M(e)).join("");
|
|
50
429
|
}
|
|
51
430
|
function y(e) {
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
function G(e) {
|
|
55
|
-
return e.replace(/\.[^.]+$/, "").replace(/[._]+/g, "-");
|
|
56
|
-
}
|
|
57
|
-
function P(e, t = {}) {
|
|
58
|
-
var l, u;
|
|
59
|
-
const n = [e.namespace, ...e.path], r = e.safe || E(e.input) ? "GET" : "POST", p = ((u = (l = t.http) == null ? void 0 : l.verb) == null ? void 0 : u[e.id]) ?? r, a = "/" + n.map((s) => $(s)).join("/"), c = n.map((s) => y(s)).join("_"), i = n.map((s) => y(s)).slice(0, -1).join("."), g = v(n[n.length - 2] ?? n[0]), f = v(n[n.length - 1]), m = n.map((s) => $(s));
|
|
60
|
-
return {
|
|
61
|
-
http: { verb: p, route: a },
|
|
62
|
-
mcp: { name: c },
|
|
63
|
-
grpc: { package: i, service: g, method: f },
|
|
64
|
-
cli: { path: m }
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function K(e, t, n) {
|
|
68
|
-
var p, a;
|
|
69
|
-
const r = (a = (p = n.http) == null ? void 0 : p.verb) == null ? void 0 : a[e];
|
|
70
|
-
return r === "GET" || r === "POST" ? r : t["x-apigen-safe"] ? "GET" : "POST";
|
|
71
|
-
}
|
|
72
|
-
class _ extends Error {
|
|
73
|
-
constructor(t) {
|
|
74
|
-
const n = t.map(
|
|
75
|
-
(r) => ` [${r.transport}] "${r.target}" ← ${r.ids[0]} vs ${r.ids[1]}`
|
|
76
|
-
);
|
|
77
|
-
super(
|
|
78
|
-
`apigen-naming: ${t.length} projection collision(s) detected:
|
|
79
|
-
${n.join(`
|
|
80
|
-
`)}`
|
|
81
|
-
), this.name = "CollisionDetectedError", this.collisions = t;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function T(e, t = {}) {
|
|
85
|
-
const n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), c = [];
|
|
86
|
-
for (const o of e) {
|
|
87
|
-
const i = P(o, t), g = `${i.http.verb} ${i.http.route}`, f = n.get(g);
|
|
88
|
-
f !== void 0 && f !== o.id ? c.push({
|
|
89
|
-
transport: "http",
|
|
90
|
-
target: g,
|
|
91
|
-
ids: [f, o.id]
|
|
92
|
-
}) : n.set(g, o.id);
|
|
93
|
-
const m = r.get(i.mcp.name);
|
|
94
|
-
m !== void 0 && m !== o.id ? c.push({
|
|
95
|
-
transport: "mcp",
|
|
96
|
-
target: i.mcp.name,
|
|
97
|
-
ids: [m, o.id]
|
|
98
|
-
}) : r.set(i.mcp.name, o.id);
|
|
99
|
-
const l = `${i.grpc.package}.${i.grpc.service}/${i.grpc.method}`, u = p.get(l);
|
|
100
|
-
u !== void 0 && u !== o.id ? c.push({
|
|
101
|
-
transport: "grpc",
|
|
102
|
-
target: l,
|
|
103
|
-
ids: [u, o.id]
|
|
104
|
-
}) : p.set(l, o.id);
|
|
105
|
-
const s = i.cli.path.join(" "), d = a.get(s);
|
|
106
|
-
d !== void 0 && d !== o.id ? c.push({
|
|
107
|
-
transport: "cli",
|
|
108
|
-
target: s,
|
|
109
|
-
ids: [d, o.id]
|
|
110
|
-
}) : a.set(s, o.id);
|
|
111
|
-
}
|
|
112
|
-
if (c.length > 0)
|
|
113
|
-
throw new _(c);
|
|
114
|
-
}
|
|
115
|
-
function w(e, t) {
|
|
116
|
-
return `x-${e}-${t}`;
|
|
117
|
-
}
|
|
118
|
-
function z(e, t) {
|
|
119
|
-
return `--${e}-${t}`;
|
|
120
|
-
}
|
|
121
|
-
function N(e, t) {
|
|
122
|
-
const n = (r) => r.toUpperCase().replace(/-/g, "_");
|
|
123
|
-
return e === "adhd" ? `APIGEN_${n(t)}` : `APIGEN_${n(e)}_${n(t)}`;
|
|
124
|
-
}
|
|
125
|
-
const D = w;
|
|
126
|
-
function U(e) {
|
|
127
|
-
let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
128
|
-
return (t === "" || /^[0-9]/.test(t)) && (t = `_${t}`), t;
|
|
431
|
+
return e.words.map(M).join("");
|
|
129
432
|
}
|
|
130
433
|
function b(e) {
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
434
|
+
return e.words.join("_");
|
|
435
|
+
}
|
|
436
|
+
function x(e) {
|
|
437
|
+
return e.replace(/\.[^.]+$/, "").replace(/[._]+/g, "-");
|
|
438
|
+
}
|
|
439
|
+
function S(e, t = {}) {
|
|
440
|
+
let n = [e.namespace, ...e.path], r = e.safe || m(e.input) ? "GET" : "POST", i = t.http?.verb?.[e.id] ?? r, a = "/" + n.map((e) => _(e)).join("/"), o = n.map((e) => b(e)).join("_"), s = n.map((e) => b(e)).slice(0, -1).join("."), c = y(n[n.length - 2] ?? n[0]), l = y(n[n.length - 1]), u = n.map((e) => _(e));
|
|
441
|
+
return {
|
|
442
|
+
http: {
|
|
443
|
+
verb: i,
|
|
444
|
+
route: a
|
|
445
|
+
},
|
|
446
|
+
mcp: { name: o },
|
|
447
|
+
grpc: {
|
|
448
|
+
package: s,
|
|
449
|
+
service: c,
|
|
450
|
+
method: l
|
|
451
|
+
},
|
|
452
|
+
cli: { path: u }
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function C(e, t, n) {
|
|
456
|
+
let r = n.http?.verb?.[e];
|
|
457
|
+
return r === "GET" || r === "POST" ? r : t["x-apigen-safe"] ? "GET" : "POST";
|
|
458
|
+
}
|
|
459
|
+
var w = class extends Error {
|
|
460
|
+
constructor(e) {
|
|
461
|
+
let t = e.map((e) => ` [${e.transport}] "${e.target}" ← ${e.ids[0]} vs ${e.ids[1]}`);
|
|
462
|
+
super(`apigen-naming: ${e.length} projection collision(s) detected:\n${t.join("\n")}`), this.name = "CollisionDetectedError", this.collisions = e;
|
|
463
|
+
}
|
|
148
464
|
};
|
|
465
|
+
function T(e, t = {}) {
|
|
466
|
+
let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = [];
|
|
467
|
+
for (let s of e) {
|
|
468
|
+
let e = S(s, t), c = `${e.http.verb} ${e.http.route}`, l = n.get(c);
|
|
469
|
+
l !== void 0 && l !== s.id ? o.push({
|
|
470
|
+
transport: "http",
|
|
471
|
+
target: c,
|
|
472
|
+
ids: [l, s.id]
|
|
473
|
+
}) : n.set(c, s.id);
|
|
474
|
+
let u = r.get(e.mcp.name);
|
|
475
|
+
u !== void 0 && u !== s.id ? o.push({
|
|
476
|
+
transport: "mcp",
|
|
477
|
+
target: e.mcp.name,
|
|
478
|
+
ids: [u, s.id]
|
|
479
|
+
}) : r.set(e.mcp.name, s.id);
|
|
480
|
+
let d = `${e.grpc.package}.${e.grpc.service}/${e.grpc.method}`, f = i.get(d);
|
|
481
|
+
f !== void 0 && f !== s.id ? o.push({
|
|
482
|
+
transport: "grpc",
|
|
483
|
+
target: d,
|
|
484
|
+
ids: [f, s.id]
|
|
485
|
+
}) : i.set(d, s.id);
|
|
486
|
+
let p = e.cli.path.join(" "), m = a.get(p);
|
|
487
|
+
m !== void 0 && m !== s.id ? o.push({
|
|
488
|
+
transport: "cli",
|
|
489
|
+
target: p,
|
|
490
|
+
ids: [m, s.id]
|
|
491
|
+
}) : a.set(p, s.id);
|
|
492
|
+
}
|
|
493
|
+
if (o.length > 0) throw new w(o);
|
|
494
|
+
}
|
|
495
|
+
function E(e, t) {
|
|
496
|
+
return `x-${e}-${t}`;
|
|
497
|
+
}
|
|
498
|
+
function D(e, t) {
|
|
499
|
+
return `--${e}-${t}`;
|
|
500
|
+
}
|
|
501
|
+
function O(e, t) {
|
|
502
|
+
let n = (e) => e.toUpperCase().replace(/-/g, "_");
|
|
503
|
+
return e === "adhd" ? `APIGEN_${n(t)}` : `APIGEN_${n(e)}_${n(t)}`;
|
|
504
|
+
}
|
|
505
|
+
var k = E;
|
|
506
|
+
function A(e) {
|
|
507
|
+
let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
508
|
+
return (t === "" || /^[0-9]/.test(t)) && (t = `_${t}`), t;
|
|
509
|
+
}
|
|
510
|
+
function j(e) {
|
|
511
|
+
let t = /* @__PURE__ */ new Set(), n = [];
|
|
512
|
+
for (let r of e) {
|
|
513
|
+
let e = A(r), i = e, a = 2;
|
|
514
|
+
for (; t.has(i);) i = `${e}_${a}`, a += 1;
|
|
515
|
+
t.add(i), n.push(i);
|
|
516
|
+
}
|
|
517
|
+
return n;
|
|
518
|
+
}
|
|
519
|
+
function M(e) {
|
|
520
|
+
return e.length === 0 ? e : e[0].toUpperCase() + e.slice(1);
|
|
521
|
+
}
|
|
522
|
+
//#endregion
|
|
523
|
+
//#region src/lib/emit.ts
|
|
524
|
+
function N(e) {
|
|
525
|
+
return e.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
526
|
+
}
|
|
527
|
+
function P(e) {
|
|
528
|
+
return N(JSON.stringify(e));
|
|
529
|
+
}
|
|
530
|
+
function F(e, t = 3e3) {
|
|
531
|
+
if (e == null) return t;
|
|
532
|
+
if (typeof e != "string" && typeof e != "number" || typeof e == "string" && e.trim() === "") throw TypeError(`apigen: invalid port option ${JSON.stringify(e)} — expected an integer in [0, 65535]`);
|
|
533
|
+
let n = Number(e);
|
|
534
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) throw TypeError(`apigen: invalid port option ${JSON.stringify(e)} — expected an integer in [0, 65535]`);
|
|
535
|
+
return n;
|
|
536
|
+
}
|
|
537
|
+
function I(e) {
|
|
538
|
+
return e.replace(/\\/g, "/");
|
|
539
|
+
}
|
|
540
|
+
//#endregion
|
|
541
|
+
export { w as CollisionDetectedError, T as checkCollisions, F as coercePort, D as envelopeCliFlag, O as envelopeEnvVar, E as envelopeKey, k as envelopeMetaKey, N as escapeLineTerminators, P as escapeStringLiteral, C as httpVerb, x as normalizeFileName, S as project, A as sanitizeIdentifier, v as toCamel, _ as toKebab, y as toPascal, I as toPosixPath, b as toSnake, j as uniqueSanitizedIdentifiers };
|
package/lib/emit.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replaces raw `U+2028` LINE SEPARATOR / `U+2029` PARAGRAPH SEPARATOR
|
|
3
|
+
* characters with their `\u2028` / `\u2029` escape sequences.
|
|
4
|
+
*
|
|
5
|
+
* `JSON.stringify` emits these two code points **verbatim** (they are valid in
|
|
6
|
+
* JSON) even though ECMAScript treats them as line terminators. That is a
|
|
7
|
+
* parse error inside a string literal on pre-ES2019 targets — this repo
|
|
8
|
+
* targets `es2018` (`tsconfig.base.json`) — and a raw separator also breaks any
|
|
9
|
+
* single-line context (a comment, a log line) it lands in.
|
|
10
|
+
*
|
|
11
|
+
* `escapeStringLiteral` applies this to a single string literal.
|
|
12
|
+
* `escapeLineTerminators` is the same escape applied **directly to an
|
|
13
|
+
* already-serialized blob** — e.g. a `JSON.stringify`'d schema map whose
|
|
14
|
+
* nested `description` fields may carry these separators — so a multi-value
|
|
15
|
+
* JSON blob spliced into generated source cannot smuggle a raw line terminator
|
|
16
|
+
* past `JSON.stringify`. It is only safe on JSON/source text (it never touches
|
|
17
|
+
* any other character); it is not a substitute for `escapeStringLiteral` on a
|
|
18
|
+
* raw value, because it does not add quotes or escape backslashes.
|
|
19
|
+
*
|
|
20
|
+
* @example escapeLineTerminators('a\u2028b') // → 'a\\u2028b'
|
|
21
|
+
*/
|
|
22
|
+
export declare function escapeLineTerminators(text: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Renders a value as a **complete, double-quoted JavaScript/TypeScript string
|
|
25
|
+
* literal** (including the surrounding quotes), safe to splice into generated
|
|
26
|
+
* source in any string-literal position.
|
|
27
|
+
*
|
|
28
|
+
* Uses `JSON.stringify`, whose output is a valid ECMAScript string literal on
|
|
29
|
+
* ES2019+ targets (the JSON-superset proposal, V8 "JSON ⊂ ECMAScript") and
|
|
30
|
+
* correctly escapes the double-quote, the backslash, and all C0 control
|
|
31
|
+
* characters (newline, carriage return, tab, …). The two characters
|
|
32
|
+
* `JSON.stringify` emits **verbatim** even though they are line terminators —
|
|
33
|
+
* `U+2028` / `U+2029` — are then escaped via {@link escapeLineTerminators}
|
|
34
|
+
* (see that helper for why this repo needs it at `es2018`).
|
|
35
|
+
*
|
|
36
|
+
* @example escapeStringLiteral("it's") // → `"it's"`
|
|
37
|
+
* @example escapeStringLiteral('a\nb') // → `"a\\nb"` (no raw newline)
|
|
38
|
+
* @example escapeStringLiteral('\u2028') // → `"\\u2028"`
|
|
39
|
+
*/
|
|
40
|
+
export declare function escapeStringLiteral(value: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Coerces a caller-supplied `port` option to a validated integer, safe to
|
|
43
|
+
* splice into generated source as a numeric literal.
|
|
44
|
+
*
|
|
45
|
+
* Generate/run options reach a plugin as **untyped** option values — a CLI
|
|
46
|
+
* `--opt port=8080` arrives as the string `'8080'`, and nothing prevents a
|
|
47
|
+
* hostile or fat-fingered `--opt port=8080); process.exit(1); //`. Splicing
|
|
48
|
+
* that raw (`await app.listen({ port: ${port} })`) is a code-injection vector.
|
|
49
|
+
* Collapsing the value to an integer in the valid TCP range `[0, 65535]`
|
|
50
|
+
* (0 = request an ephemeral port) before splicing closes it: the emitted
|
|
51
|
+
* literal is always a bare number.
|
|
52
|
+
*
|
|
53
|
+
* `undefined`/`null` fall back to `fallback` (3000, matching the generators'
|
|
54
|
+
* historical default). Only a string or a number is ever coerced — a blank
|
|
55
|
+
* string, a non-numeric string, a non-string/non-number (`true`, `[]`, an
|
|
56
|
+
* object), a non-integer, or an out-of-range value throws rather than silently
|
|
57
|
+
* emitting something wrong. The type gate matters: `Number(true)` is `1` and
|
|
58
|
+
* `Number([])` is `0`, so without it those values would sneak through as if
|
|
59
|
+
* they were ports.
|
|
60
|
+
*
|
|
61
|
+
* @example coercePort('8080') // → 8080
|
|
62
|
+
* @example coercePort(undefined) // → 3000
|
|
63
|
+
* @throws {TypeError} on a blank/non-numeric string, a non-string/non-number,
|
|
64
|
+
* a non-integer, or an out-of-range value.
|
|
65
|
+
*/
|
|
66
|
+
export declare function coercePort(value: unknown, fallback?: number): number;
|
|
67
|
+
/**
|
|
68
|
+
* Normalises a filesystem path to POSIX separators (`/`).
|
|
69
|
+
*
|
|
70
|
+
* Generated specifiers and paths must be platform-stable: a Windows-joined
|
|
71
|
+
* `pkg\\src\\index.ts` spliced verbatim into an import would not match the
|
|
72
|
+
* value an OpenAPI/schema emitter produces on POSIX. Always emit `/`.
|
|
73
|
+
*
|
|
74
|
+
* @example toPosixPath('a\\b') // → 'a/b'
|
|
75
|
+
*/
|
|
76
|
+
export declare function toPosixPath(p: string): string;
|
|
77
|
+
export { sanitizeIdentifier, uniqueSanitizedIdentifiers } from './naming';
|
package/lib/naming.d.ts
CHANGED
|
@@ -237,3 +237,29 @@ export declare const envelopeMetaKey: typeof envelopeKey;
|
|
|
237
237
|
* @example sanitizeIdentifier('123abc') // → '_123abc'
|
|
238
238
|
*/
|
|
239
239
|
export declare function sanitizeIdentifier(id: string): string;
|
|
240
|
+
/**
|
|
241
|
+
* Assigns each raw id a **unique** codegen-safe identifier, disambiguating
|
|
242
|
+
* sanitisation collisions deterministically.
|
|
243
|
+
*
|
|
244
|
+
* {@link sanitizeIdentifier} is lossy: several distinct raw ids can collapse to
|
|
245
|
+
* the same identifier (`a-b`, `a_b`, `a.b` → `a_b`). A generator that emits one
|
|
246
|
+
* `import * as <id>_ns` / `const <id>_fns` pair **per package** would then emit
|
|
247
|
+
* duplicate declarations for a project holding two such packages — a hard
|
|
248
|
+
* `routes.ts` parse error (`Identifier 'a_b_ns' has already been declared`),
|
|
249
|
+
* or, worse, a silent last-writer-wins alias.
|
|
250
|
+
*
|
|
251
|
+
* This resolves the collision by appending a stable `_2`, `_3`, … suffix in
|
|
252
|
+
* input order: the FIRST id to claim a name keeps it (so a collision-free
|
|
253
|
+
* input is byte-identical to before), and each subsequent collision gets the
|
|
254
|
+
* next free suffix. The result is deterministic for a given input order, so
|
|
255
|
+
* generated output stays reproducible.
|
|
256
|
+
*
|
|
257
|
+
* @example uniqueSanitizedIdentifiers(['a-b', 'a_b', 'a.b'])
|
|
258
|
+
* // → ['a_b', 'a_b_2', 'a_b_3']
|
|
259
|
+
* @example uniqueSanitizedIdentifiers(['dispatch-cli'])
|
|
260
|
+
* // → ['dispatch_cli']
|
|
261
|
+
* @example uniqueSanitizedIdentifiers(['a-b', 'a_b', 'a_b_2'])
|
|
262
|
+
* // → ['a_b', 'a_b_2', 'a_b_2_2'] (the suffix is appended to the
|
|
263
|
+
* // colliding sanitized base, so an id already ending in `_2` collides anew)
|
|
264
|
+
*/
|
|
265
|
+
export declare function uniqueSanitizedIdentifiers(ids: string[]): string[];
|
package/package.json
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhd/apigen-engine-naming",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@adhd/apigen-core-client": "^0.3.
|
|
5
|
+
"@adhd/apigen-core-client": "^0.3.2"
|
|
6
6
|
},
|
|
7
7
|
"main": "./index.js",
|
|
8
8
|
"module": "./index.mjs",
|
|
9
9
|
"typings": "./index.d.ts",
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"description": "Naming conventions for apigen code generation",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"api",
|
|
16
|
+
"naming",
|
|
17
|
+
"codegen",
|
|
18
|
+
"typescript"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/PseudoSky/adhd.git",
|
|
24
|
+
"directory": "packages/apigen/apigen-engine-naming"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/PseudoSky/adhd/tree/main/packages/apigen/apigen-engine-naming#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/PseudoSky/adhd/issues"
|
|
12
29
|
}
|
|
13
30
|
}
|