mushroom-cli 1.2.0-alpha.2 → 1.2.0-alpha.21

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 (46) hide show
  1. package/README.md +280 -111
  2. package/dist/check-update.js +6 -0
  3. package/dist/common.js +272 -0
  4. package/dist/config.js +394 -0
  5. package/dist/docs/bootstrap-theme.min.css +6 -0
  6. package/dist/docs/bootstrap.min.css +6 -0
  7. package/dist/docs/bootstrap.min.js +7 -0
  8. package/{docs → dist/docs}/doc-mt.js +103 -1
  9. package/{docs → dist/docs}/docs.html +83 -22
  10. package/dist/docs/docs.v2.html +5086 -0
  11. package/dist/docs/docs.v2.js +1922 -0
  12. package/dist/docs/jquery.min.js +4 -0
  13. package/dist/gen/gen-api-docs-v1.js +110 -0
  14. package/dist/gen/gen-api-docs.js +306 -0
  15. package/{gen → dist/gen}/gen-csharp.js +1246 -1414
  16. package/{gen → dist/gen}/gen-db-docs.js +204 -222
  17. package/{gen → dist/gen}/gen-js-driver-tarball.js +81 -101
  18. package/{gen → dist/gen}/gen-js-driver.js +116 -133
  19. package/dist/gen/gen-ts-driver.js +596 -0
  20. package/{gen.js → dist/gen.js} +109 -120
  21. package/{help.js → dist/help.js} +53 -55
  22. package/dist/init/init-json.js +92 -0
  23. package/dist/init/init-netcore.js +30 -0
  24. package/dist/init.js +23 -0
  25. package/dist/master-file/master-file.js +185 -0
  26. package/dist/merge.js +70 -0
  27. package/dist/mr.js +77 -0
  28. package/dist/types.js +1 -0
  29. package/dist/update/tsCode.js +82 -0
  30. package/dist/update.js +20 -0
  31. package/package.json +64 -27
  32. package/check-update.js +0 -9
  33. package/common.js +0 -236
  34. package/config.js +0 -445
  35. package/gen/gen-api-docs.js +0 -125
  36. package/gen/gen-ts-driver.js +0 -460
  37. package/init/init-json.js +0 -106
  38. package/init/init-netcore.js +0 -32
  39. package/init.js +0 -28
  40. package/master-file/master-file.js +0 -234
  41. package/merge.js +0 -84
  42. package/mr.js +0 -82
  43. package/update/tsCode.js +0 -20
  44. package/update.js +0 -24
  45. /package/{docs → dist/docs}/mt-dom-1.0.js +0 -0
  46. /package/{docs → dist/docs}/mt.extension.js +0 -0
