@nocobase/cli 2.1.0-beta.2 → 2.1.0-beta.20

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 (143) hide show
  1. package/LICENSE.txt +107 -0
  2. package/README.md +367 -19
  3. package/README.zh-CN.md +336 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +116 -0
  6. package/dist/commands/api/resource/create.js +15 -0
  7. package/dist/commands/api/resource/destroy.js +15 -0
  8. package/dist/commands/api/resource/get.js +15 -0
  9. package/dist/commands/api/resource/index.js +20 -0
  10. package/dist/commands/api/resource/list.js +16 -0
  11. package/dist/commands/api/resource/query.js +15 -0
  12. package/dist/commands/api/resource/update.js +15 -0
  13. package/dist/commands/build.js +57 -0
  14. package/dist/commands/db/logs.js +85 -0
  15. package/dist/commands/db/ps.js +60 -0
  16. package/dist/commands/db/shared.js +81 -0
  17. package/dist/commands/db/start.js +70 -0
  18. package/dist/commands/db/stop.js +70 -0
  19. package/dist/commands/dev.js +149 -0
  20. package/dist/commands/down.js +193 -0
  21. package/dist/commands/download.js +865 -0
  22. package/dist/commands/env/add.js +327 -0
  23. package/dist/commands/env/auth.js +62 -0
  24. package/dist/commands/env/list.js +41 -0
  25. package/dist/commands/env/remove.js +65 -0
  26. package/dist/commands/env/update.js +73 -0
  27. package/dist/commands/env/use.js +36 -0
  28. package/dist/commands/init.js +822 -0
  29. package/dist/commands/install.js +1888 -0
  30. package/dist/commands/logs.js +90 -0
  31. package/dist/commands/pm/disable.js +63 -0
  32. package/dist/commands/pm/enable.js +63 -0
  33. package/dist/commands/pm/list.js +54 -0
  34. package/dist/commands/prompts-stages.js +150 -0
  35. package/dist/commands/prompts-test.js +181 -0
  36. package/dist/commands/ps.js +116 -0
  37. package/dist/commands/restart.js +74 -0
  38. package/dist/commands/scaffold/migration.js +38 -0
  39. package/dist/commands/scaffold/plugin.js +37 -0
  40. package/dist/commands/self/check.js +71 -0
  41. package/dist/commands/self/index.js +20 -0
  42. package/dist/commands/self/update.js +76 -0
  43. package/dist/commands/skills/check.js +63 -0
  44. package/dist/commands/skills/index.js +20 -0
  45. package/dist/commands/skills/install.js +58 -0
  46. package/dist/commands/skills/update.js +58 -0
  47. package/dist/commands/start.js +211 -0
  48. package/dist/commands/stop.js +90 -0
  49. package/dist/commands/test.js +466 -0
  50. package/dist/commands/upgrade.js +583 -0
  51. package/dist/generated/command-registry.js +133 -0
  52. package/dist/help/runtime-help.js +20 -0
  53. package/dist/lib/api-client.js +243 -0
  54. package/dist/lib/app-runtime.js +142 -0
  55. package/dist/lib/auth-store.js +241 -0
  56. package/dist/lib/bootstrap.js +387 -0
  57. package/dist/lib/build-config.js +10 -0
  58. package/dist/lib/cli-home.js +30 -0
  59. package/dist/lib/cli-locale.js +115 -0
  60. package/dist/lib/command-discovery.js +39 -0
  61. package/dist/lib/env-auth.js +872 -0
  62. package/dist/lib/generated-command.js +142 -0
  63. package/dist/lib/naming.js +70 -0
  64. package/dist/lib/openapi.js +62 -0
  65. package/dist/lib/post-processors.js +23 -0
  66. package/dist/lib/prompt-catalog.js +581 -0
  67. package/dist/lib/prompt-validators.js +185 -0
  68. package/dist/lib/prompt-web-ui.js +2096 -0
  69. package/dist/lib/resource-command.js +335 -0
  70. package/dist/lib/resource-request.js +104 -0
  71. package/dist/lib/run-npm.js +197 -0
  72. package/dist/lib/runtime-generator.js +419 -0
  73. package/dist/lib/runtime-store.js +56 -0
  74. package/dist/lib/self-manager.js +246 -0
  75. package/dist/lib/skills-manager.js +202 -0
  76. package/dist/lib/ui.js +175 -0
  77. package/dist/locale/en-US.json +333 -0
  78. package/dist/locale/zh-CN.json +333 -0
  79. package/dist/post-processors/data-modeling.js +66 -0
  80. package/dist/post-processors/data-source-manager.js +114 -0
  81. package/dist/post-processors/index.js +19 -0
  82. package/nocobase-ctl.config.json +287 -0
  83. package/package.json +60 -26
  84. package/LICENSE +0 -661
  85. package/bin/index.js +0 -39
  86. package/nocobase.conf.tpl +0 -95
  87. package/src/cli.js +0 -19
  88. package/src/commands/benchmark.js +0 -73
  89. package/src/commands/build.js +0 -49
  90. package/src/commands/clean.js +0 -30
  91. package/src/commands/client.js +0 -166
  92. package/src/commands/create-nginx-conf.js +0 -37
  93. package/src/commands/create-plugin.js +0 -33
  94. package/src/commands/dev.js +0 -200
  95. package/src/commands/doc.js +0 -76
  96. package/src/commands/e2e.js +0 -265
  97. package/src/commands/global.js +0 -43
  98. package/src/commands/index.js +0 -45
  99. package/src/commands/instance-id.js +0 -47
  100. package/src/commands/locale/cronstrue.js +0 -122
  101. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  102. package/src/commands/locale/react-js-cron/index.js +0 -17
  103. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  104. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  105. package/src/commands/locale.js +0 -81
  106. package/src/commands/p-test.js +0 -88
  107. package/src/commands/perf.js +0 -63
  108. package/src/commands/pkg.js +0 -321
  109. package/src/commands/pm2.js +0 -37
  110. package/src/commands/postinstall.js +0 -88
  111. package/src/commands/start.js +0 -148
  112. package/src/commands/tar.js +0 -36
  113. package/src/commands/test-coverage.js +0 -55
  114. package/src/commands/test.js +0 -107
  115. package/src/commands/umi.js +0 -33
  116. package/src/commands/update-deps.js +0 -72
  117. package/src/commands/upgrade.js +0 -47
  118. package/src/commands/view-license-key.js +0 -44
  119. package/src/index.js +0 -14
  120. package/src/license.js +0 -76
  121. package/src/logger.js +0 -75
  122. package/src/plugin-generator.js +0 -80
  123. package/src/util.js +0 -517
  124. package/templates/bundle-status.html +0 -338
  125. package/templates/create-app-package.json +0 -39
  126. package/templates/plugin/.npmignore.tpl +0 -2
  127. package/templates/plugin/README.md.tpl +0 -1
  128. package/templates/plugin/client.d.ts +0 -2
  129. package/templates/plugin/client.js +0 -1
  130. package/templates/plugin/package.json.tpl +0 -11
  131. package/templates/plugin/server.d.ts +0 -2
  132. package/templates/plugin/server.js +0 -1
  133. package/templates/plugin/src/client/client.d.ts +0 -249
  134. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  135. package/templates/plugin/src/client/locale.ts +0 -21
  136. package/templates/plugin/src/client/models/index.ts +0 -12
  137. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  138. package/templates/plugin/src/index.ts +0 -2
  139. package/templates/plugin/src/locale/en-US.json +0 -1
  140. package/templates/plugin/src/locale/zh-CN.json +0 -1
  141. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  142. package/templates/plugin/src/server/index.ts.tpl +0 -1
  143. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
