@vcmap/plugin-cli 2.1.11 → 2.1.12

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
@@ -291,6 +291,12 @@ configuration of the plugin as its first argument and the base URL (without the
291
291
  from which the plugin was loaded as its second argument.
292
292
 
293
293
  ```typescript
294
+ declare type PluginConfigEditor = {
295
+ component: VueComponent;
296
+ collectionName?: string;
297
+ itemName?: string;
298
+ };
299
+
294
300
  declare interface VcsPlugin<T extends Object, S extends Object> {
295
301
  readonly name: string;
296
302
  readonly version: string;
@@ -298,6 +304,8 @@ declare interface VcsPlugin<T extends Object, S extends Object> {
298
304
  onVcsAppMounted(app: VcsUiApp): Promise<void>;
299
305
  getState(): Promise<S>;
300
306
  toJSON(): Promise<T>;
307
+ getDefaultOptions(): T;
308
+ getConfigEditors(): Array<PluginConfigEditor>;
301
309
  destroy(): void;
302
310
  }
303
311
 
@@ -307,6 +315,8 @@ declare function defaultExport<T extends Object, S extends Object>(
307
315
  ): VcsPlugin<T, S>;
308
316
  ```
309
317
 
318
+ > The function default export should not throw! Put exceptions in initialize instead.
319
+
310
320
  A Simple JavaScript implementation of this interface can be seen below::
311
321
 
312
322
  ```javascript
@@ -330,9 +340,15 @@ export default function defaultExport(config, baseUrl) {
330
340
  async getState() {
331
341
  return {};
332
342
  },
343
+ getDefaultOptions() {
344
+ return {};
345
+ },
333
346
  async toJSON() {
334
347
  return {};
335
348
  },
349
+ getConfigEditors() {
350
+ return [];
351
+ },
336
352
  destroy() {},
337
353
  };
338
354
  }
@@ -1,5 +1,5 @@
1
1
  default:
2
- image: gitlab.virtualcitysystems.de:5050/vcsuite/devops/gitlabrunner/node:16-bullseye
2
+ image: gitlab.virtualcitysystems.de:5050/vcsuite/devops/gitlabrunner/node:18-bullseye
3
3
 
4
4
  variables:
5
5
  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_PROJECT_PATH_SLUG/$CI_COMMIT_REF_SLUG
package/assets/index.html CHANGED
@@ -1,48 +1,38 @@
1
1
  <!DOCTYPE html>
2
2
  <html class="vcs-ui" lang="en">
3
3
  <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0" />
4
+ <title>VC Map</title>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
7
  <link
7
8
  rel="icon"
8
9
  type="image/png"
9
10
  href="./assets/favicon-32.png"
10
11
  sizes="32x32"
11
- />
12
+ >
12
13
  <link
13
14
  rel="icon"
14
15
  type="image/png"
15
16
  href="./assets/favicon-128.png"
16
17
  sizes="128x128"
17
- />
18
+ >
18
19
  <link
19
20
  rel="icon"
20
21
  type="image/png"
21
22
  href="./assets/favicon-180.png"
22
23
  sizes="180x180"
23
- />
24
+ >
24
25
  <link
25
26
  rel="icon"
26
27
  type="image/png"
27
28
  href="./assets/favicon-192.png"
28
29
  sizes="192x192"
29
- />
30
- <link rel="icon" type="image/svg+xml" href="./assets/favicon.svg" />
30
+ >
31
+ <link rel="icon" type="image/svg+xml" href="./assets/favicon.svg">
31
32
  <link
32
33
  rel="stylesheet"
33
34
  href="./assets/@mdi/font/css/materialdesignicons.min.css"
34
- />
35
- </head>
36
- <body style="height: 100vh">
37
- <noscript>
38
- <strong>...</strong>
39
- </noscript>
40
- <div id="app">
41
- <div id="loading-wrapper">
42
- <div id="loading-text">LOADING</div>
43
- <div id="loading-content"></div>
44
- </div>
45
- </div>
35
+ >
46
36
  <style>
47
37
  #loading-wrapper {
48
38
  position: fixed;
@@ -57,7 +47,7 @@
57
47
  position: absolute;
58
48
  top: 50%;
59
49
  left: 50%;
60
- color: #409d76;
50
+ color: grey;
61
51
  width: 100px;
62
52
  height: 30px;
63
53
  margin: -7px 0 0 -45px;
@@ -78,8 +68,8 @@
78
68
 
79
69
  #loading-content {
80
70
  border: 3px solid transparent;
81
- border-top-color: #409d76;
82
- border-bottom-color: #409d76;
71
+ border-top-color: grey;
72
+ border-bottom-color: grey;
83
73
  border-radius: 50%;
84
74
  -webkit-animation: loader 2s linear infinite;
85
75
  -moz-animation: loader 2s linear infinite;
@@ -101,8 +91,20 @@
101
91
  }
102
92
  }
103
93
  </style>
94
+ </head>
95
+ <body style="height: 100vh">
96
+ <noscript>
97
+ <strong>...</strong>
98
+ </noscript>
99
+ <div id="app">
100
+ <div id="loading-wrapper">
101
+ <div id="loading-text">LOADING</div>
102
+ <div id="loading-content"></div>
103
+ </div>
104
+ </div>
104
105
  <script type="module">
105
106
  import { initAppFromAppConfig } from '@vcmap/ui';
107
+
106
108
  initAppFromAppConfig('#app', 'app.config.json');
107
109
  </script>
108
110
  </body>
package/assets/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { version, name } from '../package.json';
1
+ import { name, version, mapVersion } from '../package.json';
2
2
 
3
3
  /**
4
4
  * @typedef {Object} PluginState
@@ -6,6 +6,7 @@ import { version, name } from '../package.json';
6
6
  */
7
7
 
8
8
  /**
9
+ * Implementation of VcsPlugin interface. This function should not throw! Put exceptions in initialize instead.
9
10
  * @param {T} config - the configuration of this plugin instance, passed in from the app.
10
11
  * @param {string} baseUrl - the absolute URL from which the plugin was loaded (without filename, ending on /)
11
12
  * @returns {import("@vcmap/ui/src/vcsUiApp").VcsPlugin<T, PluginState>}
@@ -21,6 +22,9 @@ export default function plugin(config, baseUrl) {
21
22
  get version() {
22
23
  return version;
23
24
  },
25
+ get mapVersion() {
26
+ return mapVersion;
27
+ },
24
28
  /**
25
29
  * @param {import("@vcmap/ui").VcsUiApp} vcsUiApp
26
30
  * @param {PluginState=} state
@@ -46,6 +50,14 @@ export default function plugin(config, baseUrl) {
46
50
  );
47
51
  },
48
52
  /**
53
+ * should return all default values of the configuration
54
+ * @returns {T}
55
+ */
56
+ getDefaultOptions() {
57
+ return {};
58
+ },
59
+ /**
60
+ * should return the plugin's serialization excluding all default values
49
61
  * @returns {T}
50
62
  */
51
63
  toJSON() {
@@ -65,6 +77,13 @@ export default function plugin(config, baseUrl) {
65
77
  prop: '*',
66
78
  };
67
79
  },
80
+ /**
81
+ * components for configuring the plugin and/ or custom items defined by the plugin
82
+ * @returns {Array<import("@vcmap/ui").PluginConfigEditor>}
83
+ */
84
+ getConfigEditors() {
85
+ return [];
86
+ },
68
87
  destroy() {
69
88
  // eslint-disable-next-line no-console
70
89
  console.log('hook to cleanup');
@@ -0,0 +1,33 @@
1
+ dist/
2
+ plugin-assets/
3
+ public/
4
+ test-report.xml
5
+
6
+ # local env files
7
+ .env.local
8
+ .env.*.local
9
+
10
+ # Log files
11
+ npm-debug.log*
12
+ yarn-debug.log*
13
+ yarn-error.log*
14
+ pnpm-debug.log*
15
+
16
+ # Editor directories and files
17
+ .idea
18
+ .vscode
19
+ *.suo
20
+ *.ntvs*
21
+ *.njsproj
22
+ *.sln
23
+ *.sw?
24
+
25
+ # test output
26
+ .nyc_output
27
+ coverage
28
+
29
+ # static output
30
+ docs
31
+
32
+ # index.html (prettier does not take modern html 5 rules that closing tags for void elements should be avoided)
33
+ assets/index.html
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": ["@vcsuite/eslint-config/mocha"],
3
+ "rules": {
4
+ "import/extensions": ["error", "always"]
5
+ }
6
+ }
@@ -0,0 +1,15 @@
1
+ import { describe, it, expect, beforeAll } from 'vitest';
2
+ import plugin from '../src/index.js';
3
+ import { name } from '../package.json';
4
+
5
+ describe('sample test spec', () => {
6
+ describe('plugin name', () => {
7
+ let pluginInstance;
8
+ beforeAll(() => {
9
+ pluginInstance = plugin({}, 'localhost');
10
+ });
11
+ it('should return the plugin name from the package.json', () => {
12
+ expect(pluginInstance.name).to.equal(name);
13
+ });
14
+ });
15
+ });
@@ -0,0 +1,17 @@
1
+ /* eslint-disable import/no-extraneous-dependencies, import/first */
2
+ import { vi } from 'vitest';
3
+
4
+ vi.hoisted(() => {
5
+ global.jest = vi;
6
+ });
7
+
8
+ import ResizeObserver from 'resize-observer-polyfill';
9
+
10
+ global.ResizeObserver = ResizeObserver;
11
+
12
+ import 'jest-canvas-mock';
13
+ import Vue from 'vue';
14
+
15
+ Vue.config.productionTip = false;
16
+
17
+ window.CESIUM_BASE_URL = '/node_modules/@vcmap-cesium/engine/Build/';
package/cli.js CHANGED
@@ -42,6 +42,13 @@ program.command('buildStagingApp').defaultOptions().safeAction(buildStagingApp);
42
42
 
43
43
  program.command('setup-map-ui').safeAction(setupMapUi);
44
44
 
45
- program.command('update').defaultOptions().safeAction(update);
45
+ program
46
+ .command('update')
47
+ .defaultOptions()
48
+ .option(
49
+ '--mapVersion [semver]',
50
+ 'an optional semver range to update to, e.g. 5.0 (Default is latest)',
51
+ )
52
+ .safeAction(update);
46
53
 
47
54
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/plugin-cli",
3
- "version": "2.1.11",
3
+ "version": "2.1.12",
4
4
  "description": "A CLI to help develop and build plugins for the VC Map",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -31,18 +31,18 @@
31
31
  "dependencies": {
32
32
  "@vcmap/rollup-plugin-vcs-ol": "^1.0.2",
33
33
  "@vcsuite/cli-logger": "^1.0.0",
34
+ "@vitejs/plugin-vue2": "^2.2.0",
34
35
  "commander": "^10.0.1",
35
36
  "express": "^4.18.2",
36
37
  "prompts": "^2.4.2",
37
38
  "sass": "1.32.13",
38
- "semver": "^7.5.1",
39
+ "semver": "^7.5.4",
39
40
  "tar": "^6.1.15",
40
- "vite": "^4.3.9",
41
- "@vitejs/plugin-vue2": "^2.2.0",
41
+ "vite": "^4.4.9",
42
42
  "vue-template-compiler": "~2.7.14"
43
43
  },
44
44
  "peerDependencies": {
45
- "@vcmap/ui": "^5.0.0-rc.29",
45
+ "@vcmap/ui": "^5.0.0",
46
46
  "vue": "~2.7.14"
47
47
  },
48
48
  "peerDependenciesMeta": {
@@ -54,11 +54,12 @@
54
54
  }
55
55
  },
56
56
  "devDependencies": {
57
- "@vcsuite/eslint-config": "^3.0.3",
57
+ "@vcsuite/eslint-config": "^3.0.5",
58
58
  "eslint": "^8.38.0"
59
59
  },
60
60
  "eslintIgnore": [
61
- "node_modules"
61
+ "node_modules",
62
+ "assets/tests"
62
63
  ],
63
64
  "eslintConfig": {
64
65
  "extends": "@vcsuite/eslint-config/node",
@@ -78,7 +79,7 @@
78
79
  },
79
80
  "prettier": "@vcsuite/eslint-config/prettier.js",
80
81
  "engines": {
81
- "node": "^16.14.0",
82
- "npm": "^8.3.0"
82
+ "node": "^18.12.0",
83
+ "npm": "^9.0.0"
83
84
  }
84
85
  }
package/src/create.js CHANGED
@@ -5,7 +5,7 @@ import semver from 'semver';
5
5
  import tar from 'tar';
6
6
  import { logger } from '@vcsuite/cli-logger';
7
7
  import { LicenseType, writeLicense } from './licenses.js';
8
- import { DepType, installDeps } from './packageJsonHelpers.js';
8
+ import { DepType, installDeps, setVcMapVersion } from './packageJsonHelpers.js';
9
9
  import { updatePeerDependencies } from './update.js';
10
10
  import { name, version, promiseExec, getDirname } from './pluginCliHelper.js';
11
11
 
@@ -23,6 +23,41 @@ import { name, version, promiseExec, getDirname } from './pluginCliHelper.js';
23
23
  * @property {boolean} gitlabCi
24
24
  */
25
25
 
26
+ /**
27
+ *
28
+ * @param {PluginTemplateOptions} options
29
+ * @returns {Object}
30
+ */
31
+ function createPackageJson(options) {
32
+ return {
33
+ name: options.name,
34
+ version: options.version,
35
+ description: options.description,
36
+ type: 'module',
37
+ main: 'src/index.js',
38
+ scripts: Object.assign(
39
+ { prepublishOnly: 'vcmplugin build' },
40
+ ...options.scripts,
41
+ ),
42
+ author: options.author,
43
+ license: options.license,
44
+ dependencies: {},
45
+ keywords: ['vcmap', 'plugin'],
46
+ files: [
47
+ 'src/',
48
+ 'dist/',
49
+ 'plugin-assets/',
50
+ 'LICENSE.md',
51
+ 'README.md',
52
+ 'CHANGELOG.md',
53
+ ],
54
+ exports: {
55
+ '.': './src/index.js',
56
+ './dist': './dist/index.js',
57
+ },
58
+ };
59
+ }
60
+
26
61
  /**
27
62
  * @param {string} pluginName
28
63
  * @param {string} pluginPath
@@ -46,7 +81,7 @@ async function downloadAndExtractPluginTar(
46
81
  const extractOptions = {
47
82
  file: tarPath,
48
83
  cwd: pluginPath,
49
- strip: 1,
84
+ strip: 4,
50
85
  };
51
86
  if (filter) {
52
87
  extractOptions.filter = (entryPath) =>
@@ -65,20 +100,16 @@ async function downloadAndExtractPluginTar(
65
100
  * @returns {Promise<void>}
66
101
  */
67
102
  async function copyPluginTemplate(options, pluginPath) {
68
- await downloadAndExtractPluginTar(options.template, pluginPath);
103
+ await downloadAndExtractPluginTar('@vcmap/ui', pluginPath, [
104
+ path.join('plugins', options.template),
105
+ ]);
69
106
 
70
107
  const pluginPackageJson = JSON.parse(
71
108
  (
72
109
  await fs.promises.readFile(path.join(pluginPath, 'package.json'))
73
110
  ).toString(),
74
111
  );
75
- const userPackageJson = {
76
- name: options.name,
77
- version: options.version,
78
- description: options.description,
79
- author: options.author,
80
- license: options.license,
81
- };
112
+ const userPackageJson = createPackageJson(options);
82
113
  const packageJson = { ...pluginPackageJson, ...userPackageJson };
83
114
  if (options.repository) {
84
115
  packageJson.repository = {
@@ -93,11 +124,10 @@ async function copyPluginTemplate(options, pluginPath) {
93
124
  JSON.stringify(packageJson, null, 2),
94
125
  );
95
126
 
96
- const configJson = JSON.parse(
97
- (
98
- await fs.promises.readFile(path.join(pluginPath, 'config.json'))
99
- ).toString(),
100
- );
127
+ const configPath = path.join(pluginPath, 'config.json');
128
+ const configJson = fs.existsSync(configPath)
129
+ ? JSON.parse((await fs.promises.readFile(configPath)).toString())
130
+ : {};
101
131
  configJson.name = options.name;
102
132
 
103
133
  const writeConfigPromise = fs.promises.writeFile(
@@ -140,33 +170,7 @@ async function createPluginTemplate(options, pluginPath) {
140
170
  options.scripts.push({ coverage: 'vitest run --coverage' });
141
171
  }
142
172
 
143
- const packageJson = {
144
- name: options.name,
145
- version: options.version,
146
- description: options.description,
147
- type: 'module',
148
- main: 'src/index.js',
149
- scripts: Object.assign(
150
- { prepublishOnly: 'vcmplugin build' },
151
- ...options.scripts,
152
- ),
153
- author: options.author,
154
- license: options.license,
155
- dependencies: {},
156
- keywords: ['vcmap', 'plugin'],
157
- files: [
158
- 'src/',
159
- 'dist/',
160
- 'plugin-assets/',
161
- 'LICENSE.md',
162
- 'README.md',
163
- 'CHANGELOG.md',
164
- ],
165
- exports: {
166
- '.': './src/index.js',
167
- './dist': './dist/index.js',
168
- },
169
- };
173
+ const packageJson = createPackageJson(options);
170
174
 
171
175
  if (options.repository) {
172
176
  packageJson.repository = {
@@ -176,7 +180,7 @@ async function createPluginTemplate(options, pluginPath) {
176
180
 
177
181
  const installEsLint = options.scripts.find((script) => script.lint);
178
182
  if (installEsLint) {
179
- packageJson.eslintIgnore = ['node_modules'];
183
+ packageJson.eslintIgnore = ['node_modules', 'dist', 'plugin-assets'];
180
184
  packageJson.eslintConfig = {
181
185
  root: true,
182
186
  extends: '@vcsuite/eslint-config/vue',
@@ -214,10 +218,11 @@ async function createPluginTemplate(options, pluginPath) {
214
218
 
215
219
  if (installVitest) {
216
220
  logger.debug('setting up test environment');
217
- await downloadAndExtractPluginTar('@vcmap/hello-world', pluginPath, [
218
- 'tests',
219
- 'vitest.config.js',
220
- ]);
221
+ await fs.promises.cp(
222
+ path.join(getDirname(), '..', 'assets', 'tests'),
223
+ path.join(pluginPath, 'tests'),
224
+ { recursive: true },
225
+ );
221
226
  }
222
227
 
223
228
  try {
@@ -276,7 +281,11 @@ async function createPlugin(options) {
276
281
 
277
282
  const writeReadmePromise = fs.promises.writeFile(
278
283
  path.join(pluginPath, 'README.md'),
279
- [`# ${options.name}`, 'describe your plugin'].join('\n'),
284
+ [
285
+ `# ${options.name}`,
286
+ '> Part of the [VC Map Project](https://github.com/virtualcitySYSTEMS/map-ui)',
287
+ 'describe your plugin',
288
+ ].join('\n'),
280
289
  );
