edge-functions 2.0.0 → 2.1.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.
Files changed (34) hide show
  1. package/.commitlintrc.json +40 -0
  2. package/.husky/commit-msg +5 -0
  3. package/.husky/pre-commit +4 -0
  4. package/.prettierignore +2 -1
  5. package/CHANGELOG.md +62 -0
  6. package/jest.global.setup.js +20 -0
  7. package/lib/build/bundlers/esbuild/plugins/node-polyfills/index.js +10 -1
  8. package/lib/build/bundlers/esbuild/plugins/node-polyfills/node-pollyfills-paths.test.js +40 -0
  9. package/lib/build/dispatcher/dispatcher.js +21 -69
  10. package/lib/build/dispatcher/dispatcher.test.js +121 -8
  11. package/lib/build/dispatcher/helpers/helpers.js +64 -0
  12. package/lib/commands/build.commands.js +1 -1
  13. package/lib/commands/init.commands.js +48 -5
  14. package/lib/constants/framework-initializer.constants.js +100 -17
  15. package/lib/constants/index.js +11 -2
  16. package/lib/env/env.test.js +145 -0
  17. package/lib/env/polyfills/fetch.polyfills.test.js +46 -0
  18. package/lib/env/server.env.js +6 -6
  19. package/lib/env/vulcan.env.js +1 -1
  20. package/lib/presets/custom/astro/deliver/prebuild.js +7 -1
  21. package/lib/presets/custom/next/compute/config.js +3 -0
  22. package/lib/presets/custom/next/compute/node/index.js +22 -1
  23. package/lib/utils/generateManifest/generateManifest.utils.js +30 -0
  24. package/lib/utils/generateManifest/index.js +3 -0
  25. package/lib/utils/generateWebpackBanner/generateWebpackBanner.utils.test.js +22 -0
  26. package/lib/utils/getExportedFunctionBody/getExportedFunctionBody.utils.test.js +2 -1
  27. package/lib/utils/getUrlFromResource/getUrlFromResource.utils.test.js +43 -0
  28. package/lib/utils/getVulcanBuildId/getVulcanBuildId.utils.test.js +5 -25
  29. package/lib/utils/index.js +2 -0
  30. package/lib/utils/injectFilesInMem/injectFilesInMem.utils.test.js +2 -2
  31. package/lib/utils/relocateImportsAndRequires/relocateImportsAndRequires.utils.test.js +43 -0
  32. package/lib/utils/vercel/vercel.utils.test.js +110 -0
  33. package/package.json +21 -4
  34. package/verdaccio/config/config.yaml +50 -0
@@ -0,0 +1,40 @@
1
+ {
2
+ "extends": ["@commitlint/config-conventional"],
3
+ "rules": {
4
+ "body-leading-blank": [1, "always"],
5
+ "body-max-line-length": [2, "always", 100],
6
+ "footer-leading-blank": [1, "always"],
7
+ "footer-max-line-length": [2, "always", 100],
8
+ "header-max-length": [2, "always", 100],
9
+ "scope-case": [2, "always", "lower-case"],
10
+ "subject-case": [
11
+ 2,
12
+ "never",
13
+ ["sentence-case", "start-case", "pascal-case", "upper-case"]
14
+ ],
15
+ "subject-empty": [2, "never"],
16
+ "subject-full-stop": [2, "never", "."],
17
+ "type-case": [2, "always", "lower-case"],
18
+ "type-empty": [2, "never"],
19
+ "type-enum": [
20
+ 2,
21
+ "always",
22
+ [
23
+ "build",
24
+ "chore",
25
+ "ci",
26
+ "docs",
27
+ "feat",
28
+ "fix",
29
+ "perf",
30
+ "refactor",
31
+ "revert",
32
+ "style",
33
+ "test",
34
+ "translation",
35
+ "security",
36
+ "changeset"
37
+ ]
38
+ ]
39
+ }
40
+ }
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ message="🔥 Please check your commit e.g: 'ci: added commitlint and husky'\n"
5
+ npx --no -- commitlint --edit "" || (echo "$message" && exit 1);
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ yarn lint && yarn format:check
package/.prettierignore CHANGED
@@ -1,4 +1,5 @@
1
1
  examples/*
2
2
  jsdoc/*
3
3
  yarn.lock
4
- CHANGELOG.md
4
+ CHANGELOG.md
5
+ docker-compose.yml
package/CHANGELOG.md CHANGED
@@ -1,3 +1,65 @@
1
+ ## [2.1.0](https://github.com/aziontech/vulcan/compare/v2.0.0...v2.1.0) (2023-11-23)
2
+
3
+
4
+ ### Features
5
+
6
+ * add buildId in the constructor ([5caeed9](https://github.com/aziontech/vulcan/commit/5caeed9dc4509762d2fdd7ddb5e28ce054949ffc))
7
+ * add js and ts init template ([bc382e3](https://github.com/aziontech/vulcan/commit/bc382e307e1c0162fcda5adcedb89d209edcc687))
8
+ * add tty and https polyfills ([29ede11](https://github.com/aziontech/vulcan/commit/29ede1159353c3ef2f161efdd520cbe478d56c31))
9
+ * add unit test to function relocateImportsAndRequires ([f64a2c3](https://github.com/aziontech/vulcan/commit/f64a2c349d21d7d32b9d1ad4da40b04e743ceee1))
10
+ * add unit tests ([a0fa0aa](https://github.com/aziontech/vulcan/commit/a0fa0aab558e3afdca1302fce6f470ee33d9e94c))
11
+ * Add unit tests ([#174](https://github.com/aziontech/vulcan/issues/174)) ([6b5c9a7](https://github.com/aziontech/vulcan/commit/6b5c9a72293f53f9f64d88137046658e6b441763))
12
+ * config swc jest ([9404142](https://github.com/aziontech/vulcan/commit/9404142433a7739e2340fd8e2420a2d873817b97))
13
+ * create escapeStringRegexp and remove import ([c9886a6](https://github.com/aziontech/vulcan/commit/c9886a6fd1f8d5deb4d1606f1123b6644ab5b348))
14
+ * create test for hepers ([4039625](https://github.com/aziontech/vulcan/commit/403962534756432ca00eee2b596807de942da982))
15
+ * Create tests for helper ([8813e4c](https://github.com/aziontech/vulcan/commit/8813e4c31a29de8bd5afbe05424443a924a04eee))
16
+ * custom version framework (init command) ([#169](https://github.com/aziontech/vulcan/issues/169)) ([d4a9979](https://github.com/aziontech/vulcan/commit/d4a9979d2cf77b05e004cc86342c0725a5181300))
17
+ * custom version framework init command ([9b82a66](https://github.com/aziontech/vulcan/commit/9b82a663629a96e93eef1fcff7283a5990e0ffad))
18
+ * generate manifest ([8e86f8a](https://github.com/aziontech/vulcan/commit/8e86f8a22b7d6cb7a71c17d880fae8cf999a4c0f))
19
+ * generate manifest (initial structure) ([#177](https://github.com/aziontech/vulcan/issues/177)) ([18889ee](https://github.com/aziontech/vulcan/commit/18889ee336c26c0da129252a11f9c66a776f4d25))
20
+ * remove file protocol from import on function loadVulcanConfigFile ([ed60d69](https://github.com/aziontech/vulcan/commit/ed60d697c1caf4036829ae0d878c949e37263fc6))
21
+ * skip test of get Exported Function because there is some trouble with Babel when try to execute it ([4cb2e17](https://github.com/aziontech/vulcan/commit/4cb2e17cd8f723a6c63f78f025e6cac0cdeac539))
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * fix dispatcher test after merge ([3ef16b1](https://github.com/aziontech/vulcan/commit/3ef16b126ef04005f8f912a59e57580d27167d2c))
27
+ * handle public dir in nextjs with relative paths ([7609347](https://github.com/aziontech/vulcan/commit/76093470b26dfd397e4b5fcbfe75d0b93770ff30))
28
+ * remove duplicate key ([6160f0f](https://github.com/aziontech/vulcan/commit/6160f0fdcd445e56845f1687e63455913006230f))
29
+ * remove unnecessary async ([4ede8e4](https://github.com/aziontech/vulcan/commit/4ede8e4cabd0ccdd532ec863e226fb244f939aef))
30
+ * Run each test in a different vulcan server ([0d8cfd6](https://github.com/aziontech/vulcan/commit/0d8cfd66519c2dfd8a550d20d319df41dcc53b84))
31
+
32
+ ## [2.1.0-stage.1](https://github.com/aziontech/vulcan/compare/v2.0.0...v2.1.0-stage.1) (2023-11-22)
33
+
34
+
35
+ ### Features
36
+
37
+ * add buildId in the constructor ([5caeed9](https://github.com/aziontech/vulcan/commit/5caeed9dc4509762d2fdd7ddb5e28ce054949ffc))
38
+ * add js and ts init template ([bc382e3](https://github.com/aziontech/vulcan/commit/bc382e307e1c0162fcda5adcedb89d209edcc687))
39
+ * add tty and https polyfills ([29ede11](https://github.com/aziontech/vulcan/commit/29ede1159353c3ef2f161efdd520cbe478d56c31))
40
+ * add unit test to function relocateImportsAndRequires ([f64a2c3](https://github.com/aziontech/vulcan/commit/f64a2c349d21d7d32b9d1ad4da40b04e743ceee1))
41
+ * add unit tests ([a0fa0aa](https://github.com/aziontech/vulcan/commit/a0fa0aab558e3afdca1302fce6f470ee33d9e94c))
42
+ * Add unit tests ([#174](https://github.com/aziontech/vulcan/issues/174)) ([6b5c9a7](https://github.com/aziontech/vulcan/commit/6b5c9a72293f53f9f64d88137046658e6b441763))
43
+ * config swc jest ([9404142](https://github.com/aziontech/vulcan/commit/9404142433a7739e2340fd8e2420a2d873817b97))
44
+ * create escapeStringRegexp and remove import ([c9886a6](https://github.com/aziontech/vulcan/commit/c9886a6fd1f8d5deb4d1606f1123b6644ab5b348))
45
+ * create test for hepers ([4039625](https://github.com/aziontech/vulcan/commit/403962534756432ca00eee2b596807de942da982))
46
+ * Create tests for helper ([8813e4c](https://github.com/aziontech/vulcan/commit/8813e4c31a29de8bd5afbe05424443a924a04eee))
47
+ * custom version framework (init command) ([#169](https://github.com/aziontech/vulcan/issues/169)) ([d4a9979](https://github.com/aziontech/vulcan/commit/d4a9979d2cf77b05e004cc86342c0725a5181300))
48
+ * custom version framework init command ([9b82a66](https://github.com/aziontech/vulcan/commit/9b82a663629a96e93eef1fcff7283a5990e0ffad))
49
+ * generate manifest ([8e86f8a](https://github.com/aziontech/vulcan/commit/8e86f8a22b7d6cb7a71c17d880fae8cf999a4c0f))
50
+ * generate manifest (initial structure) ([#177](https://github.com/aziontech/vulcan/issues/177)) ([18889ee](https://github.com/aziontech/vulcan/commit/18889ee336c26c0da129252a11f9c66a776f4d25))
51
+ * remove file protocol from import on function loadVulcanConfigFile ([ed60d69](https://github.com/aziontech/vulcan/commit/ed60d697c1caf4036829ae0d878c949e37263fc6))
52
+ * skip test of get Exported Function because there is some trouble with Babel when try to execute it ([4cb2e17](https://github.com/aziontech/vulcan/commit/4cb2e17cd8f723a6c63f78f025e6cac0cdeac539))
53
+
54
+
55
+ ### Bug Fixes
56
+
57
+ * fix dispatcher test after merge ([3ef16b1](https://github.com/aziontech/vulcan/commit/3ef16b126ef04005f8f912a59e57580d27167d2c))
58
+ * handle public dir in nextjs with relative paths ([7609347](https://github.com/aziontech/vulcan/commit/76093470b26dfd397e4b5fcbfe75d0b93770ff30))
59
+ * remove duplicate key ([6160f0f](https://github.com/aziontech/vulcan/commit/6160f0fdcd445e56845f1687e63455913006230f))
60
+ * remove unnecessary async ([4ede8e4](https://github.com/aziontech/vulcan/commit/4ede8e4cabd0ccdd532ec863e226fb244f939aef))
61
+ * Run each test in a different vulcan server ([0d8cfd6](https://github.com/aziontech/vulcan/commit/0d8cfd66519c2dfd8a550d20d319df41dcc53b84))
62
+
1
63
  ## [2.0.0](https://github.com/aziontech/vulcan/compare/v1.7.1...v2.0.0) (2023-10-27)
2
64
 
3
65
 
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Generate an array based on a range of numbers
3
+ * @param {number} start - start number
4
+ * @param {number} end - end number
5
+ * @returns {number[]} - generated array
6
+ */
7
+ function generateNumericArray(start, end) {
8
+ const result = [];
9
+ for (let index = start; index <= end; index++) {
10
+ result.push(index);
11
+ }
12
+ return result;
13
+ }
14
+
15
+ // eslint-disable-next-line
16
+ export default async function (globalConfig, projectConfig) {
17
+ // check docker-compose available ports
18
+ // TODO: unify this range of numbers (get from docker-compose file)
19
+ globalThis.dockerAvailablePorts = generateNumericArray(3000, 3020);
20
+ }
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable */
2
2
  // Based on https://github.com/remorses/esbuild-plugins/blob/master/node-modules-polyfill/src/index.ts
3
3
 
4
- import escapeStringRegexp from 'escape-string-regexp';
5
4
  import fs from 'fs';
6
5
  import path from 'path';
7
6
 
@@ -23,6 +22,16 @@ function removeEndingSlash(importee) {
23
22
  return importee;
24
23
  }
25
24
 
25
+ function escapeStringRegexp(string) {
26
+ if (typeof string !== 'string') {
27
+ throw new TypeError('Expected a string');
28
+ }
29
+
30
+ // Escape characters with special meaning either inside or outside character sets.
31
+ // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
32
+ return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
33
+ }
34
+
26
35
  /**
27
36
  * Generates a template for commonjs with module require
28
37
  * @param {string} importPath - the import path
@@ -0,0 +1,40 @@
1
+ import { expect, it } from '@jest/globals';
2
+ import builtinsPolyfills from './node-polyfills-paths.js';
3
+
4
+ describe('Node polyfill paths', () => {
5
+ it('Should return map of polyfills', () => {
6
+ const expectedPolyfills = [
7
+ 'process',
8
+ 'buffer',
9
+ 'util',
10
+ 'sys',
11
+ 'events',
12
+ 'stream',
13
+ 'path',
14
+ 'querystring',
15
+ 'punycode',
16
+ 'url',
17
+ 'string_decoder',
18
+ 'http',
19
+ 'https',
20
+ 'os',
21
+ 'assert',
22
+ 'constants',
23
+ '_stream_duplex',
24
+ '_stream_passthrough',
25
+ '_stream_readable',
26
+ '_stream_writable',
27
+ '_stream_transform',
28
+ 'console',
29
+ 'zlib',
30
+ 'tty',
31
+ 'domain',
32
+ ];
33
+ const listOfAvailablePolyfills = builtinsPolyfills();
34
+ const arraylistOfAvailablePolyfills = Array.from(
35
+ listOfAvailablePolyfills.keys(),
36
+ );
37
+
38
+ expect(arraylistOfAvailablePolyfills).toEqual(expectedPolyfills);
39
+ });
40
+ });
@@ -1,13 +1,5 @@
1
1
  import { join, resolve } from 'path';
2
- import {
3
- readFileSync,
4
- existsSync,
5
- mkdirSync,
6
- writeFileSync,
7
- rmSync,
8
- promises as fsPromises,
9
- } from 'fs';
10
- import { fileURLToPath } from 'url';
2
+ import { readFileSync, existsSync, writeFileSync, rmSync } from 'fs';
11
3
  import { Esbuild, Webpack } from '#bundlers';
12
4
  import {
13
5
  feedback,
@@ -23,62 +15,14 @@ import {
23
15
  } from '#utils';
24
16
  import { Messages } from '#constants';
25
17
  import { vulcan } from '#env';
18
+ import {
19
+ getAliasPath,
20
+ createDotEnvFile,
21
+ folderExistsInProject,
22
+ } from './helpers/helpers.js';
26
23
 
27
- const vulcanLibPath = getAbsoluteLibDirPath();
28
- const vulcanRootPath = resolve(vulcanLibPath, '..');
29
24
  const isWindows = process.platform === 'win32';
30
25
 
31
- /**
32
- * Get the path corresponding to a specific alias defined in the package.json.
33
- * @param {string} alias - The desired alias.
34
- * @returns {string} The path corresponding to the alias.
35
- */
36
- async function getAliasPath(alias) {
37
- const packageJsonPath = join(vulcanRootPath, 'package.json');
38
- const packageJsonContent = readFileSync(packageJsonPath, 'utf8');
39
- const packageJson = JSON.parse(packageJsonContent);
40
- let aliasPath = packageJson.imports[`#${alias}`];
41
- aliasPath = aliasPath.replace('./', `${vulcanRootPath}/`);
42
- if (isWindows) {
43
- aliasPath = aliasPath.replace(/[\\/]/g, '\\\\');
44
- }
45
-
46
- return aliasPath;
47
- }
48
-
49
- /**
50
- Create a .env file in the build folder with specified parameters.
51
- * @param {string} buildId - The version ID to write into the .env file.
52
- */
53
- function createDotEnvFile(buildId) {
54
- const projectRoot = process.cwd();
55
- const outputPath = isWindows
56
- ? fileURLToPath(new URL(`file:///${join(projectRoot, '.edge')}`))
57
- : join(projectRoot, '.edge');
58
- const envFilePath = join(outputPath, '.env');
59
-
60
- const envContent = [`VERSION_ID=${buildId}`].join('\n');
61
-
62
- mkdirSync(outputPath, { recursive: true });
63
- writeFileSync(envFilePath, envContent);
64
- }
65
-
66
- /**
67
- * The function checks if a folder exists in the current project directory.
68
- * @param {string} folder - The `folder` parameter is a string that
69
- * represents the name of the folder you want to check if it exists in the current project.
70
- * @returns {Promise<boolean>} The boolean value indicates whether the
71
- * specified folder exists in the current project directory.
72
- */
73
- async function folderExistsInProject(folder) {
74
- const filePath = join(process.cwd(), folder);
75
- try {
76
- const stats = await fsPromises.stat(filePath);
77
- return Promise.resolve(stats.isDirectory());
78
- } catch (error) {
79
- return Promise.resolve(false);
80
- }
81
- }
82
26
  /**
83
27
  * Check if the project has a package.json file and if it has dependencies or
84
28
  * devDependencies, it then checks if the node_modules folder exists and exits the process if it
@@ -134,8 +78,14 @@ class Dispatcher {
134
78
  * @param {boolean} [config.useOwnWorker] - Flag indicating whether the constructed code inserts its own worker expression without the need to inject a provider.
135
79
  * @param {string[]|undefined} [config.memoryFS] - Reference to dirs that contains files to be injected in worker memory.
136
80
  * @param {object} [config.custom] - Custom Bundle configuration.
81
+ * @param {string } buildId - Build ID
82
+ * @param {string} vulcanLibPath - Vulcan lib absolute path
137
83
  */
