@vcmap/plugin-cli 1.0.1 → 2.0.2

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/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@vcmap/plugin-cli",
3
- "version": "1.0.1",
4
- "description": "A CLI to help develop and build plugins for the virtualcityMAP",
3
+ "version": "2.0.2",
4
+ "description": "A CLI to help develop and build plugins for the VC Map",
5
5
  "main": "index.js",
6
+ "type": "module",
6
7
  "bin": {
7
8
  "vcmplugin": "cli.js"
8
9
  },
@@ -10,9 +11,14 @@
10
11
  "lint": "eslint . --env node",
11
12
  "test": "echo \"Error: no test specified\" && exit 1"
12
13
  },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/virtualcitySYSTEMS/map-plugin-cli.git"
17
+ },
13
18
  "author": "Ben Kuster <bkuster@virtualcitysystems.de>",
14
19
  "license": "MIT",
15
20
  "files": [
21
+ "assets/",
16
22
  "src/",
17
23
  "cli.js",
18
24
  "README.md",
@@ -20,35 +26,54 @@
20
26
  "LICENSE.md"
21
27
  ],
22
28
  "dependencies": {
23
- "@babel/core": "^7.10.2",
24
- "@babel/runtime": "^7.13.10",
29
+ "@vcmap/rollup-plugin-vcs-ol": "^1.0.1",
25
30
  "@vcsuite/cli-logger": "^1.0.0",
26
- "@vue/babel-preset-app": "^4.5.4",
27
31
  "archiver": "^5.0.0",
28
- "autoprefixer": "^9.8.6",
29
- "babel-loader": "^8.1.0",
30
32
  "commander": "^6.0.0",
31
- "css-loader": "^3.6.0",
32
- "postcss-loader": "^3.0.0",
33
+ "express": "^4.17.3",
33
34
  "prompts": "^2.4.1",
35
+ "sass": "1.32.13",
34
36
  "semver": "^7.3.5",
35
- "terser-webpack-plugin": "^5.1.1",
36
- "url-loader": "^4.1.0",
37
+ "unplugin-vue-components": "^0.17.21",
37
38
  "vinyl-fs": "^3.0.3",
38
- "vue": "^2.6.12",
39
- "vue-loader": "^15.9.6",
40
- "vue-template-compiler": "^2.6.12",
41
- "webpack": "^5.36.2",
42
- "webpack-dev-server": "^3.11.2"
39
+ "vite": "^2.9.1",
40
+ "vite-plugin-vue2": "^1.7.3",
41
+ "vue-template-compiler": "^2.6.14"
42
+ },
43
+ "peerDependencies": {
44
+ "@vcmap/ui": "^5.0.0-rc.6"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@vcmap/ui": {
48
+ "optional": true
49
+ }
43
50
  },
44
51
  "devDependencies": {
45
- "@vcsuite/eslint-config": "^1.0.0",
46
- "eslint": "^7.25.0"
52
+ "@vcsuite/eslint-config": "^2.1.1",
53
+ "eslint": "^8.9.0"
47
54
  },
48
55
  "eslintIgnore": [
49
- "node_modules"
56
+ "node_modules",
57
+ "assets/helloWorld"
50
58
  ],
51
59
  "eslintConfig": {
52
- "extends": "@vcsuite/eslint-config/node"
60
+ "extends": "@vcsuite/eslint-config/node",
61
+ "parserOptions": {
62
+ "ecmaVersion": 2020
63
+ },
64
+ "rules": {
65
+ "import/no-unresolved": [
66
+ 2,
67
+ {
68
+ "ignore": [
69
+ "^@vcmap/ui"
70
+ ]
71
+ }
72
+ ]
73
+ }
74
+ },
75
+ "engines": {
76
+ "node": "^16.14.0",
77
+ "npm": "^8.3.0"
53
78
  }
54
79
  }
package/src/build.js CHANGED
@@ -1,32 +1,94 @@
1
- const webpack = require('webpack');
2
- const { logger } = require('@vcsuite/cli-logger');
3
- const { getPluginName } = require('./packageJsonHelpers');
4
- const { getProdWebpackConfig } = require('./getWebpackConfig');
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { createVuePlugin } from 'vite-plugin-vue2';
4
+ import vcsOl from '@vcmap/rollup-plugin-vcs-ol';
5
+ import { logger } from '@vcsuite/cli-logger';
6
+ import { VuetifyResolver } from 'unplugin-vue-components/dist/resolvers.js';
7
+ import Components from 'unplugin-vue-components/dist/vite.js';
8
+ import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
9
+ import { getContext } from './context.js';
5
10
 