281
290
 
282
291
  const writeChangesPromise = fs.promises.writeFile(
@@ -289,12 +298,18 @@ async function createPlugin(options) {
289
298
  path.join(pluginPath, '.gitignore'),
290
299
  );
291
300
 
301
+ const copyPrettierIgnorePromise = fs.promises.copyFile(
302
+ path.join(getDirname(), '..', 'assets', 'prettierignore'),
303
+ path.join(pluginPath, '.prettierignore'),
304
+ );
305
+
292
306
  await Promise.all([
293
307
  writeNpmrcPromise,
294
308
  writeReadmePromise,
295
309
  writeChangesPromise,
296
310
  writeLicense(options.author, options.license, pluginPath),
297
311
  copyGitIgnorePromise,
312
+ copyPrettierIgnorePromise,
298
313
  ]);
299
314
 
300
315
  if (options.gitlabCi) {
@@ -314,6 +329,7 @@ async function createPlugin(options) {
314
329
  } else {
315
330
  await createPluginTemplate(options, pluginPath);
316
331
  }
332
+ await setVcMapVersion(pluginPath);
317
333
  logger.success(`Created plugin ${options.name}`);
318
334
  }
319
335
 
@@ -323,7 +339,12 @@ async function createPlugin(options) {
323
339
  export default async function create() {
324
340
  const templateChoices = [
325
341
  { title: 'no template (basic structure)', value: null },
326
- { title: 'hello-world', value: '@vcmap/hello-world' },
342
+ { title: 'hello-world', value: '@vcmap-show-case/hello-world' },
343
+ {
344
+ title: 'context-menu-example',
345
+ value: '@vcmap-show-case/context-menu-tester',
346
+ },
347
+ { title: 'feature-info-example', value: '@vcmap-show-case/simple-graph' },
327
348
  // to add further templates add a choice here
328
349
  ];
329
350
 
@@ -421,7 +442,7 @@ export default async function create() {
421
442
  choices: templateChoices,
422
443
  },
423
444
  {
424
- type: (prev, values) => (!values.template ? 'multiselect' : null),
445
+ type: 'multiselect',
425
446
  message: 'Add the following scripts to the package.json.',
426
447
  name: 'scripts',
427
448
  choices: scriptChoices,
@@ -1,22 +1,29 @@
1
- import fs from 'fs';
1
+ import { existsSync } from 'fs';
2
+ import { writeFile, readFile } from 'fs/promises';
3
+ import { parse, satisfies, validRange } from 'semver';
2
4
  import { logger } from '@vcsuite/cli-logger';
3
- import { resolveContext } from './context.js';
5
+ import path from 'path';
6
+ import { getContext } from './context.js';
4
7
  import { promiseExec } from './pluginCliHelper.js';
5
8
 
6
9
  /** @type {Object|null} */
7
10
  let packageJson = null;
8
11
 
9
12
  /**
13
+ * @param {string} [pluginPath]
10
14
  * @returns {Promise<Object>}
11
15
  */
12
- export async function getPackageJson() {
16
+ export async function getPackageJson(pluginPath) {
13
17
  if (!packageJson) {
14
- const packageJsonFileName = resolveContext('package.json');
15
- if (!fs.existsSync(packageJsonFileName)) {
18
+ const packageJsonFileName = path.join(
19
+ pluginPath || getContext(),
20
+ 'package.json',
21
+ );
22
+ if (!existsSync(packageJsonFileName)) {
16
23
  throw new Error('no package.json found in context');
17
24
  }
18
25
 
19
- const content = await fs.promises.readFile(packageJsonFileName);
26
+ const content = await readFile(packageJsonFileName);
20
27
  packageJson = JSON.parse(content.toString());
21
28
  }
22
29
 
@@ -73,9 +80,67 @@ export async function installDeps(deps, type, pluginPath) {
73
80
  } else if (type === DepType.DEV) {
74
81
  save = '--save-dev';
75
82
  }
76
- const installCmd = `npm i ${save} ${deps.join(' ')}`;
83
+ const installCmd = `npm i ${save} ${deps.map((d) => `"${d}"`).join(' ')}`; // wrap deps with "" for windows
77
84
  logger.debug(installCmd);
78
85
  const { stdout, stderr } = await promiseExec(installCmd, { cwd: pluginPath });
79
86
  logger.log(stdout);
80
87
  logger.error(stderr);
81
88
  }
89
+
90
+ /**
91
+ * Returns the version of the used @vcmap/ui dependency
92
+ * @param {string} [pluginPath]
93
+ * @returns {Promise<string>}
94
+ */
95
+ export async function getVcMapVersion(pluginPath) {
96
+ const { stdout, stderr } = await promiseExec('npm ls --json', {
97
+ cwd: pluginPath || getContext(),
98
+ });
99
+ logger.error(stderr);
100
+ const { dependencies } = JSON.parse(stdout);
101
+ return dependencies['@vcmap/ui'].version;
102
+ }
103
+
104
+ /**
105
+ * @param {string} [pluginPath]
106
+ * @returns {Promise<void>}
107
+ */
108
+ export async function setVcMapVersion(pluginPath) {
109
+ const mapVersion = await getVcMapVersion(pluginPath);
110
+ const { major, minor } = parse(mapVersion);
111
+ const pluginPackageJson = await getPackageJson(pluginPath);
112
+
113
+ pluginPackageJson.mapVersion = `^${major}.${minor}`;
114
+ logger.info(`Setting plugin mapVersion to ${pluginPackageJson.mapVersion}`);
115
+ await writeFile(
116
+ path.join(pluginPath || getContext(), 'package.json'),
117
+ JSON.stringify(pluginPackageJson, null, 2),
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Update the vcsMapVersion in the package.json
123
+ * @param {string} pluginPath
124
+ * @returns {Promise<void>}
125
+ */
126
+ export async function checkVcMapVersion(pluginPath) {
127
+ const pluginPackageJson = await getPackageJson(pluginPath);
128
+ const currentUiVersion = await getVcMapVersion(pluginPath);
129
+ if (pluginPackageJson.mapVersion) {
130
+ if (!validRange(pluginPackageJson.mapVersion)) {
131
+ logger.error(
132
+ `The current mapVersion ${pluginPackageJson.mapVersion} in the package.json is not a valid range!`,
133
+ );
134
+ } else if (
135
+ !satisfies(currentUiVersion, pluginPackageJson.mapVersion, {
136
+ includePrerelease: true,
137
+ })
138
+ ) {
139
+ logger.error(
140
+ 'The currently installed @vcmap/ui version is not covered by the mapVersion version range in the package.json! Due to breaking changes this plugin may not work as expected. Please update dependent API, where necessary!',
141
+ );
142
+ }
143
+ } else {
144
+ await setVcMapVersion(pluginPath);
145
+ }
146
+ }
package/src/serve.js CHANGED
@@ -124,6 +124,7 @@ export default async function serve(options) {
124
124
  'rbush',
125
125
  'rbush-knn',
126
126
  'pbf',
127
+ 'semver',
127
128
  '@vcmap-cesium/engine',
128
129
  'vue',
129
130
  ],
package/src/update.js CHANGED
@@ -1,18 +1,41 @@
1
1
  import { logger } from '@vcsuite/cli-logger';
2
- import { DepType, getPackageJson, installDeps } from './packageJsonHelpers.js';
2
+ import { valid } from 'semver';
3
+ import {
4
+ checkVcMapVersion,
5
+ DepType,
6
+ getPackageJson,
7
+ installDeps,
8
+ } from './packageJsonHelpers.js';
3
9
  import { name, promiseExec } from './pluginCliHelper.js';
10
+ import { getContext } from './context.js';
11
+
12
+ /**
13
+ * @typedef {Object} UpdateOptions
14
+ * @property {string} [mapVersion] - Optional version of @vcmap/ui to update to. Default is latest
15
+ */
4
16
 
5
17
  /**
6
18
  * Update peer dependencies of a provided packageJson with @vcmap/ui@latest peers
7
19
  * @param {Object} pluginPeer - peerDependencies of a plugin
8
20
  * @param {string} pluginPath
21
+ * @param {UpdateOptions} [options]
9
22
  * @returns {Promise<void>}
10
23
  */
11
- export async function updatePeerDependencies(pluginPeer, pluginPath) {
24
+ export async function updatePeerDependencies(
25
+ pluginPeer,
26
+ pluginPath,
27
+ options = {},
28
+ ) {
29
+ if (options.mapVersion && !valid(options.mapVersion)) {
30
+ logger.error(
31
+ `The mapVersion ${options.mapVersion} is not valid. Using 'latest' instead`,
32
+ );
33
+ options.mapVersion = 'latest';
34
+ }
12
35
  const { stdout, stderr } = await promiseExec('npm view @vcmap/ui --json');
13
36
  logger.error(stderr);
14
37
  const { name: mapName, peerDependencies: mapPeer } = JSON.parse(stdout);
15
- const peerDeps = [`${mapName}@latest`]; // @vcmap/ui is a required peer dep and will be updated in any case
38
+ const peerDeps = [`${mapName}@${options.mapVersion || 'latest'}`]; // @vcmap/ui is a required peer dep and will be updated in any case
16
39
  if (pluginPeer) {
17
40
  const pluginPeerDeps = Object.keys(pluginPeer)
18
41
  .filter(
@@ -41,13 +64,16 @@ async function updateCli(pluginPath) {
41
64
  }
42
65
 
43
66
  /**
44
- * Updating peer dependencies to @vmap/ui@latest
67
+ * Updating peer dependencies to @vmap/ui
45
68
  * Updating @vcmap/plugin-cli
69
+ * @param {UpdateOptions} options
46
70
  * @returns {Promise<void>}
47
71
  */
48
- export default async function update() {
72
+ export default async function update(options) {
49
73
  const packageJson = await getPackageJson();
50
- await updatePeerDependencies(packageJson.peerDependencies, process.cwd());
51
- await updateCli(process.cwd());
74
+ const context = getContext();
75
+ await updatePeerDependencies(packageJson.peerDependencies, context, options);
76
+ await checkVcMapVersion(context);
77
+ await updateCli(context);
52
78
  logger.success(`Updated plugin ${packageJson.name}`);
53
79
  }