diff --git a/.babelrc b/.babelrc deleted file mode 100644 index e7b66cb96..000000000 --- a/.babelrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["last 2 versions"] - } - } - ], - "@babel/preset-react" - ], - "plugins": [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-object-rest-spread", - "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-transform-runtime" - ], - "sourceType": "unambiguous" -} diff --git a/.eslintrc b/.eslintrc index ab93da743..c725503bc 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,8 +1,8 @@ { - "extends": [ - "@readme/eslint-config", - "@readme/eslint-config/react" - ], + "extends": ["@readme/eslint-config", "@readme/eslint-config/react", "@readme/eslint-config/typescript"], "parser": "@babel/eslint-parser", - "root": true + "root": true, + "rules": { + "@typescript-eslint/no-var-requires": "off" + } } diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index a41387d16..d25ee63e6 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, 'SKIP CI')" steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 14.x + node-version: 20.x - name: Update npm run: npm i -g npm@7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 273766244..e0a46ede0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,21 +7,26 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x, 18.x] + node-version: + - lts/-1 + - lts/* + - latest + react: [16, 17, 18] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Update npm - run: npm i -g npm@7 - - name: Install dependencies run: npm ci + - name: Install React <18 deps + if: matrix.react == '16' || matrix.react == '17' + run: npm i react@${{ matrix.react }} react-dom@${{ matrix.react }} @testing-library/react@12 + - name: Run tests run: npm test @@ -31,16 +36,17 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x, 18.x] + node-version: [20.x] + react: [18] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run visual tests (node ${{ matrix.node-version }}) run: make ci - name: Upload snapshot diffs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ failure() }} with: name: snapshots-diffs @@ -51,7 +57,7 @@ jobs: run: make updateSnapshot - name: Upload snapshots - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ failure() }} with: name: image-snapshots diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e8a0839a1..bae561e65 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ff1c4abe..3dfd4456e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,17 +13,14 @@ jobs: # Setup the git repo & Node environemnt. # - name: Checkout branch (${{ github.ref }}) - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false # install breaks with persistant creds! - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 14 - - - name: Update npm - run: npm i -g npm@7 + node-version: 20 - name: Install dependencies run: | @@ -50,17 +47,17 @@ jobs: # Merge @latest release back to @next. # - - name: Sync to next - if: "github.ref == 'refs/heads/main'" - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: next - continue-on-error: true + #- name: Sync to next + # if: "github.ref == 'refs/heads/main'" + # uses: ad-m/github-push-action@master + # with: + # github_token: ${{ secrets.GITHUB_TOKEN }} + # branch: ${{ github.ref }} + # continue-on-error: true # Sync docs to rdmd.readme.io # - - name: Sync docs to rdmd.readme.io - uses: readmeio/rdme@v8 - with: - rdme: docs ./docs --key=${{ secrets.RDME_KEY }} --version=2 + #- name: Sync docs to rdmd.readme.io + # uses: readmeio/rdme@v8 + # with: + # rdme: docs ./docs --key=${{ secrets.RDME_KEY }} --version=2 diff --git a/.gitignore b/.gitignore index 64e91f8ae..08b684b41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -dist coverage node_modules +.env .idea/ .vscode/ *.code-* @@ -13,3 +13,9 @@ node_modules __diff_output__ example/public/img/emojis +example/demo.js* +example/demo.css + +dist + +.env diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index 5426a9320..000000000 --- a/.husky/commit-msg +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 1c2482304..000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npm run pretest diff --git a/.npm-upgrade.json b/.npm-upgrade.json index 93e9aea74..712d152f7 100644 --- a/.npm-upgrade.json +++ b/.npm-upgrade.json @@ -1,88 +1,20 @@ { "ignore": { - "hast-util-to-string": { - "versions": "*2.0.0", - "reason": "" - }, - "mdast-util-toc": { - "versions": "*6.1.0", - "reason": "" - }, - "rehype-raw": { - "versions": "*6.1.1", - "reason": "" - }, - "rehype-react": { - "versions": "*7.1.1", - "reason": "" - }, - "rehype-sanitize": { - "versions": "*5.0.1", - "reason": "" - }, - "rehype-stringify": { - "versions": "*9.0.3", - "reason": "" - }, - "remark-breaks": { - "versions": "*3.0.2", - "reason": "" - }, - "remark-disable-tokenizers": { - "versions": "*1.1.0", - "reason": "" - }, - "remark-frontmatter": { - "versions": "*4.0.1", - "reason": "" - }, - "remark-parse": { - "versions": "*10.0.1", - "reason": "" - }, - "remark-rehype": { - "versions": "*10.1.0", - "reason": "" - }, - "remark-slug": { - "versions": "*7.0.1", - "reason": "" - }, - "remark-stringify": { - "versions": "*10.0.2", - "reason": "" - }, - "unified": { - "versions": "*10.1.2", - "reason": "" - }, - "unist-util-select": { - "versions": "*4.0.1", - "reason": "" - }, "@hot-loader/react-dom": { - "versions": "*17.0.2", - "reason": "" + "versions": "17.0.2", + "reason": "staying on react 16" }, - "@testing-library/react": { - "versions": "^13", - "reason": "Waiting on react" + "codemirror": { + "versions": "", + "reason": "staying on 5" }, "react": { - "versions": "^18", - "reason": "Haven't tested yet" + "versions": "18.2.0", + "reason": "staying on 16" }, "react-dom": { - "versions": "^18", - "reason": "Waiting on react" - }, - "jest": { - "versions": "^29", - "reason": "jest-image-snapshot's locked to 28" - }, - "codemirror": { - "versions": "^6", - "reason": "big rewrite, IIRC" + "versions": "18.2.0", + "reason": "staying on 16" } } } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ae557d2b4..0f920b3ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,505 @@ Changelog === +## Version 6.75.0-beta.70 + +### πŸ›  Fixes & Updates + +* compatibility for unknown nodes ([#929](https://github.com/readmeio/markdown/issues/929)) ([5d21b54](https://github.com/readmeio/markdown/commit/5d21b540cafd67e49e3ae465cfbd91ddb651169c)) + +## Version 6.75.0-beta.69 + +### ✨ New & Improved + +* force release ([d3e4da3](https://github.com/readmeio/markdown/commit/d3e4da356053453445343534a170f795cf153b05)) + + +### πŸ›  Fixes & Updates + +* **beta:** nix errant log ([#934](https://github.com/readmeio/markdown/issues/934)) ([04b55eb](https://github.com/readmeio/markdown/commit/04b55eb1c6ef0f66e9de312be5d3a55b88755e88)), closes [#933](https://github.com/readmeio/markdown/issues/933) [/github.com/readmeio/markdown/pull/933#discussion_r1664579308](https://github.com/readmeio//github.com/readmeio/markdown/pull/933/issues/discussion_r1664579308) + +## Version 6.75.0-beta.68 + +### πŸ›  Fixes & Updates + +* **beta:** toc generation when using MDX components ([#933](https://github.com/readmeio/markdown/issues/933)) ([c1408e3](https://github.com/readmeio/markdown/commit/c1408e3fa3c47d155101de9c4ec9f82819f25ca7)) + +## Version 6.75.0-beta.67 + +### ✨ New & Improved + +* hast heading ids ([#932](https://github.com/readmeio/markdown/issues/932)) ([0075460](https://github.com/readmeio/markdown/commit/0075460eea3695861ab452f4551c5e9b188d0bfe)) + + +### πŸ›  Fixes & Updates + +* **gha:** update github actions versions ([#930](https://github.com/readmeio/markdown/issues/930)) ([e728a90](https://github.com/readmeio/markdown/commit/e728a9019b423d7e9845e1dbfbf1cd0d6d95b648)) + +## Version 6.75.0-beta.66 + +### ✨ New & Improved + +* add another html block test ([#928](https://github.com/readmeio/markdown/issues/928)) ([752be9e](https://github.com/readmeio/markdown/commit/752be9e0230c89824844ebad7f8267d2ae626117)) + + +### πŸ›  Fixes & Updates + +* html block test ([#927](https://github.com/readmeio/markdown/issues/927)) ([7830a3d](https://github.com/readmeio/markdown/commit/7830a3d6e6601174a0bff585825a228032fe2673)) + +## Version 6.75.0-beta.66 + +### πŸ›  Fixes & Updates + +* html block test ([#927](https://github.com/readmeio/markdown/issues/927)) ([7830a3d](https://github.com/readmeio/markdown/commit/7830a3d6e6601174a0bff585825a228032fe2673)) + +## Version 6.75.0-beta.65 + +### ✨ New & Improved + +* compatibility for rdmd image/embed components ([#919](https://github.com/readmeio/markdown/issues/919)) ([e631c8f](https://github.com/readmeio/markdown/commit/e631c8f0ebce74f2f49e0bc9657170ceddae3a86)) + +## Version 6.75.0-beta.64 + +### πŸ›  Fixes & Updates + +* add image component caption as children ([#918](https://github.com/readmeio/markdown/issues/918)) ([59e1bd3](https://github.com/readmeio/markdown/commit/59e1bd3206a6daaac50cfc2f39cb10fb21048698)) + +## Version 6.75.0-beta.63 + +### ✨ New & Improved + +* readme-variable ([#913](https://github.com/readmeio/markdown/issues/913)) ([e3c4a5e](https://github.com/readmeio/markdown/commit/e3c4a5e45fa8dd3c106d55c6b6b1e6938073715c)) + +## Version 6.75.0-beta.62 + +### ✨ New & Improved + +* mdx position ([#917](https://github.com/readmeio/markdown/issues/917)) ([0e080fa](https://github.com/readmeio/markdown/commit/0e080fabe93f7e2bd38aa2fa4718c6702e7ee2cf)) + +## Version 6.75.0-beta.61 + +### ✨ New & Improved + +* increase code font size ([#912](https://github.com/readmeio/markdown/issues/912)) ([586515f](https://github.com/readmeio/markdown/commit/586515f8880f587f4854af8a1397193efa05e913)), closes [#915](https://github.com/readmeio/markdown/issues/915) + +## Version 6.75.0-beta.60 + +### πŸ›  Fixes & Updates + +* updates to html block ([#906](https://github.com/readmeio/markdown/issues/906)) ([ddc97db](https://github.com/readmeio/markdown/commit/ddc97dbc9cafad133b4ac1e6f06eef067a1ca6d0)) + +## Version 6.75.0-beta.59 + +### ✨ New & Improved + +* new component ([#908](https://github.com/readmeio/markdown/issues/908)) ([4df0213](https://github.com/readmeio/markdown/commit/4df0213bbdce2345ce9914b5e80e90f8b048d501)) + +## Version 6.75.0-beta.58 + +### πŸ›  Fixes & Updates + +* decode HTML outside of component render ([#905](https://github.com/readmeio/markdown/issues/905)) ([9fdf13f](https://github.com/readmeio/markdown/commit/9fdf13fbc1a8bc1ec0fb207e0ed5da2c9cbd6163)) + +## Version 6.75.0-beta.57 + +### ✨ New & Improved + +* jsx variables ([#899](https://github.com/readmeio/markdown/issues/899)) ([3ed86e3](https://github.com/readmeio/markdown/commit/3ed86e3e50f681e5dcde9a7315556f2a233cc011)) + +## Version 6.75.0-beta.56 + +### πŸ›  Fixes & Updates + +* embed rendering on the hub ([#904](https://github.com/readmeio/markdown/issues/904)) ([828f0a5](https://github.com/readmeio/markdown/commit/828f0a5debfa5d2352153413eaee933ec340f358)) + +## Version 6.75.0-beta.55 + +### ✨ New & Improved + +* escapes ([#903](https://github.com/readmeio/markdown/issues/903)) ([94c37bc](https://github.com/readmeio/markdown/commit/94c37bc2dcd8bdfc63e7ecdd3ee761a93ee54924)) + +## Version 6.75.0-beta.54 + +### ✨ New & Improved + +* add html to hast ([#901](https://github.com/readmeio/markdown/issues/901)) ([6de3d89](https://github.com/readmeio/markdown/commit/6de3d895bac72c2452b552ae8aedca75649aea23)) + + +### πŸ›  Fixes & Updates + +* cleanup ([e34ebf5](https://github.com/readmeio/markdown/commit/e34ebf579c8a09eea04abe1815775c1c27d8100c)) + +## Version 6.75.0-beta.53 + +### πŸ›  Fixes & Updates + +* embeds and images save better ([#893](https://github.com/readmeio/markdown/issues/893)) ([67e0fec](https://github.com/readmeio/markdown/commit/67e0fec706d0538b9652552800aabe6f5ec0d97e)) + +## Version 6.75.0-beta.52 + +### πŸ›  Fixes & Updates + +* allow non-modules ([70b2a90](https://github.com/readmeio/markdown/commit/70b2a90580f64b1561d8f608ce83272561d3f26f)) + +## Version 6.75.0-beta.51 + +### ✨ New & Improved + +* plain ([#898](https://github.com/readmeio/markdown/issues/898)) ([0b60259](https://github.com/readmeio/markdown/commit/0b60259b002a61964c0f0a85589d625946f508e9)) + + +### πŸ›  Fixes & Updates + +* toc ([#900](https://github.com/readmeio/markdown/issues/900)) ([b3e8f7d](https://github.com/readmeio/markdown/commit/b3e8f7d0713361b87ad30077a79c0d08c5abb937)) +* types ([86a199b](https://github.com/readmeio/markdown/commit/86a199bacc639772a6bbb7994c6132f8d58db3c5)) + +## Version 6.75.0-beta.50 + +### ✨ New & Improved + +* trigger build ([e85772c](https://github.com/readmeio/markdown/commit/e85772c32393903cce88bcde5bee5755d46ad6ad)) + +## Version 6.75.0-beta.49 + +### πŸ›  Fixes & Updates + +* migration issues ([#896](https://github.com/readmeio/markdown/issues/896)) ([9752849](https://github.com/readmeio/markdown/commit/97528497c0a1694110d3fd303328480a3fc81a63)) + +## Version 6.75.0-beta.48 + +### ✨ New & Improved + +* mdx TOC ([#883](https://github.com/readmeio/markdown/issues/883)) ([ef8f9a1](https://github.com/readmeio/markdown/commit/ef8f9a1a812f257146da11c64385edbd9dfb8c3a)) + +## Version 6.75.0-beta.47 + +### ✨ New & Improved + +* translate recipes between mdx and md ([#892](https://github.com/readmeio/markdown/issues/892)) ([025c8cd](https://github.com/readmeio/markdown/commit/025c8cd54c346cb86d8b3dff4fc66882f7956ba5)) + +## Version 6.75.0-beta.46 + +### πŸ›  Fixes & Updates + +* add externals for node build ([#895](https://github.com/readmeio/markdown/issues/895)) ([3d6eb5d](https://github.com/readmeio/markdown/commit/3d6eb5d8471c0c75e810970a1358ab3964f8ce21)) + +## Version 6.75.0-beta.45 + +### πŸ›  Fixes & Updates + +* callout styling ([#891](https://github.com/readmeio/markdown/issues/891)) ([463b870](https://github.com/readmeio/markdown/commit/463b87037cc1b3164d94d97f70680ef3d1cd7826)) + +## Version 6.75.0-beta.44 + +### ✨ New & Improved + +* fix glossary item ([#890](https://github.com/readmeio/markdown/issues/890)) ([4ec815f](https://github.com/readmeio/markdown/commit/4ec815fb48a160b9902caada92528b9807cb2ea2)) + +## Version 6.75.0-beta.43 + +### ✨ New & Improved + +* load styles! ([bdb4441](https://github.com/readmeio/markdown/commit/bdb44414612858bcb26bef6f120001356bd36f6c)) + +## Version 6.75.0-beta.42 + +### πŸ›  Fixes & Updates + +* glossary ([#889](https://github.com/readmeio/markdown/issues/889)) ([d20f8e7](https://github.com/readmeio/markdown/commit/d20f8e76e2811762b8b153fca9b47d6a44ddd173)) + +## Version 6.75.0-beta.41 + +### πŸ›  Fixes & Updates + +* images ([#888](https://github.com/readmeio/markdown/issues/888)) ([4ecbdc7](https://github.com/readmeio/markdown/commit/4ecbdc79bc7c2d749f594947ab377c40cf013df2)) + +## Version 6.75.0-beta.40 + +### πŸ›  Fixes & Updates + +* callout breaks ([#887](https://github.com/readmeio/markdown/issues/887)) ([0949888](https://github.com/readmeio/markdown/commit/0949888ab04fc2e083dc787e2226a600c8965929)) + +## Version 6.75.0-beta.39 + +### πŸ›  Fixes & Updates + +* fix types ([47fc684](https://github.com/readmeio/markdown/commit/47fc684000e0ce1e86b42359f5e47dee2229529a)) +* matching node names with main app ([#886](https://github.com/readmeio/markdown/issues/886)) ([1290014](https://github.com/readmeio/markdown/commit/1290014bb3caa595fcbb6a3540117b39e11bed35)) +* update variable types ([#885](https://github.com/readmeio/markdown/issues/885)) ([1ccf82d](https://github.com/readmeio/markdown/commit/1ccf82d9fe1e8b36c5dbc90b67846565629eed9b)) + +## Version 6.75.0-beta.38 + +### ✨ New & Improved + +* compatibility ([#881](https://github.com/readmeio/markdown/issues/881)) ([6432be8](https://github.com/readmeio/markdown/commit/6432be8bb67dd8423ec223eb6355c8b2fa0c217a)) + +## Version 6.75.0-beta.37 + +### πŸ›  Fixes & Updates + +* compilers ([#882](https://github.com/readmeio/markdown/issues/882)) ([6caaafd](https://github.com/readmeio/markdown/commit/6caaafd19de9c13ea4f48df23f74d889725b77ba)) + +## Version 6.75.0-beta.36 + +### ✨ New & Improved + +* glossary niceness and more ([#879](https://github.com/readmeio/markdown/issues/879)) ([43b5256](https://github.com/readmeio/markdown/commit/43b525686b64f216dae32dbf0b64b03620f39ef3)) + +## Version 6.75.0-beta.35 + +### πŸ›  Fixes & Updates + +* callouts ([#880](https://github.com/readmeio/markdown/issues/880)) ([cf7e284](https://github.com/readmeio/markdown/commit/cf7e2845dd666a78d347c9f3ada2dea8f64c13bd)) + +## Version 6.75.0-beta.34 + +### ✨ New & Improved + +* embeds! ([#878](https://github.com/readmeio/markdown/issues/878)) ([9dee309](https://github.com/readmeio/markdown/commit/9dee30984b10411016e625eba1f4bfe8b26e4233)) + +## Version 6.75.0-beta.33 + +### πŸ›  Fixes & Updates + +* dynamic import ([06a22ba](https://github.com/readmeio/markdown/commit/06a22bac10e95788f6703c174a1ab22b84697f9e)) + +## Version 6.75.0-beta.32 + +### ✨ New & Improved + +* fix dynamic require ([2482231](https://github.com/readmeio/markdown/commit/24822311b1f6126a28e6b29d8f4f48d39ba0f78d)) +* jsx-coercion ([#876](https://github.com/readmeio/markdown/issues/876)) ([b742c6c](https://github.com/readmeio/markdown/commit/b742c6c734cfef3bdf0a6657221a727a475e9eef)) + + +### πŸ›  Fixes & Updates + +* types ([#877](https://github.com/readmeio/markdown/issues/877)) ([c0a4d66](https://github.com/readmeio/markdown/commit/c0a4d66723618a9bea8798e65006130015696bdf)) + +## Version 6.75.0-beta.31 + +### ✨ New & Improved + +* html blocks! ([#875](https://github.com/readmeio/markdown/issues/875)) ([1761667](https://github.com/readmeio/markdown/commit/17616676527c2b431b56fa9e607d27dbd9e3ebd4)) + +## Version 6.75.0-beta.30 + +### ✨ New & Improved + +* tables ([#874](https://github.com/readmeio/markdown/issues/874)) ([ec439ef](https://github.com/readmeio/markdown/commit/ec439ef36e869195c398ebce2c2b86d80be3d6c1)) + +## Version 6.75.0-beta.29 + +### ✨ New & Improved + +* image components! ([#857](https://github.com/readmeio/markdown/issues/857)) ([0e015ce](https://github.com/readmeio/markdown/commit/0e015ce7b461c6c544ef34a76e997ea65af7eee8)) + +## Version 6.75.0-beta.28 + +### ✨ New & Improved + +* **mdx:** gemoji ([#867](https://github.com/readmeio/markdown/issues/867)) ([21ff6f3](https://github.com/readmeio/markdown/commit/21ff6f3a16d9c6602daa6c8ed5af975e60756a12)) +* mdx code tabs ([#871](https://github.com/readmeio/markdown/issues/871)) ([7cc4d30](https://github.com/readmeio/markdown/commit/7cc4d309811265aba9ac031c000b3e527a4526df)) + + +### πŸ›  Fixes & Updates + +* update node-versions ([7d367a7](https://github.com/readmeio/markdown/commit/7d367a7532252c898089203e4e4839318fb19df8)) + +## Version 6.75.0-beta.27 + +### ✨ New & Improved + +* variables and glossary ([#865](https://github.com/readmeio/markdown/issues/865)) ([aeebd7c](https://github.com/readmeio/markdown/commit/aeebd7ccc51356bdcaf286c8becfa979ae7ce22b)) + +## Version 6.75.0-beta.26 + +### ✨ New & Improved + +* bump release ([f5dd329](https://github.com/readmeio/markdown/commit/f5dd329e159f105b2e5c3c78d5f68e667b58c266)) +* bump release ([#863](https://github.com/readmeio/markdown/issues/863)) ([a8bc8d8](https://github.com/readmeio/markdown/commit/a8bc8d83bdfa6b60bd51c2955a41f2ddcaee137a)) + + +### πŸ›  Fixes & Updates + +* update ci ([#860](https://github.com/readmeio/markdown/issues/860)) ([6f54f75](https://github.com/readmeio/markdown/commit/6f54f754dbe7ee906092de402a801ed6055e703b)) + +## Version 6.75.0-beta.25 + +### ✨ New & Improved + +* pass in react ([#859](https://github.com/readmeio/markdown/issues/859)) ([34d9bb6](https://github.com/readmeio/markdown/commit/34d9bb6ae876c1c87784579a3691a115b3512b92)) + +## Version 6.75.0-beta.24 + +### ✨ New & Improved + +* async run ([#858](https://github.com/readmeio/markdown/issues/858)) ([61a3e19](https://github.com/readmeio/markdown/commit/61a3e196d449e2df8393b1c7db56cf7901d54490)) + +## Version 6.75.0-beta.23 + +### ✨ New & Improved + +* force release ([073ac1d](https://github.com/readmeio/markdown/commit/073ac1db504046b36d1d3f8618c5dc12700cd19b)) + +## Version 6.75.0-beta.22 + +### ✨ New & Improved + +* update shighlighter ([3bbed6a](https://github.com/readmeio/markdown/commit/3bbed6a9268d0296486b4db7f3fcd6239d74b581)) + +## Version 6.75.0-beta.21 + +### ✨ New & Improved + +* fix package name ([82ffcfe](https://github.com/readmeio/markdown/commit/82ffcfe5c49e6a8215c8c9958b5faacc5b7e26b6)) + +## Version 6.75.0-beta.20 + +### ✨ New & Improved + +* package-lock ([6747a1f](https://github.com/readmeio/markdown/commit/6747a1fa94e26702377067cb058f75a0dadfc720)) + +## Version 6.75.0-beta.19 + +### ✨ New & Improved + +* revert updates ([98eafe7](https://github.com/readmeio/markdown/commit/98eafe745e4ecc3b8de53a730e0eb6d7f654419b)) + +## Version 6.75.0-beta.18 + +### ✨ New & Improved + +* build ([c3f2f5c](https://github.com/readmeio/markdown/commit/c3f2f5ce318bf8fb1f84c91a4154ae0ad839ff47)) + +## Version 6.75.0-beta.17 + +### ✨ New & Improved + +* add usemdxcomponents option ([#848](https://github.com/readmeio/markdown/issues/848)) ([48351a2](https://github.com/readmeio/markdown/commit/48351a2961fd57f18a869bd714ab42ea2817a2f9)) + +## Version 6.75.0-beta.16 + +### ✨ New & Improved + +* throw ([#844](https://github.com/readmeio/markdown/issues/844)) ([ecdba1b](https://github.com/readmeio/markdown/commit/ecdba1b4c6f7ef8396818c29f329c63aae570147)) + +## Version 6.75.0-beta.15 + +### ✨ New & Improved + +* rename react ot compile ([#843](https://github.com/readmeio/markdown/issues/843)) ([52111ce](https://github.com/readmeio/markdown/commit/52111cef8482c18e1ec3be333f71d90f46284b4d)) + +## Version 6.75.0-beta.14 + +### πŸ›  Fixes & Updates + +* callout headings ([#842](https://github.com/readmeio/markdown/issues/842)) ([da78ea2](https://github.com/readmeio/markdown/commit/da78ea2f7d868b71a277ed9f7e902324c0c4a6ad)) + +## Version 6.75.0-beta.13 + +### ✨ New & Improved + +* callouts ([#841](https://github.com/readmeio/markdown/issues/841)) ([02803ea](https://github.com/readmeio/markdown/commit/02803eac0bce745637659fbe18034655dd4dcad9)) + +## Version 6.75.0-beta.12 + +### ✨ New & Improved + +* cleanup ([42ae43f](https://github.com/readmeio/markdown/commit/42ae43fa6bfb60987bf3d6dfac9f0d78cc9f1a16)) + +## Version 6.75.0-beta.11 + +### ✨ New & Improved + +* actually use options ([3858c6e](https://github.com/readmeio/markdown/commit/3858c6e7682cd26804500104dc7c5daacc57fe5b)) + +## Version 6.75.0-beta.10 + +### ✨ New & Improved + +* oops ([277b626](https://github.com/readmeio/markdown/commit/277b62664ae086cacfccfabb5d8aadc717172add)) + +## Version 6.75.0-beta.9 + +### ✨ New & Improved + +* mdx callouts ([664dfc0](https://github.com/readmeio/markdown/commit/664dfc07b6b4a58a1b1ad67ec6efb434a2ceadab)) + +## Version 6.75.0-beta.8 + +### ✨ New & Improved + +* fix name, oops ([32f090a](https://github.com/readmeio/markdown/commit/32f090a660cb8493776526b1af52c038a748c3ca)) + +## Version 6.75.0-beta.7 + +### ✨ New & Improved + +* try umd ([ae038b1](https://github.com/readmeio/markdown/commit/ae038b1544a630b3c9b5218056a5195ec229de30)) + +## Version 6.75.0-beta.6 + +### ✨ New & Improved + +* import ([ed72644](https://github.com/readmeio/markdown/commit/ed72644b87c02e308e73de0069d647842910e852)) + +## Version 6.75.0-beta.5 + +### ✨ New & Improved + +* dont optimize? ([69c3a2e](https://github.com/readmeio/markdown/commit/69c3a2eb4a125ebd8352ff41b788be403ca95d9b)) + +## Version 6.75.0-beta.4 + +### ✨ New & Improved + +* add default?! ([160d78b](https://github.com/readmeio/markdown/commit/160d78b74e41a3c342fe20357d53798329e3d34e)) + +## Version 6.75.0-beta.3 + +### ✨ New & Improved + +* build ([7bede2e](https://github.com/readmeio/markdown/commit/7bede2e8cebb80a77d5160c67d89fc6947a47ae8)) + +## Version 6.75.0-beta.2 + +### ✨ New & Improved + +* build ([46aac0a](https://github.com/readmeio/markdown/commit/46aac0afd92b4d0318565b57ed845d1f8abe89a6)) + +## Version 6.75.0-beta.1 + +### πŸ“˜ Tests & Docs + +* tweaks ([6a4d831](https://github.com/readmeio/markdown/commit/6a4d831ee8b155c764a3c3e8dba0c0e282e6dba1)) + + +### ✨ New & Improved + +* compile + run ([aa95a65](https://github.com/readmeio/markdown/commit/aa95a65fae77fd9ffa7ec8a23b053aba4026c356)) +* initial commit ([201162a](https://github.com/readmeio/markdown/commit/201162a1590f1cb83b41fbef0541436d69720852)) +* mdx v1 ([a5faf6d](https://github.com/readmeio/markdown/commit/a5faf6d8202743340b320526db48bac936ae0331)) +* mdx v1 ([3250aff](https://github.com/readmeio/markdown/commit/3250aff9669481feb3cf7c839ec96ba98e3a2cda)) + + +### πŸ›  Fixes & Updates + +* ?? ([2e86b60](https://github.com/readmeio/markdown/commit/2e86b6087677f23901b220bb2de5c44440cd594e)) +* cleanup ([5bef7c4](https://github.com/readmeio/markdown/commit/5bef7c485142913c4fd161ebe4a6569c72348893)) +* cleanup ([ca4a841](https://github.com/readmeio/markdown/commit/ca4a841fbfcde172f85d4737f3dea572807dc505)) +* dont raise ([c4e8a51](https://github.com/readmeio/markdown/commit/c4e8a516494e3b01a43cb33e3148845e3ae5f8b5)) +* errors ([b6ed87e](https://github.com/readmeio/markdown/commit/b6ed87e0f80b32d5385d8c4ad23dea1fd4e3087b)) +* fix some build stuff ([7147bad](https://github.com/readmeio/markdown/commit/7147bad85f1f1db1b0317bfdae79affa6e07962e)) +* more deps + config ([b6cd0f1](https://github.com/readmeio/markdown/commit/b6cd0f1d349ae4faa83e7c473a68ea7407177c09)) +* more errors ([2518d47](https://github.com/readmeio/markdown/commit/2518d47570c354fb2177ba43c724417a921897c0)) +* reactProcessor ([a74109c](https://github.com/readmeio/markdown/commit/a74109cfda878ddb7997c80e2bc7c08002cee7c1)) +* render callouts ([aaf5a75](https://github.com/readmeio/markdown/commit/aaf5a75277e17da130e5041b89c665b036b1dff2)) +* render callouts + error boundary ([2dedb0a](https://github.com/readmeio/markdown/commit/2dedb0ab27b356902c2733066e5bab5c54b53fa0)) +* types error ([518f698](https://github.com/readmeio/markdown/commit/518f698f937f89b6eea26daaf672badb8a77fb05)) +* update demo styling ([bc7198e](https://github.com/readmeio/markdown/commit/bc7198e6c5c8573cec092554e5afe90d501ed8e0)) +* update error boundary ([589f23d](https://github.com/readmeio/markdown/commit/589f23d5aba70458d96d26ab2a0ae77397a7aa62)) +* update remark-parse version ([cd94111](https://github.com/readmeio/markdown/commit/cd94111ef9541dee8ba41eb8f31aef8351a1ace1)) + ## Version 6.74.2 ### πŸ›  Fixes & Updates diff --git a/Dockerfile b/Dockerfile index ae455b6f4..e1f462b5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,17 @@ ARG NODE_VERSION=18 -FROM node:${NODE_VERSION}-buster +FROM node:${NODE_VERSION}-alpine3.18 ARG NODE_VERSION ENV NODE_VERSION=$NODE_VERSION ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true -ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable - -RUN apt-get update && apt-get install -y \ - curl \ - gnupg \ - fonts-noto-color-emoji \ - && curl --location --silent https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ - && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ - && apt-get update \ - && apt-get install google-chrome-stable -y --no-install-recommends \ - && rm -rf /var/lib/apt/lists/* +ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser + +RUN apk update && apk add \ + make \ + font-noto-emoji \ + font-roboto \ + chromium RUN npm install -g npm@latest diff --git a/Dockerfile.legacy b/Dockerfile.legacy new file mode 100644 index 000000000..9e408ddfb --- /dev/null +++ b/Dockerfile.legacy @@ -0,0 +1,40 @@ +ARG NODE_VERSION=18 +FROM node:${NODE_VERSION}-alpine3.18 + +ARG NODE_VERSION +ENV NODE_VERSION=$NODE_VERSION + +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true +ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser + +ENV USE_LEGACY=true + +ARG REACT_VERSION +ENV REACT_VERSION=$REACT_VERSION + +RUN apk update && apk add \ + make \ + font-noto-emoji \ + font-roboto \ + chromium + +RUN npm install -g npm@latest + +ENV DOCKER_WORKSPACE=/markdown +WORKDIR ${DOCKER_WORKSPACE} + +COPY package.json package-lock.json ./ +RUN npm install + +RUN npm install react@${REACT_VERSION} react-dom@${REACT_VERSION} @testing-library/react@12 + +COPY . ./ + +RUN mkdir -p __tests__/browser/__image_snapshots__/__diff_output__ + +RUN make emojis + +EXPOSE 9966 + +CMD ["test.browser"] +ENTRYPOINT ["npm", "run"] diff --git a/Makefile b/Makefile index dc9aac87d..6c6c59733 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +-include .env + .DEFAULT_GOAL := help .PHONY: help .EXPORT_ALL_VARIABLES: @@ -14,8 +16,24 @@ example/public/img/emojis: node_modules/@readme/emojis mkdir -p example/public/img/emojis cp node_modules/@readme/emojis/src/img/*.png example/public/img/emojis/ +mdx: + npm run build && \ + cp -R dist/* ${README_PATH}/node_modules/@readme/mdx/dist && \ + cd ${README_PATH} && \ + npm run build --workspace=@readme/react && \ + npm run build --workspace=@readme/bundles && \ + npm run ui:build && \ + echo "${NODE_ENV}" > public/data/build-env && \ + npx ts-node ./bin/print-webpack-config.ts > ./build-time-webpack-config.json && \ + npm run ui + +ifeq ($(USE_LEGACY), true) +dockerfile = -f Dockerfile.legacy +endif + build: - docker build --platform linux/amd64 -t markdown . + @echo USE_LEGACY=$(USE_LEGACY) + docker build --platform linux/amd64 -t markdown $(dockerfile) --build-arg REACT_VERSION=${REACT_VERSION} . # This lets us call `make run test.browser`. Make expects cmdline args # to be targets. So this creates noop targets out of args. Copied from diff --git a/README.md b/README.md index 0ebbba35b..e6edaf151 100644 --- a/README.md +++ b/README.md @@ -10,42 +10,100 @@ npm install --save @readme/markdown ## Usage -By default, the updated markdown package exports a function which takes a string of [ReadMe-flavored markdown](https://docs.readme.com/rdmd/docs/syntax-extensions) and returns a tree of React components: - ```jsx import React from 'react'; -import rdmd from '@readme/markdown'; +import rmdx from '@readme/markdown'; -export default ({ body }) =>
{rdmd(body)}
; +export default ({ body }) =>
{run(compile(body))}
; ``` -### Export Methods +### API + +#### `compile` + +Compiles mdx to js. A wrapper around [`mdx.compile`](https://mdxjs.com/packages/mdx/#compilefile-options) + +You usually only need this when calling `run` as well. It's been left as a seperate step as a potential caching opportunity. + +###### Parameters + +- `string` (`string`) -- An mdx document +- `opts` ([`CompileOpts`](#compileopts), optional) -- configuration + +###### Returns + +compiled code (`string`) + +#### `run` + +Run compiled code. A wrapper around [`mdx.run`](https://mdxjs.com/packages/mdx/#runcode-options) + +> [!CAUTION] +> This `eval`'s JavaScript. + +###### Parameters + +- `string` (`string`) -- A compiled mdx document +- `opts` (`RunOpts`, optional) -- configuration + +###### Returns + +A module ([`RMDXModule`](#rmdxmodule)) of renderable components + +#### `mdx` + +Compiles an ast to mdx. + +#### `mdast` + +Parses mdx to an mdast. + +#### `hast` + +Parses mdx to an hast. + +#### `plain` + +> [!NOTE] +> unimplemented + +#### `utils` + +Additional defaults, helpers, components, etc. + +### `CompileOpts` + +Extends [`CompileOptions`](https://mdxjs.com/packages/mdx/#compileoptions) + +###### Additional Properties + +- `lazyImages` (`boolean`, optional) -- Load images lazily. +- `safeMode` (`boolean`, optional) -- Extract script tags from `HTMLBlock`s +- `components` (`Record`, optional) -- An object of tag names to mdx. +- `copyButtons` (`Boolean`, optional) β€” Automatically insert a button to copy a block of text to the clipboard. Currently used on `` elements. + +### `RunOpts` + +Extends [`RunOptions`](https://mdxjs.com/packages/mdx/#runoptions) -In addition to the default React processor, the package exports some other methods for transforming ReadMe-flavored markdown: +###### Additional Properties -| Export | Description | Arguments | -| --------: | :--------------------------------------------- | :---------------- | -| _`react`_ | _(default)_ returns a VDOM tree object | `text`, `options` | -| _`md`_ | transform mdast in to ReadMe-flavored markdown | `tree`, `options` | -| _`html`_ | transform markdown in to HTML | `text`, `options` | -| _`mdast`_ | transform markdown to an mdast object | `text`, `options` | -| _`hast`_ | transform markdown to HAST object | `text`, `options` | -| _`plain`_ | transform markdown to plain text | `text`, `options` | -| _`utils`_ | contexts, defaults, helpers, etc. | N/A | +- `components` (`Record`, optional) -- An object of tag names to executed components. +- `imports` (`Record`, optional) -- An object of modules to import. +- `terms` (`GlossaryTerm[]`, optional) +- `variables` (`Variables`, optional) -- An object containing [user variables}(https://github.com/readmeio/variable). -### Settings & Options +### `RMDXModule` -Each processor method takes an options object which you can use to adjust the output HTML or React tree. These options include: +###### Properties -- **`compatibilityMode`** β€” Enable [compatibility features](https://github.com/readmeio/api-explorer/issues/668) from our old markdown engine. -- **`copyButtons`** β€” Automatically insert a button to copy a block of text to the clipboard. Currently used on `` elements. -- **`correctnewlines`** β€” Render new line delimeters as `
` tags. -- **`markdownOptions`** β€” Remark [parser options](https://github.com/remarkjs/remark/tree/main/packages/remark-stringify#processorusestringify-options). -- **`safeMode`** β€” Render html blocks as `
` elements. We normally allow all manner of html attributes that could potentially execute JavaScript.
+- `default` (`() => MDXContent`) -- The mdx douments default export
+- `toc` (`HastHeading[]`) -- A list of headings in the document
+- `Toc` (`() => MDCContent`) -- A table of contents component
 
 ## Flavored Syntax
 
-Our old editor rendered "Magic Block" components from a custom, JSON-based syntax. To provide seamless backwards-compatibility, our new processor ships with built in support for parsing this old format, and transpiles it straight in to our new, flavored Markdown.
+~~Our old editor rendered "Magic Block" components from a custom, JSON-based syntax. To provide seamless backwards-compatibility, our new processor ships with built in support for parsing this old format, and transpiles it straight in to our new, flavored Markdown.~~
 
 We've also sprinkled a bit of our own syntactic sugar on top to let you supercharge your docs. [**Learn more about ReadMe's flavored syntax!**](https://docs.readme.com/rdmd/docs/syntax-extensions)
 
diff --git a/__tests__/.eslintrc b/__tests__/.eslintrc
index 01640e707..5bb0c851d 100644
--- a/__tests__/.eslintrc
+++ b/__tests__/.eslintrc
@@ -1,5 +1,5 @@
 {
-  "extends": "@readme/eslint-config/testing",
+  "extends": ["@readme/eslint-config/testing/jest.js", "@readme/eslint-config/testing/vitest.js"],
   "rules": {
     "testing-library/no-container": "off",
     "testing-library/no-node-access": "off"
diff --git a/__tests__/GlossaryItem.test.jsx b/__tests__/Glossary.test.tsx
similarity index 66%
rename from __tests__/GlossaryItem.test.jsx
rename to __tests__/Glossary.test.tsx
index 0a923d3e2..691f2a73e 100644
--- a/__tests__/GlossaryItem.test.jsx
+++ b/__tests__/Glossary.test.tsx
@@ -1,16 +1,18 @@
-const { render, fireEvent, screen } = require('@testing-library/react');
-const React = require('react');
+import { render, fireEvent, screen } from '@testing-library/react';
+import React from 'react';
 
-const { GlossaryItem } = require('../components/GlossaryItem');
+import { Glossary } from '../components/Glossary';
 
 test('should output a glossary item if the term exists', () => {
   const term = 'acme';
   const definition = 'This is a definition';
-  const { container } = render();
+  const { container } = render(acme);
 
   const trigger = container.querySelector('.GlossaryItem-trigger');
   expect(trigger).toHaveTextContent(term);
-  fireEvent.mouseEnter(trigger);
+  if (trigger) {
+    fireEvent.mouseEnter(trigger);
+  }
   const tooltipContent = screen.getByText(definition, { exact: false });
   expect(tooltipContent).toHaveTextContent(`${term} - ${definition}`);
 });
@@ -18,18 +20,20 @@ test('should output a glossary item if the term exists', () => {
 test('should be case insensitive', () => {
   const term = 'aCme';
   const definition = 'This is a definition';
-  const { container } = render();
+  const { container } = render(acme);
 
   const trigger = container.querySelector('.GlossaryItem-trigger');
   expect(trigger).toHaveTextContent('acme');
-  fireEvent.mouseEnter(trigger);
+  if (trigger) {
+    fireEvent.mouseEnter(trigger);
+  }
   const tooltipContent = screen.getByText(definition, { exact: false });
   expect(tooltipContent).toHaveTextContent(`${term} - ${definition}`);
 });
 
 test('should output the term if the definition does not exist', () => {
   const term = 'something';
-  const { container } = render();
+  const { container } = render({term});
 
   expect(container.querySelector('.GlossaryItem-trigger')).not.toBeInTheDocument();
   expect(container.querySelector('span')).toHaveTextContent(term);
diff --git a/__tests__/__snapshots__/compilers.test.ts.snap b/__tests__/__snapshots__/compilers.test.ts.snap
new file mode 100644
index 000000000..b8522bf29
--- /dev/null
+++ b/__tests__/__snapshots__/compilers.test.ts.snap
@@ -0,0 +1,6 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`ReadMe Flavored Blocks > Embed 1`] = `
+"[Embedded meta links.](https://nyti.me/s/gzoa2xb2v3 "@embed")
+"
+`;
diff --git a/__tests__/__snapshots__/disabling-tokenizers.test.js.snap b/__tests__/__snapshots__/disabling-tokenizers.test.js.snap
deleted file mode 100644
index b5500a8e9..000000000
--- a/__tests__/__snapshots__/disabling-tokenizers.test.js.snap
+++ /dev/null
@@ -1,331 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`disableTokenizers: "blocks" disabling block tokenizer 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 12,
-              "line": 1,
-              "offset": 11,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "# heading 1",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 12,
-          "line": 1,
-          "offset": 11,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 14,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
-
-exports[`disableTokenizers: "inlines" disabling delete 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 18,
-              "line": 1,
-              "offset": 17,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "~~strikethrough~~",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 18,
-          "line": 1,
-          "offset": 17,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 20,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
-
-exports[`disableTokenizers: "inlines" disabling emphasis 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 31,
-              "line": 1,
-              "offset": 30,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "*emphatic **strong** emphatic*",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 31,
-          "line": 1,
-          "offset": 30,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 33,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
-
-exports[`disableTokenizers: "inlines" disabling inlineCode 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 19,
-              "line": 1,
-              "offset": 18,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "\`const js = true \`",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 19,
-          "line": 1,
-          "offset": 18,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 21,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
-
-exports[`disableTokenizers: {} disables a block tokenizer 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 12,
-              "line": 1,
-              "offset": 11,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "# heading 1",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 12,
-          "line": 1,
-          "offset": 11,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 14,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
-
-exports[`disableTokenizers: {} disables an inline tokenizer 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "position": Position {
-            "end": Object {
-              "column": 18,
-              "line": 1,
-              "offset": 17,
-            },
-            "indent": Array [],
-            "start": Object {
-              "column": 1,
-              "line": 1,
-              "offset": 0,
-            },
-          },
-          "type": "text",
-          "value": "\`const js = true\`",
-        },
-      ],
-      "position": Position {
-        "end": Object {
-          "column": 18,
-          "line": 1,
-          "offset": 17,
-        },
-        "indent": Array [],
-        "start": Object {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "type": "paragraph",
-    },
-  ],
-  "position": Object {
-    "end": Object {
-      "column": 2,
-      "line": 3,
-      "offset": 20,
-    },
-    "start": Object {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "type": "root",
-}
-`;
diff --git a/__tests__/__snapshots__/flavored-compilers.test.js.snap b/__tests__/__snapshots__/flavored-compilers.test.js.snap
deleted file mode 100644
index 842fda325..000000000
--- a/__tests__/__snapshots__/flavored-compilers.test.js.snap
+++ /dev/null
@@ -1,167 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ReadMe Flavored Blocks Embed 1`] = `
-"[block:embed]
-{
-  \\"title\\": \\"Embedded meta links.\\",
-  \\"url\\": \\"https://nyti.me/s/gzoa2xb2v3\\",
-  \\"provider\\": \\"nyt\\"
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Callouts 1`] = `
-"> πŸ‘ Success
-> 
-> Vitae reprehenderit at aliquid error voluptates eum dignissimos.
-
-\`\`\`
-And this is a paragraph!
-\`\`\`
-"
-`;
-
-exports[`ReadMe Magic Blocks Code Tabs 1`] = `
-"\`\`\`javascript multiple.js
-console.log('a multi-file code block');
-\`\`\`
-\`\`\`javascript
-console.log('an unnamed sample snippet');
-\`\`\`
-"
-`;
-
-exports[`ReadMe Magic Blocks Embed 1`] = `
-"[block:embed]
-{
-  \\"html\\": false,
-  \\"url\\": \\"https://youtu.be/J3-uKv1DShQ\\",
-  \\"title\\": null,
-  \\"favicon\\": \\"https://youtu.be/favicon.ico\\",
-  \\"provider\\": \\"youtu.be\\",
-  \\"href\\": \\"https://youtu.be/J3-uKv1DShQ\\"
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Figure 1`] = `
-"[block:image]
-{
-  \\"images\\": [
-    {
-      \\"image\\": [
-        \\"https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg\\",
-        \\"rdme-blue.svg\\",
-        \\"Ok, __pizza__ man.\\"
-      ],
-      \\"sizing\\": \\"80\\",
-      \\"caption\\": \\"Ok, **pizza** man.\\"
-    }
-  ]
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Figure with alt text 1`] = `
-"[block:image]
-{
-  \\"images\\": [
-    {
-      \\"image\\": [
-        \\"https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg\\",
-        \\"rdme-blue.svg\\",
-        \\"A man eating pizza and making an OK gesture\\"
-      ],
-      \\"sizing\\": \\"80\\",
-      \\"caption\\": \\"Ok, **pizza** man.\\"
-    }
-  ]
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Image 1`] = `
-"![](https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg \\"rdme-blue.svg\\")
-"
-`;
-
-exports[`ReadMe Magic Blocks Image with sizing and alignment 1`] = `
-"[block:image]
-{
-  \\"images\\": [
-    {
-      \\"image\\": [
-        \\"https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg\\",
-        \\"rdme-blue.svg\\",
-        \\"\\"
-      ],
-      \\"align\\": \\"right\\",
-      \\"sizing\\": \\"80px\\"
-    }
-  ]
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Image with sizing and border 1`] = `
-"[block:image]
-{
-  \\"images\\": [
-    {
-      \\"image\\": [
-        \\"https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg\\",
-        \\"rdme-blue.svg\\",
-        \\"\\"
-      ],
-      \\"sizing\\": \\"80px\\",
-      \\"border\\": true
-    }
-  ]
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks Tables 1`] = `
-"|  th 1  |  th 2  |
-| :----: | :----: |
-| cell 1 | cell 2 |
-"
-`;
-
-exports[`ReadMe Magic Blocks Tables with breaks 1`] = `
-"[block:parameters]
-{
-  \\"data\\": {
-    \\"h-0\\": \\"th 1\\",
-    \\"h-1\\": \\"th 2\\",
-    \\"0-0\\": \\"cell 1  \\\\nafter the break\\",
-    \\"0-1\\": \\"cell 2\\"
-  },
-  \\"cols\\": 2,
-  \\"rows\\": 1,
-  \\"align\\": [
-    \\"center\\",
-    \\"center\\"
-  ]
-}
-[/block]
-"
-`;
-
-exports[`ReadMe Magic Blocks custom blocks 1`] = `
-"[block:tutorial-tile]
-{
-  \\"backgroundColor\\": \\"#ffffff\\",
-  \\"title\\": \\"Tutorial Title\\",
-  \\"emoji\\": \\"πŸ¦‰\\",
-  \\"link\\": \\"http://test.com\\"
-}
-[/block]
-"
-`;
diff --git a/__tests__/__snapshots__/flavored-parsers.test.js.snap b/__tests__/__snapshots__/flavored-parsers.test.js.snap
deleted file mode 100644
index 5236ed12b..000000000
--- a/__tests__/__snapshots__/flavored-parsers.test.js.snap
+++ /dev/null
@@ -1,160 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Parse RDMD Syntax Code Blocks Edge Cases Code blocks should keep spaces entered at start of first line 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "className": "tab-panel",
-          "data": Object {
-            "hName": "code",
-            "hProperties": Object {
-              "lang": "javascript",
-              "meta": "tab/a.js",
-            },
-          },
-          "lang": "javascript",
-          "meta": "tab/a.js",
-          "type": "code",
-          "value": "  function sayHello (state) {
-    console.log(state);
-  }
-
-export default sayHello;",
-        },
-        Object {
-          "className": "tab-panel",
-          "data": Object {
-            "hName": "code",
-            "hProperties": Object {
-              "lang": "javascript",
-              "meta": "tab/b.js",
-            },
-          },
-          "lang": "javascript",
-          "meta": "tab/b.js",
-          "type": "code",
-          "value": "import A from './a.js';
-
-A('Hello world!');",
-        },
-      ],
-      "className": "tabs",
-      "data": Object {
-        "hName": "div",
-        "hProperties": Object {
-          "className": Array [
-            "code-tabs",
-          ],
-        },
-      },
-      "type": "code-tabs",
-    },
-  ],
-  "type": "root",
-}
-`;
-
-exports[`Parse RDMD Syntax Code Blocks Single Code Block 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "lang": "javascript",
-      "meta": "single.js",
-      "type": "code",
-      "value": "console.log('a single-file code block');",
-    },
-  ],
-  "type": "root",
-}
-`;
-
-exports[`Parse RDMD Syntax Code Blocks Tabbed Code Block 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "children": Array [
-        Object {
-          "className": "tab-panel",
-          "data": Object {
-            "hName": "code",
-            "hProperties": Object {
-              "lang": "javascript",
-              "meta": "multiple.js",
-            },
-          },
-          "lang": "javascript",
-          "meta": "multiple.js",
-          "type": "code",
-          "value": "console.log('a multi-file code block');",
-        },
-        Object {
-          "className": "tab-panel",
-          "data": Object {
-            "hName": "code",
-            "hProperties": Object {
-              "lang": "javascript",
-              "meta": "",
-            },
-          },
-          "lang": "javascript",
-          "meta": "",
-          "type": "code",
-          "value": "console.log('an unnamed sample snippet');",
-        },
-      ],
-      "className": "tabs",
-      "data": Object {
-        "hName": "div",
-        "hProperties": Object {
-          "className": Array [
-            "code-tabs",
-          ],
-        },
-      },
-      "type": "code-tabs",
-    },
-    Object {
-      "children": Array [
-        Object {
-          "type": "text",
-          "value": "Β ",
-        },
-      ],
-      "type": "paragraph",
-    },
-  ],
-  "type": "root",
-}
-`;
-
-exports[`Parse RDMD Syntax Code Blocks allows indented code 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "lang": null,
-      "meta": null,
-      "type": "code",
-      "value": "  const shouldBeIndented = true;
-  if (shouldBeIndented) pass();",
-    },
-  ],
-  "type": "root",
-}
-`;
-
-exports[`Parse RDMD Syntax Code Blocks parses indented code blocks 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "lang": null,
-      "meta": null,
-      "type": "code",
-      "value": "const shouldBeIndented = true;
-if (shouldBeIndented) pass();",
-    },
-  ],
-  "type": "root",
-}
-`;
diff --git a/__tests__/__snapshots__/html-block-parser.test.js.snap b/__tests__/__snapshots__/html-block-parser.test.js.snap
index 7ad2be1e0..ee1ab3228 100644
--- a/__tests__/__snapshots__/html-block-parser.test.js.snap
+++ b/__tests__/__snapshots__/html-block-parser.test.js.snap
@@ -1,37 +1,68 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`Parse html block parses an html block 1`] = `
-Object {
-  "children": Array [
-    Object {
-      "block": true,
-      "position": Position {
-        "end": Object {
-          "column": 5,
-          "line": 3,
-          "offset": 32,
+exports[`Parse html block > parses an html block 1`] = `
+{
+  "children": [
+    {
+      "children": [
+        {
+          "attributes": [],
+          "children": [
+            {
+              "position": {
+                "end": {
+                  "column": 21,
+                  "line": 2,
+                  "offset": 21,
+                },
+                "start": {
+                  "column": 6,
+                  "line": 2,
+                  "offset": 6,
+                },
+              },
+              "type": "text",
+              "value": "Some block html",
+            },
+          ],
+          "name": "div",
+          "position": {
+            "end": {
+              "column": 27,
+              "line": 2,
+              "offset": 27,
+            },
+            "start": {
+              "column": 1,
+              "line": 2,
+              "offset": 1,
+            },
+          },
+          "type": "mdxJsxTextElement",
         },
-        "indent": Array [
-          1,
-        ],
-        "start": Object {
+      ],
+      "position": {
+        "end": {
+          "column": 27,
+          "line": 2,
+          "offset": 27,
+        },
+        "start": {
           "column": 1,
           "line": 2,
           "offset": 1,
         },
       },
-      "type": "html",
-      "value": "
Some block html
- ", + "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 5, - "offset": 35, + "position": { + "end": { + "column": 5, + "line": 3, + "offset": 32, }, - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, diff --git a/__tests__/__snapshots__/index.test.js.snap b/__tests__/__snapshots__/index.test.js.snap index ba04fa5cb..a7330bb0b 100644 --- a/__tests__/__snapshots__/index.test.js.snap +++ b/__tests__/__snapshots__/index.test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`anchor target: should allow _blank if using HTML 1`] = `"

test

"`; @@ -10,7 +10,7 @@ exports[`anchors 1`] = ` "

link
xss
doc
-ref
+ref
blog
changelog
page

" @@ -24,7 +24,7 @@ exports[`anchors with baseUrl 1`] = ` <a href=\\"page:slug\\">page</a></p>" `; -exports[`anchors with baseUrl and special characters in url hash 1`] = `"

ref

"`; +exports[`anchors with baseUrl and special characters in url hash 1`] = `"

ref

"`; exports[`check list items 1`] = ` "
    @@ -33,36 +33,50 @@ exports[`check list items 1`] = `
" `; -exports[`code samples should parse indented code on the first line 1`] = ` -Object { - "children": Array [ - Object { - "lang": null, - "meta": null, - "position": Position { - "end": Object { +exports[`code samples > should parse indented code on the first line 1`] = ` +{ + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": { + "column": 5, + "line": 1, + "offset": 4, + }, + }, + "type": "text", + "value": "const code = true;", + }, + ], + "position": { + "end": { "column": 23, "line": 1, "offset": 22, }, - "indent": Array [], - "start": Object { - "column": 1, + "start": { + "column": 5, "line": 1, - "offset": 0, + "offset": 4, }, }, - "type": "code", - "value": "const code = true;", + "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 25, + "position": { + "end": { + "column": 23, + "line": 1, + "offset": 22, }, - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, @@ -73,1107 +87,37 @@ Object { `; exports[`emojis 1`] = ` -"

\\":joy:\\"
+"

\\":joy:\\"

:unknown-emoji:

" `; -exports[`export multiple Markdown renderers allows complex compact headings 1`] = ` -"

Basic Text

-

πŸ™€ oh noes!

-

6. Oh No

-

Lorem ipsum dolor!

" -`; - -exports[`export multiple Markdown renderers renders HTML 1`] = ` -"

Hello World

- - - - - - - - - - - - +exports[`export multiple Markdown renderers > allows complex compact headings 1`] = `undefined`; +exports[`export multiple Markdown renderers > renders HTML 1`] = `undefined`; - - - - - - - - - - - -
Col. ACol. BCol. C
Cell A1Cell B1Cell C1
Cell A2Cell B2Cell C2
Cell A3Cell B3Cell C3
-

Embed Title

-

UhOh

Lorem ipsum dolor sit amet consectetur adipisicing elit.

" -`; - -exports[`export multiple Markdown renderers renders MD 1`] = ` +exports[`export multiple Markdown renderers > renders MD 1`] = ` "# Hello World " `; -exports[`export multiple Markdown renderers renders custom React components 1`] = ` - - -
- Hello World - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Col. A - - Col. B - - Col. C -
- Cell A1 - - Cell B1 - - Cell C1 -
- Cell A2 - - Cell B2 - - Cell C2 -
- Cell A3 - - Cell B3 - - Cell C3 -
- - -

- - - Embed Title - -

- - - -

- UhOh -

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

-
- -`; - -exports[`export multiple Markdown renderers renders hAST 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 14, - "line": 1, - "offset": 13, - }, - "start": Object { - "column": 3, - "line": 1, - "offset": 2, - }, - }, - "type": "text", - "value": "Hello World", - }, - ], - "position": Object { - "end": Object { - "column": 14, - "line": 1, - "offset": 13, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "properties": Object { - "id": "hello-world", - }, - "tagName": "h1", - "type": "element", - }, - Object { - "type": "text", - "value": " - - - - - - - - - - - - - - +exports[`export multiple Markdown renderers > renders custom React components 1`] = `[Function]`; +exports[`export multiple Markdown renderers > renders hAST 1`] = `undefined`; - - - - - - - - - -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 11, - "line": 3, - "offset": 25, - }, - "start": Object { - "column": 5, - "line": 3, - "offset": 19, - }, - }, - "type": "text", - "value": "Col. A", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 3, - "offset": 26, - }, - "start": Object { - "column": 5, - "line": 3, - "offset": 19, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 21, - "line": 3, - "offset": 35, - }, - "start": Object { - "column": 15, - "line": 3, - "offset": 29, - }, - }, - "type": "text", - "value": "Col. B", - }, - ], - "position": Object { - "end": Object { - "column": 22, - "line": 3, - "offset": 36, - }, - "start": Object { - "column": 15, - "line": 3, - "offset": 29, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 31, - "line": 3, - "offset": 45, - }, - "start": Object { - "column": 25, - "line": 3, - "offset": 39, - }, - }, - "type": "text", - "value": "Col. C", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 3, - "offset": 46, - }, - "start": Object { - "column": 25, - "line": 3, - "offset": 39, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "th", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 3, - "offset": 48, - }, - "start": Object { - "column": 1, - "line": 3, - "offset": 15, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 3, - "offset": 48, - }, - "start": Object { - "column": 1, - "line": 3, - "offset": 15, - }, - }, - "properties": Object {}, - "tagName": "thead", - "type": "element", - "value": "Col. A Col. B Col. C", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 12, - "line": 5, - "offset": 94, - }, - "start": Object { - "column": 5, - "line": 5, - "offset": 87, - }, - }, - "type": "text", - "value": "Cell A1", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 5, - "offset": 94, - }, - "start": Object { - "column": 5, - "line": 5, - "offset": 87, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 22, - "line": 5, - "offset": 104, - }, - "start": Object { - "column": 15, - "line": 5, - "offset": 97, - }, - }, - "type": "text", - "value": "Cell B1", - }, - ], - "position": Object { - "end": Object { - "column": 22, - "line": 5, - "offset": 104, - }, - "start": Object { - "column": 15, - "line": 5, - "offset": 97, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 32, - "line": 5, - "offset": 114, - }, - "start": Object { - "column": 25, - "line": 5, - "offset": 107, - }, - }, - "type": "text", - "value": "Cell C1", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 5, - "offset": 114, - }, - "start": Object { - "column": 25, - "line": 5, - "offset": 107, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 5, - "offset": 116, - }, - "start": Object { - "column": 1, - "line": 5, - "offset": 83, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 12, - "line": 6, - "offset": 128, - }, - "start": Object { - "column": 5, - "line": 6, - "offset": 121, - }, - }, - "type": "text", - "value": "Cell A2", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 6, - "offset": 128, - }, - "start": Object { - "column": 5, - "line": 6, - "offset": 121, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 22, - "line": 6, - "offset": 138, - }, - "start": Object { - "column": 15, - "line": 6, - "offset": 131, - }, - }, - "type": "text", - "value": "Cell B2", - }, - ], - "position": Object { - "end": Object { - "column": 22, - "line": 6, - "offset": 138, - }, - "start": Object { - "column": 15, - "line": 6, - "offset": 131, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 32, - "line": 6, - "offset": 148, - }, - "start": Object { - "column": 25, - "line": 6, - "offset": 141, - }, - }, - "type": "text", - "value": "Cell C2", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 6, - "offset": 148, - }, - "start": Object { - "column": 25, - "line": 6, - "offset": 141, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 6, - "offset": 150, - }, - "start": Object { - "column": 1, - "line": 6, - "offset": 117, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 12, - "line": 7, - "offset": 162, - }, - "start": Object { - "column": 5, - "line": 7, - "offset": 155, - }, - }, - "type": "text", - "value": "Cell A3", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 7, - "offset": 162, - }, - "start": Object { - "column": 5, - "line": 7, - "offset": 155, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 22, - "line": 7, - "offset": 172, - }, - "start": Object { - "column": 15, - "line": 7, - "offset": 165, - }, - }, - "type": "text", - "value": "Cell B3", - }, - ], - "position": Object { - "end": Object { - "column": 22, - "line": 7, - "offset": 172, - }, - "start": Object { - "column": 15, - "line": 7, - "offset": 165, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 32, - "line": 7, - "offset": 182, - }, - "start": Object { - "column": 25, - "line": 7, - "offset": 175, - }, - }, - "type": "text", - "value": "Cell C3", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 7, - "offset": 182, - }, - "start": Object { - "column": 25, - "line": 7, - "offset": 175, - }, - }, - "properties": Object { - "align": "center", - }, - "tagName": "td", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 7, - "offset": 184, - }, - "start": Object { - "column": 1, - "line": 7, - "offset": 151, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 7, - "offset": 184, - }, - "start": Object { - "column": 1, - "line": 5, - "offset": 83, - }, - }, - "properties": Object {}, - "tagName": "tbody", - "type": "element", - "value": "Cell A1 Cell B1 Cell C1 Cell A2 Cell B2 Cell C2 Cell A3 Cell B3 Cell C3", - }, - ], - "position": Object { - "end": Object { - "column": 34, - "line": 7, - "offset": 184, - }, - "start": Object { - "column": 1, - "line": 3, - "offset": 15, - }, - }, - "properties": Object {}, - "tagName": "table", - "type": "element", - }, - Object { - "type": "text", - "value": " -", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 3, - "line": 9, - "offset": 188, - }, - "start": Object { - "column": 1, - "line": 9, - "offset": 186, - }, - }, - "type": "text", - "value": " ", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 15, - "line": 9, - "offset": 200, - }, - "start": Object { - "column": 4, - "line": 9, - "offset": 189, - }, - }, - "type": "text", - "value": "Embed Title", - }, - ], - "position": Object { - "end": Object { - "column": 67, - "line": 9, - "offset": 252, - }, - "start": Object { - "column": 3, - "line": 9, - "offset": 188, - }, - }, - "properties": Object { - "href": "https://jsfiddle.net/rafegoldberg/5VA5j/", - "title": "@embed", - }, - "tagName": "a", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 67, - "line": 9, - "offset": 252, - }, - "start": Object { - "column": 1, - "line": 9, - "offset": 186, - }, - }, - "properties": Object {}, - "tagName": "p", - "type": "element", - }, - Object { - "type": "text", - "value": " -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 9, - "line": 11, - "offset": 262, - }, - "start": Object { - "column": 5, - "line": 11, - "offset": 258, - }, - }, - "type": "text", - "value": "UhOh", - }, - ], - "position": Object { - "end": Object { - "column": 9, - "line": 11, - "offset": 262, - }, - "start": Object { - "column": 5, - "line": 11, - "offset": 258, - }, - }, - "properties": Object {}, - "tagName": "p", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 61, - "line": 11, - "offset": 314, - }, - "start": Object { - "column": 5, - "line": 11, - "offset": 258, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Object { - "end": Object { - "column": 61, - "line": 11, - "offset": 314, - }, - "start": Object { - "column": 5, - "line": 11, - "offset": 258, - }, - }, - "properties": Object {}, - "tagName": "p", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 61, - "line": 13, - "offset": 330, - }, - "start": Object { - "column": 1, - "line": 11, - "offset": 254, - }, - }, - "properties": Object { - "icon": "❗️", - "theme": "error", - "title": "UhOh", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - "tagName": "rdme-callout", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 18, - "offset": 338, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`export multiple Markdown renderers renders mdAST 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { +exports[`export multiple Markdown renderers > renders mdAST 1`] = ` +{ + "children": [ + { + "children": [ + { + "position": { + "end": { "column": 14, "line": 1, "offset": 13, }, - "indent": Array [], - "start": Object { + "start": { "column": 3, "line": 1, "offset": 2, @@ -1183,21 +127,14 @@ Object { "value": "Hello World", }, ], - "data": Object { - "hProperties": Object { - "id": "hello-world", - }, - "id": "hello-world", - }, "depth": 1, - "position": Position { - "end": Object { + "position": { + "end": { "column": 14, "line": 1, "offset": 13, }, - "indent": Array [], - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, @@ -1205,556 +142,55 @@ Object { }, "type": "heading", }, - Object { - "align": Array [ - "center", - "center", - "center", - ], - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 11, - "line": 3, - "offset": 25, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 19, - }, - }, - "type": "text", - "value": "Col. A", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 3, - "offset": 26, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 19, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 21, - "line": 3, - "offset": 35, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 3, - "offset": 29, - }, - }, - "type": "text", - "value": "Col. B", - }, - ], - "position": Position { - "end": Object { - "column": 22, - "line": 3, - "offset": 36, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 3, - "offset": 29, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 31, - "line": 3, - "offset": 45, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 3, - "offset": 39, - }, - }, - "type": "text", - "value": "Col. C", - }, - ], - "position": Position { - "end": Object { - "column": 32, - "line": 3, - "offset": 46, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 3, - "offset": 39, - }, - }, - "type": "tableCell", - }, - ], - "position": Position { - "end": Object { - "column": 34, - "line": 3, - "offset": 48, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 3, - "offset": 15, - }, - }, - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 12, - "line": 5, - "offset": 94, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 5, - "offset": 87, - }, - }, - "type": "text", - "value": "Cell A1", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 5, - "offset": 94, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 5, - "offset": 87, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 22, - "line": 5, - "offset": 104, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 5, - "offset": 97, - }, - }, - "type": "text", - "value": "Cell B1", - }, - ], - "position": Position { - "end": Object { - "column": 22, - "line": 5, - "offset": 104, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 5, - "offset": 97, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 32, - "line": 5, - "offset": 114, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 5, - "offset": 107, - }, - }, - "type": "text", - "value": "Cell C1", - }, - ], - "position": Position { - "end": Object { - "column": 32, - "line": 5, - "offset": 114, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 5, - "offset": 107, - }, - }, - "type": "tableCell", - }, - ], - "position": Position { - "end": Object { - "column": 34, - "line": 5, - "offset": 116, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 5, - "offset": 83, - }, - }, - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 12, - "line": 6, - "offset": 128, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 6, - "offset": 121, - }, - }, - "type": "text", - "value": "Cell A2", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 6, - "offset": 128, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 6, - "offset": 121, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 22, - "line": 6, - "offset": 138, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 6, - "offset": 131, - }, - }, - "type": "text", - "value": "Cell B2", - }, - ], - "position": Position { - "end": Object { - "column": 22, - "line": 6, - "offset": 138, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 6, - "offset": 131, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 32, - "line": 6, - "offset": 148, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 6, - "offset": 141, - }, - }, - "type": "text", - "value": "Cell C2", - }, - ], - "position": Position { - "end": Object { - "column": 32, - "line": 6, - "offset": 148, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 6, - "offset": 141, - }, - }, - "type": "tableCell", - }, - ], - "position": Position { - "end": Object { - "column": 34, - "line": 6, - "offset": 150, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 6, - "offset": 117, - }, - }, - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 12, - "line": 7, - "offset": 162, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 7, - "offset": 155, - }, - }, - "type": "text", - "value": "Cell A3", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 7, - "offset": 162, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 7, - "offset": 155, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 22, - "line": 7, - "offset": 172, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 7, - "offset": 165, - }, - }, - "type": "text", - "value": "Cell B3", - }, - ], - "position": Position { - "end": Object { - "column": 22, - "line": 7, - "offset": 172, - }, - "indent": Array [], - "start": Object { - "column": 15, - "line": 7, - "offset": 165, - }, - }, - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 32, - "line": 7, - "offset": 182, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 7, - "offset": 175, - }, - }, - "type": "text", - "value": "Cell C3", - }, - ], - "position": Position { - "end": Object { - "column": 32, - "line": 7, - "offset": 182, - }, - "indent": Array [], - "start": Object { - "column": 25, - "line": 7, - "offset": 175, - }, - }, - "type": "tableCell", - }, - ], - "position": Position { - "end": Object { + { + "children": [ + { + "position": { + "end": { "column": 34, "line": 7, "offset": 184, }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 7, - "offset": 151, + "start": { + "column": 3, + "line": 3, + "offset": 17, }, }, - "type": "tableRow", + "type": "text", + "value": "| Col. A | Col. B | Col. C | +|:-------:|:-------:|:-------:| +| Cell A1 | Cell B1 | Cell C1 | +| Cell A2 | Cell B2 | Cell C2 | +| Cell A3 | Cell B3 | Cell C3 |", }, ], - "position": Position { - "end": Object { + "position": { + "end": { "column": 34, "line": 7, "offset": 184, }, - "indent": Array [ - 1, - 1, - 1, - 1, - ], - "start": Object { - "column": 1, + "start": { + "column": 3, "line": 3, - "offset": 15, + "offset": 17, }, }, - "type": "table", + "type": "paragraph", }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 3, - "line": 9, - "offset": 188, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 9, - "offset": 186, - }, - }, - "type": "text", - "value": " ", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { + { + "children": [ + { + "children": [ + { + "position": { + "end": { "column": 15, "line": 9, "offset": 200, }, - "indent": Array [], - "start": Object { + "start": { "column": 4, "line": 9, "offset": 189, @@ -1764,14 +200,13 @@ Object { "value": "Embed Title", }, ], - "position": Position { - "end": Object { + "position": { + "end": { "column": 67, "line": 9, "offset": 252, }, - "indent": Array [], - "start": Object { + "start": { "column": 3, "line": 9, "offset": 188, @@ -1782,51 +217,48 @@ Object { "url": "https://jsfiddle.net/rafegoldberg/5VA5j/", }, ], - "position": Position { - "end": Object { + "position": { + "end": { "column": 67, "line": 9, "offset": 252, }, - "indent": Array [], - "start": Object { - "column": 1, + "start": { + "column": 3, "line": 9, - "offset": 186, + "offset": 188, }, }, "type": "paragraph", }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 9, + { + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 12, "line": 11, - "offset": 262, + "offset": 265, }, - "indent": Array [], - "start": Object { + "start": { "column": 5, "line": 11, "offset": 258, }, }, "type": "text", - "value": "UhOh", + "value": "❗️ UhOh", }, ], - "position": Position { - "end": Object { - "column": 9, + "position": { + "end": { + "column": 12, "line": 11, - "offset": 262, + "offset": 265, }, - "indent": Array [], - "start": Object { + "start": { "column": 5, "line": 11, "offset": 258, @@ -1834,77 +266,62 @@ Object { }, "type": "paragraph", }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { + { + "children": [ + { + "position": { + "end": { "column": 61, - "line": 11, - "offset": 314, + "line": 13, + "offset": 330, }, - "indent": Array [], - "start": Object { + "start": { "column": 5, - "line": 11, - "offset": 258, + "line": 13, + "offset": 274, }, }, "type": "text", "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", }, ], - "position": Position { - "end": Object { + "position": { + "end": { "column": 61, - "line": 11, - "offset": 314, + "line": 13, + "offset": 330, }, - "indent": Array [], - "start": Object { + "start": { "column": 5, - "line": 11, - "offset": 258, + "line": 13, + "offset": 274, }, }, "type": "paragraph", }, ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "❗️", - "theme": "error", - "title": "UhOh", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { + "position": { + "end": { "column": 61, "line": 13, "offset": 330, }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, + "start": { + "column": 3, "line": 11, - "offset": 254, + "offset": 256, }, }, - "type": "rdme-callout", + "type": "blockquote", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 18, - "offset": 338, + "position": { + "end": { + "column": 3, + "line": 16, + "offset": 335, }, - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, @@ -1914,196 +331,11 @@ Object { } `; -exports[`export multiple Markdown renderers renders plain markdown as React 1`] = ` - -

- Hello World -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Col. A - - Col. B - - Col. C -
- Cell A1 - - Cell B1 - - Cell C1 -
- Cell A2 - - Cell B2 - - Cell C2 -
- Cell A3 - - Cell B3 - - Cell C3 -
- - -

- - - Embed Title - -

- - - -

- UhOh -

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

-
-
-`; - -exports[`export multiple Markdown renderers renders plainText from AST 1`] = `"Hello World"`; +exports[`export multiple Markdown renderers > renders plain markdown as React 1`] = `undefined`; exports[`heading 1`] = `"

Example Header

"`; -exports[`image 1`] = `"

\\"Image\\"

"`; +exports[`image 1`] = `"Image"`; exports[`list items 1`] = ` "
    @@ -2111,8 +343,6 @@ exports[`list items 1`] = `
" `; -exports[`magic image 1`] = `"
\\"A

A guy. Eating pizza. And making an OK gesture.

"`; - -exports[`prefix anchors with "section-" should add a section- prefix to heading anchors 1`] = `"

heading

"`; +exports[`prefix anchors with "section-" > should add a section- prefix to heading anchors 1`] = `undefined`; -exports[`tables 1`] = `"
TablesAreCool
col 3 isright-aligned$1600
col 2 iscentered$12
zebra stripesare neat$1
"`; +exports[`tables 1`] = `"
TablesAreCool
col 3 isright-aligned$1600
col 2 iscentered$12
zebra stripesare neat$1
"`; diff --git a/__tests__/__snapshots__/link-parsers.test.js.snap b/__tests__/__snapshots__/link-parsers.test.js.snap index a4f7cde23..a29f2b323 100644 --- a/__tests__/__snapshots__/link-parsers.test.js.snap +++ b/__tests__/__snapshots__/link-parsers.test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`a bare autoLinked url 1`] = ` Object { @@ -8,69 +8,18 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 21, - "line": 1, - "offset": 20, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "text", "value": "http://www.googl.com", }, ], - "position": Position { - "end": Object { - "column": 21, - "line": 1, - "offset": 20, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "title": null, "type": "link", "url": "http://www.googl.com", }, ], - "position": Position { - "end": Object { - "column": 21, - "line": 1, - "offset": 20, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 23, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; @@ -107,69 +56,18 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 23, - "line": 1, - "offset": 22, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 1, - "offset": 1, - }, - }, "type": "text", "value": "http://www.google.com", }, ], - "position": Position { - "end": Object { - "column": 24, - "line": 1, - "offset": 23, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "title": null, "type": "link", "url": "http://www.google.com", }, ], - "position": Position { - "end": Object { - "column": 24, - "line": 1, - "offset": 23, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 26, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; @@ -182,70 +80,19 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 6, - "line": 1, - "offset": 5, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 1, - "offset": 1, - }, - }, "type": "text", "value": "link", }, ], "identifier": "link", "label": "link", - "position": Position { - "end": Object { - "column": 7, - "line": 1, - "offset": 6, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "referenceType": "shortcut", "type": "linkReference", }, ], - "position": Position { - "end": Object { - "column": 7, - "line": 1, - "offset": 6, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 9, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; @@ -258,90 +105,26 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 6, - "line": 1, - "offset": 5, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 1, - "offset": 1, - }, - }, "type": "text", "value": "link", }, ], "identifier": "link", "label": "link", - "position": Position { - "end": Object { - "column": 7, - "line": 1, - "offset": 6, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "referenceType": "shortcut", "type": "linkReference", }, ], - "position": Position { - "end": Object { - "column": 7, - "line": 1, - "offset": 6, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, Object { "identifier": "link", "label": "link", - "position": Position { - "end": Object { - "column": 24, - "line": 3, - "offset": 31, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 3, - "offset": 8, - }, - }, "title": null, "type": "definition", "url": "www.example.com", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 5, - "offset": 34, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; @@ -354,69 +137,18 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 6, - "line": 1, - "offset": 5, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 1, - "offset": 1, - }, - }, "type": "text", "value": "link", }, ], - "position": Position { - "end": Object { - "column": 27, - "line": 1, - "offset": 26, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "title": null, "type": "link", "url": "http://www.foo.com", }, ], - "position": Position { - "end": Object { - "column": 27, - "line": 1, - "offset": 26, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 29, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; @@ -429,69 +161,18 @@ Object { Object { "children": Array [ Object { - "position": Position { - "end": Object { - "column": 6, - "line": 1, - "offset": 5, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 1, - "offset": 1, - }, - }, "type": "text", "value": "link", }, ], - "position": Position { - "end": Object { - "column": 9, - "line": 1, - "offset": 8, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "title": null, "type": "link", "url": "", }, ], - "position": Position { - "end": Object { - "column": 9, - "line": 1, - "offset": 8, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "paragraph", }, ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 11, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, "type": "root", } `; diff --git a/__tests__/__snapshots__/magic-block-parser.test.js.snap b/__tests__/__snapshots__/magic-block-parser.test.js.snap deleted file mode 100644 index c0367115e..000000000 --- a/__tests__/__snapshots__/magic-block-parser.test.js.snap +++ /dev/null @@ -1,640 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Blank Magic Blocks 1`] = ` -Object { - "children": Array [], - "type": "root", -} -`; - -exports[`Blank Magic Blocks 2`] = ` -Object { - "children": Array [ - Object { - "children": Array [], - "depth": 2, - "type": "heading", - }, - ], - "type": "root", -} -`; - -exports[`Blank Magic Blocks 3`] = ` -Object { - "children": Array [ - Object { - "children": Array [], - "depth": 2, - "type": "heading", - }, - ], - "type": "root", -} -`; - -exports[`Blank Magic Blocks 4`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "No Level", - }, - ], - "depth": 2, - "type": "heading", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Block with invalid JSON 1`] = ` -Object { - "children": Array [], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Callout Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Callout Title", - }, - ], - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Lorem ipsum dolor sit amet, ", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "consectetur", - }, - ], - "type": "emphasis", - }, - Object { - "type": "text", - "value": " adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum", - }, - ], - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ‘", - "theme": "okay", - "title": "Callout Title", - "value": "Lorem ipsum dolor sit amet, _consectetur_ adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum", - }, - }, - "type": "rdme-callout", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Code Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": "javascript", - "meta": null, - }, - }, - "lang": "javascript", - "meta": null, - "type": "code", - "value": "$http.post('/someUrl', data).success(successCallback); - -alert('test');", - }, - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": "text", - "meta": "custom title", - }, - }, - "lang": "text", - "meta": "custom title", - "type": "code", - "value": "second tab", - }, - ], - "className": "tabs", - "data": Object { - "hName": "code-tabs", - }, - "type": "code-tabs", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": "javascript", - "meta": null, - }, - }, - "lang": "javascript", - "meta": null, - "type": "code", - "value": "$http.post('/someUrl', data).success(successCallback); - -alert('test');", - }, - ], - "className": "tabs", - "data": Object { - "hName": "code-tabs", - }, - "type": "code-tabs", - }, - ], - "data": Object { - "className": "pin", - "hName": "rdme-pin", - }, - "type": "rdme-pin", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Custom Callout Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Callout Title", - }, - ], - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Lorem ipsum dolor sit amet...", - }, - ], - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "✨", - "theme": "custom_theme", - "title": "Callout Title", - "value": "Lorem ipsum dolor sit amet...", - }, - }, - "type": "rdme-callout", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Custom Default Block 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [], - "data": Object { - "backgroundColor": "#ffffff", - "emoji": "πŸ¦‰", - "hName": "tutorial-tile", - "hProperties": Object { - "backgroundColor": "#ffffff", - "emoji": "πŸ¦‰", - "link": "http://test.com", - "title": "Tutorial Title", - }, - "link": "http://test.com", - "title": "Tutorial Title", - }, - "type": "div", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Custom HTML Block 1`] = ` -Object { - "children": Array [ - Object { - "data": Object { - "hName": "html-block", - "hProperties": Object { - "html": "

πŸ‘‹πŸŒ

-
-
- -
- Go -
", - "runScripts": null, - "safeMode": null, - }, - }, - "type": "html-block", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Embed Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": null, - }, - ], - "title": "youtu.be", - "type": "link", - "url": "https://youtu.be/J3-uKv1DShQ", - }, - ], - "data": Object { - "hName": "rdme-embed", - "hProperties": Object { - "favicon": "https://youtu.be/favicon.ico", - "href": "https://youtu.be/J3-uKv1DShQ", - "html": false, - "iframe": false, - "provider": "youtu.be", - "title": null, - "url": "https://youtu.be/J3-uKv1DShQ", - }, - }, - "type": "embed", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Embed Blocks with empty URL 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": undefined, - }, - ], - "title": "", - "type": "link", - "url": "", - }, - ], - "data": Object { - "hName": "rdme-embed", - "hProperties": Object { - "href": "", - "html": undefined, - "provider": "", - "title": undefined, - "typeOfEmbed": "youtube", - "url": "", - }, - }, - "type": "embed", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Embed Blocks with invalid URL 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": null, - }, - ], - "title": "www.youtu.be/J3-uKv1DShQ", - "type": "link", - "url": "www.youtu.be/J3-uKv1DShQ", - }, - ], - "data": Object { - "hName": "rdme-embed", - "hProperties": Object { - "favicon": "https://youtu.be/favicon.ico", - "href": "www.youtu.be/J3-uKv1DShQ", - "html": false, - "iframe": false, - "provider": "www.youtu.be/J3-uKv1DShQ", - "title": null, - "url": "www.youtu.be/J3-uKv1DShQ", - }, - }, - "type": "embed", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Heading Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "MagicBlock Conversion", - }, - ], - "depth": 2, - "type": "heading", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Image Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "alt": "Qui iusto fugiat doloremque? Facilis obcaecati vitae corrupti.", - "data": Object { - "hProperties": Object { - "align": "center", - "className": "border", - "width": "80%", - }, - }, - "title": "White Center Blue BG.svg", - "type": "image", - "url": "https://files.readme.io/62083ee-White_Center_Blue_BG.svg", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Qui iusto fugiat doloremque? Facilis obcaecati vitae corrupti.", - }, - ], - "type": "paragraph", - }, - ], - "data": Object { - "hName": "figcaption", - }, - "type": "figcaption", - }, - ], - "data": Object { - "hName": "figure", - }, - "type": "figure", - "url": "https://files.readme.io/62083ee-White_Center_Blue_BG.svg", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Table Blocks 1`] = ` -Object { - "children": Array [ - Object { - "align": Array [ - "left", - "left", - "left", - ], - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Left", - }, - ], - "type": "tableHead", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Center", - }, - ], - "type": "tableHead", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Right", - }, - ], - "type": "tableHead", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "L0", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "bold", - }, - ], - "type": "emphasis", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "$1600", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "L1", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "inlineCode", - "value": "code", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "$12", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "L2", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "italic", - }, - ], - "type": "emphasis", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "$1", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - ], - "type": "table", - }, - ], - "type": "root", -} -`; - -exports[`Parse Magic Blocks Unrecognized Blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [], - "data": Object { - "body": "Lorem ipsum dolor sit amet, _consectetur_ adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum", - "color": "#f00", - "hName": "unrecognized", - "hProperties": Object { - "body": "Lorem ipsum dolor sit amet, _consectetur_ adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum", - "color": "#f00", - "title": "Title", - }, - "title": "Title", - }, - "type": "div", - }, - ], - "type": "root", -} -`; - -exports[`Sanitize Schema 1`] = ` -Object { - "attributes": Array [], -} -`; diff --git a/__tests__/astToPlainText.test.js b/__tests__/astToPlainText.test.js deleted file mode 100644 index 77cd11958..000000000 --- a/__tests__/astToPlainText.test.js +++ /dev/null @@ -1,119 +0,0 @@ -import { hast, astToPlainText } from '../index'; - -const find = (node, matcher) => { - if (matcher(node)) return node; - if (node.children) { - return node.children.find(child => find(child, matcher)); - } - - return null; -}; - -describe('astToPlainText()', () => { - it("converts br's to ''", () => { - const txt = '
'; - - expect(astToPlainText(hast(txt))).toBe(''); - }); - - it("converts hr's to ''", () => { - const txt = '
'; - - expect(astToPlainText(hast(txt))).toBe(''); - }); - - it('converts flavored callouts', () => { - const txt = ` -> πŸ“˜ Title -> -> Some body - `; - - expect(astToPlainText(hast(txt))).toBe('Title Some body'); - }); - - it('converts markdown tables', () => { - const txt = ` -| Header 1 | Header 2 | -| :------- | :------- | -| Cell 1 | Cell 2 | - `; - - expect(astToPlainText(hast(txt))).toBe('Header 1 Header 2 Cell 1 Cell 2'); - }); - - it('converts magic block tables', () => { - const txt = ` -[block:parameters] -${JSON.stringify( - { - data: { - 'h-0': 'Header 1', - 'h-1': 'Header 2', - '0-0': 'Cell 1', - '0-1': 'Cell 2 \nCell 2.1', - }, - cols: 2, - rows: 1, - align: ['left', 'left', 'left'], - }, - null, - 2 -)} -[/block] - `; - - expect(astToPlainText(hast(txt))).toBe('Header 1 Header 2 Cell 1 Cell 2 Cell 2.1'); - }); - - it('converts images', () => { - const txt = ` -![image **label**](http://placekitten.com/600/600 "entitled kittens") - `; - - expect(astToPlainText(hast(txt))).toBe('entitled kittens'); - }); - - it('converts a single image', () => { - const txt = ` -![image **label**](http://placekitten.com/600/600 "entitled kittens") - `; - const ast = hast(txt); - - expect(astToPlainText(find(ast, n => n.tagName === 'img'))).toBe('entitled kittens'); - }); - - it('converts magic block images', () => { - const txt = ` - [block:image] - { - "images": [ - { - "image": ["https://files.readme.io/test.png", "Test Image Title", 100, 100, "#fff"] - } - ] - } - [/block] - `; - - expect(astToPlainText(hast(txt))).toBe('Test Image Title'); - }); - - it('converts a lone magic block image', () => { - const txt = ` - [block:image] - { - "images": [ - { - "image": ["https://files.readme.io/test.png", "Test Image Title", 100, 100, "#fff"] - } - ] - } - [/block] - `; - const tree = hast(txt); - const img = find(tree, n => n.tagName === 'img'); - - expect(astToPlainText(img)).toBe('Test Image Title'); - }); -}); diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png index 39fd1371f..8e435f209 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-block-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-block-tests-without-surprises-1-snap.png index 14d03ee80..3b0c01d05 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-block-tests-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-block-tests-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-blocks-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-blocks-without-surprises-1-snap.png index 9d0b9c7ba..47b947cb8 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-blocks-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-code-blocks-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png index 62cb9cba0..2e3a9e36e 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png new file mode 100644 index 000000000..64217a585 Binary files /dev/null and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-images-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-images-without-surprises-1-snap.png index 760308885..9ddcf06b2 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-images-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-images-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-mdx-components-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-mdx-components-without-surprises-1-snap.png new file mode 100644 index 000000000..8c9e245d8 Binary files /dev/null and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-mdx-components-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-tables-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-tables-without-surprises-1-snap.png index c9fdc78c2..9276efcf8 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-tables-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-tables-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-vars-test-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-vars-test-without-surprises-1-snap.png index 96758752e..3630397b8 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-vars-test-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-vars-test-without-surprises-1-snap.png differ diff --git a/__tests__/browser/global-setup.js b/__tests__/browser/global-setup.js deleted file mode 100644 index b5897f637..000000000 --- a/__tests__/browser/global-setup.js +++ /dev/null @@ -1,5 +0,0 @@ -import { setup as setupPuppeteer } from 'jest-environment-puppeteer'; - -export default async function globalSetup(globalConfig) { - await setupPuppeteer(globalConfig); -} diff --git a/__tests__/browser/markdown.test.js b/__tests__/browser/markdown.test.js index 40b7913a9..0e88de142 100644 --- a/__tests__/browser/markdown.test.js +++ b/__tests__/browser/markdown.test.js @@ -11,37 +11,38 @@ describe('visual regression tests', () => { }); const docs = [ - 'callouts', + // 'callouts', 'calloutTests', 'codeBlocks', - 'embeds', - 'features', - 'headings', + // 'embeds', + //'features', + // 'headings', 'images', - 'lists', + 'htmlTests', + // 'lists', + 'mdxComponents', 'tables', - 'tablesTests', 'codeBlockTests', - 'tableOfContentsTests', + // 'tableOfContentsTests', 'varsTest', ]; it.each(docs)( 'renders "%s" without surprises', async doc => { - const uri = `http://localhost:9966/?ci=true#${doc}`; + const uri = `http://localhost:9966/#/${doc}?ci=true`; await page.goto(uri, { waitUntil: 'networkidle0' }); - await sleep(500); + await sleep(5000); const image = await page.screenshot({ fullPage: true }); expect(image).toMatchImageSnapshot(); }, - 10000 + 10000, ); - it('renders html blocks, style tags, and style attributes with safeMode off', async () => { - const uri = 'http://localhost:9966/?ci=true#sanitizingTests'; + it.skip('renders html blocks, style tags, and style attributes with safeMode off', async () => { + const uri = 'http://localhost:9966/#/sanitizingTests?ci=true'; await page.goto(uri, { waitUntil: 'networkidle0' }); await sleep(500); @@ -50,8 +51,8 @@ describe('visual regression tests', () => { expect(image).toMatchImageSnapshot(); }, 10000); - it('does not render html blocks, style tags, and style attributes with safeMode on', async () => { - const uri = 'http://localhost:9966/?ci=true&safe-mode=true#sanitizingTests'; + it.skip('does not render html blocks, style tags, and style attributes with safeMode on', async () => { + const uri = 'http://localhost:9966/#/sanitizingTests?ci=true&safe-mode=true'; await page.goto(uri, { waitUntil: 'networkidle0' }); await sleep(500); diff --git a/__tests__/browser/setup.js b/__tests__/browser/setup.js index 749d220e0..579dbe11f 100644 --- a/__tests__/browser/setup.js +++ b/__tests__/browser/setup.js @@ -1,7 +1,3 @@ -import { configureToMatchImageSnapshot } from 'jest-image-snapshot'; - -const opts = {}; - -const toMatchImageSnapshot = configureToMatchImageSnapshot(opts); +import { toMatchImageSnapshot } from 'jest-image-snapshot'; expect.extend({ toMatchImageSnapshot }); diff --git a/__tests__/compilers.test.ts b/__tests__/compilers.test.ts new file mode 100644 index 000000000..dc8be67d4 --- /dev/null +++ b/__tests__/compilers.test.ts @@ -0,0 +1,31 @@ +import { mdast, mdx } from '../index'; + +describe('ReadMe Flavored Blocks', () => { + it('Embed', () => { + const txt = '[Embedded meta links.](https://nyti.me/s/gzoa2xb2v3 "@embed")'; + const ast = mdast(txt); + const out = mdx(ast); + expect(out).toMatchSnapshot(); + }); + + it.skip('Variables', () => { + expect(mdx(mdast('<>'))).toMatchInlineSnapshot(` + "<> + " + `); + }); + + it.skip('Glossary Items', () => { + expect(mdx(mdast('<>'))).toMatchInlineSnapshot(` + "<> + " + `); + }); + + it('Emojis', () => { + expect(mdx(mdast(':smiley:'))).toMatchInlineSnapshot(` + ":smiley: + " + `); + }); +}); diff --git a/__tests__/flavored-compilers/break.test.js b/__tests__/compilers/break.test.js similarity index 58% rename from __tests__/flavored-compilers/break.test.js rename to __tests__/compilers/break.test.js index adacb580b..932f56941 100644 --- a/__tests__/flavored-compilers/break.test.js +++ b/__tests__/compilers/break.test.js @@ -1,17 +1,17 @@ -import { mdast, md } from '../../index'; +import { mdast, mdx } from '../..'; -describe('break compiler', () => { +describe.skip('break compiler', () => { it('uses two spaces with `correctnewlines: false`', () => { const txt = 'line\nbreak'; const opts = { correctnewlines: false }; - expect(md(mdast(txt, opts), opts)).toBe('line \nbreak\n'); + expect(mdx(mdast(txt, opts), opts)).toBe('line \nbreak\n'); }); it('uses two spaces with `correctnewlines: true`', () => { const txt = 'line\\\nbreak'; const opts = { correctnewlines: true }; - expect(md(mdast(txt, opts), opts)).toBe('line \nbreak\n'); + expect(mdx(mdast(txt, opts), opts)).toBe('line \nbreak\n'); }); }); diff --git a/__tests__/compilers/callout.test.ts b/__tests__/compilers/callout.test.ts new file mode 100644 index 000000000..aab6904dc --- /dev/null +++ b/__tests__/compilers/callout.test.ts @@ -0,0 +1,48 @@ +import { mdast, mdx } from '../../index'; + +describe('callouts compiler', () => { + it('compiles callouts', () => { + const markdown = `> 🚧 It works! +> +> And, it no longer deletes your content! +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it('compiles callouts with no heading', () => { + const markdown = `> 🚧 +> +> And, it no longer deletes your content! +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it('compiles callouts with no heading or body!?', () => { + const markdown = `> 🚧 +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it('compiles callouts with markdown in the heading', () => { + const markdown = `> 🚧 It **works**! +> +> And, it no longer deletes your content! +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it('compiles callouts with paragraphs', () => { + const markdown = `> 🚧 It **works**! +> +> And... +> +> it correctly compiles paragraphs. :grimace: +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); +}); diff --git a/__tests__/compilers/code-tabs.test.js b/__tests__/compilers/code-tabs.test.js new file mode 100644 index 000000000..1d3931b93 --- /dev/null +++ b/__tests__/compilers/code-tabs.test.js @@ -0,0 +1,43 @@ +import { mdast, mdx } from '../../index'; + +describe('code-tabs compiler', () => { + it('compiles code tabs', () => { + const markdown = `\`\`\` +const works = true; +\`\`\` +\`\`\` +const cool = true; +\`\`\` +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it('compiles code tabs with metadata', () => { + const markdown = `\`\`\`js Testing +const works = true; +\`\`\` +\`\`\`js +const cool = true; +\`\`\` +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); + + it("doesnt't mess with joining other blocks", () => { + const markdown = `\`\`\` +const works = true; +\`\`\` +\`\`\` +const cool = true; +\`\`\` + +## Hello! + +I should stay here +`; + + expect(mdx(mdast(markdown))).toBe(markdown); + }); +}); diff --git a/__tests__/compilers/compatability.test.ts b/__tests__/compilers/compatability.test.ts new file mode 100644 index 000000000..b03e2afc8 --- /dev/null +++ b/__tests__/compilers/compatability.test.ts @@ -0,0 +1,178 @@ +import { mdx } from '../../index'; +import * as rdmd from '@readme/markdown-legacy'; + +describe('compatability with RDMD', () => { + it('compiles glossary nodes', () => { + const ast = { + type: 'readme-glossary-item', + data: { + hProperties: { + term: 'parliament', + }, + }, + }; + + expect(mdx(ast).trim()).toBe('parliament'); + }); + + it('compiles mdx glossary nodes', () => { + const ast = { + type: 'readme-glossary-item', + data: { + hName: 'Glossary', + }, + children: [{ type: 'text', value: 'parliament' }], + }; + + expect(mdx(ast).trim()).toBe('parliament'); + }); + + it('compiles mdx image nodes', () => { + const ast = { + type: 'figure', + data: { hName: 'figure' }, + children: [ + { + align: 'center', + width: '300px', + src: 'https://drastik.ch/wp-content/uploads/2023/06/blackcat.gif', + url: 'https://drastik.ch/wp-content/uploads/2023/06/blackcat.gif', + alt: '', + title: '', + type: 'image', + data: { + hProperties: { + align: 'center', + className: 'border', + width: '300px', + }, + }, + }, + { + type: 'figcaption', + data: { hName: 'figcaption' }, + children: [ + { type: 'paragraph', + children: [ + { type: 'text', value: 'hello ' }, + { type: 'strong', children: [{ type: 'text', value: 'cat' }] }, + ], + }, + ], + }, + ], + }; + + expect(mdx(ast).trim()).toBe( + '', + ); + }); + + it('compiles mdx embed nodes', () => { + const ast = { + data: { + hProperties: { + html: false, + url: 'https://cdn.shopify.com/s/files/1/0711/5132/1403/files/BRK0502-034178M.pdf', + title: 'iframe', + href: 'https://cdn.shopify.com/s/files/1/0711/5132/1403/files/BRK0502-034178M.pdf', + typeOfEmbed: 'iframe', + height: '300px', + width: '100%', + iframe: true, + }, + hName: 'embed', + html: false, + url: 'https://cdn.shopify.com/s/files/1/0711/5132/1403/files/BRK0502-034178M.pdf', + title: 'iframe', + href: 'https://cdn.shopify.com/s/files/1/0711/5132/1403/files/BRK0502-034178M.pdf', + typeOfEmbed: 'iframe', + height: '300px', + width: '100%', + iframe: true, + }, + type: 'embed', + }; + + expect(mdx(ast).trim()).toBe(''); + }); + + it('compiles reusable-content nodes', () => { + const ast = { + type: 'reusable-content', + tag: 'Parliament', + }; + + expect(mdx(ast).trim()).toBe(''); + }); + + it('compiles html comments to JSX comments', () => { + const md = ` +This is some in progress +`; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('This is some in progress {/* commented out stuff */}'); + }); + + it('compiles multi-line html comments to JSX comments', () => { + const md = ` +## Wip + + +`; + + expect(mdx(rdmd.mdast(md)).trim()).toMatchInlineSnapshot(` + "## Wip + + {/* + + ### Some stuff I was working on + + */}" + `); + }); + + it('closes un-closed self closing tags', () => { + const md = ` +This is a break:
+`; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('This is a break:
'); + }); + + it('closes un-closed self closing tags with a space', () => { + const md = ` +This is a break:
+`; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('This is a break:
'); + }); + + it('closes complex un-closed self closing tags', () => { + const md = ` +This is an image: +`; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('This is an image: '); + }); + + it('compiles escapes', () => { + const md = ` +\\- not a list item + `; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('\\- not a list item'); + }); + + it('compiles escapes of backslashes', () => { + const md = ` +\\\\**still emphatic** + `; + + expect(mdx(rdmd.mdast(md)).trim()).toBe('\\\\**still emphatic**'); + }); +}); diff --git a/__tests__/flavored-compilers/escape.test.js b/__tests__/compilers/escape.test.js similarity index 54% rename from __tests__/flavored-compilers/escape.test.js rename to __tests__/compilers/escape.test.js index e2d97f6fb..0fd63e00a 100644 --- a/__tests__/flavored-compilers/escape.test.js +++ b/__tests__/compilers/escape.test.js @@ -1,9 +1,9 @@ -import { mdast, md } from '../../index'; +import { mdast, mdx } from '../../index'; describe('escape compiler', () => { it('handles escapes', () => { const txt = '\\¶'; - expect(md(mdast(txt))).toBe('\\¶\n'); + expect(mdx(mdast(txt))).toBe('\\¶\n'); }); }); diff --git a/__tests__/compilers/gemoji.test.ts b/__tests__/compilers/gemoji.test.ts new file mode 100644 index 000000000..055465b87 --- /dev/null +++ b/__tests__/compilers/gemoji.test.ts @@ -0,0 +1,9 @@ +import { mdast, mdx } from '../../index'; + +describe('gemoji compiler', () => { + it('should compile back to a shortcode', () => { + const markdown = `This is a gemoji :joy:.`; + + expect(mdx(mdast(markdown)).trimEnd()).toEqual(markdown); + }); +}); diff --git a/__tests__/compilers/html-block.test.ts b/__tests__/compilers/html-block.test.ts new file mode 100644 index 000000000..a0314e9ca --- /dev/null +++ b/__tests__/compilers/html-block.test.ts @@ -0,0 +1,42 @@ +import { mdast, mdx } from '../../index'; + +describe('html-block compiler', () => { + it('compiles html blocks within containers', () => { + const markdown = ` +> 🚧 It compiles! +> +> {\` +> Hello, World! +> \`} +`; + + expect(mdx(mdast(markdown)).trim()).toBe(markdown.trim()); + }); + + it('compiles html blocks preserving newlines', () => { + const markdown = ` +{\` +

+const foo = () => {
+  const bar = {
+    baz: 'blammo'
+  }
+
+  return bar
+}
+
+\`}
+`; + + expect(mdx(mdast(markdown)).trim()).toBe(markdown.trim()); + }); + + it('adds newlines for readability', () => { + const markdown = `{\`

Hello, World!

\`}
`; + const expected = `{\` +

Hello, World!

+\`}
`; + + expect(mdx(mdast(markdown)).trim()).toBe(expected.trim()); + }); +}); diff --git a/__tests__/compilers/images.test.ts b/__tests__/compilers/images.test.ts new file mode 100644 index 000000000..8f39ab65b --- /dev/null +++ b/__tests__/compilers/images.test.ts @@ -0,0 +1,15 @@ +import { mdast, mdx } from '../../index'; + +describe('image compiler', () => { + it('correctly serializes an image back to markdown', () => { + const txt = '![alt text](/path/to/image.png)'; + + expect(mdx(mdast(txt))).toMatch(txt); + }); + + it('correctly serializes an Image component back to MDX', () => { + const doc = 'alt text'; + + expect(mdx(mdast(doc))).toMatch(doc); + }); +}); diff --git a/__tests__/flavored-compilers/reusable-content.test.js b/__tests__/compilers/reusable-content.test.js similarity index 77% rename from __tests__/flavored-compilers/reusable-content.test.js rename to __tests__/compilers/reusable-content.test.js index 58309df51..ba9b5d013 100644 --- a/__tests__/flavored-compilers/reusable-content.test.js +++ b/__tests__/compilers/reusable-content.test.js @@ -1,11 +1,11 @@ -import { mdast, md } from '../../index'; +import { mdast, mdx } from '../../index'; -describe('reusable content compiler', () => { +describe.skip('reusable content compiler', () => { it('writes an undefined reusable content block as a tag', () => { const doc = ''; const tree = mdast(doc); - expect(md(tree)).toMatch(doc); + expect(mdx(tree)).toMatch(doc); }); it('writes a defined reusable content block as a tag', () => { @@ -16,7 +16,7 @@ describe('reusable content compiler', () => { const tree = mdast(doc, { reusableContent: { tags } }); expect(tree.children[0].children[0].type).toBe('heading'); - expect(md(tree)).toMatch(doc); + expect(mdx(tree)).toMatch(doc); }); it('writes a defined reusable content block with multiple words as a tag', () => { @@ -27,7 +27,7 @@ describe('reusable content compiler', () => { const tree = mdast(doc, { reusableContent: { tags } }); expect(tree.children[0].children[0].type).toBe('heading'); - expect(md(tree)).toMatch(doc); + expect(mdx(tree)).toMatch(doc); }); describe('writeTags = false', () => { @@ -36,7 +36,7 @@ describe('reusable content compiler', () => { Defined: '# Whoa', }; const doc = ''; - const string = md(doc, { reusableContent: { tags, writeTags: false } }); + const string = mdx(doc, { reusableContent: { tags, writeTags: false } }); expect(string).toBe('# Whoa\n'); }); diff --git a/__tests__/compilers/tables.test.js b/__tests__/compilers/tables.test.js new file mode 100644 index 000000000..358cf842e --- /dev/null +++ b/__tests__/compilers/tables.test.js @@ -0,0 +1,40 @@ +import { mdast, mdx } from '../../index'; +import { visit } from 'unist-util-visit'; + +describe('table compiler', () => { + it('writes to markdown syntax', () => { + const markdown = ` +| th 1 | th 2 | +| :----: | :----: | +| cell 1 | cell 2 | +`; + + expect(mdx(mdast(markdown))).toBe( + `| th 1 | th 2 | +| :----: | :----: | +| cell 1 | cell 2 | +`, + ); + }); + + it.skip('saves to MDX if there are breaks', () => { + const markdown = ` +| th 1 | th 2 | +| :----: | :----: | +| cell 1 | cell 2 | +`; + + const tree = mdast(markdown); + + visit(tree, 'tableCell', cell => { + cell.children.push({ type: 'break' }, { type: 'text', value: 'inserted' }); + }); + + expect(mdx(tree)).toMatchInlineSnapshot(` + "| th 1 inserted | th 2 inserted | + | :-------------: | :-------------: | + | cell 1 inserted | cell 2 inserted | + " + `); + }); +}); diff --git a/__tests__/compilers/variable.test.ts b/__tests__/compilers/variable.test.ts new file mode 100644 index 000000000..f6232e3b9 --- /dev/null +++ b/__tests__/compilers/variable.test.ts @@ -0,0 +1,16 @@ +import * as rmdx from '../../index'; + +describe('variable compiler', () => { + it('compiles back to the ', () => { + const mdx = ` +## Hello! + +{user.name} + +### Bye bye! + `; + const tree = rmdx.mdast(mdx); + + expect(rmdx.mdx(tree).trim()).toStrictEqual(mdx.trim()); + }); +}); diff --git a/__tests__/flavored-compilers/yaml.test.js b/__tests__/compilers/yaml.test.js similarity index 63% rename from __tests__/flavored-compilers/yaml.test.js rename to __tests__/compilers/yaml.test.js index 877f1f03b..dd30c7f69 100644 --- a/__tests__/flavored-compilers/yaml.test.js +++ b/__tests__/compilers/yaml.test.js @@ -1,7 +1,7 @@ -import { mdast, md } from '../../index'; +import { mdast, mdx } from '../../index'; describe('yaml compiler', () => { - it('correctly writes out yaml', () => { + it.skip('correctly writes out yaml', () => { const txt = ` --- title: This is test @@ -11,7 +11,7 @@ author: A frontmatter test Document content! `; - expect(md(mdast(txt))).toBe(`--- + expect(mdx(mdast(txt))).toBe(`--- title: This is test author: A frontmatter test --- diff --git a/__tests__/components/Callout.test.jsx b/__tests__/components/Callout.test.tsx similarity index 50% rename from __tests__/components/Callout.test.jsx rename to __tests__/components/Callout.test.tsx index 9cece9066..e559e1584 100644 --- a/__tests__/components/Callout.test.jsx +++ b/__tests__/components/Callout.test.tsx @@ -6,13 +6,25 @@ import Callout from '../../components/Callout'; describe('Callout', () => { it('render _all_ its children', () => { render( - +

Title

First Paragraph

Second Paragraph

-
+
, ); expect(screen.getByText('Second Paragraph')).toBeVisible(); }); + + it("doesn't render all its children if it's **empty**", () => { + render( + +

Title

+

First Paragraph

+

Second Paragraph

+
, + ); + + expect(screen.queryByText('Title')).toBeNull(); + }); }); diff --git a/__tests__/components/Code.test.jsx b/__tests__/components/Code.test.jsx deleted file mode 100644 index 9dc62d2f7..000000000 --- a/__tests__/components/Code.test.jsx +++ /dev/null @@ -1,40 +0,0 @@ -jest.mock('@readme/syntax-highlighter', () => ({ - default: code => { - return {code.replace(/<<.*?>>/, 'VARIABLE_SUBSTITUTED')}; - }, - canonical: lang => lang, -})); - -const { fireEvent, render, screen } = require('@testing-library/react'); -const copy = require('copy-to-clipboard'); -const React = require('react'); - -const Code = require('../../components/Code')({ attributes: {} }, { copyButtons: true }); - -describe('Code', () => { - it('copies the variable interpolated code', () => { - const props = { - children: ['console.log("<>");'], - }; - - const { container } = render(); - - expect(container).toHaveTextContent(/VARIABLE_SUBSTITUTED/); - fireEvent.click(screen.getByRole('button')); - - expect(copy).toHaveBeenCalledWith(expect.stringMatching(/VARIABLE_SUBSTITUTED/)); - }); - - it('does not nest the button inside the code block', () => { - render({'console.log("hi");'}); - const btn = screen.getByRole('button'); - - expect(btn.parentNode.nodeName.toLowerCase()).not.toBe('code'); - }); - - it('allows undefined children?!', () => { - const { container } = render(); - - expect(container).toHaveTextContent(''); - }); -}); diff --git a/__tests__/components/Code.test.tsx b/__tests__/components/Code.test.tsx new file mode 100644 index 000000000..3f0e55b8e --- /dev/null +++ b/__tests__/components/Code.test.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { vi } from 'vitest'; + +import Code from '../../components/Code'; + +import { fireEvent, render, screen } from '@testing-library/react'; +import copy from 'copy-to-clipboard'; + +const codeProps = { + copyButtons: true, +}; + +vi.mock('@readme/syntax-highlighter', () => ({ + default: code => { + return {code.replace(/<<.*?>>/, 'VARIABLE_SUBSTITUTED')}; + }, + canonical: lang => lang, +})); + +describe.skip('Code', () => { + it.skip('copies the variable interpolated code', () => { + const props = { + children: ['console.log("<>");'], + }; + + const { container } = render(); + + expect(container).toHaveTextContent(/VARIABLE_SUBSTITUTED/); + fireEvent.click(screen.getByRole('button')); + + expect(copy).toHaveBeenCalledWith(expect.stringMatching(/VARIABLE_SUBSTITUTED/)); + }); + + it.skip('does not nest the button inside the code block', () => { + render({'console.log("hi");'}); + const btn = screen.getByRole('button'); + + expect(btn.parentNode?.nodeName.toLowerCase()).not.toBe('code'); + }); + + it.skip('allows undefined children?!', () => { + const { container } = render(); + + expect(container).toHaveTextContent(''); + }); +}); diff --git a/__tests__/components/CodeTabs.test.jsx b/__tests__/components/CodeTabs.test.jsx deleted file mode 100644 index 51c36c7ba..000000000 --- a/__tests__/components/CodeTabs.test.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import { render } from '@testing-library/react'; - -import { react } from '../../index'; - -describe('Callout', () => { - it('render _all_ its children', () => { - const md = ` -\`\`\` -assert('theme', 'dark'); -\`\`\` - `; - const { container } = render(react(md, { theme: 'dark' })); - - expect(container.querySelector('code.theme-dark')).toBeVisible(); - }); -}); diff --git a/__tests__/components/CodeTabs.test.tsx b/__tests__/components/CodeTabs.test.tsx new file mode 100644 index 000000000..667d3d3dd --- /dev/null +++ b/__tests__/components/CodeTabs.test.tsx @@ -0,0 +1,21 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import { execute } from '../helpers'; + +describe('CodeTabs', () => { + it.skip('render _all_ its children', async () => { + const md = ` +\`\`\` +assert('theme', 'dark'); +\`\`\` +\`\`\` +assert('theme', 'light'); +\`\`\` + `; + const Component = await execute(md); + const { container } = render(); + + expect(container).toHaveTextContent(`assert('theme', 'dark')`); + expect(container).toHaveTextContent(`assert('theme', 'light')`); + }); +}); diff --git a/__tests__/components/Glossary.test.tsx b/__tests__/components/Glossary.test.tsx new file mode 100644 index 000000000..a07b526b6 --- /dev/null +++ b/__tests__/components/Glossary.test.tsx @@ -0,0 +1,14 @@ +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import { execute } from '../helpers'; + +describe('Glossary', () => { + it('renders a glossary item', async () => { + const md = `parliament`; + const Content = await execute(md); + render(); + + expect(screen.getByText('parliament')).toBeVisible(); + }); +}); diff --git a/__tests__/components/HTMLBlock.test.jsx b/__tests__/components/HTMLBlock.test.jsx deleted file mode 100644 index 20748dd27..000000000 --- a/__tests__/components/HTMLBlock.test.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; -import { renderToString } from 'react-dom/server'; - -import createHTMLBlock from '../../components/HTMLBlock'; -import { react } from '../../index'; -import createSchema from '../../sanitize.schema'; - -const HTMLBlock = createHTMLBlock(createSchema(), {}); - -describe('HTML Block', () => { - beforeEach(() => { - global.mockFn = jest.fn(); - }); - - it('runs user scripts in compat mode', () => { - render(); - expect(global.mockFn).toHaveBeenCalledTimes(1); - }); - - it("doesn't run user scripts by default", () => { - render(); - expect(global.mockFn).toHaveBeenCalledTimes(0); - }); - - it("doesn't render user scripts by default", () => { - render(); - - expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); - }); - - it("doesn't render user scripts with weird endings", () => { - render(); - - expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); - }); - - it("doesn't render user scripts with a malicious string", () => { - render(); - - expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); - }); - - it("doesn't run scripts on the server (even in compat mode)", () => { - const html = ` -

Hello World

- - `; - const elem = ; - const view = renderToString(elem); - expect(elem.props.runScripts).toBe(true); - expect(view.indexOf('`}); + expect(global.mockFn).toHaveBeenCalledTimes(1); + }); + + it("doesn't run user scripts by default", () => { + render({``}); + expect(global.mockFn).toHaveBeenCalledTimes(0); + }); + + it("doesn't render user scripts by default", () => { + render({``}); + expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); + }); + + it("doesn't render user scripts with weird endings", () => { + render({``}); + expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); + }); + + it("doesn't render user scripts with a malicious string", () => { + render({`t>mockFn()cript>`}); + expect(screen.queryByText('mockFn()')).not.toBeInTheDocument(); + }); + + it("doesn't run scripts on the server (even in compat mode)", () => { + const html = ` +

Hello World

+ + `; + const elem = {html}; + const view = renderToString(elem); + expect(elem.props.runScripts).toBe(true); + expect(view.indexOf('\n\nHello!\n\n', -})} -[/block] - -[block:parameters] -${JSON.stringify({ - data: { - '0-0': "```js Tab Zed\nconsole.log('tab zed');\n```\n```js Tab One\nconsole.log('tab one')\n```", - '0-1': - '> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime repellat placeat expedita voluptatum fugiat rerum, accusamus eius dolorum sequi eveniet esse, adipisci soluta quia mollitia? Dolorem minus, dolores, rerum, pariatur sit quia eum esse voluptatibus ea veritatis non.', - '0-2': '', - 'h-0': 'Hello', - 'h-1': 'Bonjour', - 'h-2': 'Willkommen', - }, - cols: 2, - rows: 1, -})} -[/block]`; - - let rdmd; - let container; - beforeEach(() => { - rdmd = markdown.react(tabs, { compatibilityMode: true }); - // eslint-disable-next-line testing-library/no-render-in-setup - ({ container } = render(rdmd)); - }); - - it('Should use h1 tags for magic heading blocks.', () => expect(container.querySelectorAll('h1')).toHaveLength(1)); - - it('Should allow block-level RDMD compoonents in tables.', () => { - const table = container.querySelector('table'); - expect(table.querySelectorAll('.CodeTabs')).toHaveLength(1); - expect(table.querySelectorAll('blockquote')).toHaveLength(1); - }); -}); diff --git a/__tests__/custom-components/index.test.tsx b/__tests__/custom-components/index.test.tsx new file mode 100644 index 000000000..e248adff8 --- /dev/null +++ b/__tests__/custom-components/index.test.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import { render, screen } from '@testing-library/react'; +import { execute } from '../helpers'; + +describe('Custom Components', () => { + const Example = { default: () =>
It works!
}; + const Composite = { + default: () => ( + <> +
Does it work?
+ + + ), + }; + + it('renders custom components', async () => { + const doc = ` + + `; + const Page = await execute(doc, undefined, { components: { Example } }); + render(); + + expect(screen.getByText('It works!')).toBeVisible(); + }); + + it('renders custom components recursively', async () => { + const doc = ` + + `; + + const Page = await execute(doc, undefined, { components: { Example, Composite } }); + render(); + + expect(screen.getByText('It works!')).toBeVisible(); + }); +}); diff --git a/__tests__/disabling-tokenizers.test.js b/__tests__/disabling-tokenizers.test.js deleted file mode 100644 index dcf4c8d34..000000000 --- a/__tests__/disabling-tokenizers.test.js +++ /dev/null @@ -1,43 +0,0 @@ -const markdown = require('../index'); - -describe('disableTokenizers: "inlines"', () => { - const opts = { disableTokenizers: 'inlines' }; - - it('disabling inlineCode', () => { - const md = '`const js = true `'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); - - it('disabling emphasis', () => { - const md = '*emphatic **strong** emphatic*'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); - - it('disabling delete', () => { - const md = '~~strikethrough~~'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); -}); - -describe('disableTokenizers: "blocks"', () => { - const opts = { disableTokenizers: 'blocks' }; - - it('disabling block tokenizer', () => { - const md = '# heading 1'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); -}); - -describe('disableTokenizers: {}', () => { - it('disables a block tokenizer', () => { - const opts = { disableTokenizers: { block: ['atxHeading'] } }; - const md = '# heading 1'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); - - it('disables an inline tokenizer', () => { - const opts = { disableTokenizers: { inline: ['code'] } }; - const md = '`const js = true`'; - expect(markdown.mdast(md, opts)).toMatchSnapshot(); - }); -}); diff --git a/__tests__/flavored-compilers.test.js b/__tests__/flavored-compilers.test.js deleted file mode 100644 index 12f4aeaf6..000000000 --- a/__tests__/flavored-compilers.test.js +++ /dev/null @@ -1,293 +0,0 @@ -const { defaultSchema: sanitize } = require('hast-util-sanitize/lib/schema'); -const rehypeSanitize = require('rehype-sanitize'); -const remarkParse = require('remark-parse'); -const remarkStringify = require('remark-stringify'); -const unified = require('unified'); - -const parsers = Object.values(require('../processor/parse')).map(parser => parser.sanitize?.(sanitize) || parser); -const compilers = Object.values(require('../processor/compile')); -const options = require('../options').options.markdownOptions; - -const processor = unified() - .use(remarkParse, options) - .data('settings', { position: false }) - .use(parsers) - .use(rehypeSanitize); - -const parse = text => text && processor().parse(text); -const compile = tree => tree && processor().use(remarkStringify, options).use(compilers).stringify(tree); - -describe('ReadMe Flavored Blocks', () => { - it('Embed', () => { - const txt = '[Embedded meta links.](https://nyti.me/s/gzoa2xb2v3 "@nyt")'; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Variables', () => { - expect(compile(parse('<>'))).toMatchInlineSnapshot(` - "<> - " - `); - }); - - it('Glossary Items', () => { - expect(compile(parse('<>'))).toMatchInlineSnapshot(` - "<> - " - `); - }); - - it('Emojis', () => { - expect(compile(parse(':smiley:'))).toMatchInlineSnapshot(` - ":smiley: - " - `); - }); - - it('Html Block', () => { - const text = ` -[block:html] -{ - "html": ${JSON.stringify( - '' - )} -} -[/block] -`; - const ast = parse(text); - - expect(compile(ast)).toMatchInlineSnapshot(` - "[block:html] - { - \\"html\\": \\"\\" - } - [/block] - " - `); - }); -}); - -describe('ReadMe Magic Blocks', () => { - it('Embed', () => { - const txt = `[block:embed] - { - "html": false, - "url": "https://youtu.be/J3-uKv1DShQ", - "title": null, - "favicon": "https://youtu.be/favicon.ico" - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Code Tabs', () => { - const txt = `[block:code] - { - "codes": [ - { - "code": "console.log('a multi-file code block');", - "language": "javascript", - "name": "multiple.js" - }, - { - "code": "console.log('an unnamed sample snippet');", - "language": "javascript" - } - ] - } - [/block] - `; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Callouts', () => { - const txt = `[block:callout] - { - "type": "success", - "title": "Success", - "body": "Vitae reprehenderit at aliquid error voluptates eum dignissimos." - } - [/block] - - And this is a paragraph! - `; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Figure', () => { - const txt = `[block:image] - { - "images": [ - { - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "rdme-blue.svg" - ], - "caption": "Ok, __pizza__ man.", - "sizing": "80" - } - ] - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Figure with alt text', () => { - const txt = `[block:image] - { - "images": [ - { - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "rdme-blue.svg", - "A man eating pizza and making an OK gesture" - ], - "caption": "Ok, __pizza__ man.", - "sizing": "80" - } - ] - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('Image', () => { - const txt = `[block:image] - { - "images": [{ - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "rdme-blue.svg" - ] - }] - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - - expect(out).toMatchSnapshot(); - }); - - it('Image with sizing and border', () => { - const txt = `[block:image] - { - "images": [{ - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "rdme-blue.svg" - ], - "sizing": "80px", - "border": true - }] - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - - expect(out).toMatchSnapshot(); - }); - - it('Image with sizing and alignment', () => { - const txt = `[block:image] - { - "images": [{ - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "rdme-blue.svg" - ], - "sizing": "80px", - "align": "right" - }] - } - [/block]`; - const ast = parse(txt); - const out = compile(ast); - - expect(out).toMatchSnapshot(); - }); - - it('custom blocks', () => { - const txt = ` -[block:tutorial-tile] -${JSON.stringify( - { - backgroundColor: '#ffffff', - title: 'Tutorial Title', - emoji: 'πŸ¦‰', - link: 'http://test.com', - }, - null, - 2 -)} -[/block] - - `; - - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchSnapshot(); - }); - - it('font-awesome emojis', () => { - const txt = ':fa-rss-square:'; - - const ast = parse(txt); - const out = compile(ast); - expect(out).toMatchInlineSnapshot(` - ":fa-rss-square: - " - `); - }); - - it('Tables', () => { - const md = ` -[block:parameters] -${JSON.stringify({ - data: { - 'h-0': 'th 1', - 'h-1': 'th 2', - '0-0': 'cell 1', - '0-1': 'cell 2', - }, - cols: 2, - rows: 1, - align: ['center', 'center'], -})} -[/block] - `; - - expect(compile(parse(md))).toMatchSnapshot(); - }); - - it('Tables with breaks', () => { - const md = ` -[block:parameters] -${JSON.stringify({ - data: { - 'h-0': 'th 1', - 'h-1': 'th 2', - '0-0': 'cell 1 \nafter the break', - '0-1': 'cell 2', - }, - cols: 2, - rows: 1, - align: ['center', 'center'], -})} -[/block] - `; - - expect(compile(parse(md))).toMatchSnapshot(); - }); -}); diff --git a/__tests__/flavored-compilers/__snapshots__/tables.test.js.snap b/__tests__/flavored-compilers/__snapshots__/tables.test.js.snap deleted file mode 100644 index 3999ac2b3..000000000 --- a/__tests__/flavored-compilers/__snapshots__/tables.test.js.snap +++ /dev/null @@ -1,41 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`table compiler converts to magic block syntax if there are breaks 1`] = ` -"[block:parameters] -{ - \\"data\\": { - \\"h-0\\": \\"th 1\\", - \\"h-1\\": \\"th 2\\", - \\"0-0\\": \\"cell 1 \\\\nextra line\\", - \\"0-1\\": \\"cell 2\\" - }, - \\"cols\\": 2, - \\"rows\\": 1, - \\"align\\": [ - \\"center\\", - \\"center\\" - ] -} -[/block] -" -`; - -exports[`table compiler saves to magic block syntax if there are breaks 1`] = ` -"[block:parameters] -{ - \\"data\\": { - \\"h-0\\": \\"th 1\\", - \\"h-1\\": \\"th 2\\", - \\"0-0\\": \\"cell 1 \\\\nextra line\\", - \\"0-1\\": \\"cell 2\\" - }, - \\"cols\\": 2, - \\"rows\\": 1, - \\"align\\": [ - \\"center\\", - \\"center\\" - ] -} -[/block] -" -`; diff --git a/__tests__/flavored-compilers/code-tabs.test.js b/__tests__/flavored-compilers/code-tabs.test.js deleted file mode 100644 index 1ab39ed49..000000000 --- a/__tests__/flavored-compilers/code-tabs.test.js +++ /dev/null @@ -1,27 +0,0 @@ -import { mdast, md } from '../../index'; - -describe('code-tabs compiler', () => { - it('compiles code tabs', () => { - const markdown = `\`\`\` -const works = true; -\`\`\` -\`\`\` -const cool = true; -\`\`\` -`; - - expect(md(mdast(markdown))).toBe(markdown); - }); - - it('compiles code tabs with metadata', () => { - const markdown = `\`\`\`js Testing -const works = true; -\`\`\` -\`\`\`js -const cool = true; -\`\`\` -`; - - expect(md(mdast(markdown))).toBe(markdown); - }); -}); diff --git a/__tests__/flavored-compilers/images.test.js b/__tests__/flavored-compilers/images.test.js deleted file mode 100644 index 9a6e0d24b..000000000 --- a/__tests__/flavored-compilers/images.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import { mdast, md } from '../../index'; - -describe('image compiler', () => { - it('correctly serializes an image back to markdown', () => { - const txt = '![alt text](/path/to/image.png)'; - - expect(md(mdast(txt))).toMatch(txt); - }); -}); diff --git a/__tests__/flavored-compilers/magic-blocks.test.js b/__tests__/flavored-compilers/magic-blocks.test.js deleted file mode 100644 index 2475c5765..000000000 --- a/__tests__/flavored-compilers/magic-blocks.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import { md, mdast } from '../../index'; - -describe('Compile Magic Blocks', () => { - it('compiles a magic block to multiple lines', () => { - const text = ` -[block:image]{ "images": [{ "image": ["https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] -`; - const tree = mdast(text); - const compiled = md(tree); - - expect(compiled).toMatchInlineSnapshot(` - "[block:image] - { - \\"images\\": [ - { - \\"image\\": [ - \\"https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png\\", - \\"\\", - \\"\\" - ], - \\"align\\": \\"center\\" - } - ] - } - [/block] - " - `); - }); - - it('compiles a magic block in a container on a single line', () => { - const text = ` -> πŸ‘ It works! -> -> [block:image]{ "images": [{ "image": ["https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] -`; - const tree = mdast(text); - const compiled = md(tree); - - expect(compiled).toMatchInlineSnapshot(` - "> πŸ‘ It works! - > - > [block:image]{\\"images\\":[{\\"image\\":[\\"https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png\\",\\"\\",\\"\\"],\\"align\\":\\"center\\"}]}[/block] - " - `); - }); - - it('compiles two adjacent magic blocks', () => { - const text = ` -[block:image]{ "images": [{ "image": ["https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] - -[block:image]{ "images": [{ "image": ["https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] -`; - const tree = mdast(text); - const compiled = md(tree); - - expect(compiled).toMatchInlineSnapshot(` - "[block:image] - { - \\"images\\": [ - { - \\"image\\": [ - \\"https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png\\", - \\"\\", - \\"\\" - ], - \\"align\\": \\"center\\" - } - ] - } - [/block] - - - [block:image] - { - \\"images\\": [ - { - \\"image\\": [ - \\"https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png\\", - \\"\\", - \\"\\" - ], - \\"align\\": \\"center\\" - } - ] - } - [/block] - " - `); - }); -}); diff --git a/__tests__/flavored-compilers/tables.test.js b/__tests__/flavored-compilers/tables.test.js deleted file mode 100644 index d1265ae5d..000000000 --- a/__tests__/flavored-compilers/tables.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import { mdast, md } from '../../index'; - -describe('table compiler', () => { - it('converts to markdown syntax', () => { - const markdown = ` -[block:parameters] -{ - "data": { - "h-0": "th 1", - "h-1": "th 2", - "0-0": "cell 1", - "0-1": "cell 2" - }, - "cols": 2, - "rows": 1, - "align": [ - "center", - "center" - ] -} -[/block] -`; - - expect(md(mdast(markdown))).toBe( - `| th 1 | th 2 | -| :----: | :----: | -| cell 1 | cell 2 | -` - ); - }); - - it('saves to magic block syntax if there are breaks', () => { - const markdown = ` -[block:parameters] -{ - "data": { - "h-0": "th 1", - "h-1": "th 2", - "0-0": "cell 1\\nextra line", - "0-1": "cell 2" - }, - "cols": 2, - "rows": 1, - "align": [ - "center", - "center" - ] -} -[/block] -`; - - expect(md(mdast(markdown))).toMatchSnapshot(); - }); - - it('converts to magic block syntax if there are breaks', () => { - const markdown = ` -| th 1 | th 2 | -| :----: | :----: | -| cell 1 | cell 2 | -`; - const nodes = mdast(markdown); - const cell = nodes.children[0].children[1].children[0]; - cell.children = [...cell.children, { type: 'break' }, { type: 'text', value: 'extra line' }]; - - expect(md(nodes)).toMatchSnapshot(); - }); -}); diff --git a/__tests__/flavored-parsers.test.js b/__tests__/flavored-parsers.test.js deleted file mode 100644 index 16a6a9964..000000000 --- a/__tests__/flavored-parsers.test.js +++ /dev/null @@ -1,178 +0,0 @@ -const rehypeSanitize = require('rehype-sanitize'); -const remarkParse = require('remark-parse'); -const unified = require('unified'); - -const options = require('../options').options.markdownOptions; -const parseCallouts = require('../processor/parse/flavored/callout'); -const parseCodeTabs = require('../processor/parse/flavored/code-tabs'); - -const sanitize = { attributes: [], tagNames: [] }; -const process = (text, opts = options) => - text && - unified() - .use(remarkParse, opts) - .data('settings', { position: false }) - .use([parseCallouts.sanitize(sanitize), parseCodeTabs.sanitize(sanitize)]) - .use(rehypeSanitize) - .parse(text); - -describe('Parse RDMD Syntax', () => { - describe('Code Blocks', () => { - it('Tabbed Code Block', () => { - const text = - "\n\n```javascript multiple.js\nconsole.log('a multi-file code block');\n```\n```javascript\nconsole.log('an unnamed sample snippet');\n```\n\n "; - const ast = process(text); - expect(ast).toMatchSnapshot(); - }); - - it('Single Code Block', () => { - const text = "\n\n```javascript single.js\nconsole.log('a single-file code block');\n```\n\n"; - const ast = process(text); - expect(ast).toMatchSnapshot(); - }); - - it('allows indented code', () => { - const mdx = ` -\`\`\` - const shouldBeIndented = true; - if (shouldBeIndented) pass(); -\`\`\` -`; - expect(process(mdx)).toMatchSnapshot(); - }); - - it('parses indented code blocks', () => { - const mdx = ` - - const shouldBeIndented = true; - if (shouldBeIndented) pass(); - -`; - const ast = process(mdx); - - expect(ast.children[0].type).toBe('code'); - expect(ast).toMatchSnapshot(); - }); - - describe('Edge Cases', () => { - it('Code blocks should elide spaces before meta data', () => { - /** - * https://github.com/readmeio/api-explorer/issues/722 - */ - const mdx = '``` js Tab Name\nconsole.log("test zed");\n```'; - const ast = process(mdx); - const [codeBlock] = ast.children; - - expect(codeBlock.type).toBe('code'); - expect(codeBlock.meta).toBe('Tab Name'); - expect(codeBlock.lang).toBe('js'); - }); - - it('Code blocks should keep spaces entered at start of first line', () => { - const mdx = - "```javascript tab/a.js\n function sayHello (state) {\n console.log(state);\n }\n\nexport default sayHello;\n```\n```javascript tab/b.js\nimport A from './a.js';\n\nA('Hello world!');\n```\n\n"; - const ast = process(mdx); - - expect(ast).toMatchSnapshot(); - }); - - it('Code blocks should use a "smart" terminating delimiter', () => { - /** - * https://github.com/readmeio/api-explorer/issues/724 - */ - const mdx = '```bash\ndash-cli -testnet keepass genkey\n``` '; - const ast = process(mdx); - const [codeBlock] = ast.children; - expect(codeBlock.type).toBe('code'); - expect(ast.children).toHaveLength(1); - }); - - it('Handles triple backticks within a code block', () => { - const mdx = '```\nconsole.log("why would you do this?!```");\n```\n```\nbar\n```'; - const ast = process(mdx); - - expect(ast.children[0].children).toHaveLength(2); - }); - - it('Tabbed code blocks should allow internal new lines', () => { - const mdx = - "```javascript tab/a.js\nfunction sayHello (state) {\n console.log(state);\n}\n\nexport default sayHello;\n```\n```javascript tab/b.js\nimport A from './a.js';\n\nA('Hello world!');\n```\n\n"; - const ast = process(mdx); - - expect(ast.children).toHaveLength(1); - expect(ast.children[0].type).toBe('code-tabs'); - }); - - it('Tabbed code blocks should not require meta data to be specified', () => { - /** - * https://github.com/readmeio/api-explorer/issues/719 - */ - const mdx = '```\nwill break\n```\n```\nthe page!\n```'; - const ast = process(mdx); - const [codeTabs] = ast.children; - expect(codeTabs.children).toHaveLength(2); - }); - - it('Tabbed code blocks should not require any code', () => { - const mdx = '```c++ oh me\nsome code\n```\n```c++ a tab with no code\n```\n```c++ oh my\nsome more\n```'; - const ast = process(mdx); - const [codeTabs] = ast.children; - expect(codeTabs.children).toHaveLength(3); - }); - - it('Multiple empty code blocks tabs should render', () => { - const mdx = '```\n```\n```\n```'; - const ast = process(mdx); - const [codeTabs] = ast.children; - expect(codeTabs.children).toHaveLength(2); - }); - }); - }); - - it('Subsequent, non-adjacent code should render as single blocks.', () => { - const mdx = - "```javascript single.js\nconsole.log('a single-file code block');\n```\n\n```javascript single.js\nconsole.log('a single-file code block');\n```"; - const ast = process(mdx); - expect(ast.children).toHaveLength(2); - expect(ast.children.map(node => node.type)).toStrictEqual(['code', 'code']); - }); - - it('When fools just, like, totally disregard newlines...', () => { - // See this comment for more... - // https://github.com/readmeio/api-explorer/pull/627#discussion_r415420860 - const mdx = - "\n\n```javascript single.js\nconsole.log('I should be a single code block');\n```\n## I Should be an H3 Tag\n```javascript single.js\nconsole.log('I\\'m also a single code block');\n```\n\n"; - const ast = process(mdx); - expect(ast.children).toHaveLength(3); - }); - - it('More foolish disregard for newlines.', () => { - const mdx = '```\nfoo\n```\nOops\n```\nbar\n```'; - const ast = process(mdx); - - expect(ast.children.map(c => c.type)).toStrictEqual(['code', 'paragraph', 'code']); - }); - - it('Inappropriate leading whitespace is not matched.', () => { - const mdx = '```\nfoo\n ```\nOops\n```\nbar\n```'; - const ast = process(mdx); - - expect(ast.children.map(c => c.type)).toStrictEqual(['code', 'paragraph', 'code']); - }); - - it('Allows trailing text on a closing fence.', () => { - const mdx = '```\nfoo\n```\n```\nbar\n``` Oops'; - const ast = process(mdx); - - expect(ast.children.map(c => c.type)).toStrictEqual(['code-tabs', 'paragraph']); - }); - - it('is not stateful', () => { - const mdx = '```\n"Dont forget that RegExp.prototype.exec is statefule"\n```\n```\nbar\n```'; - let ast = process(mdx); - expect(ast.children.map(c => c.type)).toStrictEqual(['code-tabs']); - - ast = process(mdx); - expect(ast.children.map(c => c.type)).toStrictEqual(['code-tabs']); - }); -}); diff --git a/__tests__/flavored-parsers/__snapshots__/callouts.test.js.snap b/__tests__/flavored-parsers/__snapshots__/callouts.test.js.snap deleted file mode 100644 index 7898d05a4..000000000 --- a/__tests__/flavored-parsers/__snapshots__/callouts.test.js.snap +++ /dev/null @@ -1,2018 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Parse RDMD Callouts allows nested callouts 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "checked": null, - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "list item", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 17, - "line": 3, - "offset": 29, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 17, - }, - }, - "type": "text", - "value": "Info Callout", - }, - ], - "position": Position { - "end": Object { - "column": 17, - "line": 3, - "offset": 29, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 17, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 62, - "line": 3, - "offset": 74, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 17, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 62, - "line": 3, - "offset": 74, - }, - "indent": Array [], - "start": Object { - "column": 5, - "line": 3, - "offset": 17, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "ℹ️", - "theme": "info", - "title": "Info Callout", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 62, - "line": 5, - "offset": 98, - }, - "indent": Array [ - 3, - 3, - ], - "start": Object { - "column": 3, - "line": 3, - "offset": 15, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Position { - "end": Object { - "column": 62, - "line": 5, - "offset": 98, - }, - "indent": Array [ - 1, - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "spread": false, - "type": "listItem", - }, - ], - "ordered": false, - "position": Position { - "end": Object { - "column": 62, - "line": 5, - "offset": 98, - }, - "indent": Array [ - 1, - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "spread": false, - "start": null, - "type": "list", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 7, - "offset": 101, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts does not require a line break between the title and the body 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 24, - "line": 2, - "offset": 24, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Undocumented Behavior", - }, - ], - "position": Position { - "end": Object { - "column": 24, - "line": 2, - "offset": 24, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ’", - "theme": "default", - "title": "Undocumented Behavior", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 60, - "line": 3, - "offset": 87, - }, - "indent": Array [ - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 5, - "offset": 90, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts edge cases does not allow trailing spaces after the icon with no title 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 83, - "line": 2, - "offset": 83, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Compact headings must be followed by two line breaks before the following block.", - }, - ], - "position": Position { - "end": Object { - "column": 83, - "line": 2, - "offset": 83, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ›‘", - "theme": "error", - "title": "", - "value": "Compact headings must be followed by two line breaks before the following block.", - }, - }, - "position": Position { - "end": Object { - "column": 83, - "line": 3, - "offset": 89, - }, - "indent": Array [ - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 5, - "offset": 92, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts edge cases renders html inside a callout 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 15, - "line": 2, - "offset": 15, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Info Callout", - }, - ], - "position": Position { - "end": Object { - "column": 15, - "line": 2, - "offset": 15, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 9, - "line": 2, - "offset": 9, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "html", - "value": "", - }, - Object { - "position": Position { - "end": Object { - "column": 19, - "line": 2, - "offset": 19, - }, - "indent": Array [], - "start": Object { - "column": 9, - "line": 2, - "offset": 9, - }, - }, - "type": "text", - "value": "With html!", - }, - Object { - "position": Position { - "end": Object { - "column": 26, - "line": 2, - "offset": 26, - }, - "indent": Array [], - "start": Object { - "column": 19, - "line": 2, - "offset": 19, - }, - }, - "type": "html", - "value": "", - }, - ], - "position": Position { - "end": Object { - "column": 26, - "line": 2, - "offset": 26, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "ℹ️", - "theme": "info", - "title": "Info Callout", - "value": "With html!", - }, - }, - "position": Position { - "end": Object { - "column": 26, - "line": 4, - "offset": 46, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 7, - "offset": 50, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts parses a callout with no title 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "ℹ️", - "theme": "info", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 60, - "line": 4, - "offset": 67, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 70, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts renders an info callout 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 15, - "line": 2, - "offset": 15, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Info Callout", - }, - ], - "position": Position { - "end": Object { - "column": 15, - "line": 2, - "offset": 15, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 60, - "line": 2, - "offset": 60, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "ℹ️", - "theme": "info", - "title": "Info Callout", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 60, - "line": 4, - "offset": 80, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 83, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts requires a space between the icon and title 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 17, - "line": 2, - "offset": 17, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "ℹ️Info Callout", - }, - ], - "position": Position { - "end": Object { - "column": 17, - "line": 2, - "offset": 17, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 60, - "line": 4, - "offset": 79, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 4, - "offset": 22, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 60, - "line": 4, - "offset": 79, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 4, - "offset": 22, - }, - }, - "type": "paragraph", - }, - ], - "position": Position { - "end": Object { - "column": 60, - "line": 4, - "offset": 79, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "blockquote", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 82, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Parse RDMD Callouts supports a default theme 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Themeless", - }, - ], - "position": Position { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ₯‡", - "theme": "default", - "title": "Themeless", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 76, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 79, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ‼️ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "‼️", - "theme": "error", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ⁉️ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "⁉️", - "theme": "error", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ℹ️ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "ℹ️", - "theme": "info", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ⚠ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "⚠", - "theme": "warn", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 65, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 68, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ⚠️ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "⚠️", - "theme": "warn", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for βœ… 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "βœ…", - "theme": "okay", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 65, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 68, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ❗ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "❗", - "theme": "error", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 65, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 68, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for ❗️ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "❗️", - "theme": "error", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for πŸ‘ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ‘", - "theme": "okay", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for πŸ“˜ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ“˜", - "theme": "info", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for 🚧 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "🚧", - "theme": "warn", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`emoji modifier support render a callout for πŸ›‘ 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - ], - "position": Position { - "end": Object { - "column": 59, - "line": 2, - "offset": 59, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "paragraph", - }, - ], - "data": Object { - "hName": "rdme-callout", - "hProperties": Object { - "icon": "πŸ›‘", - "theme": "error", - "title": "", - "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", - }, - }, - "position": Position { - "end": Object { - "column": 59, - "line": 4, - "offset": 66, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "rdme-callout", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 69, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/flavored-parsers/__snapshots__/code-tabs.test.js.snap b/__tests__/flavored-parsers/__snapshots__/code-tabs.test.js.snap deleted file mode 100644 index 7baefe32c..000000000 --- a/__tests__/flavored-parsers/__snapshots__/code-tabs.test.js.snap +++ /dev/null @@ -1,205 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Code Tabs allows code tabs within html blocks 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": " -", - }, - ], - "position": Object { - "end": Object { - "column": 1, - "line": 4, - "offset": 6, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "p", - "type": "element", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "First code block -", - }, - ], - "properties": Object { - "meta": "", - }, - "tagName": "code", - "type": "element", - }, - ], - "properties": Object {}, - "tagName": "pre", - "type": "element", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Second code block -", - }, - ], - "properties": Object { - "meta": "", - }, - "tagName": "code", - "type": "element", - }, - ], - "properties": Object {}, - "tagName": "pre", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 4, - "line": 9, - "offset": 56, - }, - "start": Object { - "column": 1, - "line": 4, - "offset": 6, - }, - }, - "properties": Object { - "className": Array [ - "code-tabs", - ], - }, - "tagName": "div", - "type": "element", - }, - Object { - "type": "text", - "value": " -", - }, - Object { - "children": Array [], - "properties": Object {}, - "tagName": "p", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 14, - "offset": 66, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Code Tabs can parse code tabs 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": undefined, - "meta": "", - }, - }, - "lang": undefined, - "meta": "", - "type": "code", - "value": "First code block", - }, - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": undefined, - "meta": "", - }, - }, - "lang": undefined, - "meta": "", - "type": "code", - "value": "Second code block", - }, - ], - "className": "tabs", - "data": Object { - "hName": "div", - "hProperties": Object { - "className": Array [ - "code-tabs", - ], - }, - }, - "position": Position { - "end": Object { - "column": 4, - "line": 7, - "offset": 51, - }, - "indent": Array [ - 1, - 1, - 1, - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "code-tabs", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 10, - "offset": 55, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/flavored-parsers/__snapshots__/compact-headings.test.js.snap b/__tests__/flavored-parsers/__snapshots__/compact-headings.test.js.snap deleted file mode 100644 index bc2b44903..000000000 --- a/__tests__/flavored-parsers/__snapshots__/compact-headings.test.js.snap +++ /dev/null @@ -1,127 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Compact headings can parse compact headings 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 16, - "line": 1, - "offset": 15, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": "Compact Heading", - }, - ], - "data": Object { - "hProperties": Object { - "id": "compact-heading", - }, - "id": "compact-heading", - }, - "depth": 1, - "position": Position { - "end": Object { - "column": 1, - "line": 2, - "offset": 17, - }, - "indent": Array [ - 1, - ], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "heading", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 19, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Compact headings can parse headings that are not compact 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 22, - "line": 1, - "offset": 21, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 1, - "offset": 2, - }, - }, - "type": "text", - "value": "Non-compact Heading", - }, - ], - "data": Object { - "hProperties": Object { - "id": "non-compact-heading", - }, - "id": "non-compact-heading", - }, - "depth": 1, - "position": Position { - "end": Object { - "column": 22, - "line": 1, - "offset": 21, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "heading", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 24, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/flavored-parsers/__snapshots__/escape.test.js.snap b/__tests__/flavored-parsers/__snapshots__/escape.test.js.snap deleted file mode 100644 index fb4f962b3..000000000 --- a/__tests__/flavored-parsers/__snapshots__/escape.test.js.snap +++ /dev/null @@ -1,73 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Escape uses the "escape" type 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 3, - "line": 1, - "offset": 2, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "escape", - "value": "&", - }, - Object { - "position": Position { - "end": Object { - "column": 8, - "line": 1, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 1, - "offset": 2, - }, - }, - "type": "text", - "value": "para;", - }, - ], - "position": Position { - "end": Object { - "column": 8, - "line": 1, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "paragraph", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 3, - "offset": 10, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/flavored-parsers/__snapshots__/tables.test.js.snap b/__tests__/flavored-parsers/__snapshots__/tables.test.js.snap deleted file mode 100644 index 2c984e142..000000000 --- a/__tests__/flavored-parsers/__snapshots__/tables.test.js.snap +++ /dev/null @@ -1,150 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Parse magic block tables renders an table with missing cells 1`] = ` -Object { - "children": Array [ - Object { - "align": Array [ - "left", - "left", - ], - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "", - }, - ], - "type": "tableHead", - }, - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 9, - "line": 1, - "offset": 8, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": "Header 1", - }, - ], - "type": "tableHead", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 9, - "line": 1, - "offset": 8, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": "Cell A 1", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - ], - "position": Position { - "end": Object { - "column": 9, - "line": 12, - "offset": 120, - }, - "indent": Array [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "table", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 16, - "offset": 129, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/flavored-parsers/code-tabs.test.js b/__tests__/flavored-parsers/code-tabs.test.js deleted file mode 100644 index 6da2d153a..000000000 --- a/__tests__/flavored-parsers/code-tabs.test.js +++ /dev/null @@ -1,102 +0,0 @@ -import { mdast, hast } from '../../index'; - -describe('Code Tabs', () => { - it('can parse code tabs', () => { - const md = ` -\`\`\` -First code block -\`\`\` -\`\`\` -Second code block -\`\`\` -`; - - expect(mdast(md)).toMatchSnapshot(); - }); - - it('can parse lang and meta', () => { - const md = ` -\`\`\`javascript First Title -First code block -\`\`\` -\`\`\`text -Second code block -\`\`\` -`; - const ast = mdast(md); - - expect(ast.children[0].children[0]).toStrictEqual( - expect.objectContaining({ lang: 'javascript', meta: 'First Title' }) - ); - expect(ast.children[0].children[1]).toStrictEqual(expect.objectContaining({ lang: 'text', meta: '' })); - }); - - it('allows code tabs within html blocks', () => { - const md = ` -

- -\`\`\` -First code block -\`\`\` -\`\`\` -Second code block -\`\`\` - -

-`; - - expect(hast(md)).toMatchSnapshot(); - }); - - it('unescapes the language', () => { - const markdown = `\`\`\`js\\* -const works = true; -\`\`\` -\`\`\` -const cool = true; -\`\`\` -`; - - const tree = mdast(markdown); - expect(tree.children[0].children[0].lang).toBe('js*'); - }); - - it('unescapes the meta data', () => { - const markdown = `\`\`\`js Testing\\* -const works = true; -\`\`\` -\`\`\` -const cool = true; -\`\`\` -`; - - const tree = mdast(markdown); - expect(tree.children[0].children[0].meta).toBe('Testing*'); - }); - - it('decodes entities in the language', () => { - const markdown = `\`\`\`© -const works = true; -\`\`\` -\`\`\` -const cool = true; -\`\`\` -`; - - const tree = mdast(markdown); - expect(tree.children[0].children[0].lang).toBe('Β©'); - }); - - it('decodes entities in the meta', () => { - const markdown = `\`\`\`js © -const works = true; -\`\`\` -\`\`\` -const cool = true; -\`\`\` -`; - - const tree = mdast(markdown); - expect(tree.children[0].children[0].meta).toBe('Β©'); - }); -}); diff --git a/__tests__/flavored-parsers/compact-headings.test.js b/__tests__/flavored-parsers/compact-headings.test.js deleted file mode 100644 index b419236f4..000000000 --- a/__tests__/flavored-parsers/compact-headings.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import { mdast } from '../../index'; - -describe('Compact headings', () => { - it('can parse compact headings', () => { - const heading = '#Compact Heading'; - expect(mdast(heading)).toMatchSnapshot(); - }); - - it('reports the offsets for compact headings correctly', () => { - const heading = '#Compact Heading'; - const tree = mdast(heading, { settings: { position: true } }); - - expect(tree.children[0].position.start.offset).toBe(0); - expect(tree.children[0].position.end.offset).toBe(17); - }); - - it('can parse headings that are not compact', () => { - const heading = '# Non-compact Heading'; - expect(mdast(heading)).toMatchSnapshot(); - }); - - it('reports the offsets for non-compact headings correctly', () => { - const heading = '# Non-compact Heading'; - const tree = mdast(heading, { settings: { position: true } }); - - expect(tree.children[0].position.start.offset).toBe(0); - expect(tree.children[0].position.end.offset).toBe(21); - }); - - it('can parse a compact heading followed by a setext heading', () => { - const heading = ` -##Non-compact Heading ---- -`; - const tree = mdast(heading); - - expect(tree.children[0].children[0].value).toBe('Non-compact Heading'); - expect(tree.children[1].type).toBe('thematicBreak'); - }); -}); diff --git a/__tests__/flavored-parsers/magic-blocks.test.js b/__tests__/flavored-parsers/magic-blocks.test.js deleted file mode 100644 index 824286b45..000000000 --- a/__tests__/flavored-parsers/magic-blocks.test.js +++ /dev/null @@ -1,39 +0,0 @@ -import { mdast } from '../../index'; - -describe('Parse Magic Blocks', () => { - it('parses an magic block in a container node', () => { - const text = ` -> ℹ️ Info Callout -> -> [block:image]{ "images": [{ "image": ["https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] -`; - const tree = mdast(text); - - expect(tree.children[0].type).toBe('rdme-callout'); - expect(tree.children[0].children[1].type).toBe('image'); - }); - - it('magic block on a single line', () => { - const md = '[block:api-header]{"type": "basic"}[/block]'; - const tree = mdast(md); - expect(tree.children[0].type).toBe('heading'); - }); - - it('magic block with leading whitespace on one line', () => { - const md = ' [block:api-header]{"type": "basic"}[/block]'; - const tree = mdast(md); - expect(tree.children[0].type).toBe('heading'); - }); - - it('magic block with leading whitespace on multiple lines', () => { - const md = ` - [block:api-header] - { - "type": "basic" - } - [/block] - `; - const tree = mdast(md); - expect(tree.children[0].type).toBe('heading'); - }); -}); diff --git a/__tests__/flavored-parsers/tables.test.js b/__tests__/flavored-parsers/tables.test.js deleted file mode 100644 index 8ad802226..000000000 --- a/__tests__/flavored-parsers/tables.test.js +++ /dev/null @@ -1,38 +0,0 @@ -import { mdast, hast } from '../../index'; - -describe('Parse magic block tables', () => { - it('renders an table with missing cells', () => { - const text = ` -[block:parameters] -${JSON.stringify( - { - data: { - 'h-1': 'Header 1', - '0-0': 'Cell A 1', - }, - cols: 2, - rows: 2, - }, - null, - 2 -)} -[/block] - `; - - expect(mdast(text)).toMatchSnapshot(); - }); -}); - -describe('GFM style tables', () => { - it('renders a table with invalid html in code tags', () => { - const md = ` -| Alpha | Beta | -| :-------- | :--------------------- | -| \`\` | | -`; - - const tree = hast(md); - - expect(tree.children[1].tagName).toBe('table'); - }); -}); diff --git a/__tests__/flavored-parsers/utils.test.js b/__tests__/flavored-parsers/utils.test.js deleted file mode 100644 index 44e4284e9..000000000 --- a/__tests__/flavored-parsers/utils.test.js +++ /dev/null @@ -1,62 +0,0 @@ -import { insertBlockTokenizerBefore, insertInlineTokenizerBefore } from '../../processor/parse/utils'; - -let self; - -beforeEach(() => { - self = { - Parser: { - prototype: { - blockTokenizers: {}, - blockMethods: ['one', 'two'], - inlineTokenizers: {}, - inlineMethods: ['one', 'two'], - }, - }, - }; -}); - -describe('insertBlockTokenizerBefore', () => { - it('correctly splices the tokenizer into place', () => { - insertBlockTokenizerBefore.call(self, { - name: 'test', - before: 'one', - tokenizer: () => {}, - }); - - expect(self.Parser.prototype.blockMethods).toStrictEqual(['test', 'one', 'two']); - expect(self.Parser.prototype.blockTokenizers).toHaveProperty('test'); - }); - - it('throws an error if the method does not exist', () => { - expect(() => - insertBlockTokenizerBefore.call(self, { - name: 'test', - before: 'oh no', - tokenizer: () => {}, - }) - ).toThrow("The 'oh no' tokenizer does not exist!"); - }); -}); - -describe('insertInlineTokenizerBefore', () => { - it('correctly splices the tokenizer into place', () => { - insertInlineTokenizerBefore.call(self, { - name: 'test', - before: 'one', - tokenizer: () => {}, - }); - - expect(self.Parser.prototype.inlineMethods).toStrictEqual(['test', 'one', 'two']); - expect(self.Parser.prototype.inlineTokenizers).toHaveProperty('test'); - }); - - it('throws an error if the method does not exist', () => { - expect(() => - insertInlineTokenizerBefore.call(self, { - name: 'test', - before: 'oh no', - tokenizer: () => {}, - }) - ).toThrow("The 'oh no' tokenizer does not exist!"); - }); -}); diff --git a/__tests__/gemoji-parser.test.js b/__tests__/gemoji-parser.test.js deleted file mode 100644 index 39f2c6578..000000000 --- a/__tests__/gemoji-parser.test.js +++ /dev/null @@ -1,87 +0,0 @@ -const remarkParse = require('remark-parse'); -const unified = require('unified'); - -const parser = require('../processor/parse/gemoji-parser'); - -test('should output an image node for a known emoji', () => { - const emoji = 'joy'; - const markdown = `This is a gemoji :${emoji}:.`; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a gemoji ' }, - { - type: 'image', - title: `:${emoji}:`, - alt: `:${emoji}:`, - url: `/public/img/emojis/${emoji}.png`, - data: { - hProperties: { - align: 'absmiddle', - className: 'emoji', - height: '20', - width: '20', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should output an for a font awesome icon', () => { - const emoji = 'fa-lock'; - const markdown = `This is a gemoji :${emoji}:.`; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a gemoji ' }, - { - type: 'i', - data: { - hName: 'i', - hProperties: { - className: ['fa', emoji], - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should output nothing for unknown emojis', () => { - const emoji = 'unknown-emoji'; - const markdown = `This is a gemoji :${emoji}:.`; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [{ type: 'text', value: markdown }], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); diff --git a/__tests__/helpers.js b/__tests__/helpers.js deleted file mode 100644 index 553270a18..000000000 --- a/__tests__/helpers.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports.silenceConsole = - (prop = 'error', impl = () => {}) => - fn => { - let spy; - - try { - spy = jest.spyOn(console, prop).mockImplementation(impl); - - return fn(spy); - } finally { - spy.mockRestore(); - } - }; diff --git a/__tests__/helpers.ts b/__tests__/helpers.ts new file mode 100644 index 000000000..02a330e50 --- /dev/null +++ b/__tests__/helpers.ts @@ -0,0 +1,21 @@ +import { vi } from 'vitest'; +import { run, compile } from '../index'; + +export const silenceConsole = + (prop: keyof Console = 'error', impl = () => {}) => + fn => { + let spy; + + try { + spy = vi.spyOn(console, prop).mockImplementation(impl); + + return fn(spy); + } finally { + spy.mockRestore(); + } + }; + +export const execute = async (doc: string, compileOpts = {}, runOpts = {}) => { + const module = await run(compile(doc, compileOpts), runOpts); + return module.default; +}; diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 5db8e8284..5a5efd653 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -1,17 +1,19 @@ -const { cleanup, render, screen } = require('@testing-library/react'); -const React = require('react'); +import { cleanup, render, screen } from '@testing-library/react'; +import React, { createElement } from 'react'; -const BaseUrlContext = require('../contexts/BaseUrl'); -const markdown = require('../index'); -const { options } = require('../options'); -const { tableFlattening } = require('../processor/plugin/table-flattening'); +import { Provider } from '../contexts/BaseUrl'; +import { run, compile, utils, html as _html, mdast, hast as _hast, plain, mdx, astToPlainText } from '../index'; +import { options } from '../options'; +import { tableFlattening } from '../processor/plugin/table-flattening'; -test('it should have the proper utils exports', () => { - expect(typeof markdown.utils.BaseUrlContext).toBe('object'); - expect(typeof markdown.utils.GlossaryContext).toBe('object'); - expect(typeof markdown.utils.VariablesContext).toBe('object'); +import { execute } from './helpers'; - expect(markdown.utils.options).toStrictEqual({ +test.skip('it should have the proper utils exports', () => { + expect(typeof utils.BaseUrlContext).toBe('object'); + expect(typeof utils.GlossaryContext).toBe('object'); + expect(typeof utils.VariablesContext).toBe('object'); + + expect(options).toStrictEqual({ alwaysThrow: false, compatibilityMode: false, copyButtons: true, @@ -27,107 +29,77 @@ test('it should have the proper utils exports', () => { paddedTable: true, }, normalize: true, - reusableContent: { - disabled: false, - tags: {}, - writeTags: true, - }, safeMode: false, - settings: { position: true }, + settings: { position: false }, theme: 'light', }); }); -test('image', () => { - const { container } = render(markdown.default('![Image](http://example.com/image.png)')); - expect(container.innerHTML).toMatchSnapshot(); -}); - -test('heading', () => { - const { container } = render(markdown.default('## Example Header')); +test('image', async () => { + const md = '![Image](http://example.com/image.png)'; + const component = await execute(md); + const { container } = render(React.createElement(component)); expect(container.innerHTML).toMatchSnapshot(); }); -test('magic image', () => { - const { container } = render( - markdown.default( - ` - [block:image] - { - "images": [ - { - "image": [ - "https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg", - "man-eating-pizza-and-making-an-ok-gesture.jpg", - "", - 1024, - 682, - "#d1c8c5" - ], - "caption": "A guy. Eating pizza. And making an OK gesture.", - "sizing": "full", - "align": "center" - } - ] - } - [/block] - `, - options - ) - ); - +test.skip('heading', () => { + const { container } = render(execute('## Example Header')); expect(container.innerHTML).toMatchSnapshot(); }); -test('list items', () => { - const { container } = render(markdown.default('- listitem1')); +test.skip('list items', () => { + const { container } = render(execute('- listitem1')); expect(container.innerHTML).toMatchSnapshot(); }); -test('check list items', () => { - const { container } = render(markdown.default('- [ ] checklistitem1\n- [x] checklistitem1')); +test.skip('check list items', () => { + const { container } = render(execute('- [ ] checklistitem1\n- [x] checklistitem1')); expect(container.innerHTML).toMatchSnapshot(); }); -test('gemoji generation', () => { - const { container } = render(markdown.default(':sparkles:')); +test('gemoji generation', async () => { + const component = await execute(':sparkles:'); + const { container } = render(React.createElement(component)); expect(container.querySelector('.lightbox')).not.toBeInTheDocument(); }); -test('should strip out inputs', () => { - render(markdown.default('')); +test.skip('should strip out inputs', () => { + render(execute('')); expect(screen.queryByRole('input')).not.toBeInTheDocument(); }); -test('tables', () => { - const { container } = render( - markdown.default(`| Tables | Are | Cool | +test('tables', async () => { + const component = await execute(`| Tables | Are | Cool | | ------------- |:-------------:| -----:| | col 3 is | right-aligned | $1600 | | col 2 is | centered | $12 | | zebra stripes | are neat | $1 | - `) - ); + `); + + const { container } = render(React.createElement(component)); expect(container.innerHTML.trim()).toMatchSnapshot(); }); -test('headings', () => { +test.skip('headings', () => { render( - markdown.default(`# Heading 1 + run( + compile(`# Heading 1 ## Heading 2 ### Heading 3 #### Heading 4 ##### Heading 5 -###### Heading 6`) +###### Heading 6`), + ), ); expect(screen.getAllByRole('heading')).toHaveLength(6); }); -test('anchors', () => { +test.skip('anchors', () => { const { container } = render( - markdown.default(` + run( + compile(` [link](http://example.com) [xss](javascript:alert) [doc](doc:slug) @@ -135,70 +107,71 @@ test('anchors', () => { [blog](blog:slug) [changelog](changelog:slug) [page](page:slug) -`) +`), + ), ); expect(container.innerHTML).toMatchSnapshot(); }); -test('anchor target: should default to _self', () => { - const { container } = render(markdown.default('[test](https://example.com)')); +test.skip('anchor target: should default to _self', () => { + const { container } = render(execute('[test](https://example.com)')); expect(container.innerHTML).toMatchSnapshot(); }); -test('anchor target: should allow _blank if using HTML', () => { - const { container } = render(markdown.default('test')); +test.skip('anchor target: should allow _blank if using HTML', () => { + const { container } = render(execute('test')); expect(container.innerHTML).toMatchSnapshot(); }); -test('anchor target: should allow download if using HTML', () => { - const { container } = render(markdown.default('test')); +test.skip('anchor target: should allow download if using HTML', () => { + const { container } = render(execute('test')); expect(container.innerHTML).toMatchSnapshot(); }); -test('anchors with baseUrl', () => { +test.skip('anchors with baseUrl', () => { const { container } = render( - React.createElement( - BaseUrlContext.Provider, + createElement( + Provider, { value: '/child/v1.0', }, - markdown.html( + _html( ` [doc](doc:slug) [ref](ref:slug) [blog](blog:slug) [changelog](changelog:slug) [page](page:slug) - ` - ) - ) + `, + ), + ), ); expect(container.innerHTML).toMatchSnapshot(); }); -test('anchors with baseUrl and special characters in url hash', () => { - const { container } = render(markdown.default('[ref](ref:slug#ζ•΄)')); +test.skip('anchors with baseUrl and special characters in url hash', () => { + const { container } = render(execute('[ref](ref:slug#ζ•΄)')); expect(container.innerHTML).toMatchSnapshot(); }); -test('emojis', () => { +test.skip('emojis', () => { const { container } = render( - markdown.default(` + markdown(` :joy: :fa-lock: :unknown-emoji: -`) +`), ); expect(container.innerHTML).toMatchSnapshot(); }); -describe('code samples', () => { +describe.skip('code samples', () => { it('should codify code', () => { const { container } = render( - markdown.default(` + markdown(` \`\`\`javascript var a = 1; \`\`\` @@ -206,18 +179,20 @@ describe('code samples', () => { \`\`\` code-without-language \`\`\` - `) + `), ); expect(container.querySelectorAll('pre')).toHaveLength(2); expect(container.querySelectorAll('button')).toHaveLength(3); }); - describe('`copyButtons` option', () => { + describe.skip('`copyButtons` option', () => { it('should not insert the CopyCode component if `copyButtons=false`', () => { render( - markdown.react('This is a sentence and it contains a piece of `code` wrapped in backticks.', { - copyButtons: false, - }) + run( + compile('This is a sentence and it contains a piece of `code` wrapped in backticks.', { + copyButtons: false, + }), + ), ); expect(screen.queryByRole('button')).not.toBeInTheDocument(); @@ -226,37 +201,37 @@ describe('code samples', () => { it('should parse indented code on the first line', () => { const md = ' const code = true;'; - expect(markdown.mdast(md)).toMatchSnapshot(); + expect(mdast(md)).toMatchSnapshot(); }); }); -test('should render nothing if nothing passed in', () => { - expect(markdown.html('')).toBeNull(); +test.skip('should render nothing if nothing passed in', () => { + expect(_html('')).toBeNull(); }); -test('`correctnewlines` option', () => { - let { container } = render(markdown.react('test\ntest\ntest', { correctnewlines: true })); +test.skip('`correctnewlines` option', () => { + let { container } = render(react('test\ntest\ntest', { correctnewlines: true })); expect(container).toContainHTML('

test\ntest\ntest

'); cleanup(); - ({ container } = render(markdown.react('test\ntest\ntest', { correctnewlines: false }))); + ({ container } = render(react('test\ntest\ntest', { correctnewlines: false }))); expect(container).toContainHTML('

test
\ntest
\ntest

'); }); -describe('`alwaysThrow` option', () => { +describe.skip('`alwaysThrow` option', () => { it('should throw if `alwaysThrow` is true and magic block has invalid JSON', () => { const shouldThrow = () => render( - markdown.default( + markdown( `[block:api-header] {, "title": "Uh-oh, I'm invalid", "level": 2 } [/block]`, - { alwaysThrow: true } - ) + { alwaysThrow: true }, + ), ); expect(shouldThrow).toThrow('Invalid Magic Block JSON'); @@ -265,15 +240,15 @@ describe('`alwaysThrow` option', () => { it('should not throw if `alwaysThrow` is true but magic block has valid JSON', () => { const shouldThrow = () => render( - markdown.default( + markdown( `[block:api-header] { "title": "Ooh I'm valid πŸ’…", "level": 2 } [/block]`, - { alwaysThrow: true } - ) + { alwaysThrow: true }, + ), ); expect(() => shouldThrow()).not.toThrow('Invalid Magic Block JSON'); @@ -282,40 +257,42 @@ describe('`alwaysThrow` option', () => { // TODO not sure if this needs to work or not? // Isn't it a good thing to always strip HTML? -describe('`stripHtml` option', () => { +describe.skip('`stripHtml` option', () => { it('should allow html by default', () => { - expect(markdown.html('

Test

')).toBe('

Test

'); - expect(markdown.html('

Test

', { stripHtml: false })).toBe('

Test

'); + expect(_html('

Test

')).toBe('

Test

'); + expect(_html('

Test

', { stripHtml: false })).toBe('

Test

'); }); it.skip('should escape unknown tags', () => { - expect(markdown.html('Test')).toBe('

<unknown-tag>Test</unknown-tag>

'); + expect(_html('Test')).toBe('

<unknown-tag>Test</unknown-tag>

'); }); it('should allow certain attributes', () => { - expect(markdown.html('

Test

')).toBe('

Test

'); + expect(_html('

Test

')).toBe('

Test

'); }); it('should strip unknown attributes', () => { - expect(markdown.html('

Test

')).toBe('

Test

'); + expect(_html('

Test

')).toBe('

Test

'); }); it.skip('should escape everything if `stripHtml=true`', () => { - expect(markdown.html('

Test

', { stripHtml: true })).toBe('

<p>Test</p>

\n'); + expect(_html('

Test

', { stripHtml: true })).toBe('

<p>Test</p>

\n'); }); }); -test('should strip dangerous iframe tag', () => { - const { container } = render(markdown.react('

')); +test.skip('should strip dangerous iframe tag', () => { + const { container } = render(execute('

')); expect(container).toContainHTML('

'); }); -test('should strip dangerous img attributes', () => { - const { container } = render(markdown.default('')); - expect(container).not.toContainHTML('onerror'); +test.skip('should strip dangerous img attributes', () => { + const { container } = render(execute('')); + expect(container).toContainHTML( + '', + ); }); -describe('tree flattening', () => { +describe.skip('tree flattening', () => { it('should bring nested mdast data up to the top child level', () => { const text = ` @@ -327,7 +304,7 @@ describe('tree flattening', () => { `; - const hast = markdown.hast(text); + const hast = _hast(text); const table = hast.children[1]; expect(table.children).toHaveLength(2); @@ -354,7 +331,7 @@ describe('tree flattening', () => { }); }); -describe('export multiple Markdown renderers', () => { +describe.skip('export multiple Markdown renderers', () => { const text = `# Hello World | Col. A | Col. B | Col. C | @@ -388,31 +365,31 @@ describe('export multiple Markdown renderers', () => { }; it('renders plain markdown as React', () => { - expect(markdown.plain(text)).toMatchSnapshot(); + expect(plain(text)).toMatchSnapshot(); }); it('renders custom React components', () => { - expect(markdown.react(text)).toMatchSnapshot(); + expect(execute(text)).toMatchSnapshot(); }); it('renders hAST', () => { - expect(markdown.hast(text)).toMatchSnapshot(); + expect(_hast(text)).toMatchSnapshot(); }); it('renders mdAST', () => { - expect(markdown.mdast(text)).toMatchSnapshot(); + expect(mdast(text)).toMatchSnapshot(); }); it('renders MD', () => { - expect(markdown.md(tree)).toMatchSnapshot(); + expect(mdx(tree)).toMatchSnapshot(); }); - it('renders plainText from AST', () => { - expect(markdown.astToPlainText(tree)).toMatchSnapshot(); + it.skip('renders plainText from AST', () => { + expect(astToPlainText(tree)).toMatchSnapshot(); }); - it('astToPlainText should return an empty string if no value', () => { - expect(markdown.astToPlainText()).toBe(''); + it.skip('astToPlainText should return an empty string if no value', () => { + expect(astToPlainText()).toBe(''); }); it('allows complex compact headings', () => { @@ -422,31 +399,31 @@ describe('export multiple Markdown renderers', () => { ###**6**. Oh No Lorem ipsum dolor!`; - const html = markdown.html(mdxt); + const html = _html(mdxt); expect(html).toMatchSnapshot(); }); it('renders HTML', () => { - expect(markdown.html(text)).toMatchSnapshot(); + expect(_html(text)).toMatchSnapshot(); }); it('returns null for blank input', () => { - expect(markdown.html('')).toBeNull(); - expect(markdown.plain('')).toBeNull(); - expect(markdown.react('')).toBeNull(); - expect(markdown.hast('')).toBeNull(); - expect(markdown.mdast('')).toBeNull(); - expect(markdown.md('')).toBeNull(); + expect(_html('')).toBeNull(); + expect(plain('')).toBeNull(); + expect(execute('')).toBeNull(); + expect(_hast('')).toBeNull(); + expect(mdast('')).toBeNull(); + expect(mdx('')).toBeNull(); }); }); -describe('prefix anchors with "section-"', () => { +describe.skip('prefix anchors with "section-"', () => { it('should add a section- prefix to heading anchors', () => { - expect(markdown.html('# heading')).toMatchSnapshot(); + expect(_html('# heading')).toMatchSnapshot(); }); it('"section-" anchors should split on camelCased words', () => { - const { container } = render(markdown.react('# camelCased')); + const { container } = render(execute('# camelCased')); const anchor = container.querySelectorAll('.heading-anchor_backwardsCompatibility')[0]; expect(anchor).toHaveAttribute('id', 'section-camel-cased'); diff --git a/__tests__/lib/hast.test.ts b/__tests__/lib/hast.test.ts new file mode 100644 index 000000000..49912575a --- /dev/null +++ b/__tests__/lib/hast.test.ts @@ -0,0 +1,38 @@ +import { hast, hastFromHtml } from '../../lib'; +import { h } from 'hastscript'; + +describe('hast transformer', () => { + it('parses components into the tree', () => { + const md = ` +## Test + + + `; + const components = { + Example: "## It's coming from within the component!", + }; + + const expected = h( + undefined, + h('h2', { id: 'test' }, 'Test'), + '\n', + h('h2', { id: 'its-coming-from-within-the-component' }, "It's coming from within the component!"), + ); + + expect(hast(md, { components })).toStrictEqualExceptPosition(expected); + }); +}); + +describe('hastFromHtml', () => { + it('parses html', () => { + const html = '
Nice
'; + const tree = hastFromHtml(html); + + // @ts-ignore + expect(tree.children[0].tagName).toBe('html'); + // @ts-ignore + expect(tree.children[0].children[1].children[0].tagName).toBe('div'); + // @ts-ignore + expect(tree.children[0].children[1].children[0].children[0].tagName).toBe('span'); + }); +}); diff --git a/__tests__/lib/mdast.test.ts b/__tests__/lib/mdast.test.ts new file mode 100644 index 000000000..e5d9bc3e6 --- /dev/null +++ b/__tests__/lib/mdast.test.ts @@ -0,0 +1,13 @@ +import { mdast } from '../../lib'; + +describe('mdast transformer', () => { + it('parses variables into the tree', () => { + const md = ` +Hello, {user.name} + `; + + const ast = mdast(md); + expect(ast.children[0].children[1].type).toBe('readme-variable'); + expect(ast.children[0].children[1].value).toBe('{user.name}'); + }); +}); diff --git a/__tests__/lib/plain.test.ts b/__tests__/lib/plain.test.ts new file mode 100644 index 000000000..6821fc775 --- /dev/null +++ b/__tests__/lib/plain.test.ts @@ -0,0 +1,56 @@ +import { hast, plain } from '../../index'; + +describe('plain compiler', () => { + it('returns plain text of markdown components', () => { + const md = ` +## Hello! + +Is it _me_ you're looking for? +`; + + const tree = hast(md); + expect(plain(tree)).toEqual("Hello! Is it me you're looking for?"); + }); + + it("compiles br's to ''", () => { + const txt = '
'; + + expect(plain(hast(txt))).toBe(''); + }); + + it("compiles hr's to ''", () => { + const txt = '
'; + + expect(plain(hast(txt))).toBe(''); + }); + + it('compiles callouts', () => { + const txt = ` +> πŸ“˜ Title +> +> Some body + `; + const tree = hast(txt); + + expect(plain(tree)).toBe('Title Some body'); + }); + + it('compiles markdown tables', () => { + const txt = ` +| Header 1 | Header 2 | +| :------- | :------- | +| Cell 1 | Cell 2 | + `; + + expect(plain(hast(txt))).toBe('Header 1 Header 2 Cell 1 Cell 2'); + }); + + it('compiles images to their title', () => { + const txt = ` +![image **label**](http://placekitten.com/600/600 "entitled kittens") + `; + const tree = hast(txt); + + expect(plain(tree)).toBe('entitled kittens'); + }); +}); diff --git a/__tests__/lib/registerCustomComponents.test.js b/__tests__/lib/registerCustomComponents.test.jsx similarity index 86% rename from __tests__/lib/registerCustomComponents.test.js rename to __tests__/lib/registerCustomComponents.test.jsx index 715b62b0d..11271df70 100644 --- a/__tests__/lib/registerCustomComponents.test.js +++ b/__tests__/lib/registerCustomComponents.test.jsx @@ -1,8 +1,8 @@ -const PropTypes = require('prop-types'); -const React = require('react'); +import { any } from 'prop-types'; +import React from 'react'; -const registerCustomComponents = require('../../lib/registerCustomComponents'); -const createSchema = require('../../sanitize.schema'); +import registerCustomComponents from '../../lib/registerCustomComponents'; +import createSchema from '../../sanitize.schema'; const hastPrefix = 'prefix'; const customComponents = { @@ -17,8 +17,8 @@ const customComponents = { }, }; -customComponents.a.propTypes = { attrToConcatToSafelist: PropTypes.any }; -customComponents.twoWords.propTypes = { attrToBeSafelisted: PropTypes.any }; +customComponents.a.propTypes = { attrToConcatToSafelist: any }; +customComponents.twoWords.propTypes = { attrToBeSafelisted: any }; describe('Custom Component Registrar', () => { let registered; diff --git a/__tests__/link-parsers.test.js b/__tests__/link-parsers.test.js index cef88f877..b0ad01f29 100644 --- a/__tests__/link-parsers.test.js +++ b/__tests__/link-parsers.test.js @@ -1,29 +1,29 @@ -const markdown = require('../index'); +import { mdast } from '../index'; -test('a link with label', () => { - expect(markdown.mdast('[link](http://www.foo.com)')).toMatchSnapshot(); +test.skip('a link with label', () => { + expect(mdast('[link](http://www.foo.com)')).toMatchSnapshot(); }); -test('a link with no url', () => { - expect(markdown.mdast('[link]()')).toMatchSnapshot(); +test.skip('a link with no url', () => { + expect(mdast('[link]()')).toMatchSnapshot(); }); -test('a link ref', () => { - expect(markdown.mdast('[link]')).toMatchSnapshot(); +test.skip('a link ref', () => { + expect(mdast('[link]')).toMatchSnapshot(); }); -test('a link ref with reference', () => { - expect(markdown.mdast('[link]\n\n[link]: www.example.com')).toMatchSnapshot(); +test.skip('a link ref with reference', () => { + expect(mdast('[link]\n\n[link]: www.example.com')).toMatchSnapshot(); }); -test('a bracketed autoLinked url', () => { - expect(markdown.mdast('')).toMatchSnapshot(); +test.skip('a bracketed autoLinked url', () => { + expect(mdast('')).toMatchSnapshot(); }); -test('a bare autoLinked url', () => { - expect(markdown.mdast('http://www.googl.com')).toMatchSnapshot(); +test.skip('a bare autoLinked url', () => { + expect(mdast('http://www.googl.com')).toMatchSnapshot(); }); test.skip('a bare autoLinked url with no protocol', () => { - expect(markdown.mdast('www.google.com')).toMatchSnapshot(); + expect(mdast('www.google.com')).toMatchSnapshot(); }); diff --git a/__tests__/magic-block-parser.test.js b/__tests__/magic-block-parser.test.js deleted file mode 100644 index 564d2e52e..000000000 --- a/__tests__/magic-block-parser.test.js +++ /dev/null @@ -1,290 +0,0 @@ -const rehypeSanitize = require('rehype-sanitize'); -const remarkParse = require('remark-parse'); -const unified = require('unified'); - -const options = require('../options').options.markdownOptions; -const parser = require('../processor/parse/magic-block-parser'); - -const sanitize = { attributes: [] }; -const process = (text, opts = options) => - text && - unified() - .use(remarkParse, opts) - .data('settings', { position: false }) - .use(parser.sanitize(sanitize)) - .use(rehypeSanitize) - .parse(text); - -test('Blank Magic Blocks', () => { - const blank = `[block:api-header] - {} - [/block]`; - expect(process(blank)).toMatchSnapshot(); - - const blankBasic = `[block:api-header] - { "type": "basic" } - [/block] - `; - expect(process(blankBasic)).toMatchSnapshot(); - - const noTitle = `[block:api-header] - { "level": 2 } - [/block]`; - expect(process(noTitle)).toMatchSnapshot(); - - const noLevel = `[block:api-header] - { "title": "No Level" } - [/block]`; - expect(process(noLevel)).toMatchSnapshot(); - - const emptyTable = `[block:parameters] - { - "data": {}, - "cols": 3, - "rows": 1 - } - [/block]`; - expect(process(emptyTable).children).toHaveLength(0); - - const emptyCallout = `[block:callout] - { - "type": "info", - "title": "" - } - [/block]`; - expect(process(emptyCallout).children).toHaveLength(0); - - const emptyCodeTabs = `[block:code] - { - "codes": [ - { - "code": "", - "language": "text" - } - ] - } - [/block]`; - expect(process(emptyCodeTabs).children).toHaveLength(0); - - const emptyImage = `[block:image] - { - "images": [ - { - "image": [] - } - ] - } - [/block]`; - expect(process(emptyImage).children).toHaveLength(0); - - const nullImage = `[block:image] - { - "images": [ - {} - ] - } - [/block]`; - expect(process(nullImage).children).toHaveLength(0); -}); - -test('Sanitize Schema', () => { - parser.sanitize(sanitize); - expect(sanitize).toMatchSnapshot(); -}); - -describe('Parse Magic Blocks', () => { - it('Heading Blocks', () => { - const text = `[block:api-header] - { - "title": "MagicBlock Conversion", - "level": 2 - } - [/block] - - [block:api-header] - {} - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Image Blocks', () => { - const text = `[block:image] - { - "images": [ - { - "image": [ - "https://files.readme.io/62083ee-White_Center_Blue_BG.svg", - "White Center Blue BG.svg", - "", - 240, - 150, - "#000000" - ], - "caption": "Qui iusto fugiat doloremque? Facilis obcaecati vitae corrupti.", - "sizing": "80", - "border": true, - "align": "center" - } - ] - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Code Blocks', () => { - const text = `[block:code] - { - "codes": [ - { - "code": "$http.post('/someUrl', data).success(successCallback);\\n\\nalert('test');", - "language": "javascript" - }, - { - "code": "second tab", - "language": "text", - "name": "custom title" - } - ] - } - - [/block][block:code] - { - "sidebar": true, - "codes": [ - { - "code": "$http.post('/someUrl', data).success(successCallback);\\n\\nalert('test');", - "language": "javascript" - } - ] - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Table Blocks', () => { - const text = `[block:parameters] - { - "data": { - "h-0": "Left", - "h-1": "Center", - "h-2": "Right", - "0-0": "L0", - "0-1": "*bold*", - "0-2": "$1600", - "2-0": "L2", - "1-0": "L1", - "1-1": "\`code\`", - "1-2": "$12", - "2-1": "_italic_", - "2-2": "$1" - }, - "cols": 3, - "rows": 3 - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Embed Blocks', () => { - const text = `[block:embed] - { - "html": false, - "url": "https://youtu.be/J3-uKv1DShQ", - "title": null, - "favicon": "https://youtu.be/favicon.ico", - "iframe": false - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Embed Blocks with invalid URL', () => { - const text = `[block:embed] - { - "html": false, - "url": "www.youtu.be/J3-uKv1DShQ", - "title": null, - "favicon": "https://youtu.be/favicon.ico", - "iframe": false - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Embed Blocks with empty URL', () => { - const text = `[block:embed] - { - "url": "", - "typeOfEmbed": "youtube", - "provider": "embed" - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Callout Blocks', () => { - const text = `[block:callout] - { - "type": "success", - "title": "Callout Title", - "body": "Lorem ipsum dolor sit amet, _consectetur_ adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum" - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Custom Callout Blocks', () => { - const text = `[block:callout] - { - "type": "custom_theme", - "icon": "✨", - "title": "Callout Title", - "body": "Lorem ipsum dolor sit amet..." - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Custom HTML Block', () => { - const text = `[block:html] - ${JSON.stringify({ - html: '

πŸ‘‹πŸŒ

\n
\n
\n \n
\n Go\n
', - })} - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Custom Default Block', () => { - const text = `[block:tutorial-tile] - { - "backgroundColor": "#ffffff", - "title": "Tutorial Title", - "emoji": "πŸ¦‰", - "link": "http://test.com" - } - [/block]`; - - expect(process(text)).toMatchSnapshot(); - }); - - it('Unrecognized Blocks', () => { - const text = `[block:unrecognized] - { - "color": "#f00", - "title": "Title", - "body": "Lorem ipsum dolor sit amet, _consectetur_ adipiscing elit. Praesent nec massa tristique arcu fermentum dapibus. Integer orci turpis, mollis vel augue eget, placerat rhoncus orci. Mauris metus libero, rutrum" - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); - - it('Block with invalid JSON', () => { - const text = `[block:api-header] - {, - "title": "Uh-oh, I'm invalid", - "level": 2 - } - [/block]`; - expect(process(text)).toMatchSnapshot(); - }); -}); diff --git a/__tests__/magic-block-parser/__snapshots__/table.test.js.snap b/__tests__/magic-block-parser/__snapshots__/table.test.js.snap deleted file mode 100644 index 6ef1f54f7..000000000 --- a/__tests__/magic-block-parser/__snapshots__/table.test.js.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Table Blocks does not display data outside the declared dimensions 1`] = ` -Object { - "children": Array [ - Object { - "align": Array [ - "left", - "left", - ], - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Left", - }, - ], - "type": "tableHead", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Center", - }, - ], - "type": "tableHead", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Left 0", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Center 0", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "Left 1", - }, - ], - "type": "tableCell", - }, - Object { - "children": Array [ - Object { - "type": "text", - "value": "Center 1", - }, - ], - "type": "tableCell", - }, - ], - "type": "tableRow", - }, - ], - "type": "table", - }, - ], - "type": "root", -} -`; diff --git a/__tests__/magic-block-parser/table.test.js b/__tests__/magic-block-parser/table.test.js deleted file mode 100644 index cb25e00b2..000000000 --- a/__tests__/magic-block-parser/table.test.js +++ /dev/null @@ -1,43 +0,0 @@ -const rehypeSanitize = require('rehype-sanitize'); -const remarkParse = require('remark-parse'); -const unified = require('unified'); - -const options = require('../../options').options.markdownOptions; -const parser = require('../../processor/parse/magic-block-parser'); - -const sanitize = { attributes: [] }; -const process = (text, opts = options) => - text && - unified() - .use(remarkParse, opts) - .data('settings', { position: false }) - .use(parser.sanitize(sanitize)) - .use(rehypeSanitize) - .parse(text); - -describe('Table Blocks', () => { - it('does not display data outside the declared dimensions', () => { - const text = `[block:parameters] - { - "data": { - "h-0": "Left", - "h-1": "Center", - "h-2": "Right", - "0-0": "Left 0", - "0-1": "Center 0", - "0-2": "Right 0", - "1-0": "Left 1", - "1-1": "Center 1", - "1-2": "Right 1", - "2-0": "Left 2", - "2-1": "Center 2", - "2-2": "Right 2" - }, - "cols": 2, - "rows": 2 - } - [/block]`; - - expect(process(text)).toMatchSnapshot(); - }); -}); diff --git a/__tests__/matchers.ts b/__tests__/matchers.ts new file mode 100644 index 000000000..31767de42 --- /dev/null +++ b/__tests__/matchers.ts @@ -0,0 +1,22 @@ +import { expect } from 'vitest'; +import { map } from 'unist-util-map'; + +import type { ExpectationResult } from '@vitest/expect'; +import { Root, Node } from 'mdast'; + +const removePosition = ({ position, ...node }: Node) => node; + +function toStrictEqualExceptPosition(received: Root, expected: Root): ExpectationResult { + const { equals } = this; + const receivedTrimmed = map(received, removePosition); + const expectedTrimmed = map(expected, removePosition); + + return { + pass: equals(receivedTrimmed, expectedTrimmed), + message: () => 'Expected two trees to be equal!', + actual: receivedTrimmed, + expected: expectedTrimmed, + }; +} + +expect.extend({ toStrictEqualExceptPosition }); diff --git a/__tests__/normalize.test.js b/__tests__/normalize.test.js deleted file mode 100644 index 8a5cb78c3..000000000 --- a/__tests__/normalize.test.js +++ /dev/null @@ -1,38 +0,0 @@ -import { mdast } from '../index'; - -describe('normalize option', () => { - it('normalizes magic block newlines', () => { - const doc = ` -> blockquote -> -[block:image] -{ - "images": [ - { - "image": [ - "https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", - "", - "" - ], - "align": "center" - } - ] -} -[/block] -`; - const tree = mdast(doc); - - expect(tree.children[1].type).toBe('image'); - }); - - it('does not normalize nested magic blocks', () => { - const doc = ` -> blockquote -> -> [block:image]{ "images": [ { "image": [ "https://owlbertsio-resized.s3.amazonaws.com/This-Is-Fine.jpg.full.png", "", "" ], "align": "center" } ]}[/block] -`; - const tree = mdast(doc, { normalize: false }); - - expect(tree.children[0].children[1].type).toBe('image'); - }); -}); diff --git a/__tests__/parsers/__snapshots__/callouts.test.js.snap b/__tests__/parsers/__snapshots__/callouts.test.js.snap new file mode 100644 index 000000000..001cd713f --- /dev/null +++ b/__tests__/parsers/__snapshots__/callouts.test.js.snap @@ -0,0 +1,111 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Parse RDMD Callouts > renders an info callout 1`] = ` +{ + "children": [ + { + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 18, + "line": 2, + "offset": 18, + }, + "start": { + "column": 3, + "line": 2, + "offset": 3, + }, + }, + "type": "text", + "value": "Info Callout", + }, + ], + "position": { + "end": { + "column": 18, + "line": 2, + "offset": 18, + }, + "start": { + "column": 3, + "line": 2, + "offset": 3, + }, + }, + "type": "paragraph", + }, + { + "children": [ + { + "position": { + "end": { + "column": 60, + "line": 4, + "offset": 80, + }, + "start": { + "column": 3, + "line": 4, + "offset": 23, + }, + }, + "type": "text", + "value": "Lorem ipsum dolor sit amet consectetur adipisicing elit.", + }, + ], + "position": { + "end": { + "column": 60, + "line": 4, + "offset": 80, + }, + "start": { + "column": 3, + "line": 4, + "offset": 23, + }, + }, + "type": "paragraph", + }, + ], + "data": { + "hName": "Callout", + "hProperties": { + "empty": false, + "icon": "ℹ️", + }, + }, + "position": { + "end": { + "column": 60, + "line": 4, + "offset": 80, + }, + "start": { + "column": 1, + "line": 2, + "offset": 1, + }, + }, + "type": "rdme-callout", + }, + ], + "position": { + "end": { + "column": 60, + "line": 4, + "offset": 80, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "root", +} +`; diff --git a/__tests__/parsers/__snapshots__/compact-headings.test.js.snap b/__tests__/parsers/__snapshots__/compact-headings.test.js.snap new file mode 100644 index 000000000..7db631082 --- /dev/null +++ b/__tests__/parsers/__snapshots__/compact-headings.test.js.snap @@ -0,0 +1,108 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Compact headings > can parse compact headings 1`] = ` +{ + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 17, + "line": 1, + "offset": 16, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "text", + "value": "#Compact Heading", + }, + ], + "position": { + "end": { + "column": 17, + "line": 1, + "offset": 16, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "paragraph", + }, + ], + "position": { + "end": { + "column": 17, + "line": 1, + "offset": 16, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "root", +} +`; + +exports[`Compact headings > can parse headings that are not compact 1`] = ` +{ + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 22, + "line": 1, + "offset": 21, + }, + "start": { + "column": 3, + "line": 1, + "offset": 2, + }, + }, + "type": "text", + "value": "Non-compact Heading", + }, + ], + "depth": 1, + "position": { + "end": { + "column": 22, + "line": 1, + "offset": 21, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "heading", + }, + ], + "position": { + "end": { + "column": 22, + "line": 1, + "offset": 21, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "root", +} +`; diff --git a/__tests__/parsers/__snapshots__/escape.test.js.snap b/__tests__/parsers/__snapshots__/escape.test.js.snap new file mode 100644 index 000000000..60dc6d540 --- /dev/null +++ b/__tests__/parsers/__snapshots__/escape.test.js.snap @@ -0,0 +1,54 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Escape > uses the "escape" type 1`] = ` +{ + "children": [ + { + "children": [ + { + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "text", + "value": "¶", + }, + ], + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "paragraph", + }, + ], + "position": { + "end": { + "column": 8, + "line": 1, + "offset": 7, + }, + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "root", +} +`; diff --git a/__tests__/flavored-parsers/callouts.test.js b/__tests__/parsers/callouts.test.js similarity index 52% rename from __tests__/flavored-parsers/callouts.test.js rename to __tests__/parsers/callouts.test.js index 42895fb01..89b833589 100644 --- a/__tests__/flavored-parsers/callouts.test.js +++ b/__tests__/parsers/callouts.test.js @@ -10,22 +10,17 @@ describe('Parse RDMD Callouts', () => { expect(mdast(text)).toMatchSnapshot(); }); - it('supports a default theme', () => { - const text = ` -> πŸ₯‡ Themeless -> -> Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - - expect(mdast(text)).toMatchSnapshot(); - }); - it('parses a callout with no title', () => { const text = ` > ℹ️ > > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + + expect(tree.children[0].type).toBe('rdme-callout'); + expect(tree.children[0].data.hProperties.icon).toBe('ℹ️'); + expect(tree.children[0].data.hProperties.empty).toBe(true); }); describe('edge cases', () => { @@ -36,15 +31,21 @@ describe('Parse RDMD Callouts', () => { > With html! `; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + expect(tree.children[0].children[1].children[0].children[0].value).toBe('With html!'); + expect(tree.children[0].children[1].children[0].type).toBe('mdxJsxTextElement'); }); - it('does not allow trailing spaces after the icon with no title', () => { + it('allows trailing spaces after the icon', () => { const text = ` > πŸ›‘ > Compact headings must be followed by two line breaks before the following block.`; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + expect(tree.children[0].data.hProperties.icon).toBe('πŸ›‘'); + expect(tree.children[0].children[0].children[0].value).toBe( + 'Compact headings must be followed by two line breaks before the following block.', + ); }); }); @@ -54,25 +55,32 @@ describe('Parse RDMD Callouts', () => { > > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + expect(tree.children[0].type).toBe('blockquote'); }); - it('allows nested callouts', () => { + it('allows callouts nested in lists', () => { const text = ` - list item > ℹ️ Info Callout > > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + + expect(tree.children[0].children[0].children[1].type).toBe('rdme-callout'); }); - it('does not require a line break between the title and the body', () => { + it('does require a line break between the title and the body', () => { const text = ` > πŸ’ Undocumented Behavior > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - expect(mdast(text)).toMatchSnapshot(); + const tree = mdast(text); + expect(tree.children[0].children[0].children[0].value).toBe( + `Undocumented Behavior +Lorem ipsum dolor sit amet consectetur adipisicing elit.`, + ); }); }); @@ -85,8 +93,11 @@ describe('emoji modifier support', () => { > ${emoji} > > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; + const ast = mdast(text); - expect(ast).toMatchSnapshot(); + + expect(ast.children[0].type).toBe('rdme-callout'); + expect(ast.children[0].data.hProperties.icon).toStrictEqual(emoji); }); }); }); diff --git a/__tests__/parsers/compact-headings.test.js b/__tests__/parsers/compact-headings.test.js new file mode 100644 index 000000000..6c34f13eb --- /dev/null +++ b/__tests__/parsers/compact-headings.test.js @@ -0,0 +1,13 @@ +import { mdast } from '../../index'; + +describe('Compact headings', () => { + it('can parse compact headings', () => { + const heading = '#Compact Heading'; + expect(mdast(heading, { settings: { position: true } })).toMatchSnapshot(); + }); + + it('can parse headings that are not compact', () => { + const heading = '# Non-compact Heading'; + expect(mdast(heading, { settings: { position: true } })).toMatchSnapshot(); + }); +}); diff --git a/__tests__/flavored-parsers/escape.test.js b/__tests__/parsers/escape.test.js similarity index 100% rename from __tests__/flavored-parsers/escape.test.js rename to __tests__/parsers/escape.test.js diff --git a/__tests__/parsers/gemoji.test.ts b/__tests__/parsers/gemoji.test.ts new file mode 100644 index 000000000..34991623f --- /dev/null +++ b/__tests__/parsers/gemoji.test.ts @@ -0,0 +1,64 @@ +import { mdast } from '../../index'; + +describe('gemoji parser', () => { + it('should output an emoji node for a known emoji', () => { + const markdown = `This is a gemoji :joy:.`; + const tree = mdast(markdown); + + expect(tree.children[0].children[1]).toMatchInlineSnapshot(` + { + "name": "joy", + "type": "gemoji", + "value": "πŸ˜‚", + } + `); + }); + + it('should output an image node for a readme emoji', () => { + const markdown = `This is a gemoji :owlbert:.`; + + expect(mdast(markdown).children[0].children[1]).toMatchInlineSnapshot(` + { + "alt": ":owlbert:", + "data": { + "hProperties": { + "align": "absmiddle", + "className": "emoji", + "height": "20", + "width": "20", + }, + }, + "title": ":owlbert:", + "type": "image", + "url": "/public/img/emojis/owlbert.png", + } + `); + }); + + it('should output an for a font awesome icon', () => { + const markdown = `This is a gemoji :fa-lock:.`; + const tree = mdast(markdown); + + expect(tree.children[0].children[1]).toMatchInlineSnapshot(` + { + "data": { + "hName": "i", + "hProperties": { + "className": [ + "fa", + "fa-lock", + ], + }, + }, + "type": "i", + "value": "fa-lock", + } + `); + }); + + it('should output nothing for unknown emojis', () => { + const markdown = `This is a gemoji :unknown-emoji:.`; + + expect(mdast(markdown).children[0].children[0].value).toMatch(/:unknown-emoji:/); + }); +}); diff --git a/__tests__/plugins/toc.test.tsx b/__tests__/plugins/toc.test.tsx new file mode 100644 index 000000000..8c67c214a --- /dev/null +++ b/__tests__/plugins/toc.test.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { compile, run } from '../../index'; + +describe('toc transformer', () => { + it('parses out a toc with max depth of 2', async () => { + const md = ` +# Title + +## Subheading + +### Third + +## Second Subheading +`; + const { Toc } = await run(compile(md)); + + render(); + + expect(screen.findByText('Title')).toBeDefined(); + expect(screen.findByText('Subheading')).toBeDefined(); + expect(screen.queryByText('Third')).toBeNull(); + expect(screen.findByText('Second Subheading')).toBeDefined(); + }); + + it('parses a toc from components', async () => { + const md = ` +# Title + + + +## Subheading +`; + const components = { + CommonInfo: '## Common Heading', + }; + const executed = { + CommonInfo: await run(compile('## Common Heading')), + }; + + const { Toc } = await run(compile(md, { components }), { components: executed }); + + render(); + + expect(screen.findByText('Title')).toBeDefined(); + expect(screen.findByText('Common Heading')).toBeDefined(); + expect(screen.findByText('Subheading')).toBeDefined(); + }); +}); diff --git a/__tests__/react.test.tsx b/__tests__/react.test.tsx new file mode 100644 index 000000000..b1916fda7 --- /dev/null +++ b/__tests__/react.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { execute } from './helpers'; + +describe('import React', () => { + it('allows importing react', async () => { + const mdx = ` +import { useState } from 'react'; + +export default function Counter() { + const [count, setCount] = useState(0) + + return ( +
+

You clicked {count} times!

+ +
+ ) +} + + + `; + + const Content = await execute(mdx); + render(); + + expect(screen.getByText('You clicked 0 times!')).toBeVisible(); + userEvent.click(screen.getByRole('button')); + + await waitFor(() => screen.getByText('You clicked 1 times!')); + }); +}); diff --git a/__tests__/table-flattening/index.test.js b/__tests__/table-flattening/index.test.js index b6c6aa466..176a61410 100644 --- a/__tests__/table-flattening/index.test.js +++ b/__tests__/table-flattening/index.test.js @@ -1,6 +1,6 @@ -const { astToPlainText, hast } = require('../../index'); +import { astToPlainText, hast } from '../../index'; -describe('astToPlainText with tables', () => { +describe.skip('astToPlainText with tables', () => { it('includes all cells', () => { const text = ` | Col. A | Col. B | Col. C | @@ -21,48 +21,6 @@ describe('astToPlainText with tables', () => { | Cell *A1* | *Cell B1* | | *Cell* A2 | *Cell* B2 |`; - expect(astToPlainText(hast(text))).toMatchInlineSnapshot('"Col. A Col. B Cell A1 Cell B1 Cell A2 Cell B2"'); - }); -}); - -describe('hast(table)', () => { - it('should populate value on the tables children', () => { - const text = ` - - - - - - - - - - - - - - - - - - -
- Test table -
Col ACol B
Donuts3,000
Stationery18,000
- `; - const ast = hast(text); - const table = ast.children[0]; - - expect(table.children.map(child => child.value)).toMatchInlineSnapshot(` - Array [ - "", - "Test table", - "", - "Col A Col B", - "", - "Donuts 3,000 Stationery 18,000", - "", - ] - `); + expect(astToPlainText(hast(text))).toMatchInlineSnapshot('"Col. A Col. B Cell A1 Cell B1 Cell A2 Cell B2"'); }); }); diff --git a/__tests__/transformers/__snapshots__/reusable-content.test.js.snap b/__tests__/transformers/__snapshots__/reusable-content.test.js.snap index 712663c7b..4f2a390ec 100644 --- a/__tests__/transformers/__snapshots__/reusable-content.test.js.snap +++ b/__tests__/transformers/__snapshots__/reusable-content.test.js.snap @@ -1,213 +1,43 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`reusable content transfomer should replace a reusable content block if the block is provided 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 7, - "line": 2, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Test", - }, - ], - "data": Object { - "hProperties": Object { - "id": "test", - }, - "id": "test", - }, - "depth": 1, - "position": Position { - "end": Object { - "column": 7, - "line": 2, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "heading", +exports[`reusable content transfomer > should replace a reusable content block if the block is provided 1`] = ` +{ + "attributes": [], + "children": [], + "name": "Test", + "position": { + "end": { + "column": 9, + "line": 4, + "offset": 17, }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 6, - "line": 4, - "offset": 14, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 4, - "offset": 10, - }, - }, - "type": "text", - "value": "link", - }, - ], - "position": Position { - "end": Object { - "column": 27, - "line": 4, - "offset": 35, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 4, - "offset": 9, - }, - }, - "title": null, - "type": "link", - "url": "http://example.com", - }, - ], - "position": Position { - "end": Object { - "column": 27, - "line": 4, - "offset": 35, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 4, - "offset": 9, - }, - }, - "type": "paragraph", + "start": { + "column": 1, + "line": 4, + "offset": 9, }, - ], - "tag": "Test", - "type": "reusable-content", + }, + "type": "mdxJsxFlowElement", } `; -exports[`reusable content transfomer should replace a reusable content block with multiple words if the block is provided 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 7, - "line": 2, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "Test", - }, - ], - "data": Object { - "hProperties": Object { - "id": "test", - }, - "id": "test", - }, - "depth": 1, - "position": Position { - "end": Object { - "column": 7, - "line": 2, - "offset": 7, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "heading", +exports[`reusable content transfomer > should replace a reusable content block with multiple words if the block is provided 1`] = ` +{ + "attributes": [], + "children": [], + "name": "MyCustomComponent", + "position": { + "end": { + "column": 22, + "line": 1, + "offset": 21, }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Position { - "end": Object { - "column": 6, - "line": 4, - "offset": 14, - }, - "indent": Array [], - "start": Object { - "column": 2, - "line": 4, - "offset": 10, - }, - }, - "type": "text", - "value": "link", - }, - ], - "position": Position { - "end": Object { - "column": 27, - "line": 4, - "offset": 35, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 4, - "offset": 9, - }, - }, - "title": null, - "type": "link", - "url": "http://example.com", - }, - ], - "position": Position { - "end": Object { - "column": 27, - "line": 4, - "offset": 35, - }, - "indent": Array [], - "start": Object { - "column": 1, - "line": 4, - "offset": 9, - }, - }, - "type": "paragraph", + "start": { + "column": 1, + "line": 1, + "offset": 0, }, - ], - "tag": "MyCustomComponent", - "type": "reusable-content", + }, + "type": "mdxJsxFlowElement", } `; diff --git a/__tests__/transformers/__snapshots__/single-code-tabs.test.js.snap b/__tests__/transformers/__snapshots__/single-code-tabs.test.js.snap deleted file mode 100644 index 11a92de82..000000000 --- a/__tests__/transformers/__snapshots__/single-code-tabs.test.js.snap +++ /dev/null @@ -1,129 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Single Code Tab Transformer wraps single code blocks with tabs if they have a lang set 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": "javascript", - "meta": null, - }, - }, - "lang": "javascript", - "meta": null, - "position": Position { - "end": Object { - "column": 4, - "line": 4, - "offset": 44, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "code", - "value": "const languageSet = true;", - }, - ], - "className": "tabs", - "data": Object { - "hName": "div", - "hProperties": Object { - "className": Array [ - "code-tabs", - ], - }, - }, - "type": "code-tabs", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 7, - "offset": 48, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`Single Code Tab Transformer wraps single code blocks with tabs if they have a title set 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { - "className": "tab-panel", - "data": Object { - "hName": "code", - "hProperties": Object { - "lang": "javascript", - "meta": "Testing", - }, - }, - "lang": "javascript", - "meta": "Testing", - "position": Position { - "end": Object { - "column": 4, - "line": 4, - "offset": 52, - }, - "indent": Array [ - 1, - 1, - ], - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "type": "code", - "value": "const languageSet = true;", - }, - ], - "className": "tabs", - "data": Object { - "hName": "div", - "hProperties": Object { - "className": Array [ - "code-tabs", - ], - }, - }, - "type": "code-tabs", - }, - ], - "position": Object { - "end": Object { - "column": 2, - "line": 7, - "offset": 56, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/__tests__/transformers/__snapshots__/table-cell-inline-code.test.js.snap b/__tests__/transformers/__snapshots__/table-cell-inline-code.test.js.snap index 0d4062c97..1fa9feda0 100644 --- a/__tests__/transformers/__snapshots__/table-cell-inline-code.test.js.snap +++ b/__tests__/transformers/__snapshots__/table-cell-inline-code.test.js.snap @@ -1,747 +1,9 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`tableCellInlineCode preserves escaped pipe chars inside text table cells 1`] = ` -Object { - "children": Array [ - Object { - "type": "text", - "value": " +exports[`tableCellInlineCode > preserves escaped pipe chars inside text table cells 1`] = `undefined`; +exports[`tableCellInlineCode > splits table cells when inline code contains "unescaped" pipe chars 1`] = `undefined`; +exports[`tableCellInlineCode > unescapes escaped pipe chars inside inline code within table cells 1`] = `undefined`; - - - -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 54, - "line": 2, - "offset": 54, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "these | stay | escaped | inside | a single cell", - }, - ], - "position": Object { - "end": Object { - "column": 54, - "line": 2, - "offset": 54, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [], - "position": Object { - "end": Object { - "column": 57, - "line": 2, - "offset": 57, - }, - "start": Object { - "column": 57, - "line": 2, - "offset": 57, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 58, - "line": 2, - "offset": 58, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 58, - "line": 2, - "offset": 58, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "thead", - "type": "element", - "value": "these | stay | escaped | inside | a single cell", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 3, - "offset": 70, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "table", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 74, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`tableCellInlineCode splits table cells when inline code contains "unescaped" pipe chars 1`] = ` -Object { - "children": Array [ - Object { - "type": "text", - "value": " - - - - - - -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 8, - "line": 2, - "offset": 8, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "type": "text", - "value": "\`this", - }, - ], - "position": Object { - "end": Object { - "column": 8, - "line": 2, - "offset": 8, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 17, - "line": 2, - "offset": 17, - }, - "start": Object { - "column": 11, - "line": 2, - "offset": 11, - }, - }, - "type": "text", - "value": "splits", - }, - ], - "position": Object { - "end": Object { - "column": 17, - "line": 2, - "offset": 17, - }, - "start": Object { - "column": 11, - "line": 2, - "offset": 11, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 51, - "line": 2, - "offset": 51, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 51, - "line": 2, - "offset": 51, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "thead", - "type": "element", - "value": "\`this splits", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 3, - "offset": 63, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "table", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 67, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`tableCellInlineCode unescapes escaped pipe chars inside inline code within table cells 1`] = ` -Object { - "children": Array [ - Object { - "type": "text", - "value": " - - - - - - - - - - - - -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "position": Object { - "end": Object { - "column": 6, - "line": 2, - "offset": 6, - }, - "start": Object { - "column": 6, - "line": 2, - "offset": 6, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [], - "position": Object { - "end": Object { - "column": 11, - "line": 2, - "offset": 11, - }, - "start": Object { - "column": 11, - "line": 2, - "offset": 11, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 2, - "offset": 12, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "thead", - "type": "element", - "value": "", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "one | two | three | four", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 4, - "offset": 56, - }, - "start": Object { - "column": 3, - "line": 4, - "offset": 27, - }, - }, - "properties": Object {}, - "tagName": "code", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 4, - "offset": 56, - }, - "start": Object { - "column": 3, - "line": 4, - "offset": 27, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "td", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 38, - "line": 4, - "offset": 62, - }, - "start": Object { - "column": 35, - "line": 4, - "offset": 59, - }, - }, - "type": "text", - "value": "two", - }, - ], - "position": Object { - "end": Object { - "column": 38, - "line": 4, - "offset": 62, - }, - "start": Object { - "column": 35, - "line": 4, - "offset": 59, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "td", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 40, - "line": 4, - "offset": 64, - }, - "start": Object { - "column": 1, - "line": 4, - "offset": 25, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 40, - "line": 4, - "offset": 64, - }, - "start": Object { - "column": 1, - "line": 4, - "offset": 25, - }, - }, - "properties": Object {}, - "tagName": "tbody", - "type": "element", - "value": "one | two | three | four two", - }, - ], - "position": Object { - "end": Object { - "column": 40, - "line": 4, - "offset": 64, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "table", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 7, - "offset": 68, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; - -exports[`tableCellInlineCode unescapes escaped pipe chars inside inline code within table headers 1`] = ` -Object { - "children": Array [ - Object { - "type": "text", - "value": " - - - - - - -", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "type": "text", - "value": "one | two | three | four", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 2, - "offset": 32, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "properties": Object {}, - "tagName": "code", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 32, - "line": 2, - "offset": 32, - }, - "start": Object { - "column": 3, - "line": 2, - "offset": 3, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - Object { - "children": Array [ - Object { - "position": Object { - "end": Object { - "column": 38, - "line": 2, - "offset": 38, - }, - "start": Object { - "column": 35, - "line": 2, - "offset": 35, - }, - }, - "type": "text", - "value": "two", - }, - ], - "position": Object { - "end": Object { - "column": 38, - "line": 2, - "offset": 38, - }, - "start": Object { - "column": 35, - "line": 2, - "offset": 35, - }, - }, - "properties": Object { - "align": "left", - }, - "tagName": "th", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 40, - "line": 2, - "offset": 40, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "tr", - "type": "element", - }, - ], - "position": Object { - "end": Object { - "column": 40, - "line": 2, - "offset": 40, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "thead", - "type": "element", - "value": "one | two | three | four two", - }, - ], - "position": Object { - "end": Object { - "column": 12, - "line": 3, - "offset": 52, - }, - "start": Object { - "column": 1, - "line": 2, - "offset": 1, - }, - }, - "properties": Object {}, - "tagName": "table", - "type": "element", - }, - ], - "data": Object { - "quirksMode": false, - }, - "position": Object { - "end": Object { - "column": 2, - "line": 6, - "offset": 56, - }, - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; +exports[`tableCellInlineCode > unescapes escaped pipe chars inside inline code within table headers 1`] = `undefined`; diff --git a/__tests__/transformers/callouts.test.ts b/__tests__/transformers/callouts.test.ts new file mode 100644 index 000000000..431cb5cef --- /dev/null +++ b/__tests__/transformers/callouts.test.ts @@ -0,0 +1,39 @@ +import { mdast } from '../../index'; + +describe('callouts transformer', () => { + it('can parse callouts', () => { + const md = ` +> 🚧 It works! +> +> And, it no longer deletes your content! +`; + const tree = mdast(md); + + expect(tree.children[0].type).toBe('rdme-callout'); + expect(tree.children[0].children[0].type).toBe('paragraph'); + expect(tree.children[0].children[0].children[0].value).toBe('It works!'); + }); + + it('can parse callouts with markdown in the heading', () => { + const md = ` +> 🚧 It **works!** +> +> And, it no longer deletes your content! +`; + const tree = mdast(md); + + expect(tree.children[0].children[0].children[1].type).toBe('strong'); + }); + + it('can parse callouts with markdown in the heading immediately following the emoji', () => { + const md = ` +> 🚧 **It works!** +> +> And, it no longer deletes your content! +`; + const tree = mdast(md); + + expect(tree.children[0].data.hProperties.empty).toBe(false); + expect(tree.children[0].children[0].children[1].type).toBe('strong'); + }); +}); diff --git a/__tests__/transformers/code-tabs.test.ts b/__tests__/transformers/code-tabs.test.ts new file mode 100644 index 000000000..595cf2614 --- /dev/null +++ b/__tests__/transformers/code-tabs.test.ts @@ -0,0 +1,111 @@ +import { mdast, hast } from '../../index'; + +describe('Code Tabs Transformer', () => { + it('can parse code tabs', () => { + const md = ` +\`\`\` +First code block +\`\`\` +\`\`\` +Second code block +\`\`\` +`; + const tree = mdast(md); + + expect(tree.children[0].type).toBe('code-tabs'); + }); + + it('sets the correct data attributes', () => { + const md = ` +\`\`\` +First code block +\`\`\` +\`\`\` +Second code block +\`\`\` +`; + const tree = mdast(md); + + expect(tree.children[0].data).toMatchInlineSnapshot(` + { + "hName": "CodeTabs", + } + `); + }); + + it('can parse lang and meta', () => { + const md = ` +\`\`\`javascript First Title +First code block +\`\`\` +\`\`\`text +Second code block +\`\`\` +`; + const ast = mdast(md); + + expect(ast.children[0].children[0]).toStrictEqual( + expect.objectContaining({ lang: 'javascript', meta: 'First Title' }), + ); + expect(ast.children[0].children[1]).toStrictEqual(expect.objectContaining({ lang: 'text', meta: null })); + }); + + it('wraps single code blocks with tabs if they have a lang set', () => { + const md = ` +\`\`\`javascript +const languageSet = true; +\`\`\` +`; + + const tree = mdast(md); + expect(tree.children[0].type).toBe('code-tabs'); + }); + + it('wraps single code blocks with tabs if they have a title set', () => { + const md = ` +\`\`\`javascript Testing +const languageSet = true; +\`\`\` +`; + + const tree = mdast(md); + expect(tree.children[0].type).toBe('code-tabs'); + }); + + it('allows code tabs within html blocks', () => { + const md = ` +

+ +\`\`\` +First code block +\`\`\` +\`\`\` +Second code block +\`\`\` + +

+`; + const tree = hast(md); + + expect(tree.children[0].children[0].tagName).toBe('CodeTabs'); + }); + + it('allows code tabs within container blocks', () => { + const md = ` +- ~~~Name + {{company_name}} + ~~~ + ~~~Email + {{company_email}} + ~~~ + ~~~URL + {{company_url}} + ~~~ +`; + + const tree = mdast(md); + + expect(tree.children[0].children[0].children[0].type).toBe('code-tabs'); + expect(tree.children[0].children[0].children.length).toBe(1); + }); +}); diff --git a/__tests__/transformers/embeds.test.ts b/__tests__/transformers/embeds.test.ts new file mode 100644 index 000000000..79a6e9e45 --- /dev/null +++ b/__tests__/transformers/embeds.test.ts @@ -0,0 +1,15 @@ + +import { mdast } from '../../index'; + +describe('embeds transformer', () => { + it('converts a link with a title of "@embed" to an embed-block', () => { + const md = ` +[alt](https://example.com/cool.pdf "@embed") +`; + const tree = mdast(md); + + expect(tree.children[0].type).toBe('embed-block'); + expect(tree.children[0].data.hProperties.title).toBe('alt'); + }); + +}); diff --git a/__tests__/transformers/images.test.ts b/__tests__/transformers/images.test.ts new file mode 100644 index 000000000..7e8d06699 --- /dev/null +++ b/__tests__/transformers/images.test.ts @@ -0,0 +1,23 @@ +import { mdast } from '../../index'; + +describe('images transformer', () => { + it('converts single children images of paragraphs to an image-block', () => { + const md = ` +![alt](https://example.com/image.jpg) +`; + const tree = mdast(md); + + expect(tree.children[0].type).toBe('image-block'); + expect(tree.children[0].data.hProperties.src).toBe('https://example.com/image.jpg'); + }); + + it('can parse the caption markdown to children', () => { + const md = ` + +`; + const tree = mdast(md); + + expect(tree.children[0].children[0].children[0].type).toBe('strong'); + expect(tree.children[0].children[0].children[2].type).toBe('emphasis'); + }); +}); diff --git a/__tests__/transformers/readme-components.test.ts b/__tests__/transformers/readme-components.test.ts new file mode 100644 index 000000000..c34a0a015 --- /dev/null +++ b/__tests__/transformers/readme-components.test.ts @@ -0,0 +1,112 @@ +import { mdast } from '../../index'; + +describe('Readme Components Transformer', () => { + const nodes = [ + { md: '', type: 'rdme-callout' }, + { md: '', type: 'code' }, + { md: '', type: 'code-tabs' }, + { md: '', type: 'image-block' }, + { md: '', type: 'table' }, + { md: '', type: 'tutorial-tile' }, + ]; + + it.each(nodes)('transforms $md into a(n) $type node', ({ md, type }) => { + const tree = mdast(md); + + expect(tree.children[0].type).toBe(type); + }); + + const docs = { + ['rdme-callout']: { + md: `> πŸ“˜ It works!`, + mdx: ` + + It works! +`, + }, + code: { + md: ` +~~~ +This is a code block +~~~ + `, + mdx: ``, + }, + ['code-tabs']: { + md: ` +~~~ +First +~~~ +~~~ +Second +~~~ + `, + mdx: ` + + + + + `, + }, + image: { + md: `![](http://placekitten.com/600/200)`, + mdx: ``, + }, + table: { + md: ` +| h1 | h2 | +| --- | --- | +| a1 | a2 | + `, + // @todo there's text nodes that get inserted between the td's. Pretty sure + // they'd get filtered out by rehype, but lets keep the tests easy. + mdx: ` +
+ + + + + + +
h1h2
a1a2
+ `, + }, + }; + it.each(Object.entries(docs))('matches the equivalent markdown for %s', (type, { md, mdx }) => { + let mdTree = mdast(md); + const mdxTree = mdast(mdx); + + expect(mdxTree).toStrictEqualExceptPosition(mdTree); + }); + + it('does not convert components that have custom implementations', () => { + const mdx = ` + +`; + + const tree = mdast(mdx, { + components: { + Callout: () => null, + }, + }); + + expect(tree.children[0].type).toBe('mdxJsxFlowElement'); + expect(tree.children[0].name).toBe('Callout'); + }); + + it('converts Glossary components to markdown nodes', () => { + const mdx = ` +Demo +`; + + const tree = mdast(mdx); + expect(tree.children[0].children[0].type).toBe('readme-glossary-item'); + }); + + it('converts variable phrasing expressions to markdown nodes', () => { + const mdx = `{user.name}`; + + const tree = mdast(mdx); + expect(tree.children[0].type).toBe('readme-variable'); + }); +}); diff --git a/__tests__/transformers/readme-to-mdx.test.ts b/__tests__/transformers/readme-to-mdx.test.ts new file mode 100644 index 000000000..868f53bd0 --- /dev/null +++ b/__tests__/transformers/readme-to-mdx.test.ts @@ -0,0 +1,25 @@ +import { mdx } from '../../index'; + +describe('readme-to-mdx transformer', () => { + it('converts a tutorial tile to MDX', () => { + const ast = { + type: 'root', + children: [ + { + type: 'tutorial-tile', + backgroundColor: 'red', + emoji: 'πŸ¦‰', + id: 'test-id', + link: 'http://example.com', + slug: 'test-id', + title: 'Test', + }, + ], + }; + + expect(mdx(ast)).toMatchInlineSnapshot(` + " + " + `); + }); +}); diff --git a/__tests__/transformers/reusable-content.test.js b/__tests__/transformers/reusable-content.test.js index 461ee82bb..08eed22ef 100644 --- a/__tests__/transformers/reusable-content.test.js +++ b/__tests__/transformers/reusable-content.test.js @@ -1,6 +1,6 @@ import { mdast } from '../../index'; -describe('reusable content transfomer', () => { +describe.skip('reusable content transfomer', () => { it('should replace a reusable content block if the block is provided', () => { const tags = { Test: ` diff --git a/__tests__/transformers/single-code-tabs.test.js b/__tests__/transformers/single-code-tabs.test.js deleted file mode 100644 index 56b86c8c4..000000000 --- a/__tests__/transformers/single-code-tabs.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { mdast } from '../../index'; - -describe('Single Code Tab Transformer', () => { - it('wraps single code blocks with tabs if they have a lang set', () => { - const md = ` -\`\`\`javascript -const languageSet = true; -\`\`\` -`; - - const tree = mdast(md); - expect(tree).toMatchSnapshot(); - }); - - it('wraps single code blocks with tabs if they have a title set', () => { - const md = ` -\`\`\`javascript Testing -const languageSet = true; -\`\`\` -`; - - const tree = mdast(md); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/__tests__/transformers/table-cell-inline-code.test.js b/__tests__/transformers/table-cell-inline-code.test.js index a361051b5..65ebf9b5a 100644 --- a/__tests__/transformers/table-cell-inline-code.test.js +++ b/__tests__/transformers/table-cell-inline-code.test.js @@ -1,7 +1,7 @@ -import { hast, md, mdast } from '../../index'; +import { hast, mdx, mdast } from '../../index'; describe('tableCellInlineCode', () => { - it('unescapes escaped pipe chars inside inline code within table headers', () => { + it.skip('unescapes escaped pipe chars inside inline code within table headers', () => { const doc = ` | \`one \\| two \\| three \\| four\` | two | | :- | :- | @@ -11,7 +11,7 @@ describe('tableCellInlineCode', () => { expect(tree).toMatchSnapshot(); }); - it('unescapes escaped pipe chars inside inline code within table cells', () => { + it.skip('unescapes escaped pipe chars inside inline code within table cells', () => { const doc = ` | | | | :- | :- | @@ -22,7 +22,7 @@ describe('tableCellInlineCode', () => { expect(tree).toMatchSnapshot(); }); - it('preserves escaped pipe chars inside text table cells', () => { + it.skip('preserves escaped pipe chars inside text table cells', () => { const doc = ` | these \\| stay \\| escaped \\| inside \\| a single cell | | | :- | :- | @@ -32,7 +32,7 @@ describe('tableCellInlineCode', () => { expect(tree).toMatchSnapshot(); }); - it('splits table cells when inline code contains "unescaped" pipe chars', () => { + it.skip('splits table cells when inline code contains "unescaped" pipe chars', () => { const doc = ` | \`this | splits | up | to | more | cells\` | two | | :- | :- | @@ -42,16 +42,16 @@ describe('tableCellInlineCode', () => { expect(tree).toMatchSnapshot(); }); - it('preserves the escaped pipe character when re-serializing from mdast', () => { + it.skip('preserves the escaped pipe character when re-serializing from mdast', () => { const doc = ` | \`one \\| two \\| three \\| four\` | two | | :- | :- | `; const tree = mdast(doc); - expect(md(tree)).toMatchInlineSnapshot(` - "| \`one \\\\| two \\\\| three \\\\| four\` | two | - | :---------------------------- | :-- | + expect(mdx(tree)).toMatchInlineSnapshot(` + "| \`one \\| two \\| three \\| four\` | two | + | :- | :- | " `); }); diff --git a/__tests__/transformers/variables.test.tsx b/__tests__/transformers/variables.test.tsx new file mode 100644 index 000000000..8fbf2cfbe --- /dev/null +++ b/__tests__/transformers/variables.test.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import * as rmdx from '../../index'; +import { execute } from '../helpers'; +import { render, screen } from '@testing-library/react'; + +describe('variables transformer', () => { + it('renders user variables', async () => { + const mdx = '{user.name}'; + const variables = { + user: { + name: 'Test User', + }, + }; + const Content = await execute(mdx, { variables }); + + render(); + + expect(screen.findByText('Test User')).toBeDefined(); + }); + + it('renders user variables in a phrasing context', async () => { + const mdx = 'Hello, {user.name}!'; + const variables = { + user: { + name: 'Test User', + }, + }; + const Content = await execute(mdx, { variables }); + + render(); + + expect(screen.findByText('Test User')).toBeDefined(); + }); + + it('parses variables into the mdast', () => { + const mdx = `{user.name}`; + + // @ts-ignore + expect(rmdx.mdast(mdx)).toStrictEqualExceptPosition({ + children: [ + { + value: '{user.name}', + data: { + hName: 'Variable', + hProperties: { + name: 'name', + }, + }, + type: 'readme-variable', + }, + ], + type: 'root', + }); + }); +}); diff --git a/__tests__/variable-parser.test.js b/__tests__/variable-parser.test.js deleted file mode 100644 index dc84238fc..000000000 --- a/__tests__/variable-parser.test.js +++ /dev/null @@ -1,200 +0,0 @@ -const remarkParse = require('remark-parse'); -const unified = require('unified'); - -const parser = require('../processor/parse/variable-parser'); - -test('should output a variable node', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-variable', - text: 'apiKey', - data: { - hName: 'readme-variable', - hProperties: { - variable: 'apiKey', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should output a glossary node', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-glossary-item', - data: { - hName: 'readme-glossary-item', - hProperties: { - term: 'item', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should allow whitespace in glossary names', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-glossary-item', - data: { - hName: 'readme-glossary-item', - hProperties: { - term: 'item name', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should allow underscored glossary terms', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-glossary-item', - data: { - hName: 'readme-glossary-item', - hProperties: { - term: 'underscored_term', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should allow numeric characters in glossary terms', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-glossary-item', - data: { - hName: 'readme-glossary-item', - hProperties: { - term: 'P2P 123 Abc', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should allow non-english glossary terms', () => { - const markdown = 'This is a test <>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test ' }, - { - type: 'readme-glossary-item', - data: { - hName: 'readme-glossary-item', - hProperties: { - term: 'ラベル', - }, - }, - }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); - -test('should allow escape variables to remain', () => { - const markdown = 'This is a test escaped key \\<>.'; - const ast = { - type: 'root', - children: [ - { - type: 'paragraph', - children: [ - { type: 'text', value: 'This is a test escaped key ' }, - { type: 'text', value: '<>' }, - { type: 'text', value: '.' }, - ], - }, - ], - }; - - expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( - ast - ); -}); diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..cc90074c1 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,36 @@ +function isWebTarget(caller) { + return Boolean(caller && caller.target === 'web'); +} + +function isWebpack(caller) { + return Boolean(caller && caller.name === 'babel-loader'); +} + +module.exports = api => { + const web = api.caller(isWebTarget); + const webpack = api.caller(isWebpack); + + return { + presets: [ + [ + '@babel/preset-env', + { + useBuiltIns: web ? 'usage' : undefined, + corejs: web ? 3 : false, + targets: !web ? { node: 'current' } : undefined, + modules: webpack ? false : 'commonjs', + }, + ], + '@babel/preset-react', + '@babel/preset-typescript', + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-export-default-from', + '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-proposal-optional-chaining', + '@babel/plugin-proposal-private-methods', + ], + sourceType: 'unambiguous', + }; +}; diff --git a/components/Anchor.jsx b/components/Anchor.jsx index f0f134a41..5f95d49de 100644 --- a/components/Anchor.jsx +++ b/components/Anchor.jsx @@ -1,11 +1,11 @@ -const PropTypes = require('prop-types'); -const React = require('react'); +import { string, node } from 'prop-types'; +import React from 'react'; -const BaseUrlContext = require('../contexts/BaseUrl'); +import BaseUrlContext from '../contexts/BaseUrl'; // Nabbed from here: // https://github.com/readmeio/api-explorer/blob/0dedafcf71102feedaa4145040d3f57d79d95752/packages/api-explorer/src/lib/markdown/renderer.js#L52 -function getHref(href, baseUrl) { +export function getHref(href, baseUrl) { const [path, hash] = href.split('#'); const hashStr = hash ? `#${hash}` : ''; @@ -18,7 +18,7 @@ function getHref(href, baseUrl) { const ref = path.match(/^ref:([-_a-zA-Z0-9#]*)$/); if (ref) { - return `${base}/reference/${ref[1]}${hashStr}`; + return `${base}/reference-link/${ref[1]}${hashStr}`; } // we need to perform two matches for changelogs in case @@ -49,7 +49,9 @@ function docLink(href) { } function Anchor(props) { - const { baseUrl, children, href, target, title, ...attrs } = props; + const { children, href, target, title, ...attrs } = props; + const baseUrl = useContext(BaseUrlContext); + return ( // eslint-disable-next-line react/jsx-props-no-spreading @@ -59,12 +61,12 @@ function Anchor(props) { } Anchor.propTypes = { - baseUrl: PropTypes.string, - children: PropTypes.node.isRequired, - download: PropTypes.string, - href: PropTypes.string, - target: PropTypes.string, - title: PropTypes.string, + baseUrl: string, + children: node.isRequired, + download: string, + href: string, + target: string, + title: string, }; Anchor.defaultProps = { @@ -74,17 +76,4 @@ Anchor.defaultProps = { title: '', }; -const AnchorWithContext = props => ( - {baseUrl => } -); - -AnchorWithContext.sanitize = sanitizeSchema => { - // This is for our custom link formats - sanitizeSchema.protocols.href.push('doc', 'target', 'ref', 'blog', 'changelog', 'page'); - - return sanitizeSchema; -}; - -module.exports = AnchorWithContext; - -AnchorWithContext.getHref = getHref; +export default Anchor; diff --git a/components/Callout/index.jsx b/components/Callout/index.jsx deleted file mode 100644 index 3432b4ed8..000000000 --- a/components/Callout/index.jsx +++ /dev/null @@ -1,42 +0,0 @@ -const PropTypes = require('prop-types'); -const React = require('react'); - -const Callout = props => { - const { attributes, theme, icon } = props; - const [title, ...content] = !props.title ? [null, props.children] : props.children; - - return ( - // eslint-disable-next-line react/jsx-props-no-spreading, react/no-unknown-property -
-

- {icon} - {title} -

- {content} -
- ); -}; - -Callout.propTypes = { - attributes: PropTypes.shape({}), - calloutStyle: PropTypes.string, - children: PropTypes.arrayOf(PropTypes.any).isRequired, - icon: PropTypes.string, - node: PropTypes.shape(), - theme: PropTypes.string, - title: PropTypes.string, -}; - -Callout.defaultProps = { - attributes: null, - calloutStyle: 'info', - node: null, -}; - -Callout.sanitize = sanitizeSchema => { - sanitizeSchema.attributes['rdme-callout'] = ['icon', 'theme', 'title']; - - return sanitizeSchema; -}; - -module.exports = Callout; diff --git a/components/Callout/index.tsx b/components/Callout/index.tsx new file mode 100644 index 000000000..b10d784c9 --- /dev/null +++ b/components/Callout/index.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; + +interface Props extends React.PropsWithChildren> { + attributes?: {}; + icon: string; + theme?: string; + empty?: boolean; +} + +const themes: Record = { + '\uD83D\uDCD8': 'info', + '\uD83D\uDEA7': 'warn', + '\u26A0\uFE0F': 'warn', + '\uD83D\uDC4D': 'okay', + '\u2705': 'okay', + '\u2757\uFE0F': 'error', + '\u2757': 'error', + '\uD83D\uDED1': 'error', + '\u2049\uFE0F': 'error', + '\u203C\uFE0F': 'error', + '\u2139\uFE0F': 'info', + '\u26A0': 'warn', +}; + +const Callout = (props: Props) => { + const { attributes, children, icon, empty } = props; + let theme = props.theme || themes[icon] || 'default'; + + return ( + // @ts-ignore +
+

+ {icon} + {empty || React.Children.toArray(children)[0]} +

+ {React.Children.toArray(children).slice(1)} +
+ ); +}; + +export default Callout; diff --git a/components/Callout/style.scss b/components/Callout/style.scss index c4c78c6a6..947c2e4b0 100644 --- a/components/Callout/style.scss +++ b/components/Callout/style.scss @@ -1,19 +1,16 @@ -/* stylelint-disable no-descending-specificity */ -/* stylelint-disable font-family-no-missing-generic-family-keyword */ -/* stylelint-disable order/properties-alphabetical-order */ -/* stylelint-disable order/order */ @mixin callout($l-offset: 1.33rem) { --background: #{lighten(#dfe2e5, 8.75%)}; --border: #{lighten(#6a737d, 12.5%)}; - background: var(--background); - border-color: var(--border); - color: var(--text); - padding: $l-offset; + & { + background: var(--background); + border-color: var(--border); + color: var(--text); + padding: $l-offset; + } &_info { $color: #46b8da; - --background: #e3edf2; --title: #{$color}; --border: #{lighten($color, 5%)}; // should be #5bc0de @@ -22,7 +19,6 @@ &_warn, &_warning { $color: #eea236; - --background: #fcf8f2; --title: #{$color}; --border: #{lighten($color, 5%)}; @@ -32,7 +28,6 @@ &_okay, &_success { $color: #489e49; - --background: #f3f8f3; --title: #{$color}; --border: #{lighten($color, 5%)}; // should be #50af51 @@ -41,7 +36,6 @@ &_err, &_error { $color: #d43f3a; - --background: #fdf7f7; --title: #{$color}; --border: #{lighten($color, 5%)}; // should be #d9534f @@ -51,7 +45,6 @@ margin-left: $l-offset; position: relative; } - ul, ol { padding-left: 1.3em; @@ -60,11 +53,9 @@ a { color: inherit; } - hr { border-color: var(--border, var(--markdown-edge, #eee)); } - blockquote { color: var(--text); border-color: var(--border); @@ -74,10 +65,6 @@ .callout-heading { color: var(--title, --text); - font-size: 1.25em; // match h3 - font-family: var(--markdown-title-font); // match h3 - font-weight: var(--markdown-title-weight, 600); // match h3 - line-height: 1.25; // match h3 margin-bottom: calc(#{$l-offset} * 0.5); &:only-child { @@ -87,18 +74,15 @@ &.empty { float: left; margin-top: calc(#{$l-offset} * 0.5); - .callout-icon { line-height: 0; } } - > * { color: inherit; margin: 0; } - - &::before { + &:before { position: absolute; right: 100%; width: 2.4em; @@ -106,23 +90,20 @@ font: normal normal normal 1em/1 FontAwesome; } } - .callout-icon { float: left; margin-left: calc(-#{$l-offset} - 0.5em); margin-right: -0.25rem; } } -@mixin callout-custom-icons($R: callout) { +@mixin calloutCustomIcons($R: callout) { --emoji: 1em; - --icon-font: fontawesome; - + --icon-font: FontAwesome; &-icon { font-size: var(--emoji, 0); color: var(--icon-color, inherit) !important; } - - &-icon::before { + &-icon:before { content: var(--icon); font-family: var(--icon-font); font-size: var(--icon-size, 1rem); @@ -137,27 +118,22 @@ } @at-root .rdmdCallouts--useIconFont & { --emoji: unset; - &_okay { /* thumbs up */ --icon: '\f164'; } - &_info { /* info circle */ --icon: '\f05a'; } - &_warn { /* warning triangle */ --icon: '\f071'; } - &_error { /* warning circle */ --icon: '\f06a'; } - &_default { /* warning circle */ --emoji: 1rem; @@ -170,8 +146,7 @@ // bump specificity @include callout; } - @include callout-custom-icons; - + @include calloutCustomIcons; border-top-right-radius: var(--markdown-radius); border-bottom-right-radius: var(--markdown-radius); } diff --git a/components/CardsGrid/index.tsx b/components/CardsGrid/index.tsx new file mode 100644 index 000000000..cfc18e8cc --- /dev/null +++ b/components/CardsGrid/index.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import './style.scss'; + +const Card = ({ children }) =>
{children}
; + +const CardsGrid = ({ columns = 2, children }) => { + columns = columns >= 2 ? columns : 2; + return ( +
+ {React.Children.map(children, e => ( + {e} + ))} +
+ ); +}; + +export default CardsGrid; diff --git a/components/CardsGrid/style.scss b/components/CardsGrid/style.scss new file mode 100644 index 000000000..7e87f9343 --- /dev/null +++ b/components/CardsGrid/style.scss @@ -0,0 +1,12 @@ +.CardsGrid { + display: grid; + gap: 20px; + + .Card { + padding: 10px; + backdrop-filter: blur(20px); + border: 1px solid rgba(black, 0.1); + border-radius: 5px; + box-shadow: 0 1px 2px #{rgba(black, 0.05)}, 0 2px 5px #{rgba(black, 0.02)}; + } +} diff --git a/components/Code/index.jsx b/components/Code/index.jsx deleted file mode 100644 index 982a20f3e..000000000 --- a/components/Code/index.jsx +++ /dev/null @@ -1,103 +0,0 @@ -const copy = require('copy-to-clipboard'); -const PropTypes = require('prop-types'); -const React = require('react'); - -// Only load CodeMirror in the browser, for SSR -// apps. Necessary because of people like this: -// https://github.com/codemirror/CodeMirror/issues/3701#issuecomment-164904534 -let syntaxHighlighter; -let canonicalLanguage = () => {}; -if (typeof window !== 'undefined') { - // eslint-disable-next-line global-require - syntaxHighlighter = require('@readme/syntax-highlighter').default; - // eslint-disable-next-line global-require - ({ canonical: canonicalLanguage } = require('@readme/syntax-highlighter')); -} - -function CopyCode({ codeRef, rootClass = 'rdmd-code-copy', className = '' }) { - const copyClass = `${rootClass}_copied`; - const button = React.createRef(); - /* istanbul ignore next */ - const copier = () => { - const code = codeRef.current.textContent; - - if (copy(code)) { - const $el = button.current; - $el.classList.add(copyClass); - setTimeout(() => $el.classList.remove(copyClass), 1500); - } - }; - return - ); - })} -
-
- {children} -
- - ); -}; - -CodeTabs.propTypes = { - children: PropTypes.arrayOf(PropTypes.any).isRequired, - theme: PropTypes.string, -}; - -function CreateCodeTabs({ theme }) { - // eslint-disable-next-line react/display-name - return props => ; -} - -module.exports = CreateCodeTabs; -module.exports.CodeTabs = CodeTabs; diff --git a/components/CodeTabs/index.tsx b/components/CodeTabs/index.tsx new file mode 100644 index 000000000..c5769aeb6 --- /dev/null +++ b/components/CodeTabs/index.tsx @@ -0,0 +1,38 @@ +import { uppercase } from '@readme/syntax-highlighter'; +import React from 'react'; + +const CodeTabs = props => { + const { children, theme } = props; + + function handleClick({ target }, index: number) { + const $wrap = target.parentElement.parentElement; + const $open = [].slice.call($wrap.querySelectorAll('.CodeTabs_active')); + $open.forEach((el: Element) => el.classList.remove('CodeTabs_active')); + $wrap.classList.remove('CodeTabs_initial'); + + const codeblocks = $wrap.querySelectorAll('pre'); + codeblocks[index].classList.add('CodeTabs_active'); + + target.classList.add('CodeTabs_active'); + } + + return ( +
+
+ {(Array.isArray(children) ? children : [children]).map((pre, i) => { + const { meta, lang } = pre.props.children.props; + + /* istanbul ignore next */ + return ( + + ); + })} +
+
{children}
+
+ ); +}; + +export default CodeTabs; diff --git a/components/CodeTabs/style.scss b/components/CodeTabs/style.scss index 6cf2c3ef1..894c220be 100644 --- a/components/CodeTabs/style.scss +++ b/components/CodeTabs/style.scss @@ -1,24 +1,21 @@ -/* stylelint-disable no-descending-specificity */ -/* stylelint-disable declaration-property-value-disallowed-list */ @import '~codemirror/lib/codemirror.css'; @import '~codemirror/theme/neo.css'; -@mixin code-tabs { - $bgc-pre: #f6f8fa; - $bgc-pre-dark: #242e34; +@mixin CodeTabs { + $bgc-pre: #F6F8FA; + $bgc-pre-dark: #242E34; $bgc-bar: darken(desaturate($bgc-pre, 17.46), 4.31); $bgc-bar-dark: lighten(desaturate($bgc-pre-dark, 17.46), 4.31); $radius: var(--md-code-radius, var(--markdown-radius, 3px)); - border-radius: $radius !important; color: #333; color: var(--md-code-text, #333); + border-radius: $radius !important; overflow: hidden; &.theme-dark { color: white; color: var(--md-code-text, white); - .CodeTabs-toolbar { background: $bgc-bar-dark; background: var(--md-code-tabs, $bgc-bar-dark); @@ -31,28 +28,27 @@ display: flex; flex-flow: row nowrap; overflow: hidden; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: none; overflow-x: auto; - + -ms-overflow-style: none; + -webkit-overflow-scrolling: touch; &::-webkit-scrollbar { display: none; } - button { + white-space: nowrap; + transition: .123s ease; + -webkit-appearance: none; appearance: none; - background: transparent; - border: none; - color: inherit; - cursor: pointer; display: inline-block; - font: inherit; - font-size: 0.75em; line-height: 2; + padding: .5em 1em; + border: none; + background: transparent; outline: none; - padding: 0.5em 1em; - transition: 0.123s ease; - white-space: nowrap; + color: inherit; + font: inherit; + font-size: .75em; + cursor: pointer; } } @@ -73,20 +69,16 @@ color: var(--md-code-text, white); } - &-toolbar button:not(.CodeTabs_active):hover, - &-toolbar button:not(.CodeTabs_active):active, - &-toolbar button:not(.CodeTabs_active):focus { - background: rgba(0, 0, 0, 0.075); + &-toolbar button:not(.CodeTabs_active):hover { + background: rgba(0, 0, 0, .075); } pre { - background: var(--md-code-background, $bgc-pre); border-radius: 0 0 $radius $radius !important; + background: $bgc-pre; + background: var(--md-code-background, $bgc-pre); margin-bottom: 0; - - &:not(.CodeTabs_active) { - display: none; - } + &:not(.CodeTabs_active) { display: none } } &.theme-dark pre { @@ -100,5 +92,5 @@ } .CodeTabs { - @include code-tabs; + @include CodeTabs; } diff --git a/components/Embed/index.jsx b/components/Embed/index.jsx deleted file mode 100644 index d7138c78f..000000000 --- a/components/Embed/index.jsx +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable react/jsx-props-no-spreading, jsx-a11y/iframe-has-title */ -const propTypes = require('prop-types'); -const React = require('react'); - -const Favicon = ({ src, alt = 'favicon', ...attr }) => {alt}; -Favicon.propTypes = { - alt: propTypes.string, - src: propTypes.string, -}; - -class Embed extends React.Component { - render() { - const { lazy = true, provider, url, title, html, iframe, image, favicon, ...attrs } = this.props; - - if (!url) { - return
; - } - - if ('iframe' in this.props) { - return ", - "url": "https://www.youtube.com/watch?v=J3-uKv1DShQ&feature=youtu.be", - "title": "Funny Solidier Drop Kick", - "favicon": "https://s.ytimg.com/yts/img/favicon-vfl8qSV2F.ico", - "image": "https://i.ytimg.com/vi/J3-uKv1DShQ/hqdefault.jpg" -} -[/block] - -
Magic Block (iFrame)
-[block:embed] -{ - "html": "", - "url": "https://www.google.com/maps/place/Mama's+Royal+Cafe/@37.829698,-122.258166,16z/data=!4m13!1m7!3m6!1s0x80857dfb145a04ff:0x96b17d967421636f!2s4126+Opal+St,+Oakland,+CA+94609!3b1!8m2!3d37.8296978!4d-122.2581661!3m4!1s0x0:0x722326b6c2ac7642!8m2!3d37.8277961!4d-122.2563006?hl=en", - "title": "Mama's Royal Cafe", - "favicon": "https://www.google.com/images/branding/product/ico/maps15_bnuw3a_32dp.ico", - "image": "http://maps-api-ssl.google.com/maps/api/staticmap?center=37.829698,-122.258166&zoom=15&size=250x250&sensor=false" -} -[/block] -
-
Markdown Block
+## Syntax +Simple embedded content is written as a Markdown link, with a title of "@embed", like so: + +``` [Embed Title](https://youtu.be/8bh238ekw3 "@embed") +``` +More robust embedded content is written as a JSX component: + +``` + +``` + +## Examples + + + + + -
+### Embed Component (Embedly) -## Known Issues -At the moment, embed links written in the new ReadMe-flavored markdown syntax will simply display the link. (Magic block embeds will continue to work, though!) We're aware of the shortcoming, and plan to refactor this component as we move forward. + -[block:html] -{ - "html": "" -} -[/block] + +### Embed Component (iFrame) + + + + +### Markdown Block + +[Embed Title](https://youtu.be/8bh238ekw3 "@embed") diff --git a/docs/headings.md b/docs/headings.md index 9397186e5..5d1952919 100644 --- a/docs/headings.md +++ b/docs/headings.md @@ -1,17 +1,18 @@ --- -title: "Headings" +title: 'Headings' category: 5fdf7610134322007389a6ed hidden: false --- + ## Examples > ### Heading Block 3 > -> #### Heading Block 4 -> -> ##### Heading Block 5 -> -> ###### Heading Block 6 +> #### Heading Block 4 +> +> ##### Heading Block 5 +> +> ###### Heading Block 6 ## Edge Cases @@ -20,33 +21,40 @@ hidden: false ####Compact Notation Headers are denoted using a space-separated `#` prefix. While the space is technically required in most standard Markdown implementations, some processors allow for a compact notation as well. ReadMe supports this style, so writing this - - ###A Valid Heading - - Lorem ipsum dolor etc. -> πŸ›‘ +``` +###A Valid Heading + +Lorem ipsum dolor etc. +``` + +> πŸ›‘ > Compact headings must be followed by two line breaks before the following block. #### ATX-Style Notation #### If you prefer, you can "wrap" headers with hashes rather than simply prefixing them: - ## ATX Headings are Valid ## +``` +## ATX Headings are Valid ## +``` #### Underline Notation For top-level headings, the underline notation is valid: - Heading One - =========== - - Heading Two - --- +``` +Heading One +=========== + +Heading Two +--- +``` ### Incremented Anchors Occasionally, a single doc might contain multiple headings with the same text, which can cause the generated anchor links to conflict. ReadMe's new markdown processor normalizes heading anchors by auto-incrementing similar heading's IDs. Try it out by clicking on this section header _or_ the following sub-section title: #### Incremented Heading Anchors + #### Incremented Heading Anchors diff --git a/docs/html-tests.md b/docs/html-tests.md new file mode 100644 index 000000000..24e262a20 --- /dev/null +++ b/docs/html-tests.md @@ -0,0 +1,67 @@ +--- +title: 'HTML Blocks' +--- + +## JSX (with no HTML attributes) + + + +

Header 0

+

Paragraph with italics and bold stuff.

+
I am actually a div!
+
+ + +## JSX + + + +

Header 1

+

Paragraph with italics and bold stuff.

+
+ Behold, I am blue and indented! +
+
+ + +## HTML as a prop + + + + +## HTML in template literal + +{` + +

Header 3

+

Paragraph with italics and bold stuff.

+
+ Behold, I am blue and indented! +
+`}
+ + +## JSX in safe mode + + + +

Header 4

+

Paragraph with italics and bold stuff.

+
+ Behold, I am blue and indented! +
+
+ + +## HTML in safe mode + +{` + +

Header 5

+

Paragraph with italics and bold stuff.

+
+ Behold, I am blue and indented! +
+`}
\ No newline at end of file diff --git a/docs/images.md b/docs/images.md index bf8939c12..20bc90db0 100644 --- a/docs/images.md +++ b/docs/images.md @@ -4,28 +4,13 @@ category: 5fdf7610134322007389a6ed hidden: false --- ## Syntax +``` +![Alt text](https://cdn.path.to/some/image.jpg "This is some image...") +``` - ![Alt text](https://cdn.path.to/some/image.jpg "This is some image...") -[block:api-header] -{ - "title": "Examples" -} -[/block] +## Examples -[block:image] -{ - "images": [ - { - "image": [ - "https://files.readme.io/b8674d6-pizzabro.jpg", - "pizzabro.jpg", - 1024, - 682, - "#d1c8c5" - ], - "caption": "Click to zoom." - } - ] -} -[/block] - +![Bro eats pizza and makes an OK gesture.](https://files.readme.io/6f52e22-man-eating-pizza-and-making-an-ok-gesture.jpg "Pizza Face") + + + diff --git a/docs/lists.md b/docs/lists.md index 02694163b..7f1dc4519 100644 --- a/docs/lists.md +++ b/docs/lists.md @@ -88,7 +88,6 @@ Starting an ordered list with any number will increment continuously from that p 98. Starting in media res 98. Another list item 98. Yet another item - [block:html] { "html": "" diff --git a/docs/mdx-components.mdx b/docs/mdx-components.mdx new file mode 100644 index 000000000..c0deb49b9 --- /dev/null +++ b/docs/mdx-components.mdx @@ -0,0 +1,57 @@ +## Tables + +You can use our `Table` component to match the ReadMe theming. + +```jsx MDX +export const table = [ + ['Left', 'Center', 'Right'], + ['L0', '**bold**', '$1600'], + ['L1', '`code`', '$12'], + ['L2', '_italic_', '$1'], +]; + + + + + {table[0].map((cell, index) => ( + + ))} + + + + {table.slice(1).map(row => ( + + {table[0].map((cell, index) => ( + + ))} + + ))} + +
{cell}
{cell}
; +``` + +export const table = [ + ['Left', 'Center', 'Right'], + ['L0', '**bold**', '$1600'], + ['L1', '`code`', '$12'], + ['L2', '_italic_', '$1'], +]; + + + + + {table[0].map((cell, index) => ( + + ))} + + + + {table.slice(1).map(row => ( + + {row.map((cell, index) => ( + + ))} + + ))} + +
{cell}
{cell}
diff --git a/docs/table-of-contents-tests.md b/docs/table-of-contents-tests.md index 78614e517..2dad09c20 100644 --- a/docs/table-of-contents-tests.md +++ b/docs/table-of-contents-tests.md @@ -1,8 +1,13 @@ --- -title: "Table Of Contents Tests" +title: 'Table Of Contents Tests' category: 5fdf9fc9c2a7ef443e937315 hidden: true --- -# Variables (<>) -# Glossary Items (<>) +# Variables + +# Glossary Items demo + +## Custom Components + + diff --git a/docs/tables-tests.md b/docs/tables-tests.md deleted file mode 100644 index 664b470f6..000000000 --- a/docs/tables-tests.md +++ /dev/null @@ -1,18 +0,0 @@ -## Sparse Tables - -[block:parameters] -{ - "data": { - "h-1": "h-1", - "h-2": "h-2", - "0-0": "0-0", - "1-0": "1-0", - "0-1": "0-1", - "0-2": "0-2", - "1-2": "1-2", - "1-1": "1-1" - }, - "cols": 3, - "rows": 4 -} -[/block] diff --git a/docs/tables.md b/docs/tables.md index b34d7d73b..cda1aeb87 100644 --- a/docs/tables.md +++ b/docs/tables.md @@ -1,26 +1,25 @@ --- -title: "Tables" +title: 'Tables' category: 5fdf7610134322007389a6ed hidden: false --- -## Syntax - | Left | Center | Right | - |:-----|:--------:|------:| - | L0 | **bold** | $1600 | - | L1 | `code` | $12 | - | L2 | _italic_ | $1 | +## Syntax -> ❗️ Table cells may contain inline decorations only. -> -> Lists, headings, and other block-level Markdown components are not valid and will cause errors. +```markdown +| Left | Center | Right | +|:-----|:--------:|------:| +| L0 | **bold** | $1600 | +| L1 | `code` | $12 | +| L2 | _italic_ | $1 | +``` ### Examples This example also shows off custom theming! | Left | Center | Right | -|:-----|:--------:|------:| +| :--- | :------: | ----: | | L0 | **bold** | $1600 | | L1 | `code` | $12 | | L2 | _italic_ | $1 | @@ -35,7 +34,7 @@ Tables have been simplified to mirror a more standard implementation. We've also --table-head: #5b1c9f; --table-head-text: white; --table-stripe: #f0eaf7; - --table-edges: rgba(34, 5, 64, .5); + --table-edges: rgba(34, 5, 64, 0.5); --table-row: white; } ``` @@ -47,8 +46,10 @@ Tables have been simplified to mirror a more standard implementation. We've also /* Rows */ .markdown-body .rdmd-table tr {} -.markdown-body .rdmd-table thead tr {} /* header row's background */ -.markdown-body .rdmd-table tr:nth-child(2n) {} /* striped rows' background */ +.markdown-body .rdmd-table thead tr {} +/* header row's background */ +.markdown-body .rdmd-table tr:nth-child(2n) {} +/* striped rows' background */ /* Cells */ @@ -56,21 +57,25 @@ Tables have been simplified to mirror a more standard implementation. We've also .markdown-body .rdmd-table td {} ``` - diff --git a/docs/variable-tests.md b/docs/variable-tests.md index 01bcb8c5a..f2abebb8b 100644 --- a/docs/variable-tests.md +++ b/docs/variable-tests.md @@ -4,23 +4,22 @@ category: 5fdf9fc9c2a7ef443e937315 hidden: true --- -<> and `<>` and: +This is the variable `defvar`: {user.defvar} + +Ok, but this one is defined: {user.email} + +It **does** render in code blocks: ``` -<> +{user.defvar} ``` -and +And if you don't want that, you can escape it: -```js -const xyz = '<>'; ``` - +\{user.defvar} ``` -should \<< be escaped >> -should << -not be a var >> +## Glossary Items -also not a <> -``` +demo diff --git a/enums.ts b/enums.ts new file mode 100644 index 000000000..f090c690f --- /dev/null +++ b/enums.ts @@ -0,0 +1,13 @@ +export enum NodeTypes { + callout = 'rdme-callout', + codeTabs = 'code-tabs', + embedBlock = 'embed-block', + emoji = 'gemoji', + glossary = 'readme-glossary-item', + htmlBlock = 'html-block', + i = 'i', + imageBlock = 'image-block', + reusableContent = 'reusable-content', + tutorialTile = 'tutorial-tile', + variable = 'readme-variable', +} diff --git a/errors/mdx-syntax-error.ts b/errors/mdx-syntax-error.ts new file mode 100644 index 000000000..7bb315fe4 --- /dev/null +++ b/errors/mdx-syntax-error.ts @@ -0,0 +1,26 @@ +import { VFileMessage } from 'vfile-message'; + +export default class MdxSyntaxError extends SyntaxError { + original: VFileMessage = null; + + constructor(error: VFileMessage, doc: string) { + const { message, line, column, url } = error; + + const messages = [ + `Oh no! We ran into a syntax error at { line: ${line}, column: ${column} }, please see this url for more details: ${url}`, + ]; + + if (typeof line !== 'undefined') { + messages.push(doc.split('\n')[line - 1]); + + if (typeof column !== 'undefined') { + const prefix = new Array(column).map(() => '').join(' '); + messages.push(`${prefix}↑ ${message}`); + } + } + + super(messages.join('\n')); + + this.original = error; + } +} diff --git a/example/App.tsx b/example/App.tsx new file mode 100644 index 000000000..f00701a76 --- /dev/null +++ b/example/App.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { HashRouter, Navigate, Route, Routes } from 'react-router-dom'; + +import './demo.scss'; + +import Root from './Root'; +import docs from './docs'; + +const App = () => { + return ( + + + } path="/:fixture" /> + } /> + + + ); +}; + +export default App; diff --git a/example/Demo.jsx b/example/Demo.jsx deleted file mode 100644 index f2d88c141..000000000 --- a/example/Demo.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; - -import markdown, { reactProcessor, reactTOC, utils } from '../index'; - -import Fixtures from './Fixtures'; -import Header from './Header'; -import Router from './Router'; - -require('./demo.scss'); - -const { GlossaryContext } = utils; - -const terms = [ - { - term: 'demo', - definition: 'a thing that breaks on presentation', - }, - { - term: 'exogenous', - definition: 'relating to or developing from external factors', - }, - { - term: 'endogenous', - definition: 'having an internal cause or origin', - }, -]; - -const Maybe = ({ when, children }) => when && children; - -function DemoContent({ ci, children, fixture, name, onChange, opts }) { - return ( - - -
-
- {children} -