@an5/orm 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +174 -175
  2. package/dist/an5Metadata.js +64 -0
  3. package/dist/an5Orm.d.ts +92 -3
  4. package/dist/an5Orm.js +697 -206
  5. package/dist/config.d.ts +9 -1
  6. package/dist/config.js +13 -18
  7. package/dist/errors.d.ts +1 -1
  8. package/dist/errors.js +1 -1
  9. package/dist/generator/src/api.d.ts +35 -0
  10. package/dist/generator/src/api.js +58 -0
  11. package/dist/generator/src/code-generator.d.ts +14 -13
  12. package/dist/generator/src/code-generator.js +249 -225
  13. package/dist/generator/src/config.d.ts +162 -0
  14. package/dist/generator/src/config.js +354 -0
  15. package/dist/generator/src/dialect.d.ts +88 -0
  16. package/dist/generator/src/dialect.js +318 -0
  17. package/dist/generator/src/dotnet-generator.d.ts +21 -11
  18. package/dist/generator/src/dotnet-generator.js +1053 -546
  19. package/dist/generator/src/field-types.d.ts +96 -0
  20. package/dist/generator/src/field-types.js +433 -0
  21. package/dist/generator/src/golang-generator.d.ts +36 -0
  22. package/dist/generator/src/golang-generator.js +1229 -0
  23. package/dist/generator/src/index.d.ts +1 -1
  24. package/dist/generator/src/index.js +137 -88
  25. package/dist/generator/src/metadata-generator.d.ts +11 -8
  26. package/dist/generator/src/metadata-generator.js +105 -90
  27. package/dist/generator/src/parser.d.ts +37 -11
  28. package/dist/generator/src/parser.js +208 -206
  29. package/dist/generator/src/push-apply.d.ts +37 -0
  30. package/dist/generator/src/push-apply.js +109 -0
  31. package/dist/generator/src/push-schema.d.ts +93 -0
  32. package/dist/generator/src/push-schema.js +189 -0
  33. package/dist/generator/src/python-generator.d.ts +37 -9
  34. package/dist/generator/src/python-generator.js +428 -105
  35. package/dist/generator/src/rust-generator.d.ts +38 -0
  36. package/dist/generator/src/rust-generator.js +971 -0
  37. package/dist/generator/src/suggest.d.ts +17 -0
  38. package/dist/generator/src/suggest.js +45 -0
  39. package/dist/generator/src/type-kinds.d.ts +27 -0
  40. package/dist/generator/src/type-kinds.js +72 -0
  41. package/dist/generator/src/types.d.ts +60 -27
  42. package/dist/generator/src/types.js +41 -2
  43. package/dist/index.d.ts +3 -2
  44. package/dist/index.js +19 -8
  45. package/dist/logger.js +1 -1
  46. package/dist/migration-core.d.ts +102 -0
  47. package/dist/migration-core.js +731 -0
  48. package/dist/orm.d.ts +147 -0
  49. package/dist/orm.js +1654 -0
  50. package/dist/provider-support.d.ts +27 -0
  51. package/dist/provider-support.js +50 -0
  52. package/dist/scripts/release-cli.d.ts +2 -2
  53. package/dist/scripts/release-cli.js +115 -115
  54. package/dist/sql-utils.d.ts +3 -1
  55. package/dist/sql-utils.js +94 -24
  56. package/generator/src/api.ts +45 -0
  57. package/generator/src/code-generator.ts +259 -230
  58. package/generator/src/config.ts +496 -0
  59. package/generator/src/dialect.ts +415 -0
  60. package/generator/src/dotnet-generator.ts +1071 -544
  61. package/generator/src/field-types.ts +473 -0
  62. package/generator/src/golang-generator.ts +1267 -0
  63. package/generator/src/index.ts +146 -116
  64. package/generator/src/metadata-generator.ts +116 -101
  65. package/generator/src/parser.ts +234 -202
  66. package/generator/src/push-apply.ts +148 -0
  67. package/generator/src/push-schema.ts +250 -0
  68. package/generator/src/python-generator.ts +480 -114
  69. package/generator/src/rust-generator.ts +974 -0
  70. package/generator/src/suggest.ts +41 -0
  71. package/generator/src/type-kinds.ts +78 -0
  72. package/generator/src/types.ts +77 -29
  73. package/package.json +32 -6
