@eik/common 4.1.0 → 5.0.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 (43) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/lib/classes/custom-error.js +8 -8
  3. package/lib/classes/eik-config.js +148 -152
  4. package/lib/classes/file-mapping.js +25 -25
  5. package/lib/classes/invalid-config-error.js +7 -7
  6. package/lib/classes/local-file-location.js +45 -48
  7. package/lib/classes/missing-config-error.js +7 -7
  8. package/lib/classes/multiple-config-sources-error.js +6 -6
  9. package/lib/classes/no-files-matched-error.js +8 -8
  10. package/lib/classes/read-file.js +25 -25
  11. package/lib/classes/remote-file-location.js +30 -30
  12. package/lib/classes/resolved-files.js +38 -44
  13. package/lib/classes/single-dest-multiple-source-error.js +9 -9
  14. package/lib/helpers/config-store.js +103 -103
  15. package/lib/helpers/get-defaults.js +24 -24
  16. package/lib/helpers/index.js +21 -21
  17. package/lib/helpers/local-assets.js +49 -49
  18. package/lib/helpers/path-slashes.js +25 -12
  19. package/lib/helpers/resolve-files.js +64 -50
  20. package/lib/helpers/type-slug.js +3 -3
  21. package/lib/helpers/type-title.js +4 -4
  22. package/lib/index.js +12 -12
  23. package/lib/schemas/assert.js +41 -41
  24. package/lib/schemas/index.js +7 -7
  25. package/lib/schemas/validate.js +64 -64
  26. package/lib/schemas/validation-error.js +11 -11
  27. package/lib/stream.js +11 -11
  28. package/lib/validators/index.js +37 -37
  29. package/package.json +14 -13
  30. package/types/classes/eik-config.d.ts +1 -1
  31. package/types/classes/file-mapping.d.ts +2 -2
  32. package/types/classes/invalid-config-error.d.ts +1 -1
  33. package/types/classes/missing-config-error.d.ts +1 -1
  34. package/types/classes/multiple-config-sources-error.d.ts +1 -1
  35. package/types/classes/no-files-matched-error.d.ts +1 -1
  36. package/types/classes/resolved-files.d.ts +1 -1
  37. package/types/classes/single-dest-multiple-source-error.d.ts +1 -1
  38. package/types/helpers/config-store.d.ts +1 -1
  39. package/types/helpers/index.d.ts +10 -10
  40. package/types/helpers/path-slashes.d.ts +2 -28
  41. package/types/helpers/resolve-files.d.ts +1 -1
  42. package/types/index.d.ts +6 -6
  43. package/types/schemas/index.d.ts +3 -3
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @type {(value: unknown, message?: string) => asserts value}
3
3
  */
4
- import assert from 'node:assert';
5
- import fs from 'node:fs';
6
- import configStore from './config-store.js';
4
+ import assert from "node:assert";
5
+ import fs from "node:fs";
6
+ import configStore from "./config-store.js";
7
7
 
8
8
  /**
9
9
  * Sets up asset routes for local development. Mounted paths match those on Eik server and values are read from projects eik.json file.
@@ -12,52 +12,52 @@ import configStore from './config-store.js';
12
12
  * @param {string} rootEikDirectory - (optional) path to folder where eik configuration file can be found
13
13
  */
