@suiteportal/generator 0.2.1 → 0.2.3

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/dist/index.cjs CHANGED
@@ -95,6 +95,22 @@ function emitRecordInterface(recordId, record) {
95
95
  lines.push("}");
96
96
  return lines.join("\n");
97
97
  }
98
+ function emitSublistItem(recordId, sublistId, sublist) {
99
+ const recordName = toPascalCase(recordId);
100
+ const sublistName = toPascalCase(sublistId);
101
+ const interfaceName = `${recordName}${sublistName}Item`;
102
+ const fieldEntries = Object.entries(sublist.fields);
103
+ const lines = [];
104
+ lines.push(`/** ${sublist.label} line item on ${recordName}. */`);
105
+ lines.push(`export interface ${interfaceName} {`);
106
+ for (const [fieldId, field] of fieldEntries) {
107
+ const tsType = fieldTypeToTS(field.type);
108
+ lines.push(` /** ${field.label} */`);
109
+ lines.push(` ${fieldId}?: ${tsType};`);
110
+ }
111
+ lines.push("}");
112
+ return lines.join("\n");
113
+ }
98
114
  function emitCreateInput(recordId, record) {
99
115
  const name = toPascalCase(recordId);
100
116
  const lines = [];
@@ -107,6 +123,12 @@ function emitCreateInput(recordId, record) {
107
123
  lines.push(` /** ${field.label} */`);
108
124
  lines.push(` ${fieldId}${optional}: ${tsType};`);
109
125
  }
126
+ const sublistEntries = Object.entries(record.sublists ?? {});
127
+ for (const [sublistId] of sublistEntries) {
128
+ const itemType = `${name}${toPascalCase(sublistId)}Item`;
129
+ lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);
130
+ lines.push(` ${sublistId}?: { items: ${itemType}[] };`);
131
+ }
110
132
  lines.push("}");
111
133
  return lines.join("\n");
112
134
  }
@@ -121,6 +143,12 @@ function emitUpdateInput(recordId, record) {
121
143
  lines.push(` /** ${field.label} */`);
122
144
  lines.push(` ${fieldId}?: ${tsType};`);
123
145
  }
146
+ const sublistEntries = Object.entries(record.sublists ?? {});
147
+ for (const [sublistId] of sublistEntries) {
148
+ const itemType = `${name}${toPascalCase(sublistId)}Item`;
149
+ lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);
150
+ lines.push(` ${sublistId}?: { items: ${itemType}[] };`);
151
+ }
124
152
  lines.push("}");
125
153
  return lines.join("\n");
126
154
  }
