mushroom-cli 1.2.7 → 2.0.0-alpha.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,52 @@
1
+ import * as common from '../common.js';
2
+ export function listApi(source) {
3
+ const entities = common.getEntities(source, ['*'], true);
4
+ const endpoints = new Set();
5
+ for (const entityName in entities) {
6
+ const actions = entities[entityName].actions || {};
7
+ for (const actionName in actions) {
8
+ const action = actions[actionName];
9
+ if (!Array.isArray(action) || !action.length || action.every((a) => !a.enabled))
10
+ continue;
11
+ let method;
12
+ let id = '';
13
+ if (actionName == 'findById') {
14
+ method = 'GET';
15
+ id = '/{{id}}';
16
+ }
17
+ if (actionName == 'findMany')
18
+ method = 'GET';
19
+ else if (actionName == 'createOne' || actionName == 'createMany')
20
+ method = 'POST';
21
+ else if (actionName?.startsWith('_raw_http_method_')) {
22
+ method = 'POST';
23
+ id = '/' + actionName.substring('_raw_http_method_'.length);
24
+ }
25
+ else if (actionName == 'updateOne') {
26
+ method = 'PUT';
27
+ id = '/{{id}}';
28
+ }
29
+ else if (actionName == 'updateMany')
30
+ method = 'PUT';
31
+ else if (actionName == 'updatePartially') {
32
+ method = 'PATCH';
33
+ id = '/{{id}}';
34
+ }
35
+ else if (actionName == 'deleteOne') {
36
+ method = 'DELETE';
37
+ id = '/{{id}}';
38
+ }
39
+ else if (actionName == 'deleteMany')
40
+ method = 'DELETE';
41
+ endpoints.add(`${method} ${source.rootUrl}${entityName}s${id}`);
42
+ }
43
+ const views = entities[entityName].views || {};
44
+ for (const viewName in views) {
45
+ const view = views[viewName];
46
+ if (!Array.isArray(view) || !view.length || view.every((v) => !v.enabled))
47
+ continue;
48
+ endpoints.add(`GET ${source.rootUrl}${entityName}s/views/${viewName}`);
49
+ }
50
+ }
51
+ endpoints.forEach((e) => console.log(e));
52
+ }
package/dist/gen.js CHANGED
@@ -5,11 +5,10 @@ import help from './help.js';
5
5
  import * as common from './common.js';
6
6
  import * as masterFile from './master-file/master-file.js';
7
7
  import genApiDocs from './gen/gen-api-docs.js';
8
- import genApiDocsV1 from './gen/gen-api-docs-v1.js';
9
8
  import genDatabaseDocs from './gen/gen-db-docs.js';
10
9
  import * as javascriptDriverGenerator from './gen/gen-js-driver.js';
11
- import genJavascriptDriverTarball from './gen/gen-js-driver-tarball.js';
12
10
  import * as typescriptDriverGenerator from './gen/gen-ts-driver.js';
11
+ import * as listApi from './gen/gen-list-api.js';
13
12
  import * as csharp from './gen/gen-csharp.js';