14
14
  async function localAssets(app, rootEikDirectory = process.cwd()) {
15
- assert(
16
- // @ts-ignore
17
- app.decorateReply || app.name === 'app' || app.route,
18
- 'App must be an Express, Fastify or Hapi app instance',
19
- );
20
- assert(
21
- typeof rootEikDirectory === 'string' && rootEikDirectory,
22
- 'Path to folder for eik config must be provided and must be of type string',
23
- );
24
- // ensure eik.json only loaded 1x
25
- const eik = configStore.findInDirectory(rootEikDirectory);
15
+ assert(
16
+ // @ts-ignore
17
+ app.decorateReply || app.name === "app" || app.route,
18
+ "App must be an Express, Fastify or Hapi app instance",
19
+ );
20
+ assert(
21
+ typeof rootEikDirectory === "string" && rootEikDirectory,
22
+ "Path to folder for eik config must be provided and must be of type string",
23
+ );
24
+ // ensure eik.json only loaded 1x
25
+ const eik = configStore.findInDirectory(rootEikDirectory);
26
26
 
27
- (await eik.mappings()).forEach((mapping) => {
28
- const { pathname } = mapping.destination.url;
29
- const { contentType, absolute: path } = mapping.source;
30
- // @ts-ignore
31
- if (app.get) {
32
- // @ts-ignore
33
- app.get(pathname, (req, res) => {
34
- if (res.set) {
35
- // express
36
- res.set('Access-Control-Allow-Origin', '*');
37
- res.set('content-type', contentType);
38
- fs.createReadStream(path).pipe(res);
39
- } else if (res.type) {
40
- // fastify
41
- res.header('Access-Control-Allow-Origin', '*');
42
- res.type(contentType);
43
- res.send(fs.createReadStream(path));
44
- }
45
- });
46
- } else {
47
- // hapi
48
- // @ts-ignore
49
- app.route({
50
- method: 'GET',
51
- path: pathname,
52
- // @ts-ignore
53
- handler(req, h) {
54
- return h
55
- .response(fs.createReadStream(path))
56
- .header('Access-Control-Allow-Origin', '*')
57
- .type(contentType);
58
- },
59
- });
60
- }
61
- });
27
+ (await eik.mappings()).forEach((mapping) => {
28
+ const { pathname } = mapping.destination.url;
29
+ const { contentType, absolute: path } = mapping.source;
30
+ // @ts-ignore
31
+ if (app.get) {
32
+ // @ts-ignore
33
+ app.get(pathname, (req, res) => {
34
+ if (res.set) {
35
+ // express
36
+ res.set("Access-Control-Allow-Origin", "*");
37
+ res.set("content-type", contentType);
38
+ fs.createReadStream(path).pipe(res);
39
+ } else if (res.type) {
40
+ // fastify
41
+ res.header("Access-Control-Allow-Origin", "*");
42
+ res.type(contentType);
43
+ res.send(fs.createReadStream(path));
44
+ }
45
+ });
46
+ } else {
47
+ // hapi
48
+ // @ts-ignore
49
+ app.route({
50
+ method: "GET",
51
+ path: pathname,
52
+ // @ts-ignore
53
+ handler(req, h) {
54
+ return h
55
+ .response(fs.createReadStream(path))
56
+ .header("Access-Control-Allow-Origin", "*")
57
+ .type(contentType);
58
+ },
59
+ });
60
+ }
61
+ });
62
62
  }
63
63
  export default localAssets;
@@ -1,3 +1,6 @@
1
+ import { sep } from "path";
2
+ import { platform } from "os";
3
+
1
4
  /**
2
5
  * Add a trailing slash to a path if necessary
3
6
  *
@@ -5,7 +8,7 @@
5
8
  *
6
9
  * @returns {string}
7
10
  */
8
- const addTrailingSlash = (val) => (val.endsWith('/') ? val : `${val}/`);
11
+ export const addTrailingSlash = (val) => (val.endsWith("/") ? val : `${val}/`);
9
12
 
10
13
  /**
11
14
  * Remove a trailing slash from a path if necessary
@@ -14,17 +17,19 @@ const addTrailingSlash = (val) => (val.endsWith('/') ? val : `${val}/`);
14
17
  *
15
18
  * @returns {string}
16
19
  */
17
- const removeTrailingSlash = (val) =>
18
- val.endsWith('/') ? val.substr(0, val.length - 1) : val;
20
+ export const removeTrailingSlash = (val) =>
21
+ // this is also used to trim from config files, which may now always use the OS's sep value. Look for both.
22
+ val.endsWith("/") || val.endsWith("\\") ? val.substr(0, val.length - 1) : val;
19
23
 
20
24
  /**
21
- * Add a leading slash to a path if necessary
25
+ * Add a leading slash to a path if necessary, but not on Windows
22
26
  *
23
27
  * @param {string} val
24
28
  *
25
29
  * @returns {string}
26
30
  */
27
- const addLeadingSlash = (val) => (val.startsWith('/') ? val : `/${val}`);
31
+ export const addLeadingSlash = (val) =>
32
+ val.startsWith("/") || platform() === "win32" ? val : `/${val}`;
28
33
 
29
34
  /**
30
35
  * Remove a leading slash from a path if necessary
@@ -33,11 +38,19 @@ const addLeadingSlash = (val) => (val.startsWith('/') ? val : `/${val}`);
33
38
  *
34
39
  * @returns {string}
35
40
  */
36
- const removeLeadingSlash = (val) => (val.startsWith('/') ? val.substr(1) : val);
41
+ export const removeLeadingSlash = (val) =>
42
+ val.startsWith("/") || val.startsWith("\\") ? val.substr(1) : val;
43
+
44
+ /**
45
+ * Replaces a path string's separators (/ or \) with the current OS's sep value from node:path.
46
+ * @param {string} val
47
+ * @returns {string}
48
+ */
49
+ export const ensureOsSep = (val) => val.replace(/\/\\/g, sep);
37
50
 