@@ -134,6 +162,11 @@ function emitTypes(schema) {
134
162
  for (const [recordId, record] of recordEntries) {
135
163
  lines.push(emitRecordInterface(recordId, record));
136
164
  lines.push("");
165
+ const sublistEntries = Object.entries(record.sublists ?? {});
166
+ for (const [sublistId, sublist] of sublistEntries) {
167
+ lines.push(emitSublistItem(recordId, sublistId, sublist));
168
+ lines.push("");
169
+ }
137
170
  lines.push(emitCreateInput(recordId, record));
138
171
  lines.push("");
139
172
  lines.push(emitUpdateInput(recordId, record));
@@ -172,6 +205,7 @@ function emitClient(schema) {
172
205
  ` type CreateArgs,`,
173
206
  ` type UpdateArgs,`,
174
207
  ` type DeleteArgs,`,
208
+ ` type UpsertArgs,`,
175
209
  ` type IncludeInput,`,
176
210
  ` type ClientOptions,`,
177
211
  `} from '@suiteportal/client-runtime';`
@@ -192,6 +226,7 @@ function emitClient(schema) {
192
226
  lines.push(" create(args: CreateArgs<TCreate>): Promise<T>;");
193
227
  lines.push(" update(args: UpdateArgs<TUpdate>): Promise<T>;");
194
228
  lines.push(" delete(args: DeleteArgs): Promise<void>;");
229
+ lines.push(" upsert(args: UpsertArgs<TCreate>): Promise<T>;");
195
230
  lines.push("}");
196
231
  lines.push("");
197
232
  lines.push("/** Typed SuitePortal client with per-record delegates. */");
@@ -218,7 +253,7 @@ function emitClient(schema) {
218
253
  lines.push(" return client as unknown as SuitePortalClient;");
219
254
  lines.push("}");
220
255
  lines.push("");
221
- lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from '@suiteportal/client-runtime';");
256
+ lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, UpsertArgs, IncludeInput } from '@suiteportal/client-runtime';");
222
257
  lines.push("");
223
258
  return lines.join("\n");
224
259
  }
@@ -1 +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 a CreateInput interface for a record.\n * Excludes readOnly fields and `id`. Required writable fields are non-optional.\n */\nfunction emitCreateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for creating a ${record.label}. */`);\n lines.push(`export interface ${name}CreateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n const optional = field.required ? '' : '?';\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}${optional}: ${tsType};`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit an UpdateInput interface for a record.\n * Excludes readOnly fields and `id`. All fields are optional.\n */\nfunction emitUpdateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for updating a ${record.label}. */`);\n lines.push(`export interface ${name}UpdateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\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 lines.push(emitCreateInput(recordId, record));\n lines.push('');\n lines.push(emitUpdateInput(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 CreateArgs,`,\n ` type UpdateArgs,`,\n ` type DeleteArgs,`,\n ` type IncludeInput,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n const inputImports = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`import type { ${[...typeImports, ...inputImports].join(', ')} } from './types';`);\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, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>> {');\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(' create(args: CreateArgs<TCreate>): Promise<T>;');\n lines.push(' update(args: UpdateArgs<TUpdate>): Promise<T>;');\n lines.push(' delete(args: DeleteArgs): Promise<void>;');\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}, ${typeName}CreateInput, ${typeName}UpdateInput>;`);\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, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } 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 const inputTypes = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`export type { ${[...typeNames, ...inputTypes].join(', ')}, RecordTypeId, RecordTypeMap } from './types';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);\n lines.push(`export { createClient } from './client';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["import_promises"]}
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, SublistDefinition } 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 a TypeScript interface for a single sublist item.\n */\nfunction emitSublistItem(recordId: string, sublistId: string, sublist: SublistDefinition): string {\n const recordName = toPascalCase(recordId);\n const sublistName = toPascalCase(sublistId);\n const interfaceName = `${recordName}${sublistName}Item`;\n const fieldEntries = Object.entries(sublist.fields);\n\n const lines: string[] = [];\n lines.push(`/** ${sublist.label} line item on ${recordName}. */`);\n lines.push(`export interface ${interfaceName} {`);\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 a CreateInput interface for a record.\n * Excludes readOnly fields and `id`. Required writable fields are non-optional.\n */\nfunction emitCreateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for creating a ${record.label}. */`);\n lines.push(`export interface ${name}CreateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n const optional = field.required ? '' : '?';\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}${optional}: ${tsType};`);\n }\n\n // Sublist fields\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId] of sublistEntries) {\n const itemType = `${name}${toPascalCase(sublistId)}Item`;\n lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);\n lines.push(` ${sublistId}?: { items: ${itemType}[] };`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit an UpdateInput interface for a record.\n * Excludes readOnly fields and `id`. All fields are optional.\n */\nfunction emitUpdateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for updating a ${record.label}. */`);\n lines.push(`export interface ${name}UpdateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}?: ${tsType};`);\n }\n\n // Sublist fields\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId] of sublistEntries) {\n const itemType = `${name}${toPascalCase(sublistId)}Item`;\n lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);\n lines.push(` ${sublistId}?: { items: ${itemType}[] };`);\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 // Emit sublist item interfaces before Create/UpdateInput (they reference the item types)\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId, sublist] of sublistEntries) {\n lines.push(emitSublistItem(recordId, sublistId, sublist));\n lines.push('');\n }\n\n lines.push(emitCreateInput(recordId, record));\n lines.push('');\n lines.push(emitUpdateInput(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 CreateArgs,`,\n ` type UpdateArgs,`,\n ` type DeleteArgs,`,\n ` type UpsertArgs,`,\n ` type IncludeInput,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n const inputImports = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`import type { ${[...typeImports, ...inputImports].join(', ')} } from './types';`);\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, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>> {');\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(' create(args: CreateArgs<TCreate>): Promise<T>;');\n lines.push(' update(args: UpdateArgs<TUpdate>): Promise<T>;');\n lines.push(' delete(args: DeleteArgs): Promise<void>;');\n lines.push(' upsert(args: UpsertArgs<TCreate>): Promise<T>;');\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}, ${typeName}CreateInput, ${typeName}UpdateInput>;`);\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, CreateArgs, UpdateArgs, DeleteArgs, UpsertArgs, IncludeInput } 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 const inputTypes = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`export type { ${[...typeNames, ...inputTypes].join(', ')}, RecordTypeId, RecordTypeMap } from './types';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);\n lines.push(`export { createClient } from './client';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["import_promises"]}
package/dist/index.js CHANGED
@@ -63,6 +63,22 @@ function emitRecordInterface(recordId, record) {
63
63
  lines.push("}");
64
64
  return lines.join("\n");
65
65
  }