6
- async function build(options) {
7
- function webpackHandler(err, stats) {
8
- if (err) {
9
- logger.error(err);
10
- } else if (stats.hasErrors()) {
11
- logger.error(stats.compilation.errors);
12
- } else {
13
- logger.success(`built ${options.pluginName}`);
14
- }
15
- logger.stopSpinner();
16
- }
11
+ /**
12
+ * @typedef {Object} BuildOptions
13
+ * @property {boolean} [development]
14
+ * @property {boolean} [watch]
15
+ */
17
16
 
18
- options.pluginName = options.pluginName || await getPluginName();
19
- logger.spin(`compiling ${options.pluginName}`);
20
- options.mode = options.development ? 'development' : 'production';
17
+ export function getDefaultConfig() {
18
+ return {
19
+ publicDir: false,
20
+ plugins: [
21
+ createVuePlugin(),
22
+ Components({
23
+ resolvers: [
24
+ VuetifyResolver(),
25
+ ],
26
+ dirs: ['./src'],
27
+ include: [],
28
+ exclude: [],
29
+ }),
30
+ vcsOl(),
31
+ ],
32
+ };
33
+ }
21
34
 
22
- const config = await getProdWebpackConfig(options);
23
- const compiler = webpack(config);
35
+ /**
36
+ * @param {string} pluginName
37
+ * @returns {Object<string, string>}
38
+ */
39
+ export async function getLibraryPaths(pluginName) {
40
+ const { libraries } = await import('@vcmap/ui/build/buildHelpers.js');
41
+ const pluginPath = path.join('plugins', ...pluginName.split('/'));
42
+ const libraryPaths = {};
43
+ Object.entries(libraries).forEach(([library, assetName]) => {
44
+ const assetPath = path.join('assets', `${assetName}.js`);
24
45
 
25
- if (options.watch) {
26
- compiler.watch({}, webpackHandler);
27
- } else {
28
- compiler.run(webpackHandler);
29
- }
46
+ libraryPaths[library] = path.relative(pluginPath, assetPath);
47
+ });
48
+ return libraryPaths;
30
49
  }
31
50
 
32
- module.exports = build;
51
+ /**
52
+ * @param {BuildOptions} options
53
+ * @returns {Promise<void>}
54
+ */
55
+ export default async function buildModule(options) {
56
+ const entry = await getPluginEntry();
57
+ if (path.relative('src', entry).startsWith('.')) {
58
+ logger.warning(`detected irregular entry ${entry}`);
59
+ logger.warning('vuetify component resolution expects source files to be within "src"');
60
+ }
61
+
62
+ const pluginName = await getPluginName();
63
+ const libraryPaths = await getLibraryPaths(pluginName);
64
+ const distPath = path.join(getContext(), 'dist');
65
+ await fs.rm(distPath, { recursive: true, force: true });
66
+ await fs.mkdir(distPath);
67
+ const external = Object.keys(libraryPaths);
68
+ const config = {
69
+ ...getDefaultConfig(),
70
+ esbuild: {
71
+ minify: !options.development,
72
+ },
73
+ build: {
74
+ write: false,
75
+ emptyOutDir: false,
76
+ lib: {
77
+ entry,
78
+ formats: ['es'],
79
+ fileName: () => 'index.js',
80
+ },
81
+ rollupOptions: {
82
+ external,
83
+ output: {
84
+ paths: libraryPaths,
85
+ },
86
+ },
87
+ watch: options.watch ? {
88
+ skipWrite: true,
89
+ } : null,
90
+ },
91
+ };
92
+ const { buildLibrary } = await import('@vcmap/ui/build/buildHelpers.js');
93
+ await buildLibrary(config, '', 'index', '', true);
94
+ }
package/src/context.js CHANGED
@@ -1,25 +1,22 @@
1
- const path = require('path');
1
+ import path from 'path';
2
+ import fs from 'fs';
2
3
 
3
4
  let context = null;
4
5
 
5
- function setContext(c) {
6
+ export function setContext(c) {
6
7
  if (context) {
7
8
  throw new Error('cannot set context twice');
8
9
  }
9
- context = c;
10
+ if (!fs.existsSync(c) || !fs.statSync(c).isDirectory()) {
11
+ throw new Error('context must be an existing directory');
12
+ }
13
+ context = path.resolve(c);
10
14
  }
11
15
 
12
- function getContext() {
16
+ export function getContext() {
13
17
  return context || process.cwd();
14
18
  }
15
19
 
16
- function resolveContext(...dir) {
20
+ export function resolveContext(...dir) {
17
21
  return path.join(getContext(), ...dir);
18
22
  }
19
-
20
-
21
- module.exports = {
22
- getContext,
23
- resolveContext,
24
- setContext,
25
- };
package/src/create.js CHANGED
@@ -1,11 +1,14 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const prompts = require('prompts');
4
- const semver = require('semver');
5
- const util = require('util');
6
- const childProcess = require('child_process');
7
- const { logger } = require('@vcsuite/cli-logger');
8
- const { version, name } = require('../package.json');
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import prompts from 'prompts';
4
+ import semver from 'semver';
5
+ import util from 'util';
6
+ import childProcess from 'child_process';
7
+ import { logger } from '@vcsuite/cli-logger';
8
+ import { LicenseType, writeLicense } from './licenses.js';
9
+ import { getDirname } from './hostingHelpers.js';
10
+
11
+ export const { version, name } = JSON.parse(fs.readFileSync(path.join(getDirname(), '..', 'package.json')).toString());
9
12
 
10
13
  /**
11
14
  * @typedef {Object} PluginTemplateOptions
@@ -14,9 +17,11 @@ const { version, name } = require('../package.json');
14
17
  * @property {string} description
15
18
  * @property {Array<Object>} scripts
16
19
  * @property {string} author
20
+ * @property {string} repository
17
21
  * @property {string} license
18
- * @property {string} mapVersion
19
- * @property {boolean} addDevDep
22
+ * @property {string} registry
23
+ * @property {boolean} addCiCd
24
+ * @property {Array<string>} peerDeps
20
25
  */
21
26
 
22
27
  /**
@@ -36,23 +41,49 @@ async function createPluginTemplate(options) {
36
41
  }
37
42
 
38
43
  await fs.promises.mkdir(pluginPath);
44
+ await fs.promises.mkdir(path.join(pluginPath, 'plugin-assets'));
39
45
  logger.debug('created plugin directory');
40
-
41
46
  const packageJson = {
42
47
  name: options.name,
43
48
  version: options.version,
44
49
  description: options.description,
45
50
  main: 'src/index.js',
46
- scripts: Object.assign({}, ...options.scripts),
51
+ scripts: Object.assign({ prepublishOnly: 'vcmplugin build' }, ...options.scripts),
47
52
  author: options.author,
48
53
  license: options.license,
49
- engines: {
50
- vcm: options.mapVersion,
51
- },
52
54
  dependencies: {},
53
- devDependencies: options.addDevDep ? { [name]: `^${version}` } : {},
55
+ keywords: [
56
+ 'vcmap',
57
+ 'plugin',
58
+ ],
59
+ files: [
60
+ 'src/',
61
+ 'dist/',
62
+ 'plugin-assets/',
63
+ 'LICENSE.md',
64
+ 'README.md',
65
+ ],
66
+ exports: {
67
+ '.': './src/index.js',
68
+ './dist': './dist/index.js',
69
+ },
54
70
  };
55
71
 
72
+ if (options.repository) {
73
+ packageJson.repository = {
74
+ url: options.repository,
75
+ };
76
+ }
77
+
78
+ const installEsLint = options.scripts.find(script => script.lint);
79
+ if (installEsLint) {
80
+ packageJson.eslintIgnore = ['node_modules'];
81
+ packageJson.eslintConfig = {
82
+ root: true,
83
+ extends: '@vcsuite/eslint-config/vue',
84
+ };
85
+ }
86
+
56
87
  const writePackagePromise = fs.promises.writeFile(
57
88
  path.join(pluginPath, 'package.json'),
58
89
  JSON.stringify(packageJson, null, 2),
@@ -60,7 +91,6 @@ async function createPluginTemplate(options) {
60
91
 
61
92
  const configJson = {
62
93
  name: options.name,
63
- version: options.version,
64
94
  };
65
95
 
66
96
  const writeConfigPromise = fs.promises.writeFile(
@@ -68,6 +98,11 @@ async function createPluginTemplate(options) {
68
98
  JSON.stringify(configJson, null, 2),
69
99
  );
70
100
 
101
+ const writeNpmrcPromise = fs.promises.writeFile(
102
+ path.join(pluginPath, '.npmrc'),
103
+ `registry=${options.registry}\n`,
104
+ );
105
+
71
106
  const writeReadmePromise = fs.promises.writeFile(
72
107
  path.join(pluginPath, 'README.md'),
73
108
  [
@@ -76,30 +111,47 @@ async function createPluginTemplate(options) {
76
111
  ].join('\n'),
77
112
  );
78
113
 
114
+ const writeChangesPromise = fs.promises.writeFile(
115
+ path.join(pluginPath, 'CHANGES.md'),
116
+ `# v${options.version}\nDocument features and fixes`,
117
+ );
118
+
79
119
  await fs.promises.mkdir(path.join(pluginPath, 'src'));
80
120
  logger.debug('created src directory');
81
121
 
82
- const writeIndexPromise = fs.promises.writeFile(
83
- path.join(pluginPath, 'src', 'index.js'),
84
- ['import { version } from \'../package.json\';',
85
- '',
86
- 'export default {',
87
- ' version,',
88
- ' // preInitialize',
89
- ' // postInitialize',
90
- ' // registerUiPlugin',
91
- ' // postUiInitialize',
92
- '};'].join('\n'),
122
+ const copyTemplatePromise = fs.promises.cp(
123
+ path.join(getDirname(), '..', 'assets', 'helloWorld'),
124
+ pluginPath,
125
+ { recursive: true },
93
126
  );
94
127
 
95
- await Promise.all([writePackagePromise, writeConfigPromise, writeReadmePromise, writeIndexPromise]);
128
+ await Promise.all([
129
+ writePackagePromise,
130
+ writeConfigPromise,
131
+ writeNpmrcPromise,
132
+ writeReadmePromise,
133
+ writeChangesPromise,
134
+ copyTemplatePromise,
135
+ writeLicense(options.author, options.license, pluginPath),
136
+ ]);
137
+
96
138
 
97
- logger.spin('installing dependencies...');
139
+ logger.spin('installing dependencies... (this may take a while)');
98
140
  const exec = util.promisify(childProcess.exec);
99
141
  try {
100
- const { stdout, stderr } = await exec('npm i', { cwd: pluginPath });
142
+ options.peerDeps.push('@vcmap/ui');
143
+ const installCmd = `npm i --save-peer ${options.peerDeps.join(' ')}`;
144
+ const { stdout, stderr } = await exec(installCmd, { cwd: pluginPath });
101
145
  logger.log(stdout);
102
146
  logger.error(stderr);
147
+ const devDeps = [`${name}@${version}`];
148
+ if (installEsLint) {
149
+ devDeps.push('@vcsuite/eslint-config');
150
+ }
151
+ const installDevCmd = `npm i --save-dev ${devDeps.join(' ')}`;
152
+ const { stdout: stdoutDev, stderr: stderrDev } = await exec(installDevCmd, { cwd: pluginPath });
153
+ logger.log(stdoutDev);
154
+ logger.error(stderrDev);
103
155
  logger.success('installed dependencies');
104
156
  } catch (e) {
105
157
  logger.error(e);
@@ -112,11 +164,21 @@ async function createPluginTemplate(options) {
112
164
  /**
113
165
  * @returns {Promise<void>}
114
166
  */
115
- async function create() {
167
+ export default async function create() {
116
168
  const scriptChoices = [
117
- { title: 'build', value: { build: 'vcmplugin build' } },
118
- { title: 'pack', value: { pack: 'vcmplugin pack' } },
119
- { title: 'test', value: { test: 'echo "Error: no test specified" && exit 1' } },
169
+ { title: 'build', value: { build: 'vcmplugin build' }, selected: true },
170
+ { title: 'pack', value: { pack: 'vcmplugin pack' }, selected: true },
171
+ { title: 'start', value: { start: 'vcmplugin serve' }, selected: true },
172
+ { title: 'preview', value: { preview: 'vcmplugin preview' }, selected: true },
173
+ { title: 'lint', value: { lint: 'eslint "{src,tests}/**/*.{js,vue}"' }, selected: true },
174
+ ];
175
+
176
+ const peerDependencyChoices = [
177
+ { title: '@vcsuite/ui-components', value: '@vcsuite/ui-components', selected: true },
178
+ { title: '@vcmap/core', value: '@vcmap/core' },
179
+ { title: '@vcmap/cesium', value: '@vcmap/cesium' },
180
+ { title: 'ol', value: 'ol@~6.13.0' },
181
+ { title: '@vue/composition-api', value: '@vue/composition-api@~1.4.5' },
120
182
  ];
121
183
 
122
184
  const questions = [
@@ -163,21 +225,39 @@ async function create() {
163
225
  },
164
226
  {
165
227
  type: 'text',
228
+ name: 'repository',
229
+ message: 'Repository url',
230
+ // initial: (prev, values) => `https://github.com/virtualcitySYSTEMS/${values.name}.git`,
231
+ },
232
+ {
233
+ type: 'select',
166
234
  name: 'license',
167
235
  message: 'License',
168
- initial: 'ISC',
236
+ initial: 0,
237
+ choices: Object.values(LicenseType)
238
+ .map(type => ({
239
+ title: type,
240
+ value: type,
241
+ })),
169
242
  },
170
243
  {
171
244
  type: 'text',
172
- name: 'mapVersion',
173
- message: 'Map version',
174
- initial: '>=4.0',
245
+ name: 'registry',
246
+ message: 'Set default npm registry',
247
+ initial: 'https://registry.npmjs.org',
248
+ },
249
+ {
250
+ name: 'peerDeps',
251
+ type: 'multiselect',
252
+ message: 'Add the following peer dependencies to the package.json.',
253
+ choices: peerDependencyChoices,
254
+ hint: '- Space to select. Enter to submit',
175
255
  },
176
256
  {
177
257
  type: 'toggle',
178
- name: 'addDevDep',
179
- message: 'Add vcmplugin-cli as dev dependency?',
180
- initial: true,
258
+ name: 'addCiCd',
259
+ message: 'Add default VCS gitlab ci/cd?',
260
+ initial: false,
181
261
  active: 'yes',
182
262
  inactive: 'no',
183
263
  },
@@ -187,5 +267,3 @@ async function create() {
187
267
 
188
268
  await createPluginTemplate(answers);
189
269
  }
190
-
191
- module.exports = create;
@@ -1,19 +1,37 @@
1
- const { Command } = require('commander');
1
+ import { Command } from 'commander';
2
+ import { logger } from '@vcsuite/cli-logger';
3
+ import { setContext } from './context.js';
2
4
 
3
5
  Command.prototype.defaultOptions = function defaultOptions() {
4
6
  this
5
- .option('-n, --plugin-name [name]', 'a name override to use. extracts the name from the package.json by default')
6
- .option('--no-condense-whitespace', 'do not condense white space')
7
- .option('-e, --entry <entry>', 'entrypoint override');
7
+ .option('--context [path]', 'an optional context, default is cwd', (value) => {
8
+ setContext(value);
9
+ return value;
10
+ });
8
11
 
9
12
  return this;
10
13
  };
11
14
 
12
- Command.prototype.defaultBuildOptions = function defaultBuildOptions() {
15
+ Command.prototype.defaultServeOptions = function defaultServeOptions() {
13
16
  this
14
- .defaultOptions()
15
- .option('-l, --library [name]', 'whether to create a library with [name] or not')
16
- .option('--library-target [target]', 'library target', 'commonjs2');
17
+ .option('-p, --port [port]', 'the port to listen on', /\d+/)
18
+ .option('--auth <user:password>', 'an optional auth to append to proxy requests')
19
+ .option('-c, --config <config>', 'a config override to not use the default plugin config')
20
+ .option('--https', 'use https for serving');
17
21
 
18
22
  return this;
19
23
  };
24
+
25
+ Command.prototype.safeAction = function safeAction(action) {
26
+ this.action(async (options) => {
27
+ try {
28
+ await action(options);
29
+ } catch (e) {
30
+ if (e) {
31
+ logger.error(e);
32
+ }
33
+ logger.stopSpinner();
34
+ process.exit(1);
35
+ }
36
+ });
37
+ };