lazy-assert
Advanced tools
Comparing version 0.2.7 to 0.2.8
{ | ||
"name": "lazy-assert", | ||
"version": "0.2.7", | ||
"version": "0.2.8", | ||
"description": "An way of doing assertion for lazy people ...", | ||
"main": "src/index.js", | ||
"bin": { | ||
"lazy-refresh": "node src/scripts/refresh-actual-and-suggest.js", | ||
"lazy-remove": "node src/scripts/remove-actual-and-suggest.js" | ||
}, | ||
"scripts": { | ||
@@ -7,0 +11,0 @@ "postinstall": "node examples/5-nightwatch/nightwatch.config.js", |
@@ -176,2 +176,48 @@ var lazy = require('../index'); | ||
}); | ||
it('Should output debug validator', function () { | ||
lazy.peek('05-debug-output-validator', lazy.validators.debugOutputValidator({ | ||
"array": [ | ||
"array", | ||
[ | ||
"number", | ||
"string", | ||
"null", | ||
{ | ||
"a": [ | ||
"number" | ||
], | ||
"b": [ | ||
"undefined", | ||
[ | ||
"array", | ||
[ | ||
"number", | ||
[ | ||
"array", | ||
"string" | ||
] | ||
] | ||
] | ||
] | ||
} | ||
] | ||
], | ||
"boolean": "boolean", | ||
"null": "null", | ||
"number": "number", | ||
"string": "string" | ||
}), -1); | ||
}); | ||
it('Should output debug value', function () { | ||
lazy.peek('06-debug-output-value', lazy.validators.debugOutputValue({ | ||
'number': 1, | ||
'string': 'abc', | ||
'boolean': true, | ||
'null': null, | ||
'array': [1, 'abc', null, {a: 1}, {b: [1, ['c']]}] | ||
})); | ||
}); | ||
}); |
@@ -261,12 +261,5 @@ var assert = require('assert'); | ||
peek: function (peekKey, value, depthOrPlugin) { | ||
if (!this.testLocation) { | ||
throw utils.newError('no-test-set', 'No test script set for this test.'); | ||
} | ||
if (arguments.length < 2 || typeof peekKey !== 'string' || !peekKey) { | ||
throw utils.newError('no-peek-key', 'No peek key set for this peek') | ||
} | ||
lazyAssert.checkArguments(peekKey); | ||
var reportPath = utils.j(this.testLocation + '.report'); | ||
var expectPath = utils.j(reportPath, peekKey + '.expected'); | ||
var actualPath = utils.j(reportPath, peekKey + '.actual'); | ||
var paths = lazyAssert.getReportPaths(peekKey); | ||
@@ -276,11 +269,11 @@ var expected = ''; | ||
if (!fs.existsSync(expectPath)) { | ||
utils.write(expectPath, ''); | ||
if (!fs.existsSync(paths.expect)) { | ||
utils.write(paths.expect, ''); | ||
expected = ''; | ||
} | ||
else { | ||
expected = utils.read(expectPath); | ||
expected = utils.read(paths.expect); | ||
} | ||
utils.write(actualPath, actual); | ||
utils.write(paths.actual, actual); | ||
assert.equal( | ||
@@ -364,6 +357,7 @@ actual, expected, | ||
else if (!result.result) { | ||
delete result.result; | ||
lazyAssert.warn(peekKey, 'Validation failed with the given validator, the result is :'); | ||
lazyAssert.validators.printWarnings(result); | ||
lazyAssert.validators.printDebug(actualTargetValue, validator, result); | ||
lazyAssert.warn(peekKey, 'A default validator is : '); | ||
@@ -386,2 +380,54 @@ console.warn(JSON.stringify(lazyAssert.validators.summarizeTypeValidator(actualTargetValue), null, 2)); | ||
peekValidate: function (peekKey, actualTargetValue) { | ||
lazyAssert.checkArguments(peekKey); | ||
var paths = lazyAssert.getReportPaths(peekKey); | ||
var validator; | ||
if (!fs.existsSync(paths.validator)) { | ||
utils.write(paths.validator, '__tmp_expect__ = "undefined";'); | ||
validator = 'undefined'; | ||
} | ||
else { | ||
validator = eval(utils.read(paths.validator)); | ||
} | ||
var result = lazyAssert.validate(peekKey, actualTargetValue, validator); | ||
if (!result) { | ||
var suggest = lazyAssert.validators.summarizeTypeValidator(actualTargetValue); | ||
utils.write(paths.suggest, | ||
'__tmp_expect__ = ' | ||
+ JSON.stringify(suggest, null, 4) | ||
) | ||
} | ||
lazyAssert.ok(result, peekKey); | ||
}, | ||
checkArguments: function (peekKey) { | ||
if (!this.testLocation) { | ||
throw utils.newError('no-test-set', 'No test script set for this test.'); | ||
} | ||
if (typeof peekKey !== 'string' || !peekKey) { | ||
throw utils.newError('no-peek-key', 'No peek key set for this peek') | ||
} | ||
}, | ||
getReportPaths: function (peekKey) { | ||
var reportPath = utils.j(this.testLocation + '.report'); | ||
var expectPath = utils.j(reportPath, peekKey + '.expected'); | ||
var actualPath = utils.j(reportPath, peekKey + '.actual'); | ||
var suggestPath = utils.j(reportPath, peekKey + '.suggest.js'); | ||
var validatarPath = utils.j(reportPath, peekKey + '.validator.js'); | ||
return { | ||
report: reportPath, | ||
expect: expectPath, | ||
actual: actualPath, | ||
suggest: suggestPath, | ||
validator: validatarPath | ||
} | ||
}, | ||
newPeek: function (peekKey) { | ||
@@ -388,0 +434,0 @@ var peek = new Peek(peekKey); |
@@ -12,2 +12,3 @@ var utils = require('./utils'); | ||
var VALIDATE_KEY = '--[[validate_key]]--'; | ||
var DEBUG_PATH_KEY = '--[[path]]--'; | ||
@@ -678,5 +679,11 @@ var validatorsUtils = { | ||
/** | ||
* This method will try to go through the targetValue, | ||
* and exact a suggest validator for the developer, | ||
* so that it's quite easy to simply copy & paste to write your validate assertions | ||
* | ||
* @def: .summarizeTypeValidator: target => suggestedValidator | ||
*/ | ||
summarizeTypeValidator: function (target) { | ||
var rawValidator = validatorsUtils.preSummarizeTypeValidator(target); | ||
validatorsUtils.clearValidateKey(target); | ||
@@ -694,3 +701,3 @@ var validator = validatorsUtils.extractValidatorFromRaw(rawValidator); | ||
if ((typeof validator[key] === 'undefined' | ||
|| validator[key] === 'undefined') && !isInArray){ | ||
|| validator[key] === 'undefined') && !isInArray) { | ||
delete validator[key]; | ||
@@ -943,4 +950,4 @@ } | ||
result += '\n' + warning.subResult.map(function (warning) { | ||
return validatorsUtils.getWarningText(warning, indent + ' '); | ||
}).join('\n'); | ||
return validatorsUtils.getWarningText(warning, indent + ' '); | ||
}).join('\n'); | ||
} | ||
@@ -955,3 +962,3 @@ return result; | ||
* @def: .formalizeFailResultItem: result => undefined | ||
* result: extends #@.validators.validator.result | ||
* result: extends #@.validators.validator.result as ~FinalResult | ||
* valPath: string | ||
@@ -964,4 +971,4 @@ * condPath: string | ||
parentValPath = parentValPath || ''; | ||
parentCondPath = parentCondPath || ''; | ||
parentValPath = parentValPath || '$VAL'; | ||
parentCondPath = parentCondPath || '$COND'; | ||
@@ -990,8 +997,4 @@ var currentValPath = parentValPath; | ||
result.valPath = '$VAL' | ||
+ (currentValPath && currentValPath.substr(0, 1) !== '.' ? '.' : '') | ||
+ (currentValPath || ''); | ||
result.condPath = '$COND' | ||
+ (currentCondPath && currentCondPath.substr(0, 1) !== '.' ? '.' : '') | ||
+ (currentCondPath || ''); | ||
result.valPath = currentValPath; | ||
result.condPath = currentCondPath; | ||
@@ -1055,3 +1058,211 @@ if (result.subResult) { | ||
} | ||
}, | ||
/** | ||
* | ||
* @def: .printDebug: value, validator, result => undefined | ||
* // The value to be debug | ||
* value: any | ||
* validator: #@~Validator | ||
* | ||
* // For extracting the problematic valPath & condPath, | ||
* // so that the related path in value & validator can be highlighted | ||
* result: #@~FinalResult | ||
*/ | ||
printDebug: function (value, validator, result) { | ||
var problemPaths = validatorsUtils.getProblemPaths(result); | ||
console.log('@@d', result); | ||
console.log('@@d', problemPaths); | ||
console.warn('[WARN] $VAL ='); | ||
console.warn(JSON.stringify(validatorsUtils.debugOutputValue(value, problemPaths), null, 2)); | ||
console.warn('[WARN] $COND ='); | ||
console.warn(JSON.stringify(validatorsUtils.debugOutputValidator(validator, problemPaths), null, 2)); | ||
}, | ||
/** | ||
* Extract all valPath & condPath from result | ||
* | ||
* @def: .getProblemPaths: result, problemPaths => problemPaths | ||
* result: #@~FinalResult | ||
* | ||
* problemPaths: {path: 'leaf' | 'not-leaf'} as ~ProblemPaths | ||
* // e.g. $VAL.someKey.[1].someOtherKey | ||
* path: string | ||
*/ | ||
getProblemPaths: function (result, problemPaths) { | ||
problemPaths = problemPaths || {}; | ||
if (result.subResult) { | ||
result.subResult.forEach(function (subResult) { | ||
validatorsUtils.getProblemPaths(subResult, problemPaths); | ||
}); | ||
problemPaths[result.valPath] = 'not-leaf'; | ||
problemPaths[result.condPath] = 'not-leaf'; | ||
} | ||
else { | ||
problemPaths[result.valPath] = 'leaf'; | ||
problemPaths[result.condPath] = 'leaf'; | ||
} | ||
return problemPaths; | ||
}, | ||
/** | ||
* | ||
* @def: .getPrimitiveValue: rawValue, parentPath, key, problemPaths => valueDisplay | ||
* | ||
* // But only primitive value will be processed | ||
* rawValue: any | ||
* | ||
* // If the full path can be found in problemPaths, this value will be processed | ||
* path: string | ||
* problemPaths: #@~ProblemPaths | ||
* | ||
* /// | ||
* Example: | ||
* | ||
* 123 => "raw: 123 <<----- NOTICE" | ||
* 'abc' => "raw: 'abc' <<----- NOTICE" | ||
* true => "raw: true <<----- NOTICE" | ||
* null => "raw: null <<----- NOTICE" | ||
* undefined => "raw: undefined <<----- NOTICE" | ||
* /// | ||
* valueDisplay: string | ||
*/ | ||
getPrimitiveValueNotice: function (rawValue, path, problemPaths) { | ||
if (problemPaths[path] | ||
&& (typeof rawValue !== 'object' || rawValue === null) | ||
&& typeof rawValue !== 'function') { | ||
return 'raw: ' + JSON.stringify(rawValue).split('"').join('\'') | ||
+ validatorsUtils.getNoticeFlag(path, problemPaths); | ||
} else { | ||
return rawValue; | ||
} | ||
}, | ||
getNoticeFlag: function (path, problemPaths) { | ||
if (problemPaths[path] === 'leaf') { | ||
return ' <<----- NOTICE **Leaf** @ ' + path; | ||
} | ||
else { | ||
return ' <<----- NOTICE @ ' + path; | ||
} | ||
}, | ||
/** | ||
* All problematic paths will be detected during processing the validator | ||
* When a path is found, some extra info will be inserted into the output, | ||
* so that it's easier to find out what's wrong with the value against the validator | ||
* | ||
* ``` | ||
* # in array | ||
* # Raw: | ||
* [1, 2, null] | ||
* | ||
* # Output: | ||
* [ '$Cond.[0]', 1, '$Cond.[1]', 2, '$Cond.[3] <<----- NOTICE', 3 ] | ||
* | ||
* # in object | ||
* # Raw: | ||
* {a: {b: 1, c: null}} | ||
* | ||
* # Output: | ||
* { | ||
* '--[[path]]--': '$VAL', | ||
* a: { | ||
* '--[[path]]--': '$VAL.a' | ||
* b: 1, | ||
* c: 'raw: null <<----- NOTICE' | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @def: validator, problemPaths, parentPath => validatorWithDebugInfo | ||
* validator: #@~Validator | ||
* problemPaths: #@~ProblemPaths | ||
*/ | ||
debugOutputValidator: function (validator, problemPaths, parentPath) { | ||
parentPath = parentPath || '$COND'; | ||
if (utils.isArray(validator)) { | ||
var result = []; | ||
var type = validator[0]; | ||
if (type !== 'and' && type !== 'or' && type !== 'value' | ||
&& type !== 'array' && type !== '!') { | ||
type = 'or'; | ||
} | ||
else if (type === '!') { | ||
type = 'not'; | ||
} | ||
for (var i = 0; i < validator.length; i++) { | ||
var current = validator[i]; | ||
if ((type === 'or' && current !== type) || i) { | ||
var currentPath = parentPath + '.[' + type + ':' + i + ']'; | ||
} | ||
result.push(validatorsUtils.debugOutputValidator(current, problemPaths, currentPath)); | ||
} | ||
return result; | ||
} | ||
else if (typeof validator === 'object' && validator) { | ||
var result = {}; | ||
if (parentPath in problemPaths) { | ||
result[DEBUG_PATH_KEY] = validatorsUtils.getNoticeFlag(parentPath, problemPaths); | ||
} | ||
for (var key in validator) { | ||
var currentPath = parentPath + '.' + key; | ||
result[key] = validatorsUtils.debugOutputValidator(validator[key], problemPaths, currentPath); | ||
} | ||
return result; | ||
} | ||
else { | ||
return validatorsUtils.getPrimitiveValueNotice(validator, parentPath, problemPaths); | ||
} | ||
}, | ||
/** | ||
* Almost the same logic & purpose with #@.debugOutputValidator | ||
* | ||
* @def: .debugOutputValue: value, problemPaths, parentPath => valueWithDebugInfo | ||
*/ | ||
debugOutputValue: function (value, problemPaths, parentPath, isFromArray) { | ||
parentPath = parentPath || '$VAL'; | ||
if (utils.isArray(value)) { | ||
var result = []; | ||
for (var i = 0; i < value.length; i++) { | ||
var current = value[i]; | ||
var currentPath = parentPath + '.[' + i + ']'; | ||
result.push(validatorsUtils.debugOutputValue(current, problemPaths, currentPath)); | ||
} | ||
return result; | ||
} | ||
else if (typeof value === 'object' && value) { | ||
var result = {}; | ||
if (parentPath in problemPaths) { | ||
result[DEBUG_PATH_KEY] = validatorsUtils.getNoticeFlag(parentPath, problemPaths); | ||
} | ||
for (var key in value) { | ||
var currentPath = parentPath + '.' + key; | ||
result[key] = validatorsUtils.debugOutputValue(value[key], problemPaths, currentPath); | ||
} | ||
return result; | ||
} | ||
else { | ||
return validatorsUtils.getPrimitiveValueNotice(value, parentPath, problemPaths); | ||
} | ||
} | ||
}; | ||
@@ -1058,0 +1269,0 @@ |
@@ -49,4 +49,65 @@ var npath = require('path'); | ||
/** | ||
* /// | ||
* 遍历 baseDir 下的所有文件, | ||
* | ||
* 产生一个平级列表: | ||
* | ||
* 例如: | ||
* | ||
* ``` | ||
* base - | ||
* | a - b.js | ||
* | c - d.js | ||
* | | e.js | ||
* | f.js | ||
* ``` | ||
* | ||
* 输出: | ||
* | ||
* ``` | ||
* /a/b.js | ||
* /a/c/d.js | ||
* /a/c/e.js | ||
* /a/f.js | ||
* ``` | ||
* | ||
* @todo NOTE: 我们当前这个设计, 可能会有内存使用过大的风险, 请知悉. | ||
* /// | ||
* @def: .flattenFiles: baseDir => [filepath] throws noSuchDirError | ||
* baseDir: string // 目标的基础文件夹 | ||
* filepath: string // 相对于基础文件夹的 "相对路径" | ||
* noSuchDirError: Error // 如果 baseDir 不存在, 抛出该错误 (避免不小心为用户创建莫名其妙的文件夹) | ||
*/ | ||
flattenFiles: function (baseDir) { | ||
if (!fs.existsSync(baseDir)) { | ||
throw new Error('无此文件夹!'); | ||
} | ||
var result = []; | ||
fs.readdirSync(baseDir).forEach(function (fileEntry) { | ||
// 忽略以 `.` 起始的文件/文件夹 | ||
if (/^\./.test(fileEntry)) { | ||
return; | ||
} | ||
// 如果是文件, 直接插入 result 集合 | ||
if (fs.statSync(baseDir + '/' + fileEntry).isFile()) { | ||
result.push('/' + fileEntry); | ||
} | ||
// 如果是文件夹, 返回其子 flatten list, 并合并返回 | ||
else { | ||
utils.flattenFiles(baseDir + '/' + fileEntry).forEach(function (subFile) { | ||
result.push('/' + fileEntry + subFile); | ||
}); | ||
} | ||
}); | ||
return result; | ||
}, | ||
/** | ||
* | ||
* @def: .write: path, value => undefined throws #@.ensureFolder.isFileError | ||
@@ -53,0 +114,0 @@ * path: string // 目标的写入的文件路径 |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
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
1000000
225
11533
10
1