@stackbit/utils
Advanced tools
Comparing version 0.1.0 to 0.1.1
{ | ||
"name": "@stackbit/utils", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "Stackbit utilities", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
# utils | ||
Stackbit utilities | ||
## Install | ||
```bash | ||
npm install @stackbit/utils | ||
``` |
141
src/index.js
@@ -11,2 +11,3 @@ const path = require('path'); | ||
mapPromise, | ||
findPromise, | ||
readDirRecursively, | ||
@@ -16,7 +17,11 @@ getFirst, | ||
concat, | ||
copy, | ||
copyIfNotSet, | ||
copy, | ||
rename, | ||
failFunctionWithTag, | ||
assertFunctionWithFail, | ||
mapDeep, | ||
fieldPathToString, | ||
getFirstExistingFile, | ||
parseFirstExistingFile, | ||
parseFile, | ||
@@ -42,3 +47,2 @@ parseDataByFilePath, | ||
} | ||
next(0); | ||
@@ -69,2 +73,23 @@ }); | ||
function findPromise(array, callback, thisArg) { | ||
return new Promise((resolve, reject) => { | ||
function next(index) { | ||
if (index < array.length) { | ||
callback.call(thisArg, array[index], index, array).then(result => { | ||
if (result) { | ||
resolve(array[index]); | ||
} else { | ||
next(index + 1); | ||
} | ||
}).catch(error => { | ||
reject(error); | ||
}); | ||
} else { | ||
resolve(); | ||
} | ||
} | ||
next(0); | ||
}); | ||
} | ||
async function readDirRecursively(dir, options) { | ||
@@ -119,8 +144,2 @@ const rootDir = _.get(options, 'rootDir', dir); | ||
function copyIfNotSet(sourceObject, sourcePath, targetObject, targetPath, transform) { | ||
if (!_.has(targetObject, targetPath)) { | ||
copy(sourceObject, sourcePath, targetObject, targetPath, transform); | ||
} | ||
} | ||
function copy(sourceObject, sourcePath, targetObject, targetPath, transform) { | ||
@@ -136,2 +155,8 @@ if (_.has(sourceObject, sourcePath)) { | ||
function copyIfNotSet(sourceObject, sourcePath, targetObject, targetPath, transform) { | ||
if (!_.has(targetObject, targetPath)) { | ||
copy(sourceObject, sourcePath, targetObject, targetPath, transform); | ||
} | ||
} | ||
function rename(object, oldPath, newPath) { | ||
@@ -162,2 +187,102 @@ if (_.has(object, oldPath)) { | ||
/** | ||
* Deeply maps the passed `value` by recursively calling the `iteratee` on | ||
* value's children. The value returned from the iteratee is used to map the | ||
* children. | ||
* | ||
* The iteratee is invoked with three arguments - the `value` being iterated, | ||
* the `fieldPath` of the current `value` relative to the original passed value, | ||
* and the `stack` of ancestors of the current `value`. | ||
* | ||
* For the first time the `iterate` will be called with the original `value` | ||
* and empty arrays for `fieldPath` and `stack`. | ||
* | ||
* In other words, any `value` passed to the iteratee (except the first call, | ||
* and assuming the ancestors keys were not mapped) | ||
* will be equal to: `_.get(originalValue, fieldPath)` | ||
* | ||
* The recursion is called in pre-order depth-first-search. Meaning, the | ||
* iteratee is called first on parent nodes and then on its children. Therefore | ||
* if iteratee maps/replaces the parent node, then the children of the replaced | ||
* node will be traversed. | ||
* | ||
* @example | ||
* mapDeep({ prop: 'foo', arr: [ 'bar' , 1, 2 ] }, (value) => { | ||
* if (_.isString(value)) return '__' + value; | ||
* if (_.isNumber(value)) return value * 10; | ||
* return value; | ||
* }) | ||
* => { prop: '__foo', arr: [ '__bar', 10, 20 ] } | ||
* | ||
* mapDeep({ prop: 'foo', arr: [ 'bar' ] }, (value, fieldPath) => { | ||
* if ((_.isString(value)) return value + '__' + fieldPath.join('.'); | ||
* return value; | ||
* }) | ||
* => { prop: 'foo__prop', arr: [ 'bar__arr.0' ] } | ||
* | ||
* @param {*} value A value to map | ||
* @param {Function} iteratee Function (value: any, fieldPath: Array, stack: Array) | ||
* @param {object} [options] | ||
* @param {boolean} [options.iterateCollections] Default: true | ||
* @param {boolean} [options.iterateScalars] Default: true | ||
* @param {boolean} [options.postOrder] Change the invocation of iteratee to post-order depth-first-search. Default: false | ||
* @returns {*} | ||
*/ | ||
function mapDeep(value, iteratee, options = {}, _keyPath = [], _objectStack = []) { | ||
const postOrder = _.get(options, 'postOrder', false); | ||
let iterate; | ||
if (_.isPlainObject(value) || _.isArray(value)) { | ||
iterate = _.get(options, 'iterateCollections', true); | ||
} else { | ||
iterate = _.get(options, 'iterateScalars', true); | ||
} | ||
if (iterate && !postOrder) { | ||
value = iteratee(value, _keyPath, _objectStack); | ||
} | ||
const childrenIterator = (val, key) => { | ||
return mapDeep(val, iteratee, options, _.concat(_keyPath, key), _.concat(_objectStack, value)); | ||
}; | ||
if (_.isPlainObject(value)) { | ||
value = _.mapValues(value, childrenIterator); | ||
} else if (_.isArray(value)) { | ||
value = _.map(value, childrenIterator); | ||
} | ||
if (iterate && postOrder) { | ||
value = iteratee(value, _keyPath, _objectStack); | ||
} | ||
return value; | ||
} | ||
function fieldPathToString(fieldPath) { | ||
return _.reduce(fieldPath, (accumulator, fieldName, index) => { | ||
if (_.isString(fieldName) && /\W/.test(fieldName)) { | ||
// field name is a string with non alphanumeric character | ||
accumulator += `['${fieldName}']`; | ||
} else if (_.isNumber(fieldName)) { | ||
accumulator += `[${fieldName}]`; | ||
} else { | ||
if (index > 0) { | ||
accumulator += '.'; | ||
} | ||
accumulator += fieldName; | ||
} | ||
return accumulator; | ||
}, ''); | ||
} | ||
function getFirstExistingFile(fileNames, inputDir) { | ||
const filePaths = _.map(fileNames, fileName => path.resolve(inputDir, fileName)); | ||
return findPromise(filePaths, (filePath) => fse.pathExists(filePath)); | ||
} | ||
function parseFirstExistingFile(fileNames, inputDir) { | ||
return getFirstExistingFile(fileNames, inputDir).then(filePath => { | ||
if (filePath) { | ||
return parseFile(filePath); | ||
} else { | ||
return null; | ||
} | ||
}); | ||
} | ||
async function parseFile(filePath) { | ||
@@ -164,0 +289,0 @@ const data = await fse.readFile(filePath, 'utf8'); |
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
14877
369
9