138
- constructor(config) {
84
+ constructor(
85
+ config,
86
+ buildId = generateTimestamp(),
87
+ vulcanLibPath = getAbsoluteLibDirPath(),
88
+ ) {
139
89
  /* configuration */
140
90
  this.entry = config.entry;
141
91
  this.builder = config.builder;
@@ -147,7 +97,8 @@ class Dispatcher {
147
97
  this.memoryFS = config.memoryFS;
148
98
  this.custom = config.custom;
149
99
  /* generate */
150
- this.buildId = generateTimestamp();
100
+ this.buildId = buildId;
101
+ this.vulcanLibPath = vulcanLibPath;
151
102
  }
152
103
 
153
104
  /**
@@ -156,6 +107,7 @@ class Dispatcher {
156
107
  */
157
108
  async loadPreset() {
158
109
  const VALID_BUILD_PRESETS = presets.getKeys();
110
+ const vulcanRootPath = resolve(this.vulcanLibPath, '..');
159
111
 
160
112
  const validPreset = VALID_BUILD_PRESETS.includes(this.preset.name);
161
113
 
@@ -169,14 +121,14 @@ class Dispatcher {
169
121
  let handlerFilePath;
170
122
 
171
123
  const defaultModePath = join(
172
- vulcanLibPath,
124
+ this.vulcanLibPath,
173
125
  'presets',
174
126
  'default',
175
127
  this.preset.name,
176
128
  this.preset.mode,
177
129
  );
178
130
  const customModePath = join(
179
- vulcanLibPath,
131
+ this.vulcanLibPath,
180
132
  'presets',
181
133
  'custom',
182
134
  this.preset.name,
@@ -225,7 +177,7 @@ class Dispatcher {
225
177
  // use providers
226
178
  if (!this.useOwnWorker) {
227
179
  const workerFilePath = join(
228
- vulcanLibPath,
180
+ this.vulcanLibPath,
229
181
  'providers',
230
182
  'azion',
231
183
  'worker.js',
@@ -241,7 +193,7 @@ class Dispatcher {
241
193
  }
242
194
 
243
195
  // resolve #edge alias without vulcan context
244
- const edgehooksPath = await getAliasPath('edge');
196
+ const edgehooksPath = getAliasPath('edge', vulcanRootPath, isWindows);
245
197
  newHandlerContent = newHandlerContent?.replace('#edge', edgehooksPath);
246
198
 
247
199
  if (
@@ -320,7 +272,7 @@ class Dispatcher {
320
272
  try {
321
273
  feedback.prebuild.info(Messages.build.info.prebuild_starting);
322
274
  await prebuild(context);
323
- createDotEnvFile(this.buildId);
275
+ createDotEnvFile(this.buildId, isWindows);
324
276
  feedback.prebuild.success(Messages.build.success.prebuild_succeeded);
325
277
 
326
278
  feedback.build.info(Messages.build.info.vulcan_build_starting);
@@ -1,12 +1,125 @@
1
- // import Dispatcher from './dispatcher.js';
2
-
3
- const { describe, it } = require('@jest/globals');
1
+ import MockFs from 'mock-fs';
2
+ import fs from 'fs';
3
+ import { expect } from '@jest/globals';
4
+ import Dispatcher from './dispatcher.js';
5
+ import {
6
+ createDotEnvFile,
7
+ folderExistsInProject,
8
+ getAliasPath,
9
+ } from './helpers/helpers.js';
4
10
 
5
11
  describe('dispatcher', () => {
6
- it('should pass', () => {
7
- // TODO: fix this test
8
- // const newDispatcher = new Dispatcher('js', 'dist', 'main.js', 'v1');
9
- // // newDispatcher.run();
10
- expect(true).toBe(true);
12
+ const { env } = process;
13
+ beforeEach(() => {
14
+ jest.resetModules();
15
+ process.env = { HOME: '/home/user' };
16
+ process.cwd = jest.fn(() => '/');
17
+ });
18
+
19
+ afterEach(() => {
20
+ process.env = env;
21
+ });
22
+ it('should create a Dispatcher instance with correct properties', async () => {
23
+ const config = {
24
+ entry: 'main.js',
25
+ builder: 'esbuild',
26
+ preset: {
27
+ name: 'javascript',
28
+ mode: 'compute',
29
+ },
30
+ useNodePolyfills: false,
31
+ useOwnWorker: false,
32
+ memoryFS: undefined,
33
+ custom: {},
34
+ };
35
+
36
+ const expectedDispatcher = {
37
+ entry: 'main.js',
38
+ builder: 'esbuild',
39
+ preset: { name: 'javascript', mode: 'compute' },
40
+ useNodePolyfills: false,
41
+ useOwnWorker: false,
42
+ memoryFS: undefined,
43
+ custom: {},
44
+ buildId: '123456',
45
+ vulcanLibPath: './vulcan',
46
+ };
47
+
48
+ /**
49
+ * generate mocked timestamp
50
+ * @returns {string} - timestamp
51
+ */
52
+ function mockGenerateTimestamp() {
53
+ return '123456';
54
+ }
55
+
56
+ /**
57
+ * mock vulcan lib absolute path
58
+ * @returns {string} - absolute path
59
+ */
60
+ function getAbsoluteLibDirPath() {
61
+ return './vulcan';
62
+ }
63
+
64
+ const newDispatcher = new Dispatcher(
65
+ config,
66
+ mockGenerateTimestamp(),
67
+ getAbsoluteLibDirPath(),
68
+ );
69
+ newDispatcher.loadPreset();
70
+ expect(newDispatcher).toBeInstanceOf(Dispatcher);
71
+ expect(newDispatcher).toEqual(expectedDispatcher);
72
+ });
73
+
74
+ it('Should get alias path', async () => {
75
+ MockFs({
76
+ '/home': {
77
+ user: {
78
+ 'package.json': JSON.stringify({
79
+ imports: {
80
+ '#alias': './dist/edge',
81
+ },
82
+ }),
83
+ dist: {},
84
+ },
85
+ },
86
+ });
87
+ const aliasPath = await getAliasPath('alias', '/home/user', false);
88
+ expect(aliasPath).toEqual('/home/user/dist/edge');
89
+ MockFs.restore();
90
+ });
91
+
92
+ it('should create dot env file', () => {
93
+ MockFs({});
94
+ createDotEnvFile('123456', false);
95
+ const vulcanEnvContent = fs.readFileSync('/.edge/.env', 'utf8');
96
+ expect(vulcanEnvContent).toEqual('VERSION_ID=123456');
97
+ MockFs.restore();
98
+ });
99
+
100
+ it('should create dot env file with windows enviroment', () => {
101
+ MockFs({});
102
+ createDotEnvFile('123456', true);
103
+ const vulcanEnvContent = fs.readFileSync('/.edge/.env', 'utf8');
104
+ expect(vulcanEnvContent).toEqual('VERSION_ID=123456');
105
+ MockFs.restore();
106
+ });
107
+
108
+ it('Should verify if one directory exist in the project', async () => {
109
+ MockFs({
110
+ '/dist': {},
111
+ });
112
+ const folderExists = await folderExistsInProject('dist');
113
+ expect(folderExists).toBe(true);
114
+ MockFs.restore();
115
+ });
116
+
117
+ it('Should verify if one directory exist in the project and expect it fail', async () => {
118
+ MockFs({
119
+ '/dist': {},
120
+ });
121
+ const folderExists = await folderExistsInProject('distFail');
122
+ expect(folderExists).toBe(false);
123
+ MockFs.restore();
11
124
  });
12
125
  });
@@ -0,0 +1,64 @@
1
+ import {
2
+ readFileSync,
3
+ mkdirSync,
4
+ writeFileSync,
5
+ promises as fsPromises,
6
+ } from 'fs';
7
+ import { join } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ /**
11
+ * Get the path corresponding to a specific alias defined in the package.json.
12
+ * @param {string} alias - The desired alias.
13
+ * @param {string} vulcanRootPath - vulcan lib path
14
+ * @param {boolean} isWindows - Indicates that user is using in windows
15
+ * @returns {string} The path corresponding to the alias.
16
+ */
17
+ function getAliasPath(alias, vulcanRootPath, isWindows) {
18
+ const packageJsonPath = join(vulcanRootPath, 'package.json');
19
+ const packageJsonContent = readFileSync(packageJsonPath, 'utf8');
20
+ const packageJson = JSON.parse(packageJsonContent);
21
+ let aliasPath = packageJson.imports[`#${alias}`];
22
+ aliasPath = aliasPath.replace('./', `${vulcanRootPath}/`);
23
+ if (isWindows) {
24
+ aliasPath = aliasPath.replace(/[\\/]/g, '\\\\');
25
+ }
26
+
27
+ return aliasPath;
28
+ }
29
+
30
+ /**
31
+ Create a .env file in the build folder with specified parameters.
32
+ * @param {string} buildId - The version ID to write into the .env file.
33
+ * @param {boolean} isWindows - The boolean value indicates whether the current OS is Windows.
34
+ */
35
+ function createDotEnvFile(buildId, isWindows) {
36
+ const projectRoot = process.cwd();
37
+ const outputPath = isWindows
38
+ ? fileURLToPath(new URL(`file:///${join(projectRoot, '.edge')}`))
39
+ : join(projectRoot, '.edge');
40
+ const envFilePath = join(outputPath, '.env');
41
+ const envContent = [`VERSION_ID=${buildId}`].join('\n');
42
+
43
+ mkdirSync(outputPath, { recursive: true });
44
+ writeFileSync(envFilePath, envContent);
45
+ }
46
+
47
+ /**
48
+ * The function checks if a folder exists in the current project directory.
49
+ * @param {string} folder - The `folder` parameter is a string that
50
+ * represents the name of the folder you want to check if it exists in the current project.
51
+ * @returns {Promise<boolean>} The boolean value indicates whether the
52
+ * specified folder exists in the current project directory.
53
+ */
54
+ async function folderExistsInProject(folder) {
55
+ const filePath = join(process.cwd(), folder);
56
+ try {
57
+ const stats = await fsPromises.stat(filePath);
58
+ return Promise.resolve(stats.isDirectory());
59
+ } catch (error) {
60
+ return Promise.resolve(false);
61
+ }
62
+ }
63
+
64
+ export { createDotEnvFile, getAliasPath, folderExistsInProject };
@@ -19,7 +19,6 @@ function getConfigValue(
19
19
  ) {
20
20
  return customConfig ?? inputOption ?? vulcanVariable ?? defaultValue;
21
21
  }
22
-
23
22
  /**
24
23
  * Retrieves a preset configuration value based on priority.
25
24
  * Priority order for both name and mode: customConfig, inputOption, vulcanVariable, defaultValue.
@@ -142,6 +141,7 @@ async function buildCommand({
142
141
  ) {
143
142
  feedback.info(`Using ${config.entry} as entrypoint...`);
144
143
  }
144
+
145
145
  const BuildDispatcher = (await import('#build')).default;
146
146
  const buildDispatcher = new BuildDispatcher(config);
147
147
 
@@ -1,7 +1,11 @@
1
1
  import { join } from 'path';
2
2
  import { existsSync } from 'fs';
3
- import { createPromptModule } from 'inquirer';
4
- import { FrameworkInitializer, Messages } from '#constants';
3
+ import inquirer, { createPromptModule } from 'inquirer';
4
+ import {
5
+ FrameworkInitializer,
6
+ FrameworksDefaultVersions,
7
+ Messages,
8
+ } from '#constants';
5
9
  import { feedback, debug } from '#utils';
6
10
  import { vulcan } from '#env';
7
11
 
@@ -19,7 +23,7 @@ const prompt = createPromptModule();
19
23
  * @example
20
24
  * initCommand({ name: 'my_new_project' });
21
25
  */
22
- async function initComamnd({ name }) {
26
+ async function initCommand({ name }) {
23
27
  try {
24
28
  const AVALIABLE_TEMPLATES = Object.keys(FrameworkInitializer);
25
29
  let projectName = name;
@@ -33,6 +37,45 @@ async function initComamnd({ name }) {
33
37
  },
34
38
  ]);
35
39
 
40
+ const frameworkOptions =
41
+ FrameworksDefaultVersions[frameworkChoice]?.options || [];
42
+ let version = 'latest'; // Set default version as 'latest'
43
+
44
+ if (frameworkOptions.length > 0) {
45
+ const versionChoices = frameworkOptions
46
+ .map((option) => ({
47
+ name: `${option.value} (${option.message})`,
48
+ value: option.value,
49
+ }))
50
+ .concat([
51
+ new inquirer.Separator(),
52
+ { name: 'Custom version', value: 'custom' },
53
+ ]);
54
+
55
+ const versionPrompt = await inquirer.prompt([
56
+ {
57
+ type: 'list',
58
+ name: 'versionChoice',
59
+ message: 'Choose the version:',
60
+ choices: versionChoices,
61
+ },
62
+ ]);
63
+
64
+ if (versionPrompt.versionChoice === 'custom') {
65
+ // Logic to input a custom version
66
+ const customVersionPrompt = await inquirer.prompt([
67
+ {
68
+ type: 'input',
69
+ name: 'customVersion',
70
+ message: 'Enter the custom version:',
71
+ },
72
+ ]);
73
+ version = customVersionPrompt.customVersion;
74
+ } else {
75
+ version = versionPrompt.versionChoice;
76
+ }
77
+ }
78
+
36
79
  while (!projectName) {
37
80
  const dirExists = (dirName) => existsSync(join(process.cwd(), dirName));
38
81
 
@@ -57,7 +100,7 @@ async function initComamnd({ name }) {
57
100
  const createFrameworkTemplate = FrameworkInitializer[frameworkChoice];
58
101
  if (createFrameworkTemplate) {
59
102
  const dest = join(process.cwd(), projectName);
60
- await createFrameworkTemplate(projectName);
103
+ await createFrameworkTemplate(projectName, version);
61
104
  await vulcan.createVulcanEnv(
62
105
  { preset: frameworkChoice.toLowerCase() },
63
106
  dest,
@@ -70,4 +113,4 @@ async function initComamnd({ name }) {
70
113
  }
71
114
  }
72
115
 
73
- export default initComamnd;
116
+ export default initCommand;