@suiteportal/generator 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 +36 -0
- package/dist/index.cjs +242 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +63 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @suiteportal/generator
|
|
2
|
+
|
|
3
|
+
Code generator for SuitePortal — reads a normalized schema and emits TypeScript types, a typed client wrapper, and barrel exports.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @suiteportal/generator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { generate } from '@suiteportal/generator';
|
|
15
|
+
|
|
16
|
+
await generate({
|
|
17
|
+
schemaPath: '.suiteportal/schema.json',
|
|
18
|
+
outputDir: '.suiteportal/client',
|
|
19
|
+
});
|
|
20
|
+
// Generates: types.ts, client.ts, index.ts
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- Reads `NormalizedSchema` from `schema.json`
|
|
26
|
+
- Emits TypeScript interfaces for every record type
|
|
27
|
+
- Generates a typed client wrapper with autocomplete
|
|
28
|
+
- PascalCase naming for interfaces, proper field type mapping
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
|
|
32
|
+
Full docs at [suiteportal.dev](https://suiteportal.dev)
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
emitBarrel: () => emitBarrel,
|
|
24
|
+
emitClient: () => emitClient,
|
|
25
|
+
emitTypes: () => emitTypes,
|
|
26
|
+
fieldTypeToTS: () => fieldTypeToTS,
|
|
27
|
+
generate: () => generate,
|
|
28
|
+
readSchema: () => readSchema,
|
|
29
|
+
toPascalCase: () => toPascalCase
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/generate.ts
|
|
34
|
+
var import_promises2 = require("fs/promises");
|
|
35
|
+
var import_node_path = require("path");
|
|
36
|
+
|
|
37
|
+
// src/schema-reader.ts
|
|
38
|
+
var import_promises = require("fs/promises");
|
|
39
|
+
async function readSchema(schemaPath) {
|
|
40
|
+
const raw = await (0, import_promises.readFile)(schemaPath, "utf-8");
|
|
41
|
+
const schema = JSON.parse(raw);
|
|
42
|
+
if (!schema.records || typeof schema.records !== "object") {
|
|
43
|
+
throw new Error(`Invalid schema: missing "records" in ${schemaPath}`);
|
|
44
|
+
}
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/naming.ts
|
|
49
|
+
function toPascalCase(name) {
|
|
50
|
+
return name.split("_").map((part) => part.length > 0 ? part[0].toUpperCase() + part.slice(1).toLowerCase() : "").join("");
|
|
51
|
+
}
|
|
52
|
+
function fieldTypeToTS(fieldType) {
|
|
53
|
+
switch (fieldType) {
|
|
54
|
+
case "string":
|
|
55
|
+
case "text":
|
|
56
|
+
case "richtext":
|
|
57
|
+
case "email":
|
|
58
|
+
case "url":
|
|
59
|
+
case "phone":
|
|
60
|
+
return "string";
|
|
61
|
+
case "integer":
|
|
62
|
+
case "float":
|
|
63
|
+
case "currency":
|
|
64
|
+
case "percent":
|
|
65
|
+
return "number";
|
|
66
|
+
case "boolean":
|
|
67
|
+
return "boolean";
|
|
68
|
+
case "date":
|
|
69
|
+
case "datetime":
|
|
70
|
+
return "string";
|
|
71
|
+
// SuiteQL returns date strings
|
|
72
|
+
case "select":
|
|
73
|
+
return "string | number";
|
|
74
|
+
case "multiselect":
|
|
75
|
+
return "string";
|
|
76
|
+
case "unknown":
|
|
77
|
+
default:
|
|
78
|
+
return "unknown";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/emitters/type-emitter.ts
|
|
83
|
+
function emitRecordInterface(recordId, record) {
|
|
84
|
+
const name = toPascalCase(recordId);
|
|
85
|
+
const fieldEntries = Object.entries(record.fields);
|
|
86
|
+
const fieldCount = fieldEntries.length;
|
|
87
|
+
const lines = [];
|
|
88
|
+
lines.push(`/** ${record.label} \u2014 ${fieldCount} fields */`);
|
|
89
|
+
lines.push(`export interface ${name} {`);
|
|
90
|
+
for (const [fieldId, field] of fieldEntries) {
|
|
91
|
+
const tsType = fieldTypeToTS(field.type);
|
|
92
|
+
lines.push(` /** ${field.label} */`);
|
|
93
|
+
lines.push(` ${fieldId}?: ${tsType};`);
|
|
94
|
+
}
|
|
95
|
+
lines.push("}");
|
|
96
|
+
return lines.join("\n");
|
|
97
|
+
}
|
|
98
|
+
function emitTypes(schema) {
|
|
99
|
+
const lines = [
|
|
100
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
101
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
102
|
+
""
|
|
103
|
+
];
|
|
104
|
+
const recordEntries = Object.entries(schema.records);
|
|
105
|
+
for (const [recordId, record] of recordEntries) {
|
|
106
|
+
lines.push(emitRecordInterface(recordId, record));
|
|
107
|
+
lines.push("");
|
|
108
|
+
}
|
|
109
|
+
if (recordEntries.length > 0) {
|
|
110
|
+
const names = recordEntries.map(([id]) => `'${id}'`);
|
|
111
|
+
lines.push(`/** All available record type IDs. */`);
|
|
112
|
+
lines.push(`export type RecordTypeId = ${names.join(" | ")};`);
|
|
113
|
+
lines.push("");
|
|
114
|
+
lines.push(`/** Map of record type IDs to their TypeScript interfaces. */`);
|
|
115
|
+
lines.push(`export interface RecordTypeMap {`);
|
|
116
|
+
for (const [recordId] of recordEntries) {
|
|
117
|
+
lines.push(` ${recordId}: ${toPascalCase(recordId)};`);
|
|
118
|
+
}
|
|
119
|
+
lines.push("}");
|
|
120
|
+
lines.push("");
|
|
121
|
+
}
|
|
122
|
+
return lines.join("\n");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/emitters/client-emitter.ts
|
|
126
|
+
function emitClient(schema) {
|
|
127
|
+
const recordEntries = Object.entries(schema.records);
|
|
128
|
+
const typeImports = recordEntries.map(([id]) => toPascalCase(id));
|
|
129
|
+
const lines = [
|
|
130
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
131
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
132
|
+
"",
|
|
133
|
+
`import type { NetSuiteConfig } from '@suiteportal/connector';`,
|
|
134
|
+
`import {`,
|
|
135
|
+
` SuitePortalClient as BaseClient,`,
|
|
136
|
+
` type FindManyArgs,`,
|
|
137
|
+
` type FindFirstArgs,`,
|
|
138
|
+
` type CountArgs,`,
|
|
139
|
+
` type ClientOptions,`,
|
|
140
|
+
`} from '@suiteportal/client-runtime';`
|
|
141
|
+
];
|
|
142
|
+
if (typeImports.length > 0) {
|
|
143
|
+
lines.push(`import type { ${typeImports.join(", ")} } from './types.js';`);
|
|
144
|
+
}
|
|
145
|
+
lines.push("");
|
|
146
|
+
lines.push("/** A typed model delegate for a specific record type. */");
|
|
147
|
+
lines.push("export interface TypedModelDelegate<T> {");
|
|
148
|
+
lines.push(" findMany(args?: FindManyArgs): Promise<T[]>;");
|
|
149
|
+
lines.push(" findFirst(args?: FindFirstArgs): Promise<T | null>;");
|
|
150
|
+
lines.push(" count(args?: CountArgs): Promise<number>;");
|
|
151
|
+
lines.push("}");
|
|
152
|
+
lines.push("");
|
|
153
|
+
lines.push("/** Typed SuitePortal client with per-record delegates. */");
|
|
154
|
+
lines.push("export interface SuitePortalClient {");
|
|
155
|
+
for (const [recordId] of recordEntries) {
|
|
156
|
+
const typeName = toPascalCase(recordId);
|
|
157
|
+
lines.push(` ${recordId}: TypedModelDelegate<${typeName}>;`);
|
|
158
|
+
}
|
|
159
|
+
lines.push(" $queryRaw<T = Record<string, unknown>>(sql: string): Promise<T[]>;");
|
|
160
|
+
lines.push(" $disconnect(): void;");
|
|
161
|
+
lines.push(" $loadSchema(): Promise<void>;");
|
|
162
|
+
lines.push("}");
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push("/**");
|
|
165
|
+
lines.push(" * Create a typed SuitePortal client.");
|
|
166
|
+
lines.push(" * Loads schema.json and provides typed access to all record types.");
|
|
167
|
+
lines.push(" */");
|
|
168
|
+
lines.push("export async function createClient(");
|
|
169
|
+
lines.push(" config: NetSuiteConfig,");
|
|
170
|
+
lines.push(" options?: ClientOptions,");
|
|
171
|
+
lines.push("): Promise<SuitePortalClient> {");
|
|
172
|
+
lines.push(" const client = new BaseClient(config, options);");
|
|
173
|
+
lines.push(" await client.$loadSchema();");
|
|
174
|
+
lines.push(" return client as unknown as SuitePortalClient;");
|
|
175
|
+
lines.push("}");
|
|
176
|
+
lines.push("");
|
|
177
|
+
lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs } from '@suiteportal/client-runtime';");
|
|
178
|
+
lines.push("");
|
|
179
|
+
return lines.join("\n");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/emitters/barrel-emitter.ts
|
|
183
|
+
function emitBarrel(schema) {
|
|
184
|
+
const recordEntries = Object.entries(schema.records);
|
|
185
|
+
const typeNames = recordEntries.map(([id]) => toPascalCase(id));
|
|
186
|
+
const lines = [
|
|
187
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
188
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
189
|
+
""
|
|
190
|
+
];
|
|
191
|
+
if (typeNames.length > 0) {
|
|
192
|
+
lines.push(`export type { ${typeNames.join(", ")}, RecordTypeId, RecordTypeMap } from './types.js';`);
|
|
193
|
+
}
|
|
194
|
+
lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client.js';`);
|
|
195
|
+
lines.push(`export { createClient } from './client.js';`);
|
|
196
|
+
lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client.js';`);
|
|
197
|
+
lines.push("");
|
|
198
|
+
return lines.join("\n");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/generate.ts
|
|
202
|
+
var DEFAULT_SCHEMA_PATH = ".suiteportal/schema.json";
|
|
203
|
+
var DEFAULT_OUTPUT_DIR = ".suiteportal/client";
|
|
204
|
+
async function generate(options) {
|
|
205
|
+
const schemaPath = options?.schemaPath ?? DEFAULT_SCHEMA_PATH;
|
|
206
|
+
const outputDir = options?.outputDir ?? DEFAULT_OUTPUT_DIR;
|
|
207
|
+
const schema = await readSchema(schemaPath);
|
|
208
|
+
await (0, import_promises2.mkdir)(outputDir, { recursive: true });
|
|
209
|
+
const typesContent = emitTypes(schema);
|
|
210
|
+
const clientContent = emitClient(schema);
|
|
211
|
+
const barrelContent = emitBarrel(schema);
|
|
212
|
+
const typesPath = (0, import_node_path.join)(outputDir, "types.ts");
|
|
213
|
+
const clientPath = (0, import_node_path.join)(outputDir, "client.ts");
|
|
214
|
+
const barrelPath = (0, import_node_path.join)(outputDir, "index.ts");
|
|
215
|
+
await Promise.all([
|
|
216
|
+
(0, import_promises2.writeFile)(typesPath, typesContent, "utf-8"),
|
|
217
|
+
(0, import_promises2.writeFile)(clientPath, clientContent, "utf-8"),
|
|
218
|
+
(0, import_promises2.writeFile)(barrelPath, barrelContent, "utf-8")
|
|
219
|
+
]);
|
|
220
|
+
const recordEntries = Object.entries(schema.records);
|
|
221
|
+
const fieldCount = recordEntries.reduce(
|
|
222
|
+
(sum, [, record]) => sum + Object.keys(record.fields).length,
|
|
223
|
+
0
|
|
224
|
+
);
|
|
225
|
+
return {
|
|
226
|
+
recordCount: recordEntries.length,
|
|
227
|
+
fieldCount,
|
|
228
|
+
files: [typesPath, clientPath, barrelPath],
|
|
229
|
+
outputDir
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
233
|
+
0 && (module.exports = {
|
|
234
|
+
emitBarrel,
|
|
235
|
+
emitClient,
|
|
236
|
+
emitTypes,
|
|
237
|
+
fieldTypeToTS,
|
|
238
|
+
generate,
|
|
239
|
+
readSchema,
|
|
240
|
+
toPascalCase
|
|
241
|
+
});
|
|
242
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/generate.ts","../src/schema-reader.ts","../src/naming.ts","../src/emitters/type-emitter.ts","../src/emitters/client-emitter.ts","../src/emitters/barrel-emitter.ts"],"sourcesContent":["// Generator\nexport { generate } from './generate.js';\n\n// Schema reader\nexport { readSchema } from './schema-reader.js';\n\n// Naming utilities\nexport { toPascalCase, fieldTypeToTS } from './naming.js';\n\n// Emitters\nexport { emitTypes } from './emitters/type-emitter.js';\nexport { emitClient } from './emitters/client-emitter.js';\nexport { emitBarrel } from './emitters/barrel-emitter.js';\n\n// Types\nexport type { GenerateOptions, GenerateResult } from './types.js';\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { readSchema } from './schema-reader.js';\nimport { emitTypes } from './emitters/type-emitter.js';\nimport { emitClient } from './emitters/client-emitter.js';\nimport { emitBarrel } from './emitters/barrel-emitter.js';\nimport type { GenerateOptions, GenerateResult } from './types.js';\n\nconst DEFAULT_SCHEMA_PATH = '.suiteportal/schema.json';\nconst DEFAULT_OUTPUT_DIR = '.suiteportal/client';\n\n/**\n * Generate typed client code from a schema.json file.\n *\n * Reads the introspected schema, emits TypeScript interfaces for all records,\n * a typed client wrapper, and a barrel export file.\n */\nexport async function generate(options?: GenerateOptions): Promise<GenerateResult> {\n const schemaPath = options?.schemaPath ?? DEFAULT_SCHEMA_PATH;\n const outputDir = options?.outputDir ?? DEFAULT_OUTPUT_DIR;\n\n // Read schema\n const schema = await readSchema(schemaPath);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n // Generate files\n const typesContent = emitTypes(schema);\n const clientContent = emitClient(schema);\n const barrelContent = emitBarrel(schema);\n\n // Write files\n const typesPath = join(outputDir, 'types.ts');\n const clientPath = join(outputDir, 'client.ts');\n const barrelPath = join(outputDir, 'index.ts');\n\n await Promise.all([\n writeFile(typesPath, typesContent, 'utf-8'),\n writeFile(clientPath, clientContent, 'utf-8'),\n writeFile(barrelPath, barrelContent, 'utf-8'),\n ]);\n\n // Compute stats\n const recordEntries = Object.entries(schema.records);\n const fieldCount = recordEntries.reduce(\n (sum, [, record]) => sum + Object.keys(record.fields).length,\n 0,\n );\n\n return {\n recordCount: recordEntries.length,\n fieldCount,\n files: [typesPath, clientPath, barrelPath],\n outputDir,\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport type { NormalizedSchema } from '@suiteportal/introspector';\n\n/**\n * Read and parse a schema.json file.\n */\nexport async function readSchema(schemaPath: string): Promise<NormalizedSchema> {\n const raw = await readFile(schemaPath, 'utf-8');\n const schema = JSON.parse(raw) as NormalizedSchema;\n\n if (!schema.records || typeof schema.records !== 'object') {\n throw new Error(`Invalid schema: missing \"records\" in ${schemaPath}`);\n }\n\n return schema;\n}\n","import type { FieldType } from '@suiteportal/introspector';\n\n/**\n * Convert a record ID to PascalCase for use as a TypeScript interface name.\n * Examples:\n * 'customer' → 'Customer'\n * 'salesorder' → 'Salesorder'\n * 'customrecord_mytype' → 'CustomrecordMytype'\n */\nexport function toPascalCase(name: string): string {\n return name\n .split('_')\n .map((part) => (part.length > 0 ? part[0]!.toUpperCase() + part.slice(1).toLowerCase() : ''))\n .join('');\n}\n\n/**\n * Map a normalized FieldType to its TypeScript type representation.\n */\nexport function fieldTypeToTS(fieldType: FieldType): string {\n switch (fieldType) {\n case 'string':\n case 'text':\n case 'richtext':\n case 'email':\n case 'url':\n case 'phone':\n return 'string';\n\n case 'integer':\n case 'float':\n case 'currency':\n case 'percent':\n return 'number';\n\n case 'boolean':\n return 'boolean';\n\n case 'date':\n case 'datetime':\n return 'string'; // SuiteQL returns date strings\n\n case 'select':\n return 'string | number';\n\n case 'multiselect':\n return 'string';\n\n case 'unknown':\n default:\n return 'unknown';\n }\n}\n","import type { NormalizedSchema, RecordDefinition } from '@suiteportal/introspector';\nimport { toPascalCase, fieldTypeToTS } from '../naming.js';\n\n/**\n * Emit a TypeScript interface for a single record.\n */\nfunction emitRecordInterface(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const fieldEntries = Object.entries(record.fields);\n const fieldCount = fieldEntries.length;\n\n const lines: string[] = [];\n lines.push(`/** ${record.label} — ${fieldCount} fields */`);\n lines.push(`export interface ${name} {`);\n\n for (const [fieldId, field] of fieldEntries) {\n const tsType = fieldTypeToTS(field.type);\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}?: ${tsType};`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit the full types.ts file content from a schema.\n */\nexport function emitTypes(schema: NormalizedSchema): string {\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n const recordEntries = Object.entries(schema.records);\n\n for (const [recordId, record] of recordEntries) {\n lines.push(emitRecordInterface(recordId, record));\n lines.push('');\n }\n\n // Export a union type of all record names\n if (recordEntries.length > 0) {\n const names = recordEntries.map(([id]) => `'${id}'`);\n lines.push(`/** All available record type IDs. */`);\n lines.push(`export type RecordTypeId = ${names.join(' | ')};`);\n lines.push('');\n\n // Record type map\n lines.push(`/** Map of record type IDs to their TypeScript interfaces. */`);\n lines.push(`export interface RecordTypeMap {`);\n for (const [recordId] of recordEntries) {\n lines.push(` ${recordId}: ${toPascalCase(recordId)};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type { NormalizedSchema } from '@suiteportal/introspector';\nimport { toPascalCase } from '../naming.js';\n\n/**\n * Emit the client.ts file content — a typed wrapper around the base SuitePortalClient.\n */\nexport function emitClient(schema: NormalizedSchema): string {\n const recordEntries = Object.entries(schema.records);\n const typeImports = recordEntries.map(([id]) => toPascalCase(id));\n\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n `import type { NetSuiteConfig } from '@suiteportal/connector';`,\n `import {`,\n ` SuitePortalClient as BaseClient,`,\n ` type FindManyArgs,`,\n ` type FindFirstArgs,`,\n ` type CountArgs,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n lines.push(`import type { ${typeImports.join(', ')} } from './types.js';`);\n }\n\n lines.push('');\n\n // TypedModelDelegate interface\n lines.push('/** A typed model delegate for a specific record type. */');\n lines.push('export interface TypedModelDelegate<T> {');\n lines.push(' findMany(args?: FindManyArgs): Promise<T[]>;');\n lines.push(' findFirst(args?: FindFirstArgs): Promise<T | null>;');\n lines.push(' count(args?: CountArgs): Promise<number>;');\n lines.push('}');\n lines.push('');\n\n // SuitePortalClient interface\n lines.push('/** Typed SuitePortal client with per-record delegates. */');\n lines.push('export interface SuitePortalClient {');\n\n for (const [recordId] of recordEntries) {\n const typeName = toPascalCase(recordId);\n lines.push(` ${recordId}: TypedModelDelegate<${typeName}>;`);\n }\n\n lines.push(' $queryRaw<T = Record<string, unknown>>(sql: string): Promise<T[]>;');\n lines.push(' $disconnect(): void;');\n lines.push(' $loadSchema(): Promise<void>;');\n lines.push('}');\n lines.push('');\n\n // createClient function\n lines.push('/**');\n lines.push(' * Create a typed SuitePortal client.');\n lines.push(' * Loads schema.json and provides typed access to all record types.');\n lines.push(' */');\n lines.push('export async function createClient(');\n lines.push(' config: NetSuiteConfig,');\n lines.push(' options?: ClientOptions,');\n lines.push('): Promise<SuitePortalClient> {');\n lines.push(' const client = new BaseClient(config, options);');\n lines.push(' await client.$loadSchema();');\n lines.push(' return client as unknown as SuitePortalClient;');\n lines.push('}');\n lines.push('');\n\n // Re-export types for convenience\n lines.push('export type { FindManyArgs, FindFirstArgs, CountArgs } from \\'@suiteportal/client-runtime\\';');\n lines.push('');\n\n return lines.join('\\n');\n}\n","import type { NormalizedSchema } from '@suiteportal/introspector';\nimport { toPascalCase } from '../naming.js';\n\n/**\n * Emit the index.ts barrel export file content.\n */\nexport function emitBarrel(schema: NormalizedSchema): string {\n const recordEntries = Object.entries(schema.records);\n const typeNames = recordEntries.map(([id]) => toPascalCase(id));\n\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n // Type exports\n if (typeNames.length > 0) {\n lines.push(`export type { ${typeNames.join(', ')}, RecordTypeId, RecordTypeMap } from './types.js';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client.js';`);\n lines.push(`export { createClient } from './client.js';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client.js';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["import_promises"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NormalizedSchema, FieldType } from '@suiteportal/introspector';
|
|
2
|
+
|
|
3
|
+
/** Options for the code generator. */
|
|
4
|
+
interface GenerateOptions {
|
|
5
|
+
/** Path to schema.json. Default: '.suiteportal/schema.json' */
|
|
6
|
+
schemaPath?: string;
|
|
7
|
+
/** Output directory for generated code. Default: '.suiteportal/client' */
|
|
8
|
+
outputDir?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Result returned by the generate function. */
|
|
11
|
+
interface GenerateResult {
|
|
12
|
+
/** Number of record types generated. */
|
|
13
|
+
recordCount: number;
|
|
14
|
+
/** Total number of fields across all records. */
|
|
15
|
+
fieldCount: number;
|
|
16
|
+
/** Files that were written. */
|
|
17
|
+
files: string[];
|
|
18
|
+
/** Output directory path. */
|
|
19
|
+
outputDir: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate typed client code from a schema.json file.
|
|
24
|
+
*
|
|
25
|
+
* Reads the introspected schema, emits TypeScript interfaces for all records,
|
|
26
|
+
* a typed client wrapper, and a barrel export file.
|
|
27
|
+
*/
|
|
28
|
+
declare function generate(options?: GenerateOptions): Promise<GenerateResult>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read and parse a schema.json file.
|
|
32
|
+
*/
|
|
33
|
+
declare function readSchema(schemaPath: string): Promise<NormalizedSchema>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convert a record ID to PascalCase for use as a TypeScript interface name.
|
|
37
|
+
* Examples:
|
|
38
|
+
* 'customer' → 'Customer'
|
|
39
|
+
* 'salesorder' → 'Salesorder'
|
|
40
|
+
* 'customrecord_mytype' → 'CustomrecordMytype'
|
|
41
|
+
*/
|
|
42
|
+
declare function toPascalCase(name: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Map a normalized FieldType to its TypeScript type representation.
|
|
45
|
+
*/
|
|
46
|
+
declare function fieldTypeToTS(fieldType: FieldType): string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Emit the full types.ts file content from a schema.
|
|
50
|
+
*/
|
|
51
|
+
declare function emitTypes(schema: NormalizedSchema): string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Emit the client.ts file content — a typed wrapper around the base SuitePortalClient.
|
|
55
|
+
*/
|
|
56
|
+
declare function emitClient(schema: NormalizedSchema): string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Emit the index.ts barrel export file content.
|
|
60
|
+
*/
|
|
61
|
+
declare function emitBarrel(schema: NormalizedSchema): string;
|
|
62
|
+
|
|
63
|
+
export { type GenerateOptions, type GenerateResult, emitBarrel, emitClient, emitTypes, fieldTypeToTS, generate, readSchema, toPascalCase };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NormalizedSchema, FieldType } from '@suiteportal/introspector';
|
|
2
|
+
|
|
3
|
+
/** Options for the code generator. */
|
|
4
|
+
interface GenerateOptions {
|
|
5
|
+
/** Path to schema.json. Default: '.suiteportal/schema.json' */
|
|
6
|
+
schemaPath?: string;
|
|
7
|
+
/** Output directory for generated code. Default: '.suiteportal/client' */
|
|
8
|
+
outputDir?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Result returned by the generate function. */
|
|
11
|
+
interface GenerateResult {
|
|
12
|
+
/** Number of record types generated. */
|
|
13
|
+
recordCount: number;
|
|
14
|
+
/** Total number of fields across all records. */
|
|
15
|
+
fieldCount: number;
|
|
16
|
+
/** Files that were written. */
|
|
17
|
+
files: string[];
|
|
18
|
+
/** Output directory path. */
|
|
19
|
+
outputDir: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate typed client code from a schema.json file.
|
|
24
|
+
*
|
|
25
|
+
* Reads the introspected schema, emits TypeScript interfaces for all records,
|
|
26
|
+
* a typed client wrapper, and a barrel export file.
|
|
27
|
+
*/
|
|
28
|
+
declare function generate(options?: GenerateOptions): Promise<GenerateResult>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read and parse a schema.json file.
|
|
32
|
+
*/
|
|
33
|
+
declare function readSchema(schemaPath: string): Promise<NormalizedSchema>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convert a record ID to PascalCase for use as a TypeScript interface name.
|
|
37
|
+
* Examples:
|
|
38
|
+
* 'customer' → 'Customer'
|
|
39
|
+
* 'salesorder' → 'Salesorder'
|
|
40
|
+
* 'customrecord_mytype' → 'CustomrecordMytype'
|
|
41
|
+
*/
|
|
42
|
+
declare function toPascalCase(name: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Map a normalized FieldType to its TypeScript type representation.
|
|
45
|
+
*/
|
|
46
|
+
declare function fieldTypeToTS(fieldType: FieldType): string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Emit the full types.ts file content from a schema.
|
|
50
|
+
*/
|
|
51
|
+
declare function emitTypes(schema: NormalizedSchema): string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Emit the client.ts file content — a typed wrapper around the base SuitePortalClient.
|
|
55
|
+
*/
|
|
56
|
+
declare function emitClient(schema: NormalizedSchema): string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Emit the index.ts barrel export file content.
|
|
60
|
+
*/
|
|
61
|
+
declare function emitBarrel(schema: NormalizedSchema): string;
|
|
62
|
+
|
|
63
|
+
export { type GenerateOptions, type GenerateResult, emitBarrel, emitClient, emitTypes, fieldTypeToTS, generate, readSchema, toPascalCase };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// src/generate.ts
|
|
2
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
// src/schema-reader.ts
|
|
6
|
+
import { readFile } from "fs/promises";
|
|
7
|
+
async function readSchema(schemaPath) {
|
|
8
|
+
const raw = await readFile(schemaPath, "utf-8");
|
|
9
|
+
const schema = JSON.parse(raw);
|
|
10
|
+
if (!schema.records || typeof schema.records !== "object") {
|
|
11
|
+
throw new Error(`Invalid schema: missing "records" in ${schemaPath}`);
|
|
12
|
+
}
|
|
13
|
+
return schema;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/naming.ts
|
|
17
|
+
function toPascalCase(name) {
|
|
18
|
+
return name.split("_").map((part) => part.length > 0 ? part[0].toUpperCase() + part.slice(1).toLowerCase() : "").join("");
|
|
19
|
+
}
|
|
20
|
+
function fieldTypeToTS(fieldType) {
|
|
21
|
+
switch (fieldType) {
|
|
22
|
+
case "string":
|
|
23
|
+
case "text":
|
|
24
|
+
case "richtext":
|
|
25
|
+
case "email":
|
|
26
|
+
case "url":
|
|
27
|
+
case "phone":
|
|
28
|
+
return "string";
|
|
29
|
+
case "integer":
|
|
30
|
+
case "float":
|
|
31
|
+
case "currency":
|
|
32
|
+
case "percent":
|
|
33
|
+
return "number";
|
|
34
|
+
case "boolean":
|
|
35
|
+
return "boolean";
|
|
36
|
+
case "date":
|
|
37
|
+
case "datetime":
|
|
38
|
+
return "string";
|
|
39
|
+
// SuiteQL returns date strings
|
|
40
|
+
case "select":
|
|
41
|
+
return "string | number";
|
|
42
|
+
case "multiselect":
|
|
43
|
+
return "string";
|
|
44
|
+
case "unknown":
|
|
45
|
+
default:
|
|
46
|
+
return "unknown";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/emitters/type-emitter.ts
|
|
51
|
+
function emitRecordInterface(recordId, record) {
|
|
52
|
+
const name = toPascalCase(recordId);
|
|
53
|
+
const fieldEntries = Object.entries(record.fields);
|
|
54
|
+
const fieldCount = fieldEntries.length;
|
|
55
|
+
const lines = [];
|
|
56
|
+
lines.push(`/** ${record.label} \u2014 ${fieldCount} fields */`);
|
|
57
|
+
lines.push(`export interface ${name} {`);
|
|
58
|
+
for (const [fieldId, field] of fieldEntries) {
|
|
59
|
+
const tsType = fieldTypeToTS(field.type);
|
|
60
|
+
lines.push(` /** ${field.label} */`);
|
|
61
|
+
lines.push(` ${fieldId}?: ${tsType};`);
|
|
62
|
+
}
|
|
63
|
+
lines.push("}");
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
function emitTypes(schema) {
|
|
67
|
+
const lines = [
|
|
68
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
69
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
70
|
+
""
|
|
71
|
+
];
|
|
72
|
+
const recordEntries = Object.entries(schema.records);
|
|
73
|
+
for (const [recordId, record] of recordEntries) {
|
|
74
|
+
lines.push(emitRecordInterface(recordId, record));
|
|
75
|
+
lines.push("");
|
|
76
|
+
}
|
|
77
|
+
if (recordEntries.length > 0) {
|
|
78
|
+
const names = recordEntries.map(([id]) => `'${id}'`);
|
|
79
|
+
lines.push(`/** All available record type IDs. */`);
|
|
80
|
+
lines.push(`export type RecordTypeId = ${names.join(" | ")};`);
|
|
81
|
+
lines.push("");
|
|
82
|
+
lines.push(`/** Map of record type IDs to their TypeScript interfaces. */`);
|
|
83
|
+
lines.push(`export interface RecordTypeMap {`);
|
|
84
|
+
for (const [recordId] of recordEntries) {
|
|
85
|
+
lines.push(` ${recordId}: ${toPascalCase(recordId)};`);
|
|
86
|
+
}
|
|
87
|
+
lines.push("}");
|
|
88
|
+
lines.push("");
|
|
89
|
+
}
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/emitters/client-emitter.ts
|
|
94
|
+
function emitClient(schema) {
|
|
95
|
+
const recordEntries = Object.entries(schema.records);
|
|
96
|
+
const typeImports = recordEntries.map(([id]) => toPascalCase(id));
|
|
97
|
+
const lines = [
|
|
98
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
99
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
100
|
+
"",
|
|
101
|
+
`import type { NetSuiteConfig } from '@suiteportal/connector';`,
|
|
102
|
+
`import {`,
|
|
103
|
+
` SuitePortalClient as BaseClient,`,
|
|
104
|
+
` type FindManyArgs,`,
|
|
105
|
+
` type FindFirstArgs,`,
|
|
106
|
+
` type CountArgs,`,
|
|
107
|
+
` type ClientOptions,`,
|
|
108
|
+
`} from '@suiteportal/client-runtime';`
|
|
109
|
+
];
|
|
110
|
+
if (typeImports.length > 0) {
|
|
111
|
+
lines.push(`import type { ${typeImports.join(", ")} } from './types.js';`);
|
|
112
|
+
}
|
|
113
|
+
lines.push("");
|
|
114
|
+
lines.push("/** A typed model delegate for a specific record type. */");
|
|
115
|
+
lines.push("export interface TypedModelDelegate<T> {");
|
|
116
|
+
lines.push(" findMany(args?: FindManyArgs): Promise<T[]>;");
|
|
117
|
+
lines.push(" findFirst(args?: FindFirstArgs): Promise<T | null>;");
|
|
118
|
+
lines.push(" count(args?: CountArgs): Promise<number>;");
|
|
119
|
+
lines.push("}");
|
|
120
|
+
lines.push("");
|
|
121
|
+
lines.push("/** Typed SuitePortal client with per-record delegates. */");
|
|
122
|
+
lines.push("export interface SuitePortalClient {");
|
|
123
|
+
for (const [recordId] of recordEntries) {
|
|
124
|
+
const typeName = toPascalCase(recordId);
|
|
125
|
+
lines.push(` ${recordId}: TypedModelDelegate<${typeName}>;`);
|
|
126
|
+
}
|
|
127
|
+
lines.push(" $queryRaw<T = Record<string, unknown>>(sql: string): Promise<T[]>;");
|
|
128
|
+
lines.push(" $disconnect(): void;");
|
|
129
|
+
lines.push(" $loadSchema(): Promise<void>;");
|
|
130
|
+
lines.push("}");
|
|
131
|
+
lines.push("");
|
|
132
|
+
lines.push("/**");
|
|
133
|
+
lines.push(" * Create a typed SuitePortal client.");
|
|
134
|
+
lines.push(" * Loads schema.json and provides typed access to all record types.");
|
|
135
|
+
lines.push(" */");
|
|
136
|
+
lines.push("export async function createClient(");
|
|
137
|
+
lines.push(" config: NetSuiteConfig,");
|
|
138
|
+
lines.push(" options?: ClientOptions,");
|
|
139
|
+
lines.push("): Promise<SuitePortalClient> {");
|
|
140
|
+
lines.push(" const client = new BaseClient(config, options);");
|
|
141
|
+
lines.push(" await client.$loadSchema();");
|
|
142
|
+
lines.push(" return client as unknown as SuitePortalClient;");
|
|
143
|
+
lines.push("}");
|
|
144
|
+
lines.push("");
|
|
145
|
+
lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs } from '@suiteportal/client-runtime';");
|
|
146
|
+
lines.push("");
|
|
147
|
+
return lines.join("\n");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/emitters/barrel-emitter.ts
|
|
151
|
+
function emitBarrel(schema) {
|
|
152
|
+
const recordEntries = Object.entries(schema.records);
|
|
153
|
+
const typeNames = recordEntries.map(([id]) => toPascalCase(id));
|
|
154
|
+
const lines = [
|
|
155
|
+
"// Auto-generated by @suiteportal/generator \u2014 DO NOT EDIT",
|
|
156
|
+
`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
157
|
+
""
|
|
158
|
+
];
|
|
159
|
+
if (typeNames.length > 0) {
|
|
160
|
+
lines.push(`export type { ${typeNames.join(", ")}, RecordTypeId, RecordTypeMap } from './types.js';`);
|
|
161
|
+
}
|
|
162
|
+
lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client.js';`);
|
|
163
|
+
lines.push(`export { createClient } from './client.js';`);
|
|
164
|
+
lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client.js';`);
|
|
165
|
+
lines.push("");
|
|
166
|
+
return lines.join("\n");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/generate.ts
|
|
170
|
+
var DEFAULT_SCHEMA_PATH = ".suiteportal/schema.json";
|
|
171
|
+
var DEFAULT_OUTPUT_DIR = ".suiteportal/client";
|
|
172
|
+
async function generate(options) {
|
|
173
|
+
const schemaPath = options?.schemaPath ?? DEFAULT_SCHEMA_PATH;
|
|
174
|
+
const outputDir = options?.outputDir ?? DEFAULT_OUTPUT_DIR;
|
|
175
|
+
const schema = await readSchema(schemaPath);
|
|
176
|
+
await mkdir(outputDir, { recursive: true });
|
|
177
|
+
const typesContent = emitTypes(schema);
|
|
178
|
+
const clientContent = emitClient(schema);
|
|
179
|
+
const barrelContent = emitBarrel(schema);
|
|
180
|
+
const typesPath = join(outputDir, "types.ts");
|
|
181
|
+
const clientPath = join(outputDir, "client.ts");
|
|
182
|
+
const barrelPath = join(outputDir, "index.ts");
|
|
183
|
+
await Promise.all([
|
|
184
|
+
writeFile(typesPath, typesContent, "utf-8"),
|
|
185
|
+
writeFile(clientPath, clientContent, "utf-8"),
|
|
186
|
+
writeFile(barrelPath, barrelContent, "utf-8")
|
|
187
|
+
]);
|
|
188
|
+
const recordEntries = Object.entries(schema.records);
|
|
189
|
+
const fieldCount = recordEntries.reduce(
|
|
190
|
+
(sum, [, record]) => sum + Object.keys(record.fields).length,
|
|
191
|
+
0
|
|
192
|
+
);
|
|
193
|
+
return {
|
|
194
|
+
recordCount: recordEntries.length,
|
|
195
|
+
fieldCount,
|
|
196
|
+
files: [typesPath, clientPath, barrelPath],
|
|
197
|
+
outputDir
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export {
|
|
201
|
+
emitBarrel,
|
|
202
|
+
emitClient,
|
|
203
|
+
emitTypes,
|
|
204
|
+
fieldTypeToTS,
|
|
205
|
+
generate,
|
|
206
|
+
readSchema,
|
|
207
|
+
toPascalCase
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generate.ts","../src/schema-reader.ts","../src/naming.ts","../src/emitters/type-emitter.ts","../src/emitters/client-emitter.ts","../src/emitters/barrel-emitter.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { readSchema } from './schema-reader.js';\nimport { emitTypes } from './emitters/type-emitter.js';\nimport { emitClient } from './emitters/client-emitter.js';\nimport { emitBarrel } from './emitters/barrel-emitter.js';\nimport type { GenerateOptions, GenerateResult } from './types.js';\n\nconst DEFAULT_SCHEMA_PATH = '.suiteportal/schema.json';\nconst DEFAULT_OUTPUT_DIR = '.suiteportal/client';\n\n/**\n * Generate typed client code from a schema.json file.\n *\n * Reads the introspected schema, emits TypeScript interfaces for all records,\n * a typed client wrapper, and a barrel export file.\n */\nexport async function generate(options?: GenerateOptions): Promise<GenerateResult> {\n const schemaPath = options?.schemaPath ?? DEFAULT_SCHEMA_PATH;\n const outputDir = options?.outputDir ?? DEFAULT_OUTPUT_DIR;\n\n // Read schema\n const schema = await readSchema(schemaPath);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n // Generate files\n const typesContent = emitTypes(schema);\n const clientContent = emitClient(schema);\n const barrelContent = emitBarrel(schema);\n\n // Write files\n const typesPath = join(outputDir, 'types.ts');\n const clientPath = join(outputDir, 'client.ts');\n const barrelPath = join(outputDir, 'index.ts');\n\n await Promise.all([\n writeFile(typesPath, typesContent, 'utf-8'),\n writeFile(clientPath, clientContent, 'utf-8'),\n writeFile(barrelPath, barrelContent, 'utf-8'),\n ]);\n\n // Compute stats\n const recordEntries = Object.entries(schema.records);\n const fieldCount = recordEntries.reduce(\n (sum, [, record]) => sum + Object.keys(record.fields).length,\n 0,\n );\n\n return {\n recordCount: recordEntries.length,\n fieldCount,\n files: [typesPath, clientPath, barrelPath],\n outputDir,\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport type { NormalizedSchema } from '@suiteportal/introspector';\n\n/**\n * Read and parse a schema.json file.\n */\nexport async function readSchema(schemaPath: string): Promise<NormalizedSchema> {\n const raw = await readFile(schemaPath, 'utf-8');\n const schema = JSON.parse(raw) as NormalizedSchema;\n\n if (!schema.records || typeof schema.records !== 'object') {\n throw new Error(`Invalid schema: missing \"records\" in ${schemaPath}`);\n }\n\n return schema;\n}\n","import type { FieldType } from '@suiteportal/introspector';\n\n/**\n * Convert a record ID to PascalCase for use as a TypeScript interface name.\n * Examples:\n * 'customer' → 'Customer'\n * 'salesorder' → 'Salesorder'\n * 'customrecord_mytype' → 'CustomrecordMytype'\n */\nexport function toPascalCase(name: string): string {\n return name\n .split('_')\n .map((part) => (part.length > 0 ? part[0]!.toUpperCase() + part.slice(1).toLowerCase() : ''))\n .join('');\n}\n\n/**\n * Map a normalized FieldType to its TypeScript type representation.\n */\nexport function fieldTypeToTS(fieldType: FieldType): string {\n switch (fieldType) {\n case 'string':\n case 'text':\n case 'richtext':\n case 'email':\n case 'url':\n case 'phone':\n return 'string';\n\n case 'integer':\n case 'float':\n case 'currency':\n case 'percent':\n return 'number';\n\n case 'boolean':\n return 'boolean';\n\n case 'date':\n case 'datetime':\n return 'string'; // SuiteQL returns date strings\n\n case 'select':\n return 'string | number';\n\n case 'multiselect':\n return 'string';\n\n case 'unknown':\n default:\n return 'unknown';\n }\n}\n","import type { NormalizedSchema, RecordDefinition } from '@suiteportal/introspector';\nimport { toPascalCase, fieldTypeToTS } from '../naming.js';\n\n/**\n * Emit a TypeScript interface for a single record.\n */\nfunction emitRecordInterface(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const fieldEntries = Object.entries(record.fields);\n const fieldCount = fieldEntries.length;\n\n const lines: string[] = [];\n lines.push(`/** ${record.label} — ${fieldCount} fields */`);\n lines.push(`export interface ${name} {`);\n\n for (const [fieldId, field] of fieldEntries) {\n const tsType = fieldTypeToTS(field.type);\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}?: ${tsType};`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit the full types.ts file content from a schema.\n */\nexport function emitTypes(schema: NormalizedSchema): string {\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n const recordEntries = Object.entries(schema.records);\n\n for (const [recordId, record] of recordEntries) {\n lines.push(emitRecordInterface(recordId, record));\n lines.push('');\n }\n\n // Export a union type of all record names\n if (recordEntries.length > 0) {\n const names = recordEntries.map(([id]) => `'${id}'`);\n lines.push(`/** All available record type IDs. */`);\n lines.push(`export type RecordTypeId = ${names.join(' | ')};`);\n lines.push('');\n\n // Record type map\n lines.push(`/** Map of record type IDs to their TypeScript interfaces. */`);\n lines.push(`export interface RecordTypeMap {`);\n for (const [recordId] of recordEntries) {\n lines.push(` ${recordId}: ${toPascalCase(recordId)};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type { NormalizedSchema } from '@suiteportal/introspector';\nimport { toPascalCase } from '../naming.js';\n\n/**\n * Emit the client.ts file content — a typed wrapper around the base SuitePortalClient.\n */\nexport function emitClient(schema: NormalizedSchema): string {\n const recordEntries = Object.entries(schema.records);\n const typeImports = recordEntries.map(([id]) => toPascalCase(id));\n\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n `import type { NetSuiteConfig } from '@suiteportal/connector';`,\n `import {`,\n ` SuitePortalClient as BaseClient,`,\n ` type FindManyArgs,`,\n ` type FindFirstArgs,`,\n ` type CountArgs,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n lines.push(`import type { ${typeImports.join(', ')} } from './types.js';`);\n }\n\n lines.push('');\n\n // TypedModelDelegate interface\n lines.push('/** A typed model delegate for a specific record type. */');\n lines.push('export interface TypedModelDelegate<T> {');\n lines.push(' findMany(args?: FindManyArgs): Promise<T[]>;');\n lines.push(' findFirst(args?: FindFirstArgs): Promise<T | null>;');\n lines.push(' count(args?: CountArgs): Promise<number>;');\n lines.push('}');\n lines.push('');\n\n // SuitePortalClient interface\n lines.push('/** Typed SuitePortal client with per-record delegates. */');\n lines.push('export interface SuitePortalClient {');\n\n for (const [recordId] of recordEntries) {\n const typeName = toPascalCase(recordId);\n lines.push(` ${recordId}: TypedModelDelegate<${typeName}>;`);\n }\n\n lines.push(' $queryRaw<T = Record<string, unknown>>(sql: string): Promise<T[]>;');\n lines.push(' $disconnect(): void;');\n lines.push(' $loadSchema(): Promise<void>;');\n lines.push('}');\n lines.push('');\n\n // createClient function\n lines.push('/**');\n lines.push(' * Create a typed SuitePortal client.');\n lines.push(' * Loads schema.json and provides typed access to all record types.');\n lines.push(' */');\n lines.push('export async function createClient(');\n lines.push(' config: NetSuiteConfig,');\n lines.push(' options?: ClientOptions,');\n lines.push('): Promise<SuitePortalClient> {');\n lines.push(' const client = new BaseClient(config, options);');\n lines.push(' await client.$loadSchema();');\n lines.push(' return client as unknown as SuitePortalClient;');\n lines.push('}');\n lines.push('');\n\n // Re-export types for convenience\n lines.push('export type { FindManyArgs, FindFirstArgs, CountArgs } from \\'@suiteportal/client-runtime\\';');\n lines.push('');\n\n return lines.join('\\n');\n}\n","import type { NormalizedSchema } from '@suiteportal/introspector';\nimport { toPascalCase } from '../naming.js';\n\n/**\n * Emit the index.ts barrel export file content.\n */\nexport function emitBarrel(schema: NormalizedSchema): string {\n const recordEntries = Object.entries(schema.records);\n const typeNames = recordEntries.map(([id]) => toPascalCase(id));\n\n const lines: string[] = [\n '// Auto-generated by @suiteportal/generator — DO NOT EDIT',\n `// Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n // Type exports\n if (typeNames.length > 0) {\n lines.push(`export type { ${typeNames.join(', ')}, RecordTypeId, RecordTypeMap } from './types.js';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client.js';`);\n lines.push(`export { createClient } from './client.js';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client.js';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":";AAAA,SAAS,OAAO,iBAAiB;AACjC,SAAS,YAAY;;;ACDrB,SAAS,gBAAgB;AAMzB,eAAsB,WAAW,YAA+C;AAC9E,QAAM,MAAM,MAAM,SAAS,YAAY,OAAO;AAC9C,QAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,MAAI,CAAC,OAAO,WAAW,OAAO,OAAO,YAAY,UAAU;AACzD,UAAM,IAAI,MAAM,wCAAwC,UAAU,EAAE;AAAA,EACtE;AAEA,SAAO;AACT;;;ACNO,SAAS,aAAa,MAAsB;AACjD,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAU,KAAK,SAAS,IAAI,KAAK,CAAC,EAAG,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,IAAI,EAAG,EAC3F,KAAK,EAAE;AACZ;AAKO,SAAS,cAAc,WAA8B;AAC1D,UAAQ,WAAW;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;;;AC9CA,SAAS,oBAAoB,UAAkB,QAAkC;AAC/E,QAAM,OAAO,aAAa,QAAQ;AAClC,QAAM,eAAe,OAAO,QAAQ,OAAO,MAAM;AACjD,QAAM,aAAa,aAAa;AAEhC,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,OAAO,OAAO,KAAK,WAAM,UAAU,YAAY;AAC1D,QAAM,KAAK,oBAAoB,IAAI,IAAI;AAEvC,aAAW,CAAC,SAAS,KAAK,KAAK,cAAc;AAC3C,UAAM,SAAS,cAAc,MAAM,IAAI;AACvC,UAAM,KAAK,SAAS,MAAM,KAAK,KAAK;AACpC,UAAM,KAAK,KAAK,OAAO,MAAM,MAAM,GAAG;AAAA,EACxC;AAEA,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,UAAU,QAAkC;AAC1D,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA,qBAAoB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,IAC5C;AAAA,EACF;AAEA,QAAM,gBAAgB,OAAO,QAAQ,OAAO,OAAO;AAEnD,aAAW,CAAC,UAAU,MAAM,KAAK,eAAe;AAC9C,UAAM,KAAK,oBAAoB,UAAU,MAAM,CAAC;AAChD,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,QAAQ,cAAc,IAAI,CAAC,CAAC,EAAE,MAAM,IAAI,EAAE,GAAG;AACnD,UAAM,KAAK,uCAAuC;AAClD,UAAM,KAAK,8BAA8B,MAAM,KAAK,KAAK,CAAC,GAAG;AAC7D,UAAM,KAAK,EAAE;AAGb,UAAM,KAAK,+DAA+D;AAC1E,UAAM,KAAK,kCAAkC;AAC7C,eAAW,CAAC,QAAQ,KAAK,eAAe;AACtC,YAAM,KAAK,KAAK,QAAQ,KAAK,aAAa,QAAQ,CAAC,GAAG;AAAA,IACxD;AACA,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACtDO,SAAS,WAAW,QAAkC;AAC3D,QAAM,gBAAgB,OAAO,QAAQ,OAAO,OAAO;AACnD,QAAM,cAAc,cAAc,IAAI,CAAC,CAAC,EAAE,MAAM,aAAa,EAAE,CAAC;AAEhE,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA,qBAAoB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,KAAK,iBAAiB,YAAY,KAAK,IAAI,CAAC,uBAAuB;AAAA,EAC3E;AAEA,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,2DAA2D;AACtE,QAAM,KAAK,0CAA0C;AACrD,QAAM,KAAK,gDAAgD;AAC3D,QAAM,KAAK,uDAAuD;AAClE,QAAM,KAAK,6CAA6C;AACxD,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,4DAA4D;AACvE,QAAM,KAAK,sCAAsC;AAEjD,aAAW,CAAC,QAAQ,KAAK,eAAe;AACtC,UAAM,WAAW,aAAa,QAAQ;AACtC,UAAM,KAAK,KAAK,QAAQ,wBAAwB,QAAQ,IAAI;AAAA,EAC9D;AAEA,QAAM,KAAK,sEAAsE;AACjF,QAAM,KAAK,wBAAwB;AACnC,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,uCAAuC;AAClD,QAAM,KAAK,qEAAqE;AAChF,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,qCAAqC;AAChD,QAAM,KAAK,2BAA2B;AACtC,QAAM,KAAK,4BAA4B;AACvC,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,mDAAmD;AAC9D,QAAM,KAAK,+BAA+B;AAC1C,QAAM,KAAK,kDAAkD;AAC7D,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,4FAA8F;AACzG,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACpEO,SAAS,WAAW,QAAkC;AAC3D,QAAM,gBAAgB,OAAO,QAAQ,OAAO,OAAO;AACnD,QAAM,YAAY,cAAc,IAAI,CAAC,CAAC,EAAE,MAAM,aAAa,EAAE,CAAC;AAE9D,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA,qBAAoB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,IAC5C;AAAA,EACF;AAGA,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,KAAK,iBAAiB,UAAU,KAAK,IAAI,CAAC,oDAAoD;AAAA,EACtG;AAGA,QAAM,KAAK,2EAA2E;AACtF,QAAM,KAAK,6CAA6C;AACxD,QAAM,KAAK,4EAA4E;AACvF,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;ALpBA,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAQ3B,eAAsB,SAAS,SAAoD;AACjF,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,YAAY,SAAS,aAAa;AAGxC,QAAM,SAAS,MAAM,WAAW,UAAU;AAG1C,QAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAG1C,QAAM,eAAe,UAAU,MAAM;AACrC,QAAM,gBAAgB,WAAW,MAAM;AACvC,QAAM,gBAAgB,WAAW,MAAM;AAGvC,QAAM,YAAY,KAAK,WAAW,UAAU;AAC5C,QAAM,aAAa,KAAK,WAAW,WAAW;AAC9C,QAAM,aAAa,KAAK,WAAW,UAAU;AAE7C,QAAM,QAAQ,IAAI;AAAA,IAChB,UAAU,WAAW,cAAc,OAAO;AAAA,IAC1C,UAAU,YAAY,eAAe,OAAO;AAAA,IAC5C,UAAU,YAAY,eAAe,OAAO;AAAA,EAC9C,CAAC;AAGD,QAAM,gBAAgB,OAAO,QAAQ,OAAO,OAAO;AACnD,QAAM,aAAa,cAAc;AAAA,IAC/B,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,KAAK,OAAO,MAAM,EAAE;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa,cAAc;AAAA,IAC3B;AAAA,IACA,OAAO,CAAC,WAAW,YAAY,UAAU;AAAA,IACzC;AAAA,EACF;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@suiteportal/generator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Code generator for SuitePortal NetSuite ORM — emits TypeScript types from schema",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"clean": "rm -rf dist"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@suiteportal/introspector": "^0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Trey Hulse",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/treyhulse/netsuite-orm",
|
|
29
|
+
"directory": "packages/generator"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20.0.0"
|
|
36
|
+
},
|
|
37
|
+
"keywords": ["netsuite", "codegen", "typescript", "types", "generator"]
|
|
38
|
+
}
|