@@ -0,0 +1,185 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import JSON5 from 'json5';
4
+ import * as common from '../common.js';
5
+ function transformValidationNode(validation) {
6
+ if (!validation || typeof validation !== 'object')
7
+ return;
8
+ if (!('min' in validation) && 'gte' in validation) {
9
+ validation.min = validation.gte;
10
+ }
11
+ if (!('max' in validation) && 'lte' in validation) {
12
+ validation.max = validation.lte;
13
+ }
14
+ }
15
+ function transformEntityFieldNode(field) {
16
+ if (!field || typeof field !== 'object')
17
+ return;
18
+ transformValidationNode(field.validation);
19
+ if (Array.isArray(field.items))
20
+ transformValidationNode(field.items.validation);
21
+ if (!field.fields || typeof field.fields !== 'object')
22
+ return;
23
+ for (const fieldName in field.fields) {
24
+ transformEntityFieldNode(field.fields[fieldName]);
25
+ }
26
+ }
27
+ function transformViewNode(view) {
28
+ if (!view || !Array.isArray(view.parameters))
29
+ return;
30
+ view.parameters.forEach((p) => transformValidationNode(p.validation));
31
+ }
32
+ function mergeApiProject(totalProject, fragmentProject, options) {
33
+ if (totalProject.name != null && fragmentProject.name != null && fragmentProject.name != totalProject.name)
34
+ throw new Error(`Unable merge project '${fragmentProject.name}' into '${totalProject.name}'`);
35
+ if (totalProject.version != null &&
36
+ fragmentProject.version != null &&
37
+ fragmentProject.version != totalProject.version)
38
+ throw new Error(`Unable merge project '${fragmentProject.version}' into '${totalProject.version}'`);
39
+ if (fragmentProject.environmentVariables != null) {
40
+ totalProject.environmentVariables = totalProject.environmentVariables || {};
41
+ for (const name in fragmentProject.environmentVariables) {
42
+ if (name in totalProject.environmentVariables) {
43
+ switch (options?.environmentVariable?.duplicateNameHandling) {
44
+ case 'override':
45
+ totalProject.environmentVariables[name] = fragmentProject.environmentVariables[name];
46
+ break;
47
+ case 'ignore':
48
+ break;
49
+ default:
50
+ throw new Error(`Duplicate environment variables: ${name}. Can config dublicate name handling behavior at options.environmentVariable.duplicateNameHandling`);
51
+ }
52
+ }
53
+ else
54
+ totalProject.environmentVariables[name] = fragmentProject.environmentVariables[name];
55
+ }
56
+ }
57
+ if (fragmentProject.entities != null) {
58
+ totalProject.entities = totalProject.entities || [];
59
+ fragmentProject.entities.forEach((entity) => {
60
+ const found = totalProject.entities.some((entityInTotal, i) => {
61
+ if (entityInTotal.name !== entity.name) {
62
+ return false;
63
+ }
64
+ switch (options?.entity?.duplicateNameHandling) {
65
+ case 'override':
66
+ totalProject.entities[i] = entity;
67
+ return true;
68
+ case 'ignore':
69
+ return true;
70
+ default:
71
+ throw new Error('Duplicate entity: ' +
72
+ entity.name +
73
+ '. Can config dublicate name handling behavior at options.entity.duplicateNameHandling');
74
+ }
75
+ });
76
+ if (found)
77
+ return;
78
+ totalProject.entities.push(entity);
79
+ if (!entity.fields || typeof entity.fields !== 'object')
80
+ return;
81
+ for (const fieldName in entity.fields) {
82
+ transformEntityFieldNode(entity.fields[fieldName]);
83
+ }
84
+ });
85
+ }
86
+ if (fragmentProject.views != null) {
87
+ totalProject.views = totalProject.views || {};
88
+ for (const viewName in fragmentProject.views) {
89
+ if (viewName in totalProject.views) {
90
+ switch (options?.view?.duplicateNameHandling) {
91
+ case 'override':
92
+ totalProject.views[viewName] = fragmentProject.views[viewName];
93
+ break;
94
+ case 'ignore':
95
+ continue;
96
+ default:
97
+ throw new Error('Duplicate global view: ' +
98
+ viewName +
99
+ '. Can config dublicate name handling behavior at options.views.duplicateNameHandling');
100
+ }
101
+ }
102
+ else
103
+ totalProject.views[viewName] = fragmentProject.views[viewName];
104
+ if (!fragmentProject.views[viewName] || !Array.isArray(fragmentProject.views[viewName])) {
105
+ delete fragmentProject.views[viewName];
106
+ continue;
107
+ }
108
+ fragmentProject.views[viewName].forEach(transformViewNode);
109
+ }
110
+ }
111
+ for (const name in fragmentProject) {
112
+ if (name === 'environmentVariables' || name === 'entities' || name === 'views' || name === '$schema')
113
+ continue;
114
+ totalProject[name] = fragmentProject[name];
115
+ }
116
+ return totalProject;
117
+ }
118
+ export function processMasterFile(basePath, master) {
119
+ if (master.fragments == null || master.fragments.length == 0)
120
+ return null;
121
+ let apiProject = {};
122
+ master.fragments.forEach((fragment) => {
123
+ let apiProjectFragment;
124
+ const fragmentPath = path.join(basePath, fragment.path);
125
+ common.logInfo('Merging fragment file:', fragmentPath);
126
+ try {
127
+ const content = fs.readFileSync(fragmentPath).toString();
128
+ apiProjectFragment = JSON5.parse(content);
129
+ }
130
+ catch (e) {
131
+ if (fragment.optional) {
132
+ common.logWarning(fragmentPath, 'not found or unable to parse');
133
+ return;
134
+ }
135
+ common.logError(fragmentPath, 'not found or unable to parse');
136
+ throw e;
137
+ }
138
+ apiProject = mergeApiProject(apiProject, apiProjectFragment, master.options);
139
+ });
140
+ apiProject['$schema'] = 'https://schema.siten.vn/mushroom/project.json';
141
+ if (apiProject.entities == null)
142
+ apiProject.entities = [];
143
+ apiProject.entities.forEach((entity) => {
144
+ if (entity.actions == null)
145
+ entity.actions = {};
146
+ for (const actionName in entity.actions) {
147
+ if ((actionName != 'findMany' && actionName != 'findById') || entity.actions[actionName] == null)
148
+ continue;
149
+ entity.actions[actionName].forEach((action) => {
150
+ if (action.fields) {
151
+ action.defaultFields = action.fields.split(',');
152
+ delete action.fields;
153
+ }
154
+ if (action.allowFields) {
155
+ action.returnableFields = action.allowFields.split(',');
156
+ delete action.allowFields;
157
+ }
158
+ if (actionName !== 'findMany')
159
+ return;
160
+ const findManyAction = action;
161
+ if (findManyAction.sorting) {
162
+ findManyAction.defaultSortings = findManyAction.sorting.split(',').map((f) => {
163
+ const c = f.charAt(0);
164
+ return {
165
+ field: c === '+' || c === '-' ? f.substring(1) : f,
166
+ type: c === '-' ? 'Desc' : 'Asc',
167
+ };
168
+ });
169
+ delete findManyAction.sorting;
170
+ }
171
+ if (findManyAction.allowSorting) {
172
+ findManyAction.allowSortings = findManyAction.allowSorting.split(',').map((f) => {
173
+ const c = f.charAt(0);
174
+ return {
175
+ field: c === '+' || c === '-' ? f.substring(1) : f,
176
+ type: c === '-' ? 'Desc' : c === '+' ? 'Asc' : 'Both',
177
+ };
178
+ });
179
+ delete findManyAction.allowSorting;
180
+ }
181
+ });
182
+ }
183
+ });
184
+ return apiProject;
185
+ }
package/dist/merge.js ADDED
@@ -0,0 +1,70 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import JSON5 from 'json5';
4
+ import * as common from './common.js';
5
+ import help from './help.js';
6
+ import * as masterFile from './master-file/master-file.js';
7
+ export default async function merge(args) {
8
+ let projectName = args[1];
9
+ const output = args[2];
10
+ if (!projectName || !output) {
11
+ help(args);
12
+ return;
13
+ }
14
+ let alias = 'default';
15
+ const atIndex = projectName.indexOf('@');
16
+ if (atIndex !== -1) {
17
+ alias = projectName.substring(atIndex + 1);
18
+ projectName = projectName.substring(0, atIndex);
19
+ if (!projectName) {
20
+ help(args);
21
+ return;
22
+ }
23
+ if (!alias)
24
+ alias = 'default';
25
+ }
26
+ let mushroomConfig;
27
+ try {
28
+ const mushroomConfigContent = fs.readFileSync('./mushroom-config.json').toString();
29
+ mushroomConfig = JSON.parse(mushroomConfigContent);
30
+ }
31
+ catch (e) {
32
+ common.logError('mushroom-config.json not found or unable to parse');
33
+ throw e;
34
+ }
35
+ if (!mushroomConfig || typeof mushroomConfig !== 'object')
36
+ throw new Error(`Invalid configuration. Please re-check file mushroom-config.json`);
37
+ if (!mushroomConfig || !mushroomConfig.projects || !mushroomConfig.projects[projectName])
38
+ throw new Error(`Project not found (${projectName})`);
39
+ const project = mushroomConfig.projects[projectName];
40
+ if (!project.src)
41
+ throw new Error('Project source (src) not found');
42
+ let master;
43
+ try {
44
+ const sourceContent = fs.readFileSync(project.src).toString();
45
+ master = JSON5.parse(sourceContent);
46
+ }
47
+ catch (e) {
48
+ common.logError(project.src, 'not found or unable to parse');
49
+ throw e;
50
+ }
51
+ if (!master || typeof master !== 'object')
52
+ throw new Error(`Invalid api project configuration. Please re-check file ${project.src}`);
53
+ let projectApi = null;
54
+ if (Array.isArray(master.fragments)) {
55
+ common.logInfo('Process master file:', project.src);
56
+ projectApi = masterFile.processMasterFile(path.dirname(project.src), master);
57
+ }
58
+ else {
59
+ projectApi = master;
60
+ }
61
+ if (!projectApi || typeof projectApi !== 'object') {
62
+ throw new Error(`Invalid api project configuration. Please re-check file ${project.src}`);
63
+ }
64
+ if (projectApi.name !== projectName) {
65
+ throw new Error(`Project name is mismatched (${projectName} & ${projectApi.name})`);
66
+ }
67
+ common.ensureFolder(output);
68
+ fs.writeFileSync(output, JSON.stringify(projectApi, null, master.options?.formatIndent ? ' ' : undefined));
69
+ common.logInfo(`Merged ${projectName}@${alias} then saved to ${output}`);
70
+ }
package/dist/mr.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import * as common from './common.js';
3
+ import init from './init.js';
4
+ import config from './config.js';
5
+ import gen from './gen.js';
6
+ import merge from './merge.js';
7
+ import update from './update.js';
8
+ import help from './help.js';
9
+ import checkUpdate from './check-update.js';
10
+ const packageVersion = common.getPackageVersion();
11
+ const versionGroup = packageVersion.match(/([^-]+)(-(\w+).*)?/);
12
+ const currentDistTag = versionGroup?.[3] ? versionGroup[3] : 'latest';
13
+ common.logInfo('Mushroom CLI version', packageVersion);
14
+ async function run(args) {
15
+ let debugMode = false;
16
+ if (args.indexOf('--debug') !== -1) {
17
+ debugMode = true;
18
+ args = args.filter((arg) => arg !== '--debug');
19
+ }
20
+ let checkUpdateTask;
21
+ if (args.indexOf('--no-check-update') !== -1) {
22
+ args = args.filter((arg) => arg !== '--no-check-update');
23
+ checkUpdateTask = null;
24
+ }
25
+ else {
26
+ checkUpdateTask = checkUpdate();
27
+ checkUpdateTask.catch(() => { });
28
+ }
29
+ const startTime = new Date().getTime();
30
+ try {
31
+ switch (args[0]) {
32
+ case 'init':
33
+ await init(args);
34
+ break;
35
+ case 'config':
36
+ await config(args);
37
+ break;
38
+ case 'gen':
39
+ await gen(args);
40
+ break;
41
+ case 'merge':
42
+ merge(args);
43
+ break;
44
+ case 'update':
45
+ await update(args);
46
+ break;
47
+ case 'help':
48
+ case 'man':
49
+ help(args.slice(1).join());
50
+ break;
51
+ default:
52
+ help(args, true);
53
+ break;
54
+ }
55
+ }
56
+ catch (e) {
57
+ common.logError(debugMode ? e : 'ERROR: ' + e.message);
58
+ }
59
+ finally {
60
+ common.logInfo('Processed in', new Date().getTime() - startTime, 'ms.');
61
+ }
62
+ if (checkUpdateTask !== null)
63
+ try {
64
+ const data = await checkUpdateTask;
65
+ if (data['dist-tags'] &&
66
+ data['dist-tags'][currentDistTag] &&
67
+ data['dist-tags'][currentDistTag] !== packageVersion) {
68
+ common.logWarning(`YOUR mushroom-cli VERSION IS NOT LATEST (dist-tags: ${currentDistTag}). PLEASE RUN: npm i mushroom-cli@${data['dist-tags'][currentDistTag]} OR yarn add mushroom-cli@^${data['dist-tags'][currentDistTag]}`);
69
+ }
70
+ }
71
+ catch (e) {
72
+ if (debugMode)
73
+ common.logError(e);
74
+ }
75
+ }
76
+ const [, , ...args] = process.argv;
77
+ run(args);
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,82 @@
1
+ import fs from 'fs';
2
+ import fetch from 'node-fetch';
3
+ import * as common from '../common.js';
4
+ export default async function updateTsCode(options) {
5
+ if (options.input || options.output) {
6
+ if (!options.output) {
7
+ common.logError('Missing output file path');
8
+ return;
9
+ }
10
+ if (!options.input) {
11
+ common.logError('Missing remote url');
12
+ return;
13
+ }
14
+ pullAsync({
15
+ action: 'pull',
16
+ source: options.input,
17
+ destination: options.output,
18
+ });
19
+ common.logInfo('Finish update ts-code');
20
+ return;
21
+ }
22
+ if (!fs.existsSync('mushroom-config.json')) {
23
+ common.logError('Missing mushroom-config.json file');
24
+ return;
25
+ }
26
+ const configJson = fs.readFileSync('mushroom-config.json').toString();
27
+ const config = JSON.parse(configJson);
28
+ if (!config.update) {
29
+ common.logError("Missing 'update' in mushroom-config.json file");
30
+ return;
31
+ }
32
+ if (!config.update['ts-code']) {
33
+ common.logError("Missing 'update.ts-code' in mushroom-config.json file");
34
+ return;
35
+ }
36
+ const steps = config.update['ts-code'].steps;
37
+ if (!steps) {
38
+ common.logError("Missing 'update.ts-code.steps' in mushroom-config.json file");
39
+ return;
40
+ }
41
+ for (let i = 0; i < steps.length; i++) {
42
+ const step = steps[i];
43
+ const actionName = step.action;
44
+ switch (actionName) {
45
+ case 'pull':
46
+ await pullAsync(step);
47
+ break;
48
+ case 'replace-content':
49
+ replaceContent(step);
50
+ break;
51
+ case 'replace-regex':
52
+ replaceRegex(step);
53
+ break;
54
+ default:
55
+ common.logWarning('Unsupported step action:', actionName);
56
+ break;
57
+ }
58
+ }
59
+ common.logInfo('Finish update ts-code');
60
+ }
61
+ async function pullAsync(step) {
62
+ common.logInfo('Fetch', step.source);
63
+ const res = await fetch(step.source);
64
+ common.logInfo('Write to', step.destination);
65
+ fs.writeFileSync(step.destination, await res.text());
66
+ }
67
+ function replaceContent(step) {
68
+ common.logInfo('Replace', step.search, 'by', step.replacement, 'in', step.source, 'file');
69
+ const content = fs.readFileSync(step.source).toString();
70
+ if (!content)
71
+ return;
72
+ const output = content.replace(new RegExp(step.search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), step.replacement);
73
+ fs.writeFileSync(step.source, output);
74
+ }
75
+ function replaceRegex(step) {
76
+ common.logInfo('Replace pattern', step.pattern, 'by', step.replacement, 'in', step.source, 'file');
77
+ const content = fs.readFileSync(step.source).toString();
78
+ if (!content)
79
+ return;
80
+ const output = content.replace(new RegExp(step.pattern, 'g'), step.replacement);
81
+ fs.writeFileSync(step.source, output);
82
+ }
package/dist/update.js ADDED
@@ -0,0 +1,20 @@
1
+ import help from './help.js';
2
+ import updateTsCode from './update/tsCode.js';
3
+ export default async function update(args) {
4
+ const command = args[1];
5
+ switch (command) {
6
+ case 'ts-code':
7
+ await updateTsCode({
8
+ input: args[3],
9
+ output: args[2],
10
+ });
11
+ break;
12
+ case 'help':
13
+ case 'man':
14
+ help(args);
15
+ break;
16
+ default:
17
+ help(args, true);
18
+ break;
19
+ }
20
+ }
package/package.json CHANGED
@@ -1,27 +1,64 @@
1
- {
2
- "name": "mushroom-cli",
3
- "version": "1.2.0-alpha.2",
4
- "description": "Mushroom CLI",
5
- "main": "mr.js",
6
- "scripts": {
7
- "release": "npm publish --access public --tag alpha"
8
- },
9
- "keywords": [
10
- "Mushroom",
11
- "CLI"
12
- ],
13
- "bin": {
14
- "mushroom-cli": "mr.js",
15
- "mr": "mr.js"
16
- },
17
- "author": "suco2007",
18
- "license": "ISC",
19
- "dependencies": {
20
- "jsdom": "^21.0.0",
21
- "json5": "^2.2.3",
22
- "node-fetch": "^2.6.7",
23
- "open": "^8.4.0",
24
- "readline-sync": "^1.4.10",
25
- "targz": "^1.0.1"
26
- }
27
- }
1
+ {
2
+ "name": "mushroom-cli",
3
+ "version": "1.2.0-alpha.21",
4
+ "description": "Mushroom CLI",
5
+ "main": "dist/mr.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "tsc && copyfiles -u 2 ./src/docs/* ./dist/docs/",
9
+ "format": "prettier --write --ignore-unknown **/*",
10
+ "lint": "eslint ./src/**/*.ts",
11
+ "release": "npm run build && npm publish --access public --tag alpha",
12
+ "preinstall": "npx only-allow npm",
13
+ "prepare": "husky"
14
+ },
15
+ "lint-staged": {
16
+ "!(*.ts)": "prettier --write --ignore-unknown",
17
+ "src/**/*.ts": [
18
+ "eslint --quiet",
19
+ "prettier --write"
20
+ ]
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "keywords": [
26
+ "Mushroom",
27
+ "CLI"
28
+ ],
29
+ "bin": {
30
+ "mushroom-cli": "dist/mr.js",
31
+ "mr": "dist/mr.js"
32
+ },
33
+ "author": "suco2007",
34
+ "license": "ISC",
35
+ "dependencies": {
36
+ "jsdom": "^25.0.1",
37
+ "json5": "^2.2.3",
38
+ "minify": "^11.4.1",
39
+ "node-fetch": "^3.3.2",
40
+ "open": "^10.1.0",
41
+ "readline-sync": "^1.4.10",
42
+ "targz": "^1.0.1"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.11.1",
46
+ "@types/jsdom": "^21.1.7",
47
+ "@types/minify": "^9.1.4",
48
+ "@types/node": "^22.7.4",
49
+ "@types/node-fetch": "^2.6.11",
50
+ "@types/readline-sync": "^1.4.8",
51
+ "@types/targz": "^1.0.4",
52
+ "copyfiles": "^2.4.1",
53
+ "eslint": "^9.11.1",
54
+ "husky": "^9.1.6",
55
+ "lint-staged": "^15.2.10",
56
+ "only-allow": "^1.2.1",
57
+ "prettier": "^3.3.3",
58
+ "typescript": "^5.6.2",
59
+ "typescript-eslint": "^8.8.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=14.0.0"
63
+ }
64
+ }
package/check-update.js DELETED
@@ -1,9 +0,0 @@
1
- const fetch = require('node-fetch');
2
-
3
-
4
- function checkUpdate() {
5
- return fetch('https://registry.npmjs.org/mushroom-cli/')
6
- .then(res => res.json());
7
- }
8
-
9
- module.exports = checkUpdate;