diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 0000000..f5d30d1
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,7 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} **/
+module.exports = {
+ testEnvironment: "node",
+ transform: {
+ "^.+.tsx?$": ["ts-jest",{}],
+ },
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 7a73343..9cade39 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
},
"scripts": {
"build": "npx tsc",
+ "test": "jest",
"djockey": "npx tsc && node dist/cli.js"
},
"dependencies": {
@@ -16,12 +17,15 @@
"nunjucks": "^3.2.4"
},
"devDependencies": {
+ "@jest/globals": "^29.7.0",
"@types/argparse": "^2.0.16",
+ "@types/jest": "^29.5.12",
"@types/js-yaml": "^4.0.9",
"@types/node": "^22.4.0",
"@types/nunjucks": "^3.2.6",
"jest": "^29.7.0",
"sinon": "^18.0.0",
+ "ts-jest": "^29.2.4",
"typescript": "^5.5.4"
}
}
diff --git a/src/plugins/tableOfContentsPlugin.test.ts b/src/plugins/tableOfContentsPlugin.test.ts
new file mode 100644
index 0000000..263158c
--- /dev/null
+++ b/src/plugins/tableOfContentsPlugin.test.ts
@@ -0,0 +1,53 @@
+import { BulletList, parse, renderHTML } from "@djot/djot";
+import { DjockeyDoc } from "../types";
+import { TableOfContentsPlugin, TOCEntry } from "./tableOfContentsPlugin";
+
+test("Generates TOCEntry tree", () => {
+ const doc: DjockeyDoc = {
+ djotDoc: parse(`
+ # Heading 1
+ ## Heading 1.1
+ # Heading 2
+ ### Heading 2.2
+ `),
+ title: "Test doc",
+ originalExtension: ".djot",
+ absolutePath: "Test Doc.djot",
+ relativePath: "Test Doc.djot",
+ filename: "Test Doc",
+ frontMatter: {},
+ data: {},
+ };
+
+ const plg = new TableOfContentsPlugin();
+ plg.onPass_read(doc);
+ plg.onPass_write(doc);
+
+ const html = renderHTML({
+ tag: "doc",
+ references: {},
+ autoReferences: {},
+ footnotes: {},
+ children: [doc.data.toc as BulletList],
+ });
+
+ expect(html).toEqual(`
+-
+Heading 1
+
+
+-
+Heading 2
+
+
+
+`);
+});
diff --git a/src/plugins/tableOfContentsPlugin.ts b/src/plugins/tableOfContentsPlugin.ts
index 08f00e2..0e995e7 100644
--- a/src/plugins/tableOfContentsPlugin.ts
+++ b/src/plugins/tableOfContentsPlugin.ts
@@ -2,7 +2,7 @@ import { BulletList, Heading, Inline, ListItem } from "@djot/djot";
import { applyFilter } from "../engine/djotFiltersPlus";
import { DjockeyDoc, DjockeyPlugin } from "../types";
-type TOCEntry = {
+export type TOCEntry = {
id: string;
node: Heading;
children: TOCEntry[];
@@ -59,6 +59,9 @@ export class TableOfContentsPlugin implements DjockeyPlugin {
const renderTOCArray: (arr: TOCEntry[]) => BulletList = (arr) => {
const tocEntryToListItem = (entry: TOCEntry) => {
+ const entryChildren: BulletList[] = entry.children.length
+ ? [renderTOCArray(entry.children)]
+ : [];
const result: ListItem = {
tag: "list_item",
children: [
@@ -66,7 +69,7 @@ const renderTOCArray: (arr: TOCEntry[]) => BulletList = (arr) => {
tag: "para",
children: entry.node.children,
},
- renderTOCArray(entry.children),
+ ...entryChildren,
],
};
return result;
diff --git a/yarn.lock b/yarn.lock
index fa63775..6d1a97c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -920,6 +920,16 @@ __metadata:
languageName: node
linkType: hard
+"@types/jest@npm:^29.5.12":
+ version: 29.5.12
+ resolution: "@types/jest@npm:29.5.12"
+ dependencies:
+ expect: ^29.0.0
+ pretty-format: ^29.0.0
+ checksum: 19b1efdeed9d9a60a81edc8226cdeae5af7479e493eaed273e01243891c9651f7b8b4c08fc633a7d0d1d379b091c4179bbaa0807af62542325fd72f2dd17ce1c
+ languageName: node
+ linkType: hard
+
"@types/js-yaml@npm:^4.0.9":
version: 4.0.9
resolution: "@types/js-yaml@npm:4.0.9"
@@ -1087,6 +1097,13 @@ __metadata:
languageName: node
linkType: hard
+"async@npm:^3.2.3":
+ version: 3.2.6
+ resolution: "async@npm:3.2.6"
+ checksum: ee6eb8cd8a0ab1b58bd2a3ed6c415e93e773573a91d31df9d5ef559baafa9dab37d3b096fa7993e84585cac3697b2af6ddb9086f45d3ac8cae821bb2aab65682
+ languageName: node
+ linkType: hard
+
"babel-jest@npm:^29.7.0":
version: 29.7.0
resolution: "babel-jest@npm:29.7.0"
@@ -1215,6 +1232,15 @@ __metadata:
languageName: node
linkType: hard
+"bs-logger@npm:0.x":
+ version: 0.2.6
+ resolution: "bs-logger@npm:0.2.6"
+ dependencies:
+ fast-json-stable-stringify: 2.x
+ checksum: d34bdaf68c64bd099ab97c3ea608c9ae7d3f5faa1178b3f3f345acd94e852e608b2d4f9103fb2e503f5e69780e98293df41691b84be909b41cf5045374d54606
+ languageName: node
+ linkType: hard
+
"bser@npm:2.1.1":
version: 2.1.1
resolution: "bser@npm:2.1.1"
@@ -1290,7 +1316,7 @@ __metadata:
languageName: node
linkType: hard
-"chalk@npm:^4.0.0":
+"chalk@npm:^4.0.0, chalk@npm:^4.0.2":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
dependencies:
@@ -1498,7 +1524,9 @@ __metadata:
resolution: "djockey@workspace:."
dependencies:
"@djot/djot": ^0.3.1
+ "@jest/globals": ^29.7.0
"@types/argparse": ^2.0.16
+ "@types/jest": ^29.5.12
"@types/js-yaml": ^4.0.9
"@types/node": ^22.4.0
"@types/nunjucks": ^3.2.6
@@ -1508,6 +1536,7 @@ __metadata:
js-yaml: ^4.1.0
nunjucks: ^3.2.4
sinon: ^18.0.0
+ ts-jest: ^29.2.4
typescript: ^5.5.4
languageName: unknown
linkType: soft
@@ -1519,6 +1548,17 @@ __metadata:
languageName: node
linkType: hard
+"ejs@npm:^3.1.10":
+ version: 3.1.10
+ resolution: "ejs@npm:3.1.10"
+ dependencies:
+ jake: ^10.8.5
+ bin:
+ ejs: bin/cli.js
+ checksum: ce90637e9c7538663ae023b8a7a380b2ef7cc4096de70be85abf5a3b9641912dde65353211d05e24d56b1f242d71185c6d00e02cb8860701d571786d92c71f05
+ languageName: node
+ linkType: hard
+
"electron-to-chromium@npm:^1.5.4":
version: 1.5.11
resolution: "electron-to-chromium@npm:1.5.11"
@@ -1634,7 +1674,7 @@ __metadata:
languageName: node
linkType: hard
-"expect@npm:^29.7.0":
+"expect@npm:^29.0.0, expect@npm:^29.7.0":
version: 29.7.0
resolution: "expect@npm:29.7.0"
dependencies:
@@ -1667,7 +1707,7 @@ __metadata:
languageName: node
linkType: hard
-"fast-json-stable-stringify@npm:^2.1.0":
+"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.1.0":
version: 2.1.0
resolution: "fast-json-stable-stringify@npm:2.1.0"
checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb
@@ -1692,6 +1732,15 @@ __metadata:
languageName: node
linkType: hard
+"filelist@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "filelist@npm:1.0.4"
+ dependencies:
+ minimatch: ^5.0.1
+ checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160
+ languageName: node
+ linkType: hard
+
"fill-range@npm:^7.1.1":
version: 7.1.1
resolution: "fill-range@npm:7.1.1"
@@ -2138,6 +2187,20 @@ __metadata:
languageName: node
linkType: hard
+"jake@npm:^10.8.5":
+ version: 10.9.2
+ resolution: "jake@npm:10.9.2"
+ dependencies:
+ async: ^3.2.3
+ chalk: ^4.0.2
+ filelist: ^1.0.4
+ minimatch: ^3.1.2
+ bin:
+ jake: bin/cli.js
+ checksum: f2dc4a086b4f58446d02cb9be913c39710d9ea570218d7681bb861f7eeaecab7b458256c946aeaa7e548c5e0686cc293e6435501e4047174a3b6a504dcbfcaae
+ languageName: node
+ linkType: hard
+
"jest-changed-files@npm:^29.7.0":
version: 29.7.0
resolution: "jest-changed-files@npm:29.7.0"
@@ -2502,7 +2565,7 @@ __metadata:
languageName: node
linkType: hard
-"jest-util@npm:^29.7.0":
+"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0":
version: 29.7.0
resolution: "jest-util@npm:29.7.0"
dependencies:
@@ -2683,6 +2746,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.memoize@npm:4.x":
+ version: 4.1.2
+ resolution: "lodash.memoize@npm:4.1.2"
+ checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089
+ languageName: node
+ linkType: hard
+
"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
version: 10.4.3
resolution: "lru-cache@npm:10.4.3"
@@ -2708,6 +2778,13 @@ __metadata:
languageName: node
linkType: hard
+"make-error@npm:1.x":
+ version: 1.3.6
+ resolution: "make-error@npm:1.3.6"
+ checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402
+ languageName: node
+ linkType: hard
+
"make-fetch-happen@npm:^13.0.0":
version: 13.0.1
resolution: "make-fetch-happen@npm:13.0.1"
@@ -2768,7 +2845,7 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1":
+"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
@@ -2777,6 +2854,15 @@ __metadata:
languageName: node
linkType: hard
+"minimatch@npm:^5.0.1":
+ version: 5.1.6
+ resolution: "minimatch@npm:5.1.6"
+ dependencies:
+ brace-expansion: ^2.0.1
+ checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^9.0.4":
version: 9.0.5
resolution: "minimatch@npm:9.0.5"
@@ -3147,7 +3233,7 @@ __metadata:
languageName: node
linkType: hard
-"pretty-format@npm:^29.7.0":
+"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0":
version: 29.7.0
resolution: "pretty-format@npm:29.7.0"
dependencies:
@@ -3598,6 +3684,43 @@ __metadata:
languageName: node
linkType: hard
+"ts-jest@npm:^29.2.4":
+ version: 29.2.4
+ resolution: "ts-jest@npm:29.2.4"
+ dependencies:
+ bs-logger: 0.x
+ ejs: ^3.1.10
+ fast-json-stable-stringify: 2.x
+ jest-util: ^29.0.0
+ json5: ^2.2.3
+ lodash.memoize: 4.x
+ make-error: 1.x
+ semver: ^7.5.3
+ yargs-parser: ^21.0.1
+ peerDependencies:
+ "@babel/core": ">=7.0.0-beta.0 <8"
+ "@jest/transform": ^29.0.0
+ "@jest/types": ^29.0.0
+ babel-jest: ^29.0.0
+ jest: ^29.0.0
+ typescript: ">=4.3 <6"
+ peerDependenciesMeta:
+ "@babel/core":
+ optional: true
+ "@jest/transform":
+ optional: true
+ "@jest/types":
+ optional: true
+ babel-jest:
+ optional: true
+ esbuild:
+ optional: true
+ bin:
+ ts-jest: cli.js
+ checksum: 142246f12bb11d5edbfb5a65e298097667e2c4d390e316e356416ce00d3cd157220dbfb9de2a56b38f30776bc92ba59eff9fd78e9345ba4c6712783f27f5475a
+ languageName: node
+ linkType: hard
+
"type-detect@npm:4.0.8":
version: 4.0.8
resolution: "type-detect@npm:4.0.8"
@@ -3780,7 +3903,7 @@ __metadata:
languageName: node
linkType: hard
-"yargs-parser@npm:^21.1.1":
+"yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1":
version: 21.1.1
resolution: "yargs-parser@npm:21.1.1"
checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c