66
+ function emitSublistItem(recordId, sublistId, sublist) {
67
+ const recordName = toPascalCase(recordId);
68
+ const sublistName = toPascalCase(sublistId);
69
+ const interfaceName = `${recordName}${sublistName}Item`;
70
+ const fieldEntries = Object.entries(sublist.fields);
71
+ const lines = [];
72
+ lines.push(`/** ${sublist.label} line item on ${recordName}. */`);
73
+ lines.push(`export interface ${interfaceName} {`);
74
+ for (const [fieldId, field] of fieldEntries) {
75
+ const tsType = fieldTypeToTS(field.type);
76
+ lines.push(` /** ${field.label} */`);
77
+ lines.push(` ${fieldId}?: ${tsType};`);
78
+ }
79
+ lines.push("}");
80
+ return lines.join("\n");
81
+ }
66
82
  function emitCreateInput(recordId, record) {
67
83
  const name = toPascalCase(recordId);
68
84
  const lines = [];
@@ -75,6 +91,12 @@ function emitCreateInput(recordId, record) {
75
91
  lines.push(` /** ${field.label} */`);
76
92
  lines.push(` ${fieldId}${optional}: ${tsType};`);
77
93
  }
94
+ const sublistEntries = Object.entries(record.sublists ?? {});
95
+ for (const [sublistId] of sublistEntries) {
96
+ const itemType = `${name}${toPascalCase(sublistId)}Item`;
97
+ lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);
98
+ lines.push(` ${sublistId}?: { items: ${itemType}[] };`);
99
+ }
78
100
  lines.push("}");
79
101
  return lines.join("\n");
80
102
  }
@@ -89,6 +111,12 @@ function emitUpdateInput(recordId, record) {
89
111
  lines.push(` /** ${field.label} */`);
90
112
  lines.push(` ${fieldId}?: ${tsType};`);
91
113
  }
114
+ const sublistEntries = Object.entries(record.sublists ?? {});
115
+ for (const [sublistId] of sublistEntries) {
116
+ const itemType = `${name}${toPascalCase(sublistId)}Item`;
117
+ lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);
118
+ lines.push(` ${sublistId}?: { items: ${itemType}[] };`);
119
+ }
92
120
  lines.push("}");
93
121
  return lines.join("\n");
94
122
  }
