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(` +`); +}); 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