14
13
  export default async function gen(args) {
15
14
  let projectName = args[1];
@@ -73,10 +72,10 @@ export default async function gen(args) {
73
72
  const type = args[2];
74
73
  switch (type) {
75
74
  case 'docs':
76
- if (args.includes('v1'))
77
- await genApiDocsV1(args.filter((p) => p != 'v1'), projectName, project, alias, source);
78
- else
79
- await genApiDocs(args, projectName, project, alias, source);
75
+ if (args.includes('v1')) {
76
+ common.logWarning('Parameter v1 is ignored');
77
+ }
78
+ await genApiDocs(args, projectName, project, alias, source);
80
79
  break;
81
80
  case 'db-docs':
82
81
  genDatabaseDocs(args, projectName, project, alias, source);
@@ -84,9 +83,6 @@ export default async function gen(args) {
84
83
  case 'js-driver':
85
84
  javascriptDriverGenerator.genJavascriptDriver(args, projectName, project, alias, source);
86
85
  break;
87
- case 'js-driver-tarball':
88
- await genJavascriptDriverTarball(args, projectName, project, alias, source);
89
- break;
90
86
  case 'ts-driver':
91
87
  typescriptDriverGenerator.genTypescriptDriver(args, projectName, project, alias, source);
92
88
  break;
@@ -96,7 +92,9 @@ export default async function gen(args) {
96
92
  case 'c#-driver':
97
93
  csharp.genCSharpDriver(args, projectName, project, alias, source);
98
94
  break;
99
- case '':
95
+ case 'list-api':
96
+ listApi.listApi(source);
97
+ break;
100
98
  case undefined:
101
99
  case 'help':
102
100
  case 'man':
package/dist/help.js CHANGED
@@ -13,25 +13,25 @@ export default function help(key, wrong) {
13
13
  npx mushroom-cli init json ./api/SampleProject.json [silent]
14
14
 
15
15
  Init a dotnet core project which pre-install Mushroom Server
16
- npx mushroom-cli init netcore
16
+ npx mushroom-cli init netcore [--version 0.2|0.3|latest|alpha]
17
17
 
18
18
  Add the mushroom json file into mushroom-config.json
19
19
  npx mushroom-cli config add ./api/yourProjectName.json
20
20
 
21
21
  Config gen docs api
22
- npx mushroom-cli config gen projectName docs ./wwwroot/docs.html [alias aliasName] [features file,auth,mail,driver] [roles Admin,User-Contributor]
22
+ npx mushroom-cli config gen projectName docs ./wwwroot/docs.html [alias aliasName]
23
23
 
24
24
  Generate docs api (html format)
25
25
  npx mushroom-cli gen projectName[@aliasName] docs [tmp]
26
26
 
27
27
  Config gen database docs
28
- npx mushroom-cli config gen projectName db-docs ./wwwroot/db-docs.html [alias aliasName] [features file,auth,mail]
28
+ npx mushroom-cli config gen projectName db-docs ./wwwroot/db-docs.html [alias aliasName]
29
29
 
30
30
  Generate database docs (html format)
31
31
  npx mushroom-cli gen projectName[@aliasName] db-docs [tmp]
32
32
 
33
33
  Config gen javascript driver
34
- npx mushroom-cli config gen projectName js-driver ./src/api/mushroom.api.js [alias aliasName] [roles Admin,User-Contributor] [tarball tarballName]
34
+ npx mushroom-cli config gen projectName js-driver ./src/api/mushroom.api.js [alias aliasName]
35
35
 
36
36
  Generate javascript driver
37
37
  npx mushroom-cli gen projectName[@aliasName] js-driver
@@ -43,7 +43,7 @@ Generate entities for Mushroom project in CSharp and using MongoDb
43
43
  npx mushroom-cli gen projectName[@aliasName] c#-mongo
44
44
 
45
45
  Config gen entities for CSharp project which calls Mushroom API
46
- npx mushroom-cli config gen projectName c#-driver ./API/Generated.cs [roles Admin,User-Contributor] [alias aliasName]
46
+ npx mushroom-cli config gen projectName c#-driver ./API/Generated.cs [alias aliasName]
47
47
 
48
48
  Generate entities for CSharp project which calls Mushroom API
49
49
  npx mushroom-cli gen projectName[@aliasName] c#-driver
@@ -1,13 +1,27 @@
1
1
  import { spawn } from 'child_process';
2
2
  import * as common from '../common.js';
3
- function fetchFromGit() {
3
+ import * as templateProcessor from './netcore/templateProcessor.js';
4
+ const branches = {
5
+ '0.2': '0.2',
6
+ '0.3': 'latest',
7
+ latest: 'latest',
8
+ alpha: 'alpha',
9
+ };
10
+ function fetchFromGit(version) {
4
11
  return new Promise((resolve, reject) => {
12
+ const branch = branches[version];
13
+ if (!branch) {
14
+ reject(new Error('Unknown version ' + version));
15
+ return;
16
+ }
5
17
  const git = spawn('git', [
6
18
  'clone',
7
- 'https://tfs.siten.vn:8080/tfs/Siten/CodeBase/_git/Mushroom',
19
+ 'https://tfs.siten.vn:8080/Siten/CodeBase/_git/Mushroom',
8
20
  '-b',
9
- 'full_extensions',
21
+ branch,
10
22
  '--single-branch',
23
+ '--depth',
24
+ '1',
11
25
  ]);
12
26
  git.stdout.on('data', (data) => {
13
27
  common.logInfo('GIT:', data?.toString());
@@ -25,6 +39,13 @@ function fetchFromGit() {
25
39
  });
26
40
  }
27
41
  export default async function initNetCore(args) {
28
- await fetchFromGit();
29
- common.processTemplate('Mushroom', 'mushroom-template.json');
42
+ let version;
43
+ for (let i = 2; i < args.length; i++) {
44
+ if (args[i] === '--version') {
45
+ version = args[i + 1];
46
+ i++;
47
+ }
48
+ }
49
+ await fetchFromGit(version ?? 'latest');
50
+ templateProcessor.process('Mushroom', 'mushroom-template.json');
30
51
  }
@@ -0,0 +1,182 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import readlineSync from 'readline-sync';
4
+ import * as common from '../../common.js';
5
+ export function process(basePath, templatePath) {
6
+ const templateJsonContent = fs.readFileSync(path.join(basePath, templatePath)).toString();
7
+ const template = JSON.parse(templateJsonContent);
8
+ if (template && typeof template !== 'object') {
9
+ throw new TypeError(`Invalid template file ${templatePath}`);
10
+ }
11
+ const commands = template.steps;
12
+ if (!Array.isArray(commands)) {
13
+ throw new TypeError(`Invalid template file ${templatePath}`);
14
+ }
15
+ const variables = {};
16
+ commands.forEach((command) => processCommand(command, basePath, variables));
17
+ return variables;
18
+ }
19
+ function processCommand(command, basePath, variables) {
20
+ const commandName = command.command;
21
+ switch (commandName) {
22
+ case 'input':
23
+ processInputCommand(command, variables);
24
+ return;
25
+ case 'set':
26
+ processSetCommand(command, variables);
27
+ return;
28
+ case 'rename':
29
+ processRenameCommand(command, basePath, variables);
30
+ return;
31
+ case 'delete':
32
+ processDeleteCommand(command, basePath, variables);
33
+ return;
34
+ case 'replace':
35
+ processReplaceCommand(command, basePath, variables);
36
+ return;
37
+ default:
38
+ throw new Error(`Unknown command: ${commandName}`);
39
+ }
40
+ }
41
+ function processInputCommand(command, variables) {
42
+ const value = readlineSync.question(command.message ?? '');
43
+ if (command.validation) {
44
+ if (command.validation.required) {
45
+ if (value === '')
46
+ throw new TypeError(`${command.variable} is required`);
47
+ }
48
+ if (command.validation.pattern) {
49
+ if (!new RegExp(command.validation.pattern).test(value))
50
+ throw new Error(`${value} is not valid`);
51
+ }
52
+ }
53
+ variables[command.variable] = value;
54
+ }
55
+ function processSetCommand(command, variables) {
56
+ switch (command['function']) {
57
+ case 'New-GUID':
58
+ processSetNewGuidCommand(command.variable, variables);
59
+ break;
60
+ case 'New-RandomNumber':
61
+ processSetNewRandomNumberCommand(command.variable, variables, command.min, command.max);
62
+ break;
63
+ case 'New-RandomString':
64
+ processSetNewRandomStringCommand(command.variable, variables, command.length, command.characterPool);
65
+ break;
66
+ case 'ToLowerCase':
67
+ toLowerCommand(command.variable, variables, command.input);
68
+ break;
69
+ case 'ToUpperCase':
70
+ toUpperCaseCommand(command.variable, variables, command.input);
71
+ break;
72
+ case 'Trim':
73
+ trimCommand(command.variable, variables, command.input);
74
+ break;
75
+ case 'Replace':
76
+ replaceCommand(command.variable, variables, command.input, command.replacement, command.pattern, command.mode);
77
+ break;
78
+ default:
79
+ throw new Error(`Unknown set-command: ${command['function']}`);
80
+ }
81
+ }
82
+ function processSetNewGuidCommand(variable, variables) {
83
+ variables[variable] = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
84
+ .replace(/[xy]/g, (c) => {
85
+ const r = (Math.random() * 16) | 0;
86
+ const v = c == 'x' ? r : (r & 0x3) | 0x8;
87
+ return v.toString(16);
88
+ })
89
+ .toUpperCase();
90
+ }
91
+ function processSetNewRandomNumberCommand(variable, variables, min = 0, max = (1 << 30) * 4) {
92
+ variables[variable] = Math.floor(min + Math.random() * (max - min)).toString();
93
+ }
94
+ function processSetNewRandomStringCommand(variable, variables, length, characterPool = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM') {
95
+ let result = '';
96
+ for (let i = 0; i < length; i++) {
97
+ result += characterPool.charAt(Math.floor(Math.random() * characterPool.length));
98
+ }
99
+ variables[variable] = result;
100
+ }
101
+ function toLowerCommand(variable, variables, input) {
102
+ variables[variable] = variables[input].toLowerCase();
103
+ }
104
+ function toUpperCaseCommand(variable, variables, input) {
105
+ variables[variable] = variables[input].toUpperCase();
106
+ }
107
+ function trimCommand(variable, variables, input) {
108
+ variables[variable] = variables[input].trim();
109
+ }
110
+ function replaceCommand(variable, variables, input, replacement, pattern, mode) {
111
+ const regex = new RegExp(pattern, mode);
112
+ variables[variable] = variables[input].replace(regex, replacement);
113
+ }
114
+ function processRenameCommand(command, basePath, variables) {
115
+ const input = replaceVariables(command.input, variables);
116
+ const output = replaceVariables(command.output, variables);
117
+ fs.renameSync(path.join(basePath, input), path.join(basePath, output));
118
+ }
119
+ function processDeleteCommand(command, basePath, variables) {
120
+ const input = replaceVariables(command.input, variables);
121
+ const deletedPath = path.join(basePath, input);
122
+ if (fs.lstatSync(deletedPath).isDirectory()) {
123
+ fs.rmSync(deletedPath, { recursive: true, force: true });
124
+ }
125
+ else {
126
+ fs.rmSync(deletedPath, { force: true });
127
+ }
128
+ }
129
+ function processReplaceCommand(command, basePath, variables) {
130
+ const files = command.input;
131
+ const pattern = new RegExp(command.pattern ?? '', 'g');
132
+ const replacement = replaceVariables(command.replacement ?? '', variables);
133
+ files.forEach((file) => {
134
+ const resolvedInput = replaceVariables(file, variables);
135
+ const filePaths = resolveInputPaths(basePath, resolvedInput);
136
+ if (filePaths.length === 0) {
137
+ common.logWarning(`File ${file} does not exist, skipping...`);
138
+ return;
139
+ }
140
+ filePaths.forEach((filePath) => {
141
+ let content = fs.readFileSync(filePath).toString();
142
+ content = content.replace(pattern, () => replacement);
143
+ fs.writeFileSync(filePath, content);
144
+ });
145
+ });
146
+ }
147
+ function resolveInputPaths(basePath, input) {
148
+ const fileName = path.basename(input);
149
+ if (/[*?]/.test(fileName)) {
150
+ const dir = path.join(basePath, path.dirname(input));
151
+ if (!fs.existsSync(dir)) {
152
+ return [];
153
+ }
154
+ return findFilesByGlob(dir, globToRegExp(fileName));
155
+ }
156
+ const filePath = path.join(basePath, input);
157
+ return fs.existsSync(filePath) ? [filePath] : [];
158
+ }
159
+ function globToRegExp(glob) {
160
+ const pattern = glob
161
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
162
+ .replace(/\*/g, '.*')
163
+ .replace(/\?/g, '.');
164
+ return new RegExp(`^${pattern}$`, 'i');
165
+ }
166
+ function findFilesByGlob(dir, fileNamePattern) {
167
+ const results = [];
168
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
169
+ entries.forEach((entry) => {
170
+ const entryPath = path.join(dir, entry.name);
171
+ if (entry.isDirectory()) {
172
+ results.push(...findFilesByGlob(entryPath, fileNamePattern));
173
+ }
174
+ else if (fileNamePattern.test(entry.name)) {
175
+ results.push(entryPath);
176
+ }
177
+ });
178
+ return results;
179
+ }
180
+ function replaceVariables(str, variables) {
181
+ return str.replace(/\$\{(\w+)\}/g, (_, varName) => variables[varName] ?? '');
182
+ }
package/package.json CHANGED
@@ -1,16 +1,14 @@
1
1
  {
2
2
  "name": "mushroom-cli",
3
- "version": "1.2.7",
3
+ "version": "2.0.0-alpha.0",
4
4
  "description": "Mushroom CLI",
5
- "main": "dist/mr.js",
6
5
  "type": "module",
7
6
  "scripts": {
8
7
  "build": "tsc && copyfiles -u 2 ./src/docs/* ./dist/docs/",
9
8
  "format": "prettier --write --ignore-unknown **/*",
10
9
  "lint": "eslint ./src/**/*.ts",
11
- "release": "npm run build && npm publish --access public",
12
- "preinstall": "npx only-allow npm",
13
- "prepare": "husky"
10
+ "release": "npm run build && npm publish --access public --tag alpha",
11
+ "prepare": "npx only-allow npm && husky || exit 0"
14
12
  },
15
13
  "lint-staged": {
16
14
  "!(*.ts)": "prettier --write --ignore-unknown",
@@ -33,22 +31,17 @@
33
31
  "author": "suco2007",
34
32
  "license": "ISC",
35
33
  "dependencies": {
36
- "jsdom": "^29.1.1",
34
+ "html-minifier-terser": "^7.2.0",
37
35
  "json5": "^2.2.3",
38
- "minify": "^15.3.1",
39
36
  "node-fetch": "^3.3.2",
40
- "open": "^11.0.0",
41
- "readline-sync": "^1.4.10",
42
- "targz": "^1.0.1"
37
+ "open": "^8.4.2",
38
+ "readline-sync": "^1.4.10"
43
39
  },
44
40
  "devDependencies": {
45
41
  "@eslint/js": "^9.39.2",
46
- "@types/jsdom": "^27.0.0",
47
- "@types/minify": "^9.1.4",
42
+ "@types/html-minifier-terser": "^7.0.2",
48
43
  "@types/node": "^22.15.29",
49
- "@types/node-fetch": "^2.6.13",
50
44
  "@types/readline-sync": "^1.4.8",
51
- "@types/targz": "^1.0.5",
52
45
  "copyfiles": "^2.4.1",
53
46
  "eslint": "^9.39.2",
54
47
  "husky": "^9.1.7",
@@ -59,6 +52,6 @@
59
52
  "typescript-eslint": "^8.51.0"
60
53
  },
61
54
  "engines": {
62
- "node": ">=14.0.0"
55
+ "node": ">=14.13.1"
63
56
  }
64
57
  }