@@ -0,0 +1,142 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { executeApiRequest } from './api-client.js';
3
+ import { applyPostProcessor } from './post-processors.js';
4
+ import { registerPostProcessors } from '../post-processors/index.js';
5
+ function buildParameterFlag(parameter, options) {
6
+ const hints = [parameter.in];
7
+ if (parameter.type === 'object' || parameter.type === 'array' || parameter.jsonEncoded) {
8
+ hints.push('JSON');
9
+ }
10
+ else if (parameter.isArray) {
11
+ hints.push('repeatable');
12
+ }
13
+ else if (parameter.type) {
14
+ hints.push(parameter.type);
15
+ }
16
+ const description = [
17
+ `${parameter.description ?? ''}${parameter.description ? ' ' : ''}[${hints.join(', ')}]`.trim(),
18
+ parameter.jsonShape ? `Shape: ${parameter.jsonShape}` : undefined,
19
+ ]
20
+ .filter(Boolean)
21
+ .join('\n');
22
+ const required = options?.required ?? parameter.required;
23
+ const helpGroup = parameter.in === 'body'
24
+ ? 'Body Field'
25
+ : parameter.in === 'path'
26
+ ? 'Path Parameter'
27
+ : parameter.in === 'query'
28
+ ? 'Query Parameter'
29
+ : parameter.in === 'header'
30
+ ? 'Header Parameter'
31
+ : parameter.in === 'cookie'
32
+ ? 'Cookie Parameter'
33
+ : undefined;
34
+ if (parameter.type === 'boolean') {
35
+ return Flags.boolean({
36
+ description,
37
+ ...(helpGroup ? { helpGroup } : {}),
38
+ ...(required ? { required: true } : {}),
39
+ });
40
+ }
41
+ if (parameter.isArray && !parameter.jsonEncoded) {
42
+ return Flags.string({
43
+ description,
44
+ multiple: true,
45
+ ...(helpGroup ? { helpGroup } : {}),
46
+ ...(required ? { required: true } : {}),
47
+ });
48
+ }
49
+ return Flags.string({
50
+ description,
51
+ ...(helpGroup ? { helpGroup } : {}),
52
+ ...(required ? { required: true } : {}),
53
+ });
54
+ }
55
+ export function createGeneratedFlags(operation) {
56
+ const flags = {};
57
+ for (const parameter of operation.parameters) {
58
+ flags[parameter.flagName] = buildParameterFlag(parameter, {
59
+ // Body flags are an alternative authoring path to --body/--body-file.
60
+ // Enforce required body semantics later in parseBody(), after we know
61
+ // which input mode the user chose.
62
+ required: parameter.in === 'body' ? false : parameter.required,
63
+ });
64
+ }
65
+ if (operation.hasBody) {
66
+ flags.body = Flags.string({
67
+ description: 'Full JSON request body string. Do not combine with body field flags.',
68
+ helpGroup: 'Raw JSON Body',
69
+ exclusive: ['body-file'],
70
+ });
71
+ flags['body-file'] = Flags.string({
72
+ description: 'Path to a JSON file containing the full request body. Do not combine with body field flags.',
73
+ helpGroup: 'Raw JSON Body',
74
+ exclusive: ['body'],
75
+ });
76
+ }
77
+ flags['base-url'] = Flags.string({
78
+ description: 'NocoBase API base URL, for example http://localhost:13000/api',
79
+ helpGroup: 'Global',
80
+ });
81
+ flags.verbose = Flags.boolean({
82
+ description: 'Show detailed progress output',
83
+ default: false,
84
+ helpGroup: 'Global',
85
+ });
86
+ flags.env = Flags.string({
87
+ char: 'e',
88
+ description: 'Environment name',
89
+ helpGroup: 'Global',
90
+ });
91
+ flags.role = Flags.string({
92
+ description: 'Role override, sent as X-Role',
93
+ helpGroup: 'Global',
94
+ });
95
+ flags.token = Flags.string({
96
+ char: 't',
97
+ description: 'API key override',
98
+ helpGroup: 'Global',
99
+ });
100
+ flags['json-output'] = Flags.boolean({
101
+ char: 'j',
102
+ description: 'Print raw JSON response',
103
+ default: true,
104
+ allowNo: true,
105
+ helpGroup: 'Global',
106
+ });
107
+ return flags;
108
+ }
109
+ export class GeneratedApiCommand extends Command {
110
+ static operation;
111
+ async run() {
112
+ registerPostProcessors();
113
+ const ctor = this.constructor;
114
+ const { flags } = await this.parse(ctor);
115
+ const response = await executeApiRequest({
116
+ envName: flags.env,
117
+ baseUrl: flags['base-url'],
118
+ role: flags.role,
119
+ token: flags.token,
120
+ flags,
121
+ operation: {
122
+ method: ctor.operation.method,
123
+ pathTemplate: ctor.operation.pathTemplate,
124
+ parameters: ctor.operation.parameters,
125
+ hasBody: ctor.operation.hasBody,
126
+ bodyRequired: ctor.operation.bodyRequired,
127
+ },
128
+ });
129
+ if (!response.ok) {
130
+ this.error(`Request failed with status ${response.status}\n${JSON.stringify(response.data, null, 2)}`);
131
+ }
132
+ const processedData = await applyPostProcessor(response.data, {
133
+ flags,
134
+ operation: ctor.operation,
135
+ });
136
+ if (flags['json-output']) {
137
+ this.log(JSON.stringify(processedData, null, 2));
138
+ return;
139
+ }
140
+ this.log(`HTTP ${response.status}`);
141
+ }
142
+ }
@@ -0,0 +1,70 @@
1
+ import path from 'node:path';
2
+ export function toKebabCase(value) {
3
+ return value
4
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
5
+ .replace(/[^a-zA-Z0-9]+/g, '-')
6
+ .replace(/-+/g, '-')
7
+ .replace(/^-|-$/g, '')
8
+ .toLowerCase();
9
+ }
10
+ export function splitPathAction(pathTemplate) {
11
+ const normalizedPath = pathTemplate.replace(/^\/+/, '');
12
+ const separatorIndex = normalizedPath.lastIndexOf(':');
13
+ if (separatorIndex === -1) {
14
+ return {
15
+ resourcePath: normalizedPath,
16
+ action: 'call',
17
+ };
18
+ }
19
+ return {
20
+ resourcePath: normalizedPath.slice(0, separatorIndex),
21
+ action: normalizedPath.slice(separatorIndex + 1),
22
+ };
23
+ }
24
+ export function toLogicalResourceName(pathTemplate) {
25
+ const { resourcePath } = splitPathAction(pathTemplate);
26
+ return resourcePath
27
+ .split('/')
28
+ .filter(Boolean)
29
+ .filter((segment) => !segment.startsWith('{'))
30
+ .map((segment) => toKebabCase(segment))
31
+ .join('.');
32
+ }
33
+ export function toLogicalActionName(pathTemplate) {
34
+ return toKebabCase(splitPathAction(pathTemplate).action);
35
+ }
36
+ export function toResourceSegments(pathTemplate, options) {
37
+ const { resourcePath, action } = splitPathAction(pathTemplate);
38
+ const pathSegments = resourcePath
39
+ .split('/')
40
+ .filter(Boolean)
41
+ .flatMap((segment) => {
42
+ if (!segment.startsWith('{')) {
43
+ return [toKebabCase(segment)];
44
+ }
45
+ if (!options?.includeParams) {
46
+ return [];
47
+ }
48
+ return [`by-${toKebabCase(segment.slice(1, -1))}`];
49
+ });
50
+ return [...pathSegments, toKebabCase(action)].filter(Boolean);
51
+ }
52
+ export function toCommandSegments(moduleName, pathTemplate, options) {
53
+ const resourceSegments = toResourceSegments(pathTemplate, options);
54
+ const segments = [options?.omitModule ? '' : toKebabCase(moduleName), ...resourceSegments].filter(Boolean);
55
+ return segments.length ? segments : [toKebabCase(moduleName), 'call'];
56
+ }
57
+ export function toClassName(segments) {
58
+ return segments
59
+ .map((segment) => segment.replace(/(^\w|-\w)/g, (token) => token.replace('-', '').toUpperCase()))
60
+ .join('');
61
+ }
62
+ export function toOutputFile(outputRoot, segments) {
63
+ const folder = path.join(outputRoot, ...segments.slice(0, -1));
64
+ const filePath = path.join(folder, `${segments.at(-1)}.ts`);
65
+ return filePath;
66
+ }
67
+ export function toImportPath(fromFile, targetFile) {
68
+ const relative = path.relative(path.dirname(fromFile), targetFile).replace(/\\/g, '/');
69
+ return relative.startsWith('.') ? relative : `./${relative}`;
70
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete'];
10
+ function resolveLocalRef(document, ref) {
11
+ if (!ref.startsWith('#/')) {
12
+ return undefined;
13
+ }
14
+ return ref
15
+ .slice(2)
16
+ .split('/')
17
+ .reduce((current, segment) => current?.[segment], document);
18
+ }
19
+ function dereferenceNode(node, document, seen = new Set()) {
20
+ if (Array.isArray(node)) {
21
+ return node.map((item) => dereferenceNode(item, document, seen));
22
+ }
23
+ if (!node || typeof node !== 'object') {
24
+ return node;
25
+ }
26
+ const ref = node.$ref;
27
+ if (typeof ref === 'string') {
28
+ if (seen.has(ref)) {
29
+ return {};
30
+ }
31
+ const resolved = resolveLocalRef(document, ref);
32
+ if (!resolved) {
33
+ return node;
34
+ }
35
+ return dereferenceNode(resolved, document, new Set([...seen, ref]));
36
+ }
37
+ return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, dereferenceNode(value, document, seen)]));
38
+ }
39
+ export function collectOperations(document) {
40
+ const operations = [];
41
+ for (const [pathTemplate, pathItem] of Object.entries(document.paths ?? {})) {
42
+ for (const method of HTTP_METHODS) {
43
+ const operation = pathItem?.[method];
44
+ if (!operation || '$ref' in operation) {
45
+ continue;
46
+ }
47
+ const parameters = [...(pathItem.parameters ?? []), ...(operation.parameters ?? [])]
48
+ .map((parameter) => dereferenceNode(parameter, document))
49
+ .filter((parameter) => Boolean(parameter && !('$ref' in parameter)));
50
+ operations.push({
51
+ method,
52
+ pathTemplate,
53
+ operation: {
54
+ ...operation,
55
+ parameters,
56
+ requestBody: operation.requestBody ? dereferenceNode(operation.requestBody, document) : undefined,
57
+ },
58
+ });
59
+ }
60
+ }
61
+ return operations;
62
+ }
@@ -0,0 +1,23 @@
1
+ function buildKey(resource, action) {
2
+ return `${resource}:${action}`;
3
+ }
4
+ class PostProcessorRegistry {
5
+ processors = new Map();
6
+ register(resource, action, processor) {
7
+ this.processors.set(buildKey(resource, action), processor);
8
+ }
9
+ resolve(resource, action) {
10
+ if (!resource || !action) {
11
+ return undefined;
12
+ }
13
+ return this.processors.get(buildKey(resource, action));
14
+ }
15
+ }
16
+ export const postProcessorRegistry = new PostProcessorRegistry();
17
+ export async function applyPostProcessor(result, context) {
18
+ const processor = postProcessorRegistry.resolve(context.operation.logicalResourceName, context.operation.actionName);
19
+ if (!processor) {
20
+ return result;
21
+ }
22
+ return processor(result, context);
23
+ }