@eik/common
Advanced tools
Comparing version 4.1.1 to 5.0.0
@@ -0,1 +1,13 @@ | ||
# [5.0.0](https://github.com/eik-lib/common/compare/v4.1.1...v5.0.0) (2024-11-13) | ||
### Bug Fixes | ||
* update validate-npm-package-name ([0dac235](https://github.com/eik-lib/common/commit/0dac23582de09bb739a730a8ca9bee7370146bcc)) | ||
### BREAKING CHANGES | ||
* Requires Node >=20.5.0 | ||
## [4.1.1](https://github.com/eik-lib/common/compare/v4.1.0...v4.1.1) (2024-08-16) | ||
@@ -2,0 +14,0 @@ |
export default class CustomError extends Error { | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = this.constructor.name; | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
/** | ||
* @param {string} message | ||
*/ | ||
constructor(message) { | ||
super(message); | ||
this.name = this.constructor.name; | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
} |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import { extname, join, isAbsolute } from 'node:path'; | ||
import NoFilesMatchedError from './no-files-matched-error.js'; | ||
import SingleDestMultipleSourcesError from './single-dest-multiple-source-error.js'; | ||
import FileMapping from './file-mapping.js'; | ||
import RemoteFileLocation from './remote-file-location.js'; | ||
import schemas from '../schemas/index.js'; | ||
import { removeTrailingSlash, ensurePosix } from '../helpers/path-slashes.js'; | ||
import typeSlug from '../helpers/type-slug.js'; | ||
import resolveFiles from '../helpers/resolve-files.js'; | ||
import assert from "node:assert"; | ||
import { extname, join, isAbsolute } from "node:path"; | ||
import NoFilesMatchedError from "./no-files-matched-error.js"; | ||
import SingleDestMultipleSourcesError from "./single-dest-multiple-source-error.js"; | ||
import FileMapping from "./file-mapping.js"; | ||
import RemoteFileLocation from "./remote-file-location.js"; | ||
import schemas from "../schemas/index.js"; | ||
import { removeTrailingSlash, ensurePosix } from "../helpers/path-slashes.js"; | ||
import typeSlug from "../helpers/type-slug.js"; | ||
import resolveFiles from "../helpers/resolve-files.js"; | ||
const _config = Symbol('config'); | ||
const _tokens = Symbol('tokens'); | ||
const _config = Symbol("config"); | ||
const _tokens = Symbol("tokens"); | ||
@@ -26,3 +26,3 @@ /** | ||
const normalizeFilesDefinition = (files) => | ||
typeof files === 'string' ? { '/': files } : files; | ||
typeof files === "string" ? { "/": files } : files; | ||
@@ -34,138 +34,136 @@ /** | ||
export default class EikConfig { | ||
/** | ||
* @param {EikjsonSchema?} configHash | ||
* @param {[string, string][]?} tokens | ||
* @param {string?} configRootDir | ||
*/ | ||
constructor(configHash, tokens = null, configRootDir = process.cwd()) { | ||
/** @type EikjsonSchema */ | ||
this[_config] = JSON.parse(JSON.stringify(configHash)) || {}; | ||
this[_tokens] = new Map(tokens); | ||
/** | ||
* @param {EikjsonSchema?} configHash | ||
* @param {[string, string][]?} tokens | ||
* @param {string?} configRootDir | ||
*/ | ||
constructor(configHash, tokens = null, configRootDir = process.cwd()) { | ||
/** @type EikjsonSchema */ | ||
this[_config] = JSON.parse(JSON.stringify(configHash)) || {}; | ||
this[_tokens] = new Map(tokens); | ||
assert( | ||
// @ts-ignore | ||
isAbsolute(configRootDir), | ||
`"configRootDir" must be an absolute path: "${configRootDir}" given`, | ||
); | ||
// @ts-ignore | ||
this.cwd = removeTrailingSlash(configRootDir); | ||
/** @type {string[]} */ | ||
// @ts-ignore | ||
this.map = [].concat(this[_config]['import-map'] || []); | ||
} | ||
assert( | ||
// @ts-ignore | ||
isAbsolute(configRootDir), | ||
`"configRootDir" must be an absolute path: "${configRootDir}" given`, | ||
); | ||
// @ts-ignore | ||
this.cwd = removeTrailingSlash(configRootDir); | ||
/** @type {string[]} */ | ||
// @ts-ignore | ||
this.map = [].concat(this[_config]["import-map"] || []); | ||
} | ||
/** @type {EikjsonSchema["name"]} */ | ||
get name() { | ||
return this[_config].name; | ||
} | ||
/** @type {EikjsonSchema["name"]} */ | ||
get name() { | ||
return this[_config].name; | ||
} | ||
/** @type {EikjsonSchema["version"]} */ | ||
get version() { | ||
return this[_config].version; | ||
} | ||
/** @type {EikjsonSchema["version"]} */ | ||
get version() { | ||
return this[_config].version; | ||
} | ||
set version(newVersion) { | ||
schemas.assert.version(newVersion); | ||
this[_config].version = newVersion; | ||
} | ||
set version(newVersion) { | ||
schemas.assert.version(newVersion); | ||
this[_config].version = newVersion; | ||
} | ||
/** @type {EikjsonSchema["type"]} */ | ||
get type() { | ||
// @ts-ignore | ||
return this[_config].type || schemas.schema.properties.type.default; | ||
} | ||
/** @type {EikjsonSchema["type"]} */ | ||
get type() { | ||
// @ts-ignore | ||
return this[_config].type || schemas.schema.properties.type.default; | ||
} | ||
/** @type {string} */ | ||
get server() { | ||
const configuredServer = this[_config].server; | ||
if (configuredServer) { | ||
return configuredServer; | ||
} | ||
return this[_tokens].keys().next().value; | ||
} | ||
/** @type {string} */ | ||
get server() { | ||
const configuredServer = this[_config].server; | ||
if (configuredServer) { | ||
return configuredServer; | ||
} | ||
return this[_tokens].keys().next().value; | ||
} | ||
/** @type {[string, string][]} */ | ||
get token() { | ||
// @ts-ignore | ||
return this[_tokens].get(this.server); | ||
} | ||
/** @type {[string, string][]} */ | ||
get token() { | ||
// @ts-ignore | ||
return this[_tokens].get(this.server); | ||
} | ||
/** @type {EikjsonSchema["files"]} */ | ||
get files() { | ||
return this[_config].files; | ||
} | ||
/** @type {EikjsonSchema["files"]} */ | ||
get files() { | ||
return this[_config].files; | ||
} | ||
/** | ||
* Normalized relative directory path with any leading ./ or | ||
* trailing / characters stripped. Defaults to .eik | ||
* | ||
* @returns {string} out path string | ||
*/ | ||
get out() { | ||
const defaulted = this[_config].out || '.eik'; | ||
const out = defaulted.startsWith('./') | ||
? defaulted.substr(2) | ||
: defaulted; | ||
return removeTrailingSlash(out); | ||
} | ||
/** | ||
* Normalized relative directory path with any leading ./ or | ||
* trailing / characters stripped. Defaults to .eik | ||
* | ||
* @returns {string} out path string | ||
*/ | ||
get out() { | ||
const defaulted = this[_config].out || ".eik"; | ||
const out = defaulted.startsWith("./") ? defaulted.substr(2) : defaulted; | ||
return removeTrailingSlash(out); | ||
} | ||
/** | ||
* Serializes internal values to an object | ||
* | ||
* @returns {EikjsonSchema} object consistent with EikjsonSchema | ||
*/ | ||
toJSON() { | ||
return { ...this[_config] }; | ||
} | ||
/** | ||
* Serializes internal values to an object | ||
* | ||
* @returns {EikjsonSchema} object consistent with EikjsonSchema | ||
*/ | ||
toJSON() { | ||
return { ...this[_config] }; | ||
} | ||
/** | ||
* Validates config values against the eik JSON schema | ||
* | ||
* @return {void} | ||
*/ | ||
validate() { | ||
schemas.assert.eikJSON(this[_config]); | ||
} | ||
/** | ||
* Validates config values against the eik JSON schema | ||
* | ||
* @return {void} | ||
*/ | ||
validate() { | ||
schemas.assert.eikJSON(this[_config]); | ||
} | ||
/** | ||
* Resolves file locations on disk based on values defined in files property | ||
* of config object. | ||
* | ||
* @returns {Promise<FileMapping[]>} | ||
*/ | ||
async mappings() { | ||
const normalizedFiles = normalizeFilesDefinition(this.files); | ||
const resolvedFiles = await resolveFiles(normalizedFiles, this.cwd); | ||
/** | ||
* Resolves file locations on disk based on values defined in files property | ||
* of config object. | ||
* | ||
* @returns {Promise<FileMapping[]>} | ||
*/ | ||
async mappings() { | ||
const normalizedFiles = normalizeFilesDefinition(this.files); | ||
const resolvedFiles = await resolveFiles(normalizedFiles, this.cwd); | ||
return resolvedFiles.flatMap((files) => { | ||
// @ts-ignore | ||
const { destination, source } = files; | ||
// @ts-ignore | ||
const filesArray = Array.from(files); | ||
if (filesArray.length === 0) { | ||
throw new NoFilesMatchedError(source); | ||
} | ||
return resolvedFiles.flatMap((files) => { | ||
// @ts-ignore | ||
const { destination, source } = files; | ||
// @ts-ignore | ||
const filesArray = Array.from(files); | ||
if (filesArray.length === 0) { | ||
throw new NoFilesMatchedError(source); | ||
} | ||
if (extname(destination) !== '' && filesArray.length > 1) { | ||
throw new SingleDestMultipleSourcesError(destination); | ||
} | ||
if (extname(destination) !== "" && filesArray.length > 1) { | ||
throw new SingleDestMultipleSourcesError(destination); | ||
} | ||
return filesArray.map((localFile) => { | ||
const shouldMapFilename = extname(destination); | ||
const relativePathname = shouldMapFilename | ||
? destination | ||
: ensurePosix(join(destination, localFile.relative)); | ||
const packagePathname = ensurePosix( | ||
join(typeSlug(this.type), this.name, this.version), | ||
); | ||
return filesArray.map((localFile) => { | ||
const shouldMapFilename = extname(destination); | ||
const relativePathname = shouldMapFilename | ||
? destination | ||
: ensurePosix(join(destination, localFile.relative)); | ||
const packagePathname = ensurePosix( | ||
join(typeSlug(this.type), this.name, this.version), | ||
); | ||
const remoteDestination = new RemoteFileLocation( | ||
relativePathname, | ||
packagePathname, | ||
this.server, | ||
); | ||
return new FileMapping(localFile, remoteDestination); | ||
}); | ||
}); | ||
} | ||
const remoteDestination = new RemoteFileLocation( | ||
relativePathname, | ||
packagePathname, | ||
this.server, | ||
); | ||
return new FileMapping(localFile, remoteDestination); | ||
}); | ||
}); | ||
} | ||
} |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import LocalFileLocation from './local-file-location.js'; | ||
import RemoteFileLocation from './remote-file-location.js'; | ||
import assert from "node:assert"; | ||
import LocalFileLocation from "./local-file-location.js"; | ||
import RemoteFileLocation from "./remote-file-location.js"; | ||
@@ -12,28 +12,28 @@ /** | ||
class FileMapping { | ||
/** | ||
* @param {LocalFileLocation} source | ||
* @param {RemoteFileLocation} destination | ||
*/ | ||
constructor(source, destination) { | ||
assert( | ||
source instanceof LocalFileLocation, | ||
'"source" must be an instance of LocalFileLocation', | ||
); | ||
assert( | ||
destination instanceof RemoteFileLocation, | ||
'"destination" must be an instance of RemoteFileLocation', | ||
); | ||
/** | ||
* @param {LocalFileLocation} source | ||
* @param {RemoteFileLocation} destination | ||
*/ | ||
constructor(source, destination) { | ||
assert( | ||
source instanceof LocalFileLocation, | ||
'"source" must be an instance of LocalFileLocation', | ||
); | ||
assert( | ||
destination instanceof RemoteFileLocation, | ||
'"destination" must be an instance of RemoteFileLocation', | ||
); | ||
/** | ||
* @type {LocalFileLocation} source | ||
*/ | ||
this.source = source; | ||
/** | ||
* @type {LocalFileLocation} source | ||
*/ | ||
this.source = source; | ||
/** | ||
* @type {RemoteFileLocation} destination | ||
*/ | ||
this.destination = destination; | ||
} | ||
/** | ||
* @type {RemoteFileLocation} destination | ||
*/ | ||
this.destination = destination; | ||
} | ||
} | ||
export default FileMapping; |
@@ -1,10 +0,10 @@ | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; | ||
export default class InvalidConfigError extends CustomError { | ||
/** | ||
* @param {string} msg | ||
*/ | ||
constructor(msg) { | ||
super(`Eik config object was invalid: '${msg}'`); | ||
} | ||
/** | ||
* @param {string} msg | ||
*/ | ||
constructor(msg) { | ||
super(`Eik config object was invalid: '${msg}'`); | ||
} | ||
} |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import { join, extname, isAbsolute } from 'node:path'; | ||
import assert from "node:assert"; | ||
import { join, extname, isAbsolute } from "node:path"; | ||
// @ts-ignore | ||
import mime from 'mime-types'; | ||
import { ensurePosix } from '../helpers/path-slashes.js'; | ||
import mime from "mime-types"; | ||
import { ensurePosix } from "../helpers/path-slashes.js"; | ||
@@ -14,52 +14,45 @@ /** | ||
class LocalFileLocation { | ||
/** | ||
* @param {string} path path to file on disk relative to basePath | ||
* @param {string} basePath basePath to the file's location on disk | ||
*/ | ||
constructor(path, basePath) { | ||
assert(typeof path === 'string', '"path" must be of type "string"'); | ||
assert( | ||
typeof basePath === 'string', | ||
'"basePath" must be of type "string"', | ||
); | ||
assert( | ||
!isAbsolute(path), | ||
`"path" must be a relative path, got ${path}`, | ||
); | ||
/** | ||
* @param {string} path path to file on disk relative to basePath | ||
* @param {string} basePath basePath to the file's location on disk | ||
*/ | ||
constructor(path, basePath) { | ||
assert(typeof path === "string", '"path" must be of type "string"'); | ||
assert(typeof basePath === "string", '"basePath" must be of type "string"'); | ||
assert(!isAbsolute(path), `"path" must be a relative path, got ${path}`); | ||
/** | ||
* @type {string} path to file on disk relative to this.basePath | ||
*/ | ||
this.relative = path; | ||
/** | ||
* @type {string} path to file on disk relative to this.basePath | ||
*/ | ||
this.relative = path; | ||
/** | ||
* @type {string} absolute path to root files location on disk | ||
*/ | ||
this.basePath = basePath; | ||
/** | ||
* @type {string} absolute path to root files location on disk | ||
*/ | ||
this.basePath = basePath; | ||
/** | ||
* @type {string} absolute path to file on disk, | ||
* this is a concatentation of this.basePath and this.relative | ||
*/ | ||
this.absolute = ensurePosix(join(basePath, path)); | ||
/** | ||
* @type {string} absolute path to file on disk, | ||
* this is a concatentation of this.basePath and this.relative | ||
*/ | ||
this.absolute = ensurePosix(join(basePath, path)); | ||
/** | ||
* @type {string} file extension with "." character included. (eg. ".json") | ||
*/ | ||
this.extension = extname(path); | ||
/** | ||
* @type {string} file extension with "." character included. (eg. ".json") | ||
*/ | ||
this.extension = extname(path); | ||
/** | ||
* @type {string} full content-type header value for file | ||
*/ | ||
this.contentType = | ||
mime.contentType(this.extension) || 'application/octet-stream'; | ||
/** | ||
* @type {string} full content-type header value for file | ||
*/ | ||
this.contentType = | ||
mime.contentType(this.extension) || "application/octet-stream"; | ||
/** | ||
* @type {string} mime type of file | ||
*/ | ||
this.mimeType = | ||
mime.lookup(this.extension) || 'application/octet-stream'; | ||
} | ||
/** | ||
* @type {string} mime type of file | ||
*/ | ||
this.mimeType = mime.lookup(this.extension) || "application/octet-stream"; | ||
} | ||
} | ||
export default LocalFileLocation; |
@@ -1,10 +0,10 @@ | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; | ||
export default class MissingConfigError extends CustomError { | ||
/** | ||
* @param {string} dir | ||
*/ | ||
constructor(dir) { | ||
super(`No package.json or eik.json file found in: '${dir}'`); | ||
} | ||
/** | ||
* @param {string} dir | ||
*/ | ||
constructor(dir) { | ||
super(`No package.json or eik.json file found in: '${dir}'`); | ||
} | ||
} |
@@ -1,9 +0,9 @@ | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; | ||
export default class MultipleConfigSourcesError extends CustomError { | ||
constructor() { | ||
super( | ||
`Eik configuration was defined in both in package.json and eik.json. You must specify one or the other.`, | ||
); | ||
} | ||
constructor() { | ||
super( | ||
`Eik configuration was defined in both in package.json and eik.json. You must specify one or the other.`, | ||
); | ||
} | ||
} |
@@ -1,11 +0,11 @@ | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; | ||
export default class NoFilesMatchedError extends CustomError { | ||
/** | ||
* @param {string} file | ||
*/ | ||
constructor(file) { | ||
const message = `No files found for path: '${file}'`; | ||
super(message); | ||
} | ||
/** | ||
* @param {string} file | ||
*/ | ||
constructor(file) { | ||
const message = `No files found for path: '${file}'`; | ||
super(message); | ||
} | ||
} |
@@ -1,34 +0,34 @@ | ||
import { isReadableStream } from '../stream.js'; | ||
import { isReadableStream } from "../stream.js"; | ||
const ReadFile = class ReadFile { | ||
constructor({ mimeType = '', etag = '' } = {}) { | ||
this._mimeType = mimeType; | ||
// @ts-ignore | ||
this._stream = undefined; | ||
this._etag = etag; | ||
} | ||
constructor({ mimeType = "", etag = "" } = {}) { | ||
this._mimeType = mimeType; | ||
// @ts-ignore | ||
this._stream = undefined; | ||
this._etag = etag; | ||
} | ||
get mimeType() { | ||
return this._mimeType; | ||
} | ||
get mimeType() { | ||
return this._mimeType; | ||
} | ||
set stream(value) { | ||
if (!isReadableStream(value)) | ||
throw new Error('Value is not a Readable stream'); | ||
this._stream = value; | ||
} | ||
set stream(value) { | ||
if (!isReadableStream(value)) | ||
throw new Error("Value is not a Readable stream"); | ||
this._stream = value; | ||
} | ||
// @ts-ignore | ||
get stream() { | ||
return this._stream; | ||
} | ||
// @ts-ignore | ||
get stream() { | ||
return this._stream; | ||
} | ||
get etag() { | ||
return this._etag; | ||
} | ||
get etag() { | ||
return this._etag; | ||
} | ||
get [Symbol.toStringTag]() { | ||
return 'ReadFile'; | ||
} | ||
get [Symbol.toStringTag]() { | ||
return "ReadFile"; | ||
} | ||
}; | ||
export default ReadFile; |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import { join } from 'node:path'; | ||
import assert from "node:assert"; | ||
import { join } from "node:path"; | ||
class RemoteFileLocation { | ||
/** | ||
* @param {string} filePathname pathname for file relative to package root eg. /folder/client.js | ||
* @param {string} packagePathname pathname for package root eg. /pkg/my-pack/1.0.0 | ||
* @param {string} origin server origin eg. https://server.com | ||
*/ | ||
constructor(filePathname, packagePathname, origin) { | ||
assert( | ||
typeof filePathname === 'string', | ||
'"filePathname" must be of type "string"', | ||
); | ||
assert( | ||
typeof packagePathname === 'string', | ||
'"packagePathname" must be of type "string"', | ||
); | ||
assert(typeof origin === 'string', '"origin" must be of type "string"'); | ||
/** | ||
* @param {string} filePathname pathname for file relative to package root eg. /folder/client.js | ||
* @param {string} packagePathname pathname for package root eg. /pkg/my-pack/1.0.0 | ||
* @param {string} origin server origin eg. https://server.com | ||
*/ | ||
constructor(filePathname, packagePathname, origin) { | ||
assert( | ||
typeof filePathname === "string", | ||
'"filePathname" must be of type "string"', | ||
); | ||
assert( | ||
typeof packagePathname === "string", | ||
'"packagePathname" must be of type "string"', | ||
); | ||
assert(typeof origin === "string", '"origin" must be of type "string"'); | ||
/** | ||
* @type {string} pathname to package root | ||
*/ | ||
this.packagePathname = new URL(packagePathname, origin).pathname; | ||
/** | ||
* @type {string} pathname to package root | ||
*/ | ||
this.packagePathname = new URL(packagePathname, origin).pathname; | ||
/** | ||
* @type {string} pathname to file relative to package root | ||
*/ | ||
this.filePathname = new URL(filePathname, origin).pathname; | ||
/** | ||
* @type {string} pathname to file relative to package root | ||
*/ | ||
this.filePathname = new URL(filePathname, origin).pathname; | ||
/** | ||
* @type {URL} WHATWG URL object containing the full remote URL for the file | ||
*/ | ||
this.url = new URL(join(packagePathname, filePathname), origin); | ||
} | ||
/** | ||
* @type {URL} WHATWG URL object containing the full remote URL for the file | ||
*/ | ||
this.url = new URL(join(packagePathname, filePathname), origin); | ||
} | ||
} | ||
export default RemoteFileLocation; |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import LocalFileLocation from './local-file-location.js'; | ||
import assert from "node:assert"; | ||
import LocalFileLocation from "./local-file-location.js"; | ||
import { | ||
removeLeadingSlash, | ||
removeTrailingSlash, | ||
} from '../helpers/path-slashes.js'; | ||
removeLeadingSlash, | ||
removeTrailingSlash, | ||
} from "../helpers/path-slashes.js"; | ||
const originalFiles = Symbol('files'); | ||
const originalFiles = Symbol("files"); | ||
class ResolvedFiles { | ||
/** | ||
* @param {string[]} files | ||
* @param {{definition: [string, string], basePath: string, pattern: string}} meta | ||
*/ | ||
constructor(files, meta) { | ||
assert(Array.isArray(files), '"files" must be an array'); | ||
assert(meta, '"meta" must be defined'); | ||
assert( | ||
typeof meta.basePath, | ||
'"meta.basePath" must be a non empty string', | ||
); | ||
assert( | ||
typeof meta.pattern, | ||
'"meta.pattern" must be a non empty string', | ||
); | ||
assert( | ||
Array.isArray(meta.definition), | ||
'"meta.definition" must be an array', | ||
); | ||
assert( | ||
meta.definition.length === 2, | ||
'"meta.definition" must be an array of length 2', | ||
); | ||
/** | ||
* @param {string[]} files | ||
* @param {{definition: [string, string], basePath: string, pattern: string}} meta | ||
*/ | ||
constructor(files, meta) { | ||
assert(Array.isArray(files), '"files" must be an array'); | ||
assert(meta, '"meta" must be defined'); | ||
assert(typeof meta.basePath, '"meta.basePath" must be a non empty string'); | ||
assert(typeof meta.pattern, '"meta.pattern" must be a non empty string'); | ||
assert( | ||
Array.isArray(meta.definition), | ||
'"meta.definition" must be an array', | ||
); | ||
assert( | ||
meta.definition.length === 2, | ||
'"meta.definition" must be an array of length 2', | ||
); | ||
const [destination, source] = meta.definition; | ||
this[originalFiles] = files; | ||
this.destination = destination; | ||
this.source = source; | ||
this.basePath = meta.basePath; | ||
this.pattern = meta.pattern; | ||
} | ||
const [destination, source] = meta.definition; | ||
this[originalFiles] = files; | ||
this.destination = destination; | ||
this.source = source; | ||
this.basePath = meta.basePath; | ||
this.pattern = meta.pattern; | ||
} | ||
*[Symbol.iterator]() { | ||
for (const file of this[originalFiles]) { | ||
const relative = removeTrailingSlash( | ||
removeLeadingSlash( | ||
file.replace(/\\/g, '/').replace(this.basePath, ''), | ||
), | ||
); | ||
yield new LocalFileLocation(relative, this.basePath); | ||
} | ||
} | ||
*[Symbol.iterator]() { | ||
for (const file of this[originalFiles]) { | ||
const relative = removeTrailingSlash( | ||
removeLeadingSlash(file.replace(/\\/g, "/").replace(this.basePath, "")), | ||
); | ||
yield new LocalFileLocation(relative, this.basePath); | ||
} | ||
} | ||
} | ||
export default ResolvedFiles; |
@@ -1,12 +0,12 @@ | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; | ||
export default class SingleDestMultipleSourcesError extends CustomError { | ||
/** | ||
* @param {string} destFilePath | ||
*/ | ||
constructor(destFilePath) { | ||
super( | ||
`Cannot specify a single file destination for multiple source files. See '${destFilePath}'`, | ||
); | ||
} | ||
/** | ||
* @param {string} destFilePath | ||
*/ | ||
constructor(destFilePath) { | ||
super( | ||
`Cannot specify a single file destination for multiple source files. See '${destFilePath}'`, | ||
); | ||
} | ||
} |
@@ -1,8 +0,8 @@ | ||
import { readFileSync, writeFileSync } from 'node:fs'; | ||
import { join, dirname } from 'node:path'; | ||
import os from 'node:os'; | ||
import EikConfig from '../classes/eik-config.js'; | ||
import MissingConfigError from '../classes/missing-config-error.js'; | ||
import MultipleConfigSourcesError from '../classes/multiple-config-sources-error.js'; | ||
import InvalidConfigError from '../classes/invalid-config-error.js'; | ||
import { readFileSync, writeFileSync } from "node:fs"; | ||
import { join, dirname } from "node:path"; | ||
import os from "node:os"; | ||
import EikConfig from "../classes/eik-config.js"; | ||
import MissingConfigError from "../classes/missing-config-error.js"; | ||
import MultipleConfigSourcesError from "../classes/multiple-config-sources-error.js"; | ||
import InvalidConfigError from "../classes/invalid-config-error.js"; | ||
@@ -19,102 +19,102 @@ const homedir = os.homedir(); | ||
function readJSONFromDisk(path) { | ||
let fileData; | ||
try { | ||
fileData = readFileSync(path, { encoding: 'utf8' }); | ||
// eslint-disable-next-line no-unused-vars | ||
} catch (e) { | ||
// @ts-ignore | ||
return null; | ||
} | ||
return JSON.parse(fileData); | ||
let fileData; | ||
try { | ||
fileData = readFileSync(path, { encoding: "utf8" }); | ||
// eslint-disable-next-line no-unused-vars | ||
} catch (e) { | ||
// @ts-ignore | ||
return null; | ||
} | ||
return JSON.parse(fileData); | ||
} | ||
export default { | ||
/** | ||
* Load the configuration from an exact path and return an EikConfig object | ||
* | ||
* @param {string} configFilePathname | ||
* @param {function} loadJSONFromDisk | ||
* | ||
* @returns {EikConfig} | ||
*/ | ||
loadFromPath(configFilePathname, loadJSONFromDisk = readJSONFromDisk) { | ||
const eikJSON = loadJSONFromDisk(configFilePathname); | ||
if (!eikJSON) { | ||
throw new MissingConfigError(dirname(configFilePathname)); | ||
} | ||
let assets = eikJSON; | ||
// detect package.json | ||
if (eikJSON.eik) { | ||
assets = { | ||
name: eikJSON.name, | ||
version: eikJSON.version, | ||
...eikJSON.eik, | ||
}; | ||
} | ||
const eikrc = loadJSONFromDisk(join(homedir, '.eikrc')) || {}; | ||
return new EikConfig(assets, eikrc.tokens, dirname(configFilePathname)); | ||
}, | ||
/** | ||
* Tries to find the configuration for eik in the provided directory. | ||
* | ||
* @param {string} configRootDir The base directory for the eik project. | ||
* @param {function} [loadJSONFromDisk] The function to use to load the file from disk. | ||
* | ||
* @returns {EikConfig} | ||
*/ | ||
findInDirectory(configRootDir, loadJSONFromDisk = readJSONFromDisk) { | ||
const pkgJSON = loadJSONFromDisk(join(configRootDir, 'package.json')); | ||
const eikJSON = loadJSONFromDisk(join(configRootDir, 'eik.json')); | ||
if ( | ||
pkgJSON != null && | ||
Object.prototype.hasOwnProperty.call(pkgJSON, 'eik') && | ||
eikJSON != null | ||
) { | ||
throw new MultipleConfigSourcesError(); | ||
} | ||
let assets; | ||
if (pkgJSON) { | ||
const { name, version, eik } = pkgJSON; | ||
if (eik) { | ||
assets = { name, version, ...pkgJSON.eik }; | ||
} | ||
} | ||
if (eikJSON) { | ||
assets = { ...assets, ...eikJSON }; | ||
} | ||
if (assets == null) { | ||
throw new MissingConfigError(configRootDir); | ||
} | ||
const eikrc = loadJSONFromDisk(join(homedir, '.eikrc')) || {}; | ||
const config = new EikConfig(assets, eikrc.tokens, configRootDir); | ||
try { | ||
config.validate(); | ||
} catch (err) { | ||
throw new InvalidConfigError( | ||
// @ts-ignore | ||
`config.findInDirectory operation failed: ${err.message}`, | ||
); | ||
} | ||
return config; | ||
}, | ||
/** | ||
* Load the configuration from an exact path and return an EikConfig object | ||
* | ||
* @param {string} configFilePathname | ||
* @param {function} loadJSONFromDisk | ||
* | ||
* @returns {EikConfig} | ||
*/ | ||
loadFromPath(configFilePathname, loadJSONFromDisk = readJSONFromDisk) { | ||
const eikJSON = loadJSONFromDisk(configFilePathname); | ||
if (!eikJSON) { | ||
throw new MissingConfigError(dirname(configFilePathname)); | ||
} | ||
let assets = eikJSON; | ||
// detect package.json | ||
if (eikJSON.eik) { | ||
assets = { | ||
name: eikJSON.name, | ||
version: eikJSON.version, | ||
...eikJSON.eik, | ||
}; | ||
} | ||
const eikrc = loadJSONFromDisk(join(homedir, ".eikrc")) || {}; | ||
return new EikConfig(assets, eikrc.tokens, dirname(configFilePathname)); | ||
}, | ||
/** | ||
* Tries to find the configuration for eik in the provided directory. | ||
* | ||
* @param {string} configRootDir The base directory for the eik project. | ||
* @param {function} [loadJSONFromDisk] The function to use to load the file from disk. | ||
* | ||
* @returns {EikConfig} | ||
*/ | ||
findInDirectory(configRootDir, loadJSONFromDisk = readJSONFromDisk) { | ||
const pkgJSON = loadJSONFromDisk(join(configRootDir, "package.json")); | ||
const eikJSON = loadJSONFromDisk(join(configRootDir, "eik.json")); | ||
if ( | ||
pkgJSON != null && | ||
Object.prototype.hasOwnProperty.call(pkgJSON, "eik") && | ||
eikJSON != null | ||
) { | ||
throw new MultipleConfigSourcesError(); | ||
} | ||
let assets; | ||
if (pkgJSON) { | ||
const { name, version, eik } = pkgJSON; | ||
if (eik) { | ||
assets = { name, version, ...pkgJSON.eik }; | ||
} | ||
} | ||
if (eikJSON) { | ||
assets = { ...assets, ...eikJSON }; | ||
} | ||
if (assets == null) { | ||
throw new MissingConfigError(configRootDir); | ||
} | ||
const eikrc = loadJSONFromDisk(join(homedir, ".eikrc")) || {}; | ||
const config = new EikConfig(assets, eikrc.tokens, configRootDir); | ||
try { | ||
config.validate(); | ||
} catch (err) { | ||
throw new InvalidConfigError( | ||
// @ts-ignore | ||
`config.findInDirectory operation failed: ${err.message}`, | ||
); | ||
} | ||
return config; | ||
}, | ||
/** | ||
* Persist config changes to disk as <cwd>/eik.json | ||
* | ||
* @param {import('../classes/eik-config.js')} config | ||
*/ | ||
persistToDisk(config) { | ||
try { | ||
// @ts-ignore | ||
config.validate(); | ||
} catch (err) { | ||
throw new InvalidConfigError( | ||
// @ts-ignore | ||
`config.persistToDisk operation failed: ${err.message}`, | ||
); | ||
} | ||
// @ts-ignore | ||
const dest = join(config.cwd, 'eik.json'); | ||
writeFileSync(dest, JSON.stringify(config, null, 2)); | ||
}, | ||
/** | ||
* Persist config changes to disk as <cwd>/eik.json | ||
* | ||
* @param {import('../classes/eik-config.js')} config | ||
*/ | ||
persistToDisk(config) { | ||
try { | ||
// @ts-ignore | ||
config.validate(); | ||
} catch (err) { | ||
throw new InvalidConfigError( | ||
// @ts-ignore | ||
`config.persistToDisk operation failed: ${err.message}`, | ||
); | ||
} | ||
// @ts-ignore | ||
const dest = join(config.cwd, "eik.json"); | ||
writeFileSync(dest, JSON.stringify(config, null, 2)); | ||
}, | ||
}; |
@@ -1,5 +0,5 @@ | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import configStore from './config-store.js'; | ||
import EikConfig from '../classes/eik-config.js'; | ||
import fs from "node:fs"; | ||
import path from "node:path"; | ||
import configStore from "./config-store.js"; | ||
import EikConfig from "../classes/eik-config.js"; | ||
/** | ||
@@ -14,22 +14,22 @@ * Sets up and returns an object containing a set of default values for the app context. | ||
export default function getDefaults(directoryOrFilepath) { | ||
try { | ||
const stats = fs.statSync(directoryOrFilepath); | ||
if (stats.isDirectory()) { | ||
return configStore.findInDirectory(directoryOrFilepath); | ||
} else { | ||
return configStore.loadFromPath(directoryOrFilepath); | ||
} | ||
} catch (error) { | ||
const e = /** @type {Error} */ (error); | ||
if (e.constructor.name === 'MissingConfigError') { | ||
// assume directory | ||
let cwd = directoryOrFilepath; | ||
// detect exact file and get its directory | ||
if (path.extname(directoryOrFilepath)) { | ||
cwd = path.dirname(directoryOrFilepath); | ||
} | ||
return new EikConfig(null, [], cwd); | ||
} | ||
throw e; | ||
} | ||
try { | ||
const stats = fs.statSync(directoryOrFilepath); | ||
if (stats.isDirectory()) { | ||
return configStore.findInDirectory(directoryOrFilepath); | ||
} else { | ||
return configStore.loadFromPath(directoryOrFilepath); | ||
} | ||
} catch (error) { | ||
const e = /** @type {Error} */ (error); | ||
if (e.constructor.name === "MissingConfigError") { | ||
// assume directory | ||
let cwd = directoryOrFilepath; | ||
// detect exact file and get its directory | ||
if (path.extname(directoryOrFilepath)) { | ||
cwd = path.dirname(directoryOrFilepath); | ||
} | ||
return new EikConfig(null, [], cwd); | ||
} | ||
throw e; | ||
} | ||
} |
@@ -1,25 +0,25 @@ | ||
import localAssets from './local-assets.js'; | ||
import getDefaults from './get-defaults.js'; | ||
import configStore from './config-store.js'; | ||
import typeSlug from './type-slug.js'; | ||
import typeTitle from './type-title.js'; | ||
import resolveFiles from './resolve-files.js'; | ||
import localAssets from "./local-assets.js"; | ||
import getDefaults from "./get-defaults.js"; | ||
import configStore from "./config-store.js"; | ||
import typeSlug from "./type-slug.js"; | ||
import typeTitle from "./type-title.js"; | ||
import resolveFiles from "./resolve-files.js"; | ||
import { | ||
addTrailingSlash, | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
} from './path-slashes.js'; | ||
addTrailingSlash, | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
} from "./path-slashes.js"; | ||
export default { | ||
localAssets, | ||
getDefaults, | ||
configStore, | ||
typeSlug, | ||
typeTitle, | ||
addTrailingSlash, | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
resolveFiles, | ||
localAssets, | ||
getDefaults, | ||
configStore, | ||
typeSlug, | ||
typeTitle, | ||
addTrailingSlash, | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
resolveFiles, | ||
}; |
/** | ||
* @type {(value: unknown, message?: string) => asserts value} | ||
*/ | ||
import assert from 'node:assert'; | ||
import fs from 'node:fs'; | ||
import configStore from './config-store.js'; | ||
import assert from "node:assert"; | ||
import fs from "node:fs"; | ||
import configStore from "./config-store.js"; | ||
@@ -15,50 +15,50 @@ /** | ||
async function localAssets(app, rootEikDirectory = process.cwd()) { | ||
assert( | ||
// @ts-ignore | ||
app.decorateReply || app.name === 'app' || app.route, | ||
'App must be an Express, Fastify or Hapi app instance', | ||
); | ||
assert( | ||
typeof rootEikDirectory === 'string' && rootEikDirectory, | ||
'Path to folder for eik config must be provided and must be of type string', | ||
); | ||
// ensure eik.json only loaded 1x | ||
const eik = configStore.findInDirectory(rootEikDirectory); | ||
assert( | ||
// @ts-ignore | ||
app.decorateReply || app.name === "app" || app.route, | ||
"App must be an Express, Fastify or Hapi app instance", | ||
); | ||
assert( | ||
typeof rootEikDirectory === "string" && rootEikDirectory, | ||
"Path to folder for eik config must be provided and must be of type string", | ||
); | ||
// ensure eik.json only loaded 1x | ||
const eik = configStore.findInDirectory(rootEikDirectory); | ||
(await eik.mappings()).forEach((mapping) => { | ||
const { pathname } = mapping.destination.url; | ||
const { contentType, absolute: path } = mapping.source; | ||
// @ts-ignore | ||
if (app.get) { | ||
// @ts-ignore | ||
app.get(pathname, (req, res) => { | ||
if (res.set) { | ||
// express | ||
res.set('Access-Control-Allow-Origin', '*'); | ||
res.set('content-type', contentType); | ||
fs.createReadStream(path).pipe(res); | ||
} else if (res.type) { | ||
// fastify | ||
res.header('Access-Control-Allow-Origin', '*'); | ||
res.type(contentType); | ||
res.send(fs.createReadStream(path)); | ||
} | ||
}); | ||
} else { | ||
// hapi | ||
// @ts-ignore | ||
app.route({ | ||
method: 'GET', | ||
path: pathname, | ||
// @ts-ignore | ||
handler(req, h) { | ||
return h | ||
.response(fs.createReadStream(path)) | ||
.header('Access-Control-Allow-Origin', '*') | ||
.type(contentType); | ||
}, | ||
}); | ||
} | ||
}); | ||
(await eik.mappings()).forEach((mapping) => { | ||
const { pathname } = mapping.destination.url; | ||
const { contentType, absolute: path } = mapping.source; | ||
// @ts-ignore | ||
if (app.get) { | ||
// @ts-ignore | ||
app.get(pathname, (req, res) => { | ||
if (res.set) { | ||
// express | ||
res.set("Access-Control-Allow-Origin", "*"); | ||
res.set("content-type", contentType); | ||
fs.createReadStream(path).pipe(res); | ||
} else if (res.type) { | ||
// fastify | ||
res.header("Access-Control-Allow-Origin", "*"); | ||
res.type(contentType); | ||
res.send(fs.createReadStream(path)); | ||
} | ||
}); | ||
} else { | ||
// hapi | ||
// @ts-ignore | ||
app.route({ | ||
method: "GET", | ||
path: pathname, | ||
// @ts-ignore | ||
handler(req, h) { | ||
return h | ||
.response(fs.createReadStream(path)) | ||
.header("Access-Control-Allow-Origin", "*") | ||
.type(contentType); | ||
}, | ||
}); | ||
} | ||
}); | ||
} | ||
export default localAssets; |
@@ -1,3 +0,3 @@ | ||
import { sep } from 'path'; | ||
import { platform } from 'os'; | ||
import { sep } from "path"; | ||
import { platform } from "os"; | ||
@@ -11,3 +11,3 @@ /** | ||
*/ | ||
export const addTrailingSlash = (val) => (val.endsWith('/') ? val : `${val}/`); | ||
export const addTrailingSlash = (val) => (val.endsWith("/") ? val : `${val}/`); | ||
@@ -22,6 +22,4 @@ /** | ||
export const removeTrailingSlash = (val) => | ||
// this is also used to trim from config files, which may now always use the OS's sep value. Look for both. | ||
val.endsWith('/') || val.endsWith('\\') | ||
? val.substr(0, val.length - 1) | ||
: val; | ||
// this is also used to trim from config files, which may now always use the OS's sep value. Look for both. | ||
val.endsWith("/") || val.endsWith("\\") ? val.substr(0, val.length - 1) : val; | ||
@@ -36,3 +34,3 @@ /** | ||
export const addLeadingSlash = (val) => | ||
val.startsWith('/') || platform() === 'win32' ? val : `/${val}`; | ||
val.startsWith("/") || platform() === "win32" ? val : `/${val}`; | ||
@@ -47,3 +45,3 @@ /** | ||
export const removeLeadingSlash = (val) => | ||
val.startsWith('/') || val.startsWith('\\') ? val.substr(1) : val; | ||
val.startsWith("/") || val.startsWith("\\") ? val.substr(1) : val; | ||
@@ -62,2 +60,2 @@ /** | ||
*/ | ||
export const ensurePosix = (val) => val.replace(/\\/g, '/'); | ||
export const ensurePosix = (val) => val.replace(/\\/g, "/"); |
@@ -1,12 +0,12 @@ | ||
import { extname, join, isAbsolute, basename, sep, normalize } from 'node:path'; | ||
import isGlob from 'is-glob'; | ||
import { glob } from 'glob'; | ||
import { extname, join, isAbsolute, basename, sep, normalize } from "node:path"; | ||
import isGlob from "is-glob"; | ||
import { glob } from "glob"; | ||
import { | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
ensureOsSep, | ||
ensurePosix, | ||
} from './path-slashes.js'; | ||
import ResolvedFiles from '../classes/resolved-files.js'; | ||
removeTrailingSlash, | ||
addLeadingSlash, | ||
removeLeadingSlash, | ||
ensureOsSep, | ||
ensurePosix, | ||
} from "./path-slashes.js"; | ||
import ResolvedFiles from "../classes/resolved-files.js"; | ||
@@ -20,12 +20,12 @@ /** | ||
const pathUntilGlob = (path) => { | ||
const segments = (path || '').split(sep); | ||
const segmentsToKeep = []; | ||
for (const segment of segments) { | ||
if (segment === '.') continue; | ||
if (segment === '') continue; | ||
if (isGlob(segment)) break; | ||
segmentsToKeep.push(segment); | ||
} | ||
const segments = (path || "").split(sep); | ||
const segmentsToKeep = []; | ||
for (const segment of segments) { | ||
if (segment === ".") continue; | ||
if (segment === "") continue; | ||
if (isGlob(segment)) break; | ||
segmentsToKeep.push(segment); | ||
} | ||
return addLeadingSlash(normalize(segmentsToKeep.join(sep))); | ||
return addLeadingSlash(normalize(segmentsToKeep.join(sep))); | ||
}; | ||
@@ -42,58 +42,53 @@ | ||
const resolveFiles = async (files, cwd) => | ||
Promise.all( | ||
Object.entries(files).map(async (definition) => { | ||
let [, source] = definition; | ||
Promise.all( | ||
Object.entries(files).map(async (definition) => { | ||
let [, source] = definition; | ||
// The config may not always match the OS's separator. | ||
// Convert the input to OS-specific if necessary. | ||
// We convert back to always using forward slashes for glob, | ||
// but for calculating the paths relative to cwd we'd like | ||
// these to be OS-specific for now. | ||
source = ensureOsSep(source); | ||
// The config may not always match the OS's separator. | ||
// Convert the input to OS-specific if necessary. | ||
// We convert back to always using forward slashes for glob, | ||
// but for calculating the paths relative to cwd we'd like | ||
// these to be OS-specific for now. | ||
source = ensureOsSep(source); | ||
// normalise to absolute path | ||
let pattern = isAbsolute(source) ? source : join(cwd, source); | ||
// normalise to absolute path | ||
let pattern = isAbsolute(source) ? source : join(cwd, source); | ||
// append glob if folder | ||
if ( | ||
extname(pattern) === '' && | ||
isGlob(ensurePosix(pattern)) === false | ||
) { | ||
pattern = `${pattern}${sep}**${sep}*`; | ||
} | ||
// append glob if folder | ||
if (extname(pattern) === "" && isGlob(ensurePosix(pattern)) === false) { | ||
pattern = `${pattern}${sep}**${sep}*`; | ||
} | ||
// trim off any glob | ||
let basePath = pathUntilGlob(pattern); | ||
// trim off any glob | ||
let basePath = pathUntilGlob(pattern); | ||
// fix basePath if file | ||
if (extname(pattern) !== '') { | ||
basePath = removeTrailingSlash( | ||
basePath.replace(basename(pattern), ''), | ||
); | ||
} | ||
// fix basePath if file | ||
if (extname(pattern) !== "") { | ||
basePath = removeTrailingSlash(basePath.replace(basename(pattern), "")); | ||
} | ||
// convert glob pattern to forward slash separators | ||
// https://www.npmjs.com/package/glob#windows | ||
basePath = ensurePosix(basePath); | ||
pattern = ensurePosix(pattern); | ||
// convert glob pattern to forward slash separators | ||
// https://www.npmjs.com/package/glob#windows | ||
basePath = ensurePosix(basePath); | ||
pattern = ensurePosix(pattern); | ||
// process glob pattern into a list of existing files | ||
const resolvedFiles = await glob(pattern, { | ||
cwd: basePath, | ||
nodir: true, | ||
}); | ||
// process glob pattern into a list of existing files | ||
const resolvedFiles = await glob(pattern, { | ||
cwd: basePath, | ||
nodir: true, | ||
}); | ||
// trim off the basePath to create a relative pathed pattern | ||
pattern = removeTrailingSlash( | ||
removeLeadingSlash(pattern.replace(basePath, '')), | ||
); | ||
// trim off the basePath to create a relative pathed pattern | ||
pattern = removeTrailingSlash( | ||
removeLeadingSlash(pattern.replace(basePath, "")), | ||
); | ||
return new ResolvedFiles(resolvedFiles, { | ||
definition, | ||
basePath, | ||
pattern, | ||
}); | ||
}), | ||
); | ||
return new ResolvedFiles(resolvedFiles, { | ||
definition, | ||
basePath, | ||
pattern, | ||
}); | ||
}), | ||
); | ||
export default resolveFiles; |
@@ -8,5 +8,5 @@ /** | ||
export default (type) => { | ||
if (type === 'package') return 'pkg'; | ||
if (type === 'image') return 'img'; | ||
return type; | ||
if (type === "package") return "pkg"; | ||
if (type === "image") return "img"; | ||
return type; | ||
}; |
@@ -7,6 +7,6 @@ /** | ||
export default (type) => { | ||
if (type === 'package') return 'PACKAGE'; | ||
if (type === 'npm') return 'NPM'; | ||
if (type === 'image') return 'IMAGE'; | ||
return 'MAP'; | ||
if (type === "package") return "PACKAGE"; | ||
if (type === "npm") return "NPM"; | ||
if (type === "image") return "IMAGE"; | ||
return "MAP"; | ||
}; |
@@ -1,16 +0,16 @@ | ||
import * as validators from './validators/index.js'; | ||
import ReadFile from './classes/read-file.js'; | ||
import EikConfig from './classes/eik-config.js'; | ||
import schemas from './schemas/index.js'; | ||
import * as stream from './stream.js'; | ||
import helpers from './helpers/index.js'; | ||
import * as validators from "./validators/index.js"; | ||
import ReadFile from "./classes/read-file.js"; | ||
import EikConfig from "./classes/eik-config.js"; | ||
import schemas from "./schemas/index.js"; | ||
import * as stream from "./stream.js"; | ||
import helpers from "./helpers/index.js"; | ||
export default { | ||
validators, | ||
ReadFile, | ||
EikConfig, | ||
schemas, | ||
stream, | ||
helpers, | ||
validators, | ||
ReadFile, | ||
EikConfig, | ||
schemas, | ||
stream, | ||
helpers, | ||
}; | ||
export { validators, ReadFile, EikConfig, schemas, stream, helpers }; |
import { | ||
eikJSON, | ||
name, | ||
version, | ||
type, | ||
server, | ||
files, | ||
importMap, | ||
out, | ||
} from './validate.js'; | ||
import ValidationError from './validation-error.js'; | ||
eikJSON, | ||
name, | ||
version, | ||
type, | ||
server, | ||
files, | ||
importMap, | ||
out, | ||
} from "./validate.js"; | ||
import ValidationError from "./validation-error.js"; | ||
@@ -28,36 +28,36 @@ /** | ||
const assert = (validate, message) => (value) => { | ||
const valid = validate(value); | ||
if (valid.error) { | ||
const errorMessage = valid.error | ||
// @ts-ignore | ||
.map((err) => { | ||
let msg = err.message; | ||
if (err.params && err.params.allowedValues) { | ||
msg += ` ("${err.params.allowedValues.join('", "')}")`; | ||
} | ||
return msg; | ||
}) | ||
.join(','); | ||
// @ts-expect-error Maybe some toString magic happens here? | ||
throw new ValidationError(`${message}: ${errorMessage}`, valid.error); | ||
} | ||
const valid = validate(value); | ||
if (valid.error) { | ||
const errorMessage = valid.error | ||
// @ts-ignore | ||
.map((err) => { | ||
let msg = err.message; | ||
if (err.params && err.params.allowedValues) { | ||
msg += ` ("${err.params.allowedValues.join('", "')}")`; | ||
} | ||
return msg; | ||
}) | ||
.join(","); | ||
// @ts-expect-error Maybe some toString magic happens here? | ||
throw new ValidationError(`${message}: ${errorMessage}`, valid.error); | ||
} | ||
}; | ||
export default { | ||
/** Asserts the given [eik.json](https://eik.dev/docs/reference/eik-json) includes required fields that are valid */ | ||
eikJSON: assert(eikJSON, 'Invalid eik.json schema'), | ||
/** Asserts the given [name](https://eik.dev/docs/reference/eik-json#name) value is valid*/ | ||
name: assert(name, 'Parameter "name" is not valid'), | ||
/** Asserts the given [type](https://eik.dev/docs/reference/eik-json#type) value is valid*/ | ||
type: assert(type, 'Parameter "type" is not valid'), | ||
/** Asserts the given [version](https://eik.dev/docs/reference/eik-json#version) value is valid*/ | ||
version: assert(version, 'Parameter "version" is not valid'), | ||
/** Asserts the given [server](https://eik.dev/docs/reference/eik-json#server) value is valid*/ | ||
server: assert(server, 'Parameter "server" is not valid'), | ||
/** Asserts the given [files](https://eik.dev/docs/reference/eik-json#files) value is valid */ | ||
files: assert(files, 'Parameter "files" is not valid'), | ||
/** Asserts the given [import-map](https://eik.dev/docs/reference/eik-json#import-map) value is valid */ | ||
importMap: assert(importMap, 'Parameter "import-map" is not valid'), | ||
/** Asserts the given [out](https://eik.dev/docs/reference/eik-json#out) value is valid */ | ||
out: assert(out, 'Parameter "out" is not valid'), | ||
/** Asserts the given [eik.json](https://eik.dev/docs/reference/eik-json) includes required fields that are valid */ | ||
eikJSON: assert(eikJSON, "Invalid eik.json schema"), | ||
/** Asserts the given [name](https://eik.dev/docs/reference/eik-json#name) value is valid*/ | ||
name: assert(name, 'Parameter "name" is not valid'), | ||
/** Asserts the given [type](https://eik.dev/docs/reference/eik-json#type) value is valid*/ | ||
type: assert(type, 'Parameter "type" is not valid'), | ||
/** Asserts the given [version](https://eik.dev/docs/reference/eik-json#version) value is valid*/ | ||
version: assert(version, 'Parameter "version" is not valid'), | ||
/** Asserts the given [server](https://eik.dev/docs/reference/eik-json#server) value is valid*/ | ||
server: assert(server, 'Parameter "server" is not valid'), | ||
/** Asserts the given [files](https://eik.dev/docs/reference/eik-json#files) value is valid */ | ||
files: assert(files, 'Parameter "files" is not valid'), | ||
/** Asserts the given [import-map](https://eik.dev/docs/reference/eik-json#import-map) value is valid */ | ||
importMap: assert(importMap, 'Parameter "import-map" is not valid'), | ||
/** Asserts the given [out](https://eik.dev/docs/reference/eik-json#out) value is valid */ | ||
out: assert(out, 'Parameter "out" is not valid'), | ||
}; |
@@ -1,7 +0,7 @@ | ||
import { readFileSync } from 'node:fs'; | ||
import { join, dirname } from 'node:path'; | ||
import * as validate from './validate.js'; | ||
import assert from './assert.js'; | ||
import ValidationError from './validation-error.js'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { readFileSync } from "node:fs"; | ||
import { join, dirname } from "node:path"; | ||
import * as validate from "./validate.js"; | ||
import assert from "./assert.js"; | ||
import ValidationError from "./validation-error.js"; | ||
import { fileURLToPath } from "node:url"; | ||
@@ -12,5 +12,5 @@ const __filename = fileURLToPath(import.meta.url); | ||
const schema = JSON.parse( | ||
readFileSync(join(__dirname, './eikjson.schema.json'), 'utf8'), | ||
readFileSync(join(__dirname, "./eikjson.schema.json"), "utf8"), | ||
); | ||
export default { schema, validate, assert, ValidationError }; |
@@ -1,8 +0,8 @@ | ||
import { readFileSync } from 'node:fs'; | ||
import { join, dirname } from 'node:path'; | ||
import formats from 'ajv-formats'; | ||
import semver from 'semver'; | ||
import npmPkg from 'validate-npm-package-name'; | ||
import Ajv from 'ajv'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { readFileSync } from "node:fs"; | ||
import { join, dirname } from "node:path"; | ||
import formats from "ajv-formats"; | ||
import semver from "semver"; | ||
import npmPkg from "validate-npm-package-name"; | ||
import Ajv from "ajv"; | ||
import { fileURLToPath } from "node:url"; | ||
@@ -13,3 +13,3 @@ const __filename = fileURLToPath(import.meta.url); | ||
const eikJSONSchema = JSON.parse( | ||
readFileSync(join(__dirname, './eikjson.schema.json'), 'utf8'), | ||
readFileSync(join(__dirname, "./eikjson.schema.json"), "utf8"), | ||
); | ||
@@ -36,13 +36,13 @@ | ||
const createValidator = (schema, ajvOptions) => { | ||
// @ts-ignore | ||
const ajv = new Ajv(ajvOptions); | ||
// @ts-ignore | ||
formats(ajv); // Needed to support "uri" | ||
const validate = ajv.compile(schema); | ||
// @ts-ignore | ||
const ajv = new Ajv(ajvOptions); | ||
// @ts-ignore | ||
formats(ajv); // Needed to support "uri" | ||
const validate = ajv.compile(schema); | ||
return (data) => { | ||
const cloned = JSON.parse(JSON.stringify(data)); | ||
const valid = validate(cloned); | ||
return { value: cloned, error: !valid && validate.errors }; | ||
}; | ||
return (data) => { | ||
const cloned = JSON.parse(JSON.stringify(data)); | ||
const valid = validate(cloned); | ||
return { value: cloned, error: !valid && validate.errors }; | ||
}; | ||
}; | ||
@@ -55,4 +55,4 @@ | ||
const eikJSON = createValidator(eikJSONSchema, { | ||
removeAdditional: true, | ||
useDefaults: true, | ||
removeAdditional: true, | ||
useDefaults: true, | ||
}); | ||
@@ -65,22 +65,22 @@ | ||
const createNameValidator = (jsonSchemaValidator) => (value) => { | ||
const result = jsonSchemaValidator(value); | ||
if (!result.error) { | ||
const pkvalid = npmPkg(value); | ||
/** @type {ErrorObject[]} */ | ||
const errors = []; | ||
if (!pkvalid.validForNewPackages) { | ||
errors.push({ | ||
keyword: 'validForNewPackages', | ||
instancePath: '.name', | ||
dataPath: '.name', // this was here before, but maybe replaced by instancePath? | ||
schemaPath: '', | ||
params: [], | ||
message: 'should be valid package name', | ||
}); | ||
} | ||
if (errors.length) { | ||
result.error = errors; | ||
} | ||
} | ||
return result; | ||
const result = jsonSchemaValidator(value); | ||
if (!result.error) { | ||
const pkvalid = npmPkg(value); | ||
/** @type {ErrorObject[]} */ | ||
const errors = []; | ||
if (!pkvalid.validForNewPackages) { | ||
errors.push({ | ||
keyword: "validForNewPackages", | ||
instancePath: ".name", | ||
dataPath: ".name", // this was here before, but maybe replaced by instancePath? | ||
schemaPath: "", | ||
params: [], | ||
message: "should be valid package name", | ||
}); | ||
} | ||
if (errors.length) { | ||
result.error = errors; | ||
} | ||
} | ||
return result; | ||
}; | ||
@@ -93,22 +93,22 @@ | ||
const createVersionValidator = (jsonSchemaValidator) => (value) => { | ||
const result = jsonSchemaValidator(value); | ||
if (!result.error) { | ||
const version = semver.valid(value); | ||
/** @type {ErrorObject[]} */ | ||
const errors = []; | ||
if (!version) { | ||
errors.push({ | ||
keyword: 'invalidSemverRange', | ||
instancePath: '.version', | ||
dataPath: '.version', | ||
schemaPath: '', | ||
params: [], | ||
message: 'should be valid semver range for version', | ||
}); | ||
} | ||
if (errors.length) { | ||
result.error = errors; | ||
} | ||
} | ||
return result; | ||
const result = jsonSchemaValidator(value); | ||
if (!result.error) { | ||
const version = semver.valid(value); | ||
/** @type {ErrorObject[]} */ | ||
const errors = []; | ||
if (!version) { | ||
errors.push({ | ||
keyword: "invalidSemverRange", | ||
instancePath: ".version", | ||
dataPath: ".version", | ||
schemaPath: "", | ||
params: [], | ||
message: "should be valid semver range for version", | ||
}); | ||
} | ||
if (errors.length) { | ||
result.error = errors; | ||
} | ||
} | ||
return result; | ||
}; | ||
@@ -121,3 +121,3 @@ | ||
const name = createNameValidator( | ||
createValidator(eikJSONSchema.properties.name), | ||
createValidator(eikJSONSchema.properties.name), | ||
); | ||
@@ -130,3 +130,3 @@ | ||
const version = createVersionValidator( | ||
createValidator(eikJSONSchema.properties.version), | ||
createValidator(eikJSONSchema.properties.version), | ||
); | ||
@@ -156,3 +156,3 @@ | ||
*/ | ||
const importMap = createValidator(eikJSONSchema.properties['import-map']); | ||
const importMap = createValidator(eikJSONSchema.properties["import-map"]); | ||
@@ -159,0 +159,0 @@ /** |
// @ts-check | ||
class ValidationError extends Error { | ||
/** | ||
* @param {string} message | ||
* @param {Error} err | ||
*/ | ||
constructor(message, err) { | ||
let m = message; | ||
if (err && err.message) m += `: ${err.message}`; | ||
super(m); | ||
this.name = this.constructor.name; | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
/** | ||
* @param {string} message | ||
* @param {Error} err | ||
*/ | ||
constructor(message, err) { | ||
let m = message; | ||
if (err && err.message) m += `: ${err.message}`; | ||
super(m); | ||
this.name = this.constructor.name; | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
} | ||
export default ValidationError; |
@@ -7,6 +7,6 @@ /** | ||
export const isStream = (stream) => | ||
stream !== null && | ||
typeof stream === 'object' && | ||
// @ts-expect-error | ||
typeof stream.pipe === 'function'; | ||
stream !== null && | ||
typeof stream === "object" && | ||
// @ts-expect-error | ||
typeof stream.pipe === "function"; | ||
@@ -19,8 +19,8 @@ /** | ||
export const isReadableStream = (stream) => | ||
isStream(stream) && | ||
// @ts-expect-error | ||
stream.readable !== false && | ||
// @ts-expect-error | ||
typeof stream._read === 'function' && | ||
// @ts-expect-error | ||
typeof stream._readableState === 'object'; | ||
isStream(stream) && | ||
// @ts-expect-error | ||
stream.readable !== false && | ||
// @ts-expect-error | ||
typeof stream._read === "function" && | ||
// @ts-expect-error | ||
typeof stream._readableState === "object"; |
@@ -1,3 +0,3 @@ | ||
import semver from 'semver'; | ||
import npmPkg from 'validate-npm-package-name'; | ||
import semver from "semver"; | ||
import npmPkg from "validate-npm-package-name"; | ||
@@ -13,6 +13,6 @@ const urlIsh = /^https?:\/\/[a-zA-Z0-9-_./]+(:[0-9]+)?/; | ||
export const origin = (value) => { | ||
if (urlIsh.test(value)) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error('Parameter "origin" is not valid'); | ||
if (urlIsh.test(value)) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error('Parameter "origin" is not valid'); | ||
}; | ||
@@ -27,6 +27,6 @@ | ||
export const org = (value) => { | ||
if (/^[a-zA-Z0-9_-]+$/.test(value)) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error(`Parameter "org" is not valid - Value: ${value}`); | ||
if (/^[a-zA-Z0-9_-]+$/.test(value)) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error(`Parameter "org" is not valid - Value: ${value}`); | ||
}; | ||
@@ -41,7 +41,7 @@ | ||
export const name = (value) => { | ||
const result = npmPkg(value); | ||
if (result.validForNewPackages || result.validForOldPackages) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error(`Parameter "name" is not valid - Value: ${value}`); | ||
const result = npmPkg(value); | ||
if (result.validForNewPackages || result.validForOldPackages) { | ||
return value.toLowerCase(); | ||
} | ||
throw new Error(`Parameter "name" is not valid - Value: ${value}`); | ||
}; | ||
@@ -56,7 +56,7 @@ | ||
export const version = (value) => { | ||
const result = semver.valid(value); | ||
if (result) { | ||
return result; | ||
} | ||
throw new Error(`Parameter "version" is not valid - Value: ${value}`); | ||
const result = semver.valid(value); | ||
if (result) { | ||
return result; | ||
} | ||
throw new Error(`Parameter "version" is not valid - Value: ${value}`); | ||
}; | ||
@@ -71,6 +71,6 @@ | ||
export const alias = (value) => { | ||
if (/^[0-9]+$/.test(value)) { | ||
return value; | ||
} | ||
throw new Error(`Parameter "alias" is not valid - Value: ${value}`); | ||
if (/^[0-9]+$/.test(value)) { | ||
return value; | ||
} | ||
throw new Error(`Parameter "alias" is not valid - Value: ${value}`); | ||
}; | ||
@@ -85,11 +85,11 @@ | ||
export const type = (value) => { | ||
if ( | ||
value === 'pkg' || | ||
value === 'map' || | ||
value === 'npm' || | ||
value === 'img' | ||
) { | ||
return value; | ||
} | ||
throw new Error(`Parameter "type" is not valid - Value: ${value}`); | ||
if ( | ||
value === "pkg" || | ||
value === "map" || | ||
value === "npm" || | ||
value === "img" | ||
) { | ||
return value; | ||
} | ||
throw new Error(`Parameter "type" is not valid - Value: ${value}`); | ||
}; | ||
@@ -113,6 +113,6 @@ | ||
export const semverType = (value) => { | ||
if (value === 'major' || value === 'minor' || value === 'patch') { | ||
return value; | ||
} | ||
throw new Error(`Parameter "semverType" is not valid - Value: ${value}`); | ||
if (value === "major" || value === "minor" || value === "patch") { | ||
return value; | ||
} | ||
throw new Error(`Parameter "semverType" is not valid - Value: ${value}`); | ||
}; |
{ | ||
"name": "@eik/common", | ||
"version": "4.1.1", | ||
"version": "5.0.0", | ||
"description": "Common utilities for Eik modules", | ||
@@ -44,10 +44,11 @@ "main": "lib/index.js", | ||
"semver": "7.6.3", | ||
"validate-npm-package-name": "5.0.1" | ||
"validate-npm-package-name": "6.0.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/plugin-syntax-import-assertions": "7.24.7", | ||
"@eik/eslint-config": "1.0.2", | ||
"@babel/plugin-syntax-import-assertions": "7.26.0", | ||
"@eik/eslint-config": "1.0.5", | ||
"@eik/prettier-config": "1.0.1", | ||
"@eik/semantic-release-config": "1.0.0", | ||
"@eik/typescript-config": "1.0.0", | ||
"@hapi/hapi": "21.3.10", | ||
"@hapi/hapi": "21.3.12", | ||
"@semantic-release/changelog": "6.0.3", | ||
@@ -59,14 +60,14 @@ "@semantic-release/git": "10.0.1", | ||
"@types/validate-npm-package-name": "4.0.2", | ||
"eslint": "9.8.0", | ||
"express": "4.19.2", | ||
"fastify": "4.28.1", | ||
"json-schema-to-typescript": "15.0.0", | ||
"npm-run-all": "4.1.5", | ||
"eslint": "9.14.0", | ||
"express": "4.21.1", | ||
"fastify": "5.1.0", | ||
"json-schema-to-typescript": "15.0.3", | ||
"npm-run-all2": "7.0.1", | ||
"prettier": "3.3.3", | ||
"rimraf": "6.0.1", | ||
"semantic-release": "24.0.0", | ||
"semantic-release": "24.2.0", | ||
"stoppable": "1.1.0", | ||
"tap": "21.0.0", | ||
"typescript": "5.5.4" | ||
"tap": "21.0.1", | ||
"typescript": "5.6.3" | ||
} | ||
} |
@@ -60,5 +60,5 @@ /** | ||
export type EikjsonSchema = import("../../eikjson.js").EikjsonSchema; | ||
import FileMapping from './file-mapping.js'; | ||
import FileMapping from "./file-mapping.js"; | ||
declare const _config: unique symbol; | ||
declare const _tokens: unique symbol; | ||
export {}; |
@@ -20,3 +20,3 @@ export default FileMapping; | ||
} | ||
import LocalFileLocation from './local-file-location.js'; | ||
import RemoteFileLocation from './remote-file-location.js'; | ||
import LocalFileLocation from "./local-file-location.js"; | ||
import RemoteFileLocation from "./remote-file-location.js"; |
export default class InvalidConfigError extends CustomError { | ||
} | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; |
export default class MissingConfigError extends CustomError { | ||
} | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; |
export default class MultipleConfigSourcesError extends CustomError { | ||
constructor(); | ||
} | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; |
export default class NoFilesMatchedError extends CustomError { | ||
} | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; |
@@ -19,3 +19,3 @@ export default ResolvedFiles; | ||
} | ||
import LocalFileLocation from './local-file-location.js'; | ||
import LocalFileLocation from "./local-file-location.js"; | ||
declare const originalFiles: unique symbol; |
export default class SingleDestMultipleSourcesError extends CustomError { | ||
} | ||
import CustomError from './custom-error.js'; | ||
import CustomError from "./custom-error.js"; |
@@ -28,2 +28,2 @@ declare namespace _default { | ||
export default _default; | ||
import EikConfig from '../classes/eik-config.js'; | ||
import EikConfig from "../classes/eik-config.js"; |
@@ -14,11 +14,11 @@ declare namespace _default { | ||
export default _default; | ||
import localAssets from './local-assets.js'; | ||
import getDefaults from './get-defaults.js'; | ||
import configStore from './config-store.js'; | ||
import typeSlug from './type-slug.js'; | ||
import typeTitle from './type-title.js'; | ||
import { addTrailingSlash } from './path-slashes.js'; | ||
import { removeTrailingSlash } from './path-slashes.js'; | ||
import { addLeadingSlash } from './path-slashes.js'; | ||
import { removeLeadingSlash } from './path-slashes.js'; | ||
import resolveFiles from './resolve-files.js'; | ||
import localAssets from "./local-assets.js"; | ||
import getDefaults from "./get-defaults.js"; | ||
import configStore from "./config-store.js"; | ||
import typeSlug from "./type-slug.js"; | ||
import typeTitle from "./type-title.js"; | ||
import { addTrailingSlash } from "./path-slashes.js"; | ||
import { removeTrailingSlash } from "./path-slashes.js"; | ||
import { addLeadingSlash } from "./path-slashes.js"; | ||
import { removeLeadingSlash } from "./path-slashes.js"; | ||
import resolveFiles from "./resolve-files.js"; |
@@ -13,2 +13,2 @@ export default resolveFiles; | ||
}, cwd: string): Promise<ResolvedFiles[]>; | ||
import ResolvedFiles from '../classes/resolved-files.js'; | ||
import ResolvedFiles from "../classes/resolved-files.js"; |
@@ -10,8 +10,8 @@ declare namespace _default { | ||
export default _default; | ||
import * as validators from './validators/index.js'; | ||
import ReadFile from './classes/read-file.js'; | ||
import EikConfig from './classes/eik-config.js'; | ||
import schemas from './schemas/index.js'; | ||
import * as stream from './stream.js'; | ||
import helpers from './helpers/index.js'; | ||
import * as validators from "./validators/index.js"; | ||
import ReadFile from "./classes/read-file.js"; | ||
import EikConfig from "./classes/eik-config.js"; | ||
import schemas from "./schemas/index.js"; | ||
import * as stream from "./stream.js"; | ||
import helpers from "./helpers/index.js"; | ||
export { validators, ReadFile, EikConfig, schemas, stream, helpers }; |
@@ -9,4 +9,4 @@ declare namespace _default { | ||
declare const schema: any; | ||
import * as validate from './validate.js'; | ||
import assert from './assert.js'; | ||
import ValidationError from './validation-error.js'; | ||
import * as validate from "./validate.js"; | ||
import assert from "./assert.js"; | ||
import ValidationError from "./validation-error.js"; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
79320
23
1648
+ Addedvalidate-npm-package-name@6.0.0(transitive)
- Removedvalidate-npm-package-name@5.0.1(transitive)