[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2.1\n\norbs:\n  frontend-tools: contentful/frontend-tools@2\n  vault: contentful/vault@1.30.0\n  nx: nrwl/nx@1.6.2\n\nexecutors:\n  default:\n    docker:\n      - image: cimg/node:24.13.1\n\ncache-key: &cache-key\n  key: v2-npm-cache-{{ arch }}-{{ checksum \".nvmrc\" }}-{{ checksum \"pnpm-lock.yaml\" }}-{{ .Branch }}\n\ncommands:\n  setup_pnpm:\n    steps:\n      - run:\n          name: Install pnpm package manager\n          command: |\n            sudo corepack enable\n            corepack prepare pnpm --activate\n            pnpm config set store-dir .pnpm-store\n\n  pnpm_install:\n    steps:\n      - restore_cache: *cache-key\n      - run: node -v\n      - run: pnpm -v\n      - run: pnpm install --frozen-lockfile --prefer-offline\n      - save_cache:\n          <<: *cache-key\n          paths:\n            - .pnpm-store\n\n  nx_set_shas:\n    steps:\n      - vault/get-secrets:\n          template-preset: nx-read-circleci\n      - nx/set-shas:\n          error-on-no-successful-workflow: true\n          main-branch-name: master\n\njobs:\n  lint-and-test:\n    executor: default\n    steps:\n      - checkout\n      - vault/get-secrets:\n          template-preset: packages-read\n      - setup_pnpm\n      - pnpm_install\n      - nx_set_shas\n      - run: pnpm exec nx affected --target=build --base=$NX_BASE --head=$NX_HEAD\n      - run: pnpm exec nx affected --target=lint --base=$NX_BASE --head=$NX_HEAD\n      - run: pnpm exec nx affected --target=prettier:check --base=$NX_BASE --head=$NX_HEAD\n      - run: pnpm exec nx affected --target=test --base=$NX_BASE --head=$NX_HEAD\n      - store_test_results:\n          path: reports\n      - persist_to_workspace:\n          root: ~/project\n          paths:\n            - .\n    resource_class: medium+\n\n\n  release:\n    executor: default\n    steps:\n      - checkout\n      - vault/get-secrets:\n          template-preset: semantic-release\n      - attach_workspace:\n          at: ~/project\n      - vault/configure-lerna\n      - run: |\n          echo \"@contentful:registry=https://npm.pkg.github.com\" >> ~/.npmrc\n          echo \"//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_WRITE_TOKEN}\" >> ~/.npmrc\n      - run: pnpm nx run-many -t build\n      - run: pnpm lerna version --no-private --conventional-commits --create-release github --yes\n      - run: pnpm lerna publish from-git --yes\n\n  compressed-size:\n    executor: default\n    steps:\n      - checkout\n      - vault/get-secrets:\n          template-preset: packages-read\n      - vault/get-secrets:\n          template-preset: github-comment\n      - run: |\n          echo \"@contentful:registry=https://npm.pkg.github.com\" >> ~/.npmrc\n          echo \"//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_READ_TOKEN}\" >> ~/.npmrc\n      - frontend-tools/compressed-size:\n          package-manager: pnpm\n\nworkflows:\n  version: 2\n  # run on every commit\n  commit:\n    jobs:\n      - lint-and-test:\n          context:\n            - vault\n      - release:\n          context:\n            - vault\n          filters:\n            branches:\n              only: master\n          requires:\n            - lint-and-test\n  compressed-size:\n    jobs:\n      - compressed-size:\n          context:\n            - vault\n"
  },
  {
    "path": ".contentful/compressed-size.yml",
    "content": "version: 1\n\ncompressed-size:\n  compression: 'gzip'\n  pattern: './packages/*/{dist,build}/**/*.{js,css}'\n  strip-hash: \"\\\\b\\\\w{8}\\\\.\"\n  collapse-unchanged: true\n  minimum-change-threshold: 1024\n"
  },
  {
    "path": ".contentful/vault-secrets.yaml",
    "content": "version: 1\nservices:\n  github-action:\n    policies:\n      - dependabot\n  circleci:\n    policies:\n      - github-comment\n      - semantic-release\n      - packages-read\n      - nx-read-circleci\n"
  },
  {
    "path": ".editorconfig",
    "content": "#root = true\n\n[*]\nindent_style = space\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nmax_line_length = 100\nindent_size = 2\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintignore",
    "content": "node_modules/\n.coverage/\n.cache/\ndist/\n.eslintrc.js\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  env: {\n    browser: true,\n    es2021: true,\n  },\n  extends: [\n    'eslint:recommended',\n    'plugin:react/recommended',\n    'plugin:react-hooks/recommended',\n    'plugin:@typescript-eslint/recommended',\n  ],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaFeatures: {\n      jsx: true,\n    },\n    ecmaVersion: 'latest',\n    sourceType: 'module',\n  },\n  plugins: ['react', 'react-hooks', '@typescript-eslint', 'eslint-plugin-import-helpers'],\n  rules: {\n    'react-hooks/exhaustive-deps': 'error',\n    '@typescript-eslint/no-explicit-any': 'warn',\n    '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],\n    'import-helpers/order-imports': [\n      'warn',\n      {\n        newlinesBetween: 'always',\n        groups: ['/^react/', 'module', ['parent', 'sibling', 'index']],\n        alphabetize: { order: 'asc', ignoreCase: true },\n      },\n    ],\n    'no-restricted-imports': ['warn'],\n    'react/react-in-jsx-scope': 'off',\n  },\n  settings: {\n    react: { version: 'detect' },\n  },\n};\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\n\nregistries:\n  npm-registry-registry-npmjs-org:\n    type: npm-registry\n    url: https://registry.npmjs.org\n    token: '${{secrets.NPM_REGISTRY_REGISTRY_NPMJS_ORG_TOKEN}}'\n  npm-github:\n    type: npm-registry\n    url: https://npm.pkg.github.com\n    token: ${{secrets.NPM_REGISTRY_REGISTRY_GH_ORG_TOKEN}}\n\nupdates:\n  - package-ecosystem: npm\n    directory: '/'\n    schedule:\n      interval: weekly\n      time: '00:00'\n      timezone: Etc/UCT\n    open-pull-requests-limit: 10\n    target-branch: master\n    labels:\n      - dependencies\n      - dependabot\n    commit-message:\n      prefix: chore\n    registries:\n      - npm-registry-registry-npmjs-org\n      - npm-github\n    reviewers:\n      - 'contentful/team-tolkien'\n\n    cooldown:\n      default-days: 15"
  },
  {
    "path": ".github/semantic.yml",
    "content": "titleAndCommits: true\nanyCommit: true\nallowMergeCommits: false\ntypes:\n  - feat\n  - fix\n  - improvement\n  - docs\n  - style\n  - refactor\n  - perf\n  - test\n  - build\n  - ci\n  - chore\n  - revert\n"
  },
  {
    "path": ".github/workflows/auto-approve.yml",
    "content": "name: 'dependabot approve-and-request-merge'\non: pull_request_target\n\njobs:\n  worker:\n    permissions:\n      contents: write\n      id-token: write\n      pull-requests: write\n    runs-on: ubuntu-latest\n    if: github.actor == 'dependabot[bot]'\n    steps:\n      - uses: contentful/github-auto-merge@v2\n        with:\n          VAULT_URL: ${{ secrets.VAULT_URL }}\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "---\nname: \"CodeQL Scan for GitHub Actions Workflow\"\n\non:\n  push:\n    branches: [master]\n    paths: [\".github/workflows/**\"]\n  pull_request:\n    branches: [master]\n    paths: [\".github/workflows/**\"]\n\njobs:\n  analyze:\n    name: Analyze GitHub Actions workflows\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: actions\n\n      - name: Run CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n        with:\n          category: actions\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\n**/logs\n**/*.log\n**/npm-debug.log*\n**/yarn-debug.log*\n**/yarn-error.log*\n\n# Coverage\n**/coverage\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\n**/build/Release\n\n# Dependency directories\n**/node_modules/\n**/jspm_packages/\n\n# TypeScript v1 declaration files\n**/typings/\n\n# Optional npm cache directory\n**/.npm\n\n# Optional eslint cache\n**/.eslintcache\n\n# Optional REPL history\n**/.node_repl_history\n\n# Output of 'npm pack'\n**/*.tgz\n\n# dotenv environment variables file\n**/.env\n\n**/dist\n\n**/.rpt2_cache\n.vscode/settings.json\n.idea\n\n# test reports\nreports\n\n# nx specific\n.nx/\n\n# swc\n**/.swc\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "npx lint-staged\n"
  },
  {
    "path": ".npmrc",
    "content": "registry=https://registry.npmjs.org\nignore-scripts=true\nshamefully-hoist=true\n"
  },
  {
    "path": ".nvmrc",
    "content": "v24\n"
  },
  {
    "path": ".prettierignore",
    "content": "**/node_modules\n**/dist\n**/coverage\n"
  },
  {
    "path": ".swcrc",
    "content": "{\n  \"$schema\": \"https://swc.rs/schema.json\",\n  \"jsc\": {\n    \"parser\": {\n      \"syntax\": \"typescript\",\n      \"tsx\": true\n    },\n    \"target\": \"es5\",\n    \"loose\": false,\n    \"minify\": {\n      \"compress\": false,\n      \"mangle\": false\n    }\n  },\n  \"module\": {\n    \"type\": \"commonjs\"\n  },\n  \"minify\": false\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n### Bug Fixes\n\n- don't run npm install on prePublish ([#417](https://github.com/contentful/rich-text/issues/417)) ([0af2378](https://github.com/contentful/rich-text/commit/0af237897ce093e294833e7e17c3b69e4634e09a))\n\n### Features\n\n- adding v1 marks to rich text types [TOL-786] ([#416](https://github.com/contentful/rich-text/issues/416)) ([8885de8](https://github.com/contentful/rich-text/commit/8885de8ebba7736de46b0b8892a8aa15bb8d7ba4))\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add --no-package-lock ([#364](https://github.com/contentful/rich-text/issues/364)) ([41643c9](https://github.com/contentful/rich-text/commit/41643c9f61f525536941b54b64e944b70cb4a241))\n- add inline sources to packages ([#357](https://github.com/contentful/rich-text/issues/357)) ([bca6abb](https://github.com/contentful/rich-text/commit/bca6abb4328414b5a7a87b9b57481e161d800dcf))\n- add missing -- to circleci release commands ([#360](https://github.com/contentful/rich-text/issues/360)) ([233be08](https://github.com/contentful/rich-text/commit/233be0826cc7c76b799e70262b3281f7dbe4cd92))\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- circleci update resource class ([#359](https://github.com/contentful/rich-text/issues/359)) ([6bb3710](https://github.com/contentful/rich-text/commit/6bb3710623907a2601c218f3cea3a817790cbf59))\n- revert change to monorepo tsconfig, apply to tsconfig in rich-text-types ([#358](https://github.com/contentful/rich-text/issues/358)) ([56126cc](https://github.com/contentful/rich-text/commit/56126cc9ed3704f21b89d2dbded160be0265f153))\n- update Lerna, rollup in slatejs-adapter ([#366](https://github.com/contentful/rich-text/issues/366)) ([32448e3](https://github.com/contentful/rich-text/commit/32448e369ae2b76601dd81839e13c15432430d68))\n\n## [15.13.1](https://github.com/contentful/rich-text/compare/v15.13.0...v15.13.1) (2022-05-10)\n\n### Bug Fixes\n\n- **markdown:** handle empty table cells ([#329](https://github.com/contentful/rich-text/issues/329)) ([55a0a16](https://github.com/contentful/rich-text/commit/55a0a16a12700fefbe7e9727a7172043fd126fc5))\n\n# [15.13.0](https://github.com/contentful/rich-text/compare/v15.12.1...v15.13.0) (2022-05-06)\n\n### Features\n\n- support converting tables from markdown to rich-text ([0abc0c6](https://github.com/contentful/rich-text/commit/0abc0c60b7e3e2683ebbb427b44847e6242f6e5e))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n### Bug Fixes\n\n- upgrade react peerDependencies to support react^18.0.0 ([#323](https://github.com/contentful/rich-text/issues/323)) ([7a0bfdf](https://github.com/contentful/rich-text/commit/7a0bfdfb687cca608239e072cbc301ba1b1310d1))\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n### Features\n\n- enforce minItems in table-related node types ([#314](https://github.com/contentful/rich-text/issues/314)) ([1125331](https://github.com/contentful/rich-text/commit/112533100f66ae01cd9944069dc62fc95f1737a5))\n\n## [15.11.2](https://github.com/contentful/rich-text/compare/v15.11.1...v15.11.2) (2022-02-07)\n\n### Bug Fixes\n\n- set \"typings\" for rich-text-from-markdown ([1b3a15f](https://github.com/contentful/rich-text/commit/1b3a15f1cb15eacb6d1b15f2b79c5747e2d25618))\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n### Bug Fixes\n\n- **rich-text-types:** remove RT validation helpers ([#302](https://github.com/contentful/rich-text/issues/302)) ([fcd3a27](https://github.com/contentful/rich-text/commit/fcd3a277952f53eb3ae6ebb559ae6a02f5553c87)), closes [#295](https://github.com/contentful/rich-text/issues/295) [#274](https://github.com/contentful/rich-text/issues/274)\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n### Bug Fixes\n\n- **react-renderer:** wrap table rows in tbody ([#300](https://github.com/contentful/rich-text/issues/300)) ([e23d1f4](https://github.com/contentful/rich-text/commit/e23d1f4f5c63ce7ded84144b271f566327a144d1))\n\n### Features\n\n- **rich-text-types:** expose HEADINGS array ([#301](https://github.com/contentful/rich-text/issues/301)) ([758539d](https://github.com/contentful/rich-text/commit/758539d46f3db13c21ca2f6d74a389a6fef21803))\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n### Bug Fixes\n\n- remove support to convert tables from md to rich text ([a9d513c](https://github.com/contentful/rich-text/commit/a9d513c285e8cdedd384b89e195734dd3a8d2136))\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n### Features\n\n- **rich-text-types:** expose RT validation helper ([#292](https://github.com/contentful/rich-text/issues/292)) ([fc5a7cc](https://github.com/contentful/rich-text/commit/fc5a7cc27244f293a9a50acd785f7edcdaaa96ea))\n\n# [15.8.0](https://github.com/contentful/rich-text/compare/v15.7.0...v15.8.0) (2021-11-11)\n\n### Features\n\n- add toContentfulDocument() and toSlatejsDocument() empty block node handling ([#287](https://github.com/contentful/rich-text/issues/287)) ([fa79626](https://github.com/contentful/rich-text/commit/fa79626e4020d9640a920ca5d0ccb654e89cfa90))\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n### Features\n\n- **rich-text-types:** Add TEXT_CONTAINERS ([#286](https://github.com/contentful/rich-text/issues/286)) ([3356ea8](https://github.com/contentful/rich-text/commit/3356ea815a46901a6637f177b04bcf1926adc88d))\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n### Features\n\n- add support to convert tables from md to rich text ([#284](https://github.com/contentful/rich-text/issues/284)) ([213a29c](https://github.com/contentful/rich-text/commit/213a29c78d48b3e63088999c4eed4891906d1719))\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n### Bug Fixes\n\n- npm 15.5.0 ([#280](https://github.com/contentful/rich-text/issues/280)) ([e7aeba4](https://github.com/contentful/rich-text/commit/e7aeba49a3074fc9eae6aee569db4e30d1acb8b8))\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n# [15.4.0](https://github.com/contentful/rich-text/compare/v15.3.6...v15.4.0) (2021-09-16)\n\n### Features\n\n- **html+react:** render Table header as <th> ([#269](https://github.com/contentful/rich-text/issues/269)) ([0f82905](https://github.com/contentful/rich-text/commit/0f829059be6d91e042dfc71698009177ae4ab78d))\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n### Bug Fixes\n\n- allow table-row type to have both cells ([#267](https://github.com/contentful/rich-text/issues/267)) ([ec40598](https://github.com/contentful/rich-text/commit/ec405982109cb1c16e7adf71a541a98270d7f45b))\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n### Bug Fixes\n\n- **rich-text-types:** forbid Tables inside ListItem ([#266](https://github.com/contentful/rich-text/issues/266)) ([fc338bf](https://github.com/contentful/rich-text/commit/fc338bf040b8718057717d2681f800d5e26ba59d))\n\n## [15.3.4](https://github.com/contentful/rich-text/compare/v15.3.3...v15.3.4) (2021-09-09)\n\n### Bug Fixes\n\n- replace import to fix typings for html-renderer ([#265](https://github.com/contentful/rich-text/issues/265)) ([40c2670](https://github.com/contentful/rich-text/commit/40c267069b18454517b0f4283a7e155cffa410b6))\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text\n\n# Change Log\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n### Bug Fixes\n\n- allow the first item in Table to be a TableHeaderRow ([9a6de55](https://github.com/contentful/rich-text/commit/9a6de55ed97ca413d3922958850b8215922c06b5))\n- don't export the helper TableHeaderRow type ([179c3cb](https://github.com/contentful/rich-text/commit/179c3cb10c0f65725297445afe955f0cca135005))\n- typo ([2282665](https://github.com/contentful/rich-text/commit/2282665924404771b3353dd9b380d8863f1d4c41))\n\n### Features\n\n- add TableHeaderCell type ([5e25ac9](https://github.com/contentful/rich-text/commit/5e25ac9f35be2ad6c7ad7857cbde808cbc3437f9))\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.1.0...v15.2.0) (2021-08-16)\n\n### Bug Fixes\n\n- 🐛 html encode default inlined CF entry/asset links ([41396eb](https://github.com/contentful/rich-text/commit/41396eb800f6d5c65c634c4394a6c60cf3425255))\n- 🐛 prevent html injection via `data.uri` link rendering ([ecae89a](https://github.com/contentful/rich-text/commit/ecae89ad0d25175f342833ca989928670c24b8fd))\n- audit fix aiming mixing-deep vulnerability ([2b98cbd](https://github.com/contentful/rich-text/commit/2b98cbd8e85435305378dd91d70d55db5e9c0832))\n- audit fix root folder ([ffe9e44](https://github.com/contentful/rich-text/commit/ffe9e44c98611b0705f697c693e9b6b9d6c757cf))\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n### Features\n\n- 🎸 add RT html renderer tables support ([ce81375](https://github.com/contentful/rich-text/commit/ce8137577b269c62727dc64b7d47b4951597dbd6))\n- 🎸 add RT react renderer tables support ([fddfb8a](https://github.com/contentful/rich-text/commit/fddfb8a943b9807efe92b749d7ffdeb1308e42bd))\n- add rowspan ([e0264fb](https://github.com/contentful/rich-text/commit/e0264fbe4d9467eedf78b7c5c3a9825a584124cf))\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n### Bug Fixes\n\n- **slatejs-adapter:** release as public package ([#227](https://github.com/contentful/rich-text/issues/227)) ([0ba8197](https://github.com/contentful/rich-text/commit/0ba81974a732bc6a32109b84e688e0903cc3632c))\n\n### Features\n\n- add table markup support ([c6ae127](https://github.com/contentful/rich-text/commit/c6ae127aa460f4cd26cd6b671cd43fd2714bc650))\n\n# [14.2.0](https://github.com/contentful/rich-text/compare/v14.1.3...v14.2.0) (2021-05-04)\n\n### Features\n\n- {wip} update slate.js adapter ([c281aea](https://github.com/contentful/rich-text/commit/c281aea098e949c45ed08dd6b46babfc0a75bfb9))\n- fix test types ([0c86f93](https://github.com/contentful/rich-text/commit/0c86f9362f551cf8a2fcbeacfd995052a93a936a))\n- update contentful-to-slatejs adapter ([33a3b6d](https://github.com/contentful/rich-text/commit/33a3b6d69c118e53b7b8464e1c41d9da26edf8d9))\n- update contentful-to-slatejs-adapter ([89a32f4](https://github.com/contentful/rich-text/commit/89a32f494e434fa63b70146da29a81e24fae3cea))\n\n## [14.1.3](https://github.com/contentful/rich-text/compare/v14.1.2...v14.1.3) (2021-04-12)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n### Bug Fixes\n\n- 🐛 configure rollup copy correctly ([3446a33](https://github.com/contentful/rich-text/commit/3446a33fc5711087095a58b088828dfe6066bc7f))\n- 🐛 skip lib check for TS ([e8bf2ba](https://github.com/contentful/rich-text/commit/e8bf2ba61be9f36f104d0e0337829ac07b30eec6))\n- Add leaf object ([#5](https://github.com/contentful/rich-text/issues/5)) ([fb0b80d](https://github.com/contentful/rich-text/commit/fb0b80d7be60eb40a8dcfb51d65db2e488ea0097))\n- Add lodash.omit to externals ([#7](https://github.com/contentful/rich-text/issues/7)) ([1c65200](https://github.com/contentful/rich-text/commit/1c652002831161fa34b59b18177565db057e3bc5))\n- Remove doc deployment and fix ([90bccaa](https://github.com/contentful/rich-text/commit/90bccaaa9125cfe50627b27fff7a1b88a9044d3e))\n\n### Features\n\n- Add a default value for Marks ([6828215](https://github.com/contentful/rich-text/commit/68282155ee41f64e7f762b6823fd6d9b982ea160))\n- Add data transform ([#6](https://github.com/contentful/rich-text/issues/6)) ([9d90fa1](https://github.com/contentful/rich-text/commit/9d90fa1995939a58739dbfaa0033b92b259d0687))\n- Cleans up the `mark` property from extra props ([20ec641](https://github.com/contentful/rich-text/commit/20ec641130a17169587dae21e6fb231c180496d1))\n- **contentful-to-slate:** Implement new isVoid in Slate's Node ([3d2d38d](https://github.com/contentful/rich-text/commit/3d2d38d22e43c4500252cba7af21d29a89c6fbda))\n- data defaults to an empty object ([0a9b8a0](https://github.com/contentful/rich-text/commit/0a9b8a01049a6c48f38b09ea7075c17620db18dc))\n- first version ([11591d0](https://github.com/contentful/rich-text/commit/11591d0d32fa81028ab71946c7fd68f783b56022))\n- integrate structured-text-types ([#8](https://github.com/contentful/rich-text/issues/8)) ([d6d5e37](https://github.com/contentful/rich-text/commit/d6d5e376a7562821264ad7e3cc70b7d3cdff6ba5))\n- remove content from void nodes ([0ce9898](https://github.com/contentful/rich-text/commit/0ce989824ae3adb8452ae20db821500f63d95d68))\n- Remove nodeClass from Contentful's Document ([23bb2d5](https://github.com/contentful/rich-text/commit/23bb2d533301bf46b4f7eb0407b61972d3b38fff))\n- update dependencies ([e294233](https://github.com/contentful/rich-text/commit/e29423329e5aa3c518fd6ca6a0cdda0c7cda440c))\n- Update structured-text-type version ([#9](https://github.com/contentful/rich-text/issues/9)) ([ced65da](https://github.com/contentful/rich-text/commit/ced65dab9db1391f5b969d742594e2b9670ebb22))\n\n### Performance Improvements\n\n- ⚡️ Remove lodash.omit dependency ([93b6b76](https://github.com/contentful/rich-text/commit/93b6b765488a6d3e003a832c953ae10c3f68672e))\n\n### BREAKING CHANGES\n\n- Remove nodeClass from Contentful's Document\n- Changed the interface of Slate->Contentful adapter. Added new parameter Schema\n- **contentful-to-slate:** toSlatejsDocument now accepts Schema\n- Only supports structured-text-types >= 2.0.0\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n### Features\n\n- 🎸 emptyDoc representing an empty RT document ([80315ef](https://github.com/contentful/rich-text/commit/80315ef5130b79336336ba31de8a55e42bafe319))\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n### Bug Fixes\n\n- 🐛 detect links as children of nodes also having links ([565f423](https://github.com/contentful/rich-text/commit/565f423b2881c7bcfac40e9ee9ecb6a545fce047))\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n### Features\n\n- 🎸 Adds BLOCKS.DOCUMENT renderer support to react-renderer ([57c922c](https://github.com/contentful/rich-text/commit/57c922cb638c47729f2189815a647ba68859394e)), closes [#104](https://github.com/contentful/rich-text/issues/104)\n\n# [13.3.0](https://github.com/contentful/rich-text/compare/v13.2.0...v13.3.0) (2019-03-21)\n\n# [13.2.0](https://github.com/contentful/rich-text/compare/v13.1.0...v13.2.0) (2019-03-18)\n\n### Features\n\n- 🎸 renderText option to alter all text ([f684a6e](https://github.com/contentful/rich-text/commit/f684a6e91d81ab0c66c286adaa923bd2edf0f4f1))\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n### Bug Fixes\n\n- 🐛 Fix incorrect typings file path ([cca74d5](https://github.com/contentful/rich-text/commit/cca74d5594fb0594fd1117945e087afa2000877b))\n\n### Features\n\n- 🎸 Support filtering by node name in rich-text-links ([5ec0dda](https://github.com/contentful/rich-text/commit/5ec0dda07cdbe3d28027d28520c553b074ca699f))\n\n## [13.0.1](https://github.com/contentful/rich-text/compare/v13.0.0...v13.0.1) (2019-02-11)\n\n### Bug Fixes\n\n- 🐛 Fix wrong import in tests ([bead583](https://github.com/contentful/rich-text/commit/bead583e6e9bb71638694e466980b90e599fa47b))\n- 🐛 make \"time to read\" great again ([6edd37d](https://github.com/contentful/rich-text/commit/6edd37d47fadcc0145188fa1fdfae811cb4145dd))\n\n### Features\n\n- 🎸 Initial rich-text-react-renderer implementation ([06dad9b](https://github.com/contentful/rich-text/commit/06dad9b0359325d8fa433438dac997fc9656d13f))\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n### Bug Fixes\n\n- 🐛 use named export instead of default ([57bf365](https://github.com/contentful/rich-text/commit/57bf36510f1021f5208a3e33242cceea97940d68))\n\n### BREAKING CHANGES\n\n- removes default export from 'rich-text-plain-text-renderer'\n\n## [12.2.1](https://github.com/contentful/rich-text/compare/v12.2.0...v12.2.1) (2019-01-22)\n\n### Bug Fixes\n\n- gracefully handle empty rich text documents ([14870de](https://github.com/contentful/rich-text/commit/14870ded471f69cee84a60739bee06873ed53af9))\n\n### Features\n\n- 🎸 add time to read for reach text ([5f2115a](https://github.com/contentful/rich-text/commit/5f2115afd1ef41e0e5eb419368510d682524706e))\n\n# [12.2.0](https://github.com/contentful/rich-text/compare/v12.1.2...v12.2.0) (2018-12-20)\n\n### Bug Fixes\n\n- fix import path ([3f3edff](https://github.com/contentful/rich-text/commit/3f3edff8bc4f4463a701d0ae1d397fcf9acec325))\n- ignore unsupported marks ([1757331](https://github.com/contentful/rich-text/commit/1757331a74f360353556a242a9fe20da131b9a59))\n\n### Features\n\n- 🎸 parse links inside marks ([11722cf](https://github.com/contentful/rich-text/commit/11722cfad85d5e15b10d2b18d3c831ec613922c3))\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n### Bug Fixes\n\n- fix npm ignore ([5c9e58e](https://github.com/contentful/rich-text/commit/5c9e58ed7fabecf430c91a6776665d8ad73f4bf3))\n\n### Features\n\n- add html escaping ([4b55331](https://github.com/contentful/rich-text/commit/4b55331e86bc62787420f8081228293f1a22e1b7))\n\n## [12.1.1](https://github.com/contentful/rich-text/compare/v12.1.0...v12.1.1) (2018-12-12)\n\n### Bug Fixes\n\n- handle hyperlinks ([54508d4](https://github.com/contentful/rich-text/commit/54508d495adf5055e4089f54dd62f00f8be6be46))\n\n# [12.1.0](https://github.com/contentful/rich-text/compare/v12.0.4...v12.1.0) (2018-12-12)\n\n### Bug Fixes\n\n- **async-handling:** move to promise-based api ([a07d3fc](https://github.com/contentful/rich-text/commit/a07d3fcbd99a2d80f86bc6dcf5cba01665221ebc))\n\n## [12.0.4](https://github.com/contentful/rich-text/compare/v12.0.3...v12.0.4) (2018-12-05)\n\n### Bug Fixes\n\n- Add index.js ([383cc98](https://github.com/contentful/rich-text/commit/383cc98e5dbcf8f144c8504759c6090daff611db))\n- **package:** add babel/runtime to deps; remove 'main' from package.json ([f7adbff](https://github.com/contentful/rich-text/commit/f7adbfffe704335601751e0f43f073ba867bc534))\n- **package:** use caret operator for gatsby peer dep ([21478ef](https://github.com/contentful/rich-text/commit/21478ef77f96546dab561f603940d4de5553340e))\n\n## [12.0.3](https://github.com/contentful/rich-text/compare/v12.0.2...v12.0.3) (2018-12-05)\n\n### Bug Fixes\n\n- **build:** rm gatsby from dev-deps on gatsby plugin ([2b3f87b](https://github.com/contentful/rich-text/commit/2b3f87b0bae48b32456a10f3a9c48c9c921df401))\n- **deps:** dep to old version within monorepo ([b0da60a](https://github.com/contentful/rich-text/commit/b0da60af975cb45d94063bd78bd2b2882ad0da80))\n- **readme:** mark types in readme examples ([d997b56](https://github.com/contentful/rich-text/commit/d997b56f2b8c32b2e5b478ab5444757203e2c703))\n- Remove debugger ([c7c9c4f](https://github.com/contentful/rich-text/commit/c7c9c4f1a41d98825cdc782d3b529da03d237d3a))\n\n### Features\n\n- **transformer:** Add gatsby-transformer-contentful-richtext ([8ed2adb](https://github.com/contentful/rich-text/commit/8ed2adbe9b53cbe9992e4483a67b05e7950a743c))\n\n### Performance Improvements\n\n- ⚡️ prefer iterator unrolling to Array.from ([a887a92](https://github.com/contentful/rich-text/commit/a887a9213dee9dd6986cf313e67b94fd020d138b))\n\n## [12.0.2](https://github.com/contentful/rich-text/compare/v12.0.1...v12.0.2) (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 update path to typings ([ce5544f](https://github.com/contentful/rich-text/commit/ce5544f58712dc6a18aadda523d0c0357a66c8a5))\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 add Object.values and Array.prototype.includes polyfills ([9e2ffb4](https://github.com/contentful/rich-text/commit/9e2ffb46e3564a523c74504270b29ccc8b8249ad))\n- **from-markdown:** Fix list typos ([c392016](https://github.com/contentful/rich-text/commit/c392016e2f11628021cd27bff3447f548398c3b4))\n- **parsing:** list item, (un)ordered list, links, quotes ([8a0c580](https://github.com/contentful/rich-text/commit/8a0c580306c154f1c1d6c2ba964c46d18881be12))\n- **text:** Parse text nodes with marks correctly ([d489f90](https://github.com/contentful/rich-text/commit/d489f904a33726f42006b09871d15bcfbdd7e274))\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n### Features\n\n- 🎸 `getRichTextEntityLinks` perf and signature changes ([fcd6d7f](https://github.com/contentful/rich-text/commit/fcd6d7f42e63df87ddb58d651b86a023d45f990e))\n\n### Performance Improvements\n\n- ⚡️ Add benchmark support ([ae278b7](https://github.com/contentful/rich-text/commit/ae278b7be515a52576af0a1abb6a4cefb05f71a7))\n\n### BREAKING CHANGES\n\n- Produces an entirely new return value and obviates the `linkType`\n  parameter (all entities are grouped and returned by default).\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n### Bug Fixes\n\n- 🐛 Removes cz-lerna-changelog from devDependencies ([31daac0](https://github.com/contentful/rich-text/commit/31daac0d10a66186e01a085bd466fdc18a20ab5f))\n- 🐛 Removes obsolete field `title` from Hyperlinks ([8cb9027](https://github.com/contentful/rich-text/commit/8cb90279f5348a7fb59f211c2ba209a28fd432be))\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n### Features\n\n- 🎸 return all entity links when no linkType is provided ([02970ea](https://github.com/contentful/rich-text/commit/02970ea61b5b13d99c7b629902defe704c146b17))\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n- 🎸 Rename, refactor, docu. & cache r-t-links ([9cf6d14](https://github.com/contentful/rich-text/commit/9cf6d1460833300053cb8dde5a6e29b0ddf89964))\n\n# [10.1.0](https://github.com/contentful/rich-text/compare/v10.0.5...v10.1.0) (2018-11-16)\n\n### Bug Fixes\n\n- 🐛 removes obsolete fields from mark nodes ([b638a56](https://github.com/contentful/rich-text/commit/b638a56652520969d3ac898ac158be81a9788f67))\n\n### Features\n\n- 🎸 adds json schema generation to rich text types ([8916140](https://github.com/contentful/rich-text/commit/89161404eb911f126be23ba2a146ebf748f7489e))\n- 🎸 introduces top-level-block type ([a6bf35e](https://github.com/contentful/rich-text/commit/a6bf35e7c9ca35915a512de774b3a3fdc4c76e5d))\n\n## [10.0.5](https://github.com/contentful/rich-text/compare/v10.0.4...v10.0.5) (2018-11-12)\n\n### Bug Fixes\n\n- 🐛 handle case of missing rootNode / rootNode.content ([e2434c7](https://github.com/contentful/rich-text/commit/e2434c7f5e1401f1188dd778c2aa9a108cea5596))\n\n## [10.0.4](https://github.com/contentful/rich-text/compare/v10.0.3...v10.0.4) (2018-11-09)\n\n## [10.0.3](https://github.com/contentful/rich-text/compare/v10.0.2...v10.0.3) (2018-11-09)\n\n## [10.0.2](https://github.com/contentful/rich-text/compare/v10.0.1...v10.0.2) (2018-11-09)\n\n## [10.0.1](https://github.com/contentful/rich-text/compare/v10.0.0...v10.0.1) (2018-11-08)\n\n### Features\n\n- **packages:** Add rich text from markdown package ([bc8ec41](https://github.com/contentful/rich-text/commit/bc8ec41f5615eabcc29031ee99da3f9c70b414b3))\n\n# [10.0.0](https://github.com/contentful/rich-text/compare/v9.0.2...v10.0.0) (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## [9.0.2](https://github.com/contentful/rich-text/compare/v9.0.1...v9.0.2) (2018-10-31)\n\n## [9.0.1](https://github.com/contentful/rich-text/compare/v9.0.0...v9.0.1) (2018-10-31)\n\n# [9.0.0](https://github.com/contentful/rich-text/compare/v8.0.3...v9.0.0) (2018-10-30)\n\n### Bug Fixes\n\n- 🐛 Fix block divisor provision ([3aafb7a](https://github.com/contentful/rich-text/commit/3aafb7a756d8b6f96ef733eb299091404b3391aa))\n- 🐛 remove exclusive mocha test ([5ff5d0e](https://github.com/contentful/rich-text/commit/5ff5d0e35024b7dccda065f54ae34138d9416525))\n\n### Features\n\n- 🎸 Explicitly declare nodeClass and nodeType in core types ([0749c61](https://github.com/contentful/rich-text/commit/0749c6199bb2681509608539c76bd8149cade564))\n\n### BREAKING CHANGES\n\n- Fundamentally alters the plain text renderer behavior. (For the better!)\n- Potentially breaks TypeScript libraries pulling this in as a dependency\n  if they are not explicitly stating nodeClass and nodeType.\n\n## [8.0.3](https://github.com/contentful/rich-text/compare/v8.0.2...v8.0.3) (2018-10-30)\n\n## [8.0.2](https://github.com/contentful/rich-text/compare/v8.0.1...v8.0.2) (2018-10-29)\n\n## [8.0.1](https://github.com/contentful/rich-text/compare/v8.0.0...v8.0.1) (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 Revert mock hypenation commits ([bde9432](https://github.com/contentful/rich-text/commit/bde94323fcc02bf5ab3feeef46a9d8fc8b08d59b))\n- sync HTML renderer ([769bd95](https://github.com/contentful/rich-text/commit/769bd95add1aecad0e11fab377f99c5cdad99072))\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n## [7.0.1](https://github.com/contentful/rich-text/compare/v7.0.0...v7.0.1) (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 hypenate more hyperlink tokens ([f88b377](https://github.com/contentful/rich-text/commit/f88b3775c1849fd0ca26b103999d819fd1b9b801))\n\n# [7.0.0](https://github.com/contentful/rich-text/compare/v6.0.0...v7.0.0) (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 blockquote -> block-quote ([5b66181](https://github.com/contentful/rich-text/commit/5b66181943d835baffd7574edef5dd34ac301923))\n- 🐛 hyphenate hyper-link ([662f60d](https://github.com/contentful/rich-text/commit/662f60dd966202a03dab9c49719bf34166fbdaed))\n- 🐛 Remove .releaserc.js ([f1f72a7](https://github.com/contentful/rich-text/commit/f1f72a7435bcc60cdd1a63979cade47cd91c05fb))\n\n### chore\n\n- 🤖 :%s/ci/travis ([4731881](https://github.com/contentful/rich-text/commit/47318816edb1d9cac3f778931bb921c522e7be3a))\n- 🤖 swap for semantic-release-monorepo ([cb8ca3e](https://github.com/contentful/rich-text/commit/cb8ca3ef5a4f3df9c041967352a611f4216c9d81))\n\n### BREAKING CHANGES\n\n- major version bump\n- None, but let's pretend like there are some anyway to trigger a major\n  version bump\n\n# 6.0.0 (2018-10-24)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to `rich-text`\n\n<p align=\"center\">\n  <a href=\"http://makeapullrequest.com\">\n    <img src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg?maxAge=31557600\" alt=\"PRs Welcome\">\n  </a>\n  &nbsp;\n  <a href=\"http://makeapullrequest.com\">\n    <img src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?maxAge=31557600\" alt=\"Semantic Release\">\n  </a>\n  &nbsp;\n  <a href=\"http://standardjs.com/\">\n    <img src=\"https://img.shields.io/badge/code%20style-standard-brightgreen.svg?maxAge=31557600\" alt=\"JS Standard Style\">\n  </a>\n</p>\n\nWe appreciate any community contributions to this project, whether in the form\nof issues or pull requests.\n\nThis document outlines what we'd like you to follow in terms of commit messages\nand code style.\n\nIt also explains what to do if you want to set up the project locally and run\ntests.\n\n**Working on your first Pull Request?**\nYou can learn how from this _free_ series: [How to Contribute to an Open Source\nProject on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)\n\n## Useful npm scripts\n\n- `yarn build` builds vendored files in the `dist` directory of each package\n- `yarn commit` runs git commits with [commitizen](http://commitizen.github.io/cz-cli/)\n- `yarn clean` removes any built files and `node_modules`\n- `yarn lint` runs our TypeScript linter on all `.ts` files in each package\n- `yarn test` runs unit tests for all packages\n- `yarn test:watch` runs unit tests in \"watch\" mode (will refresh relevant\n  code paths on save)\n\n## Setup\n\nThis project is a [Lerna](https://lernajs.io/) monorepo with several packages,\neach published separately to npm.\n\n### Local Development\n\nRun `npm install` to install all necessary dependencies.\n\nAs a post-install step, all Lerna dependencies are [hoisted](https://github.com/lerna/lerna/blob/master/doc/hoist.md),\nand hence internally reliant packages (e.g., `rich-text-html-renderer`, which\ndepends upon `rich-text-types`) will resolve their modules via symlink. In other\nwords, `npm install` will _both_ install external dependencies for each project,\n_and_ ensure packages that pull in other packages in this repository as\ndependencies are linked to the local version (rather than whatever the state\nof those packages is on npm).\n\nEach package is written in [TypeScript](https://www.typescriptlang.org/) and\ncompiled to ES5 using [rollup](https://rollupjs.org/guide/en) to the `dist`\ndirectory.\n\nThis should generally only happen at publishing time, but you may want to run\n`yarn build` prematurely during local development.\n\nFor example, let's say you're working on a pull request that\n\n1. adds support for a type in `rich-text-types`, and\n2. adds behavior to handle that type in `rich-text-html-renderer`.\n\nIf changes in the latter are dependent upon changes in the former, you'll need\nto run `yarn build` to update the referenced vendored files in\n`rich-text-html-renderer`.\n\nAll necessary dependencies are installed under `node_modules` and any necessary\ntools can be accessed via npm scripts. There is no need to install anything\nglobally.\n\n### Creating commits\n\nWe follow [Angular JS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153#allowed-type)\nto generate a changelog.\n\n### Code style\n\nThis project uses [JavaScript Standard Style](https://standardjs.com/) and\n[Prettier](https://prettier.io/) conventions. Install a relevant editor plugin\nif you'd like. When in doubt, follow a style similar to the existing code :)\n\nWe use a common [rollup](https://rollupjs.org/guide/en) config to compile\npackages from TypeScript to ES5. We also use common [TypeScript](https://www.typescriptlang.org/)\nand [eslint](https://eslint.org/docs/v8.x/) configs. You'll notice\nthe `rollup.config.js` and `tsconfig.json` in each package largely reference\nthose files on a root level - this keeps code conventions consistent across the\nrepository as a whole.\n\n### Running tests\n\nWe use [Jest](https://jestjs.io/) for unit tests. See **Useful npm scripts**\nabove for some relevant npm commands.\n\n## Publishing\n\nWe use [Lerna](https://github.com/lerna/lerna) to:\n\n- keep dependencies in sync\n  - `lerna bootstrap --hoist` (which is run as a post-install step)\n- publish\n  - `NPM_CONFIG_OTP={2fa_otp_goes_here} yarn publish`\n  - As a community developer, you most likely won't have to worry about this\n    step :)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Contentful\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# rich-text\n\nMonorepo with Typescript libraries for handling and rendering Contentful Rich\nText documents.\n\n## Packages\n\n### Official\n\n- [`rich-text-from-markdown`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-from-markdown)\n  - Converts markdown documents to rich text\n- [`rich-text-html-renderer`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer)\n  - Converts rich text documents to HTML\n- [`rich-text-links`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-links)\n  - Entity (entry and asset) link extraction utilities\n- [`rich-text-plain-text-renderer`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-plain-text-renderer)\n  - Converts rich text documents to plain text\n- [`rich-text-types`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-types)\n  - Type definitions and constants for the rich text field type\n- [`gatsby-transformer-contentful-richtext`](https://github.com/contentful/rich-text/tree/4ef875c44b4c8617f4035a46569b240d8cc67bbe/deprecated/gatsby-transformer-contentful-richtext) [DEPRECATED]\n  - Parses a Contentful Rich Text document to HTML in Gatsby\n- [`rich-text-react-renderer`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer)\n  - Parses a Contentful Rich Text document to React components\n\n### Community made\n\n- [`rich-text-to-jsx`](https://github.com/connor-baer/rich-text-to-jsx)\n  - Opinionated JSX renderer for the Contentful rich text field type\n- [`rich-text-flutter`](https://github.com/Kumanu/contentful-rich-text-flutter)\n  - Flutter renderer for the Contentful rich text field type (work in progress)\n- [`ngx-contentful-rich-text`](https://github.com/kgajera/ngx-contentful-rich-text)\n  - Angular renderer for the Contentful rich text field type\n\n## About Rich Text\n\n- [Rich Text Concept](https://www.contentful.com/developers/docs/concepts/rich-text/)\n- [Getting Started](https://www.contentful.com/developers/docs/tutorials/general/getting-started-with-rich-text-field-type/)\n- [Migrate content to Rich Text](https://www.contentful.com/developers/docs/tutorials/general/migrate-to-rich-text/)\n\n## Get involved\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?maxAge=31557600)](http://makeapullrequest.com)\n\nWe appreciate any help on our repositories. For more details about how to\ncontribute, see our [CONTRIBUTING.md](https://github.com/contentful/rich-text/blob/master/CONTRIBUTING.md)\ndocument.\n\n## Reach out to us\n\n### You have questions about how to use this library?\n\n- Reach out to our community forum: [![Contentful Community Forum](https://img.shields.io/badge/-Join%20Community%20Forum-3AB2E6.svg?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MiA1OSI+CiAgPHBhdGggZmlsbD0iI0Y4RTQxOCIgZD0iTTE4IDQxYTE2IDE2IDAgMCAxIDAtMjMgNiA2IDAgMCAwLTktOSAyOSAyOSAwIDAgMCAwIDQxIDYgNiAwIDEgMCA5LTkiIG1hc2s9InVybCgjYikiLz4KICA8cGF0aCBmaWxsPSIjNTZBRUQyIiBkPSJNMTggMThhMTYgMTYgMCAwIDEgMjMgMCA2IDYgMCAxIDAgOS05QTI5IDI5IDAgMCAwIDkgOWE2IDYgMCAwIDAgOSA5Ii8+CiAgPHBhdGggZmlsbD0iI0UwNTM0RSIgZD0iTTQxIDQxYTE2IDE2IDAgMCAxLTIzIDAgNiA2IDAgMSAwLTkgOSAyOSAyOSAwIDAgMCA0MSAwIDYgNiAwIDAgMC05LTkiLz4KICA8cGF0aCBmaWxsPSIjMUQ3OEE0IiBkPSJNMTggMThhNiA2IDAgMSAxLTktOSA2IDYgMCAwIDEgOSA5Ii8+CiAgPHBhdGggZmlsbD0iI0JFNDMzQiIgZD0iTTE4IDUwYTYgNiAwIDEgMS05LTkgNiA2IDAgMCAxIDkgOSIvPgo8L3N2Zz4K&maxAge=31557600)](https://support.contentful.com/)\n- Jump into our community slack channel: [![Contentful Community Slack](https://img.shields.io/badge/-Join%20Community%20Slack-2AB27B.svg?logo=slack&maxAge=31557600)](https://www.contentful.com/slack/)\n\n### You found a bug or want to propose a feature?\n\n- File an issue here on GitHub: [![File an issue](https://img.shields.io/badge/-Create%20Issue-6cc644.svg?logo=github&maxAge=31557600)](https://github.com/contentful/rich-text/issues/new). Make sure to remove any credential from your code before sharing it.\n\n### You need to share confidential information or have other questions?\n\n- File a support ticket at our Contentful Customer Support: [![File support ticket](https://img.shields.io/badge/-Submit%20Support%20Ticket-3AB2E6.svg?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MiA1OSI+CiAgPHBhdGggZmlsbD0iI0Y4RTQxOCIgZD0iTTE4IDQxYTE2IDE2IDAgMCAxIDAtMjMgNiA2IDAgMCAwLTktOSAyOSAyOSAwIDAgMCAwIDQxIDYgNiAwIDEgMCA5LTkiIG1hc2s9InVybCgjYikiLz4KICA8cGF0aCBmaWxsPSIjNTZBRUQyIiBkPSJNMTggMThhMTYgMTYgMCAwIDEgMjMgMCA2IDYgMCAxIDAgOS05QTI5IDI5IDAgMCAwIDkgOWE2IDYgMCAwIDAgOSA5Ii8+CiAgPHBhdGggZmlsbD0iI0UwNTM0RSIgZD0iTTQxIDQxYTE2IDE2IDAgMCAxLTIzIDAgNiA2IDAgMSAwLTkgOSAyOSAyOSAwIDAgMCA0MSAwIDYgNiAwIDAgMC05LTkiLz4KICA8cGF0aCBmaWxsPSIjMUQ3OEE0IiBkPSJNMTggMThhNiA2IDAgMSAxLTktOSA2IDYgMCAwIDEgOSA5Ii8+CiAgPHBhdGggZmlsbD0iI0JFNDMzQiIgZD0iTTE4IDUwYTYgNiAwIDEgMS05LTkgNiA2IDAgMCAxIDkgOSIvPgo8L3N2Zz4K&maxAge=31557600)](https://www.contentful.com/support/)\n\n## License\n\nThis repository is published under the [MIT](LICENSE) license.\n\n## Code of Conduct\n\nWe want to provide a safe, inclusive, welcoming, and harassment-free space and experience for all participants, regardless of gender identity and expression, sexual orientation, disability, physical appearance, socioeconomic status, body size, ethnicity, nationality, level of experience, age, religion (or lack thereof), or other identity markers.\n\n[Read our full Code of Conduct](https://github.com/contentful-developer-relations/community-code-of-conduct).\n"
  },
  {
    "path": "baseJestConfig.js",
    "content": "function getConfig(packageName) {\n  return {\n    collectCoverage: true,\n    testPathIgnorePatterns: ['/dist/'],\n    moduleNameMapper: {\n      '^(\\\\.{1,2}/.*)\\\\.js$': '$1', // strip .js so TS imports resolve\n    },\n    transform: {\n      '^.+\\\\.(j|t)sx?$': '@swc/jest',\n    },\n    testMatch: ['**/*.test.[jt]s?(x)'],\n    reporters: [\n      'default',\n      [\n        'jest-junit',\n        {\n          outputDirectory: '../../reports',\n          outputName: `${packageName}-results.xml`,\n          addFileAttribute: true,\n        },\n      ],\n    ],\n  };\n}\n\nmodule.exports = getConfig;\n"
  },
  {
    "path": "catalog-info.yaml",
    "content": "apiVersion: backstage.io/v1alpha1\nkind: System\nmetadata:\n  name: rich-text\n  description: |\n    Monorepo with Typescript libraries for handling and rendering Contentful Rich Text documents.\n  annotations:\n    circleci.com/project-slug: github/contentful/rich-text\n    github.com/project-slug: contentful/rich-text\n    backstage.io/source-location: url:https://github.com/contentful/rich-text/\n    contentful.com/ci-alert-slack: prd-authoring-pub-alerts\nspec:\n  type: library\n  lifecycle: production\n  owner: group:team-content-authoring-and-publishing\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = { extends: ['@commitlint/config-conventional'] };\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"$schema\": \"node_modules/lerna/schemas/lerna-schema.json\",\n  \"npmClient\": \"pnpm\",\n  \"version\": \"independent\",\n  \"packages\": [\"packages/*\"],\n  \"command\": {\n    \"version\": {\n      \"allowBranch\": \"master\",\n      \"conventionalCommits\": true,\n      \"message\": \"chore(release): updated release notes and package versions [ci skip]\",\n      \"ignoreChanges\": [\n        \"*.md\",\n        \"*.mdx\",\n        \"**/*.spec.*\",\n        \"**/*.test.*\",\n        \"**/*.stories.*\",\n        \"**/__fixtures__/**\",\n        \"**/__tests__/**\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "nx.json",
    "content": "{\n  \"$schema\": \"./node_modules/nx/schemas/nx-schema.json\",\n  \"tasksRunnerOptions\": {\n    \"default\": {\n      \"runner\": \"nx/tasks-runners/default\",\n      \"options\": {\n        \"cacheableOperations\": [\n          \"build\",\n          \"lint\",\n          \"prebuild\",\n          \"test\",\n          \"test:prod\",\n          \"generate-json-schema\"\n        ]\n      }\n    }\n  },\n  \"targetDefaults\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\"{projectRoot}/dist\"]\n    },\n    \"lint\": {\n      \"dependsOn\": [\"^lint\"],\n      \"outputs\": [\"{projectRoot}/]\"]\n    },\n    \"prebuild\": {\n      \"dependsOn\": [\"^prebuild\"]\n    },\n    \"test\": {\n      \"dependsOn\": [\"^test\"]\n    },\n    \"generate-json-schema\": {\n      \"dependsOn\": [\"^generate-json-schema\"],\n      \"outputs\": [\"{projectRoot}/src/schemas/generated\"]\n    }\n  },\n  \"affected\": {\n    \"defaultBase\": \"origin/master\"\n  },\n  \"defaultBase\": \"master\",\n  \"namedInputs\": {\n    \"default\": [\"{projectRoot}/**/*\", \"sharedGlobals\"],\n    \"sharedGlobals\": [],\n    \"production\": [\"default\"]\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text\",\n  \"private\": true,\n  \"description\": \"A monorepo for all NPM packages related to Rich Text\",\n  \"author\": \"Contentful GmbH\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"engines\": {\n    \"node\": \">=24\"\n  },\n  \"scripts\": {\n    \"build\": \"lerna run build\",\n    \"clean\": \"lerna exec 'rm -rf node_modules/ dist/' && rm -rf node_modules/\",\n    \"lint\": \"eslint ./ --ext .ts,.tsx\",\n    \"lerna\": \"lerna\",\n    \"prettier\": \"prettier './**/*.{js,jsx,ts,tsx,md,mdx}' --write\",\n    \"prettier:check\": \"prettier --check '**/*.{jsx,js,ts,tsx,md,mdx}'\",\n    \"prebuild\": \"lerna run prebuild\",\n    \"start\": \"lerna run start\",\n    \"test\": \"lerna run test\",\n    \"prepare\": \"husky\"\n  },\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"lint-staged\": {\n    \"**/*.{jsx,js,ts,tsx,md,mdx}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"prettier\": {\n    \"singleQuote\": true,\n    \"trailingComma\": \"all\"\n  },\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"20.3.1\",\n    \"@commitlint/config-conventional\": \"20.3.1\",\n    \"@rollup/plugin-commonjs\": \"^29.0.0\",\n    \"@rollup/plugin-node-resolve\": \"16.0.3\",\n    \"@rollup/plugin-swc\": \"0.4.0\",\n    \"@swc/core\": \"1.15.10\",\n    \"@swc/cli\": \"0.7.10\",\n    \"@swc/jest\": \"0.2.39\",\n    \"@types/jest\": \"30.0.0\",\n    \"@types/rollup-plugin-json\": \"^3.0.7\",\n    \"@typescript-eslint/eslint-plugin\": \"^7.14.1\",\n    \"@typescript-eslint/parser\": \"^7.14.1\",\n    \"eslint\": \"8.57.1\",\n    \"eslint-plugin-jest\": \"29.12.1\",\n    \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n    \"eslint-plugin-react\": \"7.37.5\",\n    \"eslint-plugin-react-hooks\": \"7.0.1\",\n    \"eslint-plugin-import\": \"2.32.0\",\n    \"eslint-plugin-import-helpers\": \"2.0.0\",\n    \"eslint-plugin-you-dont-need-lodash-underscore\": \"6.14.0\",\n    \"husky\": \"^9.0.11\",\n    \"jest\": \"30.2.0\",\n    \"jest-junit\": \"16.0.0\",\n    \"lerna\": \"8.2.3\",\n    \"lint-staged\": \"16.2.7\",\n    \"prettier\": \"^3.2.5\",\n    \"rimraf\": \"6.1.2\",\n    \"rollup\": \"^4.18.0\",\n    \"rollup-plugin-json\": \"^4.0.0\",\n    \"typescript\": \"5.9.3\"\n  },\n  \"packageManager\": \"pnpm@10.33.0\",\n  \"pnpm\": {\n    \"overrides\": {\n      \"react-is\": \"^19.2.3\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/.editorconfig",
    "content": "#root = true\n\n[*]\nindent_style = space\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nmax_line_length = 100\nindent_size = 2\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/.gitignore",
    "content": "node_modules\ncoverage\n.nyc_output\n.DS_Store\n*.log\n.vscode\n.idea\ndist\ncompiled\n.awcache\n.rpt2_cache\ndocs\n.vs/slnx.sqlite\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [16.2.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.2.0...@contentful/contentful-slatejs-adapter@16.2.1) (2026-04-09)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.6...@contentful/contentful-slatejs-adapter@16.2.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [16.1.6](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.5...@contentful/contentful-slatejs-adapter@16.1.6) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.1.5](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.4...@contentful/contentful-slatejs-adapter@16.1.5) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.1.4](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.3...@contentful/contentful-slatejs-adapter@16.1.4) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.1.3](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.2...@contentful/contentful-slatejs-adapter@16.1.3) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.1.2](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.1...@contentful/contentful-slatejs-adapter@16.1.2) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.1.0...@contentful/contentful-slatejs-adapter@16.1.1) (2025-09-09)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.0.4...@contentful/contentful-slatejs-adapter@16.1.0) (2025-09-04)\n\n### Features\n\n- migrate to swc and use lingui for i18n [TOL-3288] ([#914](https://github.com/contentful/rich-text/issues/914)) ([b6782a9](https://github.com/contentful/rich-text/commit/b6782a9658b24944ccce2676f06efb1a527d9936))\n\n## [16.0.4](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.0.3...@contentful/contentful-slatejs-adapter@16.0.4) (2025-08-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.0.3](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.0.2...@contentful/contentful-slatejs-adapter@16.0.3) (2025-07-28)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.0.1...@contentful/contentful-slatejs-adapter@16.0.2) (2025-07-15)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@16.0.0...@contentful/contentful-slatejs-adapter@16.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [16.0.0](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.11...@contentful/contentful-slatejs-adapter@16.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [15.18.11](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.10...@contentful/contentful-slatejs-adapter@15.18.11) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.10](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.9...@contentful/contentful-slatejs-adapter@15.18.10) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.9](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.8...@contentful/contentful-slatejs-adapter@15.18.9) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.8](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.7...@contentful/contentful-slatejs-adapter@15.18.8) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.7](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.6...@contentful/contentful-slatejs-adapter@15.18.7) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.6](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.5...@contentful/contentful-slatejs-adapter@15.18.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.5](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.4...@contentful/contentful-slatejs-adapter@15.18.5) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.4](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.3...@contentful/contentful-slatejs-adapter@15.18.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.3](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.2...@contentful/contentful-slatejs-adapter@15.18.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.2](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.1...@contentful/contentful-slatejs-adapter@15.18.2) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.18.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.18.0...@contentful/contentful-slatejs-adapter@15.18.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.18.0](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.5...@contentful/contentful-slatejs-adapter@15.18.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [15.17.5](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.4...@contentful/contentful-slatejs-adapter@15.17.5) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.17.4](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.3...@contentful/contentful-slatejs-adapter@15.17.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.17.3](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.2...@contentful/contentful-slatejs-adapter@15.17.3) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.17.2](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.1...@contentful/contentful-slatejs-adapter@15.17.2) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.17.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.17.0...@contentful/contentful-slatejs-adapter@15.17.1) (2024-05-24)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.17.0](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.14...@contentful/contentful-slatejs-adapter@15.17.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [15.16.14](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.13...@contentful/contentful-slatejs-adapter@15.16.14) (2024-05-22)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.13](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.12...@contentful/contentful-slatejs-adapter@15.16.13) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.12](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.11...@contentful/contentful-slatejs-adapter@15.16.12) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.11](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.10...@contentful/contentful-slatejs-adapter@15.16.11) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.10](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.9...@contentful/contentful-slatejs-adapter@15.16.10) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.9](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.8...@contentful/contentful-slatejs-adapter@15.16.9) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.8](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.7...@contentful/contentful-slatejs-adapter@15.16.8) (2023-09-12)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.7](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.6...@contentful/contentful-slatejs-adapter@15.16.7) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.6](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.5...@contentful/contentful-slatejs-adapter@15.16.6) (2023-05-26)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.5](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.4...@contentful/contentful-slatejs-adapter@15.16.5) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.4](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.3...@contentful/contentful-slatejs-adapter@15.16.4) (2023-04-03)\n\n### Bug Fixes\n\n- entrypoint for types of package ([#454](https://github.com/contentful/rich-text/issues/454)) ([3809d57](https://github.com/contentful/rich-text/commit/3809d57891be88950798c1c2638ee5cebc376bd4))\n\n## [15.16.3](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.2...@contentful/contentful-slatejs-adapter@15.16.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.2](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.1...@contentful/contentful-slatejs-adapter@15.16.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.16.1](https://github.com/contentful/rich-text/compare/@contentful/contentful-slatejs-adapter@15.16.0...@contentful/contentful-slatejs-adapter@15.16.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# 15.16.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- update Lerna, rollup in slatejs-adapter ([#366](https://github.com/contentful/rich-text/issues/366)) ([32448e3](https://github.com/contentful/rich-text/commit/32448e369ae2b76601dd81839e13c15432430d68))\n\n## 15.13.1 (2022-05-10)\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## 15.9.1 (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# 15.9.0 (2021-12-09)\n\n# 15.8.0 (2021-11-11)\n\n### Features\n\n- add toContentfulDocument() and toSlatejsDocument() empty block node handling ([#287](https://github.com/contentful/rich-text/issues/287)) ([fa79626](https://github.com/contentful/rich-text/commit/fa79626e4020d9640a920ca5d0ccb654e89cfa90))\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n# 15.5.0 (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n## 15.3.5 (2021-09-13)\n\n### Bug Fixes\n\n- **rich-text-types:** forbid Tables inside ListItem ([#266](https://github.com/contentful/rich-text/issues/266)) ([fc338bf](https://github.com/contentful/rich-text/commit/fc338bf040b8718057717d2681f800d5e26ba59d))\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.1.0 (2021-08-02)\n\n# 15.0.0 (2021-06-15)\n\n### Bug Fixes\n\n- **slatejs-adapter:** release as public package ([#227](https://github.com/contentful/rich-text/issues/227)) ([0ba8197](https://github.com/contentful/rich-text/commit/0ba81974a732bc6a32109b84e688e0903cc3632c))\n\n# 14.2.0 (2021-05-04)\n\n### Features\n\n- {wip} update slate.js adapter ([c281aea](https://github.com/contentful/rich-text/commit/c281aea098e949c45ed08dd6b46babfc0a75bfb9))\n- fix test types ([0c86f93](https://github.com/contentful/rich-text/commit/0c86f9362f551cf8a2fcbeacfd995052a93a936a))\n- update contentful-to-slatejs adapter ([33a3b6d](https://github.com/contentful/rich-text/commit/33a3b6d69c118e53b7b8464e1c41d9da26edf8d9))\n- update contentful-to-slatejs-adapter ([89a32f4](https://github.com/contentful/rich-text/commit/89a32f494e434fa63b70146da29a81e24fae3cea))\n\n## 14.1.2 (2020-11-02)\n\n### Bug Fixes\n\n- 🐛 skip lib check for TS ([e8bf2ba](https://github.com/contentful/rich-text/commit/e8bf2ba61be9f36f104d0e0337829ac07b30eec6))\n\n### Performance Improvements\n\n- ⚡️ Remove lodash.omit dependency ([93b6b76](https://github.com/contentful/rich-text/commit/93b6b765488a6d3e003a832c953ae10c3f68672e))\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- update Lerna, rollup in slatejs-adapter ([#366](https://github.com/contentful/rich-text/issues/366)) ([32448e3](https://github.com/contentful/rich-text/commit/32448e369ae2b76601dd81839e13c15432430d68))\n\n## [15.13.1](https://github.com/contentful/rich-text/compare/v15.13.0...v15.13.1) (2022-05-10)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.8.0](https://github.com/contentful/rich-text/compare/v15.7.0...v15.8.0) (2021-11-11)\n\n### Features\n\n- add toContentfulDocument() and toSlatejsDocument() empty block node handling ([#287](https://github.com/contentful/rich-text/issues/287)) ([fa79626](https://github.com/contentful/rich-text/commit/fa79626e4020d9640a920ca5d0ccb654e89cfa90))\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n### Bug Fixes\n\n- **rich-text-types:** forbid Tables inside ListItem ([#266](https://github.com/contentful/rich-text/issues/266)) ([fc338bf](https://github.com/contentful/rich-text/commit/fc338bf040b8718057717d2681f800d5e26ba59d))\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.1.0) (2021-09-06)\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n### Bug Fixes\n\n- **slatejs-adapter:** release as public package ([#227](https://github.com/contentful/rich-text/issues/227)) ([0ba8197](https://github.com/contentful/rich-text/commit/0ba81974a732bc6a32109b84e688e0903cc3632c))\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/contentful-slatejs-adapter\n\n# [14.2.0](https://github.com/contentful/rich-text/compare/v14.1.3...v14.2.0) (2021-05-04)\n\n### Features\n\n- {wip} update slate.js adapter ([c281aea](https://github.com/contentful/rich-text/commit/c281aea098e949c45ed08dd6b46babfc0a75bfb9))\n- fix test types ([0c86f93](https://github.com/contentful/rich-text/commit/0c86f9362f551cf8a2fcbeacfd995052a93a936a))\n- update contentful-to-slatejs adapter ([33a3b6d](https://github.com/contentful/rich-text/commit/33a3b6d69c118e53b7b8464e1c41d9da26edf8d9))\n- update contentful-to-slatejs-adapter ([89a32f4](https://github.com/contentful/rich-text/commit/89a32f494e434fa63b70146da29a81e24fae3cea))\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n### Bug Fixes\n\n- 🐛 skip lib check for TS ([e8bf2ba](https://github.com/contentful/rich-text/commit/e8bf2ba61be9f36f104d0e0337829ac07b30eec6))\n\n### Performance Improvements\n\n- ⚡️ Remove lodash.omit dependency ([93b6b76](https://github.com/contentful/rich-text/commit/93b6b765488a6d3e003a832c953ae10c3f68672e))\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/README.md",
    "content": "# contentful-slatejs-adapter\n\nThis library provides an adapter to convert Slate's document structure to Contentful's rich text document structure and vice-versa.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/contentful-slatejs-adapter\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/contentful-slatejs-adapter\n```\n\n## Usage\n\n_TBA_\n\n```json\n{\n  \"category\": \"document\",\n  \"content\": [\n    {\n      \"category\": \"block\",\n      \"type\": \"header-one\",\n      \"content\": [\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \"This is a headline!\",\n          \"marks\": [\n            {\n              \"object\": \"mark\",\n              \"type\": \"bold\",\n              \"data\": {}\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"category\": \"block\",\n      \"type\": \"paragraph\",\n      \"content\": [\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \"\",\n          \"marks\": [\n            {\n              \"object\": \"mark\",\n              \"type\": \"bold\",\n              \"data\": {}\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"category\": \"block\",\n      \"type\": \"paragraph\",\n      \"content\": [\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \"and this is a bold text\",\n          \"marks\": [\n            {\n              \"object\": \"mark\",\n              \"type\": \"bold\",\n              \"data\": {}\n            }\n          ]\n        },\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \" but now i am not bold anymore. \",\n          \"marks\": []\n        },\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \"However, \",\n          \"marks\": [\n            {\n              \"object\": \"mark\",\n              \"type\": \"italic\",\n              \"data\": {}\n            }\n          ]\n        },\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \" i am now \",\n          \"marks\": []\n        },\n        {\n          \"category\": \"text\",\n          \"type\": \"text\",\n          \"value\": \"underlined with shit. \",\n          \"marks\": [\n            {\n              \"object\": \"mark\",\n              \"type\": \"underlined\",\n              \"data\": {}\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/package.json",
    "content": "{\n  \"name\": \"@contentful/contentful-slatejs-adapter\",\n  \"version\": \"16.2.1\",\n  \"description\": \"\",\n  \"keywords\": [],\n  \"main\": \"dist/contentful-slatejs-adapter.es5.js\",\n  \"module\": \"dist/contentful-slatejs-adapter.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/contentful-slatejs-adapter.esm.js\",\n      \"require\": \"./dist/contentful-slatejs-adapter.es5.js\",\n      \"default\": \"./dist/contentful-slatejs-adapter.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"author\": \"Contentful GmbH\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=6.0.0\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.ts\",\n    \"start\": \"rollup -c --bundleConfigAsCjs rollup.config.ts -w\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:prod\": \"yarn test -- --coverage --no-cache\",\n    \"report-coverage\": \"cat ./coverage/lcov.info | coveralls\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\"\n  },\n  \"devDependencies\": {\n    \"@faker-js/faker\": \"^10.0.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/node\": \"^25.0.2\",\n    \"colors\": \"^1.1.2\",\n    \"coveralls\": \"^3.0.0\",\n    \"cross-env\": \"^10.0.0\",\n    \"cz-conventional-changelog\": \"^3.3.0\",\n    \"lodash.camelcase\": \"^4.3.0\",\n    \"prompt\": \"^1.0.0\",\n    \"ts-jest\": \"^29.1.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  }\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/rollup.config.ts",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nexport default config(outputFile, {\n  external: Object.keys(dependencies),\n});\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/__test__/contentful-helpers.ts",
    "content": "import {\n  BLOCKS,\n  INLINES,\n  Document,\n  Block,\n  Inline,\n  Text,\n  Mark,\n  TopLevelBlock,\n  TopLevelBlockEnum,\n} from '@contentful/rich-text-types';\n\nexport interface NodeProps {\n  isVoid?: boolean;\n  data?: Record<string, any>;\n}\n\nexport function document(...content: TopLevelBlock[]): Document {\n  return {\n    data: {},\n    nodeType: BLOCKS.DOCUMENT,\n    content,\n  };\n}\n\nexport function block(\n  nodeType: TopLevelBlockEnum,\n  ...content: Array<Block | Inline | Text>\n): TopLevelBlock;\nexport function block(nodeType: BLOCKS, ...content: Array<Block | Inline | Text>): Block;\nexport function block(nodeType: BLOCKS, ...content: Array<Block | Inline | Text>): Block {\n  return {\n    nodeType,\n    content,\n    data: {},\n  };\n}\n\nexport function inline(nodeType: INLINES, ...content: Array<Inline | Text>): Inline {\n  return {\n    nodeType,\n    content,\n    data: {},\n  };\n}\n\nexport function text(value: string, ...marks: Mark[]): Text {\n  return {\n    nodeType: 'text',\n    data: {},\n    marks,\n    value: value,\n  };\n}\n\nexport function mark(type: string): Mark {\n  return {\n    type,\n  };\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/__test__/contentful-to-slatejs-adapter.test.ts",
    "content": "import * as Contentful from '@contentful/rich-text-types';\n\nimport toSlatejsDocument from '../contentful-to-slatejs-adapter';\nimport toContentfulDocument from '../slatejs-to-contentful-adapter';\nimport { SlateNode } from '../types';\nimport * as contentful from './contentful-helpers';\n\nconst schema = { blocks: { [Contentful.BLOCKS.EMBEDDED_ENTRY]: { isVoid: true } } };\n\ndescribe('both adapters (roundtrippable cases)', () => {\n  const testAdapters = (\n    message: string,\n    contentfulDoc: Contentful.Document,\n    slateDoc: SlateNode[],\n  ) => {\n    describe('toSlatejsDocument()', () => {\n      it(message, () => {\n        const actualSlateDoc = toSlatejsDocument({\n          document: contentfulDoc,\n          schema,\n        });\n        expect(actualSlateDoc).toEqual(slateDoc);\n      });\n\n      it('converts Contentful mentions to Slate mentions', () => {\n        const contentfulInput = {\n          content: [\n            {\n              content: [\n                { data: {}, marks: [], nodeType: 'text', value: 'Hello ' },\n                {\n                  content: [{ data: {}, marks: [], nodeType: 'text', value: '' }],\n                  data: { target: { sys: { id: 'user-id-0', linkType: 'User', type: 'Link' } } },\n                  nodeType: 'mention',\n                },\n                { data: {}, marks: [], nodeType: 'text', value: '' },\n              ],\n              data: {},\n              nodeType: 'paragraph',\n            },\n          ],\n          data: {},\n          nodeType: 'document',\n        };\n        const slateOutput = toSlatejsDocument({\n          document: contentfulInput as unknown as Contentful.Document,\n        });\n\n        const expectedSlateOutput = [\n          {\n            type: 'paragraph',\n            isVoid: false,\n            data: {},\n            children: [\n              {\n                data: {},\n                text: 'Hello ',\n              },\n              {\n                type: 'mention',\n                isVoid: false,\n                data: {\n                  target: {\n                    sys: {\n                      type: 'Link',\n                      linkType: 'User',\n                      id: 'user-id-0',\n                    },\n                  },\n                },\n                children: [\n                  {\n                    data: {},\n                    text: '',\n                  },\n                ],\n              },\n              {\n                data: {},\n                text: '',\n              },\n            ],\n          },\n        ];\n        expect(slateOutput).toStrictEqual(expectedSlateOutput);\n      });\n    });\n    describe('toContentfulDocument()', () => {\n      it(message, () => {\n        const actualContentfulDoc = toContentfulDocument({\n          document: slateDoc,\n          schema,\n        });\n        expect(actualContentfulDoc).toEqual(contentfulDoc);\n      });\n      it('is converts Slate mentions to Contentful mentions', () => {\n        const slateFormatWithMention = [\n          {\n            type: 'paragraph',\n            data: {},\n            children: [\n              {\n                text: 'Hello ',\n              },\n              {\n                type: 'mention',\n                data: {\n                  target: {\n                    sys: {\n                      type: 'Link',\n                      linkType: 'User',\n                      id: 'user-id-0',\n                    },\n                  },\n                },\n                children: [\n                  {\n                    text: '',\n                  },\n                ],\n              },\n              {\n                text: '',\n              },\n            ],\n          },\n        ];\n\n        const resultContentfulDoc = toContentfulDocument({\n          document: slateFormatWithMention as unknown as SlateNode[],\n          schema,\n        });\n\n        const expectedContentfulDoc = {\n          content: [\n            {\n              content: [\n                { data: {}, marks: [], nodeType: 'text', value: 'Hello ' },\n                {\n                  content: [{ data: {}, marks: [], nodeType: 'text', value: '' }],\n                  data: { target: { sys: { id: 'user-id-0', linkType: 'User', type: 'Link' } } },\n                  nodeType: 'mention',\n                },\n                { data: {}, marks: [], nodeType: 'text', value: '' },\n              ],\n              data: {},\n              nodeType: 'paragraph',\n            },\n          ],\n          data: {},\n          nodeType: 'document',\n        };\n\n        expect(resultContentfulDoc).toEqual(expectedContentfulDoc);\n      });\n      it('converts text-only nodes', () => {\n        const slateText = [\n          {\n            type: 'paragraph',\n            data: {},\n            children: [\n              {\n                text: 'Hello ',\n              },\n            ],\n          },\n        ];\n\n        const convertedToContentful = toContentfulDocument({\n          document: slateText as unknown as SlateNode[],\n        });\n\n        const expectedContentfulDoc = {\n          content: [\n            {\n              content: [{ data: {}, marks: [], nodeType: 'text', value: 'Hello ' }],\n              data: {},\n              nodeType: 'paragraph',\n            },\n          ],\n          data: {},\n          nodeType: 'document',\n        };\n\n        expect(convertedToContentful).toStrictEqual(expectedContentfulDoc);\n      });\n    });\n  };\n\n  describe('document', () => {\n    testAdapters('empty document', contentful.document(), []);\n\n    testAdapters(\n      'document with block',\n      contentful.document(contentful.block(Contentful.BLOCKS.PARAGRAPH, contentful.text(''))),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [\n            {\n              text: '',\n              data: {},\n            },\n          ],\n        },\n      ],\n    );\n\n    testAdapters(\n      'paragraph with inline',\n      contentful.document(\n        contentful.block(\n          Contentful.BLOCKS.PARAGRAPH,\n          contentful.inline(Contentful.INLINES.HYPERLINK),\n        ),\n      ),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [\n            {\n              type: Contentful.INLINES.HYPERLINK,\n              data: {},\n              isVoid: false,\n              children: [],\n            },\n          ],\n        },\n      ],\n    );\n\n    testAdapters(\n      'paragraph with text',\n      contentful.document(contentful.block(Contentful.BLOCKS.PARAGRAPH, contentful.text('hi'))),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [{ text: 'hi', data: {} }],\n        },\n      ],\n    );\n\n    testAdapters(\n      'text with marks',\n      contentful.document(\n        contentful.block(\n          Contentful.BLOCKS.PARAGRAPH,\n          contentful.text('this'),\n          contentful.text('is', contentful.mark('bold')),\n        ),\n      ),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [\n            { text: 'this', data: {} },\n            { text: 'is', data: {}, bold: true },\n          ],\n        },\n      ],\n    );\n\n    it('adds a default value to marks if undefined', () => {\n      const slateDoc = [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [{ text: 'Hi', data: {} }],\n        },\n      ];\n      const ctflDoc = toContentfulDocument({\n        document: slateDoc,\n      });\n      expect(ctflDoc).toEqual(\n        contentful.document(\n          contentful.block(Contentful.BLOCKS.PARAGRAPH, {\n            nodeType: 'text',\n            marks: [],\n            data: {},\n            value: 'Hi',\n          }),\n        ),\n      );\n    });\n\n    testAdapters(\n      'text with multiple marks',\n      contentful.document(\n        contentful.block(\n          Contentful.BLOCKS.PARAGRAPH,\n          contentful.text('this'),\n          contentful.text('is', contentful.mark('bold')),\n          contentful.text('huge', contentful.mark('bold'), contentful.mark('italic')),\n        ),\n      ),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [\n            { text: 'this', data: {} },\n            { text: 'is', data: {}, bold: true },\n            { text: 'huge', data: {}, bold: true, italic: true },\n          ],\n        },\n      ],\n    );\n\n    testAdapters(\n      'document with nested blocks',\n      contentful.document(\n        contentful.block(\n          Contentful.BLOCKS.PARAGRAPH,\n          contentful.text('this is a test', contentful.mark('bold')),\n          contentful.text('paragraph', contentful.mark('underline')),\n        ),\n        contentful.block(\n          Contentful.BLOCKS.QUOTE,\n          contentful.block(Contentful.BLOCKS.PARAGRAPH, contentful.text('this is it')),\n        ),\n      ),\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: {},\n          isVoid: false,\n          children: [\n            { text: 'this is a test', data: {}, bold: true },\n            { text: 'paragraph', data: {}, underline: true },\n          ],\n        },\n        {\n          type: Contentful.BLOCKS.QUOTE,\n          data: {},\n          isVoid: false,\n          children: [\n            {\n              type: Contentful.BLOCKS.PARAGRAPH,\n              data: {},\n              isVoid: false,\n              children: [{ text: 'this is it', data: {} }],\n            },\n          ],\n        },\n      ],\n    );\n  });\n\n  describe('converts additional data', () => {\n    testAdapters(\n      'data in block',\n      {\n        nodeType: Contentful.BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: Contentful.BLOCKS.PARAGRAPH,\n            content: [\n              {\n                nodeType: 'text',\n                marks: [],\n                data: {},\n                value: '',\n              },\n            ],\n            data: { a: 1 },\n          },\n        ],\n      },\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: { a: 1 },\n          isVoid: false,\n          children: [{ text: '', data: {} }],\n        },\n      ],\n    );\n\n    testAdapters(\n      'data in inline',\n      {\n        nodeType: Contentful.BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: Contentful.BLOCKS.PARAGRAPH,\n            data: { a: 1 },\n            content: [\n              {\n                nodeType: Contentful.INLINES.HYPERLINK,\n                data: { a: 2 },\n                content: [],\n              },\n            ],\n          },\n        ],\n      },\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: { a: 1 },\n          isVoid: false,\n          children: [\n            {\n              type: Contentful.INLINES.HYPERLINK,\n              data: { a: 2 },\n              isVoid: false,\n              children: [],\n            },\n          ],\n        },\n      ],\n    );\n\n    testAdapters(\n      'data in text',\n      {\n        nodeType: Contentful.BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: Contentful.BLOCKS.PARAGRAPH,\n            data: { a: 1 },\n            content: [\n              {\n                nodeType: Contentful.INLINES.HYPERLINK,\n                data: { a: 2 },\n                content: [\n                  {\n                    nodeType: 'text',\n                    marks: [],\n                    data: { a: 3 },\n                    value: 'YO',\n                  },\n                ],\n              },\n            ],\n          },\n        ],\n      },\n      [\n        {\n          type: Contentful.BLOCKS.PARAGRAPH,\n          data: { a: 1 },\n          isVoid: false,\n          children: [\n            {\n              type: Contentful.INLINES.HYPERLINK,\n              data: { a: 2 },\n              isVoid: false,\n              children: [\n                {\n                  text: 'YO',\n                  data: { a: 3 },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    );\n  });\n\n  describe('sets isVoid from schema', () => {\n    testAdapters(\n      'data in block',\n      {\n        nodeType: Contentful.BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: Contentful.BLOCKS.EMBEDDED_ENTRY,\n            content: [],\n            data: { a: 1 },\n          },\n        ],\n      },\n      [\n        {\n          type: Contentful.BLOCKS.EMBEDDED_ENTRY,\n          data: { a: 1 },\n          isVoid: true,\n          children: [],\n        },\n      ],\n    );\n\n    test('removes empty text nodes from void nodes content', () => {\n      const contentfulDoc: Contentful.Document = {\n        nodeType: Contentful.BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: Contentful.BLOCKS.EMBEDDED_ENTRY,\n            content: [],\n            data: { a: 1 },\n          },\n        ],\n      };\n\n      const slateDoc = [\n        {\n          type: Contentful.BLOCKS.EMBEDDED_ENTRY,\n          data: { a: 1 },\n          isVoid: true,\n          children: [{ text: '', data: {} }],\n        },\n      ];\n\n      const actualContentfulDoc = toContentfulDocument({\n        document: slateDoc,\n        schema,\n      });\n      expect(actualContentfulDoc).toEqual(contentfulDoc);\n    });\n  });\n});\n\ndescribe('toSlatejsDocument() adapter (non-roundtrippable cases)', () => {\n  // `content` for any TEXT_CONTAINER contentful node could be empty according to our\n  // validation rules, but SlateJS could crash if there isn't a text leaf.\n  it('inserts empty text nodes into text container blocks with empty `content`', () => {\n    const cfDoc = {\n      nodeType: Contentful.BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: Contentful.BLOCKS.PARAGRAPH,\n          content: [] as any,\n          data: {},\n        },\n        {\n          nodeType: Contentful.BLOCKS.HEADING_1,\n          content: [] as any,\n          data: {},\n        },\n        {\n          nodeType: Contentful.BLOCKS.HEADING_6,\n          content: [] as any,\n          data: { a: 42 },\n        },\n      ],\n    } as Contentful.Document;\n    const expectedSlateDoc = [\n      {\n        type: Contentful.BLOCKS.PARAGRAPH,\n        data: {},\n        isVoid: false,\n        children: [{ text: '', data: {} }],\n      },\n      {\n        type: Contentful.BLOCKS.HEADING_1,\n        data: {},\n        isVoid: false,\n        children: [{ text: '', data: {} }],\n      },\n      {\n        type: Contentful.BLOCKS.HEADING_6,\n        data: { a: 42 },\n        isVoid: false,\n        children: [{ text: '', data: {} }],\n      },\n    ];\n    const actualSlateDoc = toSlatejsDocument({\n      document: cfDoc,\n      schema,\n    });\n    expect(actualSlateDoc).toEqual(expectedSlateDoc);\n  });\n});\n\ndescribe('toContentfulDocument()}; adapter (non-roundtrippable cases)', () => {\n  it('neither inserts nor removes empty text nodes on container blocks with empty `children`', () => {\n    const slateDoc = [\n      {\n        type: Contentful.BLOCKS.HEADING_1,\n        data: {},\n        isVoid: false,\n        children: [{ text: '', data: {} }],\n      },\n      {\n        type: Contentful.BLOCKS.PARAGRAPH,\n        data: {},\n        isVoid: false,\n        children: [{ text: '', data: {} }],\n      },\n      {\n        type: Contentful.BLOCKS.PARAGRAPH,\n        data: {},\n        isVoid: false,\n        children: [],\n      },\n      {\n        type: Contentful.BLOCKS.HEADING_2,\n        data: {},\n        isVoid: false,\n        children: [],\n      },\n    ];\n    const expectedCfDoc = {\n      nodeType: Contentful.BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: Contentful.BLOCKS.HEADING_1,\n          content: [\n            {\n              nodeType: 'text',\n              marks: [] as any,\n              data: {},\n              value: '',\n            },\n          ],\n          data: {},\n        },\n        {\n          nodeType: Contentful.BLOCKS.PARAGRAPH,\n          content: [\n            {\n              nodeType: 'text',\n              marks: [],\n              data: {},\n              value: '',\n            },\n          ],\n          data: {},\n        },\n        {\n          nodeType: Contentful.BLOCKS.PARAGRAPH,\n          content: [\n            {\n              nodeType: 'text',\n              marks: [],\n              data: {},\n              value: '',\n            },\n          ],\n          data: {},\n        },\n        {\n          nodeType: Contentful.BLOCKS.HEADING_2,\n          content: [\n            {\n              nodeType: 'text',\n              marks: [],\n              data: {},\n              value: '',\n            },\n          ],\n          data: {},\n        },\n      ],\n    };\n    const actualCfDoc = toContentfulDocument({\n      document: slateDoc,\n      schema,\n    });\n    expect(actualCfDoc).toEqual(expectedCfDoc);\n  });\n});\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/contentful-to-slatejs-adapter.ts",
    "content": "import * as Contentful from '@contentful/rich-text-types';\n\nimport { getDataOrDefault } from './helpers';\nimport { fromJSON, Schema, SchemaJSON } from './schema';\nimport {\n  ContentfulElementNode,\n  ContentfulNode,\n  SlateElement,\n  SlateMarks,\n  SlateNode,\n  SlateText,\n} from './types';\n\nexport interface ToSlatejsDocumentProperties {\n  document: Contentful.Document;\n  schema?: SchemaJSON;\n}\n\nexport default function toSlatejsDocument({\n  document,\n  schema,\n}: ToSlatejsDocumentProperties): SlateNode[] {\n  // TODO:\n  // We allow adding data to the root document node, but Slate >v0.5.0\n  // has no concept of a root document node. We should determine whether\n  // this will be a compatibility problem for existing users.\n  return document.content.flatMap((node) => convertNode(node, fromJSON(schema)));\n}\n\nfunction convertNode(node: ContentfulNode, schema: Schema): SlateNode {\n  if (node.nodeType === 'text') {\n    return convertTextNode(node as Contentful.Text);\n  } else {\n    const contentfulNode = node as ContentfulElementNode;\n    const childNodes = contentfulNode.content.flatMap((childNode) =>\n      convertNode(childNode, schema),\n    );\n    const slateNode = convertElementNode(contentfulNode, childNodes, schema);\n    return slateNode;\n  }\n}\n\nfunction convertElementNode(\n  contentfulBlock: ContentfulElementNode,\n  slateChildren: SlateNode[],\n  schema: Schema,\n): SlateElement {\n  const children =\n    slateChildren.length === 0 && schema.isTextContainer(contentfulBlock.nodeType)\n      ? [{ text: '', data: {} }]\n      : slateChildren;\n  return {\n    type: contentfulBlock.nodeType,\n    children,\n    isVoid: schema.isVoid(contentfulBlock),\n    data: getDataOrDefault(contentfulBlock.data),\n  };\n}\n\nfunction convertTextNode(node: Contentful.Text): SlateText {\n  return {\n    text: node.value,\n    data: getDataOrDefault(node.data),\n    ...convertTextMarks(node),\n  };\n}\n\nfunction convertTextMarks(node: Contentful.Text): SlateMarks {\n  const marks: SlateMarks = {};\n  for (const mark of node.marks) {\n    marks[mark.type as keyof SlateMarks] = true;\n  }\n  return marks;\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/helpers.ts",
    "content": "/**\n * Ensures that data defaults to an empty object.\n */\nexport const getDataOrDefault = (value?: Record<string, any>) => value || {};\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/index.ts",
    "content": "export { default as toSlatejsDocument } from './contentful-to-slatejs-adapter';\nexport { default as toContentfulDocument } from './slatejs-to-contentful-adapter';\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/schema.ts",
    "content": "import { BLOCKS, TEXT_CONTAINERS } from '@contentful/rich-text-types';\n\nimport { ContentfulElementNode } from './types';\n\nconst defaultSchema: SchemaJSON = {};\n\n// TODO: Get rid of outdated SlateJS schema concept here and instead construct\n//  a `Schema` object based on `rich-text-types` constants. The original idea\n//  was to decouple code from these constants for future extensibility cases\n//  where we had to deal with custom node types that wouldn't be part of these\n//  constants while a custom (forked) rich-text editor provided `Schema`\n//  instance would be aware of them.\n/**\n * SlateJS Schema definition v0.33.x\n *\n * @export\n * @interface SchemaJSON\n */\nexport interface SchemaJSON {\n  blocks?: Record<string, SchemaValue>;\n  inlines?: Record<string, SchemaValue>;\n}\n// TODO: No need to extend `SchemaJSON` and change `isVoid` to take a `nodeType: string`\nexport interface Schema extends SchemaJSON {\n  isVoid(node: ContentfulElementNode): boolean;\n  isTextContainer(nodeType: string): boolean;\n}\n\nexport interface SchemaValue {\n  isVoid?: boolean;\n  [k: string]: any;\n}\n\n/**\n * Creates an instance of Schema from json.\n *\n * @export\n * @param {SchemaJSON} [schema=defaultSchema]\n * @returns {Schema}\n */\nexport function fromJSON(schema: SchemaJSON = defaultSchema): Schema {\n  return {\n    /**\n     * Check if a `node` is void based on the schema rules.\n     *\n     * @param {ContentfulElementNode} node\n     * @returns\n     */\n    isVoid(node: ContentfulElementNode) {\n      const root = Object.values(BLOCKS).includes(node.nodeType as any) ? 'blocks' : 'inlines';\n      return schema?.[root]?.[node.nodeType]?.['isVoid'] ?? false;\n    },\n    isTextContainer(nodeType: string) {\n      return TEXT_CONTAINERS.includes(nodeType as any);\n    },\n  };\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/slatejs-to-contentful-adapter.ts",
    "content": "import * as Contentful from '@contentful/rich-text-types';\n\nimport { getDataOrDefault } from './helpers';\nimport { Schema, SchemaJSON, fromJSON } from './schema';\nimport {\n  ContentfulElementNode,\n  ContentfulNode,\n  SlateElement,\n  SlateMarks,\n  SlateNode,\n  SlateText,\n} from './types';\n\nexport interface ToContentfulDocumentProperties {\n  document: SlateNode[];\n  schema?: SchemaJSON;\n}\n\nexport default function toContentfulDocument({\n  document,\n  schema,\n}: ToContentfulDocumentProperties): Contentful.Document {\n  // TODO:\n  // We allow adding data to the root document node, but Slate >v0.5.0\n  // has no concept of a root document node. We should determine whether\n  // this will be a compatibility problem for existing users.\n  return {\n    nodeType: Contentful.BLOCKS.DOCUMENT,\n    data: {},\n    content: document.flatMap(\n      (node) => convertNode(node, fromJSON(schema)) as Contentful.TopLevelBlock[],\n    ),\n  };\n}\n\nfunction convertNode(node: SlateNode, schema: Schema): ContentfulNode[] {\n  const nodes: ContentfulNode[] = [];\n  if (isSlateElement(node)) {\n    const contentfulElement: ContentfulElementNode = {\n      nodeType: node.type as Contentful.BLOCKS,\n      data: getDataOrDefault(node.data),\n      content: [],\n    };\n    if (!schema.isVoid(contentfulElement)) {\n      contentfulElement.content = node.children.flatMap((childNode) =>\n        convertNode(childNode, schema),\n      );\n    }\n    if (contentfulElement.content.length === 0 && schema.isTextContainer(node.type)) {\n      contentfulElement.content.push(convertText({ text: '', data: {} }));\n    }\n    nodes.push(contentfulElement);\n  } else {\n    const contentfulText = convertText(node);\n    nodes.push(contentfulText);\n  }\n  return nodes;\n}\n\nfunction convertText(node: SlateText): Contentful.Text {\n  const { text, data, ...marks } = node;\n  return {\n    nodeType: 'text',\n    value: text,\n    marks: getMarkList(marks),\n    data: getDataOrDefault(data),\n  };\n}\n\nfunction getMarkList(marks: SlateMarks): Contentful.Mark[] {\n  const contentfulMarks: Contentful.Mark[] = [];\n  for (const mark of Object.keys(marks)) {\n    contentfulMarks.push({ type: mark });\n  }\n  return contentfulMarks;\n}\n\nfunction isSlateElement(node: SlateNode): node is SlateElement {\n  return 'type' in node;\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/types/index.ts",
    "content": "import * as Contentful from '@contentful/rich-text-types';\n\nexport type SlateMarks = {\n  // This is a workaround for TypeScript's limitations around\n  // index property exclusion. Ideally we'd join the above properties\n  // with something like\n  //\n  // & { [mark: string]: string }\n  //\n  // but TypeScript doesn't allow us to create such objects, only\n  // work around inconsistencies in existing JavaScript.\n  //\n  // In reality Slate's node marks are arbitrary, but for this library\n  // denoting marks used by the tests as optional should be okay.\n  bold?: boolean;\n  italic?: boolean;\n  underline?: boolean;\n};\n\nexport type SlateText = SlateMarks & {\n  text: string;\n  data: object;\n};\n\nexport type SlateElement = {\n  type: string;\n  data: object;\n  isVoid: boolean;\n  children: SlateNode[];\n};\n\nexport type ContentfulElementNode = Contentful.Block | Contentful.Inline;\nexport type ContentfulNode = ContentfulElementNode | Contentful.Text;\nexport type SlateNode = SlateElement | SlateText;\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/src/types/slate.ts",
    "content": "/* eslint-disable */\n\nnamespace Slate {\n  // fixes \"Duplicate identifier\" when generating tests coverage\n  export type NodeObject = 'document' | 'block' | 'inline' | 'text';\n  export interface Node {\n    object: NodeObject;\n    type?: string;\n    data?: object;\n    isVoid?: boolean;\n  }\n\n  export interface Document extends Node {\n    object: 'document';\n    nodes: Block[];\n  }\n\n  export interface Block extends Node {\n    object: 'block';\n\n    nodes: Array<Block | Inline | Text>;\n  }\n\n  export interface Inline extends Node {\n    object: 'inline';\n    nodes: Array<Inline | Text>;\n  }\n\n  export interface Text extends Node {\n    object: 'text';\n    leaves: TextLeaf[];\n  }\n\n  export interface Mark {\n    type: string;\n    data: Record<string, any>;\n    object: 'mark';\n  }\n\n  export interface TextLeaf {\n    object: 'leaf';\n    text: string;\n    marks?: Mark[];\n  }\n}\n"
  },
  {
    "path": "packages/contentful-slatejs-adapter/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"lib\": [\"es2015\", \"es2016\", \"es2017\", \"ES2019\"],\n    \"strict\": true,\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"declarationDir\": \"dist/types\",\n    \"resolveJsonModule\": true,\n    \"outDir\": \"dist/lib\",\n    \"skipLibCheck\": true,\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/typings\"],\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-from-markdown/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [16.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.2.0...@contentful/rich-text-from-markdown@16.2.1) (2026-04-09)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.8...@contentful/rich-text-from-markdown@16.2.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [16.1.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.7...@contentful/rich-text-from-markdown@16.1.8) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.6...@contentful/rich-text-from-markdown@16.1.7) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.5...@contentful/rich-text-from-markdown@16.1.6) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.4...@contentful/rich-text-from-markdown@16.1.5) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.3...@contentful/rich-text-from-markdown@16.1.4) (2025-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.2...@contentful/rich-text-from-markdown@16.1.3) (2025-09-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.1...@contentful/rich-text-from-markdown@16.1.2) (2025-08-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.1.0...@contentful/rich-text-from-markdown@16.1.1) (2025-07-15)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.0.1...@contentful/rich-text-from-markdown@16.1.0) (2025-07-02)\n\n### Features\n\n- **markdown:** transform strikethrough to rich-text mark ([#883](https://github.com/contentful/rich-text/issues/883)) ([ac51579](https://github.com/contentful/rich-text/commit/ac51579f5e716bb15862796177a924c7e838edb6))\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@16.0.0...@contentful/rich-text-from-markdown@16.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [16.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.10...@contentful/rich-text-from-markdown@16.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [15.18.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.9...@contentful/rich-text-from-markdown@15.18.10) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.8...@contentful/rich-text-from-markdown@15.18.9) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.7...@contentful/rich-text-from-markdown@15.18.8) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.6...@contentful/rich-text-from-markdown@15.18.7) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.5...@contentful/rich-text-from-markdown@15.18.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.4...@contentful/rich-text-from-markdown@15.18.5) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.3...@contentful/rich-text-from-markdown@15.18.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.2...@contentful/rich-text-from-markdown@15.18.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.1...@contentful/rich-text-from-markdown@15.18.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.18.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.18.0...@contentful/rich-text-from-markdown@15.18.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.18.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.5...@contentful/rich-text-from-markdown@15.18.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [15.17.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.4...@contentful/rich-text-from-markdown@15.17.5) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.17.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.3...@contentful/rich-text-from-markdown@15.17.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.17.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.2...@contentful/rich-text-from-markdown@15.17.3) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.17.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.1...@contentful/rich-text-from-markdown@15.17.2) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.17.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.17.0...@contentful/rich-text-from-markdown@15.17.1) (2024-05-24)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.17.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.15...@contentful/rich-text-from-markdown@15.17.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [15.16.15](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.14...@contentful/rich-text-from-markdown@15.16.15) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.14](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.13...@contentful/rich-text-from-markdown@15.16.14) (2024-03-01)\n\n### Bug Fixes\n\n- support <br/> from markdown ([#536](https://github.com/contentful/rich-text/issues/536)) ([30a3668](https://github.com/contentful/rich-text/commit/30a36685f42c70c98ae4bfb514ba710812ec0824))\n\n## [15.16.13](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.12...@contentful/rich-text-from-markdown@15.16.13) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.12](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.11...@contentful/rich-text-from-markdown@15.16.12) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.11](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.10...@contentful/rich-text-from-markdown@15.16.11) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.9...@contentful/rich-text-from-markdown@15.16.10) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.8...@contentful/rich-text-from-markdown@15.16.9) (2024-01-22)\n\n### Bug Fixes\n\n- [] Wrap inline nodes inside of a table cell in paragraph node ([#520](https://github.com/contentful/rich-text/issues/520)) ([6290f7d](https://github.com/contentful/rich-text/commit/6290f7dcae96c279d97e88ad65c42a080778fe73))\n\n## [15.16.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.7...@contentful/rich-text-from-markdown@15.16.8) (2023-09-12)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.6...@contentful/rich-text-from-markdown@15.16.7) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.5...@contentful/rich-text-from-markdown@15.16.6) (2023-05-26)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.4...@contentful/rich-text-from-markdown@15.16.5) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.3...@contentful/rich-text-from-markdown@15.16.4) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.2...@contentful/rich-text-from-markdown@15.16.3) (2023-02-09)\n\n### Bug Fixes\n\n- update remark-parse to v9 to fix security issue of trim@0.0.1 ([#444](https://github.com/contentful/rich-text/issues/444)) ([f961a89](https://github.com/contentful/rich-text/commit/f961a8927d911b2653883601b3cfdcd1b255a60b))\n\n## [15.16.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.1...@contentful/rich-text-from-markdown@15.16.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.16.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-from-markdown@15.16.0...@contentful/rich-text-from-markdown@15.16.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# 15.16.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## 15.13.1 (2022-05-10)\n\n### Bug Fixes\n\n- **markdown:** handle empty table cells ([#329](https://github.com/contentful/rich-text/issues/329)) ([55a0a16](https://github.com/contentful/rich-text/commit/55a0a16a12700fefbe7e9727a7172043fd126fc5))\n\n# 15.13.0 (2022-05-06)\n\n### Features\n\n- support converting tables from markdown to rich-text ([0abc0c6](https://github.com/contentful/rich-text/commit/0abc0c60b7e3e2683ebbb427b44847e6242f6e5e))\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.2 (2022-02-07)\n\n### Bug Fixes\n\n- set \"typings\" for rich-text-from-markdown ([1b3a15f](https://github.com/contentful/rich-text/commit/1b3a15f1cb15eacb6d1b15f2b79c5747e2d25618))\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n## 15.10.1 (2021-12-21)\n\n### Bug Fixes\n\n- remove support to convert tables from md to rich text ([a9d513c](https://github.com/contentful/rich-text/commit/a9d513c285e8cdedd384b89e195734dd3a8d2136))\n\n# 15.10.0 (2021-12-15)\n\n## 15.9.1 (2021-12-10)\n\n# 15.9.0 (2021-12-09)\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n### Features\n\n- add support to convert tables from md to rich text ([#284](https://github.com/contentful/rich-text/issues/284)) ([213a29c](https://github.com/contentful/rich-text/commit/213a29c78d48b3e63088999c4eed4891906d1719))\n\n## 15.5.1 (2021-10-25)\n\n# 15.5.0 (2021-10-25)\n\n## 15.3.6 (2021-09-15)\n\n## 15.3.5 (2021-09-13)\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.1.0 (2021-08-02)\n\n# 15.0.0 (2021-06-15)\n\n## 14.1.2 (2020-11-02)\n\n## 14.0.1 (2020-01-30)\n\n# 14.0.0 (2020-01-28)\n\n# 13.4.0 (2019-08-01)\n\n# 13.1.0 (2019-03-04)\n\n## 13.0.1 (2019-02-11)\n\n# 13.0.0 (2019-01-22)\n\n# 12.2.0 (2018-12-20)\n\n### Bug Fixes\n\n- fix import path ([3f3edff](https://github.com/contentful/rich-text/commit/3f3edff8bc4f4463a701d0ae1d397fcf9acec325))\n- ignore unsupported marks ([1757331](https://github.com/contentful/rich-text/commit/1757331a74f360353556a242a9fe20da131b9a59))\n\n### Features\n\n- 🎸 parse links inside marks ([11722cf](https://github.com/contentful/rich-text/commit/11722cfad85d5e15b10d2b18d3c831ec613922c3))\n\n## 12.1.2 (2018-12-14)\n\n## 12.1.1 (2018-12-12)\n\n### Bug Fixes\n\n- handle hyperlinks ([54508d4](https://github.com/contentful/rich-text/commit/54508d495adf5055e4089f54dd62f00f8be6be46))\n\n# 12.1.0 (2018-12-12)\n\n### Bug Fixes\n\n- **async-handling:** move to promise-based api ([a07d3fc](https://github.com/contentful/rich-text/commit/a07d3fcbd99a2d80f86bc6dcf5cba01665221ebc))\n\n## 12.0.1 (2018-12-04)\n\n### Bug Fixes\n\n- **from-markdown:** Fix list typos ([c392016](https://github.com/contentful/rich-text/commit/c392016e2f11628021cd27bff3447f548398c3b4))\n- **parsing:** list item, (un)ordered list, links, quotes ([8a0c580](https://github.com/contentful/rich-text/commit/8a0c580306c154f1c1d6c2ba964c46d18881be12))\n- **text:** Parse text nodes with marks correctly ([d489f90](https://github.com/contentful/rich-text/commit/d489f904a33726f42006b09871d15bcfbdd7e274))\n\n# 12.0.0 (2018-11-29)\n\n# 11.0.0 (2018-11-27)\n\n# 10.3.0 (2018-11-26)\n\n# 10.2.0 (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# 10.1.0 (2018-11-16)\n\n### Bug Fixes\n\n- 🐛 removes obsolete fields from mark nodes ([b638a56](https://github.com/contentful/rich-text/commit/b638a56652520969d3ac898ac158be81a9788f67))\n\n### Features\n\n- 🎸 introduces top-level-block type ([a6bf35e](https://github.com/contentful/rich-text/commit/a6bf35e7c9ca35915a512de774b3a3fdc4c76e5d))\n\n## 10.0.4 (2018-11-09)\n\n## 10.0.3 (2018-11-09)\n\n## 10.0.2 (2018-11-09)\n\n## 10.0.1 (2018-11-08)\n\n### Features\n\n- **packages:** Add rich text from markdown package ([bc8ec41](https://github.com/contentful/rich-text/commit/bc8ec41f5615eabcc29031ee99da3f9c70b414b3))\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## [15.13.1](https://github.com/contentful/rich-text/compare/v15.13.0...v15.13.1) (2022-05-10)\n\n### Bug Fixes\n\n- **markdown:** handle empty table cells ([#329](https://github.com/contentful/rich-text/issues/329)) ([55a0a16](https://github.com/contentful/rich-text/commit/55a0a16a12700fefbe7e9727a7172043fd126fc5))\n\n# [15.13.0](https://github.com/contentful/rich-text/compare/v15.12.1...v15.13.0) (2022-05-06)\n\n### Features\n\n- support converting tables from markdown to rich-text ([0abc0c6](https://github.com/contentful/rich-text/commit/0abc0c60b7e3e2683ebbb427b44847e6242f6e5e))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.11.2](https://github.com/contentful/rich-text/compare/v15.11.1...v15.11.2) (2022-02-07)\n\n### Bug Fixes\n\n- set \"typings\" for rich-text-from-markdown ([1b3a15f](https://github.com/contentful/rich-text/commit/1b3a15f1cb15eacb6d1b15f2b79c5747e2d25618))\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n### Bug Fixes\n\n- remove support to convert tables from md to rich text ([a9d513c](https://github.com/contentful/rich-text/commit/a9d513c285e8cdedd384b89e195734dd3a8d2136))\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n### Features\n\n- add support to convert tables from md to rich text ([#284](https://github.com/contentful/rich-text/issues/284)) ([213a29c](https://github.com/contentful/rich-text/commit/213a29c78d48b3e63088999c4eed4891906d1719))\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/rich-text-from-markdown\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.1.0) (2021-09-06)\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n## [13.0.1](https://github.com/contentful/rich-text/compare/v13.0.0...v13.0.1) (2019-02-11)\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n# [12.2.0](https://github.com/contentful/rich-text/compare/v12.1.2...v12.2.0) (2018-12-20)\n\n### Bug Fixes\n\n- fix import path ([3f3edff](https://github.com/contentful/rich-text/commit/3f3edff8bc4f4463a701d0ae1d397fcf9acec325))\n- ignore unsupported marks ([1757331](https://github.com/contentful/rich-text/commit/1757331a74f360353556a242a9fe20da131b9a59))\n\n### Features\n\n- 🎸 parse links inside marks ([11722cf](https://github.com/contentful/rich-text/commit/11722cfad85d5e15b10d2b18d3c831ec613922c3))\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n## [12.1.1](https://github.com/contentful/rich-text/compare/v12.1.0...v12.1.1) (2018-12-12)\n\n### Bug Fixes\n\n- handle hyperlinks ([54508d4](https://github.com/contentful/rich-text/commit/54508d495adf5055e4089f54dd62f00f8be6be46))\n\n# [12.1.0](https://github.com/contentful/rich-text/compare/v12.0.4...v12.1.0) (2018-12-12)\n\n### Bug Fixes\n\n- **async-handling:** move to promise-based api ([a07d3fc](https://github.com/contentful/rich-text/commit/a07d3fcbd99a2d80f86bc6dcf5cba01665221ebc))\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n### Bug Fixes\n\n- **from-markdown:** Fix list typos ([c392016](https://github.com/contentful/rich-text/commit/c392016e2f11628021cd27bff3447f548398c3b4))\n- **parsing:** list item, (un)ordered list, links, quotes ([8a0c580](https://github.com/contentful/rich-text/commit/8a0c580306c154f1c1d6c2ba964c46d18881be12))\n- **text:** Parse text nodes with marks correctly ([d489f90](https://github.com/contentful/rich-text/commit/d489f904a33726f42006b09871d15bcfbdd7e274))\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# [10.1.0](https://github.com/contentful/rich-text/compare/v10.0.5...v10.1.0) (2018-11-16)\n\n### Bug Fixes\n\n- 🐛 removes obsolete fields from mark nodes ([b638a56](https://github.com/contentful/rich-text/commit/b638a56652520969d3ac898ac158be81a9788f67))\n\n### Features\n\n- 🎸 introduces top-level-block type ([a6bf35e](https://github.com/contentful/rich-text/commit/a6bf35e7c9ca35915a512de774b3a3fdc4c76e5d))\n\n## [10.0.4](https://github.com/contentful/rich-text/compare/v10.0.3...v10.0.4) (2018-11-09)\n\n## [10.0.3](https://github.com/contentful/rich-text/compare/v10.0.2...v10.0.3) (2018-11-09)\n\n## [10.0.2](https://github.com/contentful/rich-text/compare/v10.0.1...v10.0.2) (2018-11-09)\n\n## [10.0.1](https://github.com/contentful/rich-text/compare/v10.0.0...v10.0.1) (2018-11-08)\n\n### Features\n\n- **packages:** Add rich text from markdown package ([bc8ec41](https://github.com/contentful/rich-text/commit/bc8ec41f5615eabcc29031ee99da3f9c70b414b3))\n"
  },
  {
    "path": "packages/rich-text-from-markdown/README.md",
    "content": "# rich-text-from-markdown\n\nA library to convert markdown to Contentful Rich Text document format.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/rich-text-from-markdown\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/rich-text-from-markdown\n```\n\n## Usage\n\n### Basic\n\n```js\nconst { richTextFromMarkdown } = require('@contentful/rich-text-from-markdown');\n\nconst document = await richTextFromMarkdown('# Hello World');\n```\n\n### Advanced\n\nThe library will convert automatically the following markdown nodes:\n\n- `paragraph`\n- `heading`\n- `text`\n- `emphasis`\n- `strong`\n- `delete`\n- `inlineCode`\n- `link`\n- `thematicBreak`\n- `blockquote`\n- `list`\n- `listItem`\n- `table`\n- `tableRow`\n- `tableCell`\n\nIf the markdown content has unsupported nodes like image `![image](url)` you can add a callback as a second argument\nand it will get called everytime an unsupported node is found. The return value of the callback will be the rich text representation\nof that node.\n\n#### Example:\n\n```js\nconst { richTextFromMarkdown } = require('@contentful/rich-text-from-markdown');\n\n// define your own type for unsupported nodes like asset\nconst document = await richTextFromMarkdown(\n  \"![image]('https://example.com/image.jpg')\",\n  (node) => ({\n    nodeType: 'embedded-[entry|asset]-[block|inline]',\n    content: [],\n    data: {\n      target: {\n        sys: {\n          type: 'Link',\n          linkType: 'Entry|Asset',\n          id: '.........',\n        },\n      },\n    },\n  }),\n);\n```\n"
  },
  {
    "path": "packages/rich-text-from-markdown/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-from-markdown/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-from-markdown\",\n  \"version\": \"16.2.1\",\n  \"description\": \"convert markdown to rich text\",\n  \"keywords\": [\n    \"rich-text\",\n    \"contentful\",\n    \"markdown\"\n  ],\n  \"author\": \"Khaled Garbaya <khaled@contentful.com>\",\n  \"homepage\": \"https://github.com/contentful/rich-text#readme\",\n  \"license\": \"MIT\",\n  \"main\": \"dist/rich-text-from-markdown.es5.js\",\n  \"module\": \"dist/rich-text-from-markdown.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/rich-text-from-markdown.esm.js\",\n      \"require\": \"./dist/rich-text-from-markdown.es5.js\",\n      \"default\": \"./dist/rich-text-from-markdown.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"directories\": {\n    \"src\": \"src\",\n    \"test\": \"__tests__\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/contentful/rich-text.git\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"tsc --module commonjs && rollup -c --bundleConfigAsCjs rollup.config.js\",\n    \"start\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.js -w\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\",\n    \"lodash\": \"^4.17.11\",\n    \"remark-gfm\": \"^1.0.0\",\n    \"remark-parse\": \"^9.0.0\",\n    \"unified\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@faker-js/faker\": \"^10.0.0\",\n    \"@types/lodash\": \"^4.14.172\",\n    \"ts-jest\": \"^29.1.2\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/contentful/rich-text/issues\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-from-markdown/rollup.config.js",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nexport default config(outputFile, {\n  external: Object.keys(dependencies),\n});\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/__test__/helpers.ts",
    "content": "import {\n  TopLevelBlock,\n  Document,\n  BLOCKS,\n  Block,\n  Inline,\n  Text,\n  Mark,\n} from '@contentful/rich-text-types';\nexport interface NodeProps {\n  data?: Record<string, any>;\n}\n\nconst defaultProps: NodeProps = { data: {} };\n\nexport function document(props: NodeProps = defaultProps, ...content: TopLevelBlock[]): Document {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content,\n    ...props,\n  };\n}\n\nexport function block<T extends Block>(\n  nodeType: BLOCKS,\n  props: NodeProps = defaultProps,\n  ...content: Array<Block | Inline | Text>\n): T {\n  return {\n    nodeType,\n    content,\n    data: {},\n    ...props,\n  } as T;\n}\n\nexport function inline(\n  nodeType: string,\n  props: NodeProps = defaultProps,\n  ...content: Array<Inline | Text>\n): Inline {\n  return {\n    nodeType,\n    data: {},\n    content,\n    ...props,\n  } as Inline;\n}\n\nexport function text(value: string, ...marks: Mark[]): Text {\n  return {\n    nodeType: 'text',\n    data: {},\n    marks,\n    value: value,\n  };\n}\n\nexport function mark(type: string): Mark {\n  return {\n    type,\n  };\n}\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/__test__/index.test.ts",
    "content": "import { BLOCKS, INLINES, MARKS } from '@contentful/rich-text-types';\n\nimport { richTextFromMarkdown } from '..';\n\nimport { block, document, inline, mark, text } from './helpers';\n\ndescribe('rich-text-from-markdown', () => {\n  test('should parse some markdown', async () => {\n    const result = await richTextFromMarkdown('# Hello World');\n    expect(result).toEqual(document({}, block(BLOCKS.HEADING_1, {}, text('Hello World'))));\n  });\n\n  test('should call the fallback function when a node is not supported', async () => {\n    const fakeNode = { nodeType: 'image', data: {} };\n    const fallback = jest.fn(() => Promise.resolve(fakeNode));\n    const result = await richTextFromMarkdown(\n      '![image](https://image.example.com/image.jpg)',\n      fallback,\n    );\n\n    expect(fallback).toHaveBeenCalledTimes(1);\n    expect(result).toEqual({\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: 'image',\n          data: {},\n        },\n      ],\n    });\n  });\n});\n\ndescribe.each<[string, string[], string[]?]>([\n  ['*This is an italic text*', ['This is an italic text', 'italic']],\n  ['__This a bold text__', ['This a bold text', 'bold']],\n  ['`This is code`', ['This is code', 'code']],\n  [\n    '__This is bold and *this is an italic*__',\n    ['This is bold and ', 'bold'],\n    ['this is an italic', 'bold', 'italic'],\n  ],\n])(\n  'The markdown \"%s\" should be parsed to text with value \"%s\"',\n  (markdown, ...expectedTextWithMarks) => {\n    test(`${markdown}`, async () => {\n      const result = await richTextFromMarkdown(markdown);\n      expect(result).toEqual(\n        document(\n          {},\n          block(\n            BLOCKS.PARAGRAPH,\n            {},\n            ...expectedTextWithMarks.map(([expectedText, ...expectedMarkTypes]) =>\n              text(expectedText, ...expectedMarkTypes.map(mark)),\n            ),\n          ),\n        ),\n      );\n    });\n  },\n);\n\ndescribe('parses complex inline image markdown correctly', () => {\n  test('incoming markdown tree calls fallback twice', async () => {\n    const fakeNode = { nodeType: 'image', data: {} };\n    const fallback = jest.fn(() => Promise.resolve(fakeNode));\n    const result = await richTextFromMarkdown(\n      `![image](https://image.example.com/image.jpg)\n      ![image](https://image.example.com/image2.jpg)`,\n      fallback,\n    );\n\n    expect(fallback).toHaveBeenCalledTimes(2);\n    expect(result).toEqual({\n      nodeType: 'document',\n      data: {},\n      content: [\n        {\n          nodeType: 'image',\n          data: {},\n        },\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          text(`\n`),\n        ),\n        {\n          nodeType: 'image',\n          data: {},\n        },\n      ],\n    });\n  });\n  test('incoming markdown tree calls fallback twice', async () => {\n    const fakeNode = { nodeType: 'image', data: {} };\n    const fallback = jest.fn(() => Promise.resolve(fakeNode));\n    const result = await richTextFromMarkdown(\n      `some text ![image](https://image.example.com/image.jpg)![image](https://image.example.com/image2.jpg) some more text`,\n      fallback,\n    );\n\n    expect(fallback).toHaveBeenCalledTimes(2);\n    expect(result).toEqual({\n      nodeType: 'document',\n      data: {},\n      content: [\n        block(BLOCKS.PARAGRAPH, {}, text('some text ')),\n        {\n          nodeType: 'image',\n          data: {},\n        },\n        {\n          nodeType: 'image',\n          data: {},\n        },\n        block(BLOCKS.PARAGRAPH, {}, text(' some more text')),\n      ],\n    });\n  });\n});\n\ndescribe('links', () => {\n  test('should correctly convert a link', async () => {\n    const result = await richTextFromMarkdown('[This is a link](https://contentful.com)');\n\n    expect(result).toEqual(\n      document(\n        {},\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          inline(\n            INLINES.HYPERLINK,\n            {\n              data: {\n                uri: 'https://contentful.com',\n              },\n            },\n            text('This is a link'),\n          ),\n        ),\n      ),\n    );\n  });\n\n  test('should convert link wrapped in a mark', async () => {\n    const result = await richTextFromMarkdown(\n      '*This is a test [Contentful](https://www.contentful.com/). Text text*',\n    );\n\n    expect(result).toEqual(\n      document(\n        {},\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          text('This is a test ', mark(MARKS.ITALIC)),\n          inline(\n            INLINES.HYPERLINK,\n            {\n              data: {\n                uri: 'https://www.contentful.com/',\n              },\n            },\n            text('Contentful', mark(MARKS.ITALIC)),\n          ),\n          text('. Text text', mark(MARKS.ITALIC)),\n        ),\n      ),\n    );\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/__test__/real-world.md",
    "content": "<!-- prettier-ignore-start -->\n\n# h1 Heading\n\n## h2 Heading\n\n### h3 Heading\n\n#### h4 Heading\n\n##### h5 Heading\n\n###### h6 Heading\n\n## Paragraphs\n\nThis is a paragraph\nwith a new line.\n\nThis is a new paragraph.\n\nThis is a paragraph<br/>using br.\n\n## Horizontal Rules\n\n---\n\n---\n\n---\n\n## Emphasis\n\n**This is bold text**\n\n**This is bold text**\n\n_This is italic text_\n\n_This is italic text_\n\n~~Strikethrough is supported~~\n\n## Blockquotes\n\n> Blockquotes\n\n## Lists\n\nUnordered\n\n- Create a list by starting a line with `+`, `-`, or `*`\n- Sub-lists are made by indenting 2 spaces:\n  - Marker character change forces new list start:\n    - Ac tristique libero volutpat at\n    * Facilisis in pretium nisl aliquet\n    - Nulla volutpat aliquam velit\n- Very easy!\n- Here is a list item<br/>with a line break\n\nOrdered\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n\n4. You can use sequential numbers...\n5. ...or keep all the numbers as `1.`\n\nStart numbering with offset:\n\n57. foo\n1. bar\n\n## Code\n\nInline `code`\n\n## Links\n\n[link text](https://www.contentful.com)\n\n[link with title](https://www.contentful.com/blog/ 'title text!')\n\n## Tables\n\n| Name                                         | Country |\n| -------------------------------------------- | ------- |\n| Test 1                                       | Germany |\n| Test 2                                       | USA     |\n| > Test 3                                     | USA     |\n| \\* Test 4                                    | Germany |\n| # Test 5                                     | Germany |\n| <p>Test 6<br/>Test 7</p>                     | USA     |\n| <ul><li>Test 8</li></ul>                     | USA     |\n| <blockquote>Test 9</blockquote>              | Germany |\n| <div><p>Test 10</p> and <p>Test 11</p></div> | Germany |\n| <img src=\"image.jpg\" />                      | Germany |\n| ![Image Description](image.jpg)              | Brazil  |\n| **[Test 12](https://example.com)**           | USA     |\n\n## Tables with marks\n\n| **Bold Header 1** | **Bold Header 2** |\n| ----------------- | ----------------- |\n| _Italic_          | `Code`            |\n\n## Tables without body\n\n| abc | def |\n| --- | --- |\n\n## Table with empty cells\n\n|        |        |\n| ------ | ------ |\n| Cell 1 |        |\n|        | Cell 2 |\n\n  <!-- prettier-ignore-end -->\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/__test__/real-world.test.ts",
    "content": "import { BLOCKS, INLINES, MARKS } from '@contentful/rich-text-types';\nimport { readFileSync } from 'fs';\nimport path from 'path';\n\nimport { richTextFromMarkdown } from '..';\n\nimport { block, document, inline, mark, text } from './helpers';\n\ndescribe('rich-text-from-markdown', () => {\n  it('should parse md with all formatting options', async () => {\n    const md = readFileSync(path.resolve(__dirname, './real-world.md'), 'utf8');\n\n    const result = await richTextFromMarkdown(md);\n    expect(result).toEqual(\n      document(\n        {},\n        block(BLOCKS.HEADING_1, {}, text('h1 Heading')),\n        block(BLOCKS.HEADING_2, {}, text('h2 Heading')),\n        block(BLOCKS.HEADING_3, {}, text('h3 Heading')),\n        block(BLOCKS.HEADING_4, {}, text('h4 Heading')),\n        block(BLOCKS.HEADING_5, {}, text('h5 Heading')),\n        block(BLOCKS.HEADING_6, {}, text('h6 Heading')),\n        // Paragraphs\n        block(BLOCKS.HEADING_2, {}, text('Paragraphs')),\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          text(`This is a paragraph\nwith a new line.`),\n        ),\n        block(BLOCKS.PARAGRAPH, {}, text('This is a new paragraph.')),\n        // TODO: <br /> test should be ideally the same as the new line one.\n        block(BLOCKS.PARAGRAPH, {}, text('This is a paragraph'), text('\\n'), text('using br.')),\n\n        block(BLOCKS.HEADING_2, {}, text('Horizontal Rules')),\n        block(BLOCKS.HR),\n        block(BLOCKS.HR),\n        block(BLOCKS.HR),\n        block(BLOCKS.HEADING_2, {}, text('Emphasis')),\n        block(BLOCKS.PARAGRAPH, {}, text('This is bold text', mark(MARKS.BOLD))),\n        block(BLOCKS.PARAGRAPH, {}, text('This is bold text', mark(MARKS.BOLD))),\n        block(BLOCKS.PARAGRAPH, {}, text('This is italic text', mark(MARKS.ITALIC))),\n        block(BLOCKS.PARAGRAPH, {}, text('This is italic text', mark(MARKS.ITALIC))),\n        block(BLOCKS.PARAGRAPH, {}, text('Strikethrough is supported', mark(MARKS.STRIKETHROUGH))),\n        block(BLOCKS.HEADING_2, {}, text('Blockquotes')),\n        block(BLOCKS.QUOTE, {}, block(BLOCKS.PARAGRAPH, {}, text('Blockquotes'))),\n        block(BLOCKS.HEADING_2, {}, text('Lists')),\n        block(BLOCKS.PARAGRAPH, {}, text('Unordered')),\n        block(\n          BLOCKS.UL_LIST,\n          {},\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(\n              BLOCKS.PARAGRAPH,\n              {},\n              text('Create a list by starting a line with '),\n              text('+', mark(MARKS.CODE)),\n              text(', '),\n              text('-', mark(MARKS.CODE)),\n              text(', or '),\n              text('*', mark(MARKS.CODE)),\n            ),\n          ),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(BLOCKS.PARAGRAPH, {}, text('Sub-lists are made by indenting 2 spaces:')),\n\n            block(\n              BLOCKS.UL_LIST,\n              {},\n              block(\n                BLOCKS.LIST_ITEM,\n                {},\n                block(BLOCKS.PARAGRAPH, {}, text('Marker character change forces new list start:')),\n\n                block(\n                  BLOCKS.UL_LIST,\n                  {},\n                  block(\n                    BLOCKS.LIST_ITEM,\n                    {},\n                    block(BLOCKS.PARAGRAPH, {}, text('Ac tristique libero volutpat at')),\n                  ),\n                ),\n                block(\n                  BLOCKS.UL_LIST,\n                  {},\n                  block(\n                    BLOCKS.LIST_ITEM,\n                    {},\n                    block(BLOCKS.PARAGRAPH, {}, text('Facilisis in pretium nisl aliquet')),\n                  ),\n                ),\n                block(\n                  BLOCKS.UL_LIST,\n                  {},\n                  block(\n                    BLOCKS.LIST_ITEM,\n                    {},\n                    block(BLOCKS.PARAGRAPH, {}, text('Nulla volutpat aliquam velit')),\n                  ),\n                ),\n              ),\n            ),\n          ),\n          block(BLOCKS.LIST_ITEM, {}, block(BLOCKS.PARAGRAPH, {}, text('Very easy!'))),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(\n              BLOCKS.PARAGRAPH,\n              {},\n              text('Here is a list item'),\n              text('\\n'),\n              text('with a line break'),\n            ),\n          ),\n        ),\n        block(BLOCKS.PARAGRAPH, {}, text('Ordered')),\n        block(\n          BLOCKS.OL_LIST,\n          {},\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(BLOCKS.PARAGRAPH, {}, text('Lorem ipsum dolor sit amet')),\n          ),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(BLOCKS.PARAGRAPH, {}, text('Consectetur adipiscing elit')),\n          ),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(BLOCKS.PARAGRAPH, {}, text('Integer molestie lorem at massa')),\n          ),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(BLOCKS.PARAGRAPH, {}, text('You can use sequential numbers...')),\n          ),\n          block(\n            BLOCKS.LIST_ITEM,\n            {},\n            block(\n              BLOCKS.PARAGRAPH,\n              {},\n              text('...or keep all the numbers as '),\n              text('1.', mark(MARKS.CODE)),\n            ),\n          ),\n        ),\n        block(BLOCKS.PARAGRAPH, {}, text('Start numbering with offset:')),\n        block(\n          BLOCKS.OL_LIST,\n          {},\n          block(BLOCKS.LIST_ITEM, {}, block(BLOCKS.PARAGRAPH, {}, text('foo'))),\n          block(BLOCKS.LIST_ITEM, {}, block(BLOCKS.PARAGRAPH, {}, text('bar'))),\n        ),\n        block(BLOCKS.HEADING_2, {}, text('Code')),\n        block(BLOCKS.PARAGRAPH, {}, text('Inline '), text('code', mark('code'))),\n        block(BLOCKS.HEADING_2, {}, text('Links')),\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          inline(\n            INLINES.HYPERLINK,\n            { data: { uri: 'https://www.contentful.com' } },\n            text('link text'),\n          ),\n        ),\n        block(\n          BLOCKS.PARAGRAPH,\n          {},\n          inline(\n            INLINES.HYPERLINK,\n            { data: { uri: 'https://www.contentful.com/blog/' } },\n            text('link with title'),\n          ),\n        ),\n        // Tables\n        block(BLOCKS.HEADING_2, {}, text('Tables')),\n        block(\n          BLOCKS.TABLE,\n          {},\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Name'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Country'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Test 1'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Test 2'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('USA'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('> Test 3'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('USA'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('* Test 4'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('# Test 5'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Test 6'), text('\\n'), text('Test 7')),\n            ),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('USA'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Test 8'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('USA'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Test 9'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Test 10'), text(' and '), text('Test 11')),\n            ),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Germany'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Brazil'))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(\n                BLOCKS.PARAGRAPH,\n                {},\n                inline(\n                  INLINES.HYPERLINK,\n                  { data: { uri: 'https://example.com' } },\n                  text('Test 12', mark(MARKS.BOLD)),\n                ),\n              ),\n            ),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('USA'))),\n          ),\n        ),\n        // Tables with marks\n        block(BLOCKS.HEADING_2, {}, text('Tables with marks')),\n        block(\n          BLOCKS.TABLE,\n          {},\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Bold Header 1', mark(MARKS.BOLD))),\n            ),\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Bold Header 2', mark(MARKS.BOLD))),\n            ),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Italic', mark(MARKS.ITALIC))),\n            ),\n            block(\n              BLOCKS.TABLE_CELL,\n              {},\n              block(BLOCKS.PARAGRAPH, {}, text('Code', mark(MARKS.CODE))),\n            ),\n          ),\n        ),\n        // Tables without body\n        block(BLOCKS.HEADING_2, {}, text('Tables without body')),\n        block(\n          BLOCKS.TABLE,\n          {},\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('abc'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('def'))),\n          ),\n        ),\n        // Tables with empty cells\n        block(BLOCKS.HEADING_2, {}, text('Table with empty cells')),\n        block(\n          BLOCKS.TABLE,\n          {},\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Cell 1'))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n          ),\n          block(\n            BLOCKS.TABLE_ROW,\n            {},\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text(''))),\n            block(BLOCKS.TABLE_CELL, {}, block(BLOCKS.PARAGRAPH, {}, text('Cell 2'))),\n          ),\n        ),\n      ),\n    );\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/index.ts",
    "content": "import {\n  BLOCKS,\n  Block,\n  Document,\n  Hyperlink,\n  INLINES,\n  Inline,\n  Node,\n  Text,\n  TopLevelBlock,\n} from '@contentful/rich-text-types';\nimport _ from 'lodash';\nimport gfm from 'remark-gfm';\nimport markdown from 'remark-parse';\nimport unified from 'unified';\n\nimport { MarkdownLinkNode, MarkdownNode, MarkdownTree } from './types';\n\nconst markdownNodeTypes = new Map<string, string>([\n  ['paragraph', BLOCKS.PARAGRAPH],\n  ['heading', 'heading'],\n  ['text', 'text'],\n  ['emphasis', 'text'],\n  ['strong', 'text'],\n  ['delete', 'text'],\n  ['inlineCode', 'text'],\n  ['link', INLINES.HYPERLINK],\n  ['thematicBreak', BLOCKS.HR],\n  ['blockquote', BLOCKS.QUOTE],\n  ['list', 'list'],\n  ['listItem', BLOCKS.LIST_ITEM],\n  ['table', BLOCKS.TABLE],\n  ['tableRow', BLOCKS.TABLE_ROW],\n  ['tableCell', BLOCKS.TABLE_CELL],\n]);\n\nconst nodeTypeFor = (node: MarkdownNode) => {\n  const nodeType = markdownNodeTypes.get(node.type);\n\n  switch (nodeType) {\n    case 'heading':\n      return `${nodeType}-${node.depth}`;\n    case 'list':\n      return `${node.ordered ? 'ordered' : 'unordered'}-list`;\n    default:\n      return nodeType;\n  }\n};\n\nconst markTypes = new Map([\n  ['emphasis', 'italic'],\n  ['strong', 'bold'],\n  ['inlineCode', 'code'],\n  ['delete', 'strikethrough'],\n]);\nconst markTypeFor = (node: MarkdownNode) => {\n  return markTypes.get(node.type);\n};\n\nconst isLink = (node: MarkdownNode): node is MarkdownLinkNode => {\n  return node.type === 'link';\n};\n\nconst nodeContainerTypes = new Map([\n  ['delete', 'block'],\n  [BLOCKS.HEADING_1, 'block'],\n  [BLOCKS.HEADING_2, 'block'],\n  [BLOCKS.HEADING_3, 'block'],\n  [BLOCKS.HEADING_4, 'block'],\n  [BLOCKS.HEADING_5, 'block'],\n  [BLOCKS.HEADING_6, 'block'],\n  [BLOCKS.LIST_ITEM, 'block'],\n  [BLOCKS.UL_LIST, 'block'],\n  [BLOCKS.OL_LIST, 'block'],\n  [BLOCKS.QUOTE, 'block'],\n  [BLOCKS.HR, 'block'],\n  [BLOCKS.PARAGRAPH, 'block'],\n  [BLOCKS.TABLE, 'block'],\n  [BLOCKS.TABLE_CELL, 'block'],\n  [BLOCKS.TABLE_HEADER_CELL, 'block'],\n  [BLOCKS.TABLE_ROW, 'block'],\n  [INLINES.HYPERLINK, 'inline'],\n  ['text', 'text'],\n  ['emphasis', 'text'],\n  ['strong', 'text'],\n  ['inlineCode', 'text'],\n  ['delete', 'text'],\n]);\n\nconst isBlock = (nodeType: string) => {\n  return nodeContainerTypes.get(nodeType) === 'block';\n};\n\nconst isText = (nodeType: string) => {\n  return nodeContainerTypes.get(nodeType) === 'text';\n};\n\nconst isInline = (nodeType: string) => {\n  return nodeContainerTypes.get(nodeType) === 'inline';\n};\n\nconst isTableCell = (nodeType: string) => {\n  return nodeType === BLOCKS.TABLE_CELL;\n};\n\nconst buildHyperlink = async (\n  node: MarkdownLinkNode,\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[],\n): Promise<Hyperlink[]> => {\n  const content = (await mdToRichTextNodes(node.children, fallback, appliedMarksTypes)) as Text[];\n\n  const hyperlink: Hyperlink = {\n    nodeType: INLINES.HYPERLINK,\n    data: { uri: node.url },\n    content,\n  };\n\n  return [hyperlink];\n};\n\nconst buildGenericBlockOrInline = async (\n  node: MarkdownNode,\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[],\n): Promise<Array<Block | Inline>> => {\n  const nodeType = nodeTypeFor(node);\n  const content = await mdToRichTextNodes(node.children, fallback, appliedMarksTypes);\n\n  return [\n    {\n      nodeType: nodeType,\n      content,\n      data: {},\n    } as Block | Inline,\n  ];\n};\n\nconst buildTableCell = async (\n  node: MarkdownNode,\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[],\n): Promise<Array<Block>> => {\n  const nodeChildren = await mdToRichTextNodes(node.children, fallback, appliedMarksTypes);\n\n  const content = nodeChildren.reduce((result, contentNode) => {\n    if (isText(contentNode.nodeType) || isInline(contentNode.nodeType)) {\n      const lastNode = result[result.length - 1];\n      if (lastNode && lastNode.nodeType === BLOCKS.PARAGRAPH) {\n        lastNode.content.push(contentNode);\n      } else {\n        result.push({ nodeType: BLOCKS.PARAGRAPH, data: {}, content: [contentNode] });\n      }\n    } else {\n      result.push(contentNode);\n    }\n\n    return result;\n  }, []);\n\n  // A table cell can't be empty\n  if (content.length === 0) {\n    content.push({\n      nodeType: BLOCKS.PARAGRAPH,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          data: {},\n          marks: [],\n          value: '',\n        } as Text,\n      ],\n    });\n  }\n\n  /**\n   * We should only support texts inside table cells.\n   * Some markdowns might contain html inside tables such as <ul>, <blockquote>, etc\n   * but they are pretty much filtered out by markdownNodeTypes and nodeContainerTypes variables.\n   * so we ended up receiving only `text` nodes.\n   * We can't have table cells with text nodes directly, we must wrap text nodes inside paragraphs.\n   */\n  return [\n    {\n      nodeType: BLOCKS.TABLE_CELL,\n      content,\n      data: {},\n    } as Block,\n  ];\n};\n\nconst buildText = async (\n  node: MarkdownNode,\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[],\n): Promise<Array<Inline | Text>> => {\n  const nodeType = nodeTypeFor(node);\n  const markType = markTypeFor(node);\n  const marks = Array.from(appliedMarksTypes);\n  if (markType) {\n    marks.push(markType);\n  }\n\n  if (node.type !== 'text' && node.children) {\n    return (await mdToRichTextNodes(node.children, fallback, marks)) as Array<Inline | Text>;\n  }\n\n  if (node.value) {\n    return [\n      {\n        nodeType: nodeType,\n        value: node.value,\n        marks: marks.map((type) => ({ type })),\n        data: {},\n      } as Text,\n    ];\n  }\n};\n\nconst buildFallbackNode = async (\n  node: MarkdownNode,\n  fallback: FallbackResolver,\n): Promise<Node[]> => {\n  const fallbackResult = await fallback(node);\n\n  if (_.isArray(fallbackResult)) {\n    return fallbackResult;\n  }\n  return [fallbackResult];\n};\n\nasync function mdToRichTextNode(\n  node: MarkdownNode,\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[] = [],\n): Promise<Node[]> {\n  // By default <br/> is parsed as html node, causing it to be stripped out.\n  // We need to convert it manually in order to support it\n  if (node.type === 'html' && /<br\\s?\\/?>/gi.test(node.value)) {\n    node.value = '\\n';\n    node.type = 'text';\n  }\n\n  const nodeType = nodeTypeFor(node);\n\n  if (isLink(node)) {\n    return await buildHyperlink(node, fallback, appliedMarksTypes);\n  }\n\n  if (isTableCell(nodeType)) {\n    return await buildTableCell(node, fallback, appliedMarksTypes);\n  }\n\n  if (isBlock(nodeType) || isInline(nodeType)) {\n    return await buildGenericBlockOrInline(node, fallback, appliedMarksTypes);\n  }\n\n  if (isText(nodeType)) {\n    return await buildText(node, fallback, appliedMarksTypes);\n  }\n\n  return await buildFallbackNode(node, fallback);\n}\n\nasync function mdToRichTextNodes(\n  nodes: MarkdownNode[],\n  fallback: FallbackResolver,\n  appliedMarksTypes: string[] = [],\n): Promise<Node[]> {\n  if (!nodes) {\n    return Promise.resolve([]);\n  }\n  const rtNodes = await Promise.all(\n    nodes.map((node) => mdToRichTextNode(node, fallback, appliedMarksTypes)),\n  );\n\n  return _.flatten(rtNodes).filter(Boolean);\n}\n\nconst astToRichTextDocument = async (\n  tree: MarkdownTree,\n  fallback: FallbackResolver,\n): Promise<Document> => {\n  const content = await mdToRichTextNodes(tree.children, fallback);\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: content as TopLevelBlock[],\n  };\n};\n\nfunction expandParagraphWithInlineImages(node: MarkdownNode): MarkdownNode[] {\n  if (node.type !== 'paragraph') {\n    return [node];\n  }\n\n  const imageNodeIndices = [];\n  for (let i = 0; i < node.children.length; i++) {\n    if (node.children[i].type === 'image') {\n      imageNodeIndices.push(i);\n    }\n  }\n\n  if (imageNodeIndices.length === 0) {\n    // If no images in children, return.\n    return [node];\n  }\n  const allNodes: MarkdownNode[] = [];\n  let lastIndex = -1;\n  for (let j = 0; j < imageNodeIndices.length; j++) {\n    const index = imageNodeIndices[j];\n    // before\n    if (index !== 0) {\n      const nodesBefore: MarkdownNode[] = node.children.slice(lastIndex + 1, index);\n\n      if (nodesBefore.length > 0) {\n        allNodes.push({\n          ...node,\n          children: nodesBefore,\n        });\n      }\n    }\n    // image\n    const imageNode = node.children[index];\n    allNodes.push(imageNode);\n\n    // till end\n    let nodesAfter: MarkdownNode[] = [];\n    const rangeEnd =\n      j + 1 < imageNodeIndices.length ? imageNodeIndices[j + 1] : node.children.length;\n    if (index + 1 < rangeEnd && index === imageNodeIndices.slice(-1)[0]) {\n      nodesAfter = node.children.slice(index + 1, rangeEnd);\n\n      if (nodesAfter.length > 0) {\n        allNodes.push({\n          ...node,\n          children: nodesAfter,\n        });\n      }\n    }\n    lastIndex = index;\n  }\n  return allNodes;\n}\n\n// Inline markdown images come in as nested within a MarkdownNode paragraph\n// so we must hoist them out before transforming to rich text.\nfunction prepareMdAST(ast: MarkdownTree): MarkdownNode {\n  function prepareASTNodeChildren(node: MarkdownNode): MarkdownNode {\n    if (!node.children) {\n      return node;\n    }\n\n    const children = _.flatMap(node.children, (n) => expandParagraphWithInlineImages(n)).map((n) =>\n      prepareASTNodeChildren(n),\n    );\n\n    return { ...node, children };\n  }\n\n  return prepareASTNodeChildren({\n    depth: '0',\n    type: 'root',\n    value: '',\n    ordered: true,\n    children: ast.children,\n  });\n}\n\n// COMPAT: can resolve with either Node or an array of Nodes for back compatibility.\nexport type FallbackResolver = (mdNode: MarkdownNode) => Promise<Node | Node[] | null>;\n\nexport async function richTextFromMarkdown(\n  md: string,\n  fallback: FallbackResolver = () => Promise.resolve(null),\n): Promise<Document> {\n  const processor = unified().use(markdown).use(gfm);\n  const tree = processor.parse(md);\n  // @ts-expect-error children is missing in the return type of processor.parse\n  const ast = prepareMdAST(tree);\n  return await astToRichTextDocument(ast, fallback);\n}\n"
  },
  {
    "path": "packages/rich-text-from-markdown/src/types/index.ts",
    "content": "export interface MarkdownNode extends MarkdownTree {\n  depth: string;\n  type: string;\n  ordered: boolean;\n  value: string;\n}\n\nexport interface MarkdownTree {\n  children: MarkdownNode[];\n}\n\nexport interface MarkdownLinkNode extends MarkdownNode {\n  url: string;\n}\n"
  },
  {
    "path": "packages/rich-text-from-markdown/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist/lib\",\n    \"strict\": false,\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/types\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [17.2.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.2.1...@contentful/rich-text-html-renderer@17.2.2) (2026-04-09)\n\n### Bug Fixes\n\n- **rich-text-types:** improve esm compability [ZEND-7778] ([#1073](https://github.com/contentful/rich-text/issues/1073)) ([204aaec](https://github.com/contentful/rich-text/commit/204aaecc3893633c081986f44896e14272fa376a))\n\n## [17.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.2.0...@contentful/rich-text-html-renderer@17.2.1) (2026-04-08)\n\n### Bug Fixes\n\n- **rich-text-html-renderer:** parse and render asset [] ([#854](https://github.com/contentful/rich-text/issues/854)) ([3ca028d](https://github.com/contentful/rich-text/commit/3ca028d828979a22cb208607371ffec8990d01b7)), closes [#853](https://github.com/contentful/rich-text/issues/853)\n\n# [17.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.6...@contentful/rich-text-html-renderer@17.2.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [17.1.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.5...@contentful/rich-text-html-renderer@17.1.6) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [17.1.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.4...@contentful/rich-text-html-renderer@17.1.5) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [17.1.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.3...@contentful/rich-text-html-renderer@17.1.4) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [17.1.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.2...@contentful/rich-text-html-renderer@17.1.3) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [17.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.1...@contentful/rich-text-html-renderer@17.1.2) (2025-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [17.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.1.0...@contentful/rich-text-html-renderer@17.1.1) (2025-09-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [17.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.0.1...@contentful/rich-text-html-renderer@17.1.0) (2025-07-15)\n\n### Features\n\n- add an option to strip empty trailing paragraphs [TOL-3193] ([#892](https://github.com/contentful/rich-text/issues/892)) ([9beff0e](https://github.com/contentful/rich-text/commit/9beff0e4cba3e79dc68e6a0725e843c5d642eb87))\n\n## [17.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@17.0.0...@contentful/rich-text-html-renderer@17.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [17.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.10...@contentful/rich-text-html-renderer@17.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [16.6.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.9...@contentful/rich-text-html-renderer@16.6.10) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.8...@contentful/rich-text-html-renderer@16.6.9) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.7...@contentful/rich-text-html-renderer@16.6.8) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.6...@contentful/rich-text-html-renderer@16.6.7) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.5...@contentful/rich-text-html-renderer@16.6.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.4...@contentful/rich-text-html-renderer@16.6.5) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.3...@contentful/rich-text-html-renderer@16.6.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.2...@contentful/rich-text-html-renderer@16.6.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.1...@contentful/rich-text-html-renderer@16.6.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.6.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.6.0...@contentful/rich-text-html-renderer@16.6.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [16.6.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.5...@contentful/rich-text-html-renderer@16.6.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [16.5.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.4...@contentful/rich-text-html-renderer@16.5.5) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.5.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.3...@contentful/rich-text-html-renderer@16.5.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.5.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.2...@contentful/rich-text-html-renderer@16.5.3) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.5.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.1...@contentful/rich-text-html-renderer@16.5.2) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.5.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.5.0...@contentful/rich-text-html-renderer@16.5.1) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [16.5.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.4.0...@contentful/rich-text-html-renderer@16.5.0) (2024-05-24)\n\n### Features\n\n- add strikethrough support ([#562](https://github.com/contentful/rich-text/issues/562)) ([b87d0c3](https://github.com/contentful/rich-text/commit/b87d0c31bccb4012745c0479b2b5c92fc28c1e91))\n\n# [16.4.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.5...@contentful/rich-text-html-renderer@16.4.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [16.3.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.4...@contentful/rich-text-html-renderer@16.3.5) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.3.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.3...@contentful/rich-text-html-renderer@16.3.4) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.3.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.2...@contentful/rich-text-html-renderer@16.3.3) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.3.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.1...@contentful/rich-text-html-renderer@16.3.2) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.3.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.3.0...@contentful/rich-text-html-renderer@16.3.1) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [16.3.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.2.0...@contentful/rich-text-html-renderer@16.3.0) (2023-10-24)\n\n### Features\n\n- add default renderers for new resource nodes ([#504](https://github.com/contentful/rich-text/issues/504)) ([f748e6b](https://github.com/contentful/rich-text/commit/f748e6b0f0e22ce3809ca8881438b84b1baafb8f))\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.1.2...@contentful/rich-text-html-renderer@16.2.0) (2023-10-02)\n\n### Features\n\n- preserve formatting linebreak whitespace ([#497](https://github.com/contentful/rich-text/issues/497)) ([e62ab92](https://github.com/contentful/rich-text/commit/e62ab92f6320d970f921e751d1753cd290224224))\n\n## [16.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.1.1...@contentful/rich-text-html-renderer@16.1.2) (2023-09-12)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.1.0...@contentful/rich-text-html-renderer@16.1.1) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.5...@contentful/rich-text-html-renderer@16.1.0) (2023-06-09)\n\n### Features\n\n- add default renderer for the node ([#472](https://github.com/contentful/rich-text/issues/472)) ([5a53caf](https://github.com/contentful/rich-text/commit/5a53cafc58aa8d009d2aa2d6cb4fa2d6cee6b19d))\n\n## [16.0.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.4...@contentful/rich-text-html-renderer@16.0.5) (2023-05-26)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.0.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.3...@contentful/rich-text-html-renderer@16.0.4) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.0.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.2...@contentful/rich-text-html-renderer@16.0.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.1...@contentful/rich-text-html-renderer@16.0.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-html-renderer@16.0.0...@contentful/rich-text-html-renderer@16.0.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# 16.0.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- update Lerna, rollup in slatejs-adapter ([#366](https://github.com/contentful/rich-text/issues/366)) ([32448e3](https://github.com/contentful/rich-text/commit/32448e369ae2b76601dd81839e13c15432430d68))\n\n## 15.13.1 (2022-05-10)\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## 15.9.1 (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# 15.9.0 (2021-12-09)\n\n# 15.8.0 (2021-11-11)\n\n### Features\n\n- add toContentfulDocument() and toSlatejsDocument() empty block node handling ([#287](https://github.com/contentful/rich-text/issues/287)) ([fa79626](https://github.com/contentful/rich-text/commit/fa79626e4020d9640a920ca5d0ccb654e89cfa90))\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n## 15.5.1 (2021-10-25)\n\n# 15.5.0 (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n# 15.4.0 (2021-09-16)\n\n### Features\n\n- **html+react:** render Table header as <th> ([#269](https://github.com/contentful/rich-text/issues/269)) ([0f82905](https://github.com/contentful/rich-text/commit/0f829059be6d91e042dfc71698009177ae4ab78d))\n\n## 15.3.6 (2021-09-15)\n\n## 15.3.5 (2021-09-13)\n\n## 15.3.4 (2021-09-09)\n\n### Bug Fixes\n\n- replace import to fix typings for html-renderer ([#265](https://github.com/contentful/rich-text/issues/265)) ([40c2670](https://github.com/contentful/rich-text/commit/40c267069b18454517b0f4283a7e155cffa410b6))\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.2.0 (2021-08-16)\n\n# 15.1.0 (2021-08-02)\n\n### Bug Fixes\n\n- 🐛 html encode default inlined CF entry/asset links ([41396eb](https://github.com/contentful/rich-text/commit/41396eb800f6d5c65c634c4394a6c60cf3425255))\n- 🐛 prevent html injection via `data.uri` link rendering ([ecae89a](https://github.com/contentful/rich-text/commit/ecae89ad0d25175f342833ca989928670c24b8fd))\n\n### Features\n\n- 🎸 add RT html renderer tables support ([ce81375](https://github.com/contentful/rich-text/commit/ce8137577b269c62727dc64b7d47b4951597dbd6))\n\n# 15.0.0 (2021-06-15)\n\n## 14.1.2 (2020-11-02)\n\n## 14.0.1 (2020-01-30)\n\n# 14.0.0 (2020-01-28)\n\n# 13.4.0 (2019-08-01)\n\n# 13.1.0 (2019-03-04)\n\n# 13.0.0 (2019-01-22)\n\n## 12.2.1 (2019-01-22)\n\n### Bug Fixes\n\n- gracefully handle empty rich text documents ([14870de](https://github.com/contentful/rich-text/commit/14870ded471f69cee84a60739bee06873ed53af9))\n\n## 12.1.2 (2018-12-14)\n\n### Features\n\n- add html escaping ([4b55331](https://github.com/contentful/rich-text/commit/4b55331e86bc62787420f8081228293f1a22e1b7))\n\n# 12.1.0 (2018-12-12)\n\n## 12.0.3 (2018-12-05)\n\n### Bug Fixes\n\n- **readme:** mark types in readme examples ([d997b56](https://github.com/contentful/rich-text/commit/d997b56f2b8c32b2e5b478ab5444757203e2c703))\n\n## 12.0.2 (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 update path to typings ([ce5544f](https://github.com/contentful/rich-text/commit/ce5544f58712dc6a18aadda523d0c0357a66c8a5))\n\n## 12.0.1 (2018-12-04)\n\n# 12.0.0 (2018-11-29)\n\n# 11.0.0 (2018-11-27)\n\n# 10.3.0 (2018-11-26)\n\n# 10.2.0 (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# 10.1.0 (2018-11-16)\n\n## 10.0.1 (2018-11-08)\n\n# 10.0.0 (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## 9.0.2 (2018-10-31)\n\n# 9.0.0 (2018-10-30)\n\n### Features\n\n- 🎸 Explicitly declare nodeClass and nodeType in core types ([0749c61](https://github.com/contentful/rich-text/commit/0749c6199bb2681509608539c76bd8149cade564))\n\n### BREAKING CHANGES\n\n- Potentially breaks TypeScript libraries pulling this in as a dependency\n  if they are not explicitly stating nodeClass and nodeType.\n\n## 8.0.3 (2018-10-30)\n\n## 8.0.2 (2018-10-29)\n\n## 8.0.1 (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 Revert mock hypenation commits ([bde9432](https://github.com/contentful/rich-text/commit/bde94323fcc02bf5ab3feeef46a9d8fc8b08d59b))\n- sync HTML renderer ([769bd95](https://github.com/contentful/rich-text/commit/769bd95add1aecad0e11fab377f99c5cdad99072))\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- update Lerna, rollup in slatejs-adapter ([#366](https://github.com/contentful/rich-text/issues/366)) ([32448e3](https://github.com/contentful/rich-text/commit/32448e369ae2b76601dd81839e13c15432430d68))\n\n## [15.13.1](https://github.com/contentful/rich-text/compare/v15.13.0...v15.13.1) (2022-05-10)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.8.0](https://github.com/contentful/rich-text/compare/v15.7.0...v15.8.0) (2021-11-11)\n\n### Features\n\n- add toContentfulDocument() and toSlatejsDocument() empty block node handling ([#287](https://github.com/contentful/rich-text/issues/287)) ([fa79626](https://github.com/contentful/rich-text/commit/fa79626e4020d9640a920ca5d0ccb654e89cfa90))\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n# [15.4.0](https://github.com/contentful/rich-text/compare/v15.3.6...v15.4.0) (2021-09-16)\n\n### Features\n\n- **html+react:** render Table header as <th> ([#269](https://github.com/contentful/rich-text/issues/269)) ([0f82905](https://github.com/contentful/rich-text/commit/0f829059be6d91e042dfc71698009177ae4ab78d))\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.3.4](https://github.com/contentful/rich-text/compare/v15.3.3...v15.3.4) (2021-09-09)\n\n### Bug Fixes\n\n- replace import to fix typings for html-renderer ([#265](https://github.com/contentful/rich-text/issues/265)) ([40c2670](https://github.com/contentful/rich-text/commit/40c267069b18454517b0f4283a7e155cffa410b6))\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/rich-text-html-renderer\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.1.0...v15.2.0) (2021-08-16)\n\n### Bug Fixes\n\n- 🐛 html encode default inlined CF entry/asset links ([41396eb](https://github.com/contentful/rich-text/commit/41396eb800f6d5c65c634c4394a6c60cf3425255))\n- 🐛 prevent html injection via `data.uri` link rendering ([ecae89a](https://github.com/contentful/rich-text/commit/ecae89ad0d25175f342833ca989928670c24b8fd))\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n### Features\n\n- 🎸 add RT html renderer tables support ([ce81375](https://github.com/contentful/rich-text/commit/ce8137577b269c62727dc64b7d47b4951597dbd6))\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n## [12.2.1](https://github.com/contentful/rich-text/compare/v12.2.0...v12.2.1) (2019-01-22)\n\n### Bug Fixes\n\n- gracefully handle empty rich text documents ([14870de](https://github.com/contentful/rich-text/commit/14870ded471f69cee84a60739bee06873ed53af9))\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n### Features\n\n- add html escaping ([4b55331](https://github.com/contentful/rich-text/commit/4b55331e86bc62787420f8081228293f1a22e1b7))\n\n# [12.1.0](https://github.com/contentful/rich-text/compare/v12.0.4...v12.1.0) (2018-12-12)\n\n## [12.0.3](https://github.com/contentful/rich-text/compare/v12.0.2...v12.0.3) (2018-12-05)\n\n### Bug Fixes\n\n- **readme:** mark types in readme examples ([d997b56](https://github.com/contentful/rich-text/commit/d997b56f2b8c32b2e5b478ab5444757203e2c703))\n\n## [12.0.2](https://github.com/contentful/rich-text/compare/v12.0.1...v12.0.2) (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 update path to typings ([ce5544f](https://github.com/contentful/rich-text/commit/ce5544f58712dc6a18aadda523d0c0357a66c8a5))\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# [10.1.0](https://github.com/contentful/rich-text/compare/v10.0.5...v10.1.0) (2018-11-16)\n\n## [10.0.1](https://github.com/contentful/rich-text/compare/v10.0.0...v10.0.1) (2018-11-08)\n\n# [10.0.0](https://github.com/contentful/rich-text/compare/v9.0.2...v10.0.0) (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## [9.0.2](https://github.com/contentful/rich-text/compare/v9.0.1...v9.0.2) (2018-10-31)\n\n# [9.0.0](https://github.com/contentful/rich-text/compare/v8.0.3...v9.0.0) (2018-10-30)\n\n### Features\n\n- 🎸 Explicitly declare nodeClass and nodeType in core types ([0749c61](https://github.com/contentful/rich-text/commit/0749c6199bb2681509608539c76bd8149cade564))\n\n### BREAKING CHANGES\n\n- Potentially breaks TypeScript libraries pulling this in as a dependency\n  if they are not explicitly stating nodeClass and nodeType.\n\n## [8.0.3](https://github.com/contentful/rich-text/compare/v8.0.2...v8.0.3) (2018-10-30)\n\n## [8.0.2](https://github.com/contentful/rich-text/compare/v8.0.1...v8.0.2) (2018-10-29)\n\n## [8.0.1](https://github.com/contentful/rich-text/compare/v8.0.0...v8.0.1) (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 Revert mock hypenation commits ([bde9432](https://github.com/contentful/rich-text/commit/bde94323fcc02bf5ab3feeef46a9d8fc8b08d59b))\n- sync HTML renderer ([769bd95](https://github.com/contentful/rich-text/commit/769bd95add1aecad0e11fab377f99c5cdad99072))\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n"
  },
  {
    "path": "packages/rich-text-html-renderer/README.md",
    "content": "# rich-text-html-renderer\n\nHTML renderer for the Contentful rich text field type.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/rich-text-html-renderer\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/rich-text-html-renderer\n```\n\n## Usage\n\n```javascript\nimport { documentToHtmlString } from '@contentful/rich-text-html-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [],\n        },\n      ],\n    },\n  ],\n};\n\ndocumentToHtmlString(document); // -> <p>Hello world!</p>\n```\n\n```javascript\nimport { documentToHtmlString } from '@contentful/rich-text-html-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello',\n          marks: [{ type: 'bold' }],\n        },\n        {\n          nodeType: 'text',\n          value: ' world!',\n          marks: [{ type: 'italic' }],\n        },\n      ],\n    },\n  ],\n};\n\ndocumentToHtmlString(document); // -> <p><b>Hello</b><u> world!</u></p>\n```\n\nYou can also pass custom renderers for both marks and nodes as an optional parameter like so:\n\n```javascript\nimport { BLOCKS, MARKS } from '@contentful/rich-text-types';\nimport { documentToHtmlString } from '@contentful/rich-text-html-renderer';\n\nconst document = {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data:{},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello',\n          marks: [{ type: 'bold' }],\n          data: {}\n        },\n        {\n          nodeType: 'text',\n          value: ' world!',\n          marks: [{ type: 'italic' }]\n          data: {}\n        },\n      ],\n    },\n  ]\n};\n\nconst options = {\n  renderMark: {\n    [MARKS.BOLD]: text => `<custom-bold>${text}<custom-bold>`\n  },\n  renderNode: {\n    [BLOCKS.PARAGRAPH]: (node, next) => `<custom-paragraph>${next(node.content)}</custom-paragraph>`\n  }\n}\n\ndocumentToHtmlString(document, options);\n// -> <custom-paragraph><custom-bold>Hello</custom-bold><u> world!</u></custom-paragraph>\n```\n\nLast, but not least, you can pass a custom rendering component for an embedded entry:\n\n```javascript\nimport { BLOCKS } from '@contentful/rich-text-types';\nimport { documentToHtmlString } from '@contentful/rich-text-html-renderer';\n\nconst document = {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'embedded-entry-block',\n      data: {\n        target: (...)Link<'Entry'>(...);\n      },\n    },\n  ]\n};\n\nconst options = {\n  renderNode: {\n    [BLOCKS.EMBEDDED_ENTRY]: (node) => `<custom-component>${customComponentRenderer(node)}</custom-component>`\n  }\n}\n\ndocumentToHtmlString(document, options);\n// -> <custom-component>(...)Link<'Entry'>(...)</custom-component>\n```\n\nThe `renderNode` keys should be one of the following `BLOCKS` and `INLINES` properties as defined in [`@contentful/rich-text-types`](https://www.npmjs.com/package/@contentful/rich-text-types):\n\n- `BLOCKS`\n  - `DOCUMENT`\n  - `PARAGRAPH`\n  - `HEADING_1`\n  - `HEADING_2`\n  - `HEADING_3`\n  - `HEADING_4`\n  - `HEADING_5`\n  - `HEADING_6`\n  - `UL_LIST`\n  - `OL_LIST`\n  - `LIST_ITEM`\n  - `QUOTE`\n  - `HR`\n  - `EMBEDDED_ENTRY`\n  - `EMBEDDED_ASSET`\n  - `EMBEDDED_RESOURCE`\n\n- `INLINES`\n  - `EMBEDDED_ENTRY` (this is different from the `BLOCKS.EMBEDDED_ENTRY`)\n  - `EMBEDDED_RESOURCE`\n  - `HYPERLINK`\n  - `ENTRY_HYPERLINK`\n  - `ASSET_HYPERLINK`\n  - `RESOURCE_HYPERLINK`\n\nThe `renderMark` keys should be one of the following `MARKS` properties as defined in [`@contentful/rich-text-types`](https://www.npmjs.com/package/@contentful/rich-text-types):\n\n- `BOLD`\n- `ITALIC`\n- `UNDERLINE`\n- `CODE`\n- `SUPERSCRIPT`\n- `SUBSCRIPT`\n- `STRIKETHROUGH`\n\n#### Preserving Whitespace\n\nIn your HTML rendering options, you can utilize the `preserveWhitespace` boolean flag. When set to `true`, this flag ensures that spaces and line breaks in the Contentful rich text content are preserved in the rendered HTML. Specifically, it replaces consecutive spaces with `&nbsp;` entities and retains line breaks using `<br />` tags. This capability is particularly beneficial for content that has specific formatting requirements involving spaces and line breaks.\n\n```javascript\nimport { documentToHtmlString } from '@contentful/rich-text-html-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello     world!',\n          marks: [],\n        },\n      ],\n    },\n  ],\n};\n\nconst options = {\n  preserveWhitespace: true,\n};\n\ndocumentToHtmlString(document, options);\n// -> <p>Hello&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world!</p>\n```\n\nWith this configuration, the HTML output retains the spaces found between \"Hello\" and \"world!\".\n"
  },
  {
    "path": "packages/rich-text-html-renderer/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-html-renderer/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-html-renderer\",\n  \"version\": \"17.2.2\",\n  \"main\": \"dist/rich-text-html-renderer.es5.js\",\n  \"module\": \"dist/rich-text-html-renderer.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/rich-text-html-renderer.esm.js\",\n      \"require\": \"./dist/rich-text-html-renderer.es5.js\",\n      \"default\": \"./dist/rich-text-html-renderer.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"tsc --module commonjs && rollup -c --bundleConfigAsCjs rollup.config.js\",\n    \"start\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.js -w\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\"\n  },\n  \"devDependencies\": {\n    \"ts-jest\": \"^29.1.2\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/rollup.config.js",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nexport default config(outputFile, {\n  external: Object.keys(dependencies),\n});\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/embedded-entry.ts",
    "content": "import { BLOCKS, Document } from '@contentful/rich-text-types';\n\nexport default function (entry: Record<string, any>) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: BLOCKS.EMBEDDED_ENTRY,\n        content: [],\n        data: {\n          target: entry,\n        },\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/embedded-resource.ts",
    "content": "import { Document, BLOCKS, ResourceLink } from '@contentful/rich-text-types';\n\nexport default function (resourceLink: ResourceLink) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: BLOCKS.EMBEDDED_RESOURCE,\n        content: [],\n        data: {\n          target: resourceLink,\n        },\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/heading.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default function (heading: string) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: heading,\n        data: {},\n        content: [\n          {\n            nodeType: 'text',\n            value: 'hello world',\n            marks: [],\n            data: {},\n          },\n        ],\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/hr.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  content: [\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: 'hello world',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'paragraph',\n    },\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: '',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'hr',\n    },\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: '',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'paragraph',\n    },\n  ],\n  data: {},\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/hyperlink.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Some text ',\n          marks: [],\n          data: {},\n        },\n        {\n          nodeType: 'hyperlink',\n          content: [\n            {\n              nodeType: 'text',\n              value: 'link',\n              marks: [],\n              data: {},\n            },\n          ],\n          data: {\n            uri: 'https://url.org',\n          },\n        },\n        {\n          nodeType: 'text',\n          value: ' text.',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/index.ts",
    "content": "export { default as hrDoc } from './hr';\nexport { default as hyperlinkDoc } from './hyperlink';\nexport { default as invalidMarksDoc } from './invalid-marks';\nexport { default as invalidTypeDoc } from './invalid-type';\nexport { default as paragraphDoc } from './paragraph';\nexport { default as headingDoc } from './heading';\nexport { default as marksDoc } from './mark';\nexport { default as embeddedEntryDoc } from './embedded-entry';\nexport { default as embeddedResourceDoc } from './embedded-resource';\nexport { default as olDoc } from './ol';\nexport { default as ulDoc } from './ul';\nexport { default as quoteDoc } from './quote';\nexport { default as tableDoc } from './table';\nexport { default as tableWithHeaderDoc } from './table-header';\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/inline-entity.ts",
    "content": "import { BLOCKS, Document, INLINES } from '@contentful/rich-text-types';\n\nexport default function inlineEntity(entry: Record<string, any>, inlineType: INLINES) {\n  return {\n    content: [\n      {\n        data: {},\n        content: [\n          {\n            marks: [],\n            value: '',\n            nodeType: 'text',\n            data: {},\n          },\n          {\n            data: entry,\n            content: [\n              {\n                marks: [],\n                value: '',\n                nodeType: 'text',\n                data: {},\n              },\n            ],\n            nodeType: inlineType,\n          },\n          {\n            marks: [],\n            value: '',\n            nodeType: 'text',\n            data: {},\n          },\n        ],\n        nodeType: BLOCKS.PARAGRAPH,\n      },\n    ],\n    data: {},\n    nodeType: BLOCKS.DOCUMENT,\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/invalid-marks.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [\n            {\n              type: 'UNRECOGNIZED_MARK',\n            },\n          ],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/invalid-type.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: 'UNRECOGNIZED_TYPE' as BLOCKS,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/mark.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default function (mark: string) {\n  return {\n    nodeType: 'document',\n    data: {},\n    content: [\n      {\n        nodeType: 'paragraph',\n        data: {},\n        content: [\n          {\n            nodeType: 'text',\n            value: 'hello world',\n            marks: [{ type: mark }],\n            data: {},\n          },\n        ],\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/ol.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'Hello',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'world',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n      ],\n      nodeType: 'ordered-list',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: '',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/paragraph.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'hello world',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/quote.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: 'hello',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: 'world',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'blockquote',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/table-header.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.TABLE,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_HEADER_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 1',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_HEADER_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 1',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 2',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 2',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/table.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.TABLE,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 1',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 1',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 2',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 2',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/documents/ul.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'Hello',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'world',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n      ],\n      nodeType: 'unordered-list',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: '',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/__test__/index.test.ts",
    "content": "import { Block, BLOCKS, Document, INLINES, MARKS, ResourceLink } from '@contentful/rich-text-types';\nimport cloneDeep from 'lodash/cloneDeep';\n\nimport { documentToHtmlString, Options } from '../index';\nimport {\n  embeddedEntryDoc,\n  headingDoc,\n  hrDoc,\n  hyperlinkDoc,\n  invalidMarksDoc,\n  invalidTypeDoc,\n  marksDoc,\n  olDoc,\n  paragraphDoc,\n  tableDoc,\n  quoteDoc,\n  ulDoc,\n  tableWithHeaderDoc,\n  embeddedResourceDoc,\n} from './documents';\nimport inlineEntity from './documents/inline-entity';\n\ndescribe('documentToHtmlString', () => {\n  it('returns empty string when given an empty document', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [],\n    };\n\n    expect(documentToHtmlString(document)).toEqual('');\n  });\n\n  it('renders nodes with default node renderer', () => {\n    const docs: Array<{ doc: Document; expected: string }> = [\n      {\n        doc: paragraphDoc,\n        expected: '<p>hello world</p>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_1),\n        expected: '<h1>hello world</h1>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_2),\n        expected: '<h2>hello world</h2>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_3),\n        expected: '<h3>hello world</h3>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_4),\n        expected: '<h4>hello world</h4>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_5),\n        expected: '<h5>hello world</h5>',\n      },\n      {\n        doc: headingDoc(BLOCKS.HEADING_6),\n        expected: '<h6>hello world</h6>',\n      },\n    ];\n\n    docs.forEach(({ doc, expected }) => {\n      expect(documentToHtmlString(doc)).toEqual(expected);\n    });\n  });\n\n  it('renders marks with default mark renderer', () => {\n    const docs: Array<{ doc: Document; expected: string }> = [\n      {\n        doc: marksDoc(MARKS.ITALIC),\n        expected: '<p><i>hello world</i></p>',\n      },\n      {\n        doc: marksDoc(MARKS.BOLD),\n        expected: '<p><b>hello world</b></p>',\n      },\n      {\n        doc: marksDoc(MARKS.UNDERLINE),\n        expected: '<p><u>hello world</u></p>',\n      },\n      {\n        doc: marksDoc(MARKS.CODE),\n        expected: '<p><code>hello world</code></p>',\n      },\n      {\n        doc: marksDoc(MARKS.SUPERSCRIPT),\n        expected: '<p><sup>hello world</sup></p>',\n      },\n      {\n        doc: marksDoc(MARKS.SUBSCRIPT),\n        expected: '<p><sub>hello world</sub></p>',\n      },\n      {\n        doc: marksDoc(MARKS.STRIKETHROUGH),\n        expected: '<p><s>hello world</s></p>',\n      },\n    ];\n\n    docs.forEach(({ doc, expected }) => {\n      expect(documentToHtmlString(doc)).toEqual(expected);\n    });\n  });\n\n  it('renders nodes with passed custom node renderer', () => {\n    const options: Options = {\n      renderNode: {\n        [BLOCKS.PARAGRAPH]: (node, next) => `<p>${next(node.content)}</p>`,\n      },\n    };\n    const document: Document = paragraphDoc;\n    const expected = `<p>hello world</p>`;\n\n    expect(documentToHtmlString(document, options)).toEqual(expected);\n  });\n\n  it('renders marks with the passed custom mark rendered', () => {\n    const options: Options = {\n      renderMark: {\n        [MARKS.UNDERLINE]: (text) => `<u>${text}</u>`,\n      },\n    };\n    const document: Document = marksDoc(MARKS.UNDERLINE);\n    const expected = '<p><u>hello world</u></p>';\n\n    expect(documentToHtmlString(document, options)).toEqual(expected);\n  });\n\n  it('renders escaped html', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'foo & bar',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    const expected = '<p>foo &amp; bar</p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders escaped html with marks', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'foo & bar',\n              marks: [{ type: MARKS.UNDERLINE }, { type: MARKS.BOLD }],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    const expected = '<p><b><u>foo &amp; bar</u></b></p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('does not render unrecognized marks', () => {\n    const document: Document = invalidMarksDoc;\n    const expected = '<p>Hello world!</p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders empty node if type is not recognized', () => {\n    const document: Document = invalidTypeDoc;\n    const expected = '';\n\n    expect(documentToHtmlString(document as Document)).toEqual(expected);\n  });\n\n  it('renders default entry link block', () => {\n    const entrySys = {\n      sys: {\n        id: '9mpxT4zsRi6Iwukey8KeM',\n        link: 'Link',\n        linkType: 'Entry',\n      },\n    };\n    const document: Document = embeddedEntryDoc(entrySys);\n    const expected = `<div></div>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders default resource link block', () => {\n    const resourceLink: ResourceLink = {\n      sys: {\n        urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n        type: 'ResourceLink',\n        linkType: 'Contentful:Entry',\n      },\n    };\n    const document: Document = embeddedResourceDoc(resourceLink);\n    const expected = `<div></div>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders ordered lists', () => {\n    const document: Document = olDoc;\n    const expected = `<ol><li><p>Hello</p></li><li><p>world</p></li></ol><p></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders unordered lists', () => {\n    const document: Document = ulDoc;\n    const expected = `<ul><li><p>Hello</p></li><li><p>world</p></li></ul><p></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders blockquotes', () => {\n    const document: Document = quoteDoc;\n    const expected = `<p>hello</p><blockquote>world</blockquote>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders horizontal rule', () => {\n    const document: Document = hrDoc;\n    const expected = '<p>hello world</p><hr/><p></p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders tables', () => {\n    const document: Document = tableDoc;\n    const expected =\n      '<table>' +\n      '<tr><td><p>A 1</p></td><td><p>B 1</p></td></tr>' +\n      '<tr><td><p>A 2</p></td><td><p>B 2</p></td></tr>' +\n      '</table>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders tables with header', () => {\n    const expected =\n      '<table>' +\n      '<tr><th><p>A 1</p></th><th><p>B 1</p></th></tr>' +\n      '<tr><td><p>A 2</p></td><td><p>B 2</p></td></tr>' +\n      '</table>';\n\n    expect(documentToHtmlString(tableWithHeaderDoc)).toEqual(expected);\n  });\n\n  it('does not crash with inline elements (e.g. hyperlink)', () => {\n    const document: Document = hyperlinkDoc;\n\n    expect(documentToHtmlString(document)).toBeTruthy();\n  });\n\n  it('renders hyperlink', () => {\n    const document: Document = hyperlinkDoc;\n    const expected = '<p>Some text <a href=\"https://url.org\">link</a> text.</p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders hyperlink without allowing html injection via `data.uri`', () => {\n    const document: Document = cloneDeep(hyperlinkDoc);\n    (document.content[0].content[1] as Block).data.uri = '\">no html injection!<a href=\"';\n    const expected =\n      '<p>Some text <a href=\"&quot;>no html injection!<a href=&quot;\">link</a> text.</p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders hyperlink without invalid non-string `data.uri` values', () => {\n    const document: Document = cloneDeep(hyperlinkDoc);\n    (document.content[0].content[1] as Block).data.uri = 42;\n    const expected = '<p>Some text <a href=\"\">link</a> text.</p>';\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it(`renders asset hyperlink`, () => {\n    const asset = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Asset',\n        },\n      },\n    };\n    const document: Document = inlineEntity(asset, INLINES.ASSET_HYPERLINK);\n    const expected = `<p><span>type: ${INLINES.ASSET_HYPERLINK} id: ${asset.target.sys.id}</span></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders entry hyperlink', () => {\n    const entry = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntity(entry, INLINES.ENTRY_HYPERLINK);\n    const expected = `<p><span>type: ${INLINES.ENTRY_HYPERLINK} id: ${entry.target.sys.id}</span></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders resource hyperlink', () => {\n    const entry = {\n      target: {\n        sys: {\n          urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n          type: 'ResourceLink',\n          linkType: 'Contentful:Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntity(entry, INLINES.RESOURCE_HYPERLINK);\n    const expected = `<p><span>type: ${INLINES.RESOURCE_HYPERLINK} urn: ${entry.target.sys.urn}</span></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders embedded entry', () => {\n    const entry = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntity(entry, INLINES.EMBEDDED_ENTRY);\n    const expected = `<p><span>type: ${INLINES.EMBEDDED_ENTRY} id: ${entry.target.sys.id}</span></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('renders embedded resource', () => {\n    const entry = {\n      target: {\n        sys: {\n          urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Contentful:Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntity(entry, INLINES.EMBEDDED_RESOURCE);\n    const expected = `<p><span>type: ${INLINES.EMBEDDED_RESOURCE} urn: ${entry.target.sys.urn}</span></p>`;\n\n    expect(documentToHtmlString(document)).toEqual(expected);\n  });\n\n  it('does not crash with empty documents', () => {\n    expect(documentToHtmlString({} as Document)).toEqual('');\n  });\n\n  it('does not crash with undefined documents', () => {\n    expect(documentToHtmlString(undefined as Document)).toEqual('');\n  });\n\n  it('preserves whitespace with preserveWhitespace option', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'hello    world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    const options: Options = {\n      preserveWhitespace: true,\n    };\n    const expected = '<p>hello&nbsp;&nbsp;&nbsp;&nbsp;world</p>';\n\n    expect(documentToHtmlString(document, options)).toEqual(expected);\n  });\n\n  it('preserves line breaks with preserveWhitespace option', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'hello\\nworld',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    const options: Options = {\n      preserveWhitespace: true,\n    };\n    const expected = '<p>hello<br/>world</p>';\n\n    expect(documentToHtmlString(document, options)).toEqual(expected);\n  });\n\n  it('preserves both spaces and line breaks with preserveWhitespace option', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'hello   \\n  world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    const options: Options = {\n      preserveWhitespace: true,\n    };\n    const expected = '<p>hello&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;world</p>';\n\n    expect(documentToHtmlString(document, options)).toEqual(expected);\n  });\n});\n\ndescribe('stripEmptyTrailingParagraph', () => {\n  it('strips empty trailing paragraph when enabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p>Hello world</p>');\n  });\n\n  it('does not strip empty trailing paragraph when disabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: false,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p>Hello world</p><p></p>');\n  });\n\n  it('does not strip empty trailing paragraph when it is the only child', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p></p>');\n  });\n\n  it('does not strip non-empty trailing paragraph', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Not empty',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p>Hello world</p><p>Not empty</p>');\n  });\n\n  it('does not strip trailing paragraph with multiple text nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p>Hello world</p><p></p>');\n  });\n\n  it('does not strip trailing non-paragraph node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.HEADING_1,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToHtmlString(document, options);\n    expect(result).toEqual('<p>Hello world</p><h1></h1>');\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/escapeHtml.ts",
    "content": "const escapeRegExp = /[\"'&<>]/g;\n\nconst escapeMap: Record<string, string> = {\n  '\"': '&quot;',\n  '&': '&amp;',\n  \"'\": '&#39;',\n  '<': '&lt;',\n  '>': '&gt;',\n};\n\nexport function escapeHtml(input: string): string {\n  return input.replace(escapeRegExp, (ch) => escapeMap[ch]);\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/src/index.ts",
    "content": "import {\n  BLOCKS,\n  Block,\n  Document,\n  INLINES,\n  Inline,\n  MARKS,\n  Mark,\n  Text,\n  helpers,\n} from '@contentful/rich-text-types';\n\nimport { escapeHtml } from './escapeHtml';\n\nconst attributeValue = (value: string) => `\"${value.replace(/\"/g, '&quot;')}\"`;\n\nconst defaultNodeRenderers: RenderNode = {\n  [BLOCKS.PARAGRAPH]: (node, next) => `<p>${next(node.content)}</p>`,\n  [BLOCKS.HEADING_1]: (node, next) => `<h1>${next(node.content)}</h1>`,\n  [BLOCKS.HEADING_2]: (node, next) => `<h2>${next(node.content)}</h2>`,\n  [BLOCKS.HEADING_3]: (node, next) => `<h3>${next(node.content)}</h3>`,\n  [BLOCKS.HEADING_4]: (node, next) => `<h4>${next(node.content)}</h4>`,\n  [BLOCKS.HEADING_5]: (node, next) => `<h5>${next(node.content)}</h5>`,\n  [BLOCKS.HEADING_6]: (node, next) => `<h6>${next(node.content)}</h6>`,\n  [BLOCKS.EMBEDDED_ENTRY]: (node, next) => `<div>${next(node.content)}</div>`,\n  [BLOCKS.EMBEDDED_RESOURCE]: (node, next) => `<div>${next(node.content)}</div>`,\n  [BLOCKS.EMBEDDED_ASSET]: (node) => defaultBlockAsset(node as Block),\n  [BLOCKS.UL_LIST]: (node, next) => `<ul>${next(node.content)}</ul>`,\n  [BLOCKS.OL_LIST]: (node, next) => `<ol>${next(node.content)}</ol>`,\n  [BLOCKS.LIST_ITEM]: (node, next) => `<li>${next(node.content)}</li>`,\n  [BLOCKS.QUOTE]: (node, next) => `<blockquote>${next(node.content)}</blockquote>`,\n  [BLOCKS.HR]: () => '<hr/>',\n  [BLOCKS.TABLE]: (node, next) => `<table>${next(node.content)}</table>`,\n  [BLOCKS.TABLE_ROW]: (node, next) => `<tr>${next(node.content)}</tr>`,\n  [BLOCKS.TABLE_HEADER_CELL]: (node, next) => `<th>${next(node.content)}</th>`,\n  [BLOCKS.TABLE_CELL]: (node, next) => `<td>${next(node.content)}</td>`,\n  [INLINES.ASSET_HYPERLINK]: (node) => defaultInline(INLINES.ASSET_HYPERLINK, node as Inline),\n  [INLINES.ENTRY_HYPERLINK]: (node) => defaultInline(INLINES.ENTRY_HYPERLINK, node as Inline),\n  [INLINES.RESOURCE_HYPERLINK]: (node) =>\n    defaultInlineResource(INLINES.RESOURCE_HYPERLINK, node as Inline),\n  [INLINES.EMBEDDED_ENTRY]: (node) => defaultInline(INLINES.EMBEDDED_ENTRY, node as Inline),\n  [INLINES.EMBEDDED_RESOURCE]: (node) =>\n    defaultInlineResource(INLINES.EMBEDDED_RESOURCE, node as Inline),\n  [INLINES.HYPERLINK]: (node, next) => {\n    const href = typeof node.data.uri === 'string' ? node.data.uri : '';\n    return `<a href=${attributeValue(href)}>${next(node.content)}</a>`;\n  },\n};\n\nconst defaultMarkRenderers: RenderMark = {\n  [MARKS.BOLD]: (text) => `<b>${text}</b>`,\n  [MARKS.ITALIC]: (text) => `<i>${text}</i>`,\n  [MARKS.UNDERLINE]: (text) => `<u>${text}</u>`,\n  [MARKS.CODE]: (text) => `<code>${text}</code>`,\n  [MARKS.SUPERSCRIPT]: (text) => `<sup>${text}</sup>`,\n  [MARKS.SUBSCRIPT]: (text) => `<sub>${text}</sub>`,\n  [MARKS.STRIKETHROUGH]: (text) => `<s>${text}</s>`,\n};\n\nconst defaultBlockAsset = (node: Block) => {\n  const fileUrl = node.data?.target?.fields?.file?.url ?? '';\n  const imageUrl = fileUrl.startsWith('//') ? `https:${fileUrl}` : fileUrl;\n  const imgDescription = node.data?.target?.fields?.description ?? '';\n\n  return `<img src=\"${imageUrl}\" alt=\"${escape(imgDescription)}\" loading=\"lazy\" />`;\n};\n\nconst defaultInline = (type: string, node: Inline) =>\n  `<span>type: ${escapeHtml(type)} id: ${escapeHtml(node.data.target.sys.id)}</span>`;\n\nconst defaultInlineResource = (type: string, node: Inline) =>\n  `<span>type: ${escapeHtml(type)} urn: ${escapeHtml(node.data?.target?.sys?.urn ?? '')}</span>`;\n\nexport type CommonNode = Text | Block | Inline;\n\nexport interface Next {\n  (nodes: CommonNode[]): string;\n}\n\nexport interface NodeRenderer {\n  (node: Block | Inline, next: Next): string;\n}\n\nexport interface RenderNode {\n  [k: string]: NodeRenderer;\n}\n\nexport interface RenderMark {\n  [k: string]: (text: string) => string;\n}\n\nexport interface Options {\n  /**\n   * Node renderers\n   */\n  renderNode?: RenderNode;\n  /**\n   * Mark renderers\n   */\n  renderMark?: RenderMark;\n  /**\n   * Keep line breaks and multiple spaces\n   */\n  preserveWhitespace?: boolean;\n  /**\n   * Strip empty trailing paragraph from the document\n   */\n  stripEmptyTrailingParagraph?: boolean;\n}\n\n/**\n * Serialize a Contentful Rich Text `document` to an html string.\n */\nexport function documentToHtmlString(\n  richTextDocument: Document,\n  options: Partial<Options> = {},\n): string {\n  if (!richTextDocument || !richTextDocument.content) {\n    return '';\n  }\n\n  // Strip empty trailing paragraph if enabled\n  let processedDocument = richTextDocument;\n  if (options.stripEmptyTrailingParagraph) {\n    processedDocument = helpers.stripEmptyTrailingParagraphFromDocument(richTextDocument);\n  }\n\n  return nodeListToHtmlString(processedDocument.content, {\n    renderNode: {\n      ...defaultNodeRenderers,\n      ...options.renderNode,\n    },\n    renderMark: {\n      ...defaultMarkRenderers,\n      ...options.renderMark,\n    },\n    preserveWhitespace: options.preserveWhitespace,\n  });\n}\n\nfunction nodeListToHtmlString(\n  nodes: CommonNode[],\n  { renderNode, renderMark, preserveWhitespace }: Options,\n): string {\n  return nodes\n    .map<string>((node) => nodeToHtmlString(node, { renderNode, renderMark, preserveWhitespace }))\n    .join('');\n}\n\nfunction nodeToHtmlString(\n  node: CommonNode,\n  { renderNode, renderMark, preserveWhitespace }: Options,\n): string {\n  if (helpers.isText(node)) {\n    let nodeValue = escapeHtml(node.value);\n\n    // If preserveWhitespace is true, handle line breaks and spaces.\n    if (preserveWhitespace) {\n      nodeValue = nodeValue\n        .replace(/\\n/g, '<br/>')\n        .replace(/ {2,}/g, (match) => '&nbsp;'.repeat(match.length));\n    }\n\n    if (node.marks.length > 0) {\n      return node.marks.reduce((value: string, mark: Mark) => {\n        if (!renderMark[mark.type]) {\n          return value;\n        }\n        return renderMark[mark.type](value);\n      }, nodeValue);\n    }\n\n    return nodeValue;\n  } else {\n    const nextNode: Next = (nodes) =>\n      nodeListToHtmlString(nodes, { renderMark, renderNode, preserveWhitespace });\n    if (!node.nodeType || !renderNode[node.nodeType]) {\n      // TODO: Figure what to return when passed an unrecognized node.\n      return '';\n    }\n    return renderNode[node.nodeType](node, nextNode);\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-html-renderer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist/lib\",\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/typings\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-links/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [17.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.1.0...@contentful/rich-text-links@17.1.1) (2026-04-09)\n\n### Bug Fixes\n\n- **rich-text-types:** improve esm compability [ZEND-7778] ([#1073](https://github.com/contentful/rich-text/issues/1073)) ([204aaec](https://github.com/contentful/rich-text/commit/204aaecc3893633c081986f44896e14272fa376a))\n\n# [17.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.8...@contentful/rich-text-links@17.1.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [17.0.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.7...@contentful/rich-text-links@17.0.8) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.6...@contentful/rich-text-links@17.0.7) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.5...@contentful/rich-text-links@17.0.6) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.4...@contentful/rich-text-links@17.0.5) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.3...@contentful/rich-text-links@17.0.4) (2025-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.2...@contentful/rich-text-links@17.0.3) (2025-09-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.1...@contentful/rich-text-links@17.0.2) (2025-07-15)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [17.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@17.0.0...@contentful/rich-text-links@17.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [17.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.10...@contentful/rich-text-links@17.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [16.7.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.9...@contentful/rich-text-links@16.7.10) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.8...@contentful/rich-text-links@16.7.9) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.7...@contentful/rich-text-links@16.7.8) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.6...@contentful/rich-text-links@16.7.7) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.5...@contentful/rich-text-links@16.7.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.4...@contentful/rich-text-links@16.7.5) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.3...@contentful/rich-text-links@16.7.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.2...@contentful/rich-text-links@16.7.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.1...@contentful/rich-text-links@16.7.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.7.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.7.0...@contentful/rich-text-links@16.7.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [16.7.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.5...@contentful/rich-text-links@16.7.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [16.6.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.4...@contentful/rich-text-links@16.6.5) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.6.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.3...@contentful/rich-text-links@16.6.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.6.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.2...@contentful/rich-text-links@16.6.3) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.6.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.1...@contentful/rich-text-links@16.6.2) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.6.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.6.0...@contentful/rich-text-links@16.6.1) (2024-05-24)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [16.6.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.5...@contentful/rich-text-links@16.6.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [16.5.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.4...@contentful/rich-text-links@16.5.5) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.5.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.3...@contentful/rich-text-links@16.5.4) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.5.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.2...@contentful/rich-text-links@16.5.3) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.5.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.1...@contentful/rich-text-links@16.5.2) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.5.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.5.0...@contentful/rich-text-links@16.5.1) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [16.5.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.4.1...@contentful/rich-text-links@16.5.0) (2023-09-12)\n\n### Features\n\n- add new nodes [DANTE-1157] ([#494](https://github.com/contentful/rich-text/issues/494)) ([b1fa6df](https://github.com/contentful/rich-text/commit/b1fa6dffc4bd7e1d367e9ce2cfddffe4fe07be47))\n\n## [16.4.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.4.0...@contentful/rich-text-links@16.4.1) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [16.4.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.3.0...@contentful/rich-text-links@16.4.0) (2023-07-10)\n\n### Features\n\n- allow document parameter to be nullable ([#471](https://github.com/contentful/rich-text/issues/471)) ([e50f8d2](https://github.com/contentful/rich-text/commit/e50f8d24c60a74f43f84f415a5c393038919efd2))\n\n# [16.3.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.2.0...@contentful/rich-text-links@16.3.0) (2023-06-09)\n\n### Features\n\n- change visitNodes to visit nodes in depth-first order ([#475](https://github.com/contentful/rich-text/issues/475)) ([ace5225](https://github.com/contentful/rich-text/commit/ace52253af4e83035075a466b7c97a08072e35ad))\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.1.1...@contentful/rich-text-links@16.2.0) (2023-06-07)\n\n### Features\n\n- add deduplicate option to getRichTextResourceLinks ([#470](https://github.com/contentful/rich-text/issues/470)) ([1141d5b](https://github.com/contentful/rich-text/commit/1141d5b6848e32efce198ad2d47b6442a9660aa0))\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.1.0...@contentful/rich-text-links@16.1.1) (2023-05-31)\n\n### Bug Fixes\n\n- prevent crash when a null value is passed as document ([#468](https://github.com/contentful/rich-text/issues/468)) ([3c8531c](https://github.com/contentful/rich-text/commit/3c8531cbcdde623c66c4b13d49fff73cad096871))\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.0.4...@contentful/rich-text-links@16.1.0) (2023-05-26)\n\n### Features\n\n- 🎸 add `getRichTextResourceLinks` ([#465](https://github.com/contentful/rich-text/issues/465)) ([5746ba6](https://github.com/contentful/rich-text/commit/5746ba652ae5eac2df27d05193e19aef9e85c438))\n\n## [16.0.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.0.3...@contentful/rich-text-links@16.0.4) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.0.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.0.2...@contentful/rich-text-links@16.0.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.0.1...@contentful/rich-text-links@16.0.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-links@16.0.0...@contentful/rich-text-links@16.0.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# 16.0.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n## 15.9.1 (2021-12-10)\n\n# 15.9.0 (2021-12-09)\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n## 15.5.1 (2021-10-25)\n\n# 15.5.0 (2021-10-25)\n\n## 15.3.6 (2021-09-15)\n\n## 15.3.5 (2021-09-13)\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.1.0 (2021-08-02)\n\n# 15.0.0 (2021-06-15)\n\n## 14.1.2 (2020-11-02)\n\n## 14.0.1 (2020-01-30)\n\n# 14.0.0 (2020-01-28)\n\n### Bug Fixes\n\n- 🐛 detect links as children of nodes also having links ([565f423](https://github.com/contentful/rich-text/commit/565f423b2881c7bcfac40e9ee9ecb6a545fce047))\n\n# 13.4.0 (2019-08-01)\n\n# 13.3.0 (2019-03-21)\n\n# 13.1.0 (2019-03-04)\n\n### Bug Fixes\n\n- 🐛 Fix incorrect typings file path ([cca74d5](https://github.com/contentful/rich-text/commit/cca74d5594fb0594fd1117945e087afa2000877b))\n\n### Features\n\n- 🎸 Support filtering by node name in rich-text-links ([5ec0dda](https://github.com/contentful/rich-text/commit/5ec0dda07cdbe3d28027d28520c553b074ca699f))\n\n# 13.0.0 (2019-01-22)\n\n## 12.1.2 (2018-12-14)\n\n## 12.0.3 (2018-12-05)\n\n### Performance Improvements\n\n- ⚡️ prefer iterator unrolling to Array.from ([a887a92](https://github.com/contentful/rich-text/commit/a887a9213dee9dd6986cf313e67b94fd020d138b))\n\n## 12.0.1 (2018-12-04)\n\n# 12.0.0 (2018-11-29)\n\n### Features\n\n- 🎸 `getRichTextEntityLinks` perf and signature changes ([fcd6d7f](https://github.com/contentful/rich-text/commit/fcd6d7f42e63df87ddb58d651b86a023d45f990e))\n\n### Performance Improvements\n\n- ⚡️ Add benchmark support ([ae278b7](https://github.com/contentful/rich-text/commit/ae278b7be515a52576af0a1abb6a4cefb05f71a7))\n\n### BREAKING CHANGES\n\n- Produces an entirely new return value and obviates the `linkType`\n  parameter (all entities are grouped and returned by default).\n\n# 11.0.0 (2018-11-27)\n\n# 10.3.0 (2018-11-26)\n\n### Features\n\n- 🎸 return all entity links when no linkType is provided ([02970ea](https://github.com/contentful/rich-text/commit/02970ea61b5b13d99c7b629902defe704c146b17))\n\n# 10.2.0 (2018-11-19)\n\n### Features\n\n- 🎸 Rename, refactor, docu. & cache r-t-links ([9cf6d14](https://github.com/contentful/rich-text/commit/9cf6d1460833300053cb8dde5a6e29b0ddf89964))\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/rich-text-links\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.1.0) (2021-09-06)\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n### Bug Fixes\n\n- 🐛 detect links as children of nodes also having links ([565f423](https://github.com/contentful/rich-text/commit/565f423b2881c7bcfac40e9ee9ecb6a545fce047))\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n# [13.3.0](https://github.com/contentful/rich-text/compare/v13.2.0...v13.3.0) (2019-03-21)\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n### Bug Fixes\n\n- 🐛 Fix incorrect typings file path ([cca74d5](https://github.com/contentful/rich-text/commit/cca74d5594fb0594fd1117945e087afa2000877b))\n\n### Features\n\n- 🎸 Support filtering by node name in rich-text-links ([5ec0dda](https://github.com/contentful/rich-text/commit/5ec0dda07cdbe3d28027d28520c553b074ca699f))\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n## [12.0.3](https://github.com/contentful/rich-text/compare/v12.0.2...v12.0.3) (2018-12-05)\n\n### Performance Improvements\n\n- ⚡️ prefer iterator unrolling to Array.from ([a887a92](https://github.com/contentful/rich-text/commit/a887a9213dee9dd6986cf313e67b94fd020d138b))\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n### Features\n\n- 🎸 `getRichTextEntityLinks` perf and signature changes ([fcd6d7f](https://github.com/contentful/rich-text/commit/fcd6d7f42e63df87ddb58d651b86a023d45f990e))\n\n### Performance Improvements\n\n- ⚡️ Add benchmark support ([ae278b7](https://github.com/contentful/rich-text/commit/ae278b7be515a52576af0a1abb6a4cefb05f71a7))\n\n### BREAKING CHANGES\n\n- Produces an entirely new return value and obviates the `linkType`\n  parameter (all entities are grouped and returned by default).\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n### Features\n\n- 🎸 return all entity links when no linkType is provided ([02970ea](https://github.com/contentful/rich-text/commit/02970ea61b5b13d99c7b629902defe704c146b17))\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Rename, refactor, docu. & cache r-t-links ([9cf6d14](https://github.com/contentful/rich-text/commit/9cf6d1460833300053cb8dde5a6e29b0ddf89964))\n"
  },
  {
    "path": "packages/rich-text-links/README.md",
    "content": "# rich-text-links\n\nEntity (entry and asset) link extraction utilities for the Contentful rich text\nfield type.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/rich-text-links\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/rich-text-links\n```\n\n## Usage\n\n```javascript\nimport { getRichTextEntityLinks } from '@contentful/rich-text-links';\n\nconst document = {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'embedded-entry-block',\n          data: {\n            target: {\n              sys: {\n                linkType: 'Entry',\n                type: 'Link',\n                id: 'yXmVKmaDBm8tRfQMwA0e',\n              },\n            },\n          },\n          content: [],\n        },\n        {\n          nodeType: 'embedded-asset-block',\n          data: {\n            target: {\n              sys: {\n                linkType: 'Asset',\n                type: 'Link',\n                id: 'jNhaW0aSc6Hu74SHVMtq',\n              },\n            },\n          },\n          content: [],\n        },\n      ],\n    },\n  ],\n};\n\ngetRichTextEntityLinks(document);\n/**\n * ->\n * {\n *   Entry: [\n *     { linkType: 'Entry', type: 'Link', id: 'yXmVKmaDBm8tRfQMwA0e' }\n *   ],\n *   Asset: [\n *     { linkType: 'Asset', type: 'Link', id: 'jNhaW0aSc6Hu74SHVMtq' }\n *   ]\n * }\n */\n```\n"
  },
  {
    "path": "packages/rich-text-links/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-links/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-links\",\n  \"version\": \"17.1.1\",\n  \"main\": \"dist/rich-text-links.es5.js\",\n  \"module\": \"dist/rich-text-links.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/rich-text-links.esm.js\",\n      \"require\": \"./dist/rich-text-links.es5.js\",\n      \"default\": \"./dist/rich-text-links.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc --module commonjs && rollup -c --bundleConfigAsCjs rollup.config.js\",\n    \"prebuild\": \"rimraf dist\",\n    \"start\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.js -w\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\"\n  },\n  \"devDependencies\": {\n    \"ts-jest\": \"^29.1.2\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-links/rollup.config.js",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nexport default config(outputFile, {\n  external: Object.keys(dependencies),\n});\n"
  },
  {
    "path": "packages/rich-text-links/src/__test__/index.test.ts",
    "content": "import { Document, BLOCKS, INLINES } from '@contentful/rich-text-types';\n\nimport {\n  getAllRichTextResourceLinks,\n  getRichTextEntityLinks,\n  getRichTextResourceLinks,\n} from '../index';\nimport { Maybe } from '../types/utils';\n\nfunction makeResourceLink(spaceId: string, entryId: string) {\n  return {\n    sys: {\n      type: 'ResourceLink',\n      linkType: 'Contentful:Entry',\n      urn: `crn:contentful:::content:spaces/${spaceId}/entries/${entryId}`,\n    },\n  };\n}\n\ndescribe('getRichTextEntityLinks', () => {\n  describe('returning top-level rich text links', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_ENTRY,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Entry',\n                    type: 'Link',\n                    id: 'foo',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ASSET,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Asset',\n                    type: 'Link',\n                    id: 'bar',\n                  },\n                },\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n\n    it('returns all entity link objects', () => {\n      expect(getRichTextEntityLinks(document)).toEqual({\n        Entry: [\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'foo',\n          },\n        ],\n        Asset: [\n          {\n            linkType: 'Asset',\n            type: 'Link',\n            id: 'bar',\n          },\n        ],\n      });\n    });\n\n    it('returns an empty array if document parameter is `null`', () => {\n      /**\n       * This test is important! Not all consumers of this library have correct typescript types,\n       * we know that not handling `null` gracefully will cause issues in production.\n       */\n\n      const documentThatIsNull: Maybe<Document> = null;\n\n      expect(getRichTextEntityLinks(documentThatIsNull)).toEqual({ Asset: [], Entry: [] });\n    });\n\n    it('returns an empty array if document parameter is `undefined`', () => {\n      const documentThatIsUndefined: Maybe<Document> = undefined;\n\n      expect(getRichTextEntityLinks(documentThatIsUndefined)).toEqual({ Asset: [], Entry: [] });\n    });\n  });\n\n  describe('returning rich text links at an arbitrary level of depth', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_ENTRY,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Entry',\n                    type: 'Link',\n                    id: 'bar',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.OL_LIST,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.LIST_ITEM,\n                          data: {},\n                          content: [\n                            {\n                              nodeType: BLOCKS.EMBEDDED_ASSET,\n                              data: {\n                                target: {\n                                  sys: {\n                                    linkType: 'Asset',\n                                    type: 'Link',\n                                    id: 'quux',\n                                  },\n                                },\n                              },\n                              content: [],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: INLINES.ENTRY_HYPERLINK,\n                      data: {\n                        target: {\n                          sys: {\n                            linkType: 'Entry',\n                            type: 'Link',\n                            id: 'baz',\n                          },\n                        },\n                      },\n                      content: [],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ASSET,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Asset',\n                    type: 'Link',\n                    id: 'qux',\n                  },\n                },\n              },\n              content: [],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [{ data: {}, content: [], nodeType: BLOCKS.PARAGRAPH }],\n                },\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: INLINES.EMBEDDED_ENTRY,\n                          data: {\n                            target: {\n                              sys: { id: 'inline-header-entry', type: 'Link', linkType: 'Entry' },\n                            },\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: INLINES.ENTRY_HYPERLINK,\n                          data: {\n                            target: {\n                              sys: { id: 'hyperlink-cell-entry', type: 'Link', linkType: 'Entry' },\n                            },\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  data: {},\n                  content: [\n                    {\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.PARAGRAPH,\n                          data: {},\n                          content: [\n                            {\n                              nodeType: INLINES.ASSET_HYPERLINK,\n                              data: {\n                                target: {\n                                  sys: {\n                                    id: 'hyperlink-cell-asset',\n                                    type: 'Link',\n                                    linkType: 'Asset',\n                                  },\n                                },\n                              },\n                              content: [],\n                            },\n                          ],\n                        },\n                      ],\n                      nodeType: BLOCKS.PARAGRAPH,\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    };\n\n    it('returns all entity link objects in the same order as defined in the document', () => {\n      expect(getRichTextEntityLinks(document)).toEqual({\n        Entry: [\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'bar',\n          },\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'baz',\n          },\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'inline-header-entry',\n          },\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'hyperlink-cell-entry',\n          },\n        ],\n        Asset: [\n          {\n            linkType: 'Asset',\n            type: 'Link',\n            id: 'quux',\n          },\n          {\n            linkType: 'Asset',\n            type: 'Link',\n            id: 'qux',\n          },\n          {\n            linkType: 'Asset',\n            type: 'Link',\n            id: 'hyperlink-cell-asset',\n          },\n        ],\n      });\n    });\n  });\n\n  describe('handling redundant links', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_ENTRY,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Entry',\n                    type: 'Link',\n                    id: 'foo',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ENTRY,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Entry',\n                    type: 'Link',\n                    id: 'foo',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ASSET,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Asset',\n                    type: 'Link',\n                    id: 'bar',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ASSET,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Asset',\n                    type: 'Link',\n                    id: 'bar',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.OL_LIST,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.EMBEDDED_ENTRY,\n                      data: {\n                        target: {\n                          sys: {\n                            linkType: 'Entry',\n                            type: 'Link',\n                            id: 'foo',\n                          },\n                        },\n                      },\n                      content: [],\n                    },\n                    {\n                      nodeType: BLOCKS.EMBEDDED_ASSET,\n                      data: {\n                        target: {\n                          sys: {\n                            linkType: 'Asset',\n                            type: 'Link',\n                            id: 'bar',\n                          },\n                        },\n                      },\n                      content: [],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    };\n\n    it('ignores all redundant links', () => {\n      expect(getRichTextEntityLinks(document)).toEqual({\n        Entry: [\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'foo',\n          },\n        ],\n        Asset: [\n          {\n            linkType: 'Asset',\n            type: 'Link',\n            id: 'bar',\n          },\n        ],\n      });\n    });\n  });\n\n  describe('filtering links of given type', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_ENTRY,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Entry',\n                    type: 'Link',\n                    id: 'foo',\n                  },\n                },\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_ASSET,\n              data: {\n                target: {\n                  sys: {\n                    linkType: 'Asset',\n                    type: 'Link',\n                    id: 'bar',\n                  },\n                },\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n\n    it('ignores all links of different types', () => {\n      expect(getRichTextEntityLinks(document, BLOCKS.EMBEDDED_ENTRY)).toEqual({\n        Entry: [\n          {\n            linkType: 'Entry',\n            type: 'Link',\n            id: 'foo',\n          },\n        ],\n        Asset: [],\n      });\n    });\n  });\n});\n\ndescribe(`getRichTextResourceLinks`, () => {\n  it('returns top-level rich text resource-links', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('foo', 'bar'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(getRichTextResourceLinks(document, BLOCKS.EMBEDDED_RESOURCE)).toEqual([\n      makeResourceLink('foo', 'bar'),\n    ]);\n  });\n\n  it('returns an empty array if document parameter is `null`', () => {\n    const documentThatIsNull: Maybe<Document> = null;\n\n    expect(getRichTextResourceLinks(documentThatIsNull, BLOCKS.EMBEDDED_RESOURCE)).toEqual([]);\n  });\n\n  it('returns an empty array if document parameter is `undefined`', () => {\n    const documentThatIsUndefined: Maybe<Document> = undefined;\n\n    expect(getRichTextResourceLinks(documentThatIsUndefined, BLOCKS.EMBEDDED_RESOURCE)).toEqual([]);\n  });\n\n  it(`returns all ResourceLinks from multiple levels in the same order as defined in the document`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.OL_LIST,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.LIST_ITEM,\n                          data: {},\n                          content: [\n                            {\n                              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                              data: {\n                                target: makeResourceLink('space-1', 'entry-2'),\n                              },\n                              content: [],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                      data: {\n                        target: makeResourceLink('space-2', 'entry-1'),\n                      },\n                      content: [],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [{ data: {}, content: [], nodeType: BLOCKS.PARAGRAPH }],\n                },\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                          data: {\n                            target: makeResourceLink('space-2', 'entry-2'),\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                          data: {\n                            target: makeResourceLink('space-2', 'entry-3'),\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(getRichTextResourceLinks(document, BLOCKS.EMBEDDED_RESOURCE)).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n      makeResourceLink('space-2', 'entry-1'),\n      makeResourceLink('space-2', 'entry-2'),\n      makeResourceLink('space-2', 'entry-3'),\n    ]);\n  });\n\n  it(`de-duplicates links based on urn`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-2'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n    expect(getRichTextResourceLinks(document, BLOCKS.EMBEDDED_RESOURCE)).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n    ]);\n  });\n\n  it(`should return duplicate links if the deduplicate option value is passed as false`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-2'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n    expect(\n      getRichTextResourceLinks(document, BLOCKS.EMBEDDED_RESOURCE, { deduplicate: false }),\n    ).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n      makeResourceLink('space-1', 'entry-1'),\n    ]);\n  });\n});\n\ndescribe(`getAllRichTextResourceLinks`, () => {\n  it('returns top-level rich text resource-links', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('foo', 'bar'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.RESOURCE_HYPERLINK,\n              data: {\n                target: makeResourceLink('foo2', 'bar'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('foo3', 'bar'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(getAllRichTextResourceLinks(document)).toEqual([\n      makeResourceLink('foo', 'bar'),\n      makeResourceLink('foo2', 'bar'),\n      makeResourceLink('foo3', 'bar'),\n    ]);\n  });\n\n  it('returns an empty array if document parameter is `null`', () => {\n    const documentThatIsNull: Maybe<Document> = null;\n\n    expect(getAllRichTextResourceLinks(documentThatIsNull)).toEqual([]);\n  });\n\n  it('returns an empty array if document parameter is `undefined`', () => {\n    const documentThatIsUndefined: Maybe<Document> = undefined;\n\n    expect(getAllRichTextResourceLinks(documentThatIsUndefined)).toEqual([]);\n  });\n\n  it(`returns all ResourceLinks from multiple levels in the same order as defined in the document`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.OL_LIST,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.LIST_ITEM,\n                          data: {},\n                          content: [\n                            {\n                              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                              data: {\n                                target: makeResourceLink('space-1', 'entry-2'),\n                              },\n                              content: [],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n                {\n                  nodeType: BLOCKS.LIST_ITEM,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                      data: {\n                        target: makeResourceLink('space-2', 'entry-1'),\n                      },\n                      content: [],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [{ data: {}, content: [], nodeType: BLOCKS.PARAGRAPH }],\n                },\n                {\n                  nodeType: BLOCKS.TABLE_HEADER_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                          data: {\n                            target: makeResourceLink('space-2', 'entry-2'),\n                          },\n                          content: [],\n                        },\n                        {\n                          nodeType: INLINES.RESOURCE_HYPERLINK,\n                          data: {\n                            target: makeResourceLink('space-2', 'entry'),\n                          },\n                          content: [],\n                        },\n                        {\n                          nodeType: INLINES.EMBEDDED_RESOURCE,\n                          data: {\n                            target: makeResourceLink('space-3', 'entry'),\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      data: {},\n                      content: [\n                        {\n                          nodeType: BLOCKS.EMBEDDED_RESOURCE,\n                          data: {\n                            target: makeResourceLink('space-2', 'entry-3'),\n                          },\n                          content: [],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(getAllRichTextResourceLinks(document)).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n      makeResourceLink('space-2', 'entry-1'),\n      makeResourceLink('space-2', 'entry-2'),\n      makeResourceLink('space-2', 'entry'),\n      makeResourceLink('space-3', 'entry'),\n      makeResourceLink('space-2', 'entry-3'),\n    ]);\n  });\n\n  it(`de-duplicates links based on urn`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-2'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-2', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.RESOURCE_HYPERLINK,\n              data: {\n                target: makeResourceLink('space-2', 'entry-1'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n    expect(getAllRichTextResourceLinks(document)).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n      makeResourceLink('space-2', 'entry-1'),\n    ]);\n  });\n\n  it(`should return duplicate links if the deduplicate option value is passed as false`, () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-2'),\n              },\n              content: [],\n            },\n            {\n              nodeType: BLOCKS.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-1', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.EMBEDDED_RESOURCE,\n              data: {\n                target: makeResourceLink('space-2', 'entry-1'),\n              },\n              content: [],\n            },\n            {\n              nodeType: INLINES.RESOURCE_HYPERLINK,\n              data: {\n                target: makeResourceLink('space-2', 'entry-1'),\n              },\n              content: [],\n            },\n          ],\n        },\n      ],\n    };\n    expect(getAllRichTextResourceLinks(document, { deduplicate: false })).toEqual([\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-1', 'entry-2'),\n      makeResourceLink('space-1', 'entry-1'),\n      makeResourceLink('space-2', 'entry-1'),\n      makeResourceLink('space-2', 'entry-1'),\n    ]);\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-links/src/index.ts",
    "content": "import {\n  Block,\n  BLOCKS,\n  Document,\n  Inline,\n  INLINES,\n  Link,\n  Node,\n  NodeData,\n  ResourceLink,\n} from '@contentful/rich-text-types';\n\nimport { Maybe } from './types/utils';\n\nexport type EntityLinks = { [type in EntityType]: EntityLink[] };\nexport type EntityLinkMaps = { [type in EntityType]: Map<string, EntityLink> };\nexport type EntityType = 'Entry' | 'Asset';\nexport type EntityLink = SysObject['sys'];\nexport type SysObject = Link<EntityType>;\nexport type EntityLinkNodeData = {\n  target: SysObject;\n};\n\n// spare upstream dependencies the need to use rich-text-types\ntype AcceptedResourceLinkTypes =\n  | `${BLOCKS.EMBEDDED_RESOURCE}`\n  | `${INLINES.EMBEDDED_RESOURCE}`\n  | `${INLINES.RESOURCE_HYPERLINK}`;\n\n/**\n * Extracts all links no matter the entity they are pointing to.\n */\nexport function getRichTextResourceLinks(\n  document: Maybe<Document>,\n  nodeType: AcceptedResourceLinkTypes,\n  { deduplicate = true }: { deduplicate?: boolean } = {},\n): ResourceLink[] {\n  const isValidType = (actualNodeType: string, data: NodeData) =>\n    actualNodeType === nodeType && data.target?.sys?.type === 'ResourceLink';\n\n  return getValidResourceLinks(document, isValidType, deduplicate);\n}\n\nexport function getAllRichTextResourceLinks(\n  document: Maybe<Document>,\n  { deduplicate = true }: { deduplicate?: boolean } = {},\n): ResourceLink[] {\n  const nodeTypes: string[] = [\n    BLOCKS.EMBEDDED_RESOURCE,\n    INLINES.EMBEDDED_RESOURCE,\n    INLINES.RESOURCE_HYPERLINK,\n  ];\n  const isValidType = (actualNodeType: string, data: NodeData) =>\n    nodeTypes.includes(actualNodeType) && data.target?.sys?.type === 'ResourceLink';\n\n  return getValidResourceLinks(document, isValidType, deduplicate);\n}\n\nfunction getValidResourceLinks(\n  document: Maybe<Document>,\n  isValidType: (actualNodeType: string, data: NodeData) => boolean,\n  deduplicate: boolean,\n): ResourceLink[] {\n  const links = new Map<string, ResourceLink>();\n  visitNodes(document, (node) => {\n    if (isValidType(node.nodeType, node.data)) {\n      const key = deduplicate ? node.data.target.sys.urn : links.size;\n      links.set(key, node.data.target);\n    }\n  });\n\n  return iteratorToArray(links.values());\n}\n\n/**\n *  Extracts entity links from a Rich Text document.\n */\nexport function getRichTextEntityLinks(\n  /**\n   *  An instance of a Rich Text Document.\n   */\n  document: Maybe<Document>,\n  /**\n   *  Node type. Only the entity links with given node type will be extracted.\n   */\n  type?: string,\n): EntityLinks {\n  const entityLinks: EntityLinkMaps = {\n    Entry: new Map(),\n    Asset: new Map(),\n  };\n\n  // const content = (document && document.content) || ([] as Node[]);\n  const addLink = ({ data, nodeType }: Node) => {\n    const hasRequestedNodeType = !type || nodeType === type;\n\n    if (hasRequestedNodeType && isLinkObject(data)) {\n      entityLinks[data.target.sys.linkType].set(data.target.sys.id, data.target.sys);\n    }\n  };\n\n  visitNodes(document, addLink);\n\n  return {\n    Entry: iteratorToArray(entityLinks.Entry.values()),\n    Asset: iteratorToArray(entityLinks.Asset.values()),\n  };\n}\n\nfunction isContentNode(node: Node): node is Inline | Block {\n  return 'content' in node && Array.isArray(node.content);\n}\n\nfunction visitNodes(startNode: Maybe<Node>, onVisit: (node: Node) => void): void {\n  /**\n   * Do not remove this null check as consumers of this library do not all have good Typescript types\n   */\n  const toCrawl: Node[] = startNode ? [startNode] : [];\n\n  while (toCrawl.length > 0) {\n    const node = toCrawl.pop();\n    onVisit(node);\n\n    if (isContentNode(node)) {\n      for (let i = node.content.length - 1; i >= 0; i--) {\n        toCrawl.push(node.content[i]);\n      }\n    }\n  }\n}\n\nfunction isLinkObject(data: NodeData): data is EntityLinkNodeData {\n  const sys = data && (data.target as SysObject) && (data.target.sys as EntityLink);\n  if (!sys) {\n    return false;\n  }\n\n  const isValidLinkObject = typeof sys.id === 'string' && sys.type === 'Link';\n  if (!isValidLinkObject) {\n    return false;\n  }\n\n  const isEntityLink = sys.linkType === 'Entry' || sys.linkType === 'Asset';\n\n  return isEntityLink;\n}\n\n/**\n * Used to convert the EntityLink iterators stored by the EntityLinkMap values\n * into a client-friendly array form.\n *\n * Alternately we could do:\n * 1) Array.from(EntityLinkMap)\n * 2) [...EntityLinkMap]\n *\n * #1, although idiomatic, is about half as slow as #2.\n *\n * #2, while faster than #1, requires transpilation of the iterator protocol[1],\n * which in turn is still only about half as fast as the approach below.\n *\n * [1] See https://blog.mariusschulz.com/2017/06/30/typescript-2-3-downlevel-iteration-for-es3-es5.\n */\nfunction iteratorToArray<T>(iterator: IterableIterator<T>): T[] {\n  const result = [];\n\n  // eslint-disable-next-line no-constant-condition\n  while (true) {\n    const { value, done } = iterator.next();\n    if (done) {\n      break;\n    }\n    result.push(value);\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/rich-text-links/src/types/utils.ts",
    "content": "export type Maybe<T> = T | null | undefined;\n"
  },
  {
    "path": "packages/rich-text-links/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist/lib\",\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/typings\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [17.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.2.0...@contentful/rich-text-plain-text-renderer@17.2.1) (2026-04-09)\n\n### Bug Fixes\n\n- **rich-text-types:** improve esm compability [ZEND-7778] ([#1073](https://github.com/contentful/rich-text/issues/1073)) ([204aaec](https://github.com/contentful/rich-text/commit/204aaecc3893633c081986f44896e14272fa376a))\n\n# [17.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.6...@contentful/rich-text-plain-text-renderer@17.2.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [17.1.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.5...@contentful/rich-text-plain-text-renderer@17.1.6) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [17.1.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.4...@contentful/rich-text-plain-text-renderer@17.1.5) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [17.1.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.3...@contentful/rich-text-plain-text-renderer@17.1.4) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [17.1.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.2...@contentful/rich-text-plain-text-renderer@17.1.3) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [17.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.1...@contentful/rich-text-plain-text-renderer@17.1.2) (2025-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [17.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.1.0...@contentful/rich-text-plain-text-renderer@17.1.1) (2025-09-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [17.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.0.1...@contentful/rich-text-plain-text-renderer@17.1.0) (2025-07-15)\n\n### Features\n\n- add an option to strip empty trailing paragraphs [TOL-3193] ([#892](https://github.com/contentful/rich-text/issues/892)) ([9beff0e](https://github.com/contentful/rich-text/commit/9beff0e4cba3e79dc68e6a0725e843c5d642eb87))\n\n## [17.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@17.0.0...@contentful/rich-text-plain-text-renderer@17.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [17.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.10...@contentful/rich-text-plain-text-renderer@17.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [16.2.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.9...@contentful/rich-text-plain-text-renderer@16.2.10) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.8...@contentful/rich-text-plain-text-renderer@16.2.9) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.7...@contentful/rich-text-plain-text-renderer@16.2.8) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.6...@contentful/rich-text-plain-text-renderer@16.2.7) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.5...@contentful/rich-text-plain-text-renderer@16.2.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.4...@contentful/rich-text-plain-text-renderer@16.2.5) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.3...@contentful/rich-text-plain-text-renderer@16.2.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.2...@contentful/rich-text-plain-text-renderer@16.2.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.1...@contentful/rich-text-plain-text-renderer@16.2.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.2.0...@contentful/rich-text-plain-text-renderer@16.2.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.5...@contentful/rich-text-plain-text-renderer@16.2.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [16.1.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.4...@contentful/rich-text-plain-text-renderer@16.1.5) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.1.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.3...@contentful/rich-text-plain-text-renderer@16.1.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.1.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.2...@contentful/rich-text-plain-text-renderer@16.1.3) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.1...@contentful/rich-text-plain-text-renderer@16.1.2) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.1.0...@contentful/rich-text-plain-text-renderer@16.1.1) (2024-05-24)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.13...@contentful/rich-text-plain-text-renderer@16.1.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [16.0.13](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.12...@contentful/rich-text-plain-text-renderer@16.0.13) (2024-03-06)\n\n### Bug Fixes\n\n- correctly handle edge case [ZEND-4744] ([#541](https://github.com/contentful/rich-text/issues/541)) ([819b07d](https://github.com/contentful/rich-text/commit/819b07da3a00e6d8101e49cb0e678e3a21b4cd93))\n\n## [16.0.12](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.11...@contentful/rich-text-plain-text-renderer@16.0.12) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.11](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.10...@contentful/rich-text-plain-text-renderer@16.0.11) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.9...@contentful/rich-text-plain-text-renderer@16.0.10) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.8...@contentful/rich-text-plain-text-renderer@16.0.9) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.7...@contentful/rich-text-plain-text-renderer@16.0.8) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.6...@contentful/rich-text-plain-text-renderer@16.0.7) (2023-09-12)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.5...@contentful/rich-text-plain-text-renderer@16.0.6) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.4...@contentful/rich-text-plain-text-renderer@16.0.5) (2023-05-26)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.3...@contentful/rich-text-plain-text-renderer@16.0.4) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.2...@contentful/rich-text-plain-text-renderer@16.0.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.1...@contentful/rich-text-plain-text-renderer@16.0.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-plain-text-renderer@16.0.0...@contentful/rich-text-plain-text-renderer@16.0.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# 16.0.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n## 15.9.1 (2021-12-10)\n\n# 15.9.0 (2021-12-09)\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n## 15.5.1 (2021-10-25)\n\n# 15.5.0 (2021-10-25)\n\n## 15.3.6 (2021-09-15)\n\n## 15.3.5 (2021-09-13)\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.1.0 (2021-08-02)\n\n# 15.0.0 (2021-06-15)\n\n## 14.1.2 (2020-11-02)\n\n## 14.0.1 (2020-01-30)\n\n# 14.0.0 (2020-01-28)\n\n# 13.4.0 (2019-08-01)\n\n# 13.1.0 (2019-03-04)\n\n# 13.0.0 (2019-01-22)\n\n### Bug Fixes\n\n- 🐛 use named export instead of default ([57bf365](https://github.com/contentful/rich-text/commit/57bf36510f1021f5208a3e33242cceea97940d68))\n\n### BREAKING CHANGES\n\n- removes default export from 'rich-text-plain-text-renderer'\n\n## 12.1.2 (2018-12-14)\n\n## 12.0.3 (2018-12-05)\n\n### Bug Fixes\n\n- **readme:** mark types in readme examples ([d997b56](https://github.com/contentful/rich-text/commit/d997b56f2b8c32b2e5b478ab5444757203e2c703))\n\n## 12.0.2 (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 update path to typings ([ce5544f](https://github.com/contentful/rich-text/commit/ce5544f58712dc6a18aadda523d0c0357a66c8a5))\n\n## 12.0.1 (2018-12-04)\n\n# 12.0.0 (2018-11-29)\n\n# 11.0.0 (2018-11-27)\n\n# 10.3.0 (2018-11-26)\n\n# 10.2.0 (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# 10.1.0 (2018-11-16)\n\n## 10.0.5 (2018-11-12)\n\n### Bug Fixes\n\n- 🐛 handle case of missing rootNode / rootNode.content ([e2434c7](https://github.com/contentful/rich-text/commit/e2434c7f5e1401f1188dd778c2aa9a108cea5596))\n\n## 10.0.1 (2018-11-08)\n\n# 10.0.0 (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## 9.0.2 (2018-10-31)\n\n## 9.0.1 (2018-10-31)\n\n# 9.0.0 (2018-10-30)\n\n### Bug Fixes\n\n- 🐛 Fix block divisor provision ([3aafb7a](https://github.com/contentful/rich-text/commit/3aafb7a756d8b6f96ef733eb299091404b3391aa))\n- 🐛 remove exclusive mocha test ([5ff5d0e](https://github.com/contentful/rich-text/commit/5ff5d0e35024b7dccda065f54ae34138d9416525))\n\n### BREAKING CHANGES\n\n- Fundamentally alters the plain text renderer behavior. (For the better!)\n\n## 8.0.3 (2018-10-30)\n\n## 8.0.2 (2018-10-29)\n\n## 8.0.1 (2018-10-26)\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/rich-text-plain-text-renderer\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.1.0) (2021-09-06)\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n### Bug Fixes\n\n- 🐛 use named export instead of default ([57bf365](https://github.com/contentful/rich-text/commit/57bf36510f1021f5208a3e33242cceea97940d68))\n\n### BREAKING CHANGES\n\n- removes default export from 'rich-text-plain-text-renderer'\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n## [12.0.3](https://github.com/contentful/rich-text/compare/v12.0.2...v12.0.3) (2018-12-05)\n\n### Bug Fixes\n\n- **readme:** mark types in readme examples ([d997b56](https://github.com/contentful/rich-text/commit/d997b56f2b8c32b2e5b478ab5444757203e2c703))\n\n## [12.0.2](https://github.com/contentful/rich-text/compare/v12.0.1...v12.0.2) (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 update path to typings ([ce5544f](https://github.com/contentful/rich-text/commit/ce5544f58712dc6a18aadda523d0c0357a66c8a5))\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# [10.1.0](https://github.com/contentful/rich-text/compare/v10.0.5...v10.1.0) (2018-11-16)\n\n## [10.0.5](https://github.com/contentful/rich-text/compare/v10.0.4...v10.0.5) (2018-11-12)\n\n### Bug Fixes\n\n- 🐛 handle case of missing rootNode / rootNode.content ([e2434c7](https://github.com/contentful/rich-text/commit/e2434c7f5e1401f1188dd778c2aa9a108cea5596))\n\n## [10.0.1](https://github.com/contentful/rich-text/compare/v10.0.0...v10.0.1) (2018-11-08)\n\n# [10.0.0](https://github.com/contentful/rich-text/compare/v9.0.2...v10.0.0) (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## [9.0.2](https://github.com/contentful/rich-text/compare/v9.0.1...v9.0.2) (2018-10-31)\n\n## [9.0.1](https://github.com/contentful/rich-text/compare/v9.0.0...v9.0.1) (2018-10-31)\n\n# [9.0.0](https://github.com/contentful/rich-text/compare/v8.0.3...v9.0.0) (2018-10-30)\n\n### Bug Fixes\n\n- 🐛 Fix block divisor provision ([3aafb7a](https://github.com/contentful/rich-text/commit/3aafb7a756d8b6f96ef733eb299091404b3391aa))\n- 🐛 remove exclusive mocha test ([5ff5d0e](https://github.com/contentful/rich-text/commit/5ff5d0e35024b7dccda065f54ae34138d9416525))\n\n### BREAKING CHANGES\n\n- Fundamentally alters the plain text renderer behavior. (For the better!)\n\n## [8.0.3](https://github.com/contentful/rich-text/compare/v8.0.2...v8.0.3) (2018-10-30)\n\n## [8.0.2](https://github.com/contentful/rich-text/compare/v8.0.1...v8.0.2) (2018-10-29)\n\n## [8.0.1](https://github.com/contentful/rich-text/compare/v8.0.0...v8.0.1) (2018-10-26)\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/README.md",
    "content": "# rich-text-plain-text-renderer\n\nPlain text renderer for the Rich Text document.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/rich-text-plain-text-renderer\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/rich-text-plain-text-renderer\n```\n\n## Usage\n\n```javascript\nimport { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';\n\nconst document = {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello',\n          marks: [{ type: 'bold' }],\n          data: {},\n        },\n        {\n          nodeType: 'text',\n          value: ' world!',\n          marks: [{ type: 'italic' }],\n          data: {},\n        },\n      ],\n    },\n  ],\n};\n\ndocumentToPlainTextString(document); // -> Hello world!\n```\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/bin/benchmark/get-rich-text-entity-links.ts",
    "content": "import { BLOCKS, Document, Node } from '@contentful/rich-text-types';\n\nimport { documentToPlainTextString as docToString } from '../../src/index';\n\n/**\n * Implements just a subset of _.times since all we're really doing here is\n * cleanly filling the field with a bunch of junk data.\n */\nfunction times<N extends Node>(n: number, node: N): N[] {\n  return new Array(n).fill(node);\n}\n\nconst richTextField: Document = {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.PARAGRAPH,\n      data: {},\n      content: times(8000, {\n        nodeType: BLOCKS.UL_LIST,\n        data: {},\n        content: times(5, {\n          nodeType: BLOCKS.LIST_ITEM,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.PARAGRAPH,\n              data: {},\n              content: times(5, {\n                nodeType: 'text',\n                data: {},\n                marks: [],\n                value: 'x',\n              }),\n            },\n          ],\n        }),\n      }),\n    },\n  ],\n};\n\nexport const documentToPlainTextString = () => docToString(richTextField, '');\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/bin/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../bin/tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-plain-text-renderer\",\n  \"version\": \"17.2.1\",\n  \"main\": \"dist/rich-text-plain-text-renderer.es5.js\",\n  \"module\": \"dist/rich-text-plain-text-renderer.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/rich-text-plain-text-renderer.esm.js\",\n      \"require\": \"./dist/rich-text-plain-text-renderer.es5.js\",\n      \"default\": \"./dist/rich-text-plain-text-renderer.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc --module commonjs && rollup -c --bundleConfigAsCjs rollup.config.js\",\n    \"prebuild\": \"rimraf dist\",\n    \"start\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.js -w\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\"\n  },\n  \"devDependencies\": {\n    \"ts-jest\": \"^29.1.2\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/rollup.config.js",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nexport default config(outputFile, {\n  external: Object.keys(dependencies),\n});\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/src/__test__/index.test.ts",
    "content": "import { Document, BLOCKS, INLINES } from '@contentful/rich-text-types';\n\nimport { documentToPlainTextString } from '../index';\n\ndescribe('documentToPlainTextString', () => {\n  it('returns empty string when given an empty document', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [],\n    };\n\n    expect(documentToPlainTextString(document)).toEqual('');\n  });\n\n  it('handles a simple case', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              data: {},\n              value: 'Trout is a',\n              marks: [],\n            },\n            {\n              nodeType: 'text',\n              data: {},\n              value: ' seafood d',\n              marks: [{ type: 'italic' }],\n            },\n            {\n              nodeType: 'text',\n              data: {},\n              value: 'elicacy.',\n              marks: [],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(documentToPlainTextString(document)).toEqual('Trout is a seafood delicacy.');\n  });\n\n  describe('rendering deeply nested documents', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'This is text. ',\n              data: {},\n              marks: [{ type: 'bold' }],\n            },\n            {\n              nodeType: 'text',\n              value: '',\n              data: {},\n              marks: [],\n            },\n            {\n              nodeType: 'text',\n              value: 'This is text with some marks.',\n              data: {},\n              marks: [{ type: 'italic' }],\n            },\n            {\n              nodeType: 'text',\n              value: ' ',\n              data: {},\n              marks: [],\n            },\n            {\n              nodeType: INLINES.HYPERLINK,\n              content: [\n                {\n                  nodeType: 'text',\n                  value: 'This is text from a bolded hyperlink.',\n                  data: {},\n                  marks: [{ type: 'bold' }],\n                },\n              ],\n              data: {\n                url: 'https://example.com',\n                title: 'qux',\n              },\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.UL_LIST,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.LIST_ITEM,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      value: 'This is a list element in a separate block ',\n                      data: {},\n                      marks: [],\n                    },\n                    {\n                      nodeType: INLINES.HYPERLINK,\n                      content: [\n                        {\n                          nodeType: 'text',\n                          value: 'with a link with marks.',\n                          data: {},\n                          marks: [],\n                        },\n                      ],\n                      data: {\n                        url: 'https://google.com',\n                        title: 'woo',\n                      },\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.LIST_ITEM,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      value: 'This is a separate list element in the same block.',\n                      data: {},\n                      marks: [],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    };\n\n    it('handles nested nodes gracefully', () => {\n      expect(documentToPlainTextString(document)).toEqual(\n        [\n          'This is text.',\n          'This is text with some marks.',\n          'This is text from a bolded hyperlink.',\n          'This is a list element in a separate block with a link with marks.',\n          'This is a separate list element in the same block.',\n        ].join(' '),\n      );\n    });\n\n    it('defers to the user-supplied block divisor', () => {\n      expect(documentToPlainTextString(document, '\\n\\n')).toEqual(\n        [\n          'This is text. This is text with some marks. This is text from a bolded hyperlink.',\n          'This is a list element in a separate block with a link with marks.',\n          'This is a separate list element in the same block.',\n        ].join('\\n\\n'),\n      );\n    });\n  });\n});\n\ndescribe('stripEmptyTrailingParagraph', () => {\n  it('strips empty trailing paragraph when enabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('Hello world');\n  });\n\n  it('does not strip empty trailing paragraph when disabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: false,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('Hello world ');\n  });\n\n  it('does not strip empty trailing paragraph when it is the only child', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('');\n  });\n\n  it('does not strip non-empty trailing paragraph', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Not empty',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('Hello world Not empty');\n  });\n\n  it('does not strip trailing paragraph with multiple text nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('Hello world ');\n  });\n\n  it('does not strip trailing non-paragraph node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.HEADING_1,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToPlainTextString(document, ' ', options);\n    expect(result).toEqual('Hello world ');\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/src/index.ts",
    "content": "import { Block, Inline, Node, helpers, BLOCKS, Document } from '@contentful/rich-text-types';\n\nexport interface Options {\n  /**\n   * Strip empty trailing paragraph from the document\n   */\n  stripEmptyTrailingParagraph?: boolean;\n}\n\n/**\n * Returns the text value of a rich text document.\n *\n * NB: This can be applied to non text node of a structured text document,\n * hence the flexible typing.\n */\nexport function documentToPlainTextString(\n  rootNode: Block | Inline,\n  blockDivisor: string = ' ',\n  options: Options = {},\n): string {\n  if (!rootNode || !rootNode.content || !Array.isArray(rootNode.content)) {\n    /**\n     * Handles edge cases, such as when the value is not set in the CMA or the\n     * field has not been properly validated, e.g. because of a user extension.\n     * Note that we are nevertheless strictly type-casting `rootNode` as\n     * Block | Inline. Valid rich text documents (and their branch block nodes)\n     * should never lack a Node[] `content` property.\n     */\n    return '';\n  }\n\n  // Strip empty trailing paragraph if enabled and rootNode is a Document\n  let processedRootNode = rootNode;\n  if (rootNode.nodeType === BLOCKS.DOCUMENT && options.stripEmptyTrailingParagraph) {\n    processedRootNode = helpers.stripEmptyTrailingParagraphFromDocument(rootNode as Document);\n  }\n\n  /**\n   * Algorithm notes: We only want to apply spacing when a node is part of a\n   * sequence. This is tricky because nodes can often be deeply nested within\n   * non-semantic content arrays. For example, to get the text value of an\n   * unordered list, we have to traverse like so:\n   *\n   * {\n   *   nodeType: BLOCKS.UL_LIST,\n   *   data: {},\n   *   content: [\n   *     {\n   *       nodeType: BLOCKS.LIST_ITEM,\n   *       data: {},\n   *       content: [{\n   *         nodeType: BLOCKS.PARAGRAPH,\n   *         data: {},\n   *         content: [\n   *           { nodeType: 'text', data: {}, value: 'List ', marks: [] },\n   *           { nodeType: 'text', data: {}, value: 'item', marks: [{ type: 'bold' }] }\n   *         ]\n   *       }]\n   *     },\n   *     {\n   *       nodeType: BLOCKS.LIST_ITEM,\n   *       data: {},\n   *       content: [{\n   *         nodeType: BLOCKS.PARAGRAPH,\n   *         data: {},\n   *         content: [\n   *           { nodeType: 'text', data: {}, value: 'Another list item', marks: [] }\n   *         ]\n   *       }]\n   *     },\n   *     {\n   *       nodeType: BLOCKS.LIST_ITEM,\n   *       data: {},\n   *       content: [{\n   *         nodeType: BLOCKS.HR,\n   *         data: {},\n   *         content: [],\n   *       }]\n   *     },\n   *     {\n   *       nodeType: BLOCKS.LIST_ITEM,\n   *       data: {},\n   *       content: [{\n   *         nodeType: BLOCKS.PARAGRAPH,\n   *         data:\n   *         content: [\n   *           { nodeType: 'text', data: {}, value: 'Yet another list item', marks: [] }\n   *         ]\n   *       }]\n   *     },\n   *   }]\n   * }\n   *\n   * We want there to be a space between 'List item' and 'Another list item' (to\n   * denote a visual line break, which conventionally appears between non-text\n   * node sequences) but not a redundant space between 'List ' and 'item'.\n   * Moreover, we want just a _singular_ space between 'Another list item' and\n   * 'Yet another list item' - the non-semantic HR between the two nodes should\n   * not denote an additional space.\n   */\n  return (processedRootNode as Block).content.reduce(\n    (acc: string, node: Node, i: number): string => {\n      let nodeTextValue: string;\n\n      if (helpers.isText(node)) {\n        nodeTextValue = node.value;\n      } else if (helpers.isBlock(node) || helpers.isInline(node)) {\n        nodeTextValue = documentToPlainTextString(node, blockDivisor, options);\n        if (!nodeTextValue.length) {\n          return acc;\n        }\n      }\n\n      const nextNode = processedRootNode.content[i + 1];\n      const isNextNodeBlock = nextNode && helpers.isBlock(nextNode);\n      const divisor = isNextNodeBlock ? blockDivisor : '';\n      return acc + nodeTextValue + divisor;\n    },\n    '',\n  );\n}\n"
  },
  {
    "path": "packages/rich-text-plain-text-renderer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist/lib\",\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/typings\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [16.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.2.0...@contentful/rich-text-react-renderer@16.2.1) (2026-04-09)\n\n### Bug Fixes\n\n- **rich-text-types:** improve esm compability [ZEND-7778] ([#1073](https://github.com/contentful/rich-text/issues/1073)) ([204aaec](https://github.com/contentful/rich-text/commit/204aaecc3893633c081986f44896e14272fa376a))\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.6...@contentful/rich-text-react-renderer@16.2.0) (2026-04-08)\n\n### Features\n\n- add esm support [ZEND-7778] ([#1069](https://github.com/contentful/rich-text/issues/1069)) ([8c320bd](https://github.com/contentful/rich-text/commit/8c320bde7fa313572bdad84b91a6fd12224afc3a)), closes [#1068](https://github.com/contentful/rich-text/issues/1068)\n\n## [16.1.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.5...@contentful/rich-text-react-renderer@16.1.6) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [16.1.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.4...@contentful/rich-text-react-renderer@16.1.5) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [16.1.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.3...@contentful/rich-text-react-renderer@16.1.4) (2025-09-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [16.1.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.2...@contentful/rich-text-react-renderer@16.1.3) (2025-09-10)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [16.1.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.1...@contentful/rich-text-react-renderer@16.1.2) (2025-09-09)\n\n### Bug Fixes\n\n- bundle issues after swc migration [TOL-3396] ([#924](https://github.com/contentful/rich-text/issues/924)) ([22245f0](https://github.com/contentful/rich-text/commit/22245f0648b0164ad29dd0dfe789cd83f78283e8))\n\n## [16.1.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.1.0...@contentful/rich-text-react-renderer@16.1.1) (2025-09-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.0.2...@contentful/rich-text-react-renderer@16.1.0) (2025-07-15)\n\n### Features\n\n- add an option to strip empty trailing paragraphs [TOL-3193] ([#892](https://github.com/contentful/rich-text/issues/892)) ([9beff0e](https://github.com/contentful/rich-text/commit/9beff0e4cba3e79dc68e6a0725e843c5d642eb87))\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.0.1...@contentful/rich-text-react-renderer@16.0.2) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@16.0.0...@contentful/rich-text-react-renderer@16.0.1) (2024-12-11)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [16.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.11...@contentful/rich-text-react-renderer@16.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [15.22.11](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.10...@contentful/rich-text-react-renderer@15.22.11) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.10](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.9...@contentful/rich-text-react-renderer@15.22.10) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.9](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.8...@contentful/rich-text-react-renderer@15.22.9) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.8](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.7...@contentful/rich-text-react-renderer@15.22.8) (2024-07-24)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.6...@contentful/rich-text-react-renderer@15.22.7) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.5...@contentful/rich-text-react-renderer@15.22.6) (2024-07-17)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.4...@contentful/rich-text-react-renderer@15.22.5) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.3...@contentful/rich-text-react-renderer@15.22.4) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.2...@contentful/rich-text-react-renderer@15.22.3) (2024-07-16)\n\n### Bug Fixes\n\n- preserveWhitespace option conflicting with renderText ([#618](https://github.com/contentful/rich-text/issues/618)) ([c146dc4](https://github.com/contentful/rich-text/commit/c146dc4a89fa980f877285ab2b0b9c1114236fc9))\n\n## [15.22.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.1...@contentful/rich-text-react-renderer@15.22.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.22.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.22.0...@contentful/rich-text-react-renderer@15.22.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.22.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.21.4...@contentful/rich-text-react-renderer@15.22.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [15.21.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.21.3...@contentful/rich-text-react-renderer@15.21.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.21.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.21.2...@contentful/rich-text-react-renderer@15.21.3) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.21.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.21.1...@contentful/rich-text-react-renderer@15.21.2) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.21.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.21.0...@contentful/rich-text-react-renderer@15.21.1) (2024-05-27)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.21.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.20.0...@contentful/rich-text-react-renderer@15.21.0) (2024-05-24)\n\n### Features\n\n- add strikethrough support ([#562](https://github.com/contentful/rich-text/issues/562)) ([b87d0c3](https://github.com/contentful/rich-text/commit/b87d0c31bccb4012745c0479b2b5c92fc28c1e91))\n\n# [15.20.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.6...@contentful/rich-text-react-renderer@15.20.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [15.19.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.5...@contentful/rich-text-react-renderer@15.19.6) (2024-03-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.19.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.4...@contentful/rich-text-react-renderer@15.19.5) (2024-03-04)\n\n### Bug Fixes\n\n- 🐛 handle multiple space rendering when using preserveWhitespace ([#531](https://github.com/contentful/rich-text/issues/531)) ([982b21b](https://github.com/contentful/rich-text/commit/982b21b13736d8b1dcdb652b4eb41c7ab279ee33)), closes [#514](https://github.com/contentful/rich-text/issues/514)\n\n## [15.19.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.3...@contentful/rich-text-react-renderer@15.19.4) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.19.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.2...@contentful/rich-text-react-renderer@15.19.3) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.19.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.1...@contentful/rich-text-react-renderer@15.19.2) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.19.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.19.0...@contentful/rich-text-react-renderer@15.19.1) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.19.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.18.0...@contentful/rich-text-react-renderer@15.19.0) (2023-10-24)\n\n### Features\n\n- add default renderers for new resource nodes ([#504](https://github.com/contentful/rich-text/issues/504)) ([f748e6b](https://github.com/contentful/rich-text/commit/f748e6b0f0e22ce3809ca8881438b84b1baafb8f))\n\n# [15.18.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.17.2...@contentful/rich-text-react-renderer@15.18.0) (2023-10-02)\n\n### Features\n\n- preserve formatting linebreak whitespace ([#497](https://github.com/contentful/rich-text/issues/497)) ([e62ab92](https://github.com/contentful/rich-text/commit/e62ab92f6320d970f921e751d1753cd290224224))\n\n## [15.17.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.17.1...@contentful/rich-text-react-renderer@15.17.2) (2023-09-12)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.17.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.17.0...@contentful/rich-text-react-renderer@15.17.1) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.17.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.5...@contentful/rich-text-react-renderer@15.17.0) (2023-06-09)\n\n### Features\n\n- add default renderer for the embedded-resource-block node ([#474](https://github.com/contentful/rich-text/issues/474)) ([844c011](https://github.com/contentful/rich-text/commit/844c011ef3d6f2887d82a39784c6fb5672c6e065))\n\n## [15.16.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.4...@contentful/rich-text-react-renderer@15.16.5) (2023-05-26)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.16.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.3...@contentful/rich-text-react-renderer@15.16.4) (2023-05-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.16.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.2...@contentful/rich-text-react-renderer@15.16.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.16.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.1...@contentful/rich-text-react-renderer@15.16.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.16.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-react-renderer@15.16.0...@contentful/rich-text-react-renderer@15.16.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# 15.16.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## 15.12.1 (2022-04-21)\n\n### Bug Fixes\n\n- upgrade react peerDependencies to support react^18.0.0 ([#323](https://github.com/contentful/rich-text/issues/323)) ([7a0bfdf](https://github.com/contentful/rich-text/commit/7a0bfdfb687cca608239e072cbc301ba1b1310d1))\n\n# 15.12.0 (2022-03-25)\n\n## 15.11.1 (2022-01-04)\n\n# 15.11.0 (2021-12-27)\n\n### Bug Fixes\n\n- **react-renderer:** wrap table rows in tbody ([#300](https://github.com/contentful/rich-text/issues/300)) ([e23d1f4](https://github.com/contentful/rich-text/commit/e23d1f4f5c63ce7ded84144b271f566327a144d1))\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n## 15.9.1 (2021-12-10)\n\n# 15.9.0 (2021-12-09)\n\n# 15.7.0 (2021-11-11)\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n## 15.5.1 (2021-10-25)\n\n# 15.5.0 (2021-10-25)\n\n# 15.4.0 (2021-09-16)\n\n### Features\n\n- **html+react:** render Table header as <th> ([#269](https://github.com/contentful/rich-text/issues/269)) ([0f82905](https://github.com/contentful/rich-text/commit/0f829059be6d91e042dfc71698009177ae4ab78d))\n\n## 15.3.6 (2021-09-15)\n\n## 15.3.5 (2021-09-13)\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n# 15.2.0 (2021-08-16)\n\n### Bug Fixes\n\n- audit fix aiming mixing-deep vulnerability ([2b98cbd](https://github.com/contentful/rich-text/commit/2b98cbd8e85435305378dd91d70d55db5e9c0832))\n\n# 15.1.0 (2021-08-02)\n\n### Features\n\n- 🎸 add RT react renderer tables support ([fddfb8a](https://github.com/contentful/rich-text/commit/fddfb8a943b9807efe92b749d7ffdeb1308e42bd))\n\n# 15.0.0 (2021-06-15)\n\n## 14.1.3 (2021-04-12)\n\n## 14.1.2 (2020-11-02)\n\n## 14.0.1 (2020-01-30)\n\n# 14.0.0 (2020-01-28)\n\n# 13.4.0 (2019-08-01)\n\n### Features\n\n- 🎸 Adds BLOCKS.DOCUMENT renderer support to react-renderer ([57c922c](https://github.com/contentful/rich-text/commit/57c922cb638c47729f2189815a647ba68859394e)), closes [#104](https://github.com/contentful/rich-text/issues/104)\n\n# 13.2.0 (2019-03-18)\n\n### Features\n\n- 🎸 renderText option to alter all text ([f684a6e](https://github.com/contentful/rich-text/commit/f684a6e91d81ab0c66c286adaa923bd2edf0f4f1))\n\n# 13.1.0 (2019-03-04)\n\n## 13.0.1 (2019-02-11)\n\n### Bug Fixes\n\n- 🐛 Fix wrong import in tests ([bead583](https://github.com/contentful/rich-text/commit/bead583e6e9bb71638694e466980b90e599fa47b))\n\n### Features\n\n- 🎸 Initial rich-text-react-renderer implementation ([06dad9b](https://github.com/contentful/rich-text/commit/06dad9b0359325d8fa433438dac997fc9656d13f))\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n### Bug Fixes\n\n- upgrade react peerDependencies to support react^18.0.0 ([#323](https://github.com/contentful/rich-text/issues/323)) ([7a0bfdf](https://github.com/contentful/rich-text/commit/7a0bfdfb687cca608239e072cbc301ba1b1310d1))\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n### Bug Fixes\n\n- **react-renderer:** wrap table rows in tbody ([#300](https://github.com/contentful/rich-text/issues/300)) ([e23d1f4](https://github.com/contentful/rich-text/commit/e23d1f4f5c63ce7ded84144b271f566327a144d1))\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.4.0](https://github.com/contentful/rich-text/compare/v15.3.6...v15.4.0) (2021-09-16)\n\n### Features\n\n- **html+react:** render Table header as <th> ([#269](https://github.com/contentful/rich-text/issues/269)) ([0f82905](https://github.com/contentful/rich-text/commit/0f829059be6d91e042dfc71698009177ae4ab78d))\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.1.0...v15.2.0) (2021-08-16)\n\n### Bug Fixes\n\n- audit fix aiming mixing-deep vulnerability ([2b98cbd](https://github.com/contentful/rich-text/commit/2b98cbd8e85435305378dd91d70d55db5e9c0832))\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n### Features\n\n- 🎸 add RT react renderer tables support ([fddfb8a](https://github.com/contentful/rich-text/commit/fddfb8a943b9807efe92b749d7ffdeb1308e42bd))\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n**Note:** Version bump only for package @contentful/rich-text-react-renderer\n\n## [14.1.3](https://github.com/contentful/rich-text/compare/v14.1.2...v14.1.3) (2021-04-12)\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n### Features\n\n- 🎸 Adds BLOCKS.DOCUMENT renderer support to react-renderer ([57c922c](https://github.com/contentful/rich-text/commit/57c922cb638c47729f2189815a647ba68859394e)), closes [#104](https://github.com/contentful/rich-text/issues/104)\n\n# [13.2.0](https://github.com/contentful/rich-text/compare/v13.1.0...v13.2.0) (2019-03-18)\n\n### Features\n\n- 🎸 renderText option to alter all text ([f684a6e](https://github.com/contentful/rich-text/commit/f684a6e91d81ab0c66c286adaa923bd2edf0f4f1))\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n## [13.0.1](https://github.com/contentful/rich-text/compare/v13.0.0...v13.0.1) (2019-02-11)\n\n### Bug Fixes\n\n- 🐛 Fix wrong import in tests ([bead583](https://github.com/contentful/rich-text/commit/bead583e6e9bb71638694e466980b90e599fa47b))\n\n### Features\n\n- 🎸 Initial rich-text-react-renderer implementation ([06dad9b](https://github.com/contentful/rich-text/commit/06dad9b0359325d8fa433438dac997fc9656d13f))\n"
  },
  {
    "path": "packages/rich-text-react-renderer/README.md",
    "content": "# rich-text-react-renderer\n\nReact renderer for the Contentful rich text field type.\n\n## Installation\n\nUsing [npm](http://npmjs.org/):\n\n```sh\nnpm install @contentful/rich-text-react-renderer\n```\n\nUsing [yarn](https://yarnpkg.com/):\n\n```sh\nyarn add @contentful/rich-text-react-renderer\n```\n\n## Usage\n\n```javascript\nimport { documentToReactComponents } from '@contentful/rich-text-react-renderer';\n\nconst document = {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n};\n\ndocumentToReactComponents(document); // -> <p>Hello world!</p>\n```\n\n```javascript\nimport { documentToReactComponents } from '@contentful/rich-text-react-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello',\n          marks: [{ type: 'bold' }],\n        },\n        {\n          nodeType: 'text',\n          value: ' world!',\n          marks: [{ type: 'italic' }],\n        },\n      ],\n    },\n  ],\n};\n\ndocumentToReactComponents(document);\n// -> <p><b>Hello</b><u> world!</u></p>\n```\n\nYou can also pass custom renderers for both marks and nodes as an optional parameter like so:\n\n```javascript\nimport { BLOCKS, MARKS } from '@contentful/rich-text-types';\nimport { documentToReactComponents } from '@contentful/rich-text-react-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello',\n          marks: [{ type: 'bold' }],\n        },\n        {\n          nodeType: 'text',\n          value: ' world!',\n          marks: [{ type: 'italic' }],\n        },\n      ],\n    },\n  ],\n};\n\nconst Bold = ({ children }) => <p className=\"bold\">{children}</p>;\n\nconst Text = ({ children }) => <p className=\"align-center\">{children}</p>;\n\nconst options = {\n  renderMark: {\n    [MARKS.BOLD]: (text) => <Bold>{text}</Bold>,\n  },\n  renderNode: {\n    [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,\n  },\n  renderText: (text) => text.replace('!', '?'),\n};\n\ndocumentToReactComponents(document, options);\n// -> <p class=\"align-center\"><p class=\"bold\">Hello</p><u> world?</u></p>\n```\n\nLast, but not least, you can pass a custom rendering component for an embedded entry:\n\n```javascript\nimport { BLOCKS } from '@contentful/rich-text-types';\nimport { documentToReactComponents } from '@contentful/rich-text-react-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'embedded-entry-block',\n      data: {\n        target: (...)Link<'Entry'>(...);\n      },\n    },\n  ]\n};\n\nconst CustomComponent = ({ title, description }) => (\n  <div>\n    <h2>{title}</h2>\n    <p>{description}</p>\n  </div>\n);\n\nconst options = {\n  renderNode: {\n    [BLOCKS.EMBEDDED_ENTRY]: (node) => {\n      const { title, description } = node.data.target.fields;\n      return <CustomComponent title={title} description={description} />\n    }\n  }\n};\n\ndocumentToReactComponents(document, options);\n// -> <div><h2>[title]</h2><p>[description]</p></div>\n```\n\nThe `renderNode` keys should be one of the following `BLOCKS` and `INLINES` properties as defined in [`@contentful/rich-text-types`](https://www.npmjs.com/package/@contentful/rich-text-types):\n\n- `BLOCKS`\n  - `DOCUMENT`\n  - `PARAGRAPH`\n  - `HEADING_1`\n  - `HEADING_2`\n  - `HEADING_3`\n  - `HEADING_4`\n  - `HEADING_5`\n  - `HEADING_6`\n  - `UL_LIST`\n  - `OL_LIST`\n  - `LIST_ITEM`\n  - `QUOTE`\n  - `HR`\n  - `EMBEDDED_ENTRY`\n  - `EMBEDDED_ASSET`\n  - `EMBEDDED_RESOURCE`\n\n- `INLINES`\n  - `EMBEDDED_ENTRY` (this is different from the `BLOCKS.EMBEDDED_ENTRY`)\n  - `EMBEDDED_RESOURCE`\n  - `HYPERLINK`\n  - `ENTRY_HYPERLINK`\n  - `ASSET_HYPERLINK`\n  - `RESOURCE_HYPERLINK`\n\nThe `renderMark` keys should be one of the following `MARKS` properties as defined in [`@contentful/rich-text-types`](https://www.npmjs.com/package/@contentful/rich-text-types):\n\n- `BOLD`\n- `ITALIC`\n- `UNDERLINE`\n- `CODE`\n\nThe `renderText` callback is a function that has a single string argument and returns a React node. Each text node is evaluated individually by this callback. A possible use case for this is to replace instances of `\\n` produced by `Shift + Enter` with `<br/>` React elements. This could be accomplished in the following way:\n\n```javascript\nconst options = {\n  renderText: (text) => {\n    return text.split('\\n').reduce((children, textSegment, index) => {\n      return [...children, index > 0 && <br key={index} />, textSegment];\n    }, []);\n  },\n};\n```\n\n#### Note on adding a `key` prop in custom renderers:\n\nIt is possible to pass a `key` prop in the components returned by custom renderers. A good use case for this is in embeded entries using the node's `target.sys.id`. It is important not to pass anything that is index-like (e.g. 1 or \"1\") as it may clash with the default renderers which automatically inject a `key` prop using their index in the Contentful rich text AST.\n\nTo work around this limitation, just append any non-numeric character to your custom key.\n\n```javascript\nconst options = {\n  renderMark: {\n    [MARKS.BOLD]: (text) => {\n      return <b key={`${text}-key`}>{text}</b>;\n    },\n  },\n};\n```\n\n#### Preserving Whitespace\n\nThe `options` object can include a `preserveWhitespace` boolean flag. When set to `true`, this flag ensures that multiple spaces in the rich text content are preserved by replacing them with `&nbsp;`, and line breaks are maintained with `<br />` tags. This is useful for content that relies on specific formatting using spaces and line breaks.\n\nNote that `preserveWhitespace` is not compatible with the `renderText` option. When the functionality of `preserveWhitespace` is desired along with a custom `renderText` callback, it should be implemented within the callback instead.\n\n```javascript\nimport { documentToReactComponents } from '@contentful/rich-text-react-renderer';\n\nconst document = {\n  nodeType: 'document',\n  content: [\n    {\n      nodeType: 'paragraph',\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello     world!',\n          marks: [],\n        },\n      ],\n    },\n  ],\n};\n\nconst options = {\n  preserveWhitespace: true,\n};\n\ndocumentToReactComponents(document, options);\n// -> <p>Hello&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world!</p>\n```\n\nIn this example, the multiple spaces between \"Hello\" and \"world!\" are preserved in the rendered output.\n"
  },
  {
    "path": "packages/rich-text-react-renderer/jest.config.js",
    "content": "const getBaseConfig = require('../../baseJestConfig');\nconst package = require('./package.json');\nconst packageName = package.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-react-renderer/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-react-renderer\",\n  \"version\": \"16.2.1\",\n  \"main\": \"dist/rich-text-react-renderer.es5.js\",\n  \"module\": \"dist/rich-text-react-renderer.esm.js\",\n  \"typings\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/rich-text-react-renderer.esm.js\",\n      \"require\": \"./dist/rich-text-react-renderer.es5.js\",\n      \"default\": \"./dist/rich-text-react-renderer.es5.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"tsc --module commonjs && rollup -c --bundleConfigAsCjs rollup.config.js\",\n    \"start\": \"tsc && rollup -c --bundleConfigAsCjs rollup.config.js -w\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@contentful/rich-text-types\": \"^17.2.7\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.6 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.6 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^19.2.8\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"react\": \"^19.2.3\",\n    \"react-dom\": \"^19.2.3\",\n    \"ts-jest\": \"^29.4.6\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/rollup.config.js",
    "content": "import config from '../../rollup.config';\nimport { main as outputFile, dependencies } from './package.json';\n\nconst overrides = {\n  input: 'src/index.tsx',\n  external: [...Object.keys(dependencies), 'react'],\n};\n\nexport default config(outputFile, overrides);\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/__snapshots__/index.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`documentToReactComponents does not render unrecognized marks 1`] = `\n[\n  <p>\n    Hello world!\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders asset hyperlink 1`] = `\n[\n  <p>\n    <span>\n      type: \n      asset-hyperlink\n       id: \n      9mpxT4zsRi6Iwukey8KeM\n    </span>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders blockquotes 1`] = `\n[\n  <p>\n    hello\n  </p>,\n  <blockquote>\n    world\n  </blockquote>,\n]\n`;\n\nexports[`documentToReactComponents renders default entry link block 1`] = `\n[\n  <div />,\n]\n`;\n\nexports[`documentToReactComponents renders default resource block 1`] = `\n[\n  <div />,\n]\n`;\n\nexports[`documentToReactComponents renders embedded entry 1`] = `\n[\n  <p>\n    <span>\n      type: \n      embedded-entry-inline\n       id: \n      9mpxT4zsRi6Iwukey8KeM\n    </span>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders embedded resource 1`] = `\n[\n  <p>\n    <span>\n      type: \n      embedded-resource-inline\n       urn: \n      crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM\n    </span>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders empty node if type is not recognized 1`] = `\n[\n  <React.Fragment>\n    Hello world!\n  </React.Fragment>,\n]\n`;\n\nexports[`documentToReactComponents renders entry hyperlink 1`] = `\n[\n  <p>\n    <span>\n      type: \n      entry-hyperlink\n       id: \n      9mpxT4zsRi6Iwukey8KeM\n    </span>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders horizontal rule 1`] = `\n[\n  <p>\n    hello world\n  </p>,\n  <hr />,\n  <p />,\n]\n`;\n\nexports[`documentToReactComponents renders hyperlink 1`] = `\n[\n  <p>\n    Some text \n    <a\n      href=\"https://url.org\"\n    >\n      link\n    </a>\n     text.\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 1`] = `\n[\n  <p>\n    <i>\n      hello world\n    </i>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 2`] = `\n[\n  <p>\n    <b>\n      hello world\n    </b>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 3`] = `\n[\n  <p>\n    <u>\n      hello world\n    </u>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 4`] = `\n[\n  <p>\n    <code>\n      hello world\n    </code>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 5`] = `\n[\n  <p>\n    <sup>\n      hello world\n    </sup>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 6`] = `\n[\n  <p>\n    <sub>\n      hello world\n    </sub>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with default mark renderer 7`] = `\n[\n  <p>\n    <s>\n      hello world\n    </s>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders marks with the passed custom mark renderer 1`] = `\n[\n  <p>\n    <i>\n      <Strong>\n        hello world\n      </Strong>\n    </i>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders multiple marks with default mark renderer 1`] = `\n[\n  <p>\n    <i>\n      <b>\n        hello world\n      </b>\n    </i>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 1`] = `\n[\n  <p>\n    hello world\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 2`] = `\n[\n  <h1>\n    hello world\n  </h1>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 3`] = `\n[\n  <h2>\n    hello world\n  </h2>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 4`] = `\n[\n  <h3>\n    hello world\n  </h3>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 5`] = `\n[\n  <h4>\n    hello world\n  </h4>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 6`] = `\n[\n  <h5>\n    hello world\n  </h5>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with default node renderer 7`] = `\n[\n  <h6>\n    hello world\n  </h6>,\n]\n`;\n\nexports[`documentToReactComponents renders nodes with passed custom node renderer 1`] = `\n<Document>\n  <Paragraph>\n    hello\n  </Paragraph>\n  <blockquote>\n    world\n  </blockquote>\n</Document>\n`;\n\nexports[`documentToReactComponents renders ordered lists 1`] = `\n[\n  <ol>\n    <li>\n      <p>\n        Hello\n      </p>\n    </li>\n    <li>\n      <p>\n        world\n      </p>\n    </li>\n  </ol>,\n  <p />,\n]\n`;\n\nexports[`documentToReactComponents renders resource hyperlink 1`] = `\n[\n  <p>\n    <span>\n      type: \n      resource-hyperlink\n       urn: \n      crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM\n    </span>\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders tables 1`] = `\n[\n  <table>\n    <tbody>\n      <tr>\n        <td>\n          <p>\n            A 1\n          </p>\n        </td>\n        <td>\n          <p>\n            B 1\n          </p>\n        </td>\n      </tr>\n      <tr>\n        <td>\n          <p>\n            A 2\n          </p>\n        </td>\n        <td>\n          <p>\n            B 2\n          </p>\n        </td>\n      </tr>\n    </tbody>\n  </table>,\n]\n`;\n\nexports[`documentToReactComponents renders tables with header 1`] = `\n[\n  <table>\n    <tbody>\n      <tr>\n        <th>\n          <p>\n            A 1\n          </p>\n        </th>\n        <th>\n          <p>\n            B 1\n          </p>\n        </th>\n      </tr>\n      <tr>\n        <td>\n          <p>\n            A 2\n          </p>\n        </td>\n        <td>\n          <p>\n            B 2\n          </p>\n        </td>\n      </tr>\n    </tbody>\n  </table>,\n]\n`;\n\nexports[`documentToReactComponents renders text with the passed custom text renderer 1`] = `\n[\n  <p>\n    hello Earth\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders unaltered text with default text renderer 1`] = `\n[\n  <p>\n    hello world\n  </p>,\n]\n`;\n\nexports[`documentToReactComponents renders unordered lists 1`] = `\n[\n  <ul>\n    <li>\n      <p>\n        Hello\n      </p>\n    </li>\n    <li>\n      <p>\n        world\n      </p>\n    </li>\n  </ul>,\n  <p />,\n]\n`;\n\nexports[`documentToReactComponents returns an array of elements when given a populated document 1`] = `\n[\n  <p>\n    hello world\n  </p>,\n  <hr />,\n  <p />,\n]\n`;\n\nexports[`nodeListToReactComponents renders children as an array with keys from its index 1`] = `\n[\n  <p>\n    <b>\n      hello\n    </b>\n  </p>,\n  \" \",\n  <p>\n    world\n  </p>,\n]\n`;\n\nexports[`nodeToReactComponent does not add additional tags on invalid marks 1`] = `\"hello world\"`;\n\nexports[`nodeToReactComponent does not render altered text with default text renderer 1`] = `\n<p>\n  <b>\n    some\nlines\nof\ntext\n  </b>\n</p>\n`;\n\nexports[`nodeToReactComponent renders altered text with custom text renderer 1`] = `\n<p>\n  <b>\n    some\n    <br />\n    lines\n    <br />\n    of\n    <br />\n    text\n  </b>\n</p>\n`;\n\nexports[`nodeToReactComponent renders invalid node types in React fragments 1`] = `\n<React.Fragment>\n  hello world\n</React.Fragment>\n`;\n\nexports[`nodeToReactComponent renders valid marks 1`] = `\n<b>\n  hello world\n</b>\n`;\n\nexports[`nodeToReactComponent renders valid nodes 1`] = `\n<p>\n  hello world\n</p>\n`;\n\nexports[`preserveWhitespace preserves new lines 1`] = `\n[\n  <p>\n    hello\n    <br />\n    world\n  </p>,\n]\n`;\n\nexports[`preserveWhitespace preserves spaces between words 1`] = `\n[\n  <p>\n    hello    world\n  </p>,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph does not strip empty trailing paragraph when disabled 1`] = `\n[\n  <p>\n    Hello world\n  </p>,\n  <p />,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph does not strip empty trailing paragraph when it is the only child 1`] = `\n[\n  <p />,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph does not strip non-empty trailing paragraph 1`] = `\n[\n  <p>\n    Hello world\n  </p>,\n  <p>\n    Not empty\n  </p>,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph does not strip trailing non-paragraph node 1`] = `\n[\n  <p>\n    Hello world\n  </p>,\n  <h1 />,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph does not strip trailing paragraph with multiple text nodes 1`] = `\n[\n  <p>\n    Hello world\n  </p>,\n  <p />,\n]\n`;\n\nexports[`stripEmptyTrailingParagraph strips empty trailing paragraph when enabled 1`] = `\n[\n  <p>\n    Hello world\n  </p>,\n]\n`;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/components/Document.tsx",
    "content": "import React, { FunctionComponent, ReactNode } from 'react';\n\ntype DocumentProps = {\n  children: ReactNode;\n};\n\nconst Document: FunctionComponent<DocumentProps> = ({ children }) => {\n  return <section>{children}</section>;\n};\n\nexport default Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/components/Paragraph.tsx",
    "content": "import React, { FunctionComponent, ReactNode } from 'react';\n\ntype ParagraphProps = {\n  children: ReactNode;\n};\n\nconst Paragraph: FunctionComponent<ParagraphProps> = ({ children }) => {\n  return <p>{children}</p>;\n};\n\nexport default Paragraph;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/components/Strong.tsx",
    "content": "import React, { FunctionComponent, ReactNode } from 'react';\n\ntype StrongProps = {\n  children: ReactNode;\n};\n\nconst Strong: FunctionComponent<StrongProps> = ({ children }) => {\n  return <strong>{children}</strong>;\n};\n\nexport default Strong;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/embedded-entry.ts",
    "content": "import { BLOCKS, Document } from '@contentful/rich-text-types';\n\nexport default function (entry: Record<string, any>) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: BLOCKS.EMBEDDED_ENTRY,\n        content: [],\n        data: {\n          target: entry,\n        },\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/embedded-resource.ts",
    "content": "import { Document, BLOCKS, ResourceLink } from '@contentful/rich-text-types';\n\nexport default function (resourceLink: ResourceLink) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: BLOCKS.EMBEDDED_RESOURCE,\n        content: [],\n        data: {\n          target: resourceLink,\n        },\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/heading.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default function (heading: string) {\n  return {\n    nodeType: BLOCKS.DOCUMENT,\n    data: {},\n    content: [\n      {\n        nodeType: heading,\n        data: {},\n        content: [\n          {\n            nodeType: 'text',\n            value: 'hello world',\n            marks: [],\n            data: {},\n          },\n        ],\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/hr.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  content: [\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: 'hello world',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'paragraph',\n    },\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: '',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'hr',\n    },\n    {\n      content: [\n        {\n          marks: [],\n          nodeType: 'text',\n          value: '',\n          data: {},\n        },\n      ],\n      data: {},\n      nodeType: 'paragraph',\n    },\n  ],\n  data: {},\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/hyperlink.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Some text ',\n          marks: [],\n          data: {},\n        },\n        {\n          nodeType: 'hyperlink',\n          content: [\n            {\n              nodeType: 'text',\n              value: 'link',\n              marks: [],\n              data: {},\n            },\n          ],\n          data: {\n            uri: 'https://url.org',\n          },\n        },\n        {\n          nodeType: 'text',\n          value: ' text.',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/index.ts",
    "content": "export { default as hrDoc } from './hr';\nexport { default as hyperlinkDoc } from './hyperlink';\nexport { default as invalidMarksDoc } from './invalid-marks';\nexport { default as invalidTypeDoc } from './invalid-type';\nexport { default as paragraphDoc } from './paragraph';\nexport { default as headingDoc } from './heading';\nexport { default as marksDoc } from './mark';\nexport { default as multiMarkDoc } from './multi-mark';\nexport { default as embeddedEntryDoc } from './embedded-entry';\nexport { default as embeddedResourceDoc } from './embedded-resource';\nexport { default as inlineEntityDoc } from './inline-entity';\nexport { default as olDoc } from './ol';\nexport { default as ulDoc } from './ul';\nexport { default as quoteDoc } from './quote';\nexport { default as tableDoc } from './table';\nexport { default as tableWithHeaderDoc } from './table-header';\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/inline-entity.ts",
    "content": "import { BLOCKS, Document, INLINES } from '@contentful/rich-text-types';\n\nexport default function inlineEntity(entry: Record<string, any>, inlineType: INLINES) {\n  return {\n    content: [\n      {\n        data: {},\n        content: [\n          {\n            marks: [],\n            value: '',\n            nodeType: 'text',\n            data: {},\n          },\n          {\n            data: entry,\n            content: [\n              {\n                marks: [],\n                value: '',\n                nodeType: 'text',\n                data: {},\n              },\n            ],\n            nodeType: inlineType,\n          },\n          {\n            marks: [],\n            value: '',\n            nodeType: 'text',\n            data: {},\n          },\n        ],\n        nodeType: BLOCKS.PARAGRAPH,\n      },\n    ],\n    data: {},\n    nodeType: BLOCKS.DOCUMENT,\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/invalid-marks.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [\n            {\n              type: 'UNRECOGNIZED_MARK',\n            },\n          ],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/invalid-type.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: 'UNRECOGNIZED_TYPE' as BLOCKS,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'Hello world!',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/mark.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default function (mark: string) {\n  return {\n    nodeType: 'document',\n    data: {},\n    content: [\n      {\n        nodeType: 'paragraph',\n        data: {},\n        content: [\n          {\n            nodeType: 'text',\n            value: 'hello world',\n            marks: [{ type: mark }],\n            data: {},\n          },\n        ],\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/multi-mark.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\nexport default function () {\n  return {\n    nodeType: 'document',\n    data: {},\n    content: [\n      {\n        nodeType: 'paragraph',\n        data: {},\n        content: [\n          {\n            nodeType: 'text',\n            value: 'hello world',\n            marks: [{ type: 'bold' }, { type: 'italic' }],\n            data: {},\n          },\n        ],\n      },\n    ],\n  } as Document;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/ol.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'Hello',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'world',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n      ],\n      nodeType: 'ordered-list',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: '',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/paragraph.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: 'document',\n  data: {},\n  content: [\n    {\n      nodeType: 'paragraph',\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'hello world',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/quote.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: 'hello',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: 'world',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'blockquote',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/table-header.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.TABLE,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_HEADER_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 1',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_HEADER_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 1',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 2',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 2',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/table.ts",
    "content": "import { Document, BLOCKS } from '@contentful/rich-text-types';\n\nexport default {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.TABLE,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 1',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 1',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.TABLE_ROW,\n          data: {},\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'A 2',\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              nodeType: BLOCKS.TABLE_CELL,\n              data: {},\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  data: {},\n                  content: [\n                    {\n                      nodeType: 'text',\n                      data: {},\n                      marks: [],\n                      value: 'B 2',\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/documents/ul.ts",
    "content": "import { Document } from '@contentful/rich-text-types';\n\nexport default {\n  data: {},\n  content: [\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'Hello',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n        {\n          data: {},\n          content: [\n            {\n              data: {},\n              content: [\n                {\n                  data: {},\n                  marks: [],\n                  value: 'world',\n                  nodeType: 'text',\n                },\n              ],\n              nodeType: 'paragraph',\n            },\n          ],\n          nodeType: 'list-item',\n        },\n      ],\n      nodeType: 'unordered-list',\n    },\n    {\n      data: {},\n      content: [\n        {\n          data: {},\n          marks: [],\n          value: '',\n          nodeType: 'text',\n        },\n      ],\n      nodeType: 'paragraph',\n    },\n  ],\n  nodeType: 'document',\n} as Document;\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/__test__/index.test.tsx",
    "content": "import React, { ReactNode } from 'react';\n\nimport { BLOCKS, Document, INLINES, MARKS, ResourceLink } from '@contentful/rich-text-types';\n\nimport { CommonNode, documentToReactComponents, Options } from '..';\n\nimport { appendKeyToValidElement } from '../util/appendKeyToValidElement';\nimport { nodeListToReactComponents, nodeToReactComponent } from '../util/nodeListToReactComponents';\nimport DocumentWrapper from './components/Document';\nimport Paragraph from './components/Paragraph';\nimport Strong from './components/Strong';\nimport {\n  embeddedEntryDoc,\n  headingDoc,\n  hrDoc,\n  hyperlinkDoc,\n  inlineEntityDoc,\n  invalidMarksDoc,\n  invalidTypeDoc,\n  marksDoc,\n  multiMarkDoc,\n  olDoc,\n  paragraphDoc,\n  quoteDoc,\n  tableDoc,\n  tableWithHeaderDoc,\n  ulDoc,\n} from './documents';\nimport embeddedResource from './documents/embedded-resource';\n\ndescribe('documentToReactComponents', () => {\n  it('returns an empty array when given an empty document', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [],\n    };\n\n    expect(documentToReactComponents(document)).toEqual([]);\n  });\n\n  it('returns an array of elements when given a populated document', () => {\n    const document: Document = hrDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n    expect(documentToReactComponents(document)).toBeInstanceOf(Array);\n  });\n\n  it('renders nodes with default node renderer', () => {\n    const docs: Document[] = [\n      paragraphDoc,\n      headingDoc(BLOCKS.HEADING_1),\n      headingDoc(BLOCKS.HEADING_2),\n      headingDoc(BLOCKS.HEADING_3),\n      headingDoc(BLOCKS.HEADING_4),\n      headingDoc(BLOCKS.HEADING_5),\n      headingDoc(BLOCKS.HEADING_6),\n    ];\n\n    docs.forEach((doc) => {\n      expect(documentToReactComponents(doc)).toMatchSnapshot();\n    });\n  });\n\n  it('renders marks with default mark renderer', () => {\n    const docs: Document[] = [\n      marksDoc(MARKS.ITALIC),\n      marksDoc(MARKS.BOLD),\n      marksDoc(MARKS.UNDERLINE),\n      marksDoc(MARKS.CODE),\n      marksDoc(MARKS.SUPERSCRIPT),\n      marksDoc(MARKS.SUBSCRIPT),\n      marksDoc(MARKS.STRIKETHROUGH),\n    ];\n\n    docs.forEach((doc) => {\n      expect(documentToReactComponents(doc)).toMatchSnapshot();\n    });\n  });\n\n  it('renders unaltered text with default text renderer', () => {\n    const document: Document = paragraphDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders multiple marks with default mark renderer', () => {\n    const doc: Document = multiMarkDoc();\n    expect(documentToReactComponents(doc)).toMatchSnapshot();\n  });\n\n  it('renders nodes with passed custom node renderer', () => {\n    const options: Options = {\n      renderNode: {\n        [BLOCKS.DOCUMENT]: (node, children) => <DocumentWrapper>{children}</DocumentWrapper>,\n        [BLOCKS.PARAGRAPH]: (node, children) => <Paragraph>{children}</Paragraph>,\n      },\n    };\n    const document: Document = quoteDoc;\n    expect(documentToReactComponents(document, options)).toMatchSnapshot();\n  });\n\n  it('renders marks with the passed custom mark renderer', () => {\n    const options: Options = {\n      renderMark: {\n        [MARKS.BOLD]: (text) => <Strong>{text}</Strong>,\n      },\n    };\n    const document: Document = multiMarkDoc();\n\n    expect(documentToReactComponents(document, options)).toMatchSnapshot();\n  });\n\n  it('renders text with the passed custom text renderer', () => {\n    const options: Options = {\n      renderText: (text) => text.replace(/world/, 'Earth'),\n    };\n    const document: Document = paragraphDoc;\n\n    expect(documentToReactComponents(document, options)).toMatchSnapshot();\n  });\n\n  it('does not render unrecognized marks', () => {\n    const document: Document = invalidMarksDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders empty node if type is not recognized', () => {\n    const document: Document = invalidTypeDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders default entry link block', () => {\n    const entrySys = {\n      sys: {\n        id: '9mpxT4zsRi6Iwukey8KeM',\n        link: 'Link',\n        linkType: 'Entry',\n      },\n    };\n    const document: Document = embeddedEntryDoc(entrySys);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders default resource block', () => {\n    const resourceSys: ResourceLink = {\n      sys: {\n        urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n        type: 'ResourceLink',\n        linkType: 'Contentful:Entry',\n      },\n    };\n    const document: Document = embeddedResource(resourceSys);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders ordered lists', () => {\n    const document: Document = olDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders unordered lists', () => {\n    const document: Document = ulDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders blockquotes', () => {\n    const document: Document = quoteDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders horizontal rule', () => {\n    const document: Document = hrDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders tables', () => {\n    const document: Document = tableDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders tables with header', () => {\n    expect(documentToReactComponents(tableWithHeaderDoc)).toMatchSnapshot();\n  });\n\n  it('does not crash with inline elements (e.g. hyperlink)', () => {\n    const document: Document = hyperlinkDoc;\n\n    expect(documentToReactComponents(document)).toBeTruthy();\n  });\n\n  it('renders hyperlink', () => {\n    const document: Document = hyperlinkDoc;\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n\n  it('renders asset hyperlink', () => {\n    const asset = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          link: 'Link',\n          type: 'Asset',\n        },\n      },\n    };\n    const document: Document = inlineEntityDoc(asset, INLINES.ASSET_HYPERLINK);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n  it('renders entry hyperlink', () => {\n    const entry = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntityDoc(entry, INLINES.ENTRY_HYPERLINK);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n  it('renders resource hyperlink', () => {\n    const entry = {\n      target: {\n        sys: {\n          urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntityDoc(entry, INLINES.RESOURCE_HYPERLINK);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n  it('renders embedded entry', () => {\n    const entry = {\n      target: {\n        sys: {\n          id: '9mpxT4zsRi6Iwukey8KeM',\n          type: 'Link',\n          linkType: 'Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntityDoc(entry, INLINES.EMBEDDED_ENTRY);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n  it('renders embedded resource', () => {\n    const entry = {\n      target: {\n        sys: {\n          urn: 'crn:contentful:::content:spaces/6fqi4ljzyr0e/environments/master/entries/9mpxT4zsRi6Iwukey8KeM',\n          type: 'ResourceLink',\n          linkType: 'Contentful:Entry',\n        },\n      },\n    };\n    const document: Document = inlineEntityDoc(entry, INLINES.EMBEDDED_RESOURCE);\n\n    expect(documentToReactComponents(document)).toMatchSnapshot();\n  });\n});\n\ndescribe('appendKeyToValidElement', () => {\n  it('appends keys to default React components', () => {\n    expect(appendKeyToValidElement(<div />, 0)).toHaveProperty('key', '0');\n  });\n\n  it('appends keys to custom React components', () => {\n    expect(appendKeyToValidElement(<Paragraph>hello world</Paragraph>, 0)).toHaveProperty(\n      'key',\n      '0',\n    );\n  });\n\n  it('does not overwrite user specified keys', () => {\n    expect(appendKeyToValidElement(<div key={'xyz'} />, 0)).toHaveProperty('key', 'xyz');\n  });\n\n  it('does not add keys to text nodes', () => {\n    expect(appendKeyToValidElement('hello world', 0)).not.toHaveProperty('key');\n  });\n\n  it('does not add keys to node arrays', () => {\n    expect(appendKeyToValidElement([<div key={0} />, <div key={1} />], 0)).not.toHaveProperty(\n      'key',\n    );\n  });\n\n  it('does not add keys to null', () => {\n    expect(appendKeyToValidElement(null, 0)).toBeNull();\n  });\n});\n\ndescribe('nodeToReactComponent', () => {\n  const options: Options = {\n    renderNode: {\n      [BLOCKS.PARAGRAPH]: (node: CommonNode, children: ReactNode): ReactNode => <p>{children}</p>,\n    },\n    renderMark: {\n      [MARKS.BOLD]: (text: ReactNode): ReactNode => <b>{text}</b>,\n    },\n  };\n\n  const createBlockNode = (nodeType: BLOCKS): CommonNode => ({\n    nodeType,\n    data: {},\n    content: [\n      {\n        nodeType: 'text',\n        value: 'hello world',\n        marks: [],\n        data: {},\n      },\n    ],\n  });\n\n  const createTextNode = (type: string): CommonNode => ({\n    nodeType: 'text',\n    value: 'hello world',\n    marks: [{ type }],\n    data: {},\n  });\n\n  it('renders valid nodes', () => {\n    expect(nodeToReactComponent(createBlockNode(BLOCKS.PARAGRAPH), options)).toMatchSnapshot();\n  });\n\n  it('renders invalid node types in React fragments', () => {\n    expect(nodeToReactComponent(createBlockNode(BLOCKS.HEADING_1), options)).toMatchSnapshot();\n  });\n\n  it('renders valid marks', () => {\n    expect(nodeToReactComponent(createTextNode(MARKS.BOLD), options)).toMatchSnapshot();\n  });\n\n  it('does not add additional tags on invalid marks', () => {\n    expect(nodeToReactComponent(createTextNode(MARKS.ITALIC), options)).toMatchSnapshot();\n  });\n\n  const customTextNode: CommonNode = {\n    nodeType: BLOCKS.PARAGRAPH,\n    data: {},\n    content: [\n      {\n        nodeType: 'text',\n        value: 'some\\nlines\\nof\\ntext',\n        marks: [{ type: MARKS.BOLD }],\n        data: {},\n      },\n    ],\n  };\n\n  it('does not render altered text with default text renderer', () => {\n    expect(nodeToReactComponent(customTextNode, options)).toMatchSnapshot();\n  });\n\n  it('renders altered text with custom text renderer', () => {\n    expect(\n      nodeToReactComponent(customTextNode, {\n        ...options,\n        renderText: (text: string): ReactNode => {\n          return text.split('\\n').reduce((children, textSegment, index) => {\n            return [...children, index > 0 && <br key={index} />, textSegment];\n          }, []);\n        },\n      }),\n    ).toMatchSnapshot();\n  });\n});\n\ndescribe('nodeListToReactComponents', () => {\n  const options: Options = {\n    renderNode: {\n      [BLOCKS.PARAGRAPH]: (node: CommonNode, children: ReactNode): ReactNode => <p>{children}</p>,\n    },\n    renderMark: {\n      [MARKS.BOLD]: (text: ReactNode): ReactNode => <b>{text}</b>,\n    },\n  };\n\n  const nodes: CommonNode[] = [\n    {\n      nodeType: BLOCKS.PARAGRAPH,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'hello',\n          marks: [{ type: MARKS.BOLD }],\n          data: {},\n        },\n      ],\n    },\n    {\n      nodeType: 'text',\n      value: ' ',\n      marks: [],\n      data: {},\n    },\n    {\n      nodeType: BLOCKS.PARAGRAPH,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: 'world',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ];\n\n  it('renders children as an array with keys from its index', () => {\n    const renderedNodes: ReactNode[] = nodeListToReactComponents(nodes, options) as ReactNode[];\n    expect(renderedNodes[0]).toHaveProperty('key', '0');\n    expect(renderedNodes[1]).not.toHaveProperty('key');\n    expect(renderedNodes[2]).toHaveProperty('key', '2');\n    expect(renderedNodes).toMatchSnapshot();\n  });\n});\n\ndescribe('preserveWhitespace', () => {\n  it('preserves spaces between words', () => {\n    const options: Options = {\n      preserveWhitespace: true,\n    };\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'hello    world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    expect(documentToReactComponents(document, options)).toMatchSnapshot();\n  });\n\n  it('preserves new lines', () => {\n    const options: Options = {\n      preserveWhitespace: true,\n    };\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'hello\\nworld',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n    expect(documentToReactComponents(document, options)).toMatchSnapshot();\n  });\n});\n\ndescribe('stripEmptyTrailingParagraph', () => {\n  it('strips empty trailing paragraph when enabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n\n  it('does not strip empty trailing paragraph when disabled', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: false,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n\n  it('does not strip empty trailing paragraph when it is the only child', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n\n  it('does not strip non-empty trailing paragraph', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Not empty',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n\n  it('does not strip trailing paragraph with multiple text nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n\n  it('does not strip trailing non-paragraph node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      data: {},\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: 'Hello world',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n        {\n          nodeType: BLOCKS.HEADING_1,\n          data: {},\n          content: [\n            {\n              nodeType: 'text',\n              value: '',\n              marks: [],\n              data: {},\n            },\n          ],\n        },\n      ],\n    };\n\n    const options: Options = {\n      stripEmptyTrailingParagraph: true,\n    };\n\n    const result = documentToReactComponents(document, options);\n    expect(result).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/index.tsx",
    "content": "import React, { ReactNode } from 'react';\n\nimport {\n  Block,\n  BLOCKS,\n  Document,\n  Inline,\n  INLINES,\n  MARKS,\n  Text,\n  helpers,\n} from '@contentful/rich-text-types';\n\nimport { nodeToReactComponent } from './util/nodeListToReactComponents';\n\nconst defaultNodeRenderers: RenderNode = {\n  [BLOCKS.DOCUMENT]: (node, children) => children,\n  [BLOCKS.PARAGRAPH]: (node, children) => <p>{children}</p>,\n  [BLOCKS.HEADING_1]: (node, children) => <h1>{children}</h1>,\n  [BLOCKS.HEADING_2]: (node, children) => <h2>{children}</h2>,\n  [BLOCKS.HEADING_3]: (node, children) => <h3>{children}</h3>,\n  [BLOCKS.HEADING_4]: (node, children) => <h4>{children}</h4>,\n  [BLOCKS.HEADING_5]: (node, children) => <h5>{children}</h5>,\n  [BLOCKS.HEADING_6]: (node, children) => <h6>{children}</h6>,\n  [BLOCKS.EMBEDDED_ENTRY]: (node, children) => <div>{children}</div>,\n  [BLOCKS.EMBEDDED_RESOURCE]: (node, children) => <div>{children}</div>,\n  [BLOCKS.UL_LIST]: (node, children) => <ul>{children}</ul>,\n  [BLOCKS.OL_LIST]: (node, children) => <ol>{children}</ol>,\n  [BLOCKS.LIST_ITEM]: (node, children) => <li>{children}</li>,\n  [BLOCKS.QUOTE]: (node, children) => <blockquote>{children}</blockquote>,\n  [BLOCKS.HR]: () => <hr />,\n  [BLOCKS.TABLE]: (node, children) => (\n    <table>\n      <tbody>{children}</tbody>\n    </table>\n  ),\n  [BLOCKS.TABLE_ROW]: (node, children) => <tr>{children}</tr>,\n  [BLOCKS.TABLE_HEADER_CELL]: (node, children) => <th>{children}</th>,\n  [BLOCKS.TABLE_CELL]: (node, children) => <td>{children}</td>,\n  [INLINES.ASSET_HYPERLINK]: (node) => defaultInline(INLINES.ASSET_HYPERLINK, node as Inline),\n  [INLINES.ENTRY_HYPERLINK]: (node) => defaultInline(INLINES.ENTRY_HYPERLINK, node as Inline),\n  [INLINES.RESOURCE_HYPERLINK]: (node) =>\n    defaultInlineResource(INLINES.RESOURCE_HYPERLINK, node as Inline),\n  [INLINES.EMBEDDED_ENTRY]: (node) => defaultInline(INLINES.EMBEDDED_ENTRY, node as Inline),\n  [INLINES.EMBEDDED_RESOURCE]: (node, _children) =>\n    defaultInlineResource(INLINES.EMBEDDED_RESOURCE, node as Inline),\n  [INLINES.HYPERLINK]: (node, children) => <a href={node.data.uri}>{children}</a>,\n};\n\nconst defaultMarkRenderers: RenderMark = {\n  [MARKS.BOLD]: (text) => <b>{text}</b>,\n  [MARKS.ITALIC]: (text) => <i>{text}</i>,\n  [MARKS.UNDERLINE]: (text) => <u>{text}</u>,\n  [MARKS.CODE]: (text) => <code>{text}</code>,\n  [MARKS.SUPERSCRIPT]: (text) => <sup>{text}</sup>,\n  [MARKS.SUBSCRIPT]: (text) => <sub>{text}</sub>,\n  [MARKS.STRIKETHROUGH]: (text) => <s>{text}</s>,\n};\n\nfunction defaultInline(type: string, node: Inline): ReactNode {\n  return (\n    <span key={node.data.target.sys.id}>\n      type: {node.nodeType} id: {node.data.target.sys.id}\n    </span>\n  );\n}\n\nfunction defaultInlineResource(type: string, node: Inline) {\n  return (\n    <span key={node.data.target.sys.urn}>\n      type: {node.nodeType} urn: {node.data.target.sys.urn}\n    </span>\n  );\n}\n\nexport type CommonNode = Text | Block | Inline;\n\nexport interface NodeRenderer {\n  (node: Block | Inline, children: ReactNode): ReactNode;\n}\n\nexport interface RenderNode {\n  [k: string]: NodeRenderer;\n}\n\nexport interface RenderMark {\n  [k: string]: (text: ReactNode) => ReactNode;\n}\n\nexport interface RenderText {\n  (text: string): ReactNode;\n}\n\nexport interface Options {\n  /**\n   * Node renderers\n   */\n  renderNode?: RenderNode;\n  /**\n   * Mark renderers\n   */\n  renderMark?: RenderMark;\n  /**\n   * Text renderer\n   */\n  renderText?: RenderText;\n  /**\n   * Keep line breaks and multiple spaces\n   */\n  preserveWhitespace?: boolean;\n  /**\n   * Strip empty trailing paragraph from the document\n   */\n  stripEmptyTrailingParagraph?: boolean;\n}\n\n/**\n * Serialize a Contentful Rich Text `document` to React tree\n */\nexport function documentToReactComponents(\n  richTextDocument: Document,\n  options: Options = {},\n): ReactNode {\n  if (!richTextDocument) {\n    return null;\n  }\n\n  // Strip empty trailing paragraph if enabled\n  let processedDocument = richTextDocument;\n  if (options.stripEmptyTrailingParagraph) {\n    processedDocument = helpers.stripEmptyTrailingParagraphFromDocument(richTextDocument);\n  }\n\n  return nodeToReactComponent(processedDocument, {\n    renderNode: {\n      ...defaultNodeRenderers,\n      ...options.renderNode,\n    },\n    renderMark: {\n      ...defaultMarkRenderers,\n      ...options.renderMark,\n    },\n    renderText: options.renderText,\n    preserveWhitespace: options.preserveWhitespace,\n  });\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/util/appendKeyToValidElement.ts",
    "content": "import { cloneElement, isValidElement, ReactNode } from 'react';\n\nexport function appendKeyToValidElement(element: ReactNode, key: number): ReactNode {\n  if (isValidElement(element) && element.key === null) {\n    return cloneElement(element, { key });\n  }\n  return element;\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/src/util/nodeListToReactComponents.tsx",
    "content": "import React, { ReactNode } from 'react';\n\nimport { helpers, Mark } from '@contentful/rich-text-types';\n\nimport { CommonNode, Options } from '..';\n\nimport { appendKeyToValidElement } from './appendKeyToValidElement';\n\nexport function nodeListToReactComponents(nodes: CommonNode[], options: Options): ReactNode {\n  return nodes.map((node: CommonNode, index: number): ReactNode => {\n    return appendKeyToValidElement(nodeToReactComponent(node, options), index);\n  });\n}\n\nexport function nodeToReactComponent(node: CommonNode, options: Options): ReactNode {\n  const { renderNode, renderMark, renderText, preserveWhitespace } = options;\n\n  if (helpers.isText(node)) {\n    let nodeValue: ReactNode = renderText ? renderText(node.value) : node.value;\n\n    // Preserving whitespace is only supported with the default transformations.\n    if (preserveWhitespace && !renderText) {\n      // Preserve multiple spaces.\n      nodeValue = (nodeValue as string).replace(/ {2,}/g, (match) => '\\u00A0'.repeat(match.length));\n\n      // Preserve line breaks.\n      const lines = (nodeValue as string).split('\\n');\n      const jsxLines: (string | React.JSX.Element)[] = [];\n\n      lines.forEach((line, index) => {\n        jsxLines.push(line);\n        if (index !== lines.length - 1) {\n          jsxLines.push(<br />);\n        }\n      });\n      nodeValue = jsxLines;\n    }\n\n    return node.marks.reduce((value: ReactNode, mark: Mark): ReactNode => {\n      if (!renderMark[mark.type]) {\n        return value;\n      }\n      return renderMark[mark.type](value);\n    }, nodeValue);\n  } else {\n    const children: ReactNode = nodeListToReactComponents(node.content, options);\n    if (!node.nodeType || !renderNode[node.nodeType]) {\n      return <>{children}</>;\n    }\n    return renderNode[node.nodeType](node, children);\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-react-renderer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist/lib\",\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\"],\n    \"jsx\": \"react\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/rich-text-types/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [17.2.7](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.6...@contentful/rich-text-types@17.2.7) (2026-04-09)\n\n### Bug Fixes\n\n- **rich-text-types:** improve esm compability [ZEND-7778] ([#1073](https://github.com/contentful/rich-text/issues/1073)) ([204aaec](https://github.com/contentful/rich-text/commit/204aaecc3893633c081986f44896e14272fa376a))\n\n## [17.2.6](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.5...@contentful/rich-text-types@17.2.6) (2026-04-08)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [17.2.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.4...@contentful/rich-text-types@17.2.5) (2025-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [17.2.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.3...@contentful/rich-text-types@17.2.4) (2025-09-23)\n\n### Bug Fixes\n\n- **build:** resolve ESM import failures in rich-text-types [TOL-3435] ([#940](https://github.com/contentful/rich-text/issues/940)) ([5af12af](https://github.com/contentful/rich-text/commit/5af12af168a6005826216c2090fc989db3f8fb03))\n\n## [17.2.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.2...@contentful/rich-text-types@17.2.3) (2025-09-23)\n\n### Bug Fixes\n\n- revert lingui [ZEND-6939] ([#937](https://github.com/contentful/rich-text/issues/937)) ([a55a67b](https://github.com/contentful/rich-text/commit/a55a67b1f1b9739801bc5bc3a9885701ff970cc0))\n\n## [17.2.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.1...@contentful/rich-text-types@17.2.2) (2025-09-10)\n\n### Bug Fixes\n\n- **rich-text-types:** add .js extension for esm [] ([#926](https://github.com/contentful/rich-text/issues/926)) ([b218716](https://github.com/contentful/rich-text/commit/b218716f27a0fe8ad71d0dd8ce551f2ecd2334d6))\n\n## [17.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.2.0...@contentful/rich-text-types@17.2.1) (2025-09-09)\n\n### Bug Fixes\n\n- bundle issues after swc migration [TOL-3396] ([#924](https://github.com/contentful/rich-text/issues/924)) ([22245f0](https://github.com/contentful/rich-text/commit/22245f0648b0164ad29dd0dfe789cd83f78283e8))\n\n# [17.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.1.0...@contentful/rich-text-types@17.2.0) (2025-09-04)\n\n### Features\n\n- migrate to swc and use lingui for i18n [TOL-3288] ([#914](https://github.com/contentful/rich-text/issues/914)) ([b6782a9](https://github.com/contentful/rich-text/commit/b6782a9658b24944ccce2676f06efb1a527d9936))\n\n# [17.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.0.1...@contentful/rich-text-types@17.1.0) (2025-07-15)\n\n### Features\n\n- add an option to strip empty trailing paragraphs [TOL-3193] ([#892](https://github.com/contentful/rich-text/issues/892)) ([9beff0e](https://github.com/contentful/rich-text/commit/9beff0e4cba3e79dc68e6a0725e843c5d642eb87))\n\n## [17.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@17.0.0...@contentful/rich-text-types@17.0.1) (2025-06-16)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [17.0.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.5...@contentful/rich-text-types@17.0.0) (2024-10-29)\n\n### Features\n\n- bring rich text validator [TOL-2426] ([#694](https://github.com/contentful/rich-text/issues/694)) ([30893a6](https://github.com/contentful/rich-text/commit/30893a68b171167502135b48258ba4b93c8375c7))\n\n### BREAKING CHANGES\n\n- removed getSchemaWithNodeType in favor of validateRichTextDocument\n\n## [16.8.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.4...@contentful/rich-text-types@16.8.5) (2024-09-09)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.8.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.3...@contentful/rich-text-types@16.8.4) (2024-08-26)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.8.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.2...@contentful/rich-text-types@16.8.3) (2024-07-29)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.8.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.1...@contentful/rich-text-types@16.8.2) (2024-07-24)\n\n### Bug Fixes\n\n- exporting schema function [] ([#632](https://github.com/contentful/rich-text/issues/632)) ([21bf8a6](https://github.com/contentful/rich-text/commit/21bf8a61883abbb2174524df2ec5be826fd429a3))\n\n## [16.8.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.8.0...@contentful/rich-text-types@16.8.1) (2024-07-17)\n\n### Bug Fixes\n\n- revert schema changes [TOL-2249] ([de0157b](https://github.com/contentful/rich-text/commit/de0157bd8b7b1fd00b58e4b753befb1d9eeecbff))\n\n# [16.8.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.7.0...@contentful/rich-text-types@16.8.0) (2024-07-17)\n\n### Features\n\n- update inline enum order [] ([#620](https://github.com/contentful/rich-text/issues/620)) ([8643e11](https://github.com/contentful/rich-text/commit/8643e1126ce765842190a866556d7c0fa45a7ba8))\n- update schema for rich text types [TOL-2249] ([#619](https://github.com/contentful/rich-text/issues/619)) ([010831e](https://github.com/contentful/rich-text/commit/010831ea1259f478543845ccd70a3aa80f643db0))\n\n# [16.7.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.6.3...@contentful/rich-text-types@16.7.0) (2024-07-16)\n\n### Features\n\n- support ol & ul list validation in table cell [TOL-2249] ([#616](https://github.com/contentful/rich-text/issues/616)) ([f116c33](https://github.com/contentful/rich-text/commit/f116c33d7a26401447836d1230277f6914a31ac1))\n\n## [16.6.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.6.2...@contentful/rich-text-types@16.6.3) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.6.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.6.1...@contentful/rich-text-types@16.6.2) (2024-07-16)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.6.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.6.0...@contentful/rich-text-types@16.6.1) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [16.6.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.5.4...@contentful/rich-text-types@16.6.0) (2024-06-25)\n\n### Features\n\n- switch from tslint to eslint [TOL-2218][tol-2203] ([#594](https://github.com/contentful/rich-text/issues/594)) ([c077b5a](https://github.com/contentful/rich-text/commit/c077b5af58f94c8dc6af4715d4b82c2771d643c5))\n\n## [16.5.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.5.3...@contentful/rich-text-types@16.5.4) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.5.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.5.2...@contentful/rich-text-types@16.5.3) (2024-06-25)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.5.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.5.1...@contentful/rich-text-types@16.5.2) (2024-05-28)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.5.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.5.0...@contentful/rich-text-types@16.5.1) (2024-05-27)\n\n### Bug Fixes\n\n- fix breaking change for copying json ([#573](https://github.com/contentful/rich-text/issues/573)) ([e5d6533](https://github.com/contentful/rich-text/commit/e5d653360735efc395ad8920d8b2bfd24eb827c1))\n\n# [16.5.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.4.0...@contentful/rich-text-types@16.5.0) (2024-05-24)\n\n### Features\n\n- add strikethrough support ([#562](https://github.com/contentful/rich-text/issues/562)) ([b87d0c3](https://github.com/contentful/rich-text/commit/b87d0c31bccb4012745c0479b2b5c92fc28c1e91))\n\n# [16.4.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.5...@contentful/rich-text-types@16.4.0) (2024-05-22)\n\n### Features\n\n- upgrading rollup to latest version [TOL-2097] ([#559](https://github.com/contentful/rich-text/issues/559)) ([f14d197](https://github.com/contentful/rich-text/commit/f14d1974590d58f92bbf4cb56644095dba929ad9))\n\n## [16.3.5](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.4...@contentful/rich-text-types@16.3.5) (2024-03-04)\n\n### Bug Fixes\n\n- 🐛 export MARKS and EMPTY_DOCUMENT as ESM friendly ([#462](https://github.com/contentful/rich-text/issues/462)) ([7ea8ab3](https://github.com/contentful/rich-text/commit/7ea8ab31bcf82242291ff22640869a23b12dde57))\n\n## [16.3.4](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.3...@contentful/rich-text-types@16.3.4) (2024-01-30)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.3.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.2...@contentful/rich-text-types@16.3.3) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.3.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.1...@contentful/rich-text-types@16.3.2) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.3.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.3.0...@contentful/rich-text-types@16.3.1) (2024-01-23)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [16.3.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.2.1...@contentful/rich-text-types@16.3.0) (2023-09-12)\n\n### Features\n\n- add new nodes [DANTE-1157] ([#494](https://github.com/contentful/rich-text/issues/494)) ([b1fa6df](https://github.com/contentful/rich-text/commit/b1fa6dffc4bd7e1d367e9ce2cfddffe4fe07be47))\n\n## [16.2.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.2.0...@contentful/rich-text-types@16.2.1) (2023-08-04)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [16.2.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.1.0...@contentful/rich-text-types@16.2.0) (2023-05-26)\n\n### Features\n\n- 🎸 add `getRichTextResourceLinks` ([#465](https://github.com/contentful/rich-text/issues/465)) ([5746ba6](https://github.com/contentful/rich-text/commit/5746ba652ae5eac2df27d05193e19aef9e85c438))\n\n# [16.1.0](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.0.3...@contentful/rich-text-types@16.1.0) (2023-05-04)\n\n### Features\n\n- add embedded-resource-block to the list of supported block elements ([#461](https://github.com/contentful/rich-text/issues/461)) ([c85fd63](https://github.com/contentful/rich-text/commit/c85fd632d5166bf6a4bd30adbc3ed35668f2e7d5))\n\n## [16.0.3](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.0.2...@contentful/rich-text-types@16.0.3) (2023-03-14)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.0.2](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.0.1...@contentful/rich-text-types@16.0.2) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [16.0.1](https://github.com/contentful/rich-text/compare/@contentful/rich-text-types@16.0.0...@contentful/rich-text-types@16.0.1) (2022-12-01)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# 16.0.0 (2022-12-01)\n\n## 15.15.1 (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# 15.15.0 (2022-11-29)\n\n### Features\n\n- adding v1 marks to rich text types [TOL-786] ([#416](https://github.com/contentful/rich-text/issues/416)) ([8885de8](https://github.com/contentful/rich-text/commit/8885de8ebba7736de46b0b8892a8aa15bb8d7ba4))\n\n## 15.14.1 (2022-11-23)\n\n# 15.14.0 (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## 15.13.2 (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- revert change to monorepo tsconfig, apply to tsconfig in rich-text-types ([#358](https://github.com/contentful/rich-text/issues/358)) ([56126cc](https://github.com/contentful/rich-text/commit/56126cc9ed3704f21b89d2dbded160be0265f153))\n\n## 15.12.1 (2022-04-21)\n\n# 15.12.0 (2022-03-25)\n\n### Features\n\n- enforce minItems in table-related node types ([#314](https://github.com/contentful/rich-text/issues/314)) ([1125331](https://github.com/contentful/rich-text/commit/112533100f66ae01cd9944069dc62fc95f1737a5))\n\n## 15.11.1 (2022-01-04)\n\n### Bug Fixes\n\n- **rich-text-types:** remove RT validation helpers ([#302](https://github.com/contentful/rich-text/issues/302)) ([fcd3a27](https://github.com/contentful/rich-text/commit/fcd3a277952f53eb3ae6ebb559ae6a02f5553c87)), closes [#295](https://github.com/contentful/rich-text/issues/295) [#274](https://github.com/contentful/rich-text/issues/274)\n\n# 15.11.0 (2021-12-27)\n\n### Features\n\n- **rich-text-types:** expose HEADINGS array ([#301](https://github.com/contentful/rich-text/issues/301)) ([758539d](https://github.com/contentful/rich-text/commit/758539d46f3db13c21ca2f6d74a389a6fef21803))\n\n## 15.10.1 (2021-12-21)\n\n# 15.10.0 (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## 15.9.1 (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# 15.9.0 (2021-12-09)\n\n### Features\n\n- **rich-text-types:** expose RT validation helper ([#292](https://github.com/contentful/rich-text/issues/292)) ([fc5a7cc](https://github.com/contentful/rich-text/commit/fc5a7cc27244f293a9a50acd785f7edcdaaa96ea))\n\n# 15.7.0 (2021-11-11)\n\n### Features\n\n- **rich-text-types:** Add TEXT_CONTAINERS ([#286](https://github.com/contentful/rich-text/issues/286)) ([3356ea8](https://github.com/contentful/rich-text/commit/3356ea815a46901a6637f177b04bcf1926adc88d))\n\n## 15.6.2 (2021-11-05)\n\n## 15.6.1 (2021-11-05)\n\n# 15.6.0 (2021-11-04)\n\n## 15.5.1 (2021-10-25)\n\n### Bug Fixes\n\n- npm 15.5.0 ([#280](https://github.com/contentful/rich-text/issues/280)) ([e7aeba4](https://github.com/contentful/rich-text/commit/e7aeba49a3074fc9eae6aee569db4e30d1acb8b8))\n\n# 15.5.0 (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n## 15.3.6 (2021-09-15)\n\n### Bug Fixes\n\n- allow table-row type to have both cells ([#267](https://github.com/contentful/rich-text/issues/267)) ([ec40598](https://github.com/contentful/rich-text/commit/ec405982109cb1c16e7adf71a541a98270d7f45b))\n\n## 15.3.5 (2021-09-13)\n\n### Bug Fixes\n\n- **rich-text-types:** forbid Tables inside ListItem ([#266](https://github.com/contentful/rich-text/issues/266)) ([fc338bf](https://github.com/contentful/rich-text/commit/fc338bf040b8718057717d2681f800d5e26ba59d))\n\n## 15.3.3 (2021-09-07)\n\n## 15.3.2 (2021-09-07)\n\n## 15.3.1 (2021-09-07)\n\n# 15.3.0 (2021-09-06)\n\n### Bug Fixes\n\n- allow the first item in Table to be a TableHeaderRow ([9a6de55](https://github.com/contentful/rich-text/commit/9a6de55ed97ca413d3922958850b8215922c06b5))\n- don't export the helper TableHeaderRow type ([179c3cb](https://github.com/contentful/rich-text/commit/179c3cb10c0f65725297445afe955f0cca135005))\n- typo ([2282665](https://github.com/contentful/rich-text/commit/2282665924404771b3353dd9b380d8863f1d4c41))\n\n### Features\n\n- add TableHeaderCell type ([5e25ac9](https://github.com/contentful/rich-text/commit/5e25ac9f35be2ad6c7ad7857cbde808cbc3437f9))\n\n# 15.1.0 (2021-08-02)\n\n### Features\n\n- add rowspan ([e0264fb](https://github.com/contentful/rich-text/commit/e0264fbe4d9467eedf78b7c5c3a9825a584124cf))\n\n# 15.0.0 (2021-06-15)\n\n### Features\n\n- add table markup support ([c6ae127](https://github.com/contentful/rich-text/commit/c6ae127aa460f4cd26cd6b671cd43fd2714bc650))\n\n## 14.1.2 (2020-11-02)\n\n### Bug Fixes\n\n- 🐛 configure rollup copy correctly ([3446a33](https://github.com/contentful/rich-text/commit/3446a33fc5711087095a58b088828dfe6066bc7f))\n\n## 14.0.1 (2020-01-30)\n\n### Features\n\n- 🎸 emptyDoc representing an empty RT document ([80315ef](https://github.com/contentful/rich-text/commit/80315ef5130b79336336ba31de8a55e42bafe319))\n\n# 14.0.0 (2020-01-28)\n\n# 13.4.0 (2019-08-01)\n\n# 13.1.0 (2019-03-04)\n\n# 13.0.0 (2019-01-22)\n\n## 12.1.2 (2018-12-14)\n\n## 12.0.1 (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 add Object.values and Array.prototype.includes polyfills ([9e2ffb4](https://github.com/contentful/rich-text/commit/9e2ffb46e3564a523c74504270b29ccc8b8249ad))\n\n# 12.0.0 (2018-11-29)\n\n# 11.0.0 (2018-11-27)\n\n### Bug Fixes\n\n- 🐛 Removes obsolete field `title` from Hyperlinks ([8cb9027](https://github.com/contentful/rich-text/commit/8cb90279f5348a7fb59f211c2ba209a28fd432be))\n\n# 10.3.0 (2018-11-26)\n\n# 10.2.0 (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# 10.1.0 (2018-11-16)\n\n### Features\n\n- 🎸 adds json schema generation to rich text types ([8916140](https://github.com/contentful/rich-text/commit/89161404eb911f126be23ba2a146ebf748f7489e))\n- 🎸 introduces top-level-block type ([a6bf35e](https://github.com/contentful/rich-text/commit/a6bf35e7c9ca35915a512de774b3a3fdc4c76e5d))\n\n## 10.0.1 (2018-11-08)\n\n# 10.0.0 (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## 9.0.2 (2018-10-31)\n\n# 9.0.0 (2018-10-30)\n\n### Features\n\n- 🎸 Explicitly declare nodeClass and nodeType in core types ([0749c61](https://github.com/contentful/rich-text/commit/0749c6199bb2681509608539c76bd8149cade564))\n\n### BREAKING CHANGES\n\n- Potentially breaks TypeScript libraries pulling this in as a dependency\n  if they are not explicitly stating nodeClass and nodeType.\n\n## 8.0.3 (2018-10-30)\n\n## 8.0.2 (2018-10-29)\n\n## 8.0.1 (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 Revert mock hypenation commits ([bde9432](https://github.com/contentful/rich-text/commit/bde94323fcc02bf5ab3feeef46a9d8fc8b08d59b))\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n\n## [15.15.1](https://github.com/contentful/rich-text/compare/v15.15.0...v15.15.1) (2022-11-30)\n\n### Bug Fixes\n\n- **release:** switch to yarn ([#420](https://github.com/contentful/rich-text/issues/420)) ([0e53501](https://github.com/contentful/rich-text/commit/0e53501eb94b3d1c76ac88ca30943d2675e536c8))\n\n# [15.15.0](https://github.com/contentful/rich-text/compare/v15.14.1...v15.15.0) (2022-11-29)\n\n### Features\n\n- adding v1 marks to rich text types [TOL-786] ([#416](https://github.com/contentful/rich-text/issues/416)) ([8885de8](https://github.com/contentful/rich-text/commit/8885de8ebba7736de46b0b8892a8aa15bb8d7ba4))\n\n## [15.14.1](https://github.com/contentful/rich-text/compare/v15.14.0...v15.14.1) (2022-11-23)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [15.14.0](https://github.com/contentful/rich-text/compare/v15.13.2...v15.14.0) (2022-11-14)\n\n### Features\n\n- add super/sub script types ([#391](https://github.com/contentful/rich-text/issues/391)) ([2562f66](https://github.com/contentful/rich-text/commit/2562f66278f0eff4eeeb367025d4b465773893d1))\n\n## [15.13.2](https://github.com/contentful/rich-text/compare/v15.13.1...v15.13.2) (2022-09-07)\n\n### Bug Fixes\n\n- add prettier write command ([#345](https://github.com/contentful/rich-text/issues/345)) ([0edad4c](https://github.com/contentful/rich-text/commit/0edad4c3176cea85d56a55fc5f4072419d730c8a))\n- revert change to monorepo tsconfig, apply to tsconfig in rich-text-types ([#358](https://github.com/contentful/rich-text/issues/358)) ([56126cc](https://github.com/contentful/rich-text/commit/56126cc9ed3704f21b89d2dbded160be0265f153))\n\n## [15.12.1](https://github.com/contentful/rich-text/compare/v15.12.0...v15.12.1) (2022-04-21)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [15.12.0](https://github.com/contentful/rich-text/compare/v15.11.2...v15.12.0) (2022-03-25)\n\n### Features\n\n- enforce minItems in table-related node types ([#314](https://github.com/contentful/rich-text/issues/314)) ([1125331](https://github.com/contentful/rich-text/commit/112533100f66ae01cd9944069dc62fc95f1737a5))\n\n## [15.11.1](https://github.com/contentful/rich-text/compare/v15.11.0...v15.11.1) (2022-01-04)\n\n### Bug Fixes\n\n- **rich-text-types:** remove RT validation helpers ([#302](https://github.com/contentful/rich-text/issues/302)) ([fcd3a27](https://github.com/contentful/rich-text/commit/fcd3a277952f53eb3ae6ebb559ae6a02f5553c87)), closes [#295](https://github.com/contentful/rich-text/issues/295) [#274](https://github.com/contentful/rich-text/issues/274)\n\n# [15.11.0](https://github.com/contentful/rich-text/compare/v15.10.1...v15.11.0) (2021-12-27)\n\n### Features\n\n- **rich-text-types:** expose HEADINGS array ([#301](https://github.com/contentful/rich-text/issues/301)) ([758539d](https://github.com/contentful/rich-text/commit/758539d46f3db13c21ca2f6d74a389a6fef21803))\n\n## [15.10.1](https://github.com/contentful/rich-text/compare/v15.10.0...v15.10.1) (2021-12-21)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [15.10.0](https://github.com/contentful/rich-text/compare/v15.9.1...v15.10.0) (2021-12-15)\n\n### Features\n\n- support custom error transformer ([#296](https://github.com/contentful/rich-text/issues/296)) ([9449b87](https://github.com/contentful/rich-text/commit/9449b87fc063a00f11cfe7b2bc0fdb4d91251c69))\n\n## [15.9.1](https://github.com/contentful/rich-text/compare/v15.9.0...v15.9.1) (2021-12-10)\n\n### Bug Fixes\n\n- **rich-text-types:** resolve generated JSON schemas ([#294](https://github.com/contentful/rich-text/issues/294)) ([1e5b4c4](https://github.com/contentful/rich-text/commit/1e5b4c474e1e27e97df177748c0c8df365a2ab71))\n\n# [15.9.0](https://github.com/contentful/rich-text/compare/v15.8.0...v15.9.0) (2021-12-09)\n\n### Features\n\n- **rich-text-types:** expose RT validation helper ([#292](https://github.com/contentful/rich-text/issues/292)) ([fc5a7cc](https://github.com/contentful/rich-text/commit/fc5a7cc27244f293a9a50acd785f7edcdaaa96ea))\n\n# [15.7.0](https://github.com/contentful/rich-text/compare/v15.6.2...v15.7.0) (2021-11-11)\n\n### Features\n\n- **rich-text-types:** Add TEXT_CONTAINERS ([#286](https://github.com/contentful/rich-text/issues/286)) ([3356ea8](https://github.com/contentful/rich-text/commit/3356ea815a46901a6637f177b04bcf1926adc88d))\n\n## [15.6.2](https://github.com/contentful/rich-text/compare/v15.6.1...v15.6.2) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [15.6.1](https://github.com/contentful/rich-text/compare/v15.6.0...v15.6.1) (2021-11-05)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [15.6.0](https://github.com/contentful/rich-text/compare/v15.5.1...v15.6.0) (2021-11-04)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [15.5.1](https://github.com/contentful/rich-text/compare/v15.5.0...v15.5.1) (2021-10-25)\n\n### Bug Fixes\n\n- npm 15.5.0 ([#280](https://github.com/contentful/rich-text/issues/280)) ([e7aeba4](https://github.com/contentful/rich-text/commit/e7aeba49a3074fc9eae6aee569db4e30d1acb8b8))\n\n# [15.5.0](https://github.com/contentful/rich-text/compare/v15.4.0...v15.5.0) (2021-10-25)\n\n### Features\n\n- add v1 node types constraints ([#279](https://github.com/contentful/rich-text/issues/279)) ([5026023](https://github.com/contentful/rich-text/commit/5026023610ec1439f24fd32df9977c2cd4c13e86))\n\n## [15.3.6](https://github.com/contentful/rich-text/compare/v15.3.5...v15.3.6) (2021-09-15)\n\n### Bug Fixes\n\n- allow table-row type to have both cells ([#267](https://github.com/contentful/rich-text/issues/267)) ([ec40598](https://github.com/contentful/rich-text/commit/ec405982109cb1c16e7adf71a541a98270d7f45b))\n\n## [15.3.5](https://github.com/contentful/rich-text/compare/v15.3.4...v15.3.5) (2021-09-13)\n\n### Bug Fixes\n\n- **rich-text-types:** forbid Tables inside ListItem ([#266](https://github.com/contentful/rich-text/issues/266)) ([fc338bf](https://github.com/contentful/rich-text/commit/fc338bf040b8718057717d2681f800d5e26ba59d))\n\n## [15.3.3](https://github.com/contentful/rich-text/compare/v15.3.2...v15.3.3) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [15.3.2](https://github.com/contentful/rich-text/compare/v15.3.1...v15.3.2) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n## [15.3.1](https://github.com/contentful/rich-text/compare/v15.3.0...v15.3.1) (2021-09-07)\n\n**Note:** Version bump only for package @contentful/rich-text-types\n\n# [15.3.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.3.0) (2021-09-06)\n\n### Bug Fixes\n\n- allow the first item in Table to be a TableHeaderRow ([9a6de55](https://github.com/contentful/rich-text/commit/9a6de55ed97ca413d3922958850b8215922c06b5))\n- don't export the helper TableHeaderRow type ([179c3cb](https://github.com/contentful/rich-text/commit/179c3cb10c0f65725297445afe955f0cca135005))\n- typo ([2282665](https://github.com/contentful/rich-text/commit/2282665924404771b3353dd9b380d8863f1d4c41))\n\n### Features\n\n- add TableHeaderCell type ([5e25ac9](https://github.com/contentful/rich-text/commit/5e25ac9f35be2ad6c7ad7857cbde808cbc3437f9))\n\n# [15.2.0](https://github.com/contentful/rich-text/compare/v15.2.0...v15.1.0) (2021-09-06)\n\n### Bug Fixes\n\n- allow the first item in Table to be a TableHeaderRow ([9a6de55](https://github.com/contentful/rich-text/commit/9a6de55ed97ca413d3922958850b8215922c06b5))\n- don't export the helper TableHeaderRow type ([179c3cb](https://github.com/contentful/rich-text/commit/179c3cb10c0f65725297445afe955f0cca135005))\n- typo ([2282665](https://github.com/contentful/rich-text/commit/2282665924404771b3353dd9b380d8863f1d4c41))\n\n### Features\n\n- add TableHeaderCell type ([5e25ac9](https://github.com/contentful/rich-text/commit/5e25ac9f35be2ad6c7ad7857cbde808cbc3437f9))\n\n# [15.1.0](https://github.com/contentful/rich-text/compare/v15.0.0...v15.1.0) (2021-08-02)\n\n### Features\n\n- add rowspan ([e0264fb](https://github.com/contentful/rich-text/commit/e0264fbe4d9467eedf78b7c5c3a9825a584124cf))\n\n# [15.0.0](https://github.com/contentful/rich-text/compare/v14.2.0...v15.0.0) (2021-06-15)\n\n### Features\n\n- add table markup support ([c6ae127](https://github.com/contentful/rich-text/commit/c6ae127aa460f4cd26cd6b671cd43fd2714bc650))\n\n## [14.1.2](https://github.com/contentful/rich-text/compare/v14.0.1...v14.1.2) (2020-11-02)\n\n### Bug Fixes\n\n- 🐛 configure rollup copy correctly ([3446a33](https://github.com/contentful/rich-text/commit/3446a33fc5711087095a58b088828dfe6066bc7f))\n\n## [14.0.1](https://github.com/contentful/rich-text/compare/v14.0.0...v14.0.1) (2020-01-30)\n\n### Features\n\n- 🎸 emptyDoc representing an empty RT document ([80315ef](https://github.com/contentful/rich-text/commit/80315ef5130b79336336ba31de8a55e42bafe319))\n\n# [14.0.0](https://github.com/contentful/rich-text/compare/v13.4.0...v14.0.0) (2020-01-28)\n\n# [13.4.0](https://github.com/contentful/rich-text/compare/v13.3.0...v13.4.0) (2019-08-01)\n\n# [13.1.0](https://github.com/contentful/rich-text/compare/v13.0.1...v13.1.0) (2019-03-04)\n\n# [13.0.0](https://github.com/contentful/rich-text/compare/v12.2.1...v13.0.0) (2019-01-22)\n\n## [12.1.2](https://github.com/contentful/rich-text/compare/v12.1.1...v12.1.2) (2018-12-14)\n\n## [12.0.1](https://github.com/contentful/rich-text/compare/v12.0.0...v12.0.1) (2018-12-04)\n\n### Bug Fixes\n\n- 🐛 add Object.values and Array.prototype.includes polyfills ([9e2ffb4](https://github.com/contentful/rich-text/commit/9e2ffb46e3564a523c74504270b29ccc8b8249ad))\n\n# [12.0.0](https://github.com/contentful/rich-text/compare/v11.0.0...v12.0.0) (2018-11-29)\n\n# [11.0.0](https://github.com/contentful/rich-text/compare/v10.3.0...v11.0.0) (2018-11-27)\n\n### Bug Fixes\n\n- 🐛 Removes obsolete field `title` from Hyperlinks ([8cb9027](https://github.com/contentful/rich-text/commit/8cb90279f5348a7fb59f211c2ba209a28fd432be))\n\n# [10.3.0](https://github.com/contentful/rich-text/compare/v10.2.0...v10.3.0) (2018-11-26)\n\n# [10.2.0](https://github.com/contentful/rich-text/compare/v10.1.0...v10.2.0) (2018-11-19)\n\n### Features\n\n- 🎸 Add rich-text-references ([363b4e5](https://github.com/contentful/rich-text/commit/363b4e509e94af0932fd7cece8e56beafe8d67d2))\n\n# [10.1.0](https://github.com/contentful/rich-text/compare/v10.0.5...v10.1.0) (2018-11-16)\n\n### Features\n\n- 🎸 adds json schema generation to rich text types ([8916140](https://github.com/contentful/rich-text/commit/89161404eb911f126be23ba2a146ebf748f7489e))\n- 🎸 introduces top-level-block type ([a6bf35e](https://github.com/contentful/rich-text/commit/a6bf35e7c9ca35915a512de774b3a3fdc4c76e5d))\n\n## [10.0.1](https://github.com/contentful/rich-text/compare/v10.0.0...v10.0.1) (2018-11-08)\n\n# [10.0.0](https://github.com/contentful/rich-text/compare/v9.0.2...v10.0.0) (2018-11-02)\n\n### Features\n\n- 🎸 removes nodeClass from Node interface ([09b8162](https://github.com/contentful/rich-text/commit/09b8162bcba65bc13afa14b2b5ff046c9fed7b3b))\n\n### BREAKING CHANGES\n\n- Removes accidentally added nodeClass\n\n## [9.0.2](https://github.com/contentful/rich-text/compare/v9.0.1...v9.0.2) (2018-10-31)\n\n# [9.0.0](https://github.com/contentful/rich-text/compare/v8.0.3...v9.0.0) (2018-10-30)\n\n### Features\n\n- 🎸 Explicitly declare nodeClass and nodeType in core types ([0749c61](https://github.com/contentful/rich-text/commit/0749c6199bb2681509608539c76bd8149cade564))\n\n### BREAKING CHANGES\n\n- Potentially breaks TypeScript libraries pulling this in as a dependency\n  if they are not explicitly stating nodeClass and nodeType.\n\n## [8.0.3](https://github.com/contentful/rich-text/compare/v8.0.2...v8.0.3) (2018-10-30)\n\n## [8.0.2](https://github.com/contentful/rich-text/compare/v8.0.1...v8.0.2) (2018-10-29)\n\n## [8.0.1](https://github.com/contentful/rich-text/compare/v8.0.0...v8.0.1) (2018-10-26)\n\n### Bug Fixes\n\n- 🐛 Revert mock hypenation commits ([bde9432](https://github.com/contentful/rich-text/commit/bde94323fcc02bf5ab3feeef46a9d8fc8b08d59b))\n\n### Features\n\n- 🎸 take all packages out of \"demo mode\" ([815f18b](https://github.com/contentful/rich-text/commit/815f18be6a914e7e4782790ee46053689712494b))\n\n### BREAKING CHANGES\n\n- renames all packages\n\n# 6.0.0 (2018-10-24)\n"
  },
  {
    "path": "packages/rich-text-types/README.md",
    "content": "# rich-text-types\n\nType definitions and constants for the Contentful rich text field type.\n"
  },
  {
    "path": "packages/rich-text-types/__mocks__/@lingui/core/macro.js",
    "content": "const t = ({ _id, message }) => message;\n\nconst plural = (count, options) => {\n  let message = options.other;\n  if (count === 0) {\n    message = options.zero || options[0] || options.other;\n  }\n  if (count === 1) {\n    message = options.one || options.other;\n  }\n  return message.replace('#', count);\n};\n\nmodule.exports = { t, plural };\n"
  },
  {
    "path": "packages/rich-text-types/__test__/helpers.test.ts",
    "content": "import { BLOCKS } from '../src/blocks';\nimport { helpers } from '../src/index';\nimport { Document, Mark } from '../src/types';\n\ndescribe('helpers', () => {\n  describe('isEmptyParagraph', () => {\n    it('returns true for empty paragraph', () => {\n      const node = {\n        nodeType: BLOCKS.PARAGRAPH,\n        data: {},\n        content: [\n          {\n            nodeType: 'text' as const,\n            value: '',\n            marks: [] as Mark[],\n            data: {},\n          },\n        ],\n      };\n      expect(helpers.isEmptyParagraph(node)).toBe(true);\n    });\n\n    it('returns false for non-empty paragraph', () => {\n      const node = {\n        nodeType: BLOCKS.PARAGRAPH,\n        data: {},\n        content: [\n          {\n            nodeType: 'text' as const,\n            value: 'Hello world',\n            marks: [] as Mark[],\n            data: {},\n          },\n        ],\n      };\n      expect(helpers.isEmptyParagraph(node)).toBe(false);\n    });\n\n    it('returns false for paragraph with multiple text nodes', () => {\n      const node = {\n        nodeType: BLOCKS.PARAGRAPH,\n        data: {},\n        content: [\n          {\n            nodeType: 'text' as const,\n            value: '',\n            marks: [] as Mark[],\n            data: {},\n          },\n          {\n            nodeType: 'text' as const,\n            value: '',\n            marks: [] as Mark[],\n            data: {},\n          },\n        ],\n      };\n      expect(helpers.isEmptyParagraph(node)).toBe(false);\n    });\n\n    it('returns false for non-paragraph node', () => {\n      const node = {\n        nodeType: BLOCKS.HEADING_1,\n        data: {},\n        content: [\n          {\n            nodeType: 'text' as const,\n            value: '',\n            marks: [] as Mark[],\n            data: {},\n          },\n        ],\n      };\n      expect(helpers.isEmptyParagraph(node)).toBe(false);\n    });\n  });\n\n  describe('stripEmptyTrailingParagraphFromDocument', () => {\n    it('strips empty trailing paragraph', () => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            data: {},\n            content: [\n              {\n                nodeType: 'text' as const,\n                value: 'Hello world',\n                marks: [] as Mark[],\n                data: {},\n              },\n            ],\n          },\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            data: {},\n            content: [\n              {\n                nodeType: 'text' as const,\n                value: '',\n                marks: [] as Mark[],\n                data: {},\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = helpers.stripEmptyTrailingParagraphFromDocument(document);\n      expect(result.content).toHaveLength(1);\n      expect(result.content[0].nodeType).toBe(BLOCKS.PARAGRAPH);\n    });\n\n    it('does not strip empty trailing paragraph when it is the only child', () => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            data: {},\n            content: [\n              {\n                nodeType: 'text' as const,\n                value: '',\n                marks: [] as Mark[],\n                data: {},\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = helpers.stripEmptyTrailingParagraphFromDocument(document);\n      expect(result.content).toHaveLength(1);\n    });\n\n    it('does not strip non-empty trailing paragraph', () => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        data: {},\n        content: [\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            data: {},\n            content: [\n              {\n                nodeType: 'text' as const,\n                value: 'Hello world',\n                marks: [] as Mark[],\n                data: {},\n              },\n            ],\n          },\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            data: {},\n            content: [\n              {\n                nodeType: 'text' as const,\n                value: 'Not empty',\n                marks: [] as Mark[],\n                data: {},\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = helpers.stripEmptyTrailingParagraphFromDocument(document);\n      expect(result.content).toHaveLength(2);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-types/__test__/schemaConstraints.test.ts",
    "content": "import { BLOCKS } from '../src/blocks';\nimport { CONTAINERS, TEXT_CONTAINERS, VOID_BLOCKS } from '../src/schemaConstraints';\n\nconst allKnownBlocks = Object.values(BLOCKS);\n\ndescribe('schema constraints', () => {\n  it('all block node types are either considered a container or void', () => {\n    const blocks = [\n      BLOCKS.DOCUMENT, // Root block could be in CONTAINERS but isn't.\n      ...VOID_BLOCKS,\n      ...TEXT_CONTAINERS,\n      ...Object.keys(CONTAINERS),\n    ];\n    expect(blocks).toEqual(expect.arrayContaining(allKnownBlocks));\n    expect(blocks.length).toEqual(allKnownBlocks.length);\n  });\n\n  it('should allow UL_LIST and OL_LIST blocks as children of TABLE_CELL', () => {\n    // Get the children of TABLE_CELL\n    const tableCellChildren = CONTAINERS[BLOCKS.TABLE_CELL];\n\n    // Check that UL_LIST and OL_LIST are in the children array\n    expect(tableCellChildren).toContain(BLOCKS.UL_LIST);\n    expect(tableCellChildren).toContain(BLOCKS.OL_LIST);\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-types/__test__/validation.test.ts",
    "content": "import { BLOCKS } from '../src/blocks';\nimport { INLINES } from '../src/inlines';\nimport type { Document } from '../src/types';\nimport { validateRichTextDocument } from '../src/validator/index';\n\ndescribe('validation', () => {\n  it('fails if it is not document node', () => {\n    // @ts-expect-error we force a wrong node type to check that it fails\n    const document: Document = { nodeType: BLOCKS.PARAGRAPH, content: [], data: {} };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: ['document'],\n        name: 'in',\n        path: ['nodeType'],\n        value: 'paragraph',\n      },\n    ]);\n  });\n\n  it('fails if it has an invalid shape', () => {\n    // @ts-expect-error we force a wrong node type to check that it fails\n    const document: Document = { nodeType: BLOCKS.DOCUMENT };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        name: 'required',\n        path: ['content'],\n        details: 'The property \"content\" is required here',\n      },\n      {\n        name: 'required',\n        path: ['data'],\n        details: 'The property \"data\" is required here',\n      },\n    ]);\n  });\n\n  it('fails if it has nested documents', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong node type to check that it fails\n      content: [{ nodeType: BLOCKS.DOCUMENT, content: [], data: {} }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'table',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'nodeType'],\n        value: 'document',\n      },\n    ]);\n  });\n\n  it('fails without a nodeType property', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong node type to check that it fails\n      content: [{ content: [], data: {} }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'table',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'nodeType'],\n        value: undefined,\n      },\n    ]);\n  });\n\n  it('fails on custom nodeTypes (unknown nodeType)', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong node type to check that it fails\n      content: [{ nodeType: 'custom-node-type', content: [], data: {} }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'table',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'nodeType'],\n        value: 'custom-node-type',\n      },\n    ]);\n  });\n\n  it('fails without a content property', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong node type to check that it fails\n      content: [{ nodeType: BLOCKS.PARAGRAPH, data: {} }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The property \"content\" is required here',\n        name: 'required',\n        path: ['content', 0, 'content'],\n        value: undefined,\n      },\n    ]);\n  });\n\n  it('fails with a invalid content property', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong type to check that it fails\n      content: [{ nodeType: BLOCKS.PARAGRAPH, content: 'Hello World', data: {} }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"content\" is incorrect, expected type: Array',\n        name: 'type',\n        path: ['content', 0, 'content'],\n        type: 'Array',\n        value: 'Hello World',\n      },\n    ]);\n  });\n\n  it('fails without data property', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      // @ts-expect-error we force a wrong node type to check that it fails\n      content: [{ nodeType: BLOCKS.PARAGRAPH, content: [] }],\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The property \"data\" is required here',\n        name: 'required',\n        path: ['data'],\n      },\n    ]);\n  });\n\n  it('fails with invalid data property', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: null }],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"data\" is incorrect, expected type: Object',\n        name: 'type',\n        path: ['content', 0, 'data'],\n        type: 'Object',\n        value: null,\n      },\n    ]);\n  });\n\n  it('fails if undefined is in the content list', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }, undefined],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"1\" is incorrect, expected type: Object',\n        name: 'type',\n        path: ['content', 1],\n        type: 'Object',\n        value: undefined,\n      },\n    ]);\n  });\n\n  it('fails if undefined is in the content list of child nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.UL_LIST,\n          content: [\n            {\n              nodeType: BLOCKS.LIST_ITEM,\n              content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }, undefined],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"1\" is incorrect, expected type: Object',\n        name: 'type',\n        path: ['content', 0, 'content', 0, 'content', 1],\n        type: 'Object',\n        value: undefined,\n      },\n    ]);\n  });\n\n  it('fails with unknown properties', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [],\n      data: {},\n      // @ts-expect-error we force a wrong property to check that it fails\n      myCustomProperty: 'Hello World',\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The property \"myCustomProperty\" is not expected',\n        name: 'unexpected',\n        path: ['myCustomProperty'],\n      },\n    ]);\n  });\n\n  it.each([BLOCKS.LIST_ITEM, BLOCKS.TABLE_ROW, BLOCKS.TABLE_HEADER_CELL, BLOCKS.TABLE_CELL])(\n    'fails with a invalid block node as children (nodeType: %s) of the root node',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            // @ts-expect-error we force a wrong node type to check that it fails\n            nodeType,\n            content: [],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Value must be one of expected values',\n          expected: [\n            'blockquote',\n            'embedded-asset-block',\n            'embedded-entry-block',\n            'embedded-resource-block',\n            'heading-1',\n            'heading-2',\n            'heading-3',\n            'heading-4',\n            'heading-5',\n            'heading-6',\n            'hr',\n            'ordered-list',\n            'paragraph',\n            'table',\n            'unordered-list',\n          ],\n          name: 'in',\n          path: ['content', 0, 'nodeType'],\n          value: nodeType,\n        },\n      ]);\n    },\n  );\n\n  it.each(Object.values(INLINES))(\n    'fails with a inline node (%s) as direct children of the root node',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            // @ts-expect-error we force a wrong node type to check that it fails\n            nodeType,\n            content: [],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Value must be one of expected values',\n          expected: [\n            'blockquote',\n            'embedded-asset-block',\n            'embedded-entry-block',\n            'embedded-resource-block',\n            'heading-1',\n            'heading-2',\n            'heading-3',\n            'heading-4',\n            'heading-5',\n            'heading-6',\n            'hr',\n            'ordered-list',\n            'paragraph',\n            'table',\n            'unordered-list',\n          ],\n          name: 'in',\n          path: ['content', 0, 'nodeType'],\n          value: nodeType,\n        },\n      ]);\n    },\n  );\n\n  it('fails with text as a direct children of the root node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          // @ts-expect-error we force a wrong node type to check that it fails\n          nodeType: 'text',\n          data: {},\n          marks: [],\n          value: 'Hello World',\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'table',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'nodeType'],\n        value: 'text',\n      },\n    ]);\n  });\n\n  it('fails with inline node and text as a direct children of the root node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          // @ts-expect-error we force a wrong node type to check that it fails\n          nodeType: 'text',\n          data: {},\n          marks: [],\n          value: 'Hello World',\n        },\n        {\n          // @ts-expect-error we force a wrong node type to check that it fails\n          nodeType: INLINES.ASSET_HYPERLINK,\n          data: { target: {} },\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'table',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'nodeType'],\n        value: 'text',\n      },\n    ]);\n  });\n\n  it.each([BLOCKS.OL_LIST, BLOCKS.UL_LIST] as const)(\n    'fails for invalid block nodes inside of (%s)',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType: nodeType,\n            content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Value must be one of expected values',\n          expected: [BLOCKS.LIST_ITEM],\n          name: 'in',\n          path: ['content', 0, 'content', 0, 'nodeType'],\n          value: BLOCKS.PARAGRAPH,\n        },\n      ]);\n    },\n  );\n\n  it('fails on text node directly inside of a list item node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.UL_LIST,\n          content: [\n            {\n              nodeType: BLOCKS.LIST_ITEM,\n              content: [\n                {\n                  nodeType: 'text',\n                  data: {},\n                  value: 'Hello World',\n                  marks: [],\n                },\n              ],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [\n          'blockquote',\n          'embedded-asset-block',\n          'embedded-entry-block',\n          'embedded-resource-block',\n          'heading-1',\n          'heading-2',\n          'heading-3',\n          'heading-4',\n          'heading-5',\n          'heading-6',\n          'hr',\n          'ordered-list',\n          'paragraph',\n          'unordered-list',\n        ],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'content', 0, 'nodeType'],\n        value: 'text',\n      },\n    ]);\n  });\n\n  it('fails on invalid block nodes inside of a table node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [BLOCKS.TABLE_ROW],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'nodeType'],\n        value: BLOCKS.PARAGRAPH,\n      },\n    ]);\n  });\n\n  it('fails on invalid block nodes inside of a table row node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'content', 0, 'nodeType'],\n        value: BLOCKS.PARAGRAPH,\n      },\n    ]);\n  });\n\n  it('fails on invalid block nodes inside of a table header node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'content', 0, 'nodeType'],\n        value: BLOCKS.PARAGRAPH,\n      },\n    ]);\n  });\n\n  it.each([BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL] as const)(\n    'fails on invalid node inside of %s',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType: BLOCKS.TABLE,\n            content: [\n              {\n                nodeType: BLOCKS.TABLE_ROW,\n                content: [\n                  {\n                    nodeType,\n                    content: [{ nodeType: 'text', data: {}, marks: [], value: 'Hello World' }],\n                    data: {},\n                  },\n                ],\n                data: {},\n              },\n            ],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Value must be one of expected values',\n          expected: [BLOCKS.PARAGRAPH],\n          name: 'in',\n          path: ['content', 0, 'content', 0, 'content', 0, 'content', 0, 'nodeType'],\n          value: 'text',\n        },\n      ]);\n    },\n  );\n\n  it('fails if a table node has not at least one table row', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Size must be at least 1',\n        min: 1,\n        name: 'size',\n        path: ['content', 0, 'content'],\n        value: [],\n      },\n    ]);\n  });\n\n  it('fails if a table row node has not at least one table cell', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              content: [],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Size must be at least 1',\n        min: 1,\n        name: 'size',\n        path: ['content', 0, 'content', 0, 'content'],\n        value: [],\n      },\n    ]);\n  });\n\n  it.each([BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL] as const)(\n    'fails if a %s has not at least one child',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType: BLOCKS.TABLE,\n            content: [\n              {\n                nodeType: BLOCKS.TABLE_ROW,\n                content: [\n                  {\n                    nodeType,\n                    content: [],\n                    data: {},\n                  },\n                ],\n                data: {},\n              },\n            ],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Size must be at least 1',\n          min: 1,\n          name: 'size',\n          path: ['content', 0, 'content', 0, 'content', 0, 'content'],\n          value: [],\n        },\n      ]);\n    },\n  );\n\n  it('fails if inline nodes contains something else as a inline node or text', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          content: [\n            {\n              nodeType: INLINES.HYPERLINK,\n              // @ts-expect-error we force a wrong node type to check that it fails\n              content: [{ nodeType: BLOCKS.PARAGRAPH, content: [], data: {} }],\n              data: { uri: '' },\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: ['text'],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'content', 0, 'nodeType'],\n        value: BLOCKS.PARAGRAPH,\n      },\n    ]);\n  });\n\n  it.each([\n    BLOCKS.HEADING_1,\n    BLOCKS.HEADING_2,\n    BLOCKS.HEADING_3,\n    BLOCKS.HEADING_4,\n    BLOCKS.HEADING_5,\n    BLOCKS.HEADING_6,\n  ] as const)(\n    'fails if the headline node (%s) contains something else as a inline or text node',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType,\n            content: [\n              {\n                nodeType: BLOCKS.QUOTE,\n                content: [{ nodeType: 'text', value: 'Hello World', data: {}, marks: [] }],\n                data: {},\n              },\n            ],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'Value must be one of expected values',\n          expected: [\n            'asset-hyperlink',\n            'embedded-entry-inline',\n            'embedded-resource-inline',\n            'entry-hyperlink',\n            'hyperlink',\n            'resource-hyperlink',\n            'text',\n          ],\n          name: 'in',\n          path: ['content', 0, 'content', 0, 'nodeType'],\n          value: BLOCKS.QUOTE,\n        },\n      ]);\n    },\n  );\n\n  it('fails on invalid block nodes inside of a quote node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.QUOTE,\n          content: [\n            {\n              nodeType: BLOCKS.HEADING_1,\n              content: [{ nodeType: 'text', value: 'Hello World', data: {}, marks: [] }],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'Value must be one of expected values',\n        expected: [BLOCKS.PARAGRAPH],\n        name: 'in',\n        path: ['content', 0, 'content', 0, 'nodeType'],\n        value: BLOCKS.HEADING_1,\n      },\n    ]);\n  });\n\n  it('fails without value property on text nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          content: [\n            {\n              nodeType: 'text',\n              value: null,\n              data: {},\n              marks: [],\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"value\" is incorrect, expected type: String',\n        name: 'type',\n        path: ['content', 0, 'content', 0, 'value'],\n        type: 'String',\n        value: null,\n      },\n    ]);\n  });\n\n  it('fails with invalid row/colspan on table cell nodes', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      content: [{ nodeType: 'text', value: 'Hello Table', data: {}, marks: [] }],\n                      data: {},\n                    },\n                  ],\n                  data: { rowspan: 'argh' },\n                },\n              ],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The type of \"rowspan\" is incorrect, expected type: Number',\n        name: 'type',\n        path: ['content', 0, 'content', 0, 'content', 0, 'data', 'rowspan'],\n        type: 'Number',\n        value: 'argh',\n      },\n    ]);\n  });\n\n  it.each([INLINES.ASSET_HYPERLINK, INLINES.ENTRY_HYPERLINK, INLINES.RESOURCE_HYPERLINK] as const)(\n    'fails with invalid properties for %s',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            content: [\n              {\n                nodeType,\n                data: {},\n                content: [{ nodeType: 'text', value: `Hello ${nodeType}`, data: {}, marks: [] }],\n              },\n            ],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'The property \"target\" is required here',\n          name: 'required',\n          path: ['content', 0, 'content', 0, 'data', 'target'],\n        },\n      ]);\n    },\n  );\n\n  it('fails with invalid properties for hypperlink node', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          content: [\n            {\n              nodeType: INLINES.HYPERLINK,\n              data: {},\n              content: [{ nodeType: 'text', value: 'Hello hyperlink', data: {}, marks: [] }],\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([\n      {\n        details: 'The property \"uri\" is required here',\n        name: 'required',\n        path: ['content', 0, 'content', 0, 'data', 'uri'],\n      },\n    ]);\n  });\n\n  it.each([INLINES.EMBEDDED_ENTRY, INLINES.EMBEDDED_RESOURCE] as const)(\n    'fails with invalid properties for %s',\n    (nodeType) => {\n      const document: Document = {\n        nodeType: BLOCKS.DOCUMENT,\n        content: [\n          {\n            nodeType: BLOCKS.PARAGRAPH,\n            content: [\n              {\n                nodeType,\n                data: {},\n                content: [],\n              },\n            ],\n            data: {},\n          },\n        ],\n        data: {},\n      };\n\n      expect(validateRichTextDocument(document)).toEqual([\n        {\n          details: 'The property \"target\" is required here',\n          name: 'required',\n          path: ['content', 0, 'content', 0, 'data', 'target'],\n        },\n      ]);\n    },\n  );\n\n  it('succeeds with a valid structure', () => {\n    const document: Document = {\n      nodeType: BLOCKS.DOCUMENT,\n      content: [\n        {\n          nodeType: BLOCKS.PARAGRAPH,\n          content: [{ nodeType: 'text', value: 'Hello World', data: {}, marks: [] }],\n          data: {},\n        },\n        {\n          nodeType: BLOCKS.HEADING_1,\n          content: [{ nodeType: 'text', value: 'Hello Headline', data: {}, marks: [] }],\n          data: {},\n        },\n        {\n          nodeType: BLOCKS.UL_LIST,\n          content: [\n            {\n              nodeType: BLOCKS.LIST_ITEM,\n              content: [\n                {\n                  nodeType: BLOCKS.PARAGRAPH,\n                  content: [{ nodeType: 'text', value: 'Hello List', data: {}, marks: [] }],\n                  data: {},\n                },\n              ],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n        {\n          nodeType: BLOCKS.TABLE,\n          content: [\n            {\n              nodeType: BLOCKS.TABLE_ROW,\n              content: [\n                {\n                  nodeType: BLOCKS.TABLE_CELL,\n                  content: [\n                    {\n                      nodeType: BLOCKS.PARAGRAPH,\n                      content: [{ nodeType: 'text', value: 'Hello Table', data: {}, marks: [] }],\n                      data: {},\n                    },\n                  ],\n                  data: { rowspan: 2, colspan: 2 },\n                },\n              ],\n              data: {},\n            },\n          ],\n          data: {},\n        },\n      ],\n      data: {},\n    };\n\n    expect(validateRichTextDocument(document)).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "packages/rich-text-types/jest.config.js",
    "content": "/* eslint-disable */\n\nconst getBaseConfig = require('../../baseJestConfig');\nconst packageJson = require('./package.json');\nconst packageName = packageJson.name.split('@contentful/')[1];\n\nmodule.exports = {\n  ...getBaseConfig(packageName),\n};\n"
  },
  {
    "path": "packages/rich-text-types/package.json",
    "content": "{\n  \"name\": \"@contentful/rich-text-types\",\n  \"version\": \"17.2.7\",\n  \"main\": \"dist/cjs/index.js\",\n  \"module\": \"dist/esm/index.mjs\",\n  \"types\": \"dist/types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"import\": \"./dist/esm/index.mjs\",\n      \"require\": \"./dist/cjs/index.js\",\n      \"default\": \"./dist/cjs/index.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/contentful/rich-text.git\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://npm.pkg.github.com/\"\n  },\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"npm run build:types && npm run build:cjs && npm run build:esm && npm run fix-esm-imports\",\n    \"build:types\": \"tsc --outDir dist/types --emitDeclarationOnly\",\n    \"build:cjs\": \"swc src --strip-leading-paths --config-file ../../.swcrc -d dist/cjs -C module.type=commonjs\",\n    \"build:esm\": \"swc src --strip-leading-paths --config-file ../../.swcrc -d dist/esm --out-file-extension mjs -C jsc.target=es2022 -C module.type=es6 -C module.resolveFully=true -C module.outFileExtension=mjs\",\n    \"fix-esm-imports\": \"node ./scripts/fix-esm-import-extensions.mjs\",\n    \"start\": \"tsc && swc src --strip-leading-paths --config-file ../../.swcrc -d dist/esm --out-file-extension mjs -C module.type=es6 -C module.resolveFully=true -C module.outFileExtension=mjs -w\",\n    \"test\": \"jest\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/node\": \"^25.0.2\",\n    \"ts-jest\": \"^29.1.2\"\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-types/scripts/fix-esm-import-extensions.mjs",
    "content": "// Rewrite relative `*.js` specifiers to `*.mjs` across built ESM files\nimport { readdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst esmDir = join(here, '..', 'dist', 'esm');\n\n// Recursively walk all .mjs files under `dir`\nasync function* walk(dir) {\n  for (const entry of await readdir(dir, { withFileTypes: true })) {\n    const p = join(dir, entry.name);\n    if (entry.isDirectory()) yield* walk(p);\n    else if (extname(p) === '.mjs') yield p;\n  }\n}\n\nconst REWRITES = [\n  // import ... from './x.js'\n  [/(from\\s+['\"])(\\.{1,2}\\/[^'\"]+)\\.js(['\"])/g, '$1$2.mjs$3'],\n  // export ... from './x.js'\n  [/(export\\s+(?:\\*|{[\\s\\S]*?})\\s+from\\s+['\"])(\\.{1,2}\\/[^'\"]+)\\.js(['\"])/g, '$1$2.mjs$3'],\n  // import('./x.js')\n  [/(import\\(\\s*['\"])(\\.{1,2}\\/[^'\"]+)\\.js(['\"]\\s*\\))/g, '$1$2.mjs$3'],\n];\n\nfunction rewrite(code) {\n  return REWRITES.reduce((s, [re, replacement]) => s.replace(re, replacement), code);\n}\n\nfor await (const file of walk(esmDir)) {\n  const original = await readFile(file, 'utf8');\n  const updated = rewrite(original);\n  if (updated !== original) {\n    await writeFile(file, updated, 'utf8');\n  }\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/blocks.ts",
    "content": "/**\n * Map of all Contentful block types. Blocks contain inline or block nodes.\n */\nexport enum BLOCKS {\n  DOCUMENT = 'document',\n  PARAGRAPH = 'paragraph',\n\n  HEADING_1 = 'heading-1',\n  HEADING_2 = 'heading-2',\n  HEADING_3 = 'heading-3',\n  HEADING_4 = 'heading-4',\n  HEADING_5 = 'heading-5',\n  HEADING_6 = 'heading-6',\n\n  OL_LIST = 'ordered-list',\n  UL_LIST = 'unordered-list',\n  LIST_ITEM = 'list-item',\n\n  HR = 'hr',\n  QUOTE = 'blockquote',\n\n  EMBEDDED_ENTRY = 'embedded-entry-block',\n  EMBEDDED_ASSET = 'embedded-asset-block',\n  EMBEDDED_RESOURCE = 'embedded-resource-block',\n\n  TABLE = 'table',\n  TABLE_ROW = 'table-row',\n  TABLE_CELL = 'table-cell',\n  TABLE_HEADER_CELL = 'table-header-cell',\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/emptyDocument.ts",
    "content": "import { BLOCKS } from './blocks.js';\nimport { Document } from './types.js';\n\n/**\n * A rich text document considered to be empty.\n * Any other document structure than this is not considered empty.\n */\nexport const EMPTY_DOCUMENT: Document = {\n  nodeType: BLOCKS.DOCUMENT,\n  data: {},\n  content: [\n    {\n      nodeType: BLOCKS.PARAGRAPH,\n      data: {},\n      content: [\n        {\n          nodeType: 'text',\n          value: '',\n          marks: [],\n          data: {},\n        },\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/rich-text-types/src/helpers.ts",
    "content": "import { BLOCKS } from './blocks.js';\nimport { INLINES } from './inlines.js';\nimport { Block, Inline, Node, Text, Document as CDocument } from './types.js';\n\n/**\n * Tiny replacement for Object.values(object).includes(key) to\n * avoid including CoreJS polyfills\n */\nfunction hasValue(obj: Record<string, unknown>, value: unknown) {\n  for (const key of Object.keys(obj)) {\n    if (value === obj[key]) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\n/**\n * Checks if the node is an instance of Inline.\n */\nexport function isInline(node: Node): node is Inline {\n  return hasValue(INLINES, node.nodeType);\n}\n\n/**\n * Checks if the node is an instance of Block.\n */\nexport function isBlock(node: Node): node is Block {\n  return hasValue(BLOCKS, node.nodeType);\n}\n\n/**\n * Checks if the node is an instance of Text.\n */\nexport function isText(node: Node): node is Text {\n  return node.nodeType === 'text';\n}\n\n/**\n * Checks if a paragraph is empty (has only one child and that child is an empty string text node)\n */\nexport function isEmptyParagraph(node: Block): boolean {\n  if (node.nodeType !== BLOCKS.PARAGRAPH) {\n    return false;\n  }\n\n  if (node.content.length !== 1) {\n    return false;\n  }\n\n  const textNode = node.content[0];\n  return textNode.nodeType === 'text' && (textNode as Text).value === '';\n}\n\nfunction isValidDocument(document: unknown): document is CDocument {\n  return (\n    document != null &&\n    typeof document === 'object' &&\n    'content' in document &&\n    Array.isArray((document as CDocument).content)\n  );\n}\n\nconst MIN_NODES_FOR_STRIPPING = 2;\n\n/**\n * Strips empty trailing paragraph from a document if enabled\n * @param document - The rich text document to process\n * @returns A new document with the empty trailing paragraph removed (if conditions are met)\n * @example\n * const processedDoc = stripEmptyTrailingParagraphFromDocument(document);\n */\nexport function stripEmptyTrailingParagraphFromDocument(document: CDocument): CDocument {\n  if (!isValidDocument(document) || document.content.length < MIN_NODES_FOR_STRIPPING) {\n    return document;\n  }\n\n  const lastNode = document.content[document.content.length - 1];\n\n  // Check if the last node is an empty paragraph\n  if (isEmptyParagraph(lastNode)) {\n    return {\n      ...document,\n      content: document.content.slice(0, -1),\n    };\n  }\n\n  return document;\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/index.ts",
    "content": "export { BLOCKS } from './blocks.js';\nexport { INLINES } from './inlines.js';\nexport { MARKS } from './marks.js';\n\nexport * from './schemaConstraints.js';\n\nexport * from './types.js';\nexport * from './nodeTypes.js';\n\nexport { EMPTY_DOCUMENT } from './emptyDocument.js';\n\nimport * as helpers from './helpers.js';\nexport { helpers };\n\nexport { validateRichTextDocument } from './validator/index.js';\nexport type { ValidationError } from './validator/index.js';\n"
  },
  {
    "path": "packages/rich-text-types/src/inlines.ts",
    "content": "/**\n * Map of all Contentful inline types. Inline contain inline or text nodes.\n *\n * @note This should be kept in alphabetical order since the\n * [validation package](https://github.com/contentful/content-stack/tree/master/packages/validation)\n *  relies on the values being in a predictable order.\n */\nexport enum INLINES {\n  ASSET_HYPERLINK = 'asset-hyperlink',\n  EMBEDDED_ENTRY = 'embedded-entry-inline',\n  EMBEDDED_RESOURCE = 'embedded-resource-inline',\n  ENTRY_HYPERLINK = 'entry-hyperlink',\n  HYPERLINK = 'hyperlink',\n  RESOURCE_HYPERLINK = 'resource-hyperlink',\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/marks.ts",
    "content": "/**\n * Map of all Contentful marks.\n */\nexport enum MARKS {\n  BOLD = 'bold',\n  ITALIC = 'italic',\n  UNDERLINE = 'underline',\n  CODE = 'code',\n  SUPERSCRIPT = 'superscript',\n  SUBSCRIPT = 'subscript',\n  STRIKETHROUGH = 'strikethrough',\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/nodeTypes.ts",
    "content": "import { BLOCKS } from './blocks.js';\nimport { INLINES } from './inlines.js';\nimport { Block, Inline, ListItemBlock, Text } from './types.js';\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype EmptyNodeData = {};\n// BLOCKS\n\n// Heading\nexport interface Heading1 extends Block {\n  nodeType: BLOCKS.HEADING_1;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\nexport interface Heading2 extends Block {\n  nodeType: BLOCKS.HEADING_2;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\nexport interface Heading3 extends Block {\n  nodeType: BLOCKS.HEADING_3;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\nexport interface Heading4 extends Block {\n  nodeType: BLOCKS.HEADING_4;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\nexport interface Heading5 extends Block {\n  nodeType: BLOCKS.HEADING_5;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\nexport interface Heading6 extends Block {\n  nodeType: BLOCKS.HEADING_6;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\n// Paragraph\nexport interface Paragraph extends Block {\n  nodeType: BLOCKS.PARAGRAPH;\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\n// Quote\nexport interface Quote extends Block {\n  nodeType: BLOCKS.QUOTE;\n  data: EmptyNodeData;\n  content: Paragraph[];\n}\n// Horizontal rule\nexport interface Hr extends Block {\n  nodeType: BLOCKS.HR;\n  /**\n   *\n   * @maxItems 0\n   */\n  data: EmptyNodeData;\n  content: Array<Inline | Text>;\n}\n\n// OL\nexport interface OrderedList extends Block {\n  nodeType: BLOCKS.OL_LIST;\n  data: EmptyNodeData;\n  content: ListItem[];\n}\n// UL\nexport interface UnorderedList extends Block {\n  nodeType: BLOCKS.UL_LIST;\n  data: EmptyNodeData;\n  content: ListItem[];\n}\n\nexport interface ListItem extends Block {\n  nodeType: BLOCKS.LIST_ITEM;\n  data: EmptyNodeData;\n  content: ListItemBlock[];\n}\n\n// taken from graphql schema-generator/contentful-types/link.ts\nexport interface Link<T extends string = string> {\n  sys: {\n    type: 'Link';\n    linkType: T;\n    id: string;\n  };\n}\n\nexport interface ResourceLink {\n  sys: {\n    type: 'ResourceLink';\n    linkType: 'Contentful:Entry';\n    urn: string;\n  };\n}\n\nexport interface EntryLinkBlock extends Block {\n  nodeType: BLOCKS.EMBEDDED_ENTRY;\n  data: {\n    target: Link<'Entry'>;\n  };\n  /**\n   *\n   * @maxItems 0\n   */\n  content: Array<Inline | Text>;\n}\n\nexport interface AssetLinkBlock extends Block {\n  nodeType: BLOCKS.EMBEDDED_ASSET;\n  data: {\n    target: Link<'Asset'>;\n  };\n  /**\n   *\n   * @maxItems 0\n   */\n  content: Array<Inline | Text>;\n}\n\nexport interface ResourceLinkBlock extends Block {\n  nodeType: BLOCKS.EMBEDDED_RESOURCE;\n  data: {\n    target: ResourceLink;\n  };\n  /**\n   *\n   * @maxItems 0\n   */\n  content: Array<Inline | Text>;\n}\n\n// INLINE\n\nexport interface EntryLinkInline extends Inline {\n  nodeType: INLINES.EMBEDDED_ENTRY;\n  data: {\n    target: Link<'Entry'>;\n  };\n  /**\n   *\n   * @maxItems 0\n   */\n  content: Text[];\n}\n\nexport interface ResourceLinkInline extends Inline {\n  nodeType: INLINES.EMBEDDED_RESOURCE;\n  data: {\n    target: ResourceLink;\n  };\n  /**\n   *\n   * @maxItems 0\n   */\n  content: Text[];\n}\n\nexport interface Hyperlink extends Inline {\n  nodeType: INLINES.HYPERLINK;\n  data: {\n    uri: string;\n  };\n  content: Text[];\n}\n\nexport interface AssetHyperlink extends Inline {\n  nodeType: INLINES.ASSET_HYPERLINK;\n  data: {\n    target: Link<'Asset'>;\n  };\n  content: Text[];\n}\n\nexport interface EntryHyperlink extends Inline {\n  nodeType: INLINES.ENTRY_HYPERLINK;\n  data: {\n    target: Link<'Entry'>;\n  };\n  content: Text[];\n}\n\nexport interface ResourceHyperlink extends Inline {\n  nodeType: INLINES.RESOURCE_HYPERLINK;\n  data: {\n    target: ResourceLink;\n  };\n  content: Text[];\n}\n\nexport interface TableCell extends Block {\n  nodeType: BLOCKS.TABLE_HEADER_CELL | BLOCKS.TABLE_CELL;\n  data: {\n    colspan?: number;\n    rowspan?: number;\n  };\n\n  /**\n   * @minItems 1\n   */\n  content: Paragraph[];\n}\n\nexport interface TableHeaderCell extends TableCell {\n  nodeType: BLOCKS.TABLE_HEADER_CELL;\n}\n\n// An abstract table row can have both table cell types\n\nexport interface TableRow extends Block {\n  nodeType: BLOCKS.TABLE_ROW;\n  data: EmptyNodeData;\n\n  /**\n   * @minItems 1\n   */\n  content: TableCell[];\n}\n\nexport interface Table extends Block {\n  nodeType: BLOCKS.TABLE;\n  data: EmptyNodeData;\n\n  /**\n   * @minItems 1\n   */\n  content: TableRow[];\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/schemaConstraints.ts",
    "content": "import { BLOCKS } from './blocks.js';\nimport { INLINES } from './inlines.js';\nimport { MARKS } from './marks.js';\n\nexport type TopLevelBlockEnum =\n  | BLOCKS.PARAGRAPH\n  | BLOCKS.HEADING_1\n  | BLOCKS.HEADING_2\n  | BLOCKS.HEADING_3\n  | BLOCKS.HEADING_4\n  | BLOCKS.HEADING_5\n  | BLOCKS.HEADING_6\n  | BLOCKS.OL_LIST\n  | BLOCKS.UL_LIST\n  | BLOCKS.HR\n  | BLOCKS.QUOTE\n  | BLOCKS.EMBEDDED_ENTRY\n  | BLOCKS.EMBEDDED_ASSET\n  | BLOCKS.EMBEDDED_RESOURCE\n  | BLOCKS.TABLE;\n\n/**\n * Array of all top level block types.\n * Only these block types can be the direct children of the document.\n */\nexport const TOP_LEVEL_BLOCKS: TopLevelBlockEnum[] = [\n  BLOCKS.PARAGRAPH,\n  BLOCKS.HEADING_1,\n  BLOCKS.HEADING_2,\n  BLOCKS.HEADING_3,\n  BLOCKS.HEADING_4,\n  BLOCKS.HEADING_5,\n  BLOCKS.HEADING_6,\n  BLOCKS.OL_LIST,\n  BLOCKS.UL_LIST,\n  BLOCKS.HR,\n  BLOCKS.QUOTE,\n  BLOCKS.EMBEDDED_ENTRY,\n  BLOCKS.EMBEDDED_ASSET,\n  BLOCKS.EMBEDDED_RESOURCE,\n  BLOCKS.TABLE,\n];\n\nexport type ListItemBlockEnum =\n  | BLOCKS.PARAGRAPH\n  | BLOCKS.HEADING_1\n  | BLOCKS.HEADING_2\n  | BLOCKS.HEADING_3\n  | BLOCKS.HEADING_4\n  | BLOCKS.HEADING_5\n  | BLOCKS.HEADING_6\n  | BLOCKS.OL_LIST\n  | BLOCKS.UL_LIST\n  | BLOCKS.HR\n  | BLOCKS.QUOTE\n  | BLOCKS.EMBEDDED_ENTRY\n  | BLOCKS.EMBEDDED_ASSET\n  | BLOCKS.EMBEDDED_RESOURCE;\n\n/**\n * Array of all allowed block types inside list items\n */\nexport const LIST_ITEM_BLOCKS: TopLevelBlockEnum[] = [\n  BLOCKS.PARAGRAPH,\n  BLOCKS.HEADING_1,\n  BLOCKS.HEADING_2,\n  BLOCKS.HEADING_3,\n  BLOCKS.HEADING_4,\n  BLOCKS.HEADING_5,\n  BLOCKS.HEADING_6,\n  BLOCKS.OL_LIST,\n  BLOCKS.UL_LIST,\n  BLOCKS.HR,\n  BLOCKS.QUOTE,\n  BLOCKS.EMBEDDED_ENTRY,\n  BLOCKS.EMBEDDED_ASSET,\n  BLOCKS.EMBEDDED_RESOURCE,\n];\n\nexport const TABLE_BLOCKS = [\n  BLOCKS.TABLE,\n  BLOCKS.TABLE_ROW,\n  BLOCKS.TABLE_CELL,\n  BLOCKS.TABLE_HEADER_CELL,\n];\n\n/**\n * Array of all void block types\n */\nexport const VOID_BLOCKS = [\n  BLOCKS.HR,\n  BLOCKS.EMBEDDED_ENTRY,\n  BLOCKS.EMBEDDED_ASSET,\n  BLOCKS.EMBEDDED_RESOURCE,\n];\n\n/**\n * Dictionary of all container block types, and the set block types they accept as children.\n *\n * Note: This does not include `[BLOCKS.DOCUMENT]: TOP_LEVEL_BLOCKS`\n */\nexport const CONTAINERS = {\n  [BLOCKS.OL_LIST]: [BLOCKS.LIST_ITEM],\n  [BLOCKS.UL_LIST]: [BLOCKS.LIST_ITEM],\n  [BLOCKS.LIST_ITEM]: LIST_ITEM_BLOCKS,\n  [BLOCKS.QUOTE]: [BLOCKS.PARAGRAPH],\n  [BLOCKS.TABLE]: [BLOCKS.TABLE_ROW],\n  [BLOCKS.TABLE_ROW]: [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL],\n  [BLOCKS.TABLE_CELL]: [BLOCKS.PARAGRAPH, BLOCKS.UL_LIST, BLOCKS.OL_LIST],\n  [BLOCKS.TABLE_HEADER_CELL]: [BLOCKS.PARAGRAPH],\n};\n\n/**\n * Array of all heading levels\n */\nexport const HEADINGS = [\n  BLOCKS.HEADING_1,\n  BLOCKS.HEADING_2,\n  BLOCKS.HEADING_3,\n  BLOCKS.HEADING_4,\n  BLOCKS.HEADING_5,\n  BLOCKS.HEADING_6,\n];\n\n/**\n * Array of all block types that may contain text and inline nodes.\n */\nexport const TEXT_CONTAINERS = [BLOCKS.PARAGRAPH, ...HEADINGS];\n\n/**\n * Node types before `tables` release.\n */\nexport const V1_NODE_TYPES = [\n  BLOCKS.DOCUMENT,\n  BLOCKS.PARAGRAPH,\n  BLOCKS.HEADING_1,\n  BLOCKS.HEADING_2,\n  BLOCKS.HEADING_3,\n  BLOCKS.HEADING_4,\n  BLOCKS.HEADING_5,\n  BLOCKS.HEADING_6,\n  BLOCKS.OL_LIST,\n  BLOCKS.UL_LIST,\n  BLOCKS.LIST_ITEM,\n  BLOCKS.HR,\n  BLOCKS.QUOTE,\n  BLOCKS.EMBEDDED_ENTRY,\n  BLOCKS.EMBEDDED_ASSET,\n  INLINES.HYPERLINK,\n  INLINES.ENTRY_HYPERLINK,\n  INLINES.ASSET_HYPERLINK,\n  INLINES.EMBEDDED_ENTRY,\n  'text',\n];\n\n/**\n * Marks before `superscript` & `subscript` release.\n */\nexport const V1_MARKS = [MARKS.BOLD, MARKS.CODE, MARKS.ITALIC, MARKS.UNDERLINE];\n"
  },
  {
    "path": "packages/rich-text-types/src/types.ts",
    "content": "import { BLOCKS } from './blocks.js';\nimport { INLINES } from './inlines.js';\nimport { ListItemBlockEnum, TopLevelBlockEnum } from './schemaConstraints.js';\n\n/**\n * @additionalProperties true\n */\nexport type NodeData = Record<string, any>;\nexport interface Node {\n  readonly nodeType: string;\n\n  data: NodeData;\n}\n\nexport interface Block extends Node {\n  nodeType: BLOCKS;\n  content: Array<Block | Inline | Text>;\n}\n\nexport interface Inline extends Node {\n  nodeType: INLINES;\n  content: Array<Inline | Text>;\n}\n\nexport interface TopLevelBlock extends Block {\n  nodeType: TopLevelBlockEnum;\n}\n\nexport interface Document extends Node {\n  nodeType: BLOCKS.DOCUMENT;\n  content: TopLevelBlock[];\n}\n\nexport interface Text extends Node {\n  nodeType: 'text';\n  value: string;\n  marks: Mark[];\n}\n\nexport interface Mark {\n  type: string;\n}\n\nexport interface ListItemBlock extends Block {\n  nodeType: ListItemBlockEnum;\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/assert.ts",
    "content": "import {\n  maxSizeError,\n  typeMismatchError,\n  enumError,\n  unknownPropertyError,\n  requiredPropertyError,\n  minSizeError,\n} from './errors.js';\nimport type { Path } from './path.js';\nimport { ValidationError } from './types.js';\n\nexport class ObjectAssertion {\n  private _errors: ValidationError[] = [];\n\n  constructor(\n    private readonly obj: Record<string, any>,\n    private readonly path: Path,\n  ) {}\n\n  catch = (...errors: ValidationError[]): void => {\n    this._errors.push(...errors);\n  };\n\n  get errors(): ValidationError[] {\n    const serializeError = (error: ValidationError): string =>\n      JSON.stringify({\n        details: error.details,\n        path: error.path,\n      });\n\n    return this._errors.filter(\n      (error, index) =>\n        this._errors.findIndex((step) => serializeError(error) === serializeError(step)) === index,\n    );\n  }\n\n  /**\n   * Asserts the key exists in the object. You probably shouldn't call this\n   * function directly. Instead, use `$.object`, `$.number`, `$.string`, etc.\n   */\n  exists = (key: string): boolean => {\n    if (key in this.obj) {\n      return true;\n    }\n\n    this.catch(\n      requiredPropertyError({\n        property: key,\n        path: this.path.of(key),\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the key exists in the object and its value is a plain object. if\n   * no key is provided, it asserts the object itself.\n   */\n  public object = (key?: string): boolean => {\n    const value = key ? this.obj[key] : this.obj;\n\n    if (key) {\n      if (!this.exists(key)) {\n        return false;\n      }\n    }\n\n    if (typeof value === 'object' && !Array.isArray(value) && value !== null) {\n      return true;\n    }\n\n    const path = key ? this.path.of(key) : this.path;\n    const property = key ?? this.path.last() ?? 'value';\n\n    this.catch(\n      typeMismatchError({\n        typeName: 'Object',\n        property,\n        path,\n        value,\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the key exists in the object and its value is a string.\n   */\n  public string = (key: string): boolean => {\n    const value = this.obj[key];\n\n    if (key && !this.exists(key)) {\n      return false;\n    }\n\n    if (typeof value === 'string') {\n      return true;\n    }\n\n    this.catch(\n      typeMismatchError({\n        typeName: 'String',\n        property: key,\n        path: this.path.of(key),\n        value,\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the key exists in the object and its value is a number.\n   */\n  public number = (key: string, optional?: boolean): boolean => {\n    const value = this.obj[key];\n\n    if (optional && !(key in this.obj)) {\n      return true;\n    }\n\n    if (!this.exists(key)) {\n      return false;\n    }\n\n    if (typeof value === 'number' && !Number.isNaN(value)) {\n      return true;\n    }\n\n    this.catch(\n      typeMismatchError({\n        typeName: 'Number',\n        property: key,\n        path: this.path.of(key),\n        value,\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the key exists in the object and its value is an array. You don't\n   * need to manually call this function before `$.each` or `$.maxLength`.\n   */\n  public array = (key: string): boolean => {\n    const value = this.obj[key];\n\n    if (key && !this.exists(key)) {\n      return false;\n    }\n\n    if (Array.isArray(value)) {\n      return true;\n    }\n\n    this.catch(\n      typeMismatchError({\n        typeName: 'Array',\n        property: key,\n        path: this.path.of(key),\n        value,\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the value of the key is one of the expected values.\n   */\n  public enum = (key: string, expected: string[]): boolean => {\n    const value = this.obj[key];\n\n    if (typeof value === 'string' && expected.includes(value)) {\n      return true;\n    }\n\n    this.catch(\n      enumError({\n        expected,\n        value,\n        path: this.path.of(key),\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the array value of the object key is empty. If the value isn't an\n   * array, the function captures a type error and returns false.\n   */\n  public empty = (key: string): boolean => {\n    if (!this.array(key)) {\n      return false;\n    }\n\n    const value = this.obj[key] as Array<unknown>;\n\n    if (value.length === 0) {\n      return true;\n    }\n\n    this.catch(\n      maxSizeError({\n        max: 0,\n        value,\n        path: this.path.of(key),\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the length of the value of the object key is at least `min`. If the\n   * value isn't an array, the function captures a type error and returns false.\n   */\n  public minLength = (key: string, min: number): boolean => {\n    if (!this.array(key)) {\n      return false;\n    }\n\n    const value = this.obj[key] as Array<unknown>;\n\n    if (value.length >= min) {\n      return true;\n    }\n\n    this.catch(\n      minSizeError({\n        min,\n        value,\n        path: this.path.of(key),\n      }),\n    );\n\n    return false;\n  };\n\n  /**\n   * Asserts the object has no additional properties other than the ones\n   * specified\n   */\n  public noAdditionalProperties = (properties: string[]): boolean => {\n    const unknowns = Object.keys(this.obj)\n      .sort()\n      .filter((key) => !properties.includes(key));\n\n    unknowns.forEach((property) =>\n      this.catch(\n        unknownPropertyError({\n          property,\n          path: this.path.of(property),\n        }),\n      ),\n    );\n\n    return unknowns.length === 0;\n  };\n\n  /**\n   * Iterates over the value of the key and assert each item. If the value isn't\n   * an array, the function captures a type error and safely exits.\n   *\n   * To maintain compatibility with previous implementation, we stop early if we\n   * find any errors.\n   */\n  public each = (key: string, assert: (item: any, path: Path) => ValidationError[]): void => {\n    if (!this.array(key)) {\n      return;\n    }\n\n    const value = this.obj[key] as Array<any>;\n\n    let foundErrors = false;\n    value.forEach((item, index) => {\n      if (foundErrors) {\n        return;\n      }\n\n      const errors = assert(item, this.path.of(key).of(index));\n\n      if (errors.length > 0) {\n        foundErrors = true;\n      }\n\n      this.catch(...errors);\n    });\n  };\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/errors.ts",
    "content": "import type { Path } from './path.js';\nimport { ValidationError } from './types.js';\n\nexport const typeMismatchError = ({\n  path,\n  property,\n  typeName,\n  value,\n}: {\n  path: Path;\n  property: string | number;\n  typeName: string;\n  value: any;\n}): ValidationError => {\n  return {\n    details: `The type of \"${property}\" is incorrect, expected type: ${typeName}`,\n    name: 'type',\n    path: path.toArray(),\n    type: typeName,\n    value,\n  };\n};\n\nexport const minSizeError = ({\n  min,\n  value,\n  path,\n}: {\n  min: number;\n  value: any;\n  path: Path;\n}): ValidationError => {\n  return {\n    name: 'size',\n    min,\n    path: path.toArray(),\n    details: `Size must be at least ${min}`,\n    value,\n  };\n};\n\nexport const maxSizeError = ({\n  max,\n  value,\n  path,\n}: {\n  max: number;\n  value: any;\n  path: Path;\n}): ValidationError => {\n  return {\n    name: 'size',\n    max,\n    path: path.toArray(),\n    details: `Size must be at most ${max}`,\n    value,\n  };\n};\n\nexport const enumError = ({\n  expected,\n  value,\n  path,\n}: {\n  expected: string[];\n  value: any;\n  path: Path;\n}): ValidationError => {\n  return {\n    details: `Value must be one of expected values`,\n    name: 'in',\n    expected: [...expected].sort(),\n    path: path.toArray(),\n    value,\n  };\n};\n\nexport const unknownPropertyError = ({\n  property,\n  path,\n}: {\n  property: string;\n  path: Path;\n}): ValidationError => {\n  return {\n    details: `The property \"${property}\" is not expected`,\n    name: 'unexpected',\n    path: path.toArray(),\n  };\n};\n\nexport const requiredPropertyError = ({\n  property,\n  path,\n}: {\n  property: string;\n  path: Path;\n}): ValidationError => {\n  return {\n    details: `The property \"${property}\" is required here`,\n    name: 'required',\n    path: path.toArray(),\n  };\n};\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/index.ts",
    "content": "import { BLOCKS } from '../blocks.js';\nimport { INLINES } from '../inlines.js';\nimport { CONTAINERS, LIST_ITEM_BLOCKS, TOP_LEVEL_BLOCKS } from '../schemaConstraints.js';\nimport { Document, Text } from '../types.js';\nimport { ObjectAssertion } from './assert.js';\nimport {\n  NodeAssertion,\n  Node,\n  HyperLinkAssertion,\n  assert,\n  assertLink,\n  VOID_CONTENT,\n} from './node.js';\nimport { Path } from './path.js';\nimport { assertText } from './text.js';\nimport type { ValidationError } from './types.js';\n\nexport type { ValidationError };\n\nconst assertInlineOrText = assert([...Object.values(INLINES), 'text'].sort());\n\nconst assertList = assert([BLOCKS.LIST_ITEM]);\nconst assertVoidEntryLink = assertLink('Entry', VOID_CONTENT);\nconst assertTableCell = assert(\n  () => ({\n    nodeTypes: [BLOCKS.PARAGRAPH],\n    min: 1,\n  }),\n  (data, path) => {\n    const $ = new ObjectAssertion(data, path);\n\n    $.noAdditionalProperties(['colspan', 'rowspan']);\n    $.number('colspan', true);\n    $.number('rowspan', true);\n\n    return $.errors;\n  },\n);\n\nconst nodeValidator: Record<Node['nodeType'], NodeAssertion<any>> = {\n  [BLOCKS.DOCUMENT]: assert(TOP_LEVEL_BLOCKS),\n  [BLOCKS.PARAGRAPH]: assertInlineOrText,\n  [BLOCKS.HEADING_1]: assertInlineOrText,\n  [BLOCKS.HEADING_2]: assertInlineOrText,\n  [BLOCKS.HEADING_3]: assertInlineOrText,\n  [BLOCKS.HEADING_4]: assertInlineOrText,\n  [BLOCKS.HEADING_5]: assertInlineOrText,\n  [BLOCKS.HEADING_6]: assertInlineOrText,\n  [BLOCKS.QUOTE]: assert(CONTAINERS[BLOCKS.QUOTE]),\n  [BLOCKS.EMBEDDED_ENTRY]: assertVoidEntryLink,\n  [BLOCKS.EMBEDDED_ASSET]: assertLink('Asset', VOID_CONTENT),\n  [BLOCKS.EMBEDDED_RESOURCE]: assertLink('Contentful:Entry', VOID_CONTENT),\n  [BLOCKS.HR]: assert(VOID_CONTENT),\n  [BLOCKS.OL_LIST]: assertList,\n  [BLOCKS.UL_LIST]: assertList,\n  [BLOCKS.LIST_ITEM]: assert([...LIST_ITEM_BLOCKS].sort()),\n  [BLOCKS.TABLE]: assert(() => ({\n    nodeTypes: [BLOCKS.TABLE_ROW],\n    min: 1,\n  })),\n  [BLOCKS.TABLE_ROW]: assert(() => ({\n    nodeTypes: [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL],\n    min: 1,\n  })),\n  [BLOCKS.TABLE_CELL]: assertTableCell,\n  [BLOCKS.TABLE_HEADER_CELL]: assertTableCell,\n  [INLINES.HYPERLINK]: new HyperLinkAssertion(),\n  [INLINES.EMBEDDED_ENTRY]: assertVoidEntryLink,\n  [INLINES.EMBEDDED_RESOURCE]: assertLink('Contentful:Entry', VOID_CONTENT),\n  [INLINES.ENTRY_HYPERLINK]: assertLink('Entry', ['text']),\n  [INLINES.ASSET_HYPERLINK]: assertLink('Asset', ['text']),\n  [INLINES.RESOURCE_HYPERLINK]: assertLink('Contentful:Entry', ['text']),\n};\n\nfunction validateNode(node: Node | Text, path: Path): ValidationError[] {\n  if (node.nodeType === 'text') {\n    return assertText(node, path);\n  }\n\n  const errors = nodeValidator[node.nodeType].assert(node, path);\n\n  if (errors.length > 0) {\n    return errors;\n  }\n\n  const $ = new ObjectAssertion(node, path);\n\n  $.each('content', (item, path) => {\n    // We already know those are valid nodes thanks to the assertion done in\n    // the NodeAssertion class\n    return validateNode(item, path);\n  });\n\n  return $.errors;\n}\n\nexport const validateRichTextDocument = (document: Document): ValidationError[] => {\n  const path = new Path();\n  const $ = new ObjectAssertion(document, path);\n\n  if ($.object()) {\n    $.enum('nodeType', [BLOCKS.DOCUMENT]);\n  }\n\n  if ($.errors.length > 0) {\n    return $.errors;\n  }\n\n  return validateNode(document, path);\n};\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/node.ts",
    "content": "import {\n  AssetHyperlink,\n  AssetLinkBlock,\n  EntryHyperlink,\n  EntryLinkBlock,\n  Hyperlink,\n  ResourceLinkBlock,\n  ResourceLinkInline,\n} from '../nodeTypes.js';\nimport { Block, Document, Inline } from '../types.js';\nimport { ObjectAssertion } from './assert.js';\nimport type { Path } from './path.js';\nimport { ValidationError } from './types.js';\n\nexport type Node = Document | Block | Inline;\n\nexport type GetContentRule<T extends Node> =\n  | string[]\n  | ((\n      node: T,\n      path: Path,\n    ) => {\n      nodeTypes: string[];\n      min?: number;\n    });\n\nexport type ValidateData<T extends Node> = (data: T['data'], path: Path) => ValidationError[];\n\nexport const VOID_CONTENT: GetContentRule<Node> = [];\n\nexport class NodeAssertion<T extends Node = Node> {\n  constructor(\n    private contentRule: GetContentRule<T>,\n    private validateData?: ValidateData<T>,\n  ) {}\n\n  assert(node: T, path: Path): ValidationError[] {\n    const $ = new ObjectAssertion(node, path);\n\n    if (!$.object()) {\n      return $.errors;\n    }\n\n    $.noAdditionalProperties(['nodeType', 'data', 'content']);\n\n    const { nodeTypes, min = 0 } = Array.isArray(this.contentRule)\n      ? {\n          nodeTypes: this.contentRule,\n        }\n      : this.contentRule(node, path);\n\n    if (nodeTypes.length === 0 && min > 0) {\n      throw new Error(\n        `Invalid content rule. Cannot have enforce a 'min' of ${min} with no nodeTypes`,\n      );\n    }\n\n    $.minLength('content', min);\n\n    // Is void\n    if (nodeTypes.length === 0) {\n      $.empty('content');\n    }\n\n    // Ensure content nodes have valid nodeTypes without validating the full\n    // shape which is something that's only done later if the current node is\n    // valid.\n    else {\n      $.each('content', (item, path) => {\n        const item$ = new ObjectAssertion(item, path);\n\n        if (!item$.object()) {\n          return item$.errors;\n        }\n\n        item$.enum('nodeType', nodeTypes);\n\n        return item$.errors;\n      });\n    }\n\n    if ($.object('data')) {\n      const dataErrors = this.validateData?.(node.data, path.of('data')) ?? [];\n      $.catch(...dataErrors);\n    }\n\n    return $.errors;\n  }\n}\n\nexport class EntityLinkAssertion<\n  T extends\n    | EntryLinkBlock\n    | EntryHyperlink\n    | AssetLinkBlock\n    | AssetHyperlink\n    | ResourceLinkBlock\n    | ResourceLinkInline,\n> extends NodeAssertion<T> {\n  private type: 'ResourceLink' | 'Link';\n\n  constructor(\n    private linkType: 'Entry' | 'Asset' | 'Contentful:Entry',\n    contentNodeTypes: GetContentRule<T>,\n  ) {\n    super(contentNodeTypes, (data, path) => this.assertLink(data, path));\n    this.type = this.linkType.startsWith('Contentful:') ? 'ResourceLink' : 'Link';\n  }\n\n  private assertLink = (data: T['data'], path: Path): ValidationError[] => {\n    const $ = new ObjectAssertion(data, path);\n\n    if ($.object('target')) {\n      const sys$ = new ObjectAssertion(data.target.sys, path.of('target').of('sys'));\n\n      if (sys$.object()) {\n        sys$.enum('type', [this.type]);\n        sys$.enum('linkType', [this.linkType]);\n\n        if (this.type === 'Link') {\n          sys$.string('id');\n          sys$.noAdditionalProperties(['type', 'linkType', 'id']);\n        } else if (this.type === 'ResourceLink') {\n          sys$.string('urn');\n          sys$.noAdditionalProperties(['type', 'linkType', 'urn']);\n        }\n      }\n\n      $.catch(...sys$.errors);\n    }\n\n    $.noAdditionalProperties(['target']);\n\n    return $.errors;\n  };\n}\n\nexport class HyperLinkAssertion<T extends Hyperlink> extends NodeAssertion<T> {\n  constructor() {\n    super(['text'], (data, path) => this.assertLink(data, path));\n  }\n\n  private assertLink = (data: T['data'], path: Path): ValidationError[] => {\n    const $ = new ObjectAssertion(data, path);\n\n    $.string('uri');\n    $.noAdditionalProperties(['uri']);\n\n    return $.errors;\n  };\n}\n\nexport const assert = <T extends Node>(\n  contentRule: GetContentRule<T>,\n  validateData?: ValidateData<T>,\n): NodeAssertion<T> => {\n  return new NodeAssertion(contentRule, validateData);\n};\n\nexport const assertLink = <\n  T extends\n    | EntryLinkBlock\n    | EntryHyperlink\n    | AssetLinkBlock\n    | AssetHyperlink\n    | ResourceLinkBlock\n    | ResourceLinkInline,\n>(\n  linkType: 'Entry' | 'Asset' | 'Contentful:Entry',\n  contentRule: GetContentRule<T>,\n): EntityLinkAssertion<T> => {\n  return new EntityLinkAssertion(linkType, contentRule);\n};\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/path.ts",
    "content": "export class Path {\n  constructor(private readonly path: (string | number)[] = []) {}\n\n  of = (element: string | number): Path => {\n    return new Path([...this.path, element]);\n  };\n\n  isRoot = (): boolean => {\n    return this.path.length === 0;\n  };\n\n  last = (): string | number | undefined => {\n    return this.path[this.path.length - 1];\n  };\n\n  toArray = (): (string | number)[] => {\n    return this.path;\n  };\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/text.ts",
    "content": "import { Text } from '../types.js';\nimport { ObjectAssertion } from './assert.js';\nimport type { Path } from './path.js';\nimport { ValidationError } from './types.js';\n\nexport function assertText(text: Text, path: Path): ValidationError[] {\n  const $ = new ObjectAssertion(text, path);\n\n  if (!$.object()) {\n    return $.errors;\n  }\n\n  $.noAdditionalProperties(['nodeType', 'data', 'value', 'marks']);\n\n  $.object('data');\n  $.each('marks', (mark, path) => {\n    const mark$ = new ObjectAssertion(mark, path);\n\n    if (!mark$.object()) {\n      return mark$.errors;\n    }\n\n    // For historical reasons, we don't explicitly check for supported marks\n    // e.g. bold, italic ..etc. This makes it possible for a customer to add\n    // custom marks\n    mark$.string('type');\n\n    return mark$.errors;\n  });\n\n  $.string('value');\n\n  return $.errors;\n}\n"
  },
  {
    "path": "packages/rich-text-types/src/validator/types.ts",
    "content": "export type ValidationError = {\n  name: string;\n  type?: string;\n  value?: Record<string, any> | string | number | boolean | null;\n  min?: number | string;\n  max?: number | string;\n  details?: string | null;\n  path?: (string | number)[];\n  contentTypeId?: string | string[];\n  nodeType?: string;\n  customMessage?: string;\n  expected?: string[];\n};\n"
  },
  {
    "path": "packages/rich-text-types/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"declarationDir\": \"dist/types\",\n    \"outDir\": \"dist\",\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\", \"src/typings\"],\n    \"types\": [\"jest\", \"node\"],\n    \"inlineSources\": true,\n    \"declaration\": true,\n    \"isolatedModules\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'packages/*'\nlinkWorkspacePackages: true\npreferWorkspacePackages: true\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"local>contentful/renovate-config\"\n  ]\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import commonjs from '@rollup/plugin-commonjs';\nimport resolve from '@rollup/plugin-node-resolve';\nimport swc from '@rollup/plugin-swc';\nimport json from 'rollup-plugin-json';\n\nexport default (outputFile, overrides = {}) => ({\n  input: 'src/index.ts',\n  output: [\n    {\n      file: outputFile,\n      format: 'cjs',\n      sourcemap: true,\n    },\n    {\n      file: outputFile.replace(/\\.es5\\.js$/, '.esm.js'),\n      format: 'es',\n      sourcemap: true,\n    },\n  ],\n  watch: {\n    include: 'src/**',\n  },\n  plugins: [\n    json(),\n    swc({\n      swc: {\n        jsc: {\n          parser: {\n            syntax: 'typescript',\n            tsx: true,\n          },\n          target: 'es2019',\n          loose: false,\n          minify: {\n            compress: false,\n            mangle: false,\n          },\n        },\n        minify: false,\n      },\n    }),\n    commonjs(),\n    // Allow node_modules resolution, so you can use 'external' to control\n    // which external modules to include in the bundle\n    // https://github.com/rollup/rollup-plugin-node-resolve#usage\n    resolve({\n      extensions: ['.mjs', '.js', '.json', '.node', '.ts', '.tsx'],\n    }),\n  ],\n  ...overrides,\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"lib\": [\n      \"es2015\",\n      \"es2016\",\n      \"es2017\",\n      // otherwise schema generation fails with:\n      // Cannot find name 'Window'\n      \"dom\"\n    ],\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"strictNullChecks\": false,\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"jsx\": \"react\",\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n"
  }
]