@vcmap/plugin-cli 4.0.0 → 4.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/README.md CHANGED
@@ -426,12 +426,25 @@ If a plugin does not provide a config editor, the JsonEditor is always used as f
426
426
  To provide a custom editor, the plugin has to implement a `getConfigEditors` method returning one or more editors.
427
427
  A plugin config editor definition consists of
428
428
 
429
- - component: The vue component providing the ui of the editor. This vue component has to extend the `AbstractConfigEditor.vue`, which can be imported from `@vcmap/ui`. The component has to provide two props: `getConfig` for getting the serialized configuration and `setConfig` to update the changed configuration.
429
+ - component: The vue component providing the ui of the editor. This vue component has to extend the `AbstractConfigEditor.vue`, which can be imported from `@vcmap/ui`.
430
+ The component has to provide two props:
431
+ - `getConfig` for getting the serialized configuration and
432
+ - `setConfig` to update the changed configuration (do not pass proxies or anything by reference to setConfig! See note below for more information)
430
433
  - title: An optional title displayed in the window header of the editor and on action buttons (e.g. tooltip)
431
434
  - collectionName: The collection the item belongs to. Default is `plugins` collection. For a layer config editor you would provide `layers`.
432
435
  - itemName: The item the editor can be used for. Can be a name or className. Default is the plugin's name. For a layer you would provide `MyNewLayer.className`.
433
436
  - infoUrlCallback: An optional function returning an url referencing help or further information regarding the config editor.
434
437
 
438
+ > IMPORTANT NOTE:
439
+ >
440
+ > Make sure you do not pass proxy elements or internals by reference to `setConfig`!
441
+ >
442
+ > - proxies can be removed by using vue's `toRaw` function
443
+ > - `toRaw` is not deep, therefor nested proxy elements like arrays have to be manually removed, e.g. by iterating over the array and calling `toRaw` on each array item
444
+ > - everything passed by reference has to be deeply cloned, e.g. using `structuredClone`
445
+ >
446
+ > Best practice: Use `setConfig(structuredClone(...))` because it will throw, if you pass a proxy
447
+
435
448
  An example of plugin config editor can look like this:
436
449
 
437
450
  ```vue
@@ -462,7 +475,7 @@ An example of plugin config editor can look like this:
462
475
  VcsLabel,
463
476
  VcsTextField,
464
477
  } from '@vcmap/ui';
465
- import { ref } from 'vue';
478
+ import { ref, toRaw } from 'vue';
466
479
  import { getDefaultOptions } from '../defaultOptions.js';
467
480
 
468
481
  export default {
@@ -492,7 +505,8 @@ An example of plugin config editor can look like this:
492
505
  const localConfig = ref({ ...defaultOptions, ...config });
493
506
 
494
507
  const apply = () => {
495
- props.setConfig(localConfig.value);
508
+ // Do not pass proxy elements or internals by reference! See note above example for more information
509
+ props.setConfig(structuredClone(toRaw(localConfig.value)));
496
510
  };
497
511
 
498
512
  return {
@@ -9,8 +9,8 @@ function sleep(ms = 0) {
9
9
  });
10
10
  }
11
11
 
12
- window.VcsPluginLoaderFunction = (name, module) => ({
13
- default: () => plugin({ name }, module),
12
+ window.VcsPluginLoaderFunction = () => ({
13
+ default: (config, baseUrl) => plugin(config, baseUrl),
14
14
  });
15
15
 
16
16
  const testPropSymbol = Symbol('testProp');
@@ -12,14 +12,11 @@ function sleep(ms = 0): Promise<void> {
12
12
  type TestPluginInstance = VcsPlugin<object, object>;
13
13
 
14
14
  // @ts-expect-error: not defined on global
15
- window.VcsPluginLoaderFunction = (
16
- name: string,
17
- module: string,
18
- ): {
19
- default: () => TestPluginInstance;
15
+ window.VcsPluginLoaderFunction = (): {
16
+ default: (config: object, module: string) => TestPluginInstance;
20
17
  } => ({
21
18
  // @ts-expect-error: interface may not use this
22
- default: () => plugin({ name }, module),
19
+ default: (config, baseUrl) => plugin(config, baseUrl),
23
20
  });
24
21
 
25
22
  const testPropSymbol = Symbol('testProp');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/plugin-cli",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "A CLI to help develop and build plugins for the VC Map",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -42,7 +42,7 @@
42
42
  "vite-plugin-vuetify": "^2.0.4"
43
43
  },
44
44
  "peerDependencies": {
45
- "@vcmap/ui": "^6.0.0",
45
+ "@vcmap/ui": "^6.0",
46
46
  "vue": "~3.4.38"
47
47
  },
48
48
  "peerDependenciesMeta": {
@@ -9,6 +9,38 @@ import buildModule, { buildMapUI, getDefaultConfig } from './build.js';
9
9
  import setupMapUi from './setupMapUi.js';
10
10
  import { getVcmConfigJs } from './pluginCliHelper.js';
11
11
 
12
+ /**
13
+ * @param {VcmConfigJs} config
14
+ * @returns {string | undefined}
15
+ */
16
+ function getHtaccess(config) {
17
+ let htaccess;
18
+ if (config.htaccess) {
19
+ ({ htaccess } = config);
20
+ } else if (config.proxy) {
21
+ const htaccessLines = Object.keys(config.proxy).map((key) => {
22
+ const value = config.proxy[key];
23
+ let target;
24
+ if (typeof value === 'string') {
25
+ target = value;
26
+ } else {
27
+ ({ target } = value);
28
+ console.log(
29
+ `proxy settings for ${key} may be more complex, simply using rewrite to target: ${target}`,
30
+ );
31
+ }
32
+ return `RewriteRule ^${key.replace(/^\^/, '')} ${target} [P,L]`;
33
+ });
34
+
35
+ if (htaccessLines.length > 0) {
36
+ htaccessLines.unshift('RewriteEngine On');
37
+ htaccess = htaccessLines.join('\n');
38
+ }
39
+ }
40
+
41
+ return htaccess;
42
+ }
43
+
12
44
  /**
13
45
  * creates production preview application in the dist folder based on the @vcmap/ui default configuration.
14
46
  * @returns {Promise<void>}
@@ -70,6 +102,12 @@ export default async function buildStagingApp() {
70
102
  if (pluginConfig) {
71
103
  pluginConfig.entry = `plugins/${pluginName}/index.js`;
72
104
  }
105
+ const htaccess = getHtaccess(vcmConfigJs);
106
+ if (htaccess) {
107
+ await writeFile(path.join(distPath, '.htaccess'), htaccess);
108
+ logger.log('built .htaccess');
109
+ }
110
+
73
111
  await writeFile(
74
112
  path.join(distPath, 'app.config.json'),
75
113
  JSON.stringify(appConfig, null, 2),
@@ -28,7 +28,8 @@ export const promiseExec = util.promisify(childProcess.exec);
28
28
 
29
29
  /**
30
30
  * @typedef {PreviewOptions} VcmConfigJs
31
- * @property {Object} proxy - see https://vitejs.dev/config/server-options.html#server-proxy
31
+ * @property {Object} [proxy] - see https://vitejs.dev/config/server-options.html#server-proxy. when building a staging app, we try to deduce an .htaccess from it.
32
+ * @property {string} [htaccess] - a string representing an .htaccess file content for use in staging apps.
32
33
  */
33
34
 
34
35
  /**
package/src/update.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { logger } from '@vcsuite/cli-logger';
2
- import { validRange, prerelease } from 'semver';
2
+ import { validRange, maxSatisfying, prerelease } from 'semver';
3
3
  import {
4
4
  checkVcMapVersion,
5
5
  DepType,
@@ -36,17 +36,31 @@ export async function updatePeerDependencies(
36
36
  );
37
37
  options.mapVersion = 'latest';
38
38
  }
39
- let viewCmd = 'npm view @vcmap/ui --json';
39
+ let viewCmd =
40
+ 'npm view @vcmap/ui --json peerDependencies devDependencies version name';
40
41
  if (options.mapVersion) {
41
- viewCmd = `npm view @vcmap/ui@${options.mapVersion} --json`;
42
+ viewCmd = `npm view @vcmap/ui@${options.mapVersion} --json peerDependencies devDependencies version name`;
42
43
  }
43
44
  const { stdout, stderr } = await promiseExec(viewCmd);
44
45
  logger.error(stderr);
46
+ const npmVersions = JSON.parse(stdout);
47
+ let npmVersion = null;
48
+ if (Array.isArray(npmVersions)) {
49
+ const versions = npmVersions.map((v) => v.version);
50
+ const versionToUse = maxSatisfying(versions, options.mapVersion);
51
+ npmVersion = npmVersions.find((v) => v.version === versionToUse);
52
+ } else {
53
+ npmVersion = npmVersions;
54
+ }
55
+ if (!npmVersion) {
56
+ console.log(`could not find @vcmap/ui version for ${options.mapVersion}`);
57
+ return;
58
+ }
45
59
  const {
46
60
  name: mapName,
47
61
  peerDependencies: mapPeer,
48
62
  devDependencies: mapDev,
49
- } = JSON.parse(stdout);
63
+ } = npmVersion;
50
64
  const peerDeps = [`${mapName}@${options.mapVersion || 'latest'}`]; // @vcmap/ui is a required peer dep and will be updated in any case
51
65
  if (pluginPeer) {
52
66
  const pluginPeerDeps = Object.keys(pluginPeer)