cap-mock-generator 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -21
- package/dist/service/CdsParserService.js +37 -15
- package/dist/service/FakerService.js +71 -16
- package/dist/service/WizardService.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# CAP Mock Generator
|
|
1
|
+
# CAP Mock Generator
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/cap-mock-generator)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -9,18 +9,18 @@ An advanced, interactive, and intelligent mock dataset generation engine built s
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Features
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
- **Interactive Onboarding Wizard:** Powered by modern `@inquirer/prompts`, walking you seamlessly through configuration step-by-step.
|
|
15
|
+
- **Relational Data Integrity (Foreign Key Management):** Automatically analyzes dependencies. It ensures child tables (e.g., entity relationships ending with `ID`) match valid, existing primary keys generated from parent tables.
|
|
16
|
+
- **Automatic Virtual Column Stripping:** Cleanly filters out `Association to many` and `Composition of many` virtual elements so they never mess up your physical CSV deployment files.
|
|
17
|
+
- **Multi-Provider AI Data Layer:** High-fidelity business mock data using either **Google Gemini Pro (`gemini-2.5-flash`)** or **OpenAI (`gpt-4o-mini`)** structured JSON responses.
|
|
18
|
+
- **Resilient Fallback Core:** If your AI API tokens hit limit caps or encounter network spikes (503 Service Unavailable), the engine gracefully falls back to a lightning-fast local **Faker.js** cluster without crashing.
|
|
19
|
+
- **Clean Architectural Foundations:** Designed around the Command-Service pattern for maximum scalability and maintainability.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Installation
|
|
24
24
|
|
|
25
25
|
You can install `cap-mock-generator` globally, locally as a development dependency, or invoke it instantly on-demand using `npx`.
|
|
26
26
|
|
|
@@ -44,11 +44,11 @@ npm install cap-mock-generator --save-dev
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Usage
|
|
48
48
|
|
|
49
49
|
Once installed, open your terminal, ensure you are in the root directory of your SAP CAP application where your `package.json` and `db/` folder reside, and trigger the wizard using one of the strategies below.
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### Option A: On-The-Fly Execution
|
|
52
52
|
|
|
53
53
|
No installation required.
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ If you prefer to run the module directly without explicitly downloading it to yo
|
|
|
58
58
|
npx cap-mock-generator start
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
###
|
|
61
|
+
### Option B: Global Command Line Execution
|
|
62
62
|
|
|
63
63
|
If you selected the global installation strategy earlier, simply ignite the interface by typing:
|
|
64
64
|
|
|
@@ -66,7 +66,7 @@ If you selected the global installation strategy earlier, simply ignite the inte
|
|
|
66
66
|
cap-mock-generator start
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
###
|
|
69
|
+
### Option C: Configured Local Project Scripts
|
|
70
70
|
|
|
71
71
|
If you installed the generator locally, open your native `package.json` and map a clean entry shortcut helper to your internal `scripts` block:
|
|
72
72
|
|
|
@@ -86,12 +86,12 @@ npm run mock:gen
|
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## Interactive Onboarding Flow
|
|
90
90
|
|
|
91
91
|
When you ignite the CLI wizard, it will guide you through the following prompts:
|
|
92
92
|
|
|
93
93
|
```plaintext
|
|
94
|
-
🌟 --- CAP Mock Generator Onboarding Wizard ---
|
|
94
|
+
🌟 --- CAP Mock Generator Onboarding Wizard ---
|
|
95
95
|
|
|
96
96
|
? Enter your CDS schema filename inside the "db" directory: (schema.cds)
|
|
97
97
|
? How many mock records should be generated per Entity? (5)
|
|
@@ -115,7 +115,7 @@ When you ignite the CLI wizard, it will guide you through the following prompts:
|
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
-
##
|
|
118
|
+
## Security & Environment Compliance
|
|
119
119
|
|
|
120
120
|
Your secret API credentials, such as `GEMINI_API_KEY` or `OPENAI_API_KEY`, are processed strictly inside your immediate shell execution context memory through `process.env`.
|
|
121
121
|
|
|
@@ -123,7 +123,7 @@ They are never saved to disk, logged to the console, or transported outside the
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
##
|
|
126
|
+
## Relational Schema Topology
|
|
127
127
|
|
|
128
128
|
The generator intelligently tracks schema hierarchy. Take this complex manufacturing scenario:
|
|
129
129
|
|
|
@@ -140,9 +140,12 @@ entity Assets {
|
|
|
140
140
|
}
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
##
|
|
143
|
+
## License and Usage Notice
|
|
144
144
|
|
|
145
|
-
This
|
|
145
|
+
This library leverages the official `@sap/cds-compiler` package provided by SAP to parse CDS schema definitions for SAP CAP applications. It does not modify, bundle, or redistribute SAP source code beyond declaring `@sap/cds-compiler` as an npm dependency.
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
The `@sap/cds-compiler` package is provided under SAP's own license terms. Users of `cap-mock-generator` are responsible for reviewing and complying with the applicable SAP license terms when using this package in projects that depend on SAP CAP tooling.
|
|
148
|
+
|
|
149
|
+
Careful attention should be paid to licensing restrictions when integrating `cap-mock-generator` into commercial, enterprise, or redistributed software that includes SAP CAP dependencies.
|
|
150
|
+
|
|
151
|
+
`cap-mock-generator` itself is licensed under the MIT License. See the `LICENSE` file for details.
|
|
@@ -55,25 +55,47 @@ class CdsParserService {
|
|
|
55
55
|
const properties = [];
|
|
56
56
|
for (const [propName, propDef] of Object.entries(definition.elements)) {
|
|
57
57
|
const property = propDef;
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
const rawType = property.type || '';
|
|
59
|
+
const lowerType = rawType.toLowerCase();
|
|
60
|
+
const isCommonCountryType = rawType === 'Country' ||
|
|
61
|
+
rawType === 'sap.common.Country' ||
|
|
62
|
+
lowerType.endsWith('.country');
|
|
63
|
+
const isCommonCurrencyType = rawType === 'Currency' ||
|
|
64
|
+
rawType === 'sap.common.Currency' ||
|
|
65
|
+
lowerType.endsWith('.currency');
|
|
66
|
+
if (isCommonCountryType || isCommonCurrencyType) {
|
|
67
|
+
properties.push({
|
|
68
|
+
name: `${propName}_code`,
|
|
69
|
+
type: 'cds.String',
|
|
70
|
+
isAssociation: false,
|
|
71
|
+
isKey: !!property.key
|
|
72
|
+
});
|
|
73
|
+
continue;
|
|
66
74
|
}
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
const isManagedAssociation = property.type === 'cds.Association' &&
|
|
76
|
+
typeof property.target === 'string' &&
|
|
77
|
+
!property.on &&
|
|
78
|
+
property.cardinality?.max !== '*';
|
|
79
|
+
if (isManagedAssociation) {
|
|
80
|
+
properties.push({
|
|
81
|
+
name: `${propName}_ID`,
|
|
82
|
+
type: 'cds.UUID',
|
|
83
|
+
isAssociation: false,
|
|
84
|
+
isKey: !!property.key
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
69
87
|
}
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
const isAssociation = property.type === 'cds.Association' ||
|
|
89
|
+
property.type === 'cds.Composition' ||
|
|
90
|
+
!!property.target;
|
|
91
|
+
if (isAssociation) {
|
|
92
|
+
continue;
|
|
72
93
|
}
|
|
73
94
|
properties.push({
|
|
74
|
-
name:
|
|
75
|
-
type:
|
|
76
|
-
isAssociation:
|
|
95
|
+
name: propName,
|
|
96
|
+
type: property.type || 'cds.String',
|
|
97
|
+
isAssociation: false,
|
|
98
|
+
isKey: !!property.key
|
|
77
99
|
});
|
|
78
100
|
}
|
|
79
101
|
parsedEntities.push({
|
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const faker_1 = require("@faker-js/faker");
|
|
4
4
|
class FakerService {
|
|
5
|
+
generateKeyValue(prop, index) {
|
|
6
|
+
const lowerPropName = prop.name.toLowerCase();
|
|
7
|
+
if (lowerPropName === 'fromcurrency') {
|
|
8
|
+
const values = ['USD', 'EUR', 'TRY', 'GBP', 'CHF', 'JPY'];
|
|
9
|
+
return values[index % values.length];
|
|
10
|
+
}
|
|
11
|
+
if (lowerPropName === 'tocurrency') {
|
|
12
|
+
const values = ['EUR', 'USD', 'GBP', 'TRY', 'JPY', 'CHF'];
|
|
13
|
+
return values[index % values.length];
|
|
14
|
+
}
|
|
15
|
+
if (lowerPropName === 'validfrom' && prop.type === 'cds.Date') {
|
|
16
|
+
const date = new Date(2024, 0, 1);
|
|
17
|
+
date.setDate(date.getDate() + index);
|
|
18
|
+
return date.toISOString().split('T')[0];
|
|
19
|
+
}
|
|
20
|
+
switch (prop.type) {
|
|
21
|
+
case 'cds.UUID':
|
|
22
|
+
return faker_1.faker.string.uuid();
|
|
23
|
+
case 'cds.Integer':
|
|
24
|
+
return index + 1;
|
|
25
|
+
case 'cds.Date': {
|
|
26
|
+
const date = new Date(2024, 0, 1);
|
|
27
|
+
date.setDate(date.getDate() + index);
|
|
28
|
+
return date.toISOString().split('T')[0];
|
|
29
|
+
}
|
|
30
|
+
case 'cds.DateTime':
|
|
31
|
+
case 'cds.Timestamp': {
|
|
32
|
+
const date = new Date(2024, 0, 1, 0, 0, 0);
|
|
33
|
+
date.setMinutes(date.getMinutes() + index);
|
|
34
|
+
return date.toISOString();
|
|
35
|
+
}
|
|
36
|
+
default: {
|
|
37
|
+
if (lowerPropName.includes('currency')) {
|
|
38
|
+
const currencies = ['USD', 'EUR', 'TRY', 'GBP', 'CHF', 'JPY'];
|
|
39
|
+
return currencies[index % currencies.length];
|
|
40
|
+
}
|
|
41
|
+
if (lowerPropName.includes('country')) {
|
|
42
|
+
const countries = ['US', 'DE', 'TR', 'GB', 'FR', 'NL'];
|
|
43
|
+
return countries[index % countries.length];
|
|
44
|
+
}
|
|
45
|
+
return `${prop.name}_${index + 1}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
5
49
|
generateValue(propName, propType, parentIds) {
|
|
6
50
|
const lowerPropName = propName.toLowerCase();
|
|
7
51
|
if (lowerPropName.endsWith('id') && lowerPropName !== 'id') {
|
|
@@ -12,6 +56,12 @@ class FakerService {
|
|
|
12
56
|
if (lowerPropName.includes('mail')) {
|
|
13
57
|
return faker_1.faker.internet.email();
|
|
14
58
|
}
|
|
59
|
+
if (lowerPropName.includes('firstname')) {
|
|
60
|
+
return faker_1.faker.person.firstName();
|
|
61
|
+
}
|
|
62
|
+
if (lowerPropName.includes('lastname')) {
|
|
63
|
+
return faker_1.faker.person.lastName();
|
|
64
|
+
}
|
|
15
65
|
if (lowerPropName.includes('name')) {
|
|
16
66
|
return faker_1.faker.person.fullName();
|
|
17
67
|
}
|
|
@@ -24,32 +74,33 @@ class FakerService {
|
|
|
24
74
|
if (lowerPropName.includes('createdby') || lowerPropName.includes('modifiedby')) {
|
|
25
75
|
return faker_1.faker.internet.username();
|
|
26
76
|
}
|
|
77
|
+
if (lowerPropName === 'country_code' || lowerPropName.endsWith('country_code')) {
|
|
78
|
+
return faker_1.faker.helpers.arrayElement(['TR', 'DE', 'US', 'GB', 'FR', 'NL']);
|
|
79
|
+
}
|
|
80
|
+
if (lowerPropName === 'currency_code' || lowerPropName.endsWith('currency_code')) {
|
|
81
|
+
return faker_1.faker.helpers.arrayElement(['TRY', 'EUR', 'USD', 'GBP', 'CHF']);
|
|
82
|
+
}
|
|
27
83
|
if (lowerPropName.endsWith('currency') || lowerPropName.endsWith('code')) {
|
|
28
84
|
return faker_1.faker.string.alpha({ length: 3, casing: 'upper' });
|
|
29
85
|
}
|
|
30
86
|
switch (propType) {
|
|
31
|
-
case 'cds.Date':
|
|
87
|
+
case 'cds.Date':
|
|
32
88
|
return faker_1.faker.date.anytime().toISOString().split('T')[0];
|
|
33
|
-
|
|
34
|
-
case 'cds.UUID': {
|
|
89
|
+
case 'cds.UUID':
|
|
35
90
|
return faker_1.faker.string.uuid();
|
|
36
|
-
|
|
37
|
-
case 'cds.Integer': {
|
|
91
|
+
case 'cds.Integer':
|
|
38
92
|
return faker_1.faker.number.int({ min: 1, max: 60 });
|
|
39
|
-
|
|
40
|
-
case 'cds.Decimal': {
|
|
93
|
+
case 'cds.Decimal':
|
|
41
94
|
return faker_1.faker.number.float({ min: 10, max: 500, multipleOf: 0.01 });
|
|
42
|
-
|
|
43
|
-
case 'cds.Boolean': {
|
|
95
|
+
case 'cds.Boolean':
|
|
44
96
|
return faker_1.faker.datatype.boolean();
|
|
45
|
-
}
|
|
46
97
|
case 'cds.DateTime':
|
|
47
|
-
case 'cds.Timestamp':
|
|
98
|
+
case 'cds.Timestamp':
|
|
48
99
|
return faker_1.faker.date.past().toISOString();
|
|
49
|
-
|
|
50
|
-
|
|
100
|
+
case 'cds.LargeString':
|
|
101
|
+
return faker_1.faker.lorem.paragraph();
|
|
102
|
+
default:
|
|
51
103
|
return faker_1.faker.lorem.word();
|
|
52
|
-
}
|
|
53
104
|
}
|
|
54
105
|
}
|
|
55
106
|
generate(entity, count, parentIds) {
|
|
@@ -57,10 +108,14 @@ class FakerService {
|
|
|
57
108
|
for (let i = 0; i < count; i++) {
|
|
58
109
|
const row = {};
|
|
59
110
|
for (const prop of entity.properties) {
|
|
60
|
-
// to ile başlayan sanal ilişkiler veya many-to-many bağları temizce atlansın
|
|
61
111
|
if (prop.isAssociation)
|
|
62
112
|
continue;
|
|
63
|
-
|
|
113
|
+
if (prop.isKey) {
|
|
114
|
+
row[prop.name] = this.generateKeyValue(prop, i);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
row[prop.name] = this.generateValue(prop.name, prop.type, parentIds);
|
|
118
|
+
}
|
|
64
119
|
}
|
|
65
120
|
mockData.push(row);
|
|
66
121
|
}
|
|
@@ -86,7 +86,7 @@ class WizardService {
|
|
|
86
86
|
globalIdPool[shortName] = generatedIds;
|
|
87
87
|
const filteredEntity = {
|
|
88
88
|
...entity,
|
|
89
|
-
properties: entity.properties.filter(p => !p.isAssociation
|
|
89
|
+
properties: entity.properties.filter(p => !p.isAssociation)
|
|
90
90
|
};
|
|
91
91
|
const baseDir = path.dirname(path.dirname(path.resolve(schemaPath)));
|
|
92
92
|
const outputFolder = path.join(baseDir, 'db', 'data');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cap-mock-generator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "An interactive mock data generation engine for SAP CAP applications, leveraging the official @sap/cds-compiler by SAP for schema parsing.",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
"@google/genai": "^2.8.0",
|
|
33
33
|
"@inquirer/prompts": "^8.5.2",
|
|
34
34
|
"@sap/cds-compiler": "^6.9.2",
|
|
35
|
+
"cap-mock-generator": "file:cap-mock-generator-1.0.8.tgz",
|
|
35
36
|
"commander": "^15.0.0",
|
|
36
37
|
"csv-writer": "^1.6.0",
|
|
37
38
|
"dotenv": "^17.4.2",
|
|
38
39
|
"openai": "^6.42.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@types/dotenv": "^6.1.1",
|
|
42
42
|
"@types/node": "^25.9.2",
|
|
43
43
|
"typescript": "^6.0.3"
|
|
44
44
|
},
|