@@ -102,6 +130,11 @@ function emitTypes(schema) {
102
130
  for (const [recordId, record] of recordEntries) {
103
131
  lines.push(emitRecordInterface(recordId, record));
104
132
  lines.push("");
133
+ const sublistEntries = Object.entries(record.sublists ?? {});
134
+ for (const [sublistId, sublist] of sublistEntries) {
135
+ lines.push(emitSublistItem(recordId, sublistId, sublist));
136
+ lines.push("");
137
+ }
105
138
  lines.push(emitCreateInput(recordId, record));
106
139
  lines.push("");
107
140
  lines.push(emitUpdateInput(recordId, record));
@@ -140,6 +173,7 @@ function emitClient(schema) {
140
173
  ` type CreateArgs,`,
141
174
  ` type UpdateArgs,`,
142
175
  ` type DeleteArgs,`,
176
+ ` type UpsertArgs,`,
143
177
  ` type IncludeInput,`,
144
178
  ` type ClientOptions,`,
145
179
  `} from '@suiteportal/client-runtime';`
@@ -160,6 +194,7 @@ function emitClient(schema) {
160
194
  lines.push(" create(args: CreateArgs<TCreate>): Promise<T>;");
161
195
  lines.push(" update(args: UpdateArgs<TUpdate>): Promise<T>;");
162
196
  lines.push(" delete(args: DeleteArgs): Promise<void>;");
197
+ lines.push(" upsert(args: UpsertArgs<TCreate>): Promise<T>;");
163
198
  lines.push("}");
164
199
  lines.push("");
165
200
  lines.push("/** Typed SuitePortal client with per-record delegates. */");
@@ -186,7 +221,7 @@ function emitClient(schema) {
186
221
  lines.push(" return client as unknown as SuitePortalClient;");
187
222
  lines.push("}");
188
223
  lines.push("");
189
- lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from '@suiteportal/client-runtime';");
224
+ lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, UpsertArgs, IncludeInput } from '@suiteportal/client-runtime';");
190
225
  lines.push("");
191
226
  return lines.join("\n");
192
227
  }
package/dist/index.js.map CHANGED
@@ -1 +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 a CreateInput interface for a record.\n * Excludes readOnly fields and `id`. Required writable fields are non-optional.\n */\nfunction emitCreateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for creating a ${record.label}. */`);\n lines.push(`export interface ${name}CreateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n const optional = field.required ? '' : '?';\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}${optional}: ${tsType};`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit an UpdateInput interface for a record.\n * Excludes readOnly fields and `id`. All fields are optional.\n */\nfunction emitUpdateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for updating a ${record.label}. */`);\n lines.push(`export interface ${name}UpdateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\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 lines.push(emitCreateInput(recordId, record));\n lines.push('');\n lines.push(emitUpdateInput(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 CreateArgs,`,\n ` type UpdateArgs,`,\n ` type DeleteArgs,`,\n ` type IncludeInput,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n const inputImports = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`import type { ${[...typeImports, ...inputImports].join(', ')} } from './types';`);\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, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>> {');\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(' create(args: CreateArgs<TCreate>): Promise<T>;');\n lines.push(' update(args: UpdateArgs<TUpdate>): Promise<T>;');\n lines.push(' delete(args: DeleteArgs): Promise<void>;');\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}, ${typeName}CreateInput, ${typeName}UpdateInput>;`);\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, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } 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 const inputTypes = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`export type { ${[...typeNames, ...inputTypes].join(', ')}, RecordTypeId, RecordTypeMap } from './types';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);\n lines.push(`export { createClient } from './client';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":[]}
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, SublistDefinition } 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 a TypeScript interface for a single sublist item.\n */\nfunction emitSublistItem(recordId: string, sublistId: string, sublist: SublistDefinition): string {\n const recordName = toPascalCase(recordId);\n const sublistName = toPascalCase(sublistId);\n const interfaceName = `${recordName}${sublistName}Item`;\n const fieldEntries = Object.entries(sublist.fields);\n\n const lines: string[] = [];\n lines.push(`/** ${sublist.label} line item on ${recordName}. */`);\n lines.push(`export interface ${interfaceName} {`);\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 a CreateInput interface for a record.\n * Excludes readOnly fields and `id`. Required writable fields are non-optional.\n */\nfunction emitCreateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for creating a ${record.label}. */`);\n lines.push(`export interface ${name}CreateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n const optional = field.required ? '' : '?';\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}${optional}: ${tsType};`);\n }\n\n // Sublist fields\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId] of sublistEntries) {\n const itemType = `${name}${toPascalCase(sublistId)}Item`;\n lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);\n lines.push(` ${sublistId}?: { items: ${itemType}[] };`);\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Emit an UpdateInput interface for a record.\n * Excludes readOnly fields and `id`. All fields are optional.\n */\nfunction emitUpdateInput(recordId: string, record: RecordDefinition): string {\n const name = toPascalCase(recordId);\n const lines: string[] = [];\n lines.push(`/** Fields for updating a ${record.label}. */`);\n lines.push(`export interface ${name}UpdateInput {`);\n\n for (const [fieldId, field] of Object.entries(record.fields)) {\n if (fieldId === 'id' || field.readOnly) continue;\n const tsType = fieldTypeToTS(field.type);\n lines.push(` /** ${field.label} */`);\n lines.push(` ${fieldId}?: ${tsType};`);\n }\n\n // Sublist fields\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId] of sublistEntries) {\n const itemType = `${name}${toPascalCase(sublistId)}Item`;\n lines.push(` /** ${toPascalCase(sublistId)} sublist. */`);\n lines.push(` ${sublistId}?: { items: ${itemType}[] };`);\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 // Emit sublist item interfaces before Create/UpdateInput (they reference the item types)\n const sublistEntries = Object.entries(record.sublists ?? {});\n for (const [sublistId, sublist] of sublistEntries) {\n lines.push(emitSublistItem(recordId, sublistId, sublist));\n lines.push('');\n }\n\n lines.push(emitCreateInput(recordId, record));\n lines.push('');\n lines.push(emitUpdateInput(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 CreateArgs,`,\n ` type UpdateArgs,`,\n ` type DeleteArgs,`,\n ` type UpsertArgs,`,\n ` type IncludeInput,`,\n ` type ClientOptions,`,\n `} from '@suiteportal/client-runtime';`,\n ];\n\n if (typeImports.length > 0) {\n const inputImports = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`import type { ${[...typeImports, ...inputImports].join(', ')} } from './types';`);\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, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>> {');\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(' create(args: CreateArgs<TCreate>): Promise<T>;');\n lines.push(' update(args: UpdateArgs<TUpdate>): Promise<T>;');\n lines.push(' delete(args: DeleteArgs): Promise<void>;');\n lines.push(' upsert(args: UpsertArgs<TCreate>): Promise<T>;');\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}, ${typeName}CreateInput, ${typeName}UpdateInput>;`);\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, CreateArgs, UpdateArgs, DeleteArgs, UpsertArgs, IncludeInput } 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 const inputTypes = recordEntries.flatMap(([id]) => {\n const name = toPascalCase(id);\n return [`${name}CreateInput`, `${name}UpdateInput`];\n });\n lines.push(`export type { ${[...typeNames, ...inputTypes].join(', ')}, RecordTypeId, RecordTypeMap } from './types';`);\n }\n\n // Client exports\n lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);\n lines.push(`export { createClient } from './client';`);\n lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);\n lines.push('');\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suiteportal/generator",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Code generator for SuitePortal NetSuite ORM — emits typed queries, mutations, and includes from schema",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,7 +21,7 @@
21
21
  "clean": "rm -rf dist"
22
22
  },
23
23
  "dependencies": {
24
- "@suiteportal/introspector": "^0.1.0"
24
+ "@suiteportal/introspector": "^0.1.2"
25
25
  },
26
26
  "license": "MIT",
27
27
  "author": "Trey Hulse",