38
- export {
39
- addTrailingSlash,
40
- removeTrailingSlash,
41
- addLeadingSlash,
42
- removeLeadingSlash,
43
- };
51
+ /**
52
+ * Replaces any backslash with a forward slash.
53
+ * @param {string} val
54
+ * @returns {string}
55
+ */
56
+ export const ensurePosix = (val) => val.replace(/\\/g, "/");
@@ -1,12 +1,14 @@
1
- import { extname, join, isAbsolute, basename, sep, normalize } from 'node:path';
2
- import isGlob from 'is-glob';
3
- import { glob } from 'glob';
1
+ import { extname, join, isAbsolute, basename, sep, normalize } from "node:path";
2
+ import isGlob from "is-glob";
3
+ import { glob } from "glob";
4
4
  import {
5
- removeTrailingSlash,
6
- addLeadingSlash,
7
- removeLeadingSlash,
8
- } from './path-slashes.js';
9
- import ResolvedFiles from '../classes/resolved-files.js';
5
+ removeTrailingSlash,
6
+ addLeadingSlash,
7
+ removeLeadingSlash,
8
+ ensureOsSep,
9
+ ensurePosix,
10
+ } from "./path-slashes.js";
11
+ import ResolvedFiles from "../classes/resolved-files.js";
10
12
 
11
13
  /**
12
14
  * Create a new path from a path string preceeding a glob or the whole path if no glob is found
@@ -15,15 +17,16 @@ import ResolvedFiles from '../classes/resolved-files.js';
15
17
  * @returns {string} modified path
16
18
  */
17
19
  const pathUntilGlob = (path) => {
18
- const segments = (path || '').split(sep);
19
- const segmentsToKeep = [];
20
- for (const segment of segments) {
21
- if (segment === '.') continue;
22
- if (segment === '') continue;
23
- if (isGlob(segment)) break;
24
- segmentsToKeep.push(segment);
25
- }
26
- return addLeadingSlash(normalize(segmentsToKeep.join(sep)));
20
+ const segments = (path || "").split(sep);
21
+ const segmentsToKeep = [];
22
+ for (const segment of segments) {
23
+ if (segment === ".") continue;
24
+ if (segment === "") continue;
25
+ if (isGlob(segment)) break;
26
+ segmentsToKeep.push(segment);
27
+ }
28
+
29
+ return addLeadingSlash(normalize(segmentsToKeep.join(sep)));
27
30
  };
28
31
 
29
32
  /**
@@ -35,44 +38,55 @@ const pathUntilGlob = (path) => {
35
38
  * @returns {Promise<ResolvedFiles[]>}
36
39
  */
37
40
  const resolveFiles = async (files, cwd) =>
38
- Promise.all(
39
- Object.entries(files).map(async (definition) => {
40
- const [, source] = definition;
41
- // normalise to absolute path
42
- let pattern = isAbsolute(source) ? source : join(cwd, source);
41
+ Promise.all(
42
+ Object.entries(files).map(async (definition) => {
43
+ let [, source] = definition;
44
+
45
+ // The config may not always match the OS's separator.
46
+ // Convert the input to OS-specific if necessary.
47
+ // We convert back to always using forward slashes for glob,
48
+ // but for calculating the paths relative to cwd we'd like
49
+ // these to be OS-specific for now.
50
+ source = ensureOsSep(source);
51
+
52
+ // normalise to absolute path
53
+ let pattern = isAbsolute(source) ? source : join(cwd, source);
54
+
55
+ // append glob if folder
56
+ if (extname(pattern) === "" && isGlob(ensurePosix(pattern)) === false) {
57
+ pattern = `${pattern}${sep}**${sep}*`;
58
+ }
43
59
 
44
- // append glob if folder
45
- if (extname(pattern) === '' && isGlob(pattern) === false) {
46
- pattern = join(pattern, '/**/*');
47
- }
60
+ // trim off any glob
61
+ let basePath = pathUntilGlob(pattern);
48
62
 
49
- // trim off any glob
50
- let basePath = pathUntilGlob(pattern);
63
+ // fix basePath if file
64
+ if (extname(pattern) !== "") {
65
+ basePath = removeTrailingSlash(basePath.replace(basename(pattern), ""));
66
+ }
51
67
 
52
- // fix basePath if file
53
- if (extname(pattern) !== '') {
54
- basePath = removeTrailingSlash(
55
- basePath.replace(basename(pattern), ''),
56
- );
57
- }
68
+ // convert glob pattern to forward slash separators
69
+ // https://www.npmjs.com/package/glob#windows
70
+ basePath = ensurePosix(basePath);
71
+ pattern = ensurePosix(pattern);
58
72
 
59
- // process glob pattern into a list of existing files
60
- const resolvedFiles = await glob(pattern, {
61
- cwd: basePath,
62
- nodir: true,
63
- });
73
+ // process glob pattern into a list of existing files
74
+ const resolvedFiles = await glob(pattern, {
75
+ cwd: basePath,
76
+ nodir: true,
77
+ });
64
78
 
65
- // trim off the basePath to create a relative pathed pattern
66
- pattern = removeTrailingSlash(
67
- removeLeadingSlash(pattern.replace(basePath, '')),
68
- );
79
+ // trim off the basePath to create a relative pathed pattern
80
+ pattern = removeTrailingSlash(
81
+ removeLeadingSlash(pattern.replace(basePath, "")),
82
+ );
69
83
 
70
- return new ResolvedFiles(resolvedFiles, {
71
- definition,
72
- basePath,
73
- pattern,
74
- });
75
- }),
76
- );
84
+ return new ResolvedFiles(resolvedFiles, {
85
+ definition,
86
+ basePath,
87
+ pattern,
88
+ });
89
+ }),
90
+ );
77
91
 
78
92
  export default resolveFiles;
@@ -5,7 +5,7 @@
5
5
  * @returns {string} the Eik package type
6
6
  */
7
7
  export default (type) => {
8
- if (type === 'package') return 'pkg';
9
- if (type === 'image') return 'img';
10
- return type;
8
+ if (type === "package") return "pkg";
9
+ if (type === "image") return "img";
10
+ return type;
11
11
  };
@@ -4,8 +4,8 @@
4
4
  * @param {"PACKAGE" | "NPM" | "MAP"} type
5
5
  */
6
6
  export default (type) => {
7
- if (type === 'package') return 'PACKAGE';
8
- if (type === 'npm') return 'NPM';
9
- if (type === 'image') return 'IMAGE';
10
- return 'MAP';
7
+ if (type === "package") return "PACKAGE";
8
+ if (type === "npm") return "NPM";
9
+ if (type === "image") return "IMAGE";
10
+ return "MAP";
11
11
  };
package/lib/index.js CHANGED
@@ -1,16 +1,16 @@
1
- import * as validators from './validators/index.js';
2
- import ReadFile from './classes/read-file.js';
3
- import EikConfig from './classes/eik-config.js';
4
- import schemas from './schemas/index.js';
5
- import * as stream from './stream.js';
6
- import helpers from './helpers/index.js';
1
+ import * as validators from "./validators/index.js";
2
+ import ReadFile from "./classes/read-file.js";
3
+ import EikConfig from "./classes/eik-config.js";
4
+ import schemas from "./schemas/index.js";
5
+ import * as stream from "./stream.js";
6
+ import helpers from "./helpers/index.js";
7
7
 
8
8
  export default {
9
- validators,
10
- ReadFile,
11
- EikConfig,
12
- schemas,
13
- stream,
14
- helpers,
9
+ validators,
10
+ ReadFile,
11
+ EikConfig,
12
+ schemas,
13
+ stream,
14
+ helpers,
15
15
  };
16
16
  export { validators, ReadFile, EikConfig, schemas, stream, helpers };
@@ -1,14 +1,14 @@
1
1
  import {
2
- eikJSON,
3
- name,
4
- version,
5
- type,
6
- server,
7
- files,
8
- importMap,
9
- out,
10
- } from './validate.js';
11
- import ValidationError from './validation-error.js';
2
+ eikJSON,
3
+ name,
4
+ version,
5
+ type,
6
+ server,
7
+ files,
8
+ importMap,
9
+ out,
10
+ } from "./validate.js";
11
+ import ValidationError from "./validation-error.js";
12
12
 
13
13
  /**
14
14
  * @template T
@@ -25,38 +25,38 @@ import ValidationError from './validation-error.js';
25
25
  * @returns {SchemaAssert<T>}
26
26
  */
