Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@eik/common

Package Overview
Dependencies
Maintainers
4
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eik/common - npm Package Compare versions

Comparing version 2.0.3 to 3.0.0-next.1

lib/classes/file-mapping.js

22

CHANGELOG.md

@@ -0,1 +1,23 @@

# [3.0.0-next.1](https://github.com/eik-lib/common/compare/v2.0.3...v3.0.0-next.1) (2021-02-18)
### Features
* add extension, mime-type and content-type to file location ([a9b4fe1](https://github.com/eik-lib/common/commit/a9b4fe15cf39425070b9bd260183656933d94c5d))
* add mappings() method to eik config object ([f989ae0](https://github.com/eik-lib/common/commit/f989ae0e2de0aa5646fd33d0f5854bc7e74c8734)), closes [/github.com/eik-lib/issues/issues/2#issuecomment-779099732](https://github.com//github.com/eik-lib/issues/issues/2/issues/issuecomment-779099732)
* refactor!: packageURL removed, localAssets fixed and updated ([90fd181](https://github.com/eik-lib/common/commit/90fd1818f69384d4edeb056dc2c8367e51b21d44))
* refactor!: remove pathsAndFiles methods ([90d8a12](https://github.com/eik-lib/common/commit/90d8a12e4df8e3a37f295c6136e94bf4ade68cb4))
* feat!: preserve directory structure when globbing in config ([dff2830](https://github.com/eik-lib/common/commit/dff28301f9bc6e37ef9db32455fa64f5a7a9e80a))
### BREAKING CHANGES
* packageURL was removed as it no longer makes sense given the changes to eik json files config
localAssets has been refactored to use the new mappings method of eik config
* Consumers of the Eik Config class will all need to be updated to use the newer .mappings() method instead.
* directory structures are no longer flattened
## [2.0.3](https://github.com/eik-lib/common/compare/v2.0.2...v2.0.3) (2021-02-11)

@@ -2,0 +24,0 @@

@@ -0,2 +1,7 @@

// @ts-check
module.exports = class CustomError extends Error {
/**
* @param {string} message
*/
constructor(message) {

@@ -3,0 +8,0 @@ super(message);

152

lib/classes/eik-config.js

@@ -0,7 +1,24 @@

// @ts-check
/* eslint-disable no-continue */
/**
* @type {(value: unknown, message?: string) => asserts value}
*/
const assert = require('assert');
const { promisify } = require('util');
const path = require('path');
const { extname, join, isAbsolute } = require('path');
const isGlob = require('is-glob');
const glob = promisify(require('glob'));
const NoFilesMatchedError = require('./no-files-matched-error');
const SingleDestMultipleSourcesError = require('./single-dest-multiple-source-error');
const { assert, schema } = require('../schemas');
const FileMapping = require('./file-mapping');
const LocalFileLocation = require('./local-file-location');
const RemoteFileLocation = require('./remote-file-location');
const schemas = require('../schemas');
const {
typeSlug,
pathDiff,
addTrailingSlash,
removeTrailingSlash,
} = require('../helpers');

@@ -11,8 +28,57 @@ const _config = Symbol('config');

/**
* Normalizes Eik JSON "files" definition to object form if in string form
*
* @param {EikjsonSchema["files"]} files
*
* @returns {{[k: string]: string;}}
*/
const normalizeFilesDefinition = (files) =>
typeof files === 'string' ? { '/': files } : files;
/**
* Uses an Eik JSON "files" definition to resolve files on disk into a data structure
*
* @param {{[k: string]: string;}} files
* @param {string} cwd
*
* @returns {Promise<[string, string, string[]][]>}
*/
const resolveFiles = async (files, cwd) =>
Promise.all(
Object.entries(files).map(([dest, src]) => {
let replaced = src.replace(addTrailingSlash(cwd), '');
if (extname(replaced) === '' && isGlob(replaced) === false) {
replaced = join(replaced, '/**/*');
}
return Promise.all([
dest,
replaced,
glob(replaced, { cwd, nodir: true }),
]);
}),
);
/**
* @typedef {import ("../../eikjson").EikjsonSchema} EikjsonSchema
*/
module.exports = class EikConfig {
constructor(configHash, tokens, configRootDir) {
this[_config] = configHash;
/**
* @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);
this.cwd = configRootDir;
this.map = [].concat(configHash['import-map'] || []);
assert(
isAbsolute(configRootDir),
`"configRootDir" must be an absolute path: "${configRootDir}" given`,
);
this.cwd = removeTrailingSlash(configRootDir);
/** @type {string[]} */
this.map = [].concat(this[_config]['import-map'] || []);
}

@@ -29,10 +95,12 @@

set version(newVersion) {
assert.version(newVersion);
schemas.assert.version(newVersion);
this[_config].version = newVersion;
}
/** @type {EikjsonSchema["type"]} */
get type() {
return this[_config].type || schema.properties.type.default;
return this[_config].type || schemas.schema.properties.type.default;
}
/** @type {string} */
get server() {

@@ -54,4 +122,11 @@ const configuredServer = this[_config].server;

/**
* Normalized relative directory path with leading ./ and trailing / chars stripped
*/
get out() {
return this[_config].out || '.eik';
const defaulted = this[_config].out || '.eik';
const out = defaulted.startsWith('./')
? defaulted.substr(2)
: defaulted;
return removeTrailingSlash(out);
}

@@ -64,45 +139,32 @@

validate() {
assert.eikJSON(this[_config]);
schemas.assert.eikJSON(this[_config]);
}
async pathsAndFiles() {
const resolvedFiles = await Promise.all(
Object.entries(this.files).map(([pathname, file]) =>
Promise.all([pathname, file, glob(file, { cwd: this.cwd })]),
),
);
return resolvedFiles.flatMap(([pathname, file, filePaths]) => {
if (filePaths.length === 0) {
throw new NoFilesMatchedError(file);
/**
* @returns {Promise<FileMapping[]>}
*/
async mappings() {
const files = normalizeFilesDefinition(this.files);
const resolvedFiles = await resolveFiles(files, this.cwd);
return resolvedFiles.flatMap(([dest, src, srcFilePaths]) => {
if (srcFilePaths.length === 0) {
throw new NoFilesMatchedError(src);
}
const url = new URL(pathname, 'http://origin');
const basename = path.basename(url.pathname);
const isNamedDest = basename.includes('.');
if (extname(dest) !== '' && srcFilePaths.length > 1) {
throw new SingleDestMultipleSourcesError(dest);
}
if (isNamedDest) {
if (filePaths.length > 1)
throw new SingleDestMultipleSourcesError(pathname);
return [[pathname, filePaths[0], pathname, file]];
}
return filePaths.map((filePath) => [
path.join(pathname, path.basename(filePath)),
filePath,
pathname,
file,
]);
return srcFilePaths.map((filePath) => {
const source = new LocalFileLocation(filePath, this.cwd);
const destination = new RemoteFileLocation(
extname(dest) ? dest : join(dest, pathDiff(src, filePath)),
join(typeSlug(this.type), this.name, this.version),
this.server,
);
return new FileMapping(source, destination);
});
});
}
async pathsAndFilesAbsolute() {
const relativePathsAndFiles = await this.pathsAndFiles();
return relativePathsAndFiles.reduce((acc, [destPath, srcPath]) => {
const absoluteSrc = path.isAbsolute(srcPath)
? srcPath
: path.join(this.cwd, srcPath);
const absoluteDest = path.join(this.cwd, this.out, destPath);
acc.set(absoluteSrc, absoluteDest);
return acc;
}, new Map());
}
};

@@ -0,4 +1,9 @@

// @ts-check
const CustomError = require('./custom-error');
module.exports = class InvalidConfigError extends CustomError {
/**
* @param {string} msg
*/
constructor(msg) {

@@ -5,0 +10,0 @@ super(`Eik config object was invalid: '${msg}'`);

@@ -0,4 +1,9 @@

// @ts-check
const CustomError = require('./custom-error');
module.exports = class MissingConfigError extends CustomError {
/**
* @param {string} dir
*/
constructor(dir) {

@@ -5,0 +10,0 @@ super(`No package.json or eik.json file found in: '${dir}'`);

@@ -0,1 +1,3 @@

// @ts-check
const CustomError = require('./custom-error');

@@ -2,0 +4,0 @@

@@ -0,4 +1,9 @@

// @ts-check
const CustomError = require('./custom-error');
module.exports = class NoFilesMatchedError extends CustomError {
/**
* @param {string} file
*/
constructor(file) {

@@ -5,0 +10,0 @@ const message = `No files found for path: '${file}'`;

@@ -1,2 +0,2 @@

'use strict';
// @ts-check;

@@ -6,6 +6,3 @@ const { isReadableStream } = require('../stream');

const ReadFile = class ReadFile {
constructor({
mimeType = '',
etag = '',
} = {}) {
constructor({ mimeType = '', etag = '' } = {}) {
this._mimeType = mimeType;

@@ -21,3 +18,4 @@ this._stream = undefined;

set stream(value) {
if (!isReadableStream(value)) throw new Error('Value is not a Readable stream');
if (!isReadableStream(value))
throw new Error('Value is not a Readable stream');
this._stream = value;

@@ -37,3 +35,3 @@ }

}
}
};
module.exports = ReadFile;

@@ -0,4 +1,9 @@

// @ts-check
const CustomError = require('./custom-error');
module.exports = class SingleDestMultipleSourcesError extends CustomError {
/**
* @param {string} destFilePath
*/
constructor(destFilePath) {

@@ -5,0 +10,0 @@ super(

@@ -0,1 +1,3 @@

// @ts-check
const { readFileSync, writeFileSync } = require('fs');

@@ -10,6 +12,13 @@ const { join } = require('path');

/**
* Read a file at a given path and parse it
*
* @param {string} path
*
* @returns {object}
*/
function readJSONFromDisk(path) {
let fileData;
try {
fileData = readFileSync(path);
fileData = readFileSync(path, { encoding: 'utf8' });
} catch (e) {

@@ -57,12 +66,22 @@ return null;

config.validate();
} catch(err) {
throw new InvalidConfigError(`config.findInDirectory operation failed: ${err.message}`);
} catch (err) {
throw new InvalidConfigError(
`config.findInDirectory operation failed: ${err.message}`,
);
}
return config;
},
/**
* Persist config changes to disk as <cwd>/eik.json
*
* @param {import('../classes/eik-config')} config
*/
persistToDisk(config) {
try {
config.validate();
} catch(err) {
throw new InvalidConfigError(`config.persistToDisk operation failed: ${err.message}`);
} catch (err) {
throw new InvalidConfigError(
`config.persistToDisk operation failed: ${err.message}`,
);
}

@@ -69,0 +88,0 @@ const dest = join(config.cwd, 'eik.json');

@@ -0,1 +1,3 @@

// @ts-check
'use strict';

@@ -11,3 +13,3 @@

*
* @returns {{server:string,token:string,js:string|object,css:string|object,version:string,map:Array,name:string,out:string,cwd:string}}
* @returns {import("../classes/eik-config")} EikConfig
*/

@@ -19,3 +21,3 @@ module.exports = function getDefaults(cwd) {

if (e.constructor.name === 'MissingConfigError') {
return new EikConfig({}, [], cwd);
return new EikConfig(null, [], cwd);
}

@@ -22,0 +24,0 @@ throw e;

const localAssets = require('./local-assets');
const packageURL = require('./package-url');
const getDefaults = require('./get-defaults');
const configStore = require('./config-store');
const typeSlug = require('./type-slug');
const typeTitle = require('./type-title');
const pathDiff = require('./path-diff');
const {
addTrailingSlash,
removeTrailingSlash,
addLeadingSlash,
removeLeadingSlash,
} = require('./path-slashes');
module.exports = { localAssets, packageURL, getDefaults, configStore };
module.exports = {
localAssets,
getDefaults,
configStore,
typeSlug,
typeTitle,
pathDiff,
addTrailingSlash,
removeTrailingSlash,
addLeadingSlash,
removeLeadingSlash,
};
/* eslint-disable no-await-in-loop */
/**
* @type {(value: unknown, message?: string) => asserts value}
*/
const assert = require('assert');
const { join, extname, basename } = require('path');
const fs = require('fs');
const configStore = require("./config-store")
const configStore = require('./config-store');
/**
* Sets up asset routes for local development. Mounted paths match those on Eik server and values are read from projects eik.json file.
*
*
* @param {object} app - express js or fastify app instance
* @param {string} rootEikDirectory - (optional) path to folder where eik configuration file can be found
*/
async function localAssets(
app,
rootEikDirectory = process.cwd(),
) {
assert(app.decorateReply || app.name === 'app', 'App must be an Express or Fastify app instance');
assert(typeof rootEikDirectory === 'string' && rootEikDirectory, 'Path to folder for eik config must be provided and must be of type string');
async function localAssets(app, rootEikDirectory = process.cwd()) {
assert(
app.decorateReply || app.name === 'app',
'App must be an Express or Fastify 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.pathsAndFiles()).forEach(([pathname, filePath]) => {
const ext = extname(filePath);
const pathnameHasExt = !!extname(pathname);
const value = pathnameHasExt
? join(`/pkg/${eik.name}/${eik.version}`, pathname)
: join(
`/pkg/${eik.name}/${eik.version}`,
pathname,
basename(filePath),
);
const fileOnDisk = join(eik.cwd, filePath);
let contentType;
switch (ext) {
case '.js':
contentType = 'application/javascript';
break;
case '.map':
case '.json':
contentType = 'application/json';
break;
case '.css':
contentType = 'text/css';
break;
default:
contentType = 'application/octet-stream';
}
app.get(value, (req, res) => {
(await eik.mappings()).forEach((mapping) => {
app.get(mapping.destination.url.pathname, (req, res) => {
if (res.set) {
// express
res.set('Access-Control-Allow-Origin', '*');
res.set('content-type', contentType);
fs.createReadStream(fileOnDisk).pipe(res);
res.set('content-type', mapping.source.contentType);
fs.createReadStream(mapping.source.absolute).pipe(res);
} else if (res.type) {
// fastify
res.header('Access-Control-Allow-Origin', '*');
res.type(contentType);
res.send(fs.createReadStream(fileOnDisk));
res.type(mapping.source.contentType);
res.send(fs.createReadStream(mapping.source.absolute));
}
});
})
});
}
module.exports = localAssets;

@@ -1,2 +0,2 @@

'use strict';
// @ts-check

@@ -15,6 +15,7 @@ const {

const assert = (validate, message) => value => {
const valid = validate(value);
if (valid.error) {
const errorMessage = valid.error.map(err => {
const assert = (validate, message) => (value) => {
const valid = validate(value);
if (valid.error) {
const errorMessage = valid.error
.map((err) => {
let msg = err.message;

@@ -25,6 +26,7 @@ if (err.params && err.params.allowedValues) {

return msg;
}).join(',');
throw new ValidationError(`${message}: ${errorMessage}`);
}
};
})
.join(',');
throw new ValidationError(`${message}: ${errorMessage}`, valid.error);
}
};

@@ -31,0 +33,0 @@ module.exports = {

@@ -30,7 +30,12 @@ {

"description": "File mapping definition for the package. Keys represent files or paths to be created on the Eik Server. Values represent paths to local files to be published.",
"type": "object",
"minProperties": 1,
"additionalProperties": {
"type": "string"
}
"oneOf": [
{
"type": "object",
"minProperties": 1,
"additionalProperties": {
"type": "string"
}
},
{ "type": "string", "minLength": 1 }
]
},

@@ -37,0 +42,0 @@ "import-map": {

@@ -1,2 +0,2 @@

'use strict';
// @ts-check

@@ -3,0 +3,0 @@ const schema = require('./eikjson.schema.json');

@@ -1,3 +0,1 @@

'use strict';
const formats = require('ajv-formats');

@@ -12,2 +10,3 @@ const semver = require('semver');

const ajv = new Ajv(ajvOptions);
// @ts-ignore
formats(ajv); // Needed to support "uri"

@@ -14,0 +13,0 @@ const validate = ajv.compile({

@@ -1,4 +0,8 @@

'use strict';
// @ts-check
class ValidationError extends Error {
/**
* @param {string} message
* @param {Error} err
*/
constructor(message, err) {

@@ -12,2 +16,2 @@ let m = message;

}
module.exports = ValidationError;
module.exports = ValidationError;
'use strict';
const isStream = (stream) => stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function';
const isStream = (stream) =>
stream !== null &&
typeof stream === 'object' &&
typeof stream.pipe === 'function';
module.exports.isStream = isStream;
const isReadableStream = (stream) => isStream(stream) && stream.readable !== false && typeof stream._read === 'function' && typeof stream._readableState === 'object';
const isReadableStream = (stream) =>
isStream(stream) &&
stream.readable !== false &&
typeof stream._read === 'function' &&
typeof stream._readableState === 'object';
module.exports.isReadableStream = isReadableStream;

@@ -6,3 +6,3 @@ 'use strict';

const origin = value => {
const origin = (value) => {
if (new RegExp('^https?://[a-zA-Z0-9-_./]+(:[0-9]+)?').test(value)) {

@@ -15,3 +15,3 @@ return value.toLowerCase();

const org = value => {
const org = (value) => {
if (/^[a-zA-Z0-9_-]+$/.test(value)) {

@@ -24,3 +24,3 @@ return value.toLowerCase();

const name = value => {
const name = (value) => {
const result = npmPkg(value);

@@ -34,3 +34,3 @@ if (result.validForNewPackages || result.validForOldPackages) {

const version = value => {
const version = (value) => {
const result = semver.valid(value);

@@ -44,3 +44,3 @@ if (result) {

const alias = value => {
const alias = (value) => {
if (/^[0-9]+$/.test(value)) {

@@ -53,3 +53,3 @@ return value;

const type = value => {
const type = (value) => {
if (value === 'pkg' || value === 'map' || value === 'npm') {

@@ -63,6 +63,6 @@ return value;

// TODO; https://github.com/asset-pipe/core/issues/12
const extra = value => value;
const extra = (value) => value;
module.exports.extra = extra;
const semverType = value => {
const semverType = (value) => {
if (value === 'major' || value === 'minor' || value === 'patch') {

@@ -69,0 +69,0 @@ return value;

{
"name": "@eik/common",
"version": "2.0.3",
"version": "3.0.0-next.1",
"description": "Common utilities for Eik modules",

@@ -12,5 +12,10 @@ "main": "lib/index.js",

"scripts": {
"test": "tap",
"test": "tap --test-regex=.test.js --test-ignore=node_modules",
"lint:fix": "eslint --fix .",
"lint": "eslint ."
"lint": "eslint .",
"schema:types": "json2ts lib/schemas/eikjson.schema.json > eikjson.d.ts",
"schema:outdated": "npm run schema:types && git diff --exit-code HEAD:eikjson.d.ts eikjson.d.ts",
"style:check": "prettier -c .",
"style:format": "prettier -w .",
"typecheck": "tsc"
},

@@ -32,2 +37,4 @@ "repository": {

"glob": "^7.1.6",
"is-glob": "^4.0.1",
"mime-types": "^2.1.29",
"node-fetch": "^2.6.1",

@@ -44,3 +51,3 @@ "semver": "^7.0.0",

"@semantic-release/release-notes-generator": "9.0.1",
"eslint": "7.19.0",
"eslint": "7.20.0",
"eslint-config-airbnb-base": "14.2.1",

@@ -51,5 +58,6 @@ "eslint-config-prettier": "7.2.0",

"express": "4.17.1",
"fastify": "3.11.0",
"fastify": "3.12.0",
"json-schema-to-typescript": "^10.1.3",
"prettier": "2.2.1",
"semantic-release": "17.3.7",
"semantic-release": "17.3.9",
"stoppable": "1.1.0",

@@ -56,0 +64,0 @@ "tap": "14.11.0"

@@ -11,3 +11,3 @@ # Eik Commons

Importing schemas
Importing schemas

@@ -28,3 +28,3 @@ ```js

//or
//or

@@ -80,2 +80,3 @@ assert.eikJSON({

```
##### files

@@ -85,3 +86,3 @@

const { error, value } = schemas.validate.files({
'./index.js': '/path/to/file.js'
'./index.js': '/path/to/file.js',
});

@@ -92,3 +93,3 @@

assert.files({
'./index.js': '/path/to/file.js'
'./index.js': '/path/to/file.js',
});

@@ -100,3 +101,5 @@ ```

```js
const { error, value } = schemas.validate.importMap('http://meserver.com/map.json');
const { error, value } = schemas.validate.importMap(
'http://meserver.com/map.json',
);

@@ -146,6 +149,6 @@ const { error, value } = schemas.validate.importMap([

"server": "https://assets.myeikserver.com",
"files" :{
"files": {
"esm.js": "./assets/esm.js",
"esm.css": "./assets/esm.css",
"/": "./assets/**/*.map",
"/": "./assets/**/*.map"
}

@@ -166,3 +169,3 @@ }

This helper function can be used to build URLs for given entries in an `eik.json` files section.
This helper function can be used to build URLs for given entries in an `eik.json` files section.

@@ -176,6 +179,6 @@ Given the following `eik.json` file:

"server": "https://assets.myeikserver.com",
"files" :{
"files": {
"esm.js": "./assets/esm.js",
"esm.css": "./assets/esm.css",
"/": "./assets/**/*.map",
"/": "./assets/**/*.map"
}

@@ -193,2 +196,1 @@ }

The URL returned will be `https://assets.myeikserver.com/pkg/my-app/1.0.0/esm.js`
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc