@ones-open/cli 2.1.0 → 2.1.1

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 (2) hide show
  1. package/bin/index.es.js +261 -0
  2. package/package.json +4 -4
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+ import { ONESProjectTemplate, getCliVersionByMetaPath, Version, tryGitInit, renameHiddenTemplateFiles, getNpm, getPackageInNodeModulesDir } from '@ones-open/cli-utils';
3
+ import chalk from 'chalk';
4
+ import { Command, Option } from 'commander';
5
+ import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
6
+ import { checkIsLegalPluginType, getPluginProjectCreatingTasks } from '@ones-open/cli-plugin';
7
+ import { execa } from 'execa';
8
+ import { pathExists, copy } from 'fs-extra';
9
+ import inquirer from 'inquirer';
10
+ import Listr from 'listr';
11
+ import { isAbsolute, join, basename, dirname } from 'path';
12
+ import { fileURLToPath } from 'url';
13
+ import envinfo from 'envinfo';
14
+ import { cwd } from 'process';
15
+
16
+ /* eslint-disable no-console */
17
+ const defaultConfig = {
18
+ System: ['OS', 'CPU', 'Memory', 'Shell'],
19
+ Binaries: ['Node', 'npm'],
20
+ npmPackages: ['@ones-open/cli-utils', '@ones-open/cli-plugin', '@ones-open/cli-monorepo'],
21
+ npmGlobalPackages: ['@ones-open/cli']
22
+ };
23
+ const defaultOptions = {
24
+ duplicates: true,
25
+ showNotFound: true
26
+ };
27
+ async function printEnvironmentInfo(config = defaultConfig, options = defaultOptions) {
28
+ const info = await envinfo.run(config, options);
29
+ console.log(chalk.bold('\nEnvironment Info:'), info);
30
+ }
31
+
32
+ const LEGAL_PROJECT_TYPE = Object.values(ONESProjectTemplate);
33
+ const LEGAL_PROJECT_TYPE_SET = new Set(LEGAL_PROJECT_TYPE);
34
+ const LEGAL_POLICY = ['simple', 'standard'];
35
+ function isLegalProjectType(projectType) {
36
+ return LEGAL_PROJECT_TYPE_SET.has(projectType);
37
+ }
38
+ function isLegalPolicy(policy) {
39
+ return _includesInstanceProperty(LEGAL_POLICY).call(LEGAL_POLICY, policy);
40
+ }
41
+ async function getRootPath(currentWorkingDirectory, specificPath) {
42
+ const hasSpecificPath = specificPath && specificPath.length > 0;
43
+ if (hasSpecificPath) {
44
+ // we had to check if the path is absolute or not
45
+ const isAbsolutePath = isAbsolute(specificPath);
46
+ const root = isAbsolutePath ? specificPath : join(currentWorkingDirectory, specificPath);
47
+ const isPathExists = await pathExists(root);
48
+ if (!isPathExists) {
49
+ throw new Error('The specific path does not exist on the file system');
50
+ }
51
+ return {
52
+ hasSpecificPath,
53
+ root,
54
+ projectName: basename(root)
55
+ };
56
+ }
57
+ return {
58
+ hasSpecificPath,
59
+ root: currentWorkingDirectory,
60
+ projectName: basename(currentWorkingDirectory)
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Copy the project basic template files
66
+ *
67
+ * We need to consider the path of current file path after complication.
68
+ * When we compute the path on the file system.
69
+ *
70
+ * e.g:
71
+ *
72
+ * Current file in `/Users/user/ones/cli/src/bin/index.ts`
73
+ * Then the location of current file after complication is `/Users/user/ones/cli/bin/index.js`
74
+ */
75
+ async function copyBasicTemplateFiles(projectType, projectPath) {
76
+ const currentFilePath = fileURLToPath(import.meta.url);
77
+ const currentFileDir = dirname(currentFilePath);
78
+ const templatePath = join(currentFileDir, '../template');
79
+ if (projectType === ONESProjectTemplate.Monorepo) {
80
+ await copy(templatePath, projectPath);
81
+ await renameHiddenTemplateFiles(projectPath);
82
+ } else {
83
+ // Only copy the package.json for the plugin project creating
84
+ const basicTemplatePackageJsonPath = join(templatePath, 'package.json');
85
+ const packageJsonPath = join(projectPath, 'package.json');
86
+ await copy(basicTemplatePackageJsonPath, packageJsonPath);
87
+ }
88
+ }
89
+ async function installSubCli({
90
+ root,
91
+ subCliName,
92
+ installLocalDependencies,
93
+ distTag
94
+ }) {
95
+ const cliNameWithVersionSuffix = `${subCliName}@${distTag}`;
96
+ const installCommand = getNpm();
97
+ const installArgs = installLocalDependencies ? ['link', subCliName, '--save-dev', '--no-optional'] : ['install', cliNameWithVersionSuffix, '--save-dev', '--no-optional'];
98
+ await execa(installCommand, installArgs, {
99
+ cwd: root,
100
+ stdio: 'ignore'
101
+ });
102
+ const subCliPath = getPackageInNodeModulesDir(root, subCliName);
103
+ const subCliPackageJsonPath = join(subCliPath, 'package.json');
104
+ const isSubCliInstalled = await pathExists(subCliPackageJsonPath);
105
+ if (!isSubCliInstalled) {
106
+ throw new Error(`${subCliName} does not exist in node_modules`);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * TODO: support different project types
112
+ */
113
+ function getExternalTaskByTemplateType(currentWorkingDirectory, projectCreatingParams, options) {
114
+ const {
115
+ template
116
+ } = projectCreatingParams;
117
+ if (template === ONESProjectTemplate.Plugin) {
118
+ return getPluginProjectCreatingTasks({
119
+ currentWorkingDirectory,
120
+ projectCreatingParams,
121
+ options
122
+ });
123
+ }
124
+ return undefined;
125
+ }
126
+ async function createProject(rawProjectName, options) {
127
+ try {
128
+ const {
129
+ projectType,
130
+ specificPath,
131
+ useDefaultPreset,
132
+ installLocalDependencies,
133
+ distTag: rawDistTag,
134
+ pluginType,
135
+ policy
136
+ } = options;
137
+ const cliVersion = await getCliVersionByMetaPath(import.meta.url);
138
+ if (!cliVersion) throw new Error('Get sub cli version failed.');
139
+ const distTag = rawDistTag ? rawDistTag :
140
+ // Get ONES CLI major version to match correct dependencies version
141
+ new Version(cliVersion).major;
142
+ if (!projectType || !isLegalProjectType(projectType)) {
143
+ throw new Error(`Illegal project type: ${projectType}`);
144
+ }
145
+ if (!checkIsLegalPluginType(pluginType)) {
146
+ throw new Error(`Illegal plugin type: ${pluginType}`);
147
+ }
148
+ if (!isLegalPolicy(policy)) {
149
+ throw new Error(`Illegal policy: ${policy}`);
150
+ }
151
+ const {
152
+ root,
153
+ projectName
154
+ } = await getRootPath(cwd(), specificPath);
155
+ const defaultProjectName = rawProjectName || projectName;
156
+ let projectCreatingParams = {
157
+ template: ONESProjectTemplate.Plugin,
158
+ name: defaultProjectName,
159
+ description: '',
160
+ appID: ''
161
+ };
162
+ const prompts = [{
163
+ type: 'list',
164
+ name: 'template',
165
+ message: 'Choose a template:',
166
+ choices: LEGAL_PROJECT_TYPE,
167
+ default: projectCreatingParams.template,
168
+ // Temporary hide the monorepo template type until we support it
169
+ when: false
170
+ // when: !projectType || !templates.includes(projectType),
171
+ }, {
172
+ type: 'input',
173
+ name: 'appID',
174
+ message: 'Project app ID(Refer to https://developer.ones.com/docs/guide/developer-license to learn how to get the appID.):',
175
+ validate: rawInput => {
176
+ const input = rawInput.trim();
177
+ if (input.length === 0) return 'Project app ID is required and cannot be empty';
178
+ return true;
179
+ }
180
+ }, {
181
+ type: 'input',
182
+ name: 'name',
183
+ message: 'Project name:',
184
+ default: defaultProjectName,
185
+ validate: rawInput => {
186
+ const input = rawInput.trim();
187
+ if (input.length === 0) return 'Project name is required and cannot be empty';
188
+ return true;
189
+ },
190
+ when: !useDefaultPreset
191
+ }, {
192
+ type: 'input',
193
+ name: 'description',
194
+ message: 'Project description:',
195
+ when: !useDefaultPreset
196
+ }];
197
+
198
+ // display interactive prompts
199
+ const answers = await inquirer.prompt(prompts);
200
+ Object.entries(answers).forEach(([key, value]) => {
201
+ if (!value) return;
202
+ projectCreatingParams = {
203
+ ...projectCreatingParams,
204
+ [key]: value
205
+ };
206
+ });
207
+ const projectCreatingTasks = [{
208
+ title: 'Git init',
209
+ task: async (ctx, task) => {
210
+ try {
211
+ await tryGitInit(root);
212
+ } catch (error) {
213
+ if (error instanceof Error) {
214
+ const {
215
+ message
216
+ } = error;
217
+ task.skip(message);
218
+ }
219
+ }
220
+ }
221
+ }, {
222
+ title: 'Copy basic template files',
223
+ task: () => copyBasicTemplateFiles(projectCreatingParams.template, root)
224
+ }, {
225
+ title: 'Install sub CLI dependencies',
226
+ task: () => {
227
+ const subCliName = `@ones-open/cli-${projectCreatingParams.template}`;
228
+ return installSubCli({
229
+ subCliName,
230
+ root,
231
+ installLocalDependencies,
232
+ distTag
233
+ });
234
+ }
235
+ }];
236
+ const createProject = new Listr(projectCreatingTasks);
237
+ const externalTask = getExternalTaskByTemplateType(root, projectCreatingParams, {
238
+ ...options,
239
+ distTag
240
+ });
241
+ externalTask && createProject.add(externalTask);
242
+ await createProject.run(projectCreatingParams);
243
+ console.log(chalk.bold('\nProject has been created'), `\n${chalk.bold('Project path:')} ${chalk.green(root)}`, `\n${chalk.bold('Project name:')} ${chalk.green(projectCreatingParams.name)}`, `\n${chalk.bold('Project type:')} ${chalk.green(projectCreatingParams.template)}`, `\n${chalk.bold('Project description:')} ${chalk.green(projectCreatingParams.description)}`, `\n${chalk.bold('Project sub CLI:')} ${chalk.green(`@ones-open/cli-${projectCreatingParams.template}`)}`);
244
+ } catch (error) {
245
+ console.error(chalk.red(error));
246
+ await printEnvironmentInfo();
247
+ }
248
+ }
249
+
250
+ const cliVersion = (await getCliVersionByMetaPath(import.meta.url)) || 'unknown';
251
+ const ones = new Command('ones');
252
+ const gray = chalk.gray;
253
+ ones.version(cliVersion, '-v, --version', 'output the current version');
254
+ ones.command('create [project-name]').description(`create project from preset project template by type
255
+ ${gray(`
256
+ Tip: if you leave the [project-name] blank and
257
+ 1. not specified the specific path, then will use current folder name as default project name
258
+ 2. the specific path is also specified, then will use the folder name as default project name
259
+ `)}`).option('-d, --use-default-preset', 'skip prompts and use default preset').option('-s, --specific-path <path>', 'create at a specific path, it will automatically detect relative or absolute path').option('--plugin-type [type]', 'support type: team, organization', 'team').option('--policy <policy>', 'support policy: simple, standard', 'simple').addOption(new Option('-t, --project-type <type>', 'the type of project template, support: monorepo, plugin').default('plugin').hideHelp(true)).addOption(new Option('--install-local-dependencies', 'development only, install local dependencies after create project').hideHelp(true)).addOption(new Option('--dist-tag <tag>', 'specify the dist tag of sub CLI dependencies, default: latest').hideHelp(true)).addOption(new Option('--ones-version <onesVersion>', 'specify the version of ONES')).action(createProject);
260
+ ones.command('envinfo').description('print environment info').action(printEnvironmentInfo);
261
+ ones.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ones-open/cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Command line interface for developers",
5
5
  "bin": {
6
6
  "ones": "./bin/index.es.js"
@@ -40,8 +40,8 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@ones-open/cli-plugin": "^2.1.0",
44
- "@ones-open/cli-utils": "^2.1.0",
43
+ "@ones-open/cli-plugin": "^2.1.1",
44
+ "@ones-open/cli-utils": "^2.1.1",
45
45
  "chalk": "~5.0.1",
46
46
  "commander": "~9.4.0",
47
47
  "envinfo": "~7.8.1",
@@ -56,5 +56,5 @@
56
56
  "@types/listr": "^0.14.4"
57
57
  },
58
58
  "type": "module",
59
- "gitHead": "a15f5cf783067b23ff384818c3270eabc8675d5c"
59
+ "gitHead": "1e51d94a7a0362a4d26958a4f47b116914e12e5f"
60
60
  }