27
27
  const assert = (validate, message) => (value) => {
28
- const valid = validate(value);
29
- if (valid.error) {
30
- const errorMessage = valid.error
31
- // @ts-ignore
32
- .map((err) => {
33
- let msg = err.message;
34
- if (err.params && err.params.allowedValues) {
35
- msg += ` ("${err.params.allowedValues.join('", "')}")`;
36
- }
37
- return msg;
38
- })
39
- .join(',');
40
- // @ts-expect-error Maybe some toString magic happens here?
41
- throw new ValidationError(`${message}: ${errorMessage}`, valid.error);
42
- }
28
+ const valid = validate(value);
29
+ if (valid.error) {
30
+ const errorMessage = valid.error
31
+ // @ts-ignore
32
+ .map((err) => {
33
+ let msg = err.message;
34
+ if (err.params && err.params.allowedValues) {
35
+ msg += ` ("${err.params.allowedValues.join('", "')}")`;
36
+ }
37
+ return msg;
38
+ })
39
+ .join(",");
40
+ // @ts-expect-error Maybe some toString magic happens here?
41
+ throw new ValidationError(`${message}: ${errorMessage}`, valid.error);
42
+ }
43
43
  };
44
44
 
45
45
  export default {
46
- /** Asserts the given [eik.json](https://eik.dev/docs/reference/eik-json) includes required fields that are valid */
47
- eikJSON: assert(eikJSON, 'Invalid eik.json schema'),
48
- /** Asserts the given [name](https://eik.dev/docs/reference/eik-json#name) value is valid*/
49
- name: assert(name, 'Parameter "name" is not valid'),
50
- /** Asserts the given [type](https://eik.dev/docs/reference/eik-json#type) value is valid*/
51
- type: assert(type, 'Parameter "type" is not valid'),
52
- /** Asserts the given [version](https://eik.dev/docs/reference/eik-json#version) value is valid*/
53
- version: assert(version, 'Parameter "version" is not valid'),
54
- /** Asserts the given [server](https://eik.dev/docs/reference/eik-json#server) value is valid*/
55
- server: assert(server, 'Parameter "server" is not valid'),
56
- /** Asserts the given [files](https://eik.dev/docs/reference/eik-json#files) value is valid */
57
- files: assert(files, 'Parameter "files" is not valid'),
58
- /** Asserts the given [import-map](https://eik.dev/docs/reference/eik-json#import-map) value is valid */
59
- importMap: assert(importMap, 'Parameter "import-map" is not valid'),
60
- /** Asserts the given [out](https://eik.dev/docs/reference/eik-json#out) value is valid */
61
- out: assert(out, 'Parameter "out" is not valid'),
46
+ /** Asserts the given [eik.json](https://eik.dev/docs/reference/eik-json) includes required fields that are valid */
47
+ eikJSON: assert(eikJSON, "Invalid eik.json schema"),
48
+ /** Asserts the given [name](https://eik.dev/docs/reference/eik-json#name) value is valid*/
49
+ name: assert(name, 'Parameter "name" is not valid'),
50
+ /** Asserts the given [type](https://eik.dev/docs/reference/eik-json#type) value is valid*/
51
+ type: assert(type, 'Parameter "type" is not valid'),
52
+ /** Asserts the given [version](https://eik.dev/docs/reference/eik-json#version) value is valid*/
53
+ version: assert(version, 'Parameter "version" is not valid'),
54
+ /** Asserts the given [server](https://eik.dev/docs/reference/eik-json#server) value is valid*/
55
+ server: assert(server, 'Parameter "server" is not valid'),
56
+ /** Asserts the given [files](https://eik.dev/docs/reference/eik-json#files) value is valid */
57
+ files: assert(files, 'Parameter "files" is not valid'),
58
+ /** Asserts the given [import-map](https://eik.dev/docs/reference/eik-json#import-map) value is valid */
59
+ importMap: assert(importMap, 'Parameter "import-map" is not valid'),
60
+ /** Asserts the given [out](https://eik.dev/docs/reference/eik-json#out) value is valid */
61
+ out: assert(out, 'Parameter "out" is not valid'),
62
62
  };
@@ -1,15 +1,15 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join, dirname } from 'node:path';
3
- import * as validate from './validate.js';
4
- import assert from './assert.js';
5
- import ValidationError from './validation-error.js';
6
- import { fileURLToPath } from 'node:url';
1
+ import { readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import * as validate from "./validate.js";
4
+ import assert from "./assert.js";
5
+ import ValidationError from "./validation-error.js";
6
+ import { fileURLToPath } from "node:url";
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = dirname(__filename);
10
10
 
11
11
  const schema = JSON.parse(
12
- readFileSync(join(__dirname, './eikjson.schema.json'), 'utf8'),
12
+ readFileSync(join(__dirname, "./eikjson.schema.json"), "utf8"),
13
13
  );
14
14
 
15
15
  export default { schema, validate, assert, ValidationError };