dbdocs 0.6.1 → 0.6.4

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 CHANGED
@@ -19,7 +19,7 @@ $ npm install -g dbdocs
19
19
  $ dbdocs COMMAND
20
20
  running command...
21
21
  $ dbdocs (-v|--version|version)
22
- dbdocs/0.6.1 darwin-x64 node-v15.10.0
22
+ dbdocs/0.6.2 darwin-x64 node-v15.10.0
23
23
  $ dbdocs --help [COMMAND]
24
24
  USAGE
25
25
  $ dbdocs COMMAND
@@ -35,7 +35,9 @@ USAGE
35
35
  * [`dbdocs ls`](#dbdocs-ls)
36
36
  * [`dbdocs password`](#dbdocs-password)
37
37
  * [`dbdocs remove [PROJECT_NAME]`](#dbdocs-remove-project_name)
38
+ * [`dbdocs rename`](#dbdocs-rename)
38
39
  * [`dbdocs token`](#dbdocs-token)
40
+ * [`dbdocs validate [FILEPATH]`](#dbdocs-validate-filepath)
39
41
 
40
42
  ## `dbdocs build [FILEPATH]`
41
43
 
@@ -129,6 +131,19 @@ USAGE
129
131
  ARGUMENTS
130
132
  PROJECT_NAME name of the project which you want to remove
131
133
  ```
134
+
135
+ ## `dbdocs rename`
136
+
137
+ change your username
138
+
139
+ ```
140
+ USAGE
141
+ $ dbdocs rename
142
+
143
+ DESCRIPTION
144
+ change your username and your default organization name
145
+ ```
146
+
132
147
  ## `dbdocs token`
133
148
 
134
149
  generate or revoke your authentication token
@@ -141,4 +156,16 @@ OPTIONS
141
156
  -g, --generate generate authentication token
142
157
  -r, --revoke revoke authentication token
143
158
  ```
159
+
160
+ ## `dbdocs validate [FILEPATH]`
161
+
162
+ validate docs content
163
+
164
+ ```
165
+ USAGE
166
+ $ dbdocs validate [FILEPATH]
167
+
168
+ ARGUMENTS
169
+ FILEPATH dbml file path
170
+ ```
144
171
  <!-- commandsstop -->
@@ -1 +1 @@
1
- {"version":"0.6.1","commands":{"build":{"id":"build","description":"build docs","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","description":"project name"},"password":{"name":"password","type":"option","char":"p","description":"password for project"}},"args":[{"name":"filepath","description":"dbml file path"}]},"login":{"id":"login","description":"login to dbdocs\nlogin with your dbdocs credentials\n","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"logout":{"id":"logout","description":"logout\nclears local login credentials\n","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"ls":{"id":"ls","description":"list projects","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"password":{"id":"password","description":"set password for your project or remove password","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","char":"p","description":"project name","helpValue":"project name"},"set":{"name":"set","type":"option","char":"s","description":"password for your project","helpValue":"password"},"remove":{"name":"remove","type":"boolean","char":"r","description":"remove password from your project","allowNo":false}},"args":[]},"remove":{"id":"remove","description":"remove docs","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"project_name","description":"name of the project which you want to remove"}]},"token":{"id":"token","description":"generate or revoke your authentication token","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"generate":{"name":"generate","type":"boolean","char":"g","description":"generate authentication token","allowNo":false},"revoke":{"name":"revoke","type":"boolean","char":"r","description":"revoke authentication token","allowNo":false}},"args":[]}}}
1
+ {"version":"0.6.4","commands":{"build":{"id":"build","description":"build docs","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","description":"project name"},"password":{"name":"password","type":"option","char":"p","description":"password for project"}},"args":[{"name":"filepath","description":"dbml file path"}]},"login":{"id":"login","description":"login to dbdocs\nlogin with your dbdocs credentials\n","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"logout":{"id":"logout","description":"logout\nclears local login credentials\n","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"ls":{"id":"ls","description":"list projects","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"password":{"id":"password","description":"set password for your project or remove password","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","char":"p","description":"project name","helpValue":"project name"},"set":{"name":"set","type":"option","char":"s","description":"password for your project","helpValue":"password"},"remove":{"name":"remove","type":"boolean","char":"r","description":"remove password from your project","allowNo":false}},"args":[]},"remove":{"id":"remove","description":"remove docs","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"project_name","description":"name of the project which you want to remove"}]},"rename":{"id":"rename","description":"change your username","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"token":{"id":"token","description":"generate or revoke your authentication token","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{"generate":{"name":"generate","type":"boolean","char":"g","description":"generate authentication token","allowNo":false},"revoke":{"name":"revoke","type":"boolean","char":"r","description":"revoke authentication token","allowNo":false}},"args":[]},"validate":{"id":"validate","description":"validate docs content","pluginName":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"filepath","description":"dbml file path"}]}}}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "dbdocs",
3
- "version": "0.6.1",
3
+ "version": "0.6.4",
4
4
  "author": "@holistics",
5
5
  "bin": {
6
6
  "dbdocs": "./bin/run"
7
7
  },
8
8
  "dependencies": {
9
+ "@dbml/core": "^2.4.2",
9
10
  "@oclif/command": "^1",
10
11
  "@oclif/config": "^1",
11
12
  "@oclif/plugin-help": "^2",
@@ -51,6 +52,9 @@
51
52
  "init": [
52
53
  "./src/hooks/init/checkUpdate",
53
54
  "./src/hooks/init/loadEnv"
55
+ ],
56
+ "prerun":[
57
+ "./src/hooks/prerun/checkVersion"
54
58
  ]
55
59
  }
56
60
  },
