@suiteportal/generator 0.1.1 → 0.2.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/dist/index.cjs CHANGED
@@ -136,6 +136,10 @@ function emitClient(schema) {
136
136
  ` type FindManyArgs,`,
137
137
  ` type FindFirstArgs,`,
138
138
  ` type CountArgs,`,
139
+ ` type CreateArgs,`,
140
+ ` type UpdateArgs,`,
141
+ ` type DeleteArgs,`,
142
+ ` type IncludeInput,`,
139
143
  ` type ClientOptions,`,
140
144
  `} from '@suiteportal/client-runtime';`
141
145
  ];
@@ -148,6 +152,9 @@ function emitClient(schema) {
148
152
  lines.push(" findMany(args?: FindManyArgs): Promise<T[]>;");
149
153
  lines.push(" findFirst(args?: FindFirstArgs): Promise<T | null>;");
150
154
  lines.push(" count(args?: CountArgs): Promise<number>;");
155
+ lines.push(" create(args: CreateArgs): Promise<T>;");
156
+ lines.push(" update(args: UpdateArgs): Promise<T>;");
157
+ lines.push(" delete(args: DeleteArgs): Promise<void>;");
151
158
  lines.push("}");
152
159
  lines.push("");
153
160
  lines.push("/** Typed SuitePortal client with per-record delegates. */");
@@ -174,7 +181,7 @@ function emitClient(schema) {
174
181
  lines.push(" return client as unknown as SuitePortalClient;");
175
182
  lines.push("}");
176
183
  lines.push("");
177
- lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs } from '@suiteportal/client-runtime';");
184
+ lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from '@suiteportal/client-runtime';");
178
185
  lines.push("");
179
186
  return lines.join("\n");
180
187
  }
@@ -193,7 +200,7 @@ function emitBarrel(schema) {
193
200
  }
194
201
  lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);
195
202
  lines.push(`export { createClient } from './client';`);
196
- lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client';`);
203
+ lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);
197
204
  lines.push("");
198
205
  return lines.join("\n");
199
206
  }
@@ -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 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';`);\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';`);\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 } 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 } 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 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 lines.push(`import type { ${typeImports.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> {');\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): Promise<T>;');\n lines.push(' update(args: UpdateArgs): 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}>;`);\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 lines.push(`export type { ${typeNames.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
@@ -104,6 +104,10 @@ function emitClient(schema) {
104
104
  ` type FindManyArgs,`,
105
105
  ` type FindFirstArgs,`,
106
106
  ` type CountArgs,`,
107
+ ` type CreateArgs,`,
108
+ ` type UpdateArgs,`,
109
+ ` type DeleteArgs,`,
110
+ ` type IncludeInput,`,
107
111
  ` type ClientOptions,`,
108
112
  `} from '@suiteportal/client-runtime';`
109
113
  ];
@@ -116,6 +120,9 @@ function emitClient(schema) {
116
120
  lines.push(" findMany(args?: FindManyArgs): Promise<T[]>;");
117
121
  lines.push(" findFirst(args?: FindFirstArgs): Promise<T | null>;");
118
122
  lines.push(" count(args?: CountArgs): Promise<number>;");
123
+ lines.push(" create(args: CreateArgs): Promise<T>;");
124
+ lines.push(" update(args: UpdateArgs): Promise<T>;");
125
+ lines.push(" delete(args: DeleteArgs): Promise<void>;");
119
126
  lines.push("}");
120
127
  lines.push("");
121
128
  lines.push("/** Typed SuitePortal client with per-record delegates. */");
@@ -142,7 +149,7 @@ function emitClient(schema) {
142
149
  lines.push(" return client as unknown as SuitePortalClient;");
143
150
  lines.push("}");
144
151
  lines.push("");
145
- lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs } from '@suiteportal/client-runtime';");
152
+ lines.push("export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from '@suiteportal/client-runtime';");
146
153
  lines.push("");
147
154
  return lines.join("\n");
148
155
  }
@@ -161,7 +168,7 @@ function emitBarrel(schema) {
161
168
  }
162
169
  lines.push(`export type { SuitePortalClient, TypedModelDelegate } from './client';`);
163
170
  lines.push(`export { createClient } from './client';`);
164
- lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs } from './client';`);
171
+ lines.push(`export type { FindManyArgs, FindFirstArgs, CountArgs, CreateArgs, UpdateArgs, DeleteArgs, IncludeInput } from './client';`);
165
172
  lines.push("");
166
173
  return lines.join("\n");
167
174
  }
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 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';`);\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';`);\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 } 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 } 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 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 lines.push(`import type { ${typeImports.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> {');\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): Promise<T>;');\n lines.push(' update(args: UpdateArgs): 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}>;`);\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 lines.push(`export type { ${typeNames.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,7 +1,7 @@
1
1
  {
2
2
  "name": "@suiteportal/generator",
3
- "version": "0.1.1",
4
- "description": "Code generator for SuitePortal NetSuite ORM — emits TypeScript types from schema",
3
+ "version": "0.2.0",
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",
7
7
  "module": "./dist/index.js",