Skip to content

Commit

Permalink
feat(@power-doctest/asciidoctor): add asciidoctor parser
Browse files Browse the repository at this point in the history
  • Loading branch information
azu committed Sep 1, 2019
1 parent 1100bd3 commit ffb3a9e
Show file tree
Hide file tree
Showing 13 changed files with 184 additions and 32 deletions.
2 changes: 1 addition & 1 deletion packages/@power-doctest/asciidoctor/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @power-doctest/asciidoctor

A power-doctest Runner using for Asciidoctor.
A [Asciidoctor](https://asciidoctor.org/) parser for power-doctest.

## Install

Expand Down
4 changes: 3 additions & 1 deletion packages/@power-doctest/asciidoctor/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@power-doctest/asciidoctor",
"version": "1.0.0",
"description": "A power-doctest Runner using for Asciidoctor.",
"description": "A Asciidoctor parser for power-doctest.",
"keywords": [
"asciidoc",
"asciidoctor",
Expand Down Expand Up @@ -30,6 +30,7 @@
},
"scripts": {
"build": "cross-env NODE_ENV=production tsc -p .",
"updateSnapshot": "cross-env UPDATE_SNAPSHOT=1 npm test",
"clean": "rimraf lib/",
"prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"",
"prepublish": "npm run --if-present build",
Expand All @@ -42,6 +43,7 @@
"tabWidth": 4
},
"dependencies": {
"@power-doctest/types": "^1.0.0",
"asciidoctor": "^2.0.3"
},
"devDependencies": {
Expand Down
99 changes: 96 additions & 3 deletions packages/@power-doctest/asciidoctor/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,100 @@
import { ParsedCode, ParsedResults, ParserArgs } from "@power-doctest/types";
import * as fs from "fs";
import * as path from "path";

const Asciidoctor = require("asciidoctor");
const asciidoctor = Asciidoctor();
type Attributes = {
[index: string]: string;
}
const getState = (attributes: Attributes): "none" | "enabled" | "disabled" => {
const state = attributes["doctest-state"];
if (!state) {
return "none";
}
if (/enable(d)?/.test(state)) {
return "enabled";
} else if (/disable(d)?/.test(state)) {
return "disabled";
}
return "none";
};

const getMeta = (attributes: Attributes): {} | undefined => {
const meta = attributes["doctest-meta"];
if (!meta) {
return;
}
try {
return JSON.parse(meta);
} catch (error) {
// parse error
throw new Error(`Can not parsed. doctest-meta={...} should be JSON object: ${error}`);
}
};

const getOptions = (attributes: Attributes): {} | undefined => {
const meta = attributes["doctest-options"];
if (!meta) {
return;
}
try {
return JSON.parse(meta);
} catch (error) {
// parse error
throw new Error(`Can not parsed. doctest-options={...} should be JSON object: ${error}`);
}
};

// inlining include::
const inlineCode = (code: string, baseFilePath: string): string => {
// include:: -> link:
const pattern = /link:(.+)\[.*?]/;
const dirName = path.dirname(baseFilePath);
return code.replace(pattern, (all, filePath) => {
const fileName = path.resolve(dirName, filePath);
if (fs.existsSync(fileName)) {
return fs.readFileSync(fileName, "utf-8");
}
return all;
});
};

export function parse(code: string) {
const doc = asciidoctor.load(code);
return doc;
export function parse(args: ParserArgs): ParsedResults {
const doc = asciidoctor.load(args.content);
return doc.getBlocks()
.filter((block: any) => {
const attributes = block.getAttributes();
return attributes.style === "source" && (attributes.language === "js" || attributes.language === "javascript");
})
.map((block: any) => {
const lineNumber: number = block.document.getReader().lineno;
const attributes: {} = block.getAttributes();
const code: string = block.getSource();
const lines: string[] = block.getSourceLines();
const meta = getMeta(attributes);
const doctestOptions = getOptions(attributes);
const parsedCode: ParsedCode = {
code: inlineCode(code, args.filePath),
state: getState(attributes),
location: {
start: {
line: lineNumber,
column: 0
},
end: {
line: lineNumber + lines.length,
column: 0
}
},
metadata: meta,
doctestOptions: doctestOptions ? {
filePath: args.filePath,
...doctestOptions
} : {
filePath: args.filePath
}
};
return parsedCode;
});
}
27 changes: 0 additions & 27 deletions packages/@power-doctest/asciidoctor/test/index.test.ts

This file was deleted.

49 changes: 49 additions & 0 deletions packages/@power-doctest/asciidoctor/test/snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as fs from "fs";
import * as path from "path";
import * as assert from "assert";
// transform function
import { parse } from "../src";

const fixturesDir = path.join(__dirname, "snapshots");

const trimUndefinedProperty = <T>(o: T, baseDir: string): T => {
return JSON.parse(stringify(o, baseDir));
};
const stringify = (o: {}, baseDir: string): string => {
return JSON.stringify(o, (key: string, value: any) => {
if (key === "filePath" && typeof value === "string") {
return path.relative(baseDir, value);
} else {
return value;
}
}, 4);
};
describe("Snapshot testing", () => {
fs.readdirSync(fixturesDir)
.map(caseName => {
const normalizedTestName = caseName.replace(/-/g, " ");
it(`Test ${normalizedTestName}`, async function() {
const fixtureDir = path.join(fixturesDir, caseName);
const actualFilePath = path.join(fixtureDir, "input.adoc");
const actualContent = fs.readFileSync(actualFilePath, "utf-8");
const results = parse({
content: actualContent,
filePath: actualFilePath
});
const expectedFilePath = path.join(fixtureDir, "output.json");
// Usage: update snapshots
// UPDATE_SNAPSHOT=1 npm test
if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) {
fs.writeFileSync(expectedFilePath, stringify(results, fixtureDir));
this.skip(); // skip when updating snapshots
return;
}
// compare input and output
const expectedContent = JSON.parse(fs.readFileSync(expectedFilePath, "utf-8"));
assert.deepStrictEqual(
trimUndefinedProperty(results, fixtureDir),
expectedContent
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,javascript,doctest-state="disabled"]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,javascript,doctest-state="enabled"]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,js]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,javascript,doctest-meta={ "ECMAScript": 2017 }]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,javascript,doctest-options={ "runMode": "any" }]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[source,javascript]
----
const str = "string";
console.log(str);
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[source,javascript]
----
include::source.js[]
----
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("from source.js");

0 comments on commit ffb3a9e

Please sign in to comment.