bonescript-compiler 0.5.4 → 0.5.6

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.
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ /**
3
+ * BoneScript OpenAPI Emitter
4
+ * Generates OpenAPI 3.0.3 YAML and JSON specs from an IRSystem.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.emitOpenApiJson = exports.emitOpenApiSpec = void 0;
8
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
9
+ function toSnakeCase(s) {
10
+ return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
11
+ }
12
+ function toDashCase(s) {
13
+ return toSnakeCase(s).replace(/_/g, "-");
14
+ }
15
+ function toPascalCase(s) {
16
+ return s.replace(/(^|_)([a-z])/g, (_, _p, c) => c.toUpperCase());
17
+ }
18
+ function irTypeToOpenApi(irType) {
19
+ if (irType === "string")
20
+ return { type: "string" };
21
+ if (irType === "uint" || irType === "int")
22
+ return { type: "integer" };
23
+ if (irType === "float")
24
+ return { type: "number" };
25
+ if (irType === "bool")
26
+ return { type: "boolean" };
27
+ if (irType === "timestamp")
28
+ return { type: "string", format: "date-time" };
29
+ if (irType === "uuid")
30
+ return { type: "string", format: "uuid" };
31
+ if (irType === "bytes")
32
+ return { type: "string", format: "byte" };
33
+ if (irType === "json")
34
+ return { type: "object" };
35
+ const listMatch = irType.match(/^list<(.+)>$/);
36
+ if (listMatch)
37
+ return { type: "array", items: irTypeToOpenApi(listMatch[1]) };
38
+ const setMatch = irType.match(/^set<(.+)>$/);
39
+ if (setMatch)
40
+ return { type: "array", items: irTypeToOpenApi(setMatch[1]) };
41
+ const optMatch = irType.match(/^optional<(.+)>$/);
42
+ if (optMatch)
43
+ return { ...irTypeToOpenApi(optMatch[1]), nullable: true };
44
+ return { type: "string" };
45
+ }
46
+ function ind(n) {
47
+ return " ".repeat(n);
48
+ }
49
+ function yamlValue(v, depth) {
50
+ if (v === null || v === undefined)
51
+ return "null";
52
+ if (typeof v === "boolean")
53
+ return String(v);
54
+ if (typeof v === "number")
55
+ return String(v);
56
+ if (typeof v === "string") {
57
+ if (v.includes(":") ||
58
+ v.includes("#") ||
59
+ v.includes("'") ||
60
+ v.startsWith("{") ||
61
+ v.startsWith("[")) {
62
+ return JSON.stringify(v);
63
+ }
64
+ return v;
65
+ }
66
+ if (Array.isArray(v)) {
67
+ if (v.length === 0)
68
+ return "[]";
69
+ return ("\n" +
70
+ v
71
+ .map((item) => ind(depth) + "- " + yamlValue(item, depth + 1))
72
+ .join("\n"));
73
+ }
74
+ if (typeof v === "object") {
75
+ const entries = Object.entries(v);
76
+ if (entries.length === 0)
77
+ return "{}";
78
+ return ("\n" +
79
+ entries
80
+ .map(([k, val]) => {
81
+ const valStr = yamlValue(val, depth + 1);
82
+ if (valStr.startsWith("\n")) {
83
+ return ind(depth) + k + ":" + valStr;
84
+ }
85
+ return ind(depth) + k + ": " + valStr;
86
+ })
87
+ .join("\n"));
88
+ }
89
+ return String(v);
90
+ }
91
+ function objToYaml(obj, depth = 0) {
92
+ const lines = [];
93
+ for (const [k, v] of Object.entries(obj)) {
94
+ const valStr = yamlValue(v, depth + 1);
95
+ if (valStr.startsWith("\n")) {
96
+ lines.push(ind(depth) + k + ":" + valStr);
97
+ }
98
+ else {
99
+ lines.push(ind(depth) + k + ": " + valStr);
100
+ }
101
+ }
102
+ return lines.join("\n");
103
+ }
104
+ // ─── Spec builder ─────────────────────────────────────────────────────────────
105
+ function buildSpec(system) {
106
+ const paths = {};
107
+ const schemas = {};
108
+ for (const mod of system.modules) {
109
+ if (mod.kind !== "api_service" || mod.models.length === 0)
110
+ continue;
111
+ const model = mod.models[0];
112
+ const tableName = toSnakeCase(model.name);
113
+ const modelName = toPascalCase(model.name);
114
+ const collectionPath = "/" + tableName + "s";
115
+ const itemPath = "/" + tableName + "s/{id}";
116
+ const allMethods = mod.interfaces.flatMap((i) => i.methods);
117
+ const crudNames = new Set(["create", "read", "update", "delete", "list"]);
118
+ const capabilityMethods = allMethods.filter((m) => !crudNames.has(m.name.toLowerCase()));
119
+ const securityRef = [{ BearerAuth: [] }];
120
+ const listOp = {
121
+ summary: "List " + modelName,
122
+ operationId: "list" + modelName,
123
+ tags: [modelName],
124
+ parameters: [
125
+ { name: "page", in: "query", schema: { type: "integer", default: 1 } },
126
+ {
127
+ name: "page_size",
128
+ in: "query",
129
+ schema: { type: "integer", default: 50 },
130
+ },
131
+ ],
132
+ responses: {
133
+ "200": {
134
+ description: "List of " + modelName,
135
+ content: {
136
+ "application/json": {
137
+ schema: {
138
+ type: "object",
139
+ properties: {
140
+ items: {
141
+ type: "array",
142
+ items: { $ref: "#/components/schemas/" + modelName },
143
+ },
144
+ total: { type: "integer" },
145
+ page: { type: "integer" },
146
+ page_size: { type: "integer" },
147
+ },
148
+ },
149
+ },
150
+ },
151
+ },
152
+ "401": { description: "Unauthorized" },
153
+ },
154
+ };
155
+ const createOp = {
156
+ summary: "Create " + modelName,
157
+ operationId: "create" + modelName,
158
+ tags: [modelName],
159
+ security: securityRef,
160
+ requestBody: {
161
+ required: true,
162
+ content: {
163
+ "application/json": {
164
+ schema: { $ref: "#/components/schemas/" + modelName },
165
+ },
166
+ },
167
+ },
168
+ responses: {
169
+ "200": {
170
+ description: "Created",
171
+ content: {
172
+ "application/json": {
173
+ schema: { $ref: "#/components/schemas/" + modelName },
174
+ },
175
+ },
176
+ },
177
+ "401": { description: "Unauthorized" },
178
+ "422": { description: "Precondition failed" },
179
+ "400": { description: "Bad request" },
180
+ },
181
+ };
182
+ paths[collectionPath] = { get: listOp, post: createOp };
183
+ const idParam = [
184
+ {
185
+ name: "id",
186
+ in: "path",
187
+ required: true,
188
+ schema: { type: "string", format: "uuid" },
189
+ },
190
+ ];
191
+ paths[itemPath] = {
192
+ get: {
193
+ summary: "Get " + modelName,
194
+ operationId: "get" + modelName,
195
+ tags: [modelName],
196
+ parameters: idParam,
197
+ security: securityRef,
198
+ responses: {
199
+ "200": {
200
+ description: "Found",
201
+ content: {
202
+ "application/json": {
203
+ schema: { $ref: "#/components/schemas/" + modelName },
204
+ },
205
+ },
206
+ },
207
+ "401": { description: "Unauthorized" },
208
+ "400": { description: "Not found" },
209
+ },
210
+ },
211
+ put: {
212
+ summary: "Update " + modelName,
213
+ operationId: "update" + modelName,
214
+ tags: [modelName],
215
+ parameters: idParam,
216
+ security: securityRef,
217
+ requestBody: {
218
+ required: true,
219
+ content: {
220
+ "application/json": {
221
+ schema: { $ref: "#/components/schemas/" + modelName },
222
+ },
223
+ },
224
+ },
225
+ responses: {
226
+ "200": {
227
+ description: "Updated",
228
+ content: {
229
+ "application/json": {
230
+ schema: { $ref: "#/components/schemas/" + modelName },
231
+ },
232
+ },
233
+ },
234
+ "401": { description: "Unauthorized" },
235
+ "422": { description: "Precondition failed" },
236
+ "400": { description: "Bad request" },
237
+ },
238
+ },
239
+ delete: {
240
+ summary: "Delete " + modelName,
241
+ operationId: "delete" + modelName,
242
+ tags: [modelName],
243
+ parameters: idParam,
244
+ security: securityRef,
245
+ responses: {
246
+ "200": { description: "Deleted" },
247
+ "401": { description: "Unauthorized" },
248
+ "400": { description: "Not found" },
249
+ },
250
+ },
251
+ };
252
+ for (const method of capabilityMethods) {
253
+ const capPath = collectionPath + "/" + toDashCase(method.name);
254
+ const capOp = {
255
+ summary: method.name + " on " + modelName,
256
+ operationId: method.name + modelName,
257
+ tags: [modelName],
258
+ requestBody: {
259
+ required: true,
260
+ content: {
261
+ "application/json": {
262
+ schema: { $ref: "#/components/schemas/" + modelName },
263
+ },
264
+ },
265
+ },
266
+ responses: {
267
+ "200": {
268
+ description: "Success",
269
+ content: {
270
+ "application/json": {
271
+ schema: {
272
+ type: "object",
273
+ properties: {
274
+ ok: { type: "boolean" },
275
+ action: { type: "string" },
276
+ },
277
+ },
278
+ },
279
+ },
280
+ },
281
+ "401": { description: "Unauthorized" },
282
+ "422": { description: "Precondition failed" },
283
+ "400": { description: "Bad request" },
284
+ },
285
+ };
286
+ if (method.authenticated) {
287
+ capOp.security = securityRef;
288
+ }
289
+ paths[capPath] = { post: capOp };
290
+ }
291
+ const properties = {};
292
+ for (const field of model.fields) {
293
+ properties[field.name] = irTypeToOpenApi(field.type);
294
+ }
295
+ schemas[modelName] = {
296
+ type: "object",
297
+ properties,
298
+ };
299
+ }
300
+ return {
301
+ openapi: "3.0.3",
302
+ info: {
303
+ title: system.name,
304
+ version: system.version,
305
+ description: "Generated by BoneScript compiler",
306
+ },
307
+ servers: [{ url: "http://localhost:3000" }],
308
+ paths,
309
+ components: {
310
+ securitySchemes: {
311
+ BearerAuth: {
312
+ type: "http",
313
+ scheme: "bearer",
314
+ bearerFormat: "JWT",
315
+ },
316
+ },
317
+ schemas,
318
+ },
319
+ };
320
+ }
321
+ // ─── Public API ───────────────────────────────────────────────────────────────
322
+ function emitOpenApiSpec(system) {
323
+ const spec = buildSpec(system);
324
+ const lines = ["# Generated by BoneScript compiler"];
325
+ lines.push(objToYaml(spec));
326
+ return lines.join("\n") + "\n";
327
+ }
328
+ exports.emitOpenApiSpec = emitOpenApiSpec;
329
+ function emitOpenApiJson(system) {
330
+ return JSON.stringify(buildSpec(system), null, 2);
331
+ }
332
+ exports.emitOpenApiJson = emitOpenApiJson;
333
+ //# sourceMappingURL=emit_openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit_openapi.js","sourceRoot":"","sources":["../src/emit_openapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * BoneScript Postman Collection Emitter
3
+ * Generates a Postman Collection v2.1 JSON from an IRSystem.
4
+ */
5
+ import * as IR from "./ir";
6
+ export declare function emitPostmanCollection(system: IR.IRSystem): string;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ /**
3
+ * BoneScript Postman Collection Emitter
4
+ * Generates a Postman Collection v2.1 JSON from an IRSystem.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.emitPostmanCollection = void 0;
8
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
9
+ function toSnakeCase(s) {
10
+ return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
11
+ }
12
+ function toDashCase(s) {
13
+ return toSnakeCase(s).replace(/_/g, "-");
14
+ }
15
+ function sampleValue(irType) {
16
+ if (irType === "string")
17
+ return "example";
18
+ if (irType === "uint" || irType === "int")
19
+ return 1;
20
+ if (irType === "float")
21
+ return 1.0;
22
+ if (irType === "bool")
23
+ return true;
24
+ if (irType === "uuid")
25
+ return "00000000-0000-0000-0000-000000000001";
26
+ if (irType === "timestamp")
27
+ return "2024-01-01T00:00:00.000Z";
28
+ if (irType === "bytes")
29
+ return "";
30
+ if (irType === "json")
31
+ return {};
32
+ const listMatch = irType.match(/^list<(.+)>$/);
33
+ if (listMatch)
34
+ return [];
35
+ const setMatch = irType.match(/^set<(.+)>$/);
36
+ if (setMatch)
37
+ return [];
38
+ const optMatch = irType.match(/^optional<(.+)>$/);
39
+ if (optMatch)
40
+ return null;
41
+ return "example";
42
+ }
43
+ function buildSampleBody(model) {
44
+ const body = {};
45
+ for (const field of model.fields) {
46
+ body[field.name] = sampleValue(field.type);
47
+ }
48
+ return body;
49
+ }
50
+ function makeRequest(name, method, url, body) {
51
+ const headers = [
52
+ { key: "Content-Type", value: "application/json" },
53
+ { key: "Authorization", value: "Bearer {{token}}" },
54
+ ];
55
+ const req = {
56
+ name,
57
+ request: {
58
+ method,
59
+ header: headers,
60
+ url: {
61
+ raw: url,
62
+ host: ["{{baseUrl}}"],
63
+ path: url
64
+ .replace("{{baseUrl}}/", "")
65
+ .split("/")
66
+ .filter(Boolean),
67
+ },
68
+ },
69
+ };
70
+ if (body !== undefined) {
71
+ req.request.body = {
72
+ mode: "raw",
73
+ raw: JSON.stringify(body, null, 2),
74
+ options: { raw: { language: "json" } },
75
+ };
76
+ }
77
+ return req;
78
+ }
79
+ // ─── Public API ───────────────────────────────────────────────────────────────
80
+ function emitPostmanCollection(system) {
81
+ const folders = [];
82
+ for (const mod of system.modules) {
83
+ if (mod.kind !== "api_service" || mod.models.length === 0)
84
+ continue;
85
+ const model = mod.models[0];
86
+ const tableName = toSnakeCase(model.name);
87
+ const baseUrl = `{{baseUrl}}/${tableName}s`;
88
+ const sampleBody = buildSampleBody(model);
89
+ const items = [
90
+ makeRequest(`List ${model.name}s`, "GET", baseUrl),
91
+ makeRequest(`Create ${model.name}`, "POST", baseUrl, sampleBody),
92
+ makeRequest(`Get ${model.name}`, "GET", `${baseUrl}/:id`),
93
+ makeRequest(`Update ${model.name}`, "PUT", `${baseUrl}/:id`, sampleBody),
94
+ makeRequest(`Delete ${model.name}`, "DELETE", `${baseUrl}/:id`),
95
+ ];
96
+ const crudNames = new Set(["create", "read", "update", "delete", "list"]);
97
+ const allMethods = mod.interfaces.flatMap((i) => i.methods);
98
+ const capabilityMethods = allMethods.filter((m) => !crudNames.has(m.name.toLowerCase()));
99
+ for (const method of capabilityMethods) {
100
+ const dashName = toDashCase(method.name);
101
+ items.push(makeRequest(method.name + " " + model.name, "POST", `${baseUrl}/${dashName}`, sampleBody));
102
+ }
103
+ folders.push({
104
+ name: mod.name,
105
+ item: items,
106
+ });
107
+ }
108
+ const collection = {
109
+ info: {
110
+ name: system.name,
111
+ schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
112
+ },
113
+ auth: {
114
+ type: "bearer",
115
+ bearer: [{ key: "token", value: "{{token}}", type: "string" }],
116
+ },
117
+ variable: [
118
+ { key: "baseUrl", value: "http://localhost:3000" },
119
+ { key: "token", value: "" },
120
+ ],
121
+ item: folders,
122
+ };
123
+ return JSON.stringify(collection, null, 2);
124
+ }
125
+ exports.emitPostmanCollection = emitPostmanCollection;
126
+ //# sourceMappingURL=emit_postman.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit_postman.js","sourceRoot":"","sources":["../src/emit_postman.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * BoneScript TypeScript SDK Emitter
3
+ * Generates a typed fetch client SDK from an IRSystem.
4
+ */
5
+ import * as IR from "./ir";
6
+ export declare function emitTypescriptSdk(system: IR.IRSystem): string;
7
+ export declare function emitSdkPackageJson(system: IR.IRSystem): string;
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ /**
3
+ * BoneScript TypeScript SDK Emitter
4
+ * Generates a typed fetch client SDK from an IRSystem.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.emitSdkPackageJson = exports.emitTypescriptSdk = void 0;
8
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
9
+ function toSnakeCase(s) {
10
+ return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
11
+ }
12
+ function toCamelCase(s) {
13
+ return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
14
+ }
15
+ function toPascalCase(s) {
16
+ const c = toCamelCase(s);
17
+ return c.charAt(0).toUpperCase() + c.slice(1);
18
+ }
19
+ function irTypeToTs(irType) {
20
+ if (irType === "string")
21
+ return "string";
22
+ if (irType === "uint" || irType === "int")
23
+ return "number";
24
+ if (irType === "float")
25
+ return "number";
26
+ if (irType === "bool")
27
+ return "boolean";
28
+ if (irType === "timestamp")
29
+ return "string";
30
+ if (irType === "uuid")
31
+ return "string";
32
+ if (irType === "bytes")
33
+ return "string";
34
+ if (irType === "json")
35
+ return "unknown";
36
+ const listMatch = irType.match(/^list<(.+)>$/);
37
+ if (listMatch)
38
+ return irTypeToTs(listMatch[1]) + "[]";
39
+ const setMatch = irType.match(/^set<(.+)>$/);
40
+ if (setMatch)
41
+ return irTypeToTs(setMatch[1]) + "[]";
42
+ const optMatch = irType.match(/^optional<(.+)>$/);
43
+ if (optMatch)
44
+ return irTypeToTs(optMatch[1]) + " | null";
45
+ return "unknown";
46
+ }
47
+ // ─── SDK generator ────────────────────────────────────────────────────────────
48
+ function emitTypescriptSdk(system) {
49
+ const lines = [];
50
+ const systemPascal = toPascalCase(system.name.replace(/[^a-zA-Z0-9_]/g, "_"));
51
+ lines.push("// Generated by BoneScript compiler. Import this file into your frontend.");
52
+ lines.push(`// System: ${system.name} v${system.version}`);
53
+ lines.push("");
54
+ // Collect all models for interface generation
55
+ const allModels = [];
56
+ for (const mod of system.modules) {
57
+ if (mod.kind === "api_service" && mod.models.length > 0) {
58
+ for (const model of mod.models) {
59
+ allModels.push({ mod, model });
60
+ }
61
+ }
62
+ }
63
+ // Emit TypeScript interfaces
64
+ for (const { model } of allModels) {
65
+ const typeName = toPascalCase(model.name);
66
+ lines.push(`export interface ${typeName} {`);
67
+ for (const field of model.fields) {
68
+ const nullable = field.nullable ? " | null" : "";
69
+ lines.push(` ${field.name}: ${irTypeToTs(field.type)}${nullable};`);
70
+ }
71
+ lines.push("}");
72
+ lines.push("");
73
+ }
74
+ // Emit client class
75
+ lines.push(`export class ${systemPascal}Client {`);
76
+ lines.push(` constructor(private baseUrl: string, private getToken?: () => string | null) {}`);
77
+ lines.push("");
78
+ // Private request helper
79
+ lines.push(` private async request<T>(method: string, path: string, body?: unknown): Promise<T> {`);
80
+ lines.push(` const headers: Record<string, string> = {`);
81
+ lines.push(` "Content-Type": "application/json",`);
82
+ lines.push(` };`);
83
+ lines.push(` if (this.getToken) {`);
84
+ lines.push(` const token = this.getToken();`);
85
+ lines.push(` if (token) headers["Authorization"] = "Bearer " + token;`);
86
+ lines.push(` }`);
87
+ lines.push(` const res = await fetch(this.baseUrl + path, {`);
88
+ lines.push(` method,`);
89
+ lines.push(` headers,`);
90
+ lines.push(` body: body !== undefined ? JSON.stringify(body) : undefined,`);
91
+ lines.push(` });`);
92
+ lines.push(` if (!res.ok) {`);
93
+ lines.push(` const text = await res.text().catch(() => res.statusText);`);
94
+ lines.push(` throw new Error(\`HTTP \${res.status}: \${text}\`);`);
95
+ lines.push(` }`);
96
+ lines.push(` if (res.status === 204) return undefined as unknown as T;`);
97
+ lines.push(` return res.json() as Promise<T>;`);
98
+ lines.push(` }`);
99
+ lines.push("");
100
+ // Per-entity methods
101
+ for (const { mod, model } of allModels) {
102
+ const entity = toPascalCase(model.name);
103
+ const tableName = toSnakeCase(model.name);
104
+ const basePath = `/${tableName}s`;
105
+ lines.push(` // ─── ${entity} ───`);
106
+ lines.push("");
107
+ lines.push(` list${entity}(page = 1, pageSize = 50): Promise<{ items: ${entity}[]; total: number; page: number; page_size: number }> {`);
108
+ lines.push(` return this.request("GET", \`${basePath}?page=\${page}&page_size=\${pageSize}\`);`);
109
+ lines.push(` }`);
110
+ lines.push("");
111
+ lines.push(` get${entity}(id: string): Promise<${entity}> {`);
112
+ lines.push(` return this.request("GET", \`${basePath}/\${id}\`);`);
113
+ lines.push(` }`);
114
+ lines.push("");
115
+ lines.push(` create${entity}(data: Partial<${entity}>): Promise<${entity}> {`);
116
+ lines.push(` return this.request("POST", "${basePath}", data);`);
117
+ lines.push(` }`);
118
+ lines.push("");
119
+ lines.push(` update${entity}(id: string, data: Partial<${entity}>): Promise<${entity}> {`);
120
+ lines.push(` return this.request("PUT", \`${basePath}/\${id}\`, data);`);
121
+ lines.push(` }`);
122
+ lines.push("");
123
+ lines.push(` delete${entity}(id: string): Promise<void> {`);
124
+ lines.push(` return this.request("DELETE", \`${basePath}/\${id}\`);`);
125
+ lines.push(` }`);
126
+ lines.push("");
127
+ // Capability methods
128
+ const crudNames = new Set(["create", "read", "update", "delete", "list"]);
129
+ const allMethods = mod.interfaces.flatMap((i) => i.methods);
130
+ const capabilityMethods = allMethods.filter((m) => !crudNames.has(m.name.toLowerCase()));
131
+ for (const method of capabilityMethods) {
132
+ const methodCamel = toCamelCase(method.name);
133
+ const dashName = toSnakeCase(method.name).replace(/_/g, "-");
134
+ lines.push(` ${methodCamel}(data: Record<string, unknown>): Promise<{ ok: boolean; action: string }> {`);
135
+ lines.push(` return this.request("POST", "${basePath}/${dashName}", data);`);
136
+ lines.push(` }`);
137
+ lines.push("");
138
+ }
139
+ }
140
+ lines.push("}");
141
+ lines.push("");
142
+ return lines.join("\n");
143
+ }
144
+ exports.emitTypescriptSdk = emitTypescriptSdk;
145
+ function emitSdkPackageJson(system) {
146
+ const pkgName = toSnakeCase(system.name).replace(/_/g, "-") + "-sdk";
147
+ return JSON.stringify({
148
+ name: pkgName,
149
+ version: system.version,
150
+ description: `TypeScript SDK for ${system.name} — generated by BoneScript compiler`,
151
+ main: "client.js",
152
+ types: "client.d.ts",
153
+ scripts: {
154
+ build: "tsc",
155
+ },
156
+ devDependencies: {
157
+ typescript: "5.3.3",
158
+ },
159
+ }, null, 2);
160
+ }
161
+ exports.emitSdkPackageJson = emitSdkPackageJson;
162
+ //# sourceMappingURL=emit_sdk.js.map