mushroom-cli 1.2.0-alpha.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +199 -154
  2. package/dist/check-update.js +6 -0
  3. package/dist/common.js +280 -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/dist/docs/doc-mt.js +633 -0
  9. package/dist/docs/docs.html +5380 -0
  10. package/{docs → dist/docs}/docs.v2.html +5205 -6615
  11. package/dist/docs/docs.v2.js +2036 -0
  12. package/dist/docs/jquery.min.js +4 -0
  13. package/dist/docs/mt-dom-1.0.js +1398 -0
  14. package/dist/docs/mt.extension.js +199 -0
  15. package/dist/gen/gen-api-docs-v1.js +110 -0
  16. package/dist/gen/gen-api-docs.js +327 -0
  17. package/{gen → dist/gen}/gen-csharp.js +1256 -1399
  18. package/{gen → dist/gen}/gen-db-docs.js +204 -222
  19. package/{gen → dist/gen}/gen-js-driver-tarball.js +81 -101
  20. package/{gen → dist/gen}/gen-js-driver.js +116 -133
  21. package/dist/gen/gen-ts-driver.js +600 -0
  22. package/{gen.js → dist/gen.js} +109 -124
  23. package/{help.js → dist/help.js} +53 -55
  24. package/dist/init/init-json.js +92 -0
  25. package/dist/init/init-netcore.js +30 -0
  26. package/dist/init.js +23 -0
  27. package/dist/master-file/master-file.js +185 -0
  28. package/dist/merge.js +70 -0
  29. package/dist/mr.js +77 -0
  30. package/dist/types.js +1 -0
  31. package/dist/update/tsCode.js +82 -0
  32. package/dist/update.js +20 -0
  33. package/package.json +64 -28
  34. package/check-update.js +0 -9
  35. package/common.js +0 -273
  36. package/config.js +0 -445
  37. package/docs/doc-mt.js +0 -523
  38. package/docs/docs.html +0 -5190
  39. package/docs/mt-dom-1.0.js +0 -1268
  40. package/docs/mt.extension.js +0 -174
  41. package/gen/gen-api-docs-v1.js +0 -125
  42. package/gen/gen-api-docs.js +0 -259
  43. package/gen/gen-ts-driver.js +0 -471
  44. package/init/init-json.js +0 -106
  45. package/init/init-netcore.js +0 -32
  46. package/init.js +0 -28
  47. package/master-file/master-file.js +0 -234
  48. package/merge.js +0 -84
  49. package/mr.js +0 -86
  50. package/update/tsCode.js +0 -20
  51. package/update.js +0 -24
@@ -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,28 +1,64 @@
1
- {
2
- "name": "mushroom-cli",
3
- "version": "1.2.0-alpha.8",
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-comments": "node-fetch: 2.x; open: 8.x",
20
- "dependencies": {
21
- "jsdom": "^22.1.0",
22
- "json5": "^2.2.3",
23
- "node-fetch": "^2.6.11",
24
- "open": "^8.4.2",
25
- "readline-sync": "^1.4.10",
26
- "targz": "^1.0.1"
27
- }
28
- }
1
+ {
2
+ "name": "mushroom-cli",
3
+ "version": "1.2.0",
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",
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": "^26.1.0",
37
+ "json5": "^2.2.3",
38
+ "minify": "^14.0.0",
39
+ "node-fetch": "^3.3.2",
40
+ "open": "^10.1.2",
41
+ "readline-sync": "^1.4.10",
42
+ "targz": "^1.0.1"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.28.0",
46
+ "@types/jsdom": "^21.1.7",
47
+ "@types/minify": "^9.1.4",
48
+ "@types/node": "^22.15.29",
49
+ "@types/node-fetch": "^2.6.12",
50
+ "@types/readline-sync": "^1.4.8",
51
+ "@types/targz": "^1.0.5",
52
+ "copyfiles": "^2.4.1",
53
+ "eslint": "^9.28.0",
54
+ "husky": "^9.1.7",
55
+ "lint-staged": "^16.1.0",
56
+ "only-allow": "^1.2.1",
57
+ "prettier": "^3.5.3",
58
+ "typescript": "^5.8.3",
59
+ "typescript-eslint": "^8.33.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;