@@ -10,14 +10,7 @@ const verifyToken = require('../utils/verifyToken');
10
10
  const { getOrg } = require('../utils/org');
11
11
  const { shouldAskForFeedback } = require('../utils/feedback');
12
12
  const { isValidName } = require('../validators/projectName');
13
-
14
- async function validate (content) {
15
- const res = await axios.post(`${vars.apiUrl}/parse`, {
16
- content,
17
- });
18
-
19
- return res.data.model;
20
- }
13
+ const parse = require('../utils/parse');
21
14
 
22
15
  async function build (project, authConfig) {
23
16
  const res = await axios.post(`${vars.apiUrl}/projects`, project, authConfig);
@@ -57,20 +50,16 @@ class BuildCommand extends Command {
57
50
  // validate dbml syntax, get project name if it's already defined in the file
58
51
  spinner.text = 'Parsing file content';
59
52
  spinner.start();
53
+ let model = null;
60
54
  try {
61
- const model = await validate(content);
55
+ model = await parse(content);
62
56
  if (!project) {
63
- project = model.database['1'].name;
57
+ project = model.name;
64
58
  }
65
59
  spinner.succeed('Parsing file content');
66
- } catch (err) {
67
- let message = err.message || 'Something wrong :( Please try again.';
68
- if (err.response) {
69
- const { error } = err.response.data;
70
- if (error.name === 'SyntaxError') {
71
- message = `You have syntax error in ${path.basename(filepath)} line ${error.location.start.line} column ${error.location.start.column}. ${error.message}`;
72
- }
73
- }
60
+ } catch (error) {
61
+ if (!error.location) throw error;
62
+ const message = `You have syntax error in ${path.basename(filepath)} line ${error.location.start.line} column ${error.location.start.column}. ${error.message}`;
74
63
  throw new Error(message);
75
64
  }
76
65
 
@@ -95,6 +84,7 @@ class BuildCommand extends Command {
95
84
  doc: {
96
85
  content,
97
86
  },
87
+ shallowSchema: model.schemas,
98
88
  }, authConfig);
99
89
  if (!newProject.isPublic) {
100
90
  if (isCreated || password) {
@@ -0,0 +1,88 @@
1
+ const { Command } = require('@oclif/command');
2
+ const inquirer = require('inquirer');
3
+ const axios = require('axios');
4
+ const ora = require('ora');
5
+ const { vars } = require('../vars');
6
+ const { isValidUserName } = require('../validators/userName');
7
+ const verifyToken = require('../utils/verifyToken');
8
+
9
+ async function enterUserName () {
10
+ const answer = await inquirer.prompt([
11
+ {
12
+ message: 'Please input your new username: ',
13
+ name: 'newUserName',
14
+ },
15
+ ]);
16
+ return answer.newUserName;
17
+ }
18
+
19
+ async function validateAndUpdateUserName (spinner, authConfig, command) {
20
+ let newUserName = await enterUserName();
21
+
22
+ while (!isValidUserName(newUserName)) {
23
+ spinner.warn('Invalid username! Username can only contain alphabets, numbers, "-" or "_" and can not be blanked!');
24
+ newUserName = await enterUserName();
25
+ }
26
+
27
+ try {
28
+ const { data: { user, hasRevokedToken } } = await axios.put(`${vars.apiUrl}/account/rename`, { newUserName }, authConfig);
29
+ return { user, hasRevokedToken };
30
+ } catch (err) {
31
+ const { error } = err.response.data;
32
+ const warningNames = ['UserNameNotChange', 'UserNameExisted'];
33
+ if (warningNames.includes(error.name)) {
34
+ spinner.warn(error.message);
35
+ } else {
36
+ command.error(error.message);
37
+ }
38
+ return { user: null, hasRevokedToken: null };
39
+ }
40
+ }
41
+
42
+ class RenameCommand extends Command {
43
+ async run () {
44
+ const spinner = ora({});
45
+ try {
46
+ const authConfig = await verifyToken();
47
+
48
+ this.warn('After renaming, your authentication token (if exists) will be revoked. Please re-generate a new one!');
49
+ this.warn('You may need to re-login your account on the dbdocs web app for the best user experience.');
50
+
51
+ let { user, hasRevokedToken } = await validateAndUpdateUserName(spinner, authConfig, this);
52
+ while (!user) {
53
+ ({ user, hasRevokedToken } = await validateAndUpdateUserName(spinner, authConfig, this));
54
+ }
55
+ if (hasRevokedToken) {
56
+ spinner.succeed('Rename successfully and your access token has been revoked, please generate a new one!');
57
+ } else {
58
+ spinner.succeed('Rename successfully!');
59
+ }
60
+ } catch (err) {
61
+ if (spinner.isSpinning) {
62
+ spinner.fail();
63
+ }
64
+ let message = err.message || 'Something wrong :( Please try again.';
65
+ if (err.response) {
66
+ const { error } = err.response.data;
67
+ switch (error.name) {
68
+ case 'TokenExpiredError':
69
+ message = 'Your token has expired. Please login again.';
70
+ break;
71
+
72
+ case 'InvalidAuthToken':
73
+ message = 'Invalid token. Please login again.';
74
+ break;
75
+
76
+ default:
77
+ message = error.message;
78
+ break;
79
+ }
80
+ }
81
+ this.error(message);
82
+ }
83
+ }
84
+ }
85
+
86
+ RenameCommand.description = 'change your username';
87
+
88
+ module.exports = RenameCommand;
@@ -0,0 +1,43 @@
1
+ const { Command, flags } = require('@oclif/command');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const ora = require('ora');
5
+ const parse = require('../utils/parse');
6
+
7
+ class ValidateCommand extends Command {
8
+ async run () {
9
+ const spinner = ora({});
10
+ let filepath = null;
11
+ try {
12
+ const { args } = this.parse(ValidateCommand);
13
+ filepath = args.filepath;
14
+ let content = '';
15
+ content = fs.readFileSync(path.resolve(process.cwd(), filepath), 'utf-8');
16
+
17
+ spinner.text = 'Validating file content';
18
+ spinner.start();
19
+
20
+ await parse(content);
21
+ spinner.succeed('Validating file content');
22
+ spinner.succeed('Done. Parse succeeded without errors.');
23
+ } catch (error) {
24
+ let message = error.message || 'Something wrong :( Please try again.';
25
+ if (filepath && error.location) message = `You have syntax error in ${path.basename(filepath)} line ${error.location.start.line} column ${error.location.start.column}. ${error.message}`;
26
+ if (spinner.isSpinning) {
27
+ spinner.fail(`Failed: ${message}`);
28
+ } else {
29
+ this.error(message);
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ ValidateCommand.description = 'validate docs content';
36
+
37
+ ValidateCommand.flags = {};
38
+
39
+ ValidateCommand.args = [
40
+ { name: 'filepath', description: 'dbml file path' },
41
+ ];
42
+
43
+ module.exports = ValidateCommand;
@@ -0,0 +1,20 @@
1
+ const { getVersion, getPackageVersion, compareVersion } = require('./helper');
2
+
3
+ module.exports = async function () {
4
+ let shouldExit = false;
5
+ try {
6
+ const localVersion = getPackageVersion();
7
+ const remoteVersion = await getVersion();
8
+ const mustUpgrade = compareVersion(localVersion, remoteVersion.required) === -1;
9
+ if (mustUpgrade) {
10
+ shouldExit = true;
11
+ this.error('Your CLI version is no longer supported, please upgrade with "npm i -g dbdocs"');
12
+ }
13
+ const shouldUpgrade = compareVersion(localVersion, remoteVersion.current) === -1;
14
+ if (shouldUpgrade) this.warn('A new version is available, use "npm i -g dbdocs" to upgrade to the latest version');
15
+ } catch (err) {
16
+ const message = err.message || 'Something goes wrong when checking version';
17
+ if (shouldExit) this.error(message);
18
+ this.warn(message);
19
+ }
20
+ };
@@ -0,0 +1,37 @@
1
+ const axios = require('axios');
2
+ const { vars } = require('../../vars');
3
+ const pkg = require('../../../package.json');
4
+
5
+ const getVersion = async () => {
6
+ const res = await axios.get(`${vars.apiUrl}/version/cli`);
7
+ return res.data;
8
+ };
9
+ const getPackageVersion = () => {
10
+ const ver = pkg.version;
11
+ const [major, minor, patch] = ver.split('.');
12
+ return { major, minor, patch };
13
+ };
14
+
15
+ /**
16
+ * @param {{major: number, minor: number, patch: number}} a: version to compare
17
+ * @param {{major: number, minor: number, patch: number}} b: version to compare to
18
+ * @returns {number}
19
+ * 0: a = b;
20
+ * 1: a > b;
21
+ * -1: a < b;
22
+ */
23
+ const compareVersion = (a, b) => {
24
+ if (a.major > b.major) return 1;
25
+ if (a.major < b.major) return -1;
26
+ if (a.minor > b.minor) return 1;
27
+ if (a.minor < b.minor) return -1;
28
+ if (a.patch > b.patch) return 1;
29
+ if (a.patch < b.patch) return -1;
30
+ return 0;
31
+ };
32
+
33
+ module.exports = {
34
+ getVersion,
35
+ getPackageVersion,
36
+ compareVersion,
37
+ };
@@ -1 +1 @@
1
- {"BUILD_COUNT":2}
1
+ {"BUILD_COUNT":1}
@@ -0,0 +1,18 @@
1
+ const { Worker } = require('worker_threads');
2
+
3
+ const parse = (content) => {
4
+ return new Promise((resolve, reject) => {
5
+ const workerPath = `${__dirname}/parserWorker.js`;
6
+
7
+ const worker = new Worker(workerPath, {
8
+ workerData: { content },
9
+ });
10
+ worker.on('message', resolve);
11
+ worker.on('error', reject);
12
+ worker.on('exit', (code) => {
13
+ if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
14
+ });
15
+ });
16
+ };
17
+
18
+ module.exports = parse;
@@ -0,0 +1,20 @@
1
+ const { parentPort, workerData } = require("worker_threads");
2
+ const { Parser } = require("@dbml/core");
3
+
4
+ function parse (content) {
5
+ const databaseObject = Parser.parse(content, 'dbml');
6
+ const schemas = databaseObject.schemas.map((schema) => {
7
+ return {
8
+ name: schema.name,
9
+ tables: schema.tables.map((table) => table.name),
10
+ };
11
+ });
12
+ return {
13
+ name: databaseObject.name,
14
+ schemas,
15
+ };
16
+ }
17
+
18
+ const { content } = workerData;
19
+ const result = parse(content);
20
+ parentPort.postMessage(result);
@@ -0,0 +1,6 @@
1
+ const pattern = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i;
2
+ const isValidUserName = (userName) => pattern.test(userName);
3
+
4
+ module.exports = {
5
+ isValidUserName,
6
+ };