Comparing version 1.2.3 to 1.3.0
@@ -35,4 +35,4 @@ const createError = require("createerror"); | ||
exports.SnippetProcessingError = createError({ | ||
name: "SnippetProcessingError" | ||
exports.SnippetValidationError = createError({ | ||
name: "SnippetValidationError" | ||
}); | ||
@@ -39,0 +39,0 @@ |
@@ -51,2 +51,19 @@ const EventEmitter = require("events"); | ||
function last(arr) { | ||
return arr.length > 0 ? arr[arr.length - 1] : undefined; | ||
} | ||
function makeTest(titlePath) { | ||
return { | ||
title: last(titlePath), | ||
body: "", | ||
duration: 0, | ||
fullTitle: () => titlePath.join(" "), | ||
titlePath: () => titlePath, | ||
isPending: () => false, | ||
currentRetry: () => 0, | ||
slow: () => 0 | ||
}; | ||
} | ||
function noopWrapper(output) { | ||
@@ -227,50 +244,74 @@ return output; | ||
const test = { | ||
title: sourceFile, | ||
body: "", | ||
duration: 0, | ||
fullTitle: () => sourceFile, | ||
titlePath: () => [sourceFile], | ||
isPending: () => false, | ||
currentRetry: () => 0, | ||
slow: () => 0 | ||
}; | ||
let prepared; | ||
emitter.emit("test", test); | ||
const executionResult = { | ||
status: "", | ||
error: null | ||
}; | ||
try { | ||
const { markdown } = await this.prepareFile(sourceFile); | ||
markdown.validateSnippets(); | ||
executionResult.status = "pass"; | ||
prepared = await this.prepareFile(sourceFile); | ||
} catch (e) { | ||
const titlePath = [sourceFile, "prepare"]; | ||
const test = makeTest(titlePath); | ||
debug( | ||
'unable to process "%s" with: %s', | ||
'unable to prepare "%s" with: %s', | ||
sourceFile, | ||
errors.errorToOutput(e) | ||
); | ||
executionResult.status = "fail"; | ||
executionResult.error = e; | ||
emitter.emit("test", test); | ||
emitter.emit("fail", test, e); | ||
emitter.emit("test end", test); | ||
return; | ||
} | ||
switch (executionResult.status) { | ||
case "pass": | ||
debug("execution passed for %s", sourceFile); | ||
emitter.emit("pass", test); | ||
break; | ||
case "fail": | ||
debug( | ||
'unable to process "%s" with: %s', | ||
sourceFile, | ||
errors.errorToOutput(executionResult.error) | ||
); | ||
emitter.emit("fail", test, executionResult.error); | ||
break; | ||
const { markdown } = prepared; | ||
const snippets = markdown.getSnippets(); | ||
const { error, results } = markdown.validateSnippets(); | ||
for (const [indexKey, executionResult] of Object.entries(results)) { | ||
const index = Number(indexKey); | ||
let displayIndex; | ||
let displayTitle; | ||
switch (executionResult.compare) { | ||
case "none": | ||
case "nothrow": | ||
displayIndex = index; | ||
displayTitle = `${snippets.get(index).lang} evaluation`; | ||
break; | ||
case "output": | ||
displayIndex = index + 1; | ||
displayTitle = "captured output"; | ||
break; | ||
} | ||
const titlePath = [sourceFile, `[${displayIndex}] ${displayTitle}`]; | ||
const test = makeTest(titlePath); | ||
emitter.emit("test", test); | ||
if (executionResult.status === "pending") { | ||
// identify it as such | ||
test.isPending = () => true; | ||
} | ||
switch (executionResult.status) { | ||
case "pass": | ||
debug("execution passed for %s", sourceFile); | ||
emitter.emit("pass", test); | ||
break; | ||
case "fail": | ||
debug( | ||
'unable to process "%s" with: %s', | ||
sourceFile, | ||
errors.errorToOutput(executionResult.error) | ||
); | ||
emitter.emit("fail", test, executionResult.error); | ||
break; | ||
case "pending": | ||
debug("execution skipped for %s", sourceFile); | ||
emitter.emit("pending", test); | ||
break; | ||
} | ||
emitter.emit("test end", test); | ||
} | ||
emitter.emit("test end", test); | ||
return error; | ||
} | ||
@@ -293,2 +334,3 @@ | ||
tests: markdownFiles.length, | ||
start: 0, | ||
duration: 0, // support epilogue generation | ||
@@ -308,6 +350,11 @@ passes: 0, | ||
emitter.on("test", () => (stats.total += 1)); | ||
emitter.on("pass", () => (stats.passes += 1)); | ||
emitter.on("fail", (test, error) => { | ||
stats.failures += 1; | ||
errorEntries.push({ file: test.title, error }); | ||
emitter.on("fail", () => (stats.failures += 1)); | ||
emitter.on("pending", () => (stats.skipped += 1)); | ||
emitter.on("suite end", suite => { | ||
const { title, error } = suite; | ||
if (error) { | ||
errorEntries.push({ file: title, error }); | ||
} | ||
}); | ||
@@ -352,15 +399,32 @@ | ||
emitter.once("start", () => print()); | ||
emitter.on("pass", test => print(` ${test.title} PASSED`)); | ||
emitter.on("fail", test => print(` ${test.title} FAILED`)); | ||
emitter.on("suite", suite => print(` ${suite.title}`)); | ||
emitter.on("pass", test => print(` - ${test.title} PASSED`)); | ||
emitter.on("fail", test => print(` - ${test.title} FAILED`)); | ||
emitter.on("fail", (_, error) => print(`${error}\n`)); | ||
emitter.on("pending", test => print(` - ${test.title} SKIPPED`)); | ||
} | ||
// update the start time | ||
stats.start = Date.now(); | ||
emitter.emit("start"); | ||
const rootSuite = { | ||
title: "", | ||
fullTitle: () => "" | ||
}; | ||
emitter.emit("suite", rootSuite); | ||
for (const file of markdownFiles) { | ||
emitter.total += 1; | ||
await this._validateFile(file, emitter); | ||
const suite = { | ||
title: file, | ||
fullTitle: () => file | ||
}; | ||
emitter.emit("suite", suite); | ||
const error = await this._validateFile(file, emitter); | ||
emitter.emit("suite end", { ...suite, error }); | ||
} | ||
emitter.emit("suite end", rootSuite); | ||
emitter.emit("end"); | ||
@@ -367,0 +431,0 @@ |
@@ -135,3 +135,3 @@ const marked = require("marked"); | ||
} | ||
this.snippets.validateSnippets(); | ||
return this.snippets.validate(); | ||
} | ||
@@ -138,0 +138,0 @@ |
@@ -10,2 +10,10 @@ const canEvaluate = require("./canEvaluate"); | ||
function assertNoError(snippet) { | ||
const { output } = snippet; | ||
if (output.kind === "error") { | ||
throw new Error("snippet evaluation resulted in an error"); | ||
} | ||
} | ||
function compareOutput(snippet, nextSnippet) { | ||
@@ -15,10 +23,2 @@ const { output } = snippet; | ||
if (nextSnippet.lang !== "output") { | ||
if (output.kind === "error") { | ||
throw new Error("snippet evaluation resulted in an error"); | ||
} else { | ||
return; | ||
} | ||
} | ||
const hasOutput = output && (output.kind || output.text); | ||
@@ -74,3 +74,3 @@ if (hasOutput) { | ||
} catch (e) { | ||
checkErrors[index] = new errors.SnippetProcessingError({ | ||
checkErrors[index] = new errors.SnippetValidationError({ | ||
message: e.message, | ||
@@ -180,13 +180,38 @@ data: { original: e } | ||
const lastSnippetIndex = this.items.length - 1; | ||
const validateErrors = {}; | ||
const validateResults = {}; | ||
for (const [index, snippet] of this.entries()) { | ||
const validationResult = { | ||
compare: "none", | ||
status: "", | ||
error: null | ||
}; | ||
if (!canEvaluate(snippet)) { | ||
continue; | ||
} | ||
// record the result | ||
validateResults[index] = validationResult; | ||
// reference following snippet for comparisons | ||
const nextSnippet = index < lastSnippetIndex ? this.get(index + 1) : {}; | ||
try { | ||
if (canEvaluate(snippet) && snippet.flags.evaluate) { | ||
compareOutput(snippet, nextSnippet); | ||
if (snippet.flags.evaluate) { | ||
if (nextSnippet.lang === "output") { | ||
validationResult.compare = "output"; | ||
compareOutput(snippet, nextSnippet); | ||
} else { | ||
validationResult.compare = "nothrow"; | ||
assertNoError(snippet); | ||
} | ||
validationResult.status = "pass"; | ||
} else { | ||
validationResult.status = "pending"; | ||
} | ||
} catch (e) { | ||
validateErrors[index] = new errors.SnippetProcessingError({ | ||
validationResult.status = "fail"; | ||
validationResult.error = new errors.SnippetValidationError({ | ||
message: e.message, | ||
@@ -198,13 +223,16 @@ data: { original: e } | ||
return Object.keys(validateErrors).length > 0 ? validateErrors : null; | ||
} | ||
validateSnippets() { | ||
const validateErrors = this.validate(); | ||
if (validateErrors) { | ||
throw new errors.FileProcessingError({ | ||
let error; | ||
const validateErrors = Object.values(validateResults) | ||
.map(result => result.error) | ||
.filter(Boolean); | ||
if (validateErrors.length > 0) { | ||
error = new errors.FileProcessingError({ | ||
message: errors.snippetErrorsToMsg(validateErrors), | ||
data: { errors: validateErrors } | ||
}); | ||
} else { | ||
error = null; | ||
} | ||
return { error, results: validateResults }; | ||
} | ||
@@ -211,0 +239,0 @@ |
{ | ||
"name": "evaldown", | ||
"version": "1.2.3", | ||
"version": "1.3.0", | ||
"description": "Evalute JavaScript snippets in markdown files and output static pages.", | ||
@@ -5,0 +5,0 @@ "main": "lib/Evaldown.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
71329
1826