@ixon-cdk/core 1.21.0-next.2 → 1.22.0-next.0

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/api/api.utils.js CHANGED
@@ -1,4 +1,4 @@
1
- function whileMoreAfter(reqFn) {
1
+ export function whileMoreAfter(reqFn) {
2
2
  const fetcher = async (seed, moreAfter) => {
3
3
  const response = await reqFn(moreAfter);
4
4
  const data = [...seed, ...response.data.data];
@@ -12,7 +12,3 @@ function whileMoreAfter(reqFn) {
12
12
  status: 'success',
13
13
  }));
14
14
  }
15
-
16
- module.exports = {
17
- whileMoreAfter,
18
- };
@@ -1,8 +1,8 @@
1
- const fs = require('fs');
2
- const ApiBaseService = require('./base.service');
3
- const httpRequest = require('../http-request');
1
+ import fs from 'node:fs';
2
+ import { ApiBaseService } from './base.service.js';
3
+ import httpRequest from '../http-request.js';
4
4
 
5
- module.exports = class AuthService extends ApiBaseService {
5
+ export class AuthService extends ApiBaseService {
6
6
  logIn(credentials) {
7
7
  const c = credentials;
8
8
  const expiresIn = 2592000; // 30 days
@@ -42,7 +42,7 @@ module.exports = class AuthService extends ApiBaseService {
42
42
 
43
43
  remember(secretId) {
44
44
  fs.writeFileSync(this._getAccessTokenFilePath(), secretId, {
45
- encoding: 'utf8',
45
+ encoding: 'utf-8',
46
46
  flag: 'w',
47
47
  });
48
48
  }
@@ -52,4 +52,4 @@ module.exports = class AuthService extends ApiBaseService {
52
52
  fs.rmSync(this._getAccessTokenFilePath());
53
53
  }
54
54
  }
55
- };
55
+ }
@@ -1,8 +1,9 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const ConfigService = require('../config/config.service');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { ConfigService } from '../config/config.service.js';
4
+ import { getRootDir } from '../utils.js';
4
5
 
5
- module.exports = class ApiBaseService {
6
+ export class ApiBaseService {
6
7
  _configSrv = new ConfigService();
7
8
 
8
9
  /**
@@ -19,7 +20,7 @@ module.exports = class ApiBaseService {
19
20
 
20
21
  /** Returns an absolute path to the `.accesstoken` file. */
21
22
  _getAccessTokenFilePath() {
22
- return path.join(require('../utils').getRootDir(), '.accesstoken');
23
+ return path.join(getRootDir(), '.accesstoken');
23
24
  }
24
25
 
25
26
  _getApiAuthHeaderValue() {
@@ -53,4 +54,4 @@ module.exports = class ApiBaseService {
53
54
  }
54
55
  return secretId;
55
56
  }
56
- };
57
+ }
@@ -0,0 +1,119 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { merge } from 'lodash-es';
4
+ import {
5
+ getArgv,
6
+ getRootDir,
7
+ logFileCrudMessage,
8
+ logErrorMessage,
9
+ } from '../utils.js';
10
+
11
+ export class ConfigService {
12
+ _config = { components: {} };
13
+
14
+ constructor(configFile) {
15
+ // When the CDK is part of a larger project workspace it may be desirable to have a more explicit config-file name. Therefore, unless
16
+ // a specific config file path was defined in the constructor, we'll first try to find `cdk.config.json`, before falling back to the
17
+ // default file name `config.json`.
18
+ if (configFile !== undefined) {
19
+ this._path = path.join(getRootDir(), configFile);
20
+ } else {
21
+ const argv = getArgv();
22
+ const argConfigPath = argv['config'] || argv['c'];
23
+ if (argConfigPath) {
24
+ if (fs.existsSync(path.join(getRootDir(), argConfigPath))) {
25
+ this._path = path.join(getRootDir(), argConfigPath);
26
+ } else {
27
+ logErrorMessage(
28
+ `Config file not found: ${path.join(getRootDir(), argConfigPath)}`,
29
+ );
30
+ process.exit(1);
31
+ }
32
+ this._path = path.join(getRootDir(), argConfigPath);
33
+ } else if (fs.existsSync(path.join(getRootDir(), 'cdk.config.json'))) {
34
+ this._path = path.join(getRootDir(), 'cdk.config.json');
35
+ } else {
36
+ this._path = path.join(getRootDir(), 'config.json');
37
+ }
38
+ }
39
+
40
+ if (!fs.existsSync(this._path)) {
41
+ this._path = path.join(getRootDir(), 'cdk.config.json');
42
+ fs.writeFileSync(
43
+ this._path,
44
+ `${JSON.stringify(
45
+ {
46
+ $schema: './node_modules/@ixon-cdk/core/config/schema.json',
47
+ prefix: 'pct',
48
+ components: {},
49
+ },
50
+ null,
51
+ 2,
52
+ )}\n`,
53
+ { encoding: 'utf-8' },
54
+ );
55
+ logFileCrudMessage('CREATE', 'cdk.config.json');
56
+ }
57
+
58
+ try {
59
+ this._config = JSON.parse(fs.readFileSync(this._path, 'utf-8'));
60
+ } catch {
61
+ logErrorMessage("Couldn't parse config file.");
62
+ process.exit(1);
63
+ }
64
+ }
65
+
66
+ hasComponent(name) {
67
+ return name in this._config.components;
68
+ }
69
+
70
+ getComponent(name) {
71
+ return this._config.components[name];
72
+ }
73
+
74
+ getNewComponentRoot() {
75
+ return this._config.newComponentRoot || 'components';
76
+ }
77
+
78
+ getOutputPath() {
79
+ return this._config.outputPath || 'dist';
80
+ }
81
+
82
+ getPrefix() {
83
+ return this._config.prefix || null;
84
+ }
85
+
86
+ getApiApplication() {
87
+ return this._config.apiApplication || 'LtDdZKEPa5lK';
88
+ }
89
+
90
+ getApiBaseUrl() {
91
+ return this._config.apiBaseUrl || 'https://api.ayayot.com';
92
+ }
93
+
94
+ getApiVersion() {
95
+ return this._config.apiVersion || '2';
96
+ }
97
+
98
+ addComponent(name, config) {
99
+ this._config.components[name] = config;
100
+ this._sync();
101
+ }
102
+
103
+ extendComponent(name, config) {
104
+ this._config.components[name] = merge(
105
+ {},
106
+ this._config.components[name],
107
+ config,
108
+ );
109
+ this._sync();
110
+ }
111
+
112
+ _sync() {
113
+ fs.writeFileSync(this._path, `${JSON.stringify(this._config, null, 2)}\n`, {
114
+ encoding: 'utf-8',
115
+ flag: 'w',
116
+ });
117
+ logFileCrudMessage('UPDATE', path.basename(this._path));
118
+ }
119
+ }
@@ -1,15 +1,14 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const ApiBaseService = require('./base.service');
4
- const httpRequest = require('../http-request');
5
- const { whileMoreAfter } = require('./api.utils');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { ApiBaseService } from './base.service.js';
4
+ import httpRequest from '../http-request.js';
5
+ import { whileMoreAfter } from './api.utils.js';
6
+ import { generatePreviewHash, getRootDir } from '../utils.js';
6
7
 
7
- module.exports = class DeployService extends ApiBaseService {
8
+ export class DeployService extends ApiBaseService {
8
9
  deploy(companyId, templateId, file) {
9
10
  const url = `${this._getApiBaseUrl()}/page-component-templates/${templateId}/version-upload`;
10
- const body = fs.readFileSync(
11
- path.join(require('../utils').getRootDir(), file),
12
- );
11
+ const body = fs.readFileSync(path.join(getRootDir(), file));
13
12
  const headers = {
14
13
  ...this._getApiDefaultHeaders(),
15
14
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -49,7 +48,7 @@ module.exports = class DeployService extends ApiBaseService {
49
48
  ),
50
49
  )
51
50
  .then(([fqdn, version, template]) => {
52
- const hash = require('../utils').generatePreviewHash(
51
+ const hash = generatePreviewHash(
53
52
  template.publicId,
54
53
  template.name,
55
54
  version.publicId,
@@ -180,4 +179,4 @@ module.exports = class DeployService extends ApiBaseService {
180
179
  };
181
180
  return httpRequest({ method: 'PATCH', url, data: body, headers });
182
181
  }
183
- };
182
+ }
@@ -1,14 +1,14 @@
1
- const fs = require('fs');
2
- const { merge } = require('lodash');
3
- const path = require('path');
4
- const {
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { merge } from 'lodash-es';
4
+ import {
5
5
  getArgv,
6
6
  getRootDir,
7
7
  logFileCrudMessage,
8
8
  logErrorMessage,
9
- } = require('../utils');
9
+ } from '../utils.js';
10
10
 
11
- module.exports = class ConfigService {
11
+ export class ConfigService {
12
12
  _config = { components: {} };
13
13
 
14
14
  constructor(configFile) {
@@ -58,7 +58,7 @@ module.exports = class ConfigService {
58
58
  }
59
59
 
60
60
  try {
61
- config = require(this._path);
61
+ config = JSON.parse(fs.readFileSync(this._path, 'utf-8'));
62
62
  } catch {
63
63
  logErrorMessage("Couldn't parse config file.");
64
64
  process.exit(1);
@@ -115,9 +115,9 @@ module.exports = class ConfigService {
115
115
 
116
116
  _sync() {
117
117
  fs.writeFileSync(this._path, `${JSON.stringify(this._config, null, 2)}\n`, {
118
- encoding: 'utf8',
118
+ encoding: 'utf-8',
119
119
  flag: 'w',
120
120
  });
121
121
  logFileCrudMessage('UPDATE', path.basename(this._path));
122
122
  }
123
- };
123
+ }
package/http-request.js CHANGED
@@ -1,13 +1,17 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const axios = require('axios');
4
- const { getRootDir, logErrorMessage } = require('./utils');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import axios from 'axios';
4
+ import { getRootDir, logErrorMessage } from './utils.js';
5
5
 
6
- module.exports = function request(options) {
6
+ export default async function request(options) {
7
7
  const customPath = path.join(getRootDir(), 'http-request.js');
8
8
 
9
9
  if (fs.existsSync(customPath)) {
10
- const customRequest = require(customPath);
10
+ let customRequest = await import(customPath);
11
+
12
+ if (typeof customRequest === 'object' && 'default' in customRequest) {
13
+ customRequest = customRequest.default;
14
+ }
11
15
 
12
16
  if (typeof customRequest !== 'function') {
13
17
  logErrorMessage(
@@ -29,4 +33,4 @@ module.exports = function request(options) {
29
33
  }
30
34
 
31
35
  return axios.request(options);
32
- };
36
+ }
package/index.js CHANGED
@@ -1,10 +1,8 @@
1
- module.exports = {
2
- AuthService: require('./api/auth.service'),
3
- DeployService: require('./api/deploy.service'),
4
- ConfigService: require('./config/config.service'),
5
- Server: require('./server'),
6
- TemplateService: require('./template/template.service'),
7
- ...require('./meta-files'),
8
- ...require('./prompts'),
9
- ...require('./utils'),
10
- };
1
+ export { AuthService } from './api/auth.service.js';
2
+ export { DeployService } from './api/deploy.service.js';
3
+ export { ConfigService } from './config/config.service.js';
4
+ export { Server } from './server/index.js';
5
+ export { TemplateService } from './template/template.service.js';
6
+ export * from './meta-files.js';
7
+ export * from './prompts.js';
8
+ export * from './utils.js';
package/meta-files.js CHANGED
@@ -1,10 +1,10 @@
1
- const fs = require('fs');
2
- const fse = require('fs-extra');
3
- const path = require('path');
4
- const { watch } = require('chokidar');
5
- const { globSync } = require('glob');
6
- const { debounce, isEqual, uniqWith } = require('lodash');
7
- const { getRootDir } = require('./utils');
1
+ import fs from 'node:fs';
2
+ import fse from 'fs-extra';
3
+ import path from 'node:path';
4
+ import { watch } from 'chokidar';
5
+ import { globSync } from 'glob';
6
+ import { debounce, isEqual, uniqWith } from 'lodash-es';
7
+ import { getRootDir } from './utils.js';
8
8
 
9
9
  const ICON_FILE_NAME = 'icon.svg';
10
10
  const MANIFEST_FILE_NAME = 'manifest.json';
@@ -20,78 +20,78 @@ const WATCH_OPTIONS = {
20
20
  * @property {String} [output] - A path relative to outputPath (default is dist/component-name).
21
21
  */
22
22
 
23
- module.exports = {
24
- cleanDir(dir) {
25
- fse.emptyDirSync(dir);
26
- },
27
- /**
28
- * @param {Array<String | Asset>} assets
29
- * @param {String} inputDir
30
- * @param {String} outputDir
31
- */
32
- copyAssets(assets, inputDir, outputDir) {
33
- _getAssetSpecs(assets, inputDir, outputDir).forEach(
34
- ({ glob, input, output }) => {
35
- const globFilePath = path.join(input, glob).replaceAll('\\', '/');
36
- globSync(globFilePath).forEach(file => {
37
- const filePath = file.slice(input.length + 1);
38
- _copyFromToSync(filePath, input, output);
39
- });
40
- },
41
- );
42
- },
43
- watchAssets(assets, inputDir, outputDir) {
44
- const root = getRootDir();
45
- return Promise.all(
46
- _getAssetSpecs(assets, inputDir, outputDir).map(asset => {
47
- return watch(path.join(asset.input, asset.glob), WATCH_OPTIONS).on(
48
- 'all',
49
- (type, file) => {
50
- const filePath = path
51
- .join(root, file)
52
- .slice(asset.input.length + 1);
53
- switch (type) {
54
- case 'add':
55
- case 'addDir':
56
- case 'change':
57
- case 'changeDir':
58
- _copyFromToSync(filePath, asset.input, asset.output);
59
- break;
60
- case 'unlink':
61
- case 'unlinkDir':
62
- fse.removeSync(path.join(asset.output, filePath));
63
- break;
64
- default:
65
- break;
66
- }
67
- },
68
- );
69
- }),
70
- );
71
- },
72
- watchInputDir(dir, watchCallback) {
73
- const _debouncedCallback = debounce(() => watchCallback(), 300);
74
- watch([`${dir}/**`], WATCH_OPTIONS).on('all', (_, _path) => {
75
- if (
76
- _path.endsWith(path.join(dir, MANIFEST_FILE_NAME)) ||
77
- _path.endsWith(path.join(dir, ICON_FILE_NAME))
78
- ) {
79
- watchCallback(true);
80
- } else {
81
- _debouncedCallback();
82
- }
83
- });
84
- },
85
- writeDemoFile(tag, outputDir, outputFile) {
86
- const demoFileContent = `<meta charset="utf-8">\n<title>${tag} demo</title>\n<script src="./${path.basename(
87
- outputFile,
88
- )}"></script>\n\n\n<${tag}></${tag}>\n\n`;
89
- fs.writeFileSync(`${outputDir}/demo.html`, demoFileContent, {
90
- encoding: 'utf8',
91
- flag: 'w',
92
- });
93
- },
94
- };
23
+ export function cleanDir(dir) {
24
+ fse.emptyDirSync(dir);
25
+ }
26
+
27
+ /**
28
+ * @param {Array<String | Asset>} assets
29
+ * @param {String} inputDir
30
+ * @param {String} outputDir
31
+ */
32
+ export function copyAssets(assets, inputDir, outputDir) {
33
+ _getAssetSpecs(assets, inputDir, outputDir).forEach(
34
+ ({ glob, input, output }) => {
35
+ const globFilePath = path.join(input, glob).replaceAll('\\', '/');
36
+ globSync(globFilePath).forEach(file => {
37
+ const filePath = file.slice(input.length + 1);
38
+ _copyFromToSync(filePath, input, output);
39
+ });
40
+ },
41
+ );
42
+ }
43
+
44
+ export function watchAssets(assets, inputDir, outputDir) {
45
+ const root = getRootDir();
46
+ return Promise.all(
47
+ _getAssetSpecs(assets, inputDir, outputDir).map(asset => {
48
+ return watch(path.join(asset.input, asset.glob), WATCH_OPTIONS).on(
49
+ 'all',
50
+ (type, file) => {
51
+ const filePath = path.join(root, file).slice(asset.input.length + 1);
52
+ switch (type) {
53
+ case 'add':
54
+ case 'addDir':
55
+ case 'change':
56
+ case 'changeDir':
57
+ _copyFromToSync(filePath, asset.input, asset.output);
58
+ break;
59
+ case 'unlink':
60
+ case 'unlinkDir':
61
+ fse.removeSync(path.join(asset.output, filePath));
62
+ break;
63
+ default:
64
+ break;
65
+ }
66
+ },
67
+ );
68
+ }),
69
+ );
70
+ }
71
+
72
+ export function watchInputDir(dir, watchCallback) {
73
+ const _debouncedCallback = debounce(() => watchCallback(), 300);
74
+ watch([`${dir}/**`], WATCH_OPTIONS).on('all', (_, _path) => {
75
+ if (
76
+ _path.endsWith(path.join(dir, MANIFEST_FILE_NAME)) ||
77
+ _path.endsWith(path.join(dir, ICON_FILE_NAME))
78
+ ) {
79
+ watchCallback(true);
80
+ } else {
81
+ _debouncedCallback();
82
+ }
83
+ });
84
+ }
85
+
86
+ export function writeDemoFile(tag, outputDir, outputFile) {
87
+ const demoFileContent = `<meta charset="utf-8">\n<title>${tag} demo</title>\n<script src="./${path.basename(
88
+ outputFile,
89
+ )}"></script>\n\n\n<${tag}></${tag}>\n\n`;
90
+ fs.writeFileSync(`${outputDir}/demo.html`, demoFileContent, {
91
+ encoding: 'utf8',
92
+ flag: 'w',
93
+ });
94
+ }
95
95
 
96
96
  /**
97
97
  * Copies an asset file or directory from the source directory to a destination directory.
package/package.json CHANGED
@@ -1,23 +1,27 @@
1
1
  {
2
2
  "name": "@ixon-cdk/core",
3
- "version": "1.21.0-next.2",
3
+ "version": "1.22.0-next.0",
4
4
  "description": "",
5
+ "type": "module",
5
6
  "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
6
10
  "author": "",
7
11
  "license": "ISC",
8
12
  "dependencies": {
9
13
  "app-root-dir": "^1.0.2",
10
14
  "archiver": "^7.0.1",
11
- "axios": "^1.11.0",
12
- "chalk": "^4.1.2",
15
+ "axios": "^1.13.2",
16
+ "chalk": "^5.6.2",
13
17
  "chokidar": "^3.6.0",
14
18
  "cors": "^2.8.5",
15
19
  "crypto-js": "^4.2.0",
16
- "express": "^4.19.2",
17
- "fs-extra": "^11.2.0",
18
- "glob": "^9.3.5",
19
- "livereload": "^0.9.3",
20
- "lodash": "^4.17.21",
20
+ "express": "^5.2.1",
21
+ "fs-extra": "^11.3.2",
22
+ "glob": "^13.0.0",
23
+ "livereload": "^0.10.3",
24
+ "lodash-es": "^4.17.21",
21
25
  "opener": "^1.5.2",
22
26
  "prompts": "^2.4.2",
23
27
  "yargs": "^17.7.2"
package/prompts.js CHANGED
@@ -1,34 +1,33 @@
1
- module.exports = {
2
- promptCompanyId(name) {
3
- return {
4
- type: 'text',
5
- name,
6
- message: 'What is the ID of your Company?',
7
- validate: value => {
8
- if (!value) {
9
- return 'Company ID is required.';
10
- }
11
- if (!/^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$/.test(value)) {
12
- return 'Invalid company ID.';
13
- }
14
- return true;
15
- },
16
- };
17
- },
18
- promptPageComponentTemplateId(name) {
19
- return {
20
- type: 'text',
21
- name,
22
- message: 'What is the ID of the UI Component?',
23
- validate: value => {
24
- if (!value) {
25
- return 'UI Component ID is required.';
26
- }
27
- if (!/^[a-zA-Z0-9]{12}$/.test(value)) {
28
- return 'Invalid UI Component ID.';
29
- }
30
- return true;
31
- },
32
- };
33
- },
34
- };
1
+ export function promptCompanyId(name) {
2
+ return {
3
+ type: 'text',
4
+ name,
5
+ message: 'What is the ID of your Company?',
6
+ validate: value => {
7
+ if (!value) {
8
+ return 'Company ID is required.';
9
+ }
10
+ if (!/^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$/.test(value)) {
11
+ return 'Invalid company ID.';
12
+ }
13
+ return true;
14
+ },
15
+ };
16
+ }
17
+
18
+ export function promptPageComponentTemplateId(name) {
19
+ return {
20
+ type: 'text',
21
+ name,
22
+ message: 'What is the ID of the UI Component?',
23
+ validate: value => {
24
+ if (!value) {
25
+ return 'UI Component ID is required.';
26
+ }
27
+ if (!/^[a-zA-Z0-9]{12}$/.test(value)) {
28
+ return 'Invalid UI Component ID.';
29
+ }
30
+ return true;
31
+ },
32
+ };
33
+ }
package/server/index.js CHANGED
@@ -1,17 +1,22 @@
1
- const path = require('path');
2
- const express = require('express');
3
- const cors = require('cors');
4
- const liveReload = require('livereload');
5
- const ApiBaseService = require('../api/base.service');
6
- const ConfigService = require('../config/config.service');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import express from 'express';
5
+ import cors from 'cors';
6
+ import liveReload from 'livereload';
7
+ import opener from 'opener';
8
+ import { debounce } from 'lodash-es';
9
+ import { ApiBaseService } from '../api/base.service.js';
10
+ import { ConfigService } from '../config/config.service.js';
11
+ import { getRootDir } from '../utils.js';
7
12
 
8
13
  const LR_PORT_DEFAULT = 35729;
9
14
 
10
- module.exports = class Server {
15
+ export class Server {
11
16
  constructor(opts) {
12
17
  this._apiSrv = new ApiBaseService();
13
18
  this._configSrv = new ConfigService();
14
- this._rootDir = require('../utils').getRootDir();
19
+ this._rootDir = getRootDir();
15
20
  this._opts = {
16
21
  port: 8000,
17
22
  componentBasePath: 'components',
@@ -57,30 +62,33 @@ module.exports = class Server {
57
62
  port: this._opts.liveReloadPort,
58
63
  });
59
64
  const _refresh = () => lrServer.refresh('/');
60
- const _debouncedRefresh = require('lodash/debounce')(_refresh, 250);
65
+ const _debouncedRefresh = debounce(_refresh, 250);
61
66
  names
62
67
  .flatMap(name => [
63
68
  [path.join(this._rootDir, this._getOutput(name)), 100],
64
69
  [path.join(this._rootDir, `dist/${name}/manifest.json`), 500],
65
70
  ])
66
71
  .forEach(([filename, interval]) =>
67
- require('fs').watchFile(filename, { interval }, _debouncedRefresh),
72
+ fs.watchFile(filename, { interval }, _debouncedRefresh),
68
73
  );
69
74
 
70
75
  // Simulator app
71
76
  let appDir;
72
77
  try {
73
- appDir = path.dirname(require.resolve('@ixon-cdk/simulator'));
78
+ appDir = path.dirname(
79
+ fileURLToPath(import.meta.resolve('@ixon-cdk/simulator')),
80
+ );
74
81
  } catch {
75
- // If require.resolve is invoked immediately after the simulator is installed, it will return
76
- // a "MODULE_NOT_FOUND" error. In that case (as a fallback) we'll find the simulator app dir
77
- // relative to the core module (which should have already been installed).
82
+ // If import.meta.resolve is invoked immediately after the simulator is installed, it will
83
+ // return a "MODULE_NOT_FOUND" error. In that case (as a fallback) we'll find the simulator
84
+ // app dir relative to the core module (which should have already been installed).
78
85
  appDir = path.join(
79
- require.resolve('@ixon-cdk/core'),
86
+ fileURLToPath(import.meta.resolve('@ixon-cdk/core')),
80
87
  '../../simulator/dist',
81
88
  );
82
89
  }
83
- app.get(`/${this._opts.componentBasePath}/*`, (req, res) => {
90
+ app.use(express.static(appDir));
91
+ app.get(`/${this._opts.componentBasePath}/*splat`, (req, res) => {
84
92
  res.sendStatus(404);
85
93
  });
86
94
  app.get(
@@ -100,8 +108,7 @@ module.exports = class Server {
100
108
  },
101
109
  });
102
110
  });
103
- app.get('*.*', express.static(appDir));
104
- app.all('*', (req, res) => {
111
+ app.all('*splat', (req, res) => {
105
112
  res.status(200).sendFile('/index.html', { root: appDir });
106
113
  });
107
114
 
@@ -120,7 +127,7 @@ module.exports = class Server {
120
127
  }
121
128
  const queryString = params.toString();
122
129
  const openUrl = `${this._getBaseUrl()}/?${queryString}`;
123
- require('opener')(openUrl);
130
+ opener(openUrl);
124
131
  return openUrl;
125
132
  }
126
133
 
@@ -155,4 +162,4 @@ module.exports = class Server {
155
162
  _getOutputDir(name) {
156
163
  return name ? `${this._configSrv.getOutputPath()}/${name}` : null;
157
164
  }
158
- };
165
+ }
@@ -1,18 +1,19 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const prompts = require('prompts');
4
-
5
- const {
1
+ import { execSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import prompts from 'prompts';
6
+ import { ConfigService } from '../config/config.service.js';
7
+ import {
6
8
  getFiles,
7
9
  getRootDir,
8
10
  ensureModule,
9
11
  logErrorMessage,
10
12
  logFileCrudMessage,
11
13
  pascalCase,
12
- } = require('../utils');
13
- const ConfigService = require('../config/config.service');
14
+ } from '../utils.js';
14
15
 
15
- module.exports = class TemplateService {
16
+ export class TemplateService {
16
17
  _configSrv = new ConfigService();
17
18
 
18
19
  _rootDir = getRootDir();
@@ -136,8 +137,8 @@ module.exports = class TemplateService {
136
137
  files.forEach(file => {
137
138
  if (/\.(jsx?|tsx?|svelte|vue)$/i.test(file)) {
138
139
  const fileContents = fs.readFileSync(file);
139
- const { dependencies } = require(
140
- path.join(examplesRoot, 'package.json'),
140
+ const { dependencies } = JSON.parse(
141
+ fs.readFileSync(path.join(examplesRoot, 'package.json'), 'utf-8'),
141
142
  );
142
143
  this._checkDependencies(fileContents, dependencies || {});
143
144
  }
@@ -317,7 +318,9 @@ module.exports = class TemplateService {
317
318
  if (file.interpolateContent) {
318
319
  const text = fs.readFileSync(
319
320
  path.join(
320
- path.dirname(require.resolve('@ixon-cdk/templates')),
321
+ path.dirname(
322
+ fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
323
+ ),
321
324
  file.source,
322
325
  ),
323
326
  { encoding: 'utf-8' },
@@ -329,7 +332,9 @@ module.exports = class TemplateService {
329
332
  } else {
330
333
  fs.copyFileSync(
331
334
  path.join(
332
- path.dirname(require.resolve('@ixon-cdk/templates')),
335
+ path.dirname(
336
+ fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
337
+ ),
333
338
  file.source,
334
339
  ),
335
340
  path.join(this._rootDir, file.dest),
@@ -341,17 +346,20 @@ module.exports = class TemplateService {
341
346
  /**
342
347
  * This script loops over a dependencies object and will check if the provided file contents is
343
348
  * importing any. When that is the case, it will first check for that package whether it could
344
- * already be a depencency in your workspace. If not, the package will get installed and saved.
349
+ * already be a dependency in your workspace. If not, the package will get installed and saved.
345
350
  */
346
351
  _checkDependencies(fileContents, dependencies) {
347
- const rootDeps =
348
- require(path.join(this._rootDir, 'package.json')).dependencies || {};
352
+ const rootPkgJsonRaw = fs.readFileSync(
353
+ path.join(this._rootDir, 'package.json'),
354
+ 'utf-8',
355
+ );
356
+ const rootDeps = JSON.parse(rootPkgJsonRaw).dependencies || {};
349
357
  Object.keys(dependencies).forEach(pkg => {
350
358
  const matcher = new RegExp(`^\\s*import.*\\s['"]${pkg}\\S*['"]`, 'gm');
351
359
  if (matcher.test(fileContents) && !(pkg in rootDeps)) {
352
360
  const version = dependencies[pkg];
353
361
  console.log(`Installing package '${pkg}'...`);
354
- require('child_process').execSync(`npm i ${pkg}@${version} --save`);
362
+ execSync(`npm i ${pkg}@${version} --save`);
355
363
  }
356
364
  });
357
365
  }
@@ -370,7 +378,7 @@ module.exports = class TemplateService {
370
378
  * This script will find and replace the component class definition and the arguments for the
371
379
  * custom element define method in a static input file.
372
380
  *
373
- * Given the example input file has the follwing contents:
381
+ * Given the example input file has the following contents:
374
382
  *
375
383
  * ```js
376
384
  * class PctExample extends HTMLElement {
@@ -420,7 +428,9 @@ module.exports = class TemplateService {
420
428
  }
421
429
 
422
430
  _discover() {
423
- const dir = path.dirname(require.resolve('@ixon-cdk/templates'));
431
+ const dir = path.dirname(
432
+ fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
433
+ );
424
434
  const files = fs.readdirSync(dir);
425
435
  const tail = ['iframe-wrapper'];
426
436
  files
@@ -485,4 +495,4 @@ module.exports = class TemplateService {
485
495
  .replace(/<%=\s*tag\s*%>/g, params.tag)
486
496
  .replace(/<%=\s*classify\(\s*tag\s*\)\s*%>/g, pascalCase(params.tag));
487
497
  }
488
- };
498
+ }
package/utils.js CHANGED
@@ -1,87 +1,17 @@
1
- const fs = require('fs');
2
- const fse = require('fs-extra');
3
- const path = require('path');
4
- const chalk = require('chalk');
5
- const { globSync } = require('glob');
6
- const flow = require('lodash/flow');
7
- const camelCase = require('lodash/camelCase');
8
- const upperFirst = require('lodash/upperFirst');
1
+ import fs from 'node:fs';
2
+ import net from 'node:net';
3
+ import path from 'node:path';
4
+ import { execSync } from 'node:child_process';
5
+ import { get as getAppRootDir } from 'app-root-dir';
6
+ import archiver from 'archiver';
7
+ import chalk from 'chalk';
8
+ import CryptoJS from 'crypto-js';
9
+ import fse from 'fs-extra';
10
+ import { globSync } from 'glob';
11
+ import { camelCase, flow, upperFirst } from 'lodash-es';
12
+ import yargs from 'yargs/yargs';
9
13
 
10
- function dirContains(dir, globPattern) {
11
- const files = globSync(path.join(dir, globPattern));
12
- return !!files.length;
13
- }
14
-
15
- function getArgv() {
16
- const remain = process.argv.slice(2);
17
- const { argv } = require('yargs/yargs')(remain).version(false);
18
-
19
- return argv;
20
- }
21
-
22
- function getRootDir() {
23
- return require('app-root-dir').get();
24
- }
25
-
26
- function logErrorMessage(message) {
27
- console.log(chalk.redBright.bold(message));
28
- }
29
-
30
- function logFileCrudMessage(crud, file) {
31
- switch (crud) {
32
- case 'CREATE':
33
- case 'UPDATE':
34
- console.log(`${chalk.green(crud)} ${file}`);
35
- break;
36
- default:
37
- break;
38
- }
39
- }
40
-
41
- function logSuccessMessage(message) {
42
- console.log(chalk.green(message));
43
- }
44
-
45
- function moduleExists(moduleName) {
46
- let exists = true;
47
- try {
48
- require.resolve(moduleName);
49
- } catch {
50
- exists = false;
51
- }
52
- return exists;
53
- }
54
-
55
- function ensureModule(moduleName, moduleVersion = null, dev = true) {
56
- if (!moduleExists(moduleName)) {
57
- if (moduleName.startsWith('@ixon-cdk/')) {
58
- moduleVersion = require('./package.json').version;
59
- }
60
- const v = moduleVersion ? '@' + moduleVersion : '';
61
- console.log(`Installing package '${moduleName}${v}...`);
62
- require('child_process').execSync(
63
- `npm install --save${dev ? '-dev' : ''} ${moduleName}${v}`,
64
- );
65
- }
66
- }
67
-
68
- function zip(output, callback) {
69
- const outputDir = path.dirname(output);
70
- const zipFile = path.join(`${outputDir}.zip`);
71
- const stream = fs.createWriteStream(zipFile);
72
- stream.on('close', () => {
73
- fse.removeSync(outputDir);
74
- callback(zipFile);
75
- });
76
- const archive = require('archiver')('zip', { zlib: { level: 9 } });
77
- archive.pipe(stream);
78
- archive.directory(outputDir, path.basename(outputDir));
79
- archive.finalize();
80
- }
81
-
82
- const pascalCase = flow(camelCase, upperFirst);
83
-
84
- function apiHttpErrorToMessage(error, exit = true) {
14
+ export function apiHttpErrorToMessage(error, exit = true) {
85
15
  if (typeof error === 'string') {
86
16
  logErrorMessage(error);
87
17
  exit && process.exit(1);
@@ -108,7 +38,42 @@ function apiHttpErrorToMessage(error, exit = true) {
108
38
  exit && process.exit(1);
109
39
  }
110
40
 
111
- function generatePreviewHash(
41
+ export function checkPortAvailable(port) {
42
+ return new Promise((resolve, reject) => {
43
+ const server = net.createServer();
44
+ server
45
+ .once('error', err => {
46
+ server.close();
47
+ return reject(err);
48
+ })
49
+ .once('listening', () => {
50
+ server.close();
51
+ return resolve(port);
52
+ })
53
+ .listen(port);
54
+ });
55
+ }
56
+
57
+ export function dirContains(dir, globPattern) {
58
+ const files = globSync(path.join(dir, globPattern));
59
+ return !!files.length;
60
+ }
61
+
62
+ export function ensureModule(moduleName, moduleVersion = null, dev = true) {
63
+ if (!moduleExists(moduleName)) {
64
+ if (moduleName.startsWith('@ixon-cdk/')) {
65
+ const modulePkgJson = JSON.parse(
66
+ fs.readFileSync('./package.json', 'utf-8'),
67
+ );
68
+ moduleVersion = modulePkgJson.version;
69
+ }
70
+ const v = moduleVersion ? '@' + moduleVersion : '';
71
+ console.log(`Installing package '${moduleName}${v}...`);
72
+ execSync(`npm install --save${dev ? '-dev' : ''} ${moduleName}${v}`);
73
+ }
74
+ }
75
+
76
+ export function generatePreviewHash(
112
77
  templateId,
113
78
  templateName,
114
79
  versionId,
@@ -123,10 +88,33 @@ function generatePreviewHash(
123
88
  vmp: versionMainPath,
124
89
  };
125
90
  const salt = 'A9qJ03jh';
126
- return require('crypto-js').AES.encrypt(JSON.stringify(ref), salt).toString();
91
+ return CryptoJS.AES.encrypt(JSON.stringify(ref), salt).toString();
127
92
  }
128
93
 
129
- async function getFiles(dir) {
94
+ export function getArgv() {
95
+ const remain = process.argv.slice(2);
96
+ const { argv } = yargs(remain).version(false);
97
+ return argv;
98
+ }
99
+
100
+ export function getAvailablePort() {
101
+ return new Promise((resolve, reject) => {
102
+ const server = net.createServer();
103
+ server
104
+ .once('error', err => {
105
+ server.close();
106
+ return reject(err);
107
+ })
108
+ .once('listening', () => {
109
+ const { port } = server.address();
110
+ server.close();
111
+ return resolve(port);
112
+ })
113
+ .listen();
114
+ });
115
+ }
116
+
117
+ export async function getFiles(dir) {
130
118
  const dirents = await fs.promises.readdir(dir, { withFileTypes: true });
131
119
  const files = await Promise.all(
132
120
  dirents.map(dirent => {
@@ -137,18 +125,46 @@ async function getFiles(dir) {
137
125
  return Array.prototype.concat(...files);
138
126
  }
139
127
 
140
- module.exports = {
141
- dirContains,
142
- getArgv,
143
- getRootDir,
144
- logErrorMessage,
145
- getFiles,
146
- logFileCrudMessage,
147
- logSuccessMessage,
148
- moduleExists,
149
- ensureModule,
150
- zip,
151
- pascalCase,
152
- apiHttpErrorToMessage,
153
- generatePreviewHash,
154
- };
128
+ export function getRootDir() {
129
+ return getAppRootDir();
130
+ }
131
+
132
+ export function logErrorMessage(message) {
133
+ console.log(chalk.redBright.bold(message));
134
+ }
135
+
136
+ export function logFileCrudMessage(crud, file) {
137
+ if (['CREATE', 'UPDATE'].includes(crud)) {
138
+ console.log(`${chalk.green(crud)} ${file}`);
139
+ }
140
+ }
141
+
142
+ export function logSuccessMessage(message) {
143
+ console.log(chalk.green(message));
144
+ }
145
+
146
+ export function moduleExists(moduleName) {
147
+ let exists = true;
148
+ try {
149
+ import.meta.resolve(moduleName);
150
+ } catch {
151
+ exists = false;
152
+ }
153
+ return exists;
154
+ }
155
+
156
+ export const pascalCase = flow(camelCase, upperFirst);
157
+
158
+ export function zip(output, callback) {
159
+ const outputDir = path.dirname(output);
160
+ const zipFile = path.join(`${outputDir}.zip`);
161
+ const stream = fs.createWriteStream(zipFile);
162
+ stream.on('close', () => {
163
+ fse.removeSync(outputDir);
164
+ callback(zipFile);
165
+ });
166
+ const archive = archiver('zip', { zlib: { level: 9 } });
167
+ archive.pipe(stream);
168
+ archive.directory(outputDir, path.basename(outputDir));
169
+ archive.finalize();
170
+ }