cap-mock-generator 1.0.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.
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runCLI = runCLI;
37
+ const commander_1 = require("commander");
38
+ const prompts_1 = require("@inquirer/prompts");
39
+ const cdsParser_1 = require("../parser/cdsParser");
40
+ const fakerGenerator_1 = require("../generators/fakerGenerator");
41
+ const aiGenerator_1 = require("../generators/aiGenerator");
42
+ const csvWriter_1 = require("../writer/csvWriter");
43
+ const path = __importStar(require("path"));
44
+ const fs = __importStar(require("fs"));
45
+ function runCLI() {
46
+ const program = new commander_1.Command();
47
+ program
48
+ .name('cap-mock-generator')
49
+ .description('SAP BTP CAP projeleri için modern interaktif mock veri üretici')
50
+ .version('1.0.0');
51
+ program
52
+ .command('start')
53
+ .description('Aşamalı kurulum sihirbazını başlatır')
54
+ .action(async () => {
55
+ await startInteractiveWizard();
56
+ });
57
+ if (process.argv.length <= 2) {
58
+ startInteractiveWizard();
59
+ }
60
+ else {
61
+ program.parse(process.argv);
62
+ }
63
+ }
64
+ async function startInteractiveWizard() {
65
+ console.log('\n🌟 --- CAP Mock Generator Kurulum Sihirbazı --- \n');
66
+ try {
67
+ // 💡 1. İSTEK: Sadece dosya ismini istiyoruz, default olarak schema.cds atıyoruz
68
+ const fileName = await (0, prompts_1.input)({
69
+ message: 'db altındaki CDS şema dosyanızın adı nedir? (Örn: schema.cds veya data-models.cds):',
70
+ default: 'schema.cds',
71
+ validate: (value) => {
72
+ // Kullanıcı ne girerse girsin önünü otomatik './db/' ile bağlıyoruz
73
+ const computedPath = path.join('.', 'db', value);
74
+ if (!fs.existsSync(computedPath)) {
75
+ return `db klasörü altında "${value}" dosyası bulunamadı! Lütfen kontrol edin.`;
76
+ }
77
+ return true;
78
+ }
79
+ });
80
+ // Gerçek path'i arka planda oluşturuyoruz
81
+ const schemaPath = path.join('.', 'db', fileName);
82
+ const countStr = await (0, prompts_1.input)({
83
+ message: 'Entity başına kaç adet mock veri üretilsin?',
84
+ default: '5',
85
+ validate: (value) => isNaN(Number(value)) ? 'Lütfen geçerli bir sayı girin.' : true
86
+ });
87
+ const count = parseInt(countStr, 10);
88
+ const useAI = await (0, prompts_1.confirm)({
89
+ message: 'Yapay Zeka (AI) motorunu kullanmak ister misiniz?',
90
+ default: false
91
+ });
92
+ let aiProvider = '';
93
+ let apiKey = '';
94
+ if (useAI) {
95
+ aiProvider = await (0, prompts_1.select)({
96
+ message: 'Hangi AI sağlayıcısını kullanmak istersiniz?',
97
+ choices: [
98
+ { name: 'Gemini', value: 'Gemini' },
99
+ { name: 'OpenAI', value: 'OpenAI' }
100
+ ]
101
+ });
102
+ apiKey = await (0, prompts_1.password)({
103
+ message: `Lütfen ${aiProvider} API Key değerinizi giriniz:`,
104
+ validate: (value) => value.trim() === '' ? 'API Key boş bırakılamaz!' : true
105
+ });
106
+ if (aiProvider === 'Gemini') {
107
+ process.env.GEMINI_API_KEY = apiKey;
108
+ }
109
+ else {
110
+ process.env.OPENAI_API_KEY = apiKey;
111
+ }
112
+ }
113
+ await executeCoreWorkflow(schemaPath, count, useAI && aiProvider === 'Gemini');
114
+ }
115
+ catch (error) {
116
+ if (error.name === 'ExitPromptError') {
117
+ console.log('\n👋 Sihirbaz kullanıcı tarafından iptal edildi. Görüşmek üzere!');
118
+ }
119
+ else {
120
+ console.error('\n❌ Sihirbaz çalışırken bir hata oluştu:', error.message);
121
+ }
122
+ }
123
+ }
124
+ async function executeCoreWorkflow(schemaPath, count, isGeminiActive) {
125
+ try {
126
+ console.log('\n⚙️ İşlem başlatılıyor...');
127
+ const entities = (0, cdsParser_1.parseCdsSchema)(schemaPath);
128
+ if (entities.length === 0) {
129
+ console.log('⚠️ Şema içinde geçerli bir Entity tanımı bulunamadı.');
130
+ return;
131
+ }
132
+ const globalIdPool = {};
133
+ for (const entity of entities) {
134
+ console.log(`\n📦 Entity İşleniyor: [${entity.name}]`);
135
+ // Havuzdan bu entity için parent ID'leri çekmeye çalışıyoruz
136
+ // Akış sırasına göre ActiveDataCollectors önce işlendiği için ID'leri havuzda hazır olacak
137
+ let activeCollectorIds = [];
138
+ const shortName = entity.name.split('.').pop() || '';
139
+ // Eşleşen herhangi bir parent ID listesi var mı kontrol et
140
+ for (const key of Object.keys(globalIdPool)) {
141
+ if (key.toLowerCase().includes('datacollector') || key.toLowerCase().includes('active')) {
142
+ activeCollectorIds = globalIdPool[key];
143
+ break;
144
+ }
145
+ }
146
+ let mockRows = [];
147
+ if (isGeminiActive && process.env.GEMINI_API_KEY) {
148
+ console.log(`🤖 Gemini AI ile akıllı business verileri üretiliyor...`);
149
+ const aiResult = await (0, aiGenerator_1.generateMockDataWithAI)(entity, count, activeCollectorIds);
150
+ if (aiResult)
151
+ mockRows = aiResult;
152
+ }
153
+ if (mockRows.length === 0) {
154
+ console.log(`📦 Lokal Faker motoru ile veri üretiliyor...`);
155
+ mockRows = (0, fakerGenerator_1.generateMockData)(entity, count, activeCollectorIds);
156
+ }
157
+ // Üretilen ID'leri havuza atıyoruz (Child tablonun kullanabilmesi için)
158
+ const generatedIds = mockRows.map(row => row.ID).filter(Boolean);
159
+ globalIdPool[entity.name] = generatedIds;
160
+ globalIdPool[shortName] = generatedIds;
161
+ const filteredEntity = {
162
+ ...entity,
163
+ properties: entity.properties.filter(p => !p.isAssociation && !p.name.startsWith('to'))
164
+ };
165
+ const baseDir = path.dirname(path.dirname(path.resolve(schemaPath)));
166
+ const outputFolder = path.join(baseDir, 'db', 'data');
167
+ const savedPath = await (0, csvWriter_1.writeMockDataToCsv)(outputFolder, filteredEntity, mockRows);
168
+ console.log(`✅ CSV başarıyla kaydedildi: ${savedPath}`);
169
+ }
170
+ console.log('\n✨ Tüm işlemler başarıyla tamamlandı! Lokalinize gidip CSV dosyalarınızı kontrol edebilirsiniz. 😎\n');
171
+ }
172
+ catch (error) {
173
+ console.error('\n❌ Akış sırasında bir hata meydana geldi:', error.message);
174
+ }
175
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const commander_1 = require("commander");
40
+ const prompts_1 = require("@inquirer/prompts");
41
+ const WizardService_1 = __importDefault(require("../service/WizardService"));
42
+ const path = __importStar(require("path"));
43
+ const fs = __importStar(require("fs"));
44
+ exports.default = new commander_1.Command('start')
45
+ .description('Triggers the interactive onboarding wizard to generate mock datasets.')
46
+ .action(async () => {
47
+ console.log('\n🌟 --- CAP Mock Generator Onboarding Wizard --- \n');
48
+ try {
49
+ const fileName = await (0, prompts_1.input)({
50
+ message: 'Enter your CDS schema filename inside the "db" directory:',
51
+ default: 'schema.cds',
52
+ validate: (value) => {
53
+ const computedPath = path.join('.', 'db', value);
54
+ if (!fs.existsSync(computedPath)) {
55
+ return `File "${value}" not found inside the "db" directory!`;
56
+ }
57
+ return true;
58
+ }
59
+ });
60
+ const schemaPath = path.join('.', 'db', fileName);
61
+ const countStr = await (0, prompts_1.input)({
62
+ message: 'How many mock records should be generated per Entity?',
63
+ default: '5',
64
+ validate: (value) => isNaN(Number(value)) ? 'Please provide a valid numeric value.' : true
65
+ });
66
+ const count = parseInt(countStr, 10);
67
+ const useAI = await (0, prompts_1.confirm)({
68
+ message: 'Do you want to enable the AI smart data layer engine?',
69
+ default: false
70
+ });
71
+ let aiProvider = 'Gemini';
72
+ let apiKey = '';
73
+ if (useAI) {
74
+ aiProvider = await (0, prompts_1.select)({
75
+ message: 'Select your preferred AI Provider target:',
76
+ choices: [
77
+ { name: 'Gemini (Google)', value: 'Gemini' },
78
+ { name: 'OpenAI (GPT)', value: 'OpenAI' }
79
+ ]
80
+ });
81
+ apiKey = await (0, prompts_1.password)({
82
+ message: `Provide your secret authorization ${aiProvider} API Key:`,
83
+ validate: (value) => value.trim() === '' ? 'API Key payload cannot be empty!' : true
84
+ });
85
+ if (aiProvider === 'Gemini') {
86
+ process.env.GEMINI_API_KEY = apiKey;
87
+ }
88
+ else {
89
+ process.env.OPENAI_API_KEY = apiKey;
90
+ }
91
+ }
92
+ const wizardService = new WizardService_1.default();
93
+ await wizardService.executeWorkflow(schemaPath, count, useAI, aiProvider);
94
+ }
95
+ catch (error) {
96
+ if (error.name === 'ExitPromptError') {
97
+ console.log('\n👋 Wizard cancelled by developer instruction. See you around!');
98
+ }
99
+ else {
100
+ console.error('\n❌ Execution failed on prompt layer:', error.message);
101
+ }
102
+ }
103
+ });
package/dist/cli.js ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const start_1 = __importDefault(require("./cli/start"));
9
+ const program = new commander_1.Command();
10
+ program
11
+ .name('cap-mock-generator')
12
+ .description('Advanced structured smart mock dataset generation tool engine for SAP BTP CAP.')
13
+ .version('1.0.0');
14
+ program.addCommand(start_1.default);
15
+ if (process.argv.length <= 2) {
16
+ process.argv.push('start');
17
+ }
18
+ program.parse(process.argv);
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateMockDataWithAI = generateMockDataWithAI;
4
+ const genai_1 = require("@google/genai");
5
+ // ESKİ: const ai = new GoogleGenAI({}); satırını buradan siliyoruz!
6
+ async function generateMockDataWithAI(entity, count = 5, parentIds) {
7
+ if (!process.env.GEMINI_API_KEY) {
8
+ throw new Error("AI ile veri üretimi için 'GEMINI_API_KEY' tanımlanmalıdır.");
9
+ }
10
+ try {
11
+ // 💡 YENİ: İstemciyi tam bu satırda, API Key ortama enjekte edildikten sonra ayağa kaldırıyoruz.
12
+ // Böylece o sinir bozucu erken uyarı mesajı tamamen yok oluyor.
13
+ const ai = new genai_1.GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
14
+ const dynamicProperties = {};
15
+ const requiredFields = [];
16
+ for (const prop of entity.properties) {
17
+ if (prop.isAssociation && prop.name.startsWith('to'))
18
+ continue;
19
+ requiredFields.push(prop.name);
20
+ if (prop.name === 'dataCollectorID' && parentIds && parentIds.length > 0) {
21
+ dynamicProperties[prop.name] = {
22
+ type: genai_1.Type.STRING,
23
+ description: `CRITICAL: Foreign key. Use one from: [${parentIds.join(', ')}].`
24
+ };
25
+ }
26
+ else if (prop.type === 'cds.Integer' || prop.type === 'cds.Decimal') {
27
+ dynamicProperties[prop.name] = { type: genai_1.Type.NUMBER };
28
+ }
29
+ else if (prop.type === 'cds.Boolean') {
30
+ dynamicProperties[prop.name] = { type: genai_1.Type.BOOLEAN };
31
+ }
32
+ else {
33
+ dynamicProperties[prop.name] = { type: genai_1.Type.STRING };
34
+ }
35
+ }
36
+ const prompt = `
37
+ You are an expert data generator for SAP CAP applications.
38
+ Generate highly realistic business data for: "${entity.name}". Generate exactly ${count} records.
39
+ `;
40
+ const response = await ai.models.generateContent({
41
+ model: 'gemini-2.5-flash',
42
+ contents: prompt,
43
+ config: {
44
+ responseMimeType: 'application/json',
45
+ responseSchema: {
46
+ type: genai_1.Type.ARRAY,
47
+ description: `List of mock data objects for ${entity.name}`,
48
+ items: {
49
+ type: genai_1.Type.OBJECT,
50
+ properties: dynamicProperties,
51
+ required: requiredFields
52
+ }
53
+ },
54
+ temperature: 0.7
55
+ }
56
+ });
57
+ const rawContent = response.text;
58
+ if (!rawContent)
59
+ return null;
60
+ return JSON.parse(rawContent);
61
+ }
62
+ catch (error) {
63
+ console.warn('⚠️ Gemini API tarafında bir sorun oluştu veya boş veri döndü.');
64
+ return null;
65
+ }
66
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateMockData = generateMockData;
4
+ const faker_1 = require("@faker-js/faker");
5
+ function generateValueForProperty(propName, propType, parentIds) {
6
+ const lowerPropName = propName.toLowerCase();
7
+ // 💡 TAM DİNAMİK İLİŞKİ KONTROLÜ:
8
+ // Eğer alan adı 'id' ile bitiyorsa (dataCollectorID vb.) ve bu bir primary 'ID' değilse
9
+ if (lowerPropName.endsWith('id') && lowerPropName !== 'id') {
10
+ // Elimizde üst tablodan gelen gerçek ID'ler varsa onlardan birini seç
11
+ if (parentIds && parentIds.length > 0) {
12
+ return faker_1.faker.helpers.arrayElement(parentIds);
13
+ }
14
+ }
15
+ // İsim bazlı kurallar
16
+ if (lowerPropName.includes('mail'))
17
+ return faker_1.faker.internet.email();
18
+ if (lowerPropName.includes('name'))
19
+ return faker_1.faker.person.fullName();
20
+ if (lowerPropName.includes('title'))
21
+ return faker_1.faker.commerce.productName();
22
+ if (lowerPropName.includes('receiver'))
23
+ return faker_1.faker.internet.username();
24
+ if (lowerPropName.includes('createdby'))
25
+ return faker_1.faker.internet.username();
26
+ // Tip bazlı kurallar
27
+ switch (propType) {
28
+ case 'cds.UUID':
29
+ return faker_1.faker.string.uuid();
30
+ case 'cds.Integer':
31
+ return faker_1.faker.number.int({ min: 1, max: 60 });
32
+ case 'cds.Decimal':
33
+ return faker_1.faker.number.float({ min: 10, max: 500, multipleOf: 0.01 });
34
+ case 'cds.Boolean':
35
+ return faker_1.faker.datatype.boolean();
36
+ case 'cds.DateTime':
37
+ case 'cds.Timestamp':
38
+ return faker_1.faker.date.past().toISOString();
39
+ default:
40
+ return faker_1.faker.lorem.word();
41
+ }
42
+ }
43
+ function generateMockData(entity, count = 5, parentIds) {
44
+ const mockData = [];
45
+ for (let i = 0; i < count; i++) {
46
+ const row = {};
47
+ for (const prop of entity.properties) {
48
+ if (prop.isAssociation || prop.name.startsWith('to')) {
49
+ continue;
50
+ }
51
+ row[prop.name] = generateValueForProperty(prop.name, prop.type, parentIds);
52
+ }
53
+ mockData.push(row);
54
+ }
55
+ return mockData;
56
+ }
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commander_1 = require("./cli/commander");
4
+ (0, commander_1.runCLI)();
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseCdsSchema = parseCdsSchema;
40
+ const cds_compiler_1 = __importDefault(require("@sap/cds-compiler"));
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ function parseCdsSchema(filePath) {
44
+ const absolutePath = path.resolve(filePath);
45
+ if (!fs.existsSync(absolutePath)) {
46
+ throw new Error(`CDS dosyası bulunamadı: ${absolutePath}`);
47
+ }
48
+ const cdsContent = fs.readFileSync(absolutePath, 'utf-8');
49
+ const csn = cds_compiler_1.default.parse.cdl(cdsContent, filePath);
50
+ const parsedEntities = [];
51
+ if (csn && csn.definitions) {
52
+ for (const [key, def] of Object.entries(csn.definitions)) {
53
+ const definition = def;
54
+ if (definition.kind === 'entity' && definition.elements) {
55
+ const properties = [];
56
+ for (const [propName, propDef] of Object.entries(definition.elements)) {
57
+ const property = propDef;
58
+ const isAssoc = property.type === 'cds.Association' ||
59
+ property.type === 'cds.Composition' ||
60
+ property.type === undefined ||
61
+ propName.startsWith('to');
62
+ let finalType = property.type || 'Association';
63
+ if (typeof property.target === 'string') {
64
+ finalType = `Association.${property.target}`;
65
+ }
66
+ properties.push({
67
+ name: propName,
68
+ type: finalType,
69
+ isAssociation: isAssoc
70
+ });
71
+ }
72
+ parsedEntities.push({
73
+ name: key,
74
+ properties: properties
75
+ });
76
+ }
77
+ }
78
+ }
79
+ return parsedEntities;
80
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const cds_compiler_1 = __importDefault(require("@sap/cds-compiler"));
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ class CdsParserService {
43
+ parse(filePath) {
44
+ const absolutePath = path.resolve(filePath);
45
+ if (!fs.existsSync(absolutePath)) {
46
+ throw new Error(`CDS file not found at: ${absolutePath}`);
47
+ }
48
+ const cdsContent = fs.readFileSync(absolutePath, 'utf-8');
49
+ const csn = cds_compiler_1.default.parse.cdl(cdsContent, filePath);
50
+ const parsedEntities = [];
51
+ if (csn && csn.definitions) {
52
+ for (const [key, def] of Object.entries(csn.definitions)) {
53
+ const definition = def;
54
+ if (definition.kind === 'entity' && definition.elements) {
55
+ const properties = [];
56
+ for (const [propName, propDef] of Object.entries(definition.elements)) {
57
+ const property = propDef;
58
+ const isAssoc = property.type === 'cds.Association' ||
59
+ property.type === 'cds.Composition' ||
60
+ property.type === undefined ||
61
+ propName.startsWith('to');
62
+ let finalType = property.type || 'Association';
63
+ if (typeof property.target === 'string') {
64
+ finalType = `Association.${property.target}`;
65
+ }
66
+ properties.push({
67
+ name: propName,
68
+ type: finalType,
69
+ isAssociation: isAssoc
70
+ });
71
+ }
72
+ parsedEntities.push({
73
+ name: key,
74
+ properties: properties
75
+ });
76
+ }
77
+ }
78
+ }
79
+ return parsedEntities;
80
+ }
81
+ }
82
+ exports.default = CdsParserService;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const csv_writer_1 = require("csv-writer");
37
+ const path = __importStar(require("path"));
38
+ const fs = __importStar(require("fs"));
39
+ class CsvWriterService {
40
+ async write(outputDir, entity, data) {
41
+ const targetDir = path.resolve(outputDir);
42
+ if (!fs.existsSync(targetDir)) {
43
+ fs.mkdirSync(targetDir, { recursive: true });
44
+ }
45
+ const outputPath = path.join(targetDir, `${entity.name}.csv`);
46
+ const headers = entity.properties.map(prop => ({ id: prop.name, title: prop.name }));
47
+ const csvWriter = (0, csv_writer_1.createObjectCsvWriter)({
48
+ path: outputPath,
49
+ header: headers,
50
+ append: false
51
+ });
52
+ await csvWriter.writeRecords(data);
53
+ return outputPath;
54
+ }
55
+ }
56
+ exports.default = CsvWriterService;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const faker_1 = require("@faker-js/faker");
4
+ class FakerService {
5
+ generateValue(propName, propType, parentIds) {
6
+ const lowerPropName = propName.toLowerCase();
7
+ if (lowerPropName.endsWith('id') && lowerPropName !== 'id') {
8
+ if (parentIds && parentIds.length > 0) {
9
+ return faker_1.faker.helpers.arrayElement(parentIds);
10
+ }
11
+ }
12
+ if (lowerPropName.includes('mail')) {
13
+ return faker_1.faker.internet.email();
14
+ }
15
+ if (lowerPropName.includes('name')) {
16
+ return faker_1.faker.person.fullName();
17
+ }
18
+ if (lowerPropName.includes('title')) {
19
+ return faker_1.faker.commerce.productName();
20
+ }
21
+ if (lowerPropName.includes('receiver')) {
22
+ return faker_1.faker.internet.username();
23
+ }
24
+ if (lowerPropName.includes('createdby')) {
25
+ return faker_1.faker.internet.username();
26
+ }
27
+ switch (propType) {
28
+ case 'cds.UUID': {
29
+ return faker_1.faker.string.uuid();
30
+ }
31
+ case 'cds.Integer': {
32
+ return faker_1.faker.number.int({ min: 1, max: 60 });
33
+ }
34
+ case 'cds.Decimal': {
35
+ return faker_1.faker.number.float({ min: 10, max: 500, multipleOf: 0.01 });
36
+ }
37
+ case 'cds.Boolean': {
38
+ return faker_1.faker.datatype.boolean();
39
+ }
40
+ case 'cds.DateTime':
41
+ case 'cds.Timestamp': {
42
+ return faker_1.faker.date.past().toISOString();
43
+ }
44
+ default: {
45
+ return faker_1.faker.lorem.word();
46
+ }
47
+ }
48
+ }
49
+ generate(entity, count, parentIds) {
50
+ const mockData = [];
51
+ for (let i = 0; i < count; i++) {
52
+ const row = {};
53
+ for (const prop of entity.properties) {
54
+ if (prop.isAssociation || prop.name.startsWith('to'))
55
+ continue;
56
+ row[prop.name] = this.generateValue(prop.name, prop.type, parentIds);
57
+ }
58
+ mockData.push(row);
59
+ }
60
+ return mockData;
61
+ }
62
+ }
63
+ exports.default = FakerService;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const genai_1 = require("@google/genai");
4
+ class GeminiService {
5
+ async generate(entity, count, parentIds) {
6
+ if (!process.env.GEMINI_API_KEY)
7
+ return null;
8
+ try {
9
+ const ai = new genai_1.GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
10
+ const dynamicProperties = {};
11
+ const requiredFields = [];
12
+ for (const prop of entity.properties) {
13
+ if (prop.isAssociation || prop.name.startsWith('to'))
14
+ continue;
15
+ requiredFields.push(prop.name);
16
+ if (prop.name.toLowerCase().endsWith('id') && prop.name.toLowerCase() !== 'id' && parentIds && parentIds.length > 0) {
17
+ dynamicProperties[prop.name] = {
18
+ type: genai_1.Type.STRING,
19
+ description: `CRITICAL: Foreign key. Pick one value from this pool: [${parentIds.join(', ')}].`
20
+ };
21
+ }
22
+ else if (prop.type === 'cds.Integer' || prop.type === 'cds.Decimal') {
23
+ dynamicProperties[prop.name] = { type: genai_1.Type.NUMBER };
24
+ }
25
+ else if (prop.type === 'cds.Boolean') {
26
+ dynamicProperties[prop.name] = { type: genai_1.Type.BOOLEAN };
27
+ }
28
+ else {
29
+ dynamicProperties[prop.name] = { type: genai_1.Type.STRING };
30
+ }
31
+ }
32
+ const prompt = `Generate highly realistic business mock data for entity: "${entity.name}". Count: ${count} rows.`;
33
+ const response = await ai.models.generateContent({
34
+ model: 'gemini-2.5-flash',
35
+ contents: prompt,
36
+ config: {
37
+ responseMimeType: 'application/json',
38
+ responseSchema: {
39
+ type: genai_1.Type.ARRAY,
40
+ description: `List of mock objects for ${entity.name}`,
41
+ items: {
42
+ type: genai_1.Type.OBJECT,
43
+ properties: dynamicProperties,
44
+ required: requiredFields
45
+ }
46
+ },
47
+ temperature: 0.7
48
+ }
49
+ });
50
+ return response.text ? JSON.parse(response.text) : null;
51
+ }
52
+ catch (error) {
53
+ console.warn('⚠️ Gemini API encountered an issue, redirecting to local generation fallback.');
54
+ return null;
55
+ }
56
+ }
57
+ }
58
+ exports.default = GeminiService;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const openai_1 = require("openai");
4
+ class OpenAiService {
5
+ async generate(entity, count, parentIds) {
6
+ if (!process.env.OPENAI_API_KEY)
7
+ return null;
8
+ try {
9
+ const openai = new openai_1.OpenAI({ apiKey: process.env.OPENAI_API_KEY });
10
+ const openAiProperties = {};
11
+ const requiredFields = [];
12
+ for (const prop of entity.properties) {
13
+ if (prop.isAssociation || prop.name.startsWith('to'))
14
+ continue;
15
+ requiredFields.push(prop.name);
16
+ if (prop.name.toLowerCase().endsWith('id') && prop.name.toLowerCase() !== 'id' && parentIds && parentIds.length > 0) {
17
+ openAiProperties[prop.name] = {
18
+ type: 'string',
19
+ description: `CRITICAL: Foreign key. Pick one value from: ${parentIds.join(', ')}`
20
+ };
21
+ }
22
+ else if (prop.type === 'cds.Integer' || prop.type === 'cds.Decimal') {
23
+ openAiProperties[prop.name] = { type: 'number' };
24
+ }
25
+ else if (prop.type === 'cds.Boolean') {
26
+ openAiProperties[prop.name] = { type: 'boolean' };
27
+ }
28
+ else {
29
+ openAiProperties[prop.name] = { type: 'string' };
30
+ }
31
+ }
32
+ const prompt = `Generate highly realistic business mock data for entity: "${entity.name}". Count: ${count} rows.`;
33
+ const response = await openai.chat.completions.create({
34
+ model: 'gpt-4o-mini',
35
+ messages: [
36
+ { role: 'system', content: 'You are a strict data generator that outputs a JSON array matching the requested schema.' },
37
+ { role: 'user', content: prompt }
38
+ ],
39
+ response_format: {
40
+ type: 'json_schema',
41
+ json_schema: {
42
+ name: 'mock_data_response',
43
+ strict: true,
44
+ schema: {
45
+ type: 'object',
46
+ properties: {
47
+ data: {
48
+ type: 'array',
49
+ items: {
50
+ type: 'object',
51
+ properties: openAiProperties,
52
+ required: requiredFields,
53
+ additionalProperties: false
54
+ }
55
+ }
56
+ },
57
+ required: ['data'],
58
+ additionalProperties: false
59
+ }
60
+ }
61
+ },
62
+ temperature: 0.7
63
+ });
64
+ const content = response.choices[0].message?.content;
65
+ return content ? JSON.parse(content).data : null;
66
+ }
67
+ catch (error) {
68
+ console.warn('⚠️ OpenAI API encountered an issue, redirecting to local generation fallback.');
69
+ return null;
70
+ }
71
+ }
72
+ }
73
+ exports.default = OpenAiService;
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const CdsParserService_1 = __importDefault(require("./CdsParserService"));
40
+ const GeminiService_1 = __importDefault(require("./GeminiService"));
41
+ const OpenAiService_1 = __importDefault(require("./OpenAiService"));
42
+ const FakerService_1 = __importDefault(require("./FakerService"));
43
+ const CsvWriterService_1 = __importDefault(require("./CsvWriterService"));
44
+ const path = __importStar(require("path"));
45
+ class WizardService {
46
+ parser = new CdsParserService_1.default();
47
+ gemini = new GeminiService_1.default();
48
+ openai = new OpenAiService_1.default();
49
+ faker = new FakerService_1.default();
50
+ csvWriter = new CsvWriterService_1.default();
51
+ async executeWorkflow(schemaPath, count, useAI, aiProvider) {
52
+ try {
53
+ console.log('\n⚙️ Processing schema and initializing execution...');
54
+ const entities = this.parser.parse(schemaPath);
55
+ if (entities.length === 0) {
56
+ console.log('⚠️ No valid Entity definitions found inside the schema.');
57
+ return;
58
+ }
59
+ const globalIdPool = {};
60
+ for (const entity of entities) {
61
+ console.log(`\n📦 Processing Entity: [${entity.name}]`);
62
+ let activeCollectorIds = [];
63
+ const shortName = entity.name.split('.').pop() || '';
64
+ for (const key of Object.keys(globalIdPool)) {
65
+ if (key.toLowerCase().includes('datacollector') || key.toLowerCase().includes('active')) {
66
+ activeCollectorIds = globalIdPool[key];
67
+ break;
68
+ }
69
+ }
70
+ let mockRows = [];
71
+ if (useAI) {
72
+ console.log(`🤖 Generating smart context data via ${aiProvider}...`);
73
+ if (aiProvider === 'Gemini') {
74
+ mockRows = await this.gemini.generate(entity, count, activeCollectorIds) || [];
75
+ }
76
+ else {
77
+ mockRows = await this.openai.generate(entity, count, activeCollectorIds) || [];
78
+ }
79
+ }
80
+ if (mockRows.length === 0) {
81
+ console.log(`📦 Generating fast fallback mock data via local Faker engine...`);
82
+ mockRows = this.faker.generate(entity, count, activeCollectorIds);
83
+ }
84
+ const generatedIds = mockRows.map(row => row.ID).filter(Boolean);
85
+ globalIdPool[entity.name] = generatedIds;
86
+ globalIdPool[shortName] = generatedIds;
87
+ const filteredEntity = {
88
+ ...entity,
89
+ properties: entity.properties.filter(p => !p.isAssociation && !p.name.startsWith('to'))
90
+ };
91
+ const baseDir = path.dirname(path.dirname(path.resolve(schemaPath)));
92
+ const outputFolder = path.join(baseDir, 'db', 'data');
93
+ const savedPath = await this.csvWriter.write(outputFolder, filteredEntity, mockRows);
94
+ console.log(`✅ CSV successfully exported to: ${savedPath}`);
95
+ }
96
+ console.log('\n✨ Execution successfully completed! Check your db/data directory. 😎\n');
97
+ }
98
+ catch (error) {
99
+ console.error('\n❌ An error occurred during runtime execution:', error.message);
100
+ }
101
+ }
102
+ }
103
+ exports.default = WizardService;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.writeMockDataToCsv = writeMockDataToCsv;
37
+ const csv_writer_1 = require("csv-writer");
38
+ const path = __importStar(require("path"));
39
+ const fs = __importStar(require("fs"));
40
+ async function writeMockDataToCsv(outputDir, entity, data) {
41
+ const targetDir = path.resolve(outputDir);
42
+ if (!fs.existsSync(targetDir)) {
43
+ fs.mkdirSync(targetDir, { recursive: true });
44
+ }
45
+ const fileName = `${entity.name}.csv`;
46
+ const outputPath = path.join(targetDir, fileName);
47
+ const headers = entity.properties.map(prop => ({
48
+ id: prop.name,
49
+ title: prop.name
50
+ }));
51
+ const csvWriter = (0, csv_writer_1.createObjectCsvWriter)({
52
+ path: outputPath,
53
+ header: headers,
54
+ append: false
55
+ });
56
+ await csvWriter.writeRecords(data);
57
+ return outputPath;
58
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "cap-mock-generator",
3
+ "version": "1.0.0",
4
+ "description": "Advanced interactive smart mock dataset generation engine for SAP BTP CAP applications.",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "cap-mock-generator": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepare": "npm run build",
16
+ "start": "tsc && node dist/cli.js start"
17
+ },
18
+ "keywords": [
19
+ "sap",
20
+ "btp",
21
+ "cap",
22
+ "cds",
23
+ "mock-data",
24
+ "faker",
25
+ "gemini",
26
+ "openai"
27
+ ],
28
+ "author": "Berkay Ergün",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@faker-js/faker": "^10.4.0",
32
+ "@google/genai": "^2.8.0",
33
+ "@inquirer/prompts": "^8.5.2",
34
+ "@sap/cds-compiler": "^6.9.2",
35
+ "commander": "^15.0.0",
36
+ "csv-writer": "^1.6.0",
37
+ "dotenv": "^17.4.2",
38
+ "openai": "^6.42.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/dotenv": "^6.1.1",
42
+ "@types/node": "^25.9.2",
43
+ "typescript": "^6.0.3"
44
+ }
45
+ }