@@ -1 +1 @@
1
- export {};
1
+ export {};
@@ -1,88 +1,137 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const path_1 = __importDefault(require("path"));
7
- const parser_1 = require("./parser");
8
- const code_generator_1 = require("./code-generator");
9
- const metadata_generator_1 = require("./metadata-generator");
10
- const python_generator_1 = require("./python-generator");
11
- const dotnet_generator_1 = require("./dotnet-generator");
12
- const fs_1 = __importDefault(require("fs"));
13
- function clearGeneratedFiles(outputDir, extension) {
14
- if (!fs_1.default.existsSync(outputDir)) {
15
- fs_1.default.mkdirSync(outputDir, { recursive: true });
16
- return;
17
- }
18
- for (const entry of fs_1.default.readdirSync(outputDir)) {
19
- const fullPath = path_1.default.join(outputDir, entry);
20
- const stat = fs_1.default.statSync(fullPath);
21
- if (stat.isDirectory())
22
- continue;
23
- if (entry.endsWith(extension)) {
24
- fs_1.default.unlinkSync(fullPath);
25
- }
26
- }
27
- }
28
- async function main() {
29
- const rootDir = process.cwd();
30
- let config = {};
31
- try {
32
- let configPath = path_1.default.join(rootDir, 'an5Orm.config.js');
33
- if (!fs_1.default.existsSync(configPath)) {
34
- configPath = path_1.default.join(rootDir, 'an5Orm.config.cjs');
35
- }
36
- if (fs_1.default.existsSync(configPath)) {
37
- config = require(configPath);
38
- }
39
- }
40
- catch (err) {
41
- console.warn('⚠️ Could not load an5Orm.config.js/.cjs, using defaults.', err);
42
- }
43
- const schemaDir = path_1.default.resolve(rootDir, config.schemaDir || 'an5Schema');
44
- const outputTypesDir = path_1.default.resolve(rootDir, config.outputs?.typescript?.outputDir || 'an5Client/typescript');
45
- const outputMetadataPath = path_1.default.resolve(rootDir, config.outputs?.typescript?.metadataFile || 'an5Client/typescript/an5Metadata.ts');
46
- const outputPythonMetadataPath = path_1.default.resolve(rootDir, config.outputs?.python?.metadataFile || 'an5Client/python/an5_metadata.py');
47
- const outputDotnetDir = path_1.default.resolve(rootDir, config.outputs?.dotnet?.outputDir || 'an5Client/dotnet');
48
- console.log('🚀 Starting ORM generation...');
49
- try {
50
- clearGeneratedFiles(outputTypesDir, '.ts');
51
- clearGeneratedFiles(outputDotnetDir, '.cs');
52
- if (fs_1.default.existsSync(outputMetadataPath)) {
53
- fs_1.default.unlinkSync(outputMetadataPath);
54
- }
55
- if (fs_1.default.existsSync(outputPythonMetadataPath)) {
56
- fs_1.default.unlinkSync(outputPythonMetadataPath);
57
- }
58
- const parser = new parser_1.SchemaParser(schemaDir);
59
- const models = await parser.parse();
60
- console.log(`📦 Parsed ${models.length} models from schema.`);
61
- const codeGen = new code_generator_1.CodeGenerator(outputTypesDir);
62
- codeGen.generate(models);
63
- console.log(`✨ Generated modular types in ${outputTypesDir}`);
64
- const metadataDir = path_1.default.dirname(outputMetadataPath);
65
- if (!fs_1.default.existsSync(metadataDir)) {
66
- fs_1.default.mkdirSync(metadataDir, { recursive: true });
67
- }
68
- const metadataGen = new metadata_generator_1.MetadataGenerator(outputMetadataPath);
69
- metadataGen.generate(models);
70
- console.log(`✨ Generated metadata in ${outputMetadataPath}`);
71
- const pythonDir = path_1.default.dirname(outputPythonMetadataPath);
72
- if (!fs_1.default.existsSync(pythonDir)) {
73
- fs_1.default.mkdirSync(pythonDir, { recursive: true });
74
- }
75
- const pythonGen = new python_generator_1.PythonGenerator(outputPythonMetadataPath);
76
- pythonGen.generate(models);
77
- console.log(`✨ Generated Python metadata in ${outputPythonMetadataPath}`);
78
- const dotnetGen = new dotnet_generator_1.DotnetGenerator(outputDotnetDir);
79
- dotnetGen.generate(models);
80
- console.log(`✨ Generated .NET models in ${outputDotnetDir}`);
81
- console.log('✅ ORM generation completed successfully.');
82
- }
83
- catch (error) {
84
- console.error('❌ ORM generation failed:', error);
85
- process.exit(1);
86
- }
87
- }
88
- main();
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const config_1 = require("./config");
8
+ const field_types_1 = require("./field-types");
9
+ const parser_1 = require("./parser");
10
+ const code_generator_1 = require("./code-generator");
11
+ const metadata_generator_1 = require("./metadata-generator");
12
+ const python_generator_1 = require("./python-generator");
13
+ const dotnet_generator_1 = require("./dotnet-generator");
14
+ const golang_generator_1 = require("./golang-generator");
15
+ const rust_generator_1 = require("./rust-generator");
16
+ const fs_1 = __importDefault(require("fs"));
17
+ function clearGeneratedFiles(outputDir, extension) {
18
+ if (!fs_1.default.existsSync(outputDir)) {
19
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
20
+ return;
21
+ }
22
+ for (const entry of fs_1.default.readdirSync(outputDir)) {
23
+ const fullPath = path_1.default.join(outputDir, entry);
24
+ const stat = fs_1.default.statSync(fullPath);
25
+ if (stat.isDirectory())
26
+ continue;
27
+ if (entry.endsWith(extension)) {
28
+ fs_1.default.unlinkSync(fullPath);
29
+ }
30
+ }
31
+ }
32
+ function clearGeneratedPythonFiles(outputDir) {
33
+ if (!fs_1.default.existsSync(outputDir)) {
34
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
35
+ return;
36
+ }
37
+ // Delete generated .py files but preserve hand-maintained adapter.
38
+ const preserve = new Set(['an5_adapter.py']);
39
+ for (const entry of fs_1.default.readdirSync(outputDir)) {
40
+ const fullPath = path_1.default.join(outputDir, entry);
41
+ const stat = fs_1.default.statSync(fullPath);
42
+ if (stat.isDirectory())
43
+ continue;
44
+ if (entry.endsWith('.py') && !preserve.has(entry)) {
45
+ fs_1.default.unlinkSync(fullPath);
46
+ }
47
+ }
48
+ }
49
+ async function main() {
50
+ // Loaded through the validating loader, so a mistyped key or a wrong type
51
+ // stops here instead of quietly generating somewhere else.
52
+ let config;
53
+ try {
54
+ config = (0, config_1.loadConfig)();
55
+ }
56
+ catch (err) {
57
+ if (err instanceof config_1.ConfigError) {
58
+ console.error(`❌ ${err.message}:`);
59
+ console.error((0, config_1.formatIssues)(err.issues));
60
+ process.exit(1);
61
+ }
62
+ console.warn('⚠️ Could not load an5Orm.config.js/.cjs, using defaults.', err);
63
+ config = (0, config_1.loadConfig)(path_1.default.join(process.cwd(), 'no-such-dir'));
64
+ }
65
+ const { rootDir } = config;
66
+ const schemaDir = config.outputs.schemaDir;
67
+ const outputTypesDir = config.outputs.typescriptDir;
68
+ const outputMetadataPath = config.outputs.typescriptMetadataFile;
69
+ const outputPythonMetadataPath = config.outputs.pythonMetadataFile;
70
+ const outputDotnetDir = config.outputs.dotnetDir;
71
+ const outputGolangDir = config.outputs.golangDir;
72
+ const outputRustDir = config.outputs.rustDir;
73
+ const generateMetadata = config.config.generation.generateMetadata;
74
+ console.log('🚀 Starting ORM generation...');
75
+ // The target provider comes from the connection string: both the allowed
76
+ // field types and the SQL follow it, instead of one shared list.
77
+ const provider = (0, config_1.providerFromConfig)(config.config, process.env);
78
+ console.log(`🗄️ Provider: ${field_types_1.PROVIDER_LABELS[provider]} (${provider})`);
79
+ try {
80
+ clearGeneratedFiles(outputTypesDir, '.ts');
81
+ clearGeneratedFiles(outputDotnetDir, '.cs');
82
+ clearGeneratedFiles(outputGolangDir, '.go');
83
+ clearGeneratedFiles(path_1.default.join(outputRustDir, 'src'), '.rs');
84
+ const pythonDirEarly = path_1.default.dirname(outputPythonMetadataPath);
85
+ clearGeneratedPythonFiles(pythonDirEarly);
86
+ if (config.config.generation.generateMetadata && fs_1.default.existsSync(outputMetadataPath)) {
87
+ fs_1.default.unlinkSync(outputMetadataPath);
88
+ }
89
+ const parser = new parser_1.SchemaParser(schemaDir, provider);
90
+ const models = await parser.parse();
91
+ console.log(`📦 Parsed ${models.length} models from schema.`);
92
+ const codeGen = new code_generator_1.CodeGenerator(outputTypesDir);
93
+ codeGen.generate(models);
94
+ console.log(`✨ Generated modular types in ${outputTypesDir}`);
95
+ if (generateMetadata) {
96
+ const metadataDir = path_1.default.dirname(outputMetadataPath);
97
+ if (!fs_1.default.existsSync(metadataDir)) {
98
+ fs_1.default.mkdirSync(metadataDir, { recursive: true });
99
+ }
100
+ const metadataGen = new metadata_generator_1.MetadataGenerator(outputMetadataPath);
101
+ metadataGen.generate(models);
102
+ console.log(`✨ Generated metadata in ${outputMetadataPath}`);
103
+ }
104
+ else {
105
+ console.log('⏭ Skipping metadata (generation.generateMetadata is false)');
106
+ }
107
+ const pythonDir = path_1.default.dirname(outputPythonMetadataPath);
108
+ if (!fs_1.default.existsSync(pythonDir)) {
109
+ fs_1.default.mkdirSync(pythonDir, { recursive: true });
110
+ }
111
+ const pythonGen = new python_generator_1.PythonGenerator(outputPythonMetadataPath);
112
+ pythonGen.generate(models);
113
+ console.log(`✨ Generated Python metadata and client models in ${pythonDir}`);
114
+ const dotnetGen = new dotnet_generator_1.DotnetGenerator(outputDotnetDir);
115
+ dotnetGen.generate(models);
116
+ console.log(`✨ Generated .NET models in ${outputDotnetDir}`);
117
+ const golangGen = new golang_generator_1.GolangGenerator(outputGolangDir);
118
+ golangGen.generate(models);
119
+ console.log(`✨ Generated Golang models in ${outputGolangDir}`);
120
+ const rustGen = new rust_generator_1.RustGenerator(outputRustDir);
121
+ rustGen.generate(models);
122
+ console.log(`✨ Generated Rust client in ${outputRustDir}`);
123
+ console.log('✅ ORM generation completed successfully.');
124
+ }
125
+ catch (error) {
126
+ // Print every bad field type with its provider, instead of the parser's
127
+ // nested error object.
128
+ if (error instanceof field_types_1.FieldTypeError) {
129
+ console.error(`❌ ${error.message}:`);
130
+ console.error((0, config_1.formatIssues)(error.issues));
131
+ process.exit(1);
132
+ }
133
+ console.error('❌ ORM generation failed:', error);
134
+ process.exit(1);
135
+ }
136
+ }
137
+ main();
@@ -1,8 +1,11 @@
1
- import { Model } from './types';
2
- export declare class MetadataGenerator {
3
- private outputPath;
4
- constructor(outputPath: string);
5
- generate(models: Model[]): void;
6
- private getAllPropertyVariations;
7
- private toCamelCase;
8
- }
1
+ import { Model } from './types';
2
+ export declare class MetadataGenerator {
3
+ private outputPath;
4
+ private relationImport;
5
+ constructor(outputPath: string, relationImport?: string);
6
+ generate(models: Model[]): void;
7
+ private getAllPropertyVariations;
8
+ private toSnakeCase;
9
+ private formatFieldMetadata;
10
+ private toCamelCase;
11
+ }
@@ -1,90 +1,105 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.MetadataGenerator = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- class MetadataGenerator {
9
- constructor(outputPath) {
10
- this.outputPath = outputPath;
11
- }
12
- generate(models) {
13
- let metaContent = '// This file is auto-generated. Do not edit directly.\n\n';
14
- metaContent += 'export const modelToTable: Record<string, string> = {\n';
15
- for (const model of models) {
16
- const props = this.getAllPropertyVariations(model.name);
17
- const fullTableName = `[${model.schemaName}].[${model.tableName}]`;
18
- for (const prop of props) {
19
- metaContent += ` ${prop}: "${fullTableName}",\n`;
20
- }
21
- }
22
- metaContent += '};\n\n';
23
- metaContent += 'export const modelDescriptions: Record<string, string | undefined> = {\n';
24
- for (const model of models) {
25
- const props = this.getAllPropertyVariations(model.name);
26
- for (const prop of props) {
27
- metaContent += ` ${prop}: ${model.description ? JSON.stringify(model.description) : 'undefined'},\n`;
28
- }
29
- }
30
- metaContent += '};\n\n';
31
- metaContent += 'export const modelFields: Record<string, Record<string, { ts: string; sql: string; description?: string }>> = {\n';
32
- for (const model of models) {
33
- const props = this.getAllPropertyVariations(model.name);
34
- const fieldsStr = `{ ${model.fields.map(f => `${f.name}: ${this.formatFieldMetadata(f)}`).join(', ')} }`;
35
- for (const prop of props) {
36
- metaContent += ` ${prop}: ${fieldsStr},\n`;
37
- }
38
- }
39
- metaContent += '};\n\n';
40
- metaContent += 'export interface RelationDef {\n modelName: string;\n relationType: "many" | "one";\n foreignKey: string;\n localKey: string;\n}\n\n';
41
- metaContent += 'export const relationMap: Record<string, Record<string, RelationDef>> = {\n';
42
- for (const model of models) {
43
- const props = this.getAllPropertyVariations(model.name);
44
- let relationsContent = ` {\n`;
45
- for (const rel of model.relations) {
46
- relationsContent += ` ${rel.name}: { modelName: "${this.toCamelCase(rel.type)}", relationType: "${rel.isArray ? 'many' : 'one'}", foreignKey: "${rel.foreignKey || 'id'}", localKey: "${rel.localKey || 'id'}" },\n`;
47
- }
48
- relationsContent += ` }`;
49
- for (const prop of props) {
50
- metaContent += ` ${prop}: ${relationsContent},\n`;
51
- }
52
- }
53
- metaContent += '};\n';
54
- fs_1.default.writeFileSync(this.outputPath, metaContent);
55
- }
56
- getAllPropertyVariations(modelName) {
57
- const variations = new Set();
58
- // 1. Standard camelCase (e.g. User -> user, McpServer -> mcpServer)
59
- variations.add(this.toCamelCase(modelName));
60
- // 2. Handle known acronyms at start (e.g. LLMProvider -> lLMProvider)
61
- // This is already handled by toCamelCase if it only lowercases the first letter.
62
- // But we might want 'llmProvider' as well.
63
- const acronyms = ['LLM', 'AI', 'MCP', 'IT', 'QC', 'HR', 'MR', 'WH', 'SSIS', 'API', 'URL', 'ID', 'JSON'];
64
- for (const acronym of acronyms) {
65
- if (modelName.startsWith(acronym)) {
66
- // e.g. LLMProvider -> llmProvider
67
- variations.add(acronym.toLowerCase() + modelName.slice(acronym.length));
68
- // e.g. LLMProvider -> lLMProvider (Prisma style)
69
- variations.add(acronym[0].toLowerCase() + acronym.slice(1) + modelName.slice(acronym.length));
70
- }
71
- }
72
- return Array.from(variations);
73
- }
74
- formatFieldMetadata(field) {
75
- const entries = [
76
- `ts: ${JSON.stringify(`${field.type}${field.isOptional ? '?' : ''}`)}`,
77
- `sql: ${JSON.stringify(field.sqlType)}`,
78
- ];
79
- if (field.description) {
80
- entries.push(`description: ${JSON.stringify(field.description)}`);
81
- }
82
- return `{ ${entries.join(', ')} }`;
83
- }
84
- toCamelCase(str) {
85
- if (!str)
86
- return '';
87
- return str[0].toLowerCase() + str.slice(1);
88
- }
89
- }
90
- exports.MetadataGenerator = MetadataGenerator;
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MetadataGenerator = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const types_1 = require("./types");
9
+ class MetadataGenerator {
10
+ constructor(outputPath, relationImport = 'import type { RelationDef } from "@an5/orm";') {
11
+ this.outputPath = outputPath;
12
+ this.relationImport = relationImport;
13
+ }
14
+ generate(models) {
15
+ let metaContent = '// This file is auto-generated. Do not edit directly.\n\n';
16
+ metaContent += `${this.relationImport}\n\n`;
17
+ metaContent += 'export const modelToTable: Record<string, string> = {\n';
18
+ for (const model of models) {
19
+ const props = this.getAllPropertyVariations(model.name);
20
+ const fullTableName = (0, types_1.bracketedTableName)(model);
21
+ for (const prop of props) {
22
+ metaContent += ` ${prop}: "${fullTableName}",\n`;
23
+ }
24
+ }
25
+ metaContent += '};\n\n';
26
+ metaContent += 'export const modelDescriptions: Record<string, string | undefined> = {\n';
27
+ for (const model of models) {
28
+ const props = this.getAllPropertyVariations(model.name);
29
+ for (const prop of props) {
30
+ metaContent += ` ${prop}: ${model.description ? JSON.stringify(model.description) : 'undefined'},\n`;
31
+ }
32
+ }
33
+ metaContent += '};\n\n';
34
+ metaContent += 'export const modelFields: Record<string, Record<string, { ts: string; sql: string; description?: string }>> = {\n';
35
+ for (const model of models) {
36
+ const props = this.getAllPropertyVariations(model.name);
37
+ const fieldsStr = `{ ${model.fields.map(f => `${f.name}: ${this.formatFieldMetadata(f)}`).join(', ')} }`;
38
+ for (const prop of props) {
39
+ metaContent += ` ${prop}: ${fieldsStr},\n`;
40
+ }
41
+ }
42
+ metaContent += '};\n\n';
43
+ metaContent += 'export const relationMap: Record<string, Record<string, RelationDef>> = {\n';
44
+ for (const model of models) {
45
+ const props = this.getAllPropertyVariations(model.name);
46
+ let relationsContent = ` {\n`;
47
+ for (const rel of model.relations) {
48
+ relationsContent += ` ${rel.name}: { modelName: "${this.toCamelCase(rel.type)}", relationType: "${rel.isArray ? 'many' : 'one'}", foreignKey: "${rel.foreignKey || 'id'}", localKey: "${rel.localKey || 'id'}" },\n`;
49
+ }
50
+ relationsContent += ` }`;
51
+ for (const prop of props) {
52
+ metaContent += ` ${prop}: ${relationsContent},\n`;
53
+ }
54
+ }
55
+ metaContent += '};\n';
56
+ fs_1.default.writeFileSync(this.outputPath, metaContent);
57
+ }
58
+ getAllPropertyVariations(modelName) {
59
+ const variations = new Set();
60
+ // 1. PascalCase (User)
61
+ variations.add(modelName);
62
+ // 2. camelCase (user)
63
+ variations.add(this.toCamelCase(modelName));
64
+ // 3. Plural PascalCase (Users)
65
+ variations.add(modelName + 's');
66
+ // 4. Plural camelCase (users)
67
+ variations.add(this.toCamelCase(modelName) + 's');
68
+ // 5. snake_case (user, mc_server)
69
+ variations.add(this.toSnakeCase(modelName));
70
+ variations.add(this.toSnakeCase(modelName) + 's');
71
+ const acronyms = ['LLM', 'AI', 'MCP', 'IT', 'QC', 'HR', 'MR', 'WH', 'SSIS', 'API', 'URL', 'ID', 'JSON'];
72
+ for (const acronym of acronyms) {
73
+ if (modelName.startsWith(acronym)) {
74
+ variations.add(acronym.toLowerCase() + modelName.slice(acronym.length));
75
+ variations.add(acronym[0].toLowerCase() + acronym.slice(1) + modelName.slice(acronym.length));
76
+ variations.add(acronym.toLowerCase() + modelName.slice(acronym.length) + 's');
77
+ }
78
+ }
79
+ return Array.from(variations);
80
+ }
81
+ toSnakeCase(str) {
82
+ if (!str)
83
+ return '';
84
+ return str
85
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
86
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2')
87
+ .toLowerCase();
88
+ }
89
+ formatFieldMetadata(field) {
90
+ const entries = [
91
+ `ts: ${JSON.stringify(`${field.type}${field.isOptional ? '?' : ''}`)}`,
92
+ `sql: ${JSON.stringify(field.sqlType)}`,
93
+ ];
94
+ if (field.description) {
95
+ entries.push(`description: ${JSON.stringify(field.description)}`);
96
+ }
97
+ return `{ ${entries.join(', ')} }`;
98
+ }
99
+ toCamelCase(str) {
100
+ if (!str)
101
+ return '';
102
+ return str[0].toLowerCase() + str.slice(1);
103
+ }
104
+ }
105
+ exports.MetadataGenerator = MetadataGenerator;
@@ -1,11 +1,37 @@
1
- import { Model } from './types';
2
- export declare function sqlTypeToTs(sqlType: string): string;
3
- export declare class SchemaParser {
4
- private schemaDir;
5
- private schemaText;
6
- constructor(schemaDir: string);
7
- parse(): Promise<Model[]>;
8
- private loadSchema;
9
- private parseModelLine;
10
- private postProcessRelations;
11
- }
1
+ import { Model } from './types';
2
+ import { Provider } from './field-types';
3
+ /**
4
+ * Maps a column type of a provider to its TypeScript type.
5
+ *
6
+ * `provider` defaults to SQL Server so existing callers keep their behaviour;
7
+ * the generator passes the provider derived from the connection string.
8
+ */
9
+ export declare function sqlTypeToTs(sqlType: string, provider?: Provider): string;
10
+ export declare class SchemaParser {
11
+ private schemaDir;
12
+ private provider;
13
+ private schemaText;
14
+ private issues;
15
+ private modelRefs;
16
+ private models;
17
+ /**
18
+ * @param schemaDir directory holding the `.an5` files
19
+ * @param provider target database; decides which field types are valid
20
+ */
21
+ constructor(schemaDir: string, provider?: Provider);
22
+ parse(): Promise<Model[]>;
23
+ private loadSchema;
24
+ private parseModelLine;
25
+ /**
26
+ * Settles the fields that matched no type: a name matching a model in the
27
+ * schema is a relation, anything else is a bad type — reported with the
28
+ * provider name and a suggestion.
29
+ *
30
+ * The decision has to wait for the whole schema, because a relation may point
31
+ * at a model declared later. Every upper-case token used to count as a
32
+ * relation, so `INTEGER` written for SQL Server became a relation to a model
33
+ * named `INTEGER` and nothing ever complained.
34
+ */
35
+ private resolveModelRefs;
36
+ private postProcessRelations;
37
+ }