├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── discussion.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── main.yaml │ └── semver-check.yaml ├── .gitignore ├── .husky └── pre-commit ├── .mocha-multi.json ├── .npmignore ├── .nycrc.json ├── .releaserc.cjs ├── .renovaterc.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── eslint.config.js ├── package-lock.json ├── package.json ├── src ├── PipelineContent.d.ts ├── PipelineContent.js ├── PipelineRequest.d.ts ├── PipelineRequest.js ├── PipelineResponse.d.ts ├── PipelineResponse.js ├── PipelineState.d.ts ├── PipelineState.js ├── PipelineStatusError.d.ts ├── PipelineStatusError.js ├── html-pipe.js ├── index.d.ts ├── index.js ├── json-pipe.js ├── options-pipe.js ├── robots-pipe.js ├── site-config.d.ts ├── sitemap-pipe.js ├── steps │ ├── add-heading-ids.js │ ├── create-page-blocks.js │ ├── create-pictures.js │ ├── csp.js │ ├── extract-metadata.js │ ├── fetch-404.js │ ├── fetch-content.js │ ├── fetch-mapped-metadata.js │ ├── fetch-sourced-metadata.js │ ├── fix-sections.js │ ├── folder-mapping.js │ ├── get-metadata.js │ ├── init-config.js │ ├── make-html.js │ ├── parse-markdown.js │ ├── render-code.js │ ├── render.js │ ├── rewrite-icons.js │ ├── rewrite-urls.js │ ├── set-custom-response-headers.js │ ├── set-x-surrogate-key-header.js │ ├── split-sections.js │ ├── stringify-response.js │ ├── unwrap-sole-images.js │ ├── utils.js │ └── validate-captcha.js └── utils │ ├── crypto.node.js │ ├── crypto.worker.js │ ├── hast-utils.js │ ├── heading-handler.js │ ├── id-slugger.js │ ├── json-filter.js │ ├── last-modified.js │ ├── mdast-to-hast.js │ ├── modifiers.js │ ├── path.js │ └── section-handler.js └── test ├── FileS3Loader.js ├── StaticS3Loader.js ├── fixtures ├── code │ └── super-test │ │ ├── 404-csp-nonce.html │ │ ├── 404-csp-nonce.ref.html │ │ ├── 404-test.html │ │ ├── my-block.selector.html │ │ ├── spa │ │ └── index.html │ │ ├── static-nonce-fragment.html │ │ ├── static-nonce-fragment.ref.html │ │ ├── static-nonce-header.html │ │ ├── static-nonce-header.ref.html │ │ ├── static-nonce-meta-different.html │ │ ├── static-nonce-meta-different.ref.html │ │ ├── static-nonce-meta-move-as-header.html │ │ ├── static-nonce-meta-move-as-header.ref.html │ │ ├── static-nonce-meta.html │ │ ├── static-nonce-meta.ref.html │ │ └── static.html ├── content │ ├── articles.md │ ├── blog │ │ └── index.md │ ├── description-blockquote.html │ ├── description-blockquote.md │ ├── description-long.html │ ├── description-long.md │ ├── description.html │ ├── description.md │ ├── empty-table-row.html │ ├── empty-table-row.md │ ├── fedpub-header.md │ ├── fedpub-header.plain.html │ ├── generic-product.md │ ├── generic-product │ │ └── metadata.json │ ├── gt-many-refs.html │ ├── gt-many-refs.md │ ├── head-with-script.html │ ├── head-with-script.md │ ├── headings.html │ ├── headings.md │ ├── icons-ignored.html │ ├── icons-ignored.md │ ├── icons.html │ ├── icons.md │ ├── image-from-meta-rewrite-link.html │ ├── image-from-meta-rewrite-link.md │ ├── image-from-meta-rewrite.html │ ├── image-from-meta-rewrite.md │ ├── image-from-meta.html │ ├── image-from-meta.md │ ├── image-no-alt.html │ ├── image-no-alt.md │ ├── image-with-title.html │ ├── image-with-title.md │ ├── image.html │ ├── image.md │ ├── images.html │ ├── images.md │ ├── index.md │ ├── large.html │ ├── large.md │ ├── md-headings.html │ ├── md-headings.md │ ├── meta-response-headers.html │ ├── meta-response-headers.md │ ├── meta-response-headers.plain.html │ ├── metadata-kv.json │ ├── metadata-product.json │ ├── metadata.json │ ├── no-head-html.html │ ├── no-head-html.md │ ├── nonce-headers-different.html │ ├── nonce-headers-different.md │ ├── nonce-headers-meta.html │ ├── nonce-headers-meta.md │ ├── nonce-headers.html │ ├── nonce-headers.md │ ├── nonce-meta-different.html │ ├── nonce-meta-different.md │ ├── nonce-meta-move-as-header.html │ ├── nonce-meta-move-as-header.md │ ├── nonce-meta.html │ ├── nonce-meta.md │ ├── nonce-script-only.html │ ├── nonce-script-only.md │ ├── nonce-style-only.html │ ├── nonce-style-only.md │ ├── not-found-with-handler.html │ ├── one-section.html │ ├── one-section.md │ ├── one-section.plain.html │ ├── one-section │ │ ├── index.md │ │ └── index.plain.html │ ├── page-block-1-col.html │ ├── page-block-1-col.md │ ├── page-block-1-col.plain.html │ ├── page-block-2-col.html │ ├── page-block-2-col.md │ ├── page-block-2-col.plain.html │ ├── page-block-empty-cols.html │ ├── page-block-empty-cols.md │ ├── page-block-no-title.html │ ├── page-block-no-title.md │ ├── page-block-strong.html │ ├── page-block-strong.md │ ├── page-block-table-in-table.html │ ├── page-block-table-in-table.md │ ├── page-block-with-html-table.html │ ├── page-block-with-html-table.md │ ├── page-metadata-block-canonical.html │ ├── page-metadata-block-canonical.md │ ├── page-metadata-block-empty-url.html │ ├── page-metadata-block-empty-url.md │ ├── page-metadata-block-html.html │ ├── page-metadata-block-html.md │ ├── page-metadata-block-multi-a.html │ ├── page-metadata-block-multi-a.md │ ├── page-metadata-block-multi-ol.html │ ├── page-metadata-block-multi-ol.md │ ├── page-metadata-block-multi-p.html │ ├── page-metadata-block-multi-p.md │ ├── page-metadata-block-multi-ul.html │ ├── page-metadata-block-multi-ul.md │ ├── page-metadata-block.html │ ├── page-metadata-block.md │ ├── page-metadata-content-blocks.html │ ├── page-metadata-content-blocks.md │ ├── page-metadata-hreflang.html │ ├── page-metadata-hreflang.md │ ├── page-metadata-htmllang-short.html │ ├── page-metadata-htmllang-short.md │ ├── page-metadata-htmllang.html │ ├── page-metadata-htmllang.md │ ├── page-metadata-json.html │ ├── page-metadata-json.md │ ├── page-metadata-jsonld-error.html │ ├── page-metadata-jsonld-error.md │ ├── page-metadata-jsonld-global.html │ ├── page-metadata-jsonld-global.md │ ├── page-metadata-jsonld-list.html │ ├── page-metadata-jsonld-list.md │ ├── page-metadata-jsonld-multi.html │ ├── page-metadata-jsonld-multi.md │ ├── page-metadata-jsonld-xss.html │ ├── page-metadata-jsonld-xss.md │ ├── page-metadata-jsonld.html │ ├── page-metadata-jsonld.md │ ├── page-metadata-no-fallback.html │ ├── page-metadata-no-fallback.md │ ├── page-metadata-twitter-fallback.html │ ├── page-metadata-twitter-fallback.md │ ├── page-with-gridtables.html │ ├── page-with-gridtables.md │ ├── pricing.json │ ├── simple.html │ ├── simple.md │ ├── simple.plain.html │ ├── sitemap-bad-data.json │ ├── sitemap-corrupt.json │ ├── sitemap.json │ ├── sitemap.xml │ ├── special │ │ └── default-article.md │ ├── static-content.html │ ├── stray-p-strong.html │ ├── stray-p-strong.md │ ├── styling.md │ ├── styling.plain.html │ ├── unwrap-images.html │ └── unwrap-images.md ├── json │ ├── test-data-invalid.json │ └── test-data.json ├── mdasts │ ├── example.json │ ├── example.md │ ├── forms.json │ ├── forms.md │ ├── grayscale.json │ ├── grayscale.md │ ├── heading-ids.json │ ├── headings.json │ ├── headings.md │ ├── icon-example.json │ ├── icon-example.md │ ├── links.json │ ├── paragraph.json │ ├── simple-links.json │ ├── simple-links.md │ ├── simple.json │ ├── simple.md │ ├── tags.html │ └── tags.md └── sections │ ├── 2images.json │ ├── 2images.md │ ├── complex.json │ ├── complex.md │ ├── header.json │ ├── header.md │ ├── headerimage.json │ ├── headerimage.md │ ├── headerlist.json │ ├── headerlist.md │ ├── headerpara2images.json │ ├── headerpara2images.md │ ├── headerparagraph.json │ ├── headerparagraph.md │ ├── headerparaimage.json │ ├── headerparaimage.md │ ├── herosection.json │ ├── herosection.md │ ├── paragraph.json │ ├── paragraph.md │ ├── paragraphwithlink.json │ └── paragraphwithlink.md ├── html-pipe.test.js ├── json-pipe.test.js ├── markdown-utils.js ├── modifiers.test.js ├── options-pipe.test.js ├── pipeline-request.test.js ├── pipeline-response.test.js ├── rendering.test.js ├── robots-pipe.test.js ├── setup-env.js ├── sitemap-pipe.test.js ├── steps ├── fetch-content.test.js ├── fetch-mapped-metadata.test.js ├── get-metadata.test.js ├── init-config.test.js ├── mdast-to-hast.test.js ├── parse-markdown.test.js ├── set-custom-headers.test.js ├── stringify-response.test.js ├── utils.test.js └── validate-captcha.test.js ├── utils.js └── utils ├── id-slugger-test.js ├── json-filter.test.js ├── last-modified.test.js └── path.test.js /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | 6 | --- 7 | 8 | **Description** 9 | A clear and concise description of what the bug is. 10 | 11 | **To Reproduce** 12 | Steps to reproduce the behavior: 13 | 1. Go to '...' 14 | 2. Click on '....' 15 | 3. Scroll down to '....' 16 | 4. See error 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Version:** 25 | run: `$ hlx --version` 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Discussion 3 | about: Start a new discussion 4 | labels: question 5 | 6 | --- 7 | 8 | ## Overview 9 | whats' this discussion about? 10 | 11 | ## Details 12 | more details 13 | 14 | ## Proposed Actions 15 | and now? 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: enhancement 5 | 6 | --- 7 | 8 | **Is your feature request related to a problem? Please describe.** 9 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 10 | 11 | **Describe the solution you'd like** 12 | A clear and concise description of what you want to happen. 13 | 14 | **Describe alternatives you've considered** 15 | A clear and concise description of any alternative solutions or features you've considered. 16 | 17 | **Additional context** 18 | Add any other context or screenshots about the feature request here. 19 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Please ensure your pull request adheres to the following guidelines: 2 | - [ ] make sure to link the related issues in this description 3 | - [ ] when merging / squashing, make sure the fixed issue references are visible in the commits, for easy compilation of release notes 4 | 5 | ## Related Issues 6 | 7 | 8 | Thanks for contributing! 9 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | 7 | env: 8 | CI_BUILD_NUM: ${{ github.run_id }} 9 | CI_BRANCH: ${{ github.ref_name }} 10 | 11 | jobs: 12 | test: 13 | name: Test 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Use Node.js 20.x 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: '22.x' 21 | - run: npm ci 22 | - run: npm run lint 23 | - run: npm test 24 | - uses: codecov/codecov-action@v5 25 | with: 26 | token: ${{ secrets.CODECOV_TOKEN }} 27 | - name: Semantic Release (Dry Run) 28 | run: npm run semantic-release-dry 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} 32 | CORALOGIX_TAGGER_API_KEY: ${{ secrets.CORALOGIX_TAGGER_API_KEY }} 33 | 34 | release: 35 | name: Release 36 | runs-on: ubuntu-latest 37 | needs: test 38 | if: github.ref == 'refs/heads/5.x' || github.ref == 'refs/heads/main' 39 | steps: 40 | - uses: actions/checkout@v4 41 | - name: Use Node.js 20.x 42 | uses: actions/setup-node@v4 43 | with: 44 | node-version: '22.x' 45 | - run: npm ci 46 | - run: npm run semantic-release 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} 50 | CORALOGIX_TAGGER_API_KEY: ${{ secrets.CORALOGIX_TAGGER_API_KEY }} 51 | -------------------------------------------------------------------------------- /.github/workflows/semver-check.yaml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | on: 3 | push: 4 | branches-ignore: 5 | - 'main' 6 | 7 | jobs: 8 | ci_trigger: 9 | runs-on: ubuntu-latest 10 | name: Comment Semantic Release Status 11 | steps: 12 | - name: Comment 13 | id: comment 14 | uses: adobe-rnd/github-semantic-release-comment-action@main 15 | with: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | .nyc_output/ 3 | node_modules/ 4 | junit 5 | dist 6 | tmp 7 | logs 8 | .DS_Store 9 | test-results.xml 10 | .env 11 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.mocha-multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporterEnabled": "spec,xunit", 3 | "xunitReporterOptions": { 4 | "output": "junit/test-results.xml" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | build 3 | coverage 4 | junit 5 | logs 6 | node_modules/ 7 | snykmocha.js 8 | test/* 9 | test-results.xml 10 | !test/StaticS3Loader.js 11 | -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": [ 3 | "lcov", 4 | "text", 5 | "text-summary" 6 | ], 7 | "check-coverage": true, 8 | "lines": 100, 9 | "branches": 100, 10 | "statements": 100, 11 | "skip-full": true 12 | } 13 | -------------------------------------------------------------------------------- /.releaserc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | ["@semantic-release/changelog", { 6 | "changelogFile": "CHANGELOG.md", 7 | }], 8 | "@semantic-release/npm", 9 | ["@semantic-release/git", { 10 | "assets": ["package.json", "CHANGELOG.md"], 11 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 12 | }], 13 | ["@semantic-release/github", {}] 14 | ], 15 | branches: ['main', '5.x'], 16 | }; 17 | -------------------------------------------------------------------------------- /.renovaterc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>adobe/helix-shared"], 3 | "baseBranches": ["main", "5.x"], 4 | "packageRules": [ 5 | { 6 | "groupName": "adobe fixes", 7 | "branchTopic": "{{{depNameSanitized}}}-adobe-fixes-{{{newMajor}}}{{#if separateMinorPatch}}{{#if isPatch}}.{{{newMinor}}}{{/if}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}", 8 | "matchUpdateTypes": ["patch", "pin", "digest", "minor"], 9 | "automerge": true, 10 | "matchPackagePatterns": ["^@adobe/"], 11 | "schedule": ["at any time"] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Helix HTML Pipeline 2 | 3 | This package contains the common code for `helix-pipeline-service` and `helix-cloudflare-page` for rendering the html response for helix3. it has the following design goals: 4 | 5 | - be platform neutral, i.e. not using node or browser specific modules or dependencies. 6 | - +/-0 runtime dependencies (eg. node [crypto](https://nodejs.org/api/crypto.html)) 7 | - offer extension interfaces where platform abstraction is required (e.g. reading from S3, sending to SQS) 8 | 9 | ## Status 10 | [![codecov](https://img.shields.io/codecov/c/github/adobe/helix-html-pipeline.svg)](https://codecov.io/gh/adobe/helix-html-pipeline) 11 | ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/adobe/helix-html-pipeline/main.yaml) 12 | [![GitHub license](https://img.shields.io/github/license/adobe/helix-html-pipeline.svg)](https://github.com/adobe/helix-html-pipeline/blob/master/LICENSE.txt) 13 | [![GitHub issues](https://img.shields.io/github/issues/adobe/helix-html-pipeline.svg)](https://github.com/adobe/helix-html-pipeline/issues) 14 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 15 | 16 | ## Installation 17 | 18 | ```bash 19 | $ npm install @adobe/helix-html-pipeline 20 | ``` 21 | ## Development 22 | 23 | ### Build 24 | 25 | ```bash 26 | $ npm install 27 | ``` 28 | 29 | ### Test 30 | 31 | ```bash 32 | $ npm test 33 | ``` 34 | 35 | ### Lint 36 | 37 | ```bash 38 | $ npm run lint 39 | ``` 40 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { defineConfig, globalIgnores } from '@eslint/config-helpers'; 13 | import { recommended, source, test } from '@adobe/eslint-config-helix'; 14 | 15 | export default defineConfig([ 16 | globalIgnores([ 17 | '.vscode/*', 18 | 'coverage/*', 19 | ]), 20 | { 21 | rules: { 22 | 'import/extensions': ['error', 'ignorePackages'], 23 | 'import/prefer-default-export': 0, 24 | 'no-param-reassign': ['error', { props: false }], 25 | }, 26 | plugins: { 27 | import: recommended.plugins.import, 28 | }, 29 | extends: [recommended], 30 | }, 31 | source, 32 | test, 33 | ]); 34 | -------------------------------------------------------------------------------- /src/PipelineContent.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License; Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing; software distributed under 8 | * the License is distributed on an "AS IS" BASIS; WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND; either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import {Node} from "unist"; 13 | import { Root } from 'hast'; 14 | import { IDSlugger } from './utils/id-slugger.js'; 15 | 16 | declare enum SourceType { 17 | CONTENT = 'content', 18 | CODE = 'code', 19 | } 20 | 21 | declare class PipelineContent { 22 | /** 23 | * source of content: `content` or `code` 24 | * @default 'content' 25 | */ 26 | sourceBus: SourceType; 27 | 28 | /** 29 | * http status of the content fetch response 30 | */ 31 | status: number; 32 | 33 | /** 34 | * raw data of the content 35 | */ 36 | data: string; 37 | 38 | /** 39 | * http headers of the content fetch response 40 | */ 41 | headers: object; 42 | 43 | /** 44 | * the source location of the loaded content 45 | */ 46 | sourceLocation: string; 47 | 48 | /** 49 | * Markdown AST of the parsed content 50 | */ 51 | mdast: Node; 52 | 53 | /** 54 | * The transformed document (hast) representation 55 | */ 56 | hast: Root; 57 | 58 | /** 59 | * slugger to use for heading id calculations 60 | */ 61 | slugger: IDSlugger; 62 | 63 | /** 64 | * document specific metadata 65 | */ 66 | meta: object; 67 | title: string; 68 | intro: string; 69 | image: string; 70 | } 71 | -------------------------------------------------------------------------------- /src/PipelineContent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { IDSlugger } from './utils/id-slugger.js'; 13 | 14 | /** 15 | * State of the pipeline 16 | * @class PipelineState 17 | */ 18 | export class PipelineContent { 19 | /** 20 | * Creates the pipeline content 21 | */ 22 | constructor() { 23 | Object.assign(this, { 24 | sourceBus: 'content', 25 | slugger: new IDSlugger(), 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/PipelineRequest.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License; Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing; software distributed under 8 | * the License is distributed on an "AS IS" BASIS; WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND; either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import {PathInfo, PipelineContent, S3Loader} from "./index"; 13 | 14 | declare interface PipelineRequestInit { 15 | method?:string, 16 | headers?:Map | object; 17 | body?:string; 18 | } 19 | 20 | declare class PipelineRequest { 21 | constructor(url:URL|string, opts?:RequestInit); 22 | url: URL; 23 | method: string; 24 | headers: Map; 25 | body: string; 26 | params: object; 27 | } 28 | -------------------------------------------------------------------------------- /src/PipelineRequest.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /** 14 | * Request of a pipeline 15 | * @class PipelineRequest 16 | */ 17 | export class PipelineRequest { 18 | /** 19 | * request url 20 | */ 21 | url; 22 | 23 | /** 24 | * uppercase request method 25 | */ 26 | method; 27 | 28 | /** 29 | * request body 30 | */ 31 | body; 32 | 33 | /** 34 | * request headers 35 | */ 36 | headers; 37 | 38 | /** 39 | * request params; 40 | */ 41 | params; 42 | 43 | /** 44 | * Creates the pipeline request 45 | * @param {URL|string} url 46 | * @param {PipelineRequestInit} [init] 47 | */ 48 | constructor(url, init = {}) { 49 | let headers = init.headers ?? new Map(); 50 | if (typeof headers.get !== 'function') { 51 | headers = new Map(Object.entries(init.headers)); 52 | } 53 | Object.assign(this, { 54 | url: url instanceof URL ? url : new URL(url), 55 | method: init.method ?? 'GET', 56 | body: init.body, 57 | headers, 58 | }); 59 | this.params = Object.fromEntries(this.url.searchParams.entries()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/PipelineResponse.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License; Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing; software distributed under 8 | * the License is distributed on an "AS IS" BASIS; WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND; either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { Element } from 'hast'; 13 | 14 | declare interface PipelineResponseInit { 15 | status?: number; 16 | headers: Map | object; 17 | } 18 | 19 | declare class PipelineResponse { 20 | constructor(body?:string, init?:PipelineResponseInit); 21 | status: number; 22 | /** 23 | * The transformed document (hast) representation 24 | */ 25 | document: Element; 26 | body: string; 27 | headers: Map; 28 | error: any; 29 | 30 | /** 31 | * the last modified time of the response. this is the max of the last-modified times of the 32 | * various source. e.g. if the `head.html` is newer than the `content`, then the last-modified 33 | * header will be the one of the `head.html` 34 | */ 35 | lastModifiedTime: number; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/PipelineResponse.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /** 14 | * Response of a pipeline 15 | * @class PipelineResponse 16 | */ 17 | export class PipelineResponse { 18 | /** 19 | * Creates the pipeline response 20 | */ 21 | constructor(body = undefined, init = {}) { 22 | let headers = init.headers ?? new Map(); 23 | if (typeof headers.get !== 'function') { 24 | headers = new Map(Object.entries(init.headers)); 25 | } 26 | 27 | Object.assign(this, { 28 | status: init.status ?? 200, 29 | body, 30 | document: undefined, 31 | headers, 32 | error: undefined, 33 | lastModifiedSources: {}, 34 | }); 35 | } 36 | 37 | /** 38 | * Returns the json parsed object of `this.body`. 39 | * @returns {object} 40 | */ 41 | json() { 42 | return JSON.parse(this.body); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/PipelineState.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | import { getPathInfo } from './utils/path.js'; 14 | import { PipelineContent } from './PipelineContent.js'; 15 | import { Modifiers } from './utils/modifiers.js'; 16 | 17 | /** 18 | * State of the pipeline 19 | * @class PipelineState 20 | */ 21 | export class PipelineState { 22 | /** 23 | * Creates the pipeline state 24 | * @param {PipelineOptions} opts 25 | */ 26 | constructor(opts) { 27 | Object.assign(this, { 28 | log: opts.log ?? console, 29 | env: opts.env, 30 | info: getPathInfo(opts.path), 31 | config: opts.config, 32 | content: new PipelineContent(), 33 | contentBusId: opts.config.contentBusId, 34 | site: opts.site, 35 | org: opts.org, 36 | owner: opts.config.owner, 37 | repo: opts.config.repo, 38 | ref: opts.ref, 39 | partition: opts.partition, 40 | metadata: Modifiers.EMPTY, 41 | headers: Modifiers.EMPTY, 42 | s3Loader: opts.s3Loader, 43 | fetch: opts.fetch, 44 | timer: opts.timer, 45 | type: 'html', 46 | }); 47 | for (const prop of ['org', 'site', 'contentBusId', 'repo', 'owner', 'ref', 'partition']) { 48 | if (!this[prop]) { 49 | throw new Error(`${prop} required`); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/PipelineStatusError.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | declare class PipelineStatusError extends Error { 13 | code:number; 14 | } 15 | -------------------------------------------------------------------------------- /src/PipelineStatusError.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | export class PipelineStatusError extends Error { 13 | constructor(code, message) { 14 | super(message); 15 | this.code = code; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | export * from './html-pipe.js'; 13 | export * from './json-pipe.js'; 14 | export * from './options-pipe.js'; 15 | export * from './robots-pipe.js'; 16 | export * from './sitemap-pipe.js'; 17 | export * from './PipelineContent.js'; 18 | export * from './PipelineRequest.js'; 19 | export * from './PipelineResponse.js'; 20 | export * from './PipelineState.js'; 21 | export * from './PipelineStatusError.js'; 22 | -------------------------------------------------------------------------------- /src/steps/add-heading-ids.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { toString } from 'hast-util-to-string'; 13 | import { visit } from 'unist-util-visit'; 14 | 15 | /** 16 | * Adds missing `id` attributes to the headings 17 | * @type PipelineStep 18 | * @param {PipelineContent } content The current context of processing pipeline 19 | */ 20 | export default async function fixSections({ content }) { 21 | const { slugger, hast } = content; 22 | visit(hast, (node) => { 23 | if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.tagName)) { 24 | const { properties } = node; 25 | if (!properties.id) { 26 | const text = toString(node).trim(); 27 | if (text) { 28 | properties.id = slugger.slug(text); 29 | } 30 | } 31 | } 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /src/steps/fix-sections.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { selectAll } from 'hast-util-select'; 13 | import { h } from 'hastscript'; 14 | import { wrapContent } from './utils.js'; 15 | 16 | /** 17 | * fixes the sections of a document. 18 | * @type PipelineStep 19 | * @param {PipelineContent} content 20 | */ 21 | export default async function fixSections({ content }) { 22 | const { hast } = content; 23 | const $sections = selectAll('div', hast); 24 | 25 | // if there are no sections wrap everything in a div with appropriate class names from meta 26 | if ($sections.length === 0) { 27 | const $outerDiv = h('div'); 28 | wrapContent($outerDiv, hast); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/steps/init-config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { Modifiers } from '../utils/modifiers.js'; 13 | import { getOriginalHost } from './utils.js'; 14 | import { recordLastModified } from '../utils/last-modified.js'; 15 | 16 | function replaceParams(str, info) { 17 | if (!str) { 18 | return ''; 19 | } 20 | return str 21 | .replaceAll('$owner', info.owner) 22 | .replaceAll('$org', info.org) 23 | .replaceAll('$site', info.site) 24 | .replaceAll('$repo', info.repo) 25 | .replaceAll('$ref', info.ref); 26 | } 27 | 28 | /** 29 | * Initializes the pipeline state with the config from the config service 30 | * (passed via the `config` parameter during state construction). 31 | * 32 | * @type PipelineStep 33 | * @param {PipelineState} state 34 | * @param {PipelineRequest} req 35 | * @param {PipelineResponse} res 36 | * @returns {Promise} 37 | */ 38 | export default function initConfig(state, req, res) { 39 | const { config, partition } = state; 40 | state.metadata = new Modifiers(config.metadata?.[partition]?.data || {}); 41 | state.headers = new Modifiers(config.headers || {}); 42 | 43 | // set custom preview and live hosts 44 | state.previewHost = replaceParams(config.cdn?.preview?.host, state); 45 | state.liveHost = replaceParams(config.cdn?.live?.host, state); 46 | state.prodHost = config.cdn?.prod?.host || getOriginalHost(req.headers); 47 | recordLastModified(state, res, 'config', state.config.lastModified); 48 | } 49 | -------------------------------------------------------------------------------- /src/steps/make-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import mdast2hast from '../utils/mdast-to-hast.js'; 13 | 14 | /** 15 | * Converts the markdown to a jsdom dom and stores it in `content.document` 16 | * @type PipelineStep 17 | * @param {PipelineState} state 18 | */ 19 | export default function html(state) { 20 | const { content } = state; 21 | const { mdast } = content; 22 | content.hast = mdast2hast(mdast, content.slugger); 23 | } 24 | -------------------------------------------------------------------------------- /src/steps/parse-markdown.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { unified } from 'unified'; 13 | import remarkParse from 'remark-parse'; 14 | import { removePosition } from 'unist-util-remove-position'; 15 | import { dereference, remarkGfmNoLink } from '@adobe/helix-markdown-support'; 16 | import remarkGridTable from '@adobe/remark-gridtables'; 17 | 18 | /** 19 | * Parses the markdown body 20 | * @type PipelineStep 21 | * @param {PipelineState} state 22 | */ 23 | export default function parseMarkdown(state) { 24 | const { content } = state; 25 | 26 | // convert linebreaks 27 | const converted = content.data.replace(/(\r\n|\n|\r)/gm, '\n'); 28 | content.mdast = unified() 29 | .use(remarkParse) 30 | .use(remarkGfmNoLink) 31 | .use(remarkGridTable) 32 | .parse(converted); 33 | 34 | removePosition(content.mdast, { force: true }); 35 | dereference(content.mdast); 36 | } 37 | -------------------------------------------------------------------------------- /src/steps/render-code.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import mime from 'mime'; 13 | import { 14 | contentSecurityPolicyOnCode, 15 | } from './csp.js'; 16 | 17 | const CHARSET_RE = /charset=([^()<>@,;:"/[\]?.=\s]*)/i; 18 | 19 | /** 20 | * "Renders" the content from the code-bus as-is 21 | * @type PipelineStep 22 | * @param {PipelineState} state 23 | * @param {PipelineRequest} req 24 | * @param {PipelineResponse} res 25 | * @returns {Promise} 26 | */ 27 | export default async function renderCode(state, req, res) { 28 | res.body = state.content.data; 29 | let contentType = mime.getType(state.info.resourcePath); 30 | const originalType = res.headers.get('content-type'); 31 | if (originalType) { 32 | const match = CHARSET_RE.exec(originalType); 33 | if (match) { 34 | contentType += `; charset=${match[1]}`; 35 | } 36 | } 37 | res.headers.set('content-type', contentType); 38 | 39 | contentSecurityPolicyOnCode(state, res); 40 | } 41 | -------------------------------------------------------------------------------- /src/steps/rewrite-urls.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | import { CONTINUE, visit } from 'unist-util-visit'; 14 | import { rewriteUrl } from './utils.js'; 15 | 16 | /** 17 | * Rewrites all A and IMG urls 18 | * @param {PipelineState} state 19 | */ 20 | export default async function rewriteUrls(state) { 21 | const { content: { hast } } = state; 22 | 23 | const els = { 24 | a: 'href', 25 | img: 'src', 26 | }; 27 | 28 | visit(hast, (node) => { 29 | if (node.type !== 'element') { 30 | return CONTINUE; 31 | } 32 | const attr = els[node.tagName]; 33 | if (attr) { 34 | node.properties[attr] = rewriteUrl(state, node.properties[attr]); 35 | } 36 | return CONTINUE; 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/steps/split-sections.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /** 14 | * Splits the sections in the mdast tree 15 | * @type PipelineStep 16 | * @param {PipelineState} state 17 | */ 18 | export default function split(state) { 19 | const { content: { mdast } } = state; 20 | 21 | // filter all children that are break blocks 22 | const dividers = mdast.children.filter((node) => node.type === 'thematicBreak') 23 | // then get their index in the list of children 24 | .map((node) => mdast.children.indexOf(node)); 25 | 26 | // find pairwise permutations of spaces between blocks 27 | // include the very start and end of the document 28 | const starts = [0, ...dividers]; 29 | const ends = [...dividers, mdast.children.length]; 30 | 31 | // content.mdast.children = _.zip(starts, ends) 32 | mdast.children = starts.map((k, i) => [k, ends[i]]) 33 | // but filter out empty section 34 | .filter(([start, end]) => start !== end) 35 | // then return all nodes that are in between 36 | .map(([start, end]) => { 37 | // skip 'thematicBreak' nodes 38 | const index = mdast.children[start].type === 'thematicBreak' ? start + 1 : start; 39 | return { 40 | type: 'section', 41 | children: mdast.children.slice(index, end), 42 | }; 43 | }); 44 | 45 | // unwrap sole section directly on the root 46 | if (mdast.children.length === 1 && mdast.children[0].type === 'section') { 47 | mdast.children = mdast.children[0].children; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/steps/stringify-response.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { toHtml } from 'hast-util-to-html'; 13 | import rehypeFormat from 'rehype-format'; 14 | 15 | /** 16 | * Serializes the response document to HTML 17 | * @param {PipelineState} state 18 | * @param {PipelineRequest} req 19 | * @param {PipelineResponse} res 20 | */ 21 | export default function stringify(state, req, res) { 22 | const { log } = state; 23 | if (res.body) { 24 | log.debug('stringify: ignoring already defined context.response.body'); 25 | return; 26 | } 27 | const doc = res.document; 28 | if (!doc) { 29 | throw Error('no response document'); 30 | } 31 | rehypeFormat()(doc); 32 | 33 | res.body = toHtml(doc, { 34 | upperDoctype: true, 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /src/steps/unwrap-sole-images.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { map } from 'unist-util-map'; 13 | 14 | /** 15 | * Unwraps hero images to avoid the unnecessary paragraph. 16 | * 17 | * @param {object} request The content request 18 | */ 19 | export default function unwrap({ content }) { 20 | let sections = content.mdast.children.filter((node) => node.type === 'section'); 21 | if (!sections.length) { 22 | sections = [content.mdast]; 23 | } 24 | sections.forEach((section) => { 25 | map(section, (node, index, parent) => { 26 | if (node.type === 'paragraph' // If we have a paragraph 27 | && (parent.type === 'root' // … in the document root 28 | || parent.type === 'section') // … or in a section 29 | && parent.meta.types.includes('has-only-image') // … that only has images 30 | && parent.meta.types.includes('nb-image-1')) { // … and actually only 1 of them 31 | // … then consider it a hero image, and unwrap from the paragraph 32 | const position = parent.children.indexOf(node); 33 | const [img] = parent.children[position].children; 34 | parent.children[position] = img; 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/crypto.node.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | // node runtime 14 | import cryptoImpl from 'node:crypto'; 15 | 16 | export default cryptoImpl; 17 | -------------------------------------------------------------------------------- /src/utils/crypto.worker.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | // browser/worker runtime 14 | // eslint-disable-next-line no-undef 15 | export default crypto; 16 | -------------------------------------------------------------------------------- /src/utils/hast-utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | export function childNodes(node) { 14 | return node.children.filter((n) => n.type === 'element'); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/heading-handler.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { defaultHandlers } from 'mdast-util-to-hast'; 13 | import { toString } from 'mdast-util-to-string'; 14 | import strip from 'strip-markdown'; 15 | 16 | /** 17 | * Injects heading identifiers during the MDAST to VDOM transformation. 18 | */ 19 | export default function heading(slugger) { 20 | return function handler(h, node) { 21 | // Prepare the heading id 22 | const headingIdentifier = slugger.slug(toString(strip()(node)).trim()); 23 | 24 | // Inject the id after transformation 25 | const el = defaultHandlers.heading(h, node); 26 | el.properties.id = el.properties.id || headingIdentifier; 27 | return el; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/id-slugger.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { slug } from 'github-slugger'; 13 | 14 | export class IDSlugger { 15 | constructor() { 16 | this.occurrences = {}; 17 | } 18 | 19 | /** 20 | * Generate a unique slug. 21 | * @param {string} value String of text to slugify 22 | * @return {string} A unique slug string 23 | */ 24 | slug(value) { 25 | let id = slug(value) 26 | // remove leading numbers 27 | .replace(/^\d+-+/, ''); 28 | 29 | // resolve collisions 30 | const original = id; 31 | while (id in this.occurrences) { 32 | this.occurrences[original] += 1; 33 | id = `${original}-${this.occurrences[original]}`; 34 | } 35 | this.occurrences[id] = 0; 36 | return id; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/mdast-to-hast.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { toHast as mdast2hast, defaultHandlers } from 'mdast-util-to-hast'; 13 | import { raw } from 'hast-util-raw'; 14 | import { mdast2hastGridTablesHandler, TYPE_TABLE } from '@adobe/mdast-util-gridtables'; 15 | 16 | import section from './section-handler.js'; 17 | import heading from './heading-handler.js'; 18 | 19 | /** 20 | * Turns the MDAST into a HAST structure 21 | * @param {Node} mdast mdast tree 22 | * @param {GithubSlugger} slugger github slugger for the heading ids 23 | * @returns {Root} the HAST document 24 | */ 25 | export default function getHast(mdast, slugger) { 26 | const hast = mdast2hast(mdast, { 27 | handlers: { 28 | ...defaultHandlers, 29 | section: section(), 30 | heading: heading(slugger), 31 | [TYPE_TABLE]: mdast2hastGridTablesHandler(), 32 | }, 33 | allowDangerousHtml: true, 34 | }); 35 | 36 | return raw(hast); 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/section-handler.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | export default function sectionHandler() { 13 | return function handler(state, node) { 14 | const n = { ...node }; 15 | 16 | const children = state.all(n); 17 | return { 18 | type: 'element', 19 | tagName: 'div', 20 | children, 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /test/StaticS3Loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /** 13 | * @implements S3Loader 14 | */ 15 | export class StaticS3Loader { 16 | constructor() { 17 | this.buckets = {}; 18 | } 19 | 20 | reply(bucketId, key, response) { 21 | let bucket = this.buckets[bucketId]; 22 | if (!bucket) { 23 | bucket = {}; 24 | this.buckets[bucketId] = bucket; 25 | } 26 | bucket[key] = response; 27 | return this; 28 | } 29 | 30 | async getObject(bucketId, key) { 31 | const bucket = this.buckets[bucketId]; 32 | const response = bucket?.[key] ?? { 33 | status: 404, 34 | body: '', 35 | headers: new Map(), 36 | }; 37 | if (response instanceof Error) { 38 | // eslint-disable-next-line no-console 39 | console.log(`StaticS3Loader: failing ${bucketId}/${key} -> ${response.message}`); 40 | throw response; 41 | } 42 | // eslint-disable-next-line no-console 43 | console.log(`StaticS3Loader: loading ${bucketId}/${key} -> ${response.status}`); 44 | return response; 45 | } 46 | 47 | async headObject(bucketId, key) { 48 | return this.getObject(bucketId, key); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/404-csp-nonce.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Page not found 7 | 11 | 12 | 13 | 14 | 30 | 34 | 35 | 50 | 51 | 52 | 53 | 54 |
55 |
56 |
57 | 58 | 404 59 | 60 |

Page Not Found

61 |

62 | Go home 63 |

64 |
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/404-csp-nonce.ref.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Page not found 7 | 11 | 12 | 13 | 14 | 30 | 34 | 35 | 50 | 51 | 52 | 53 | 54 |
55 |
56 |
57 | 58 | 404 59 | 60 |

Page Not Found

61 |

62 | Go home 63 |

64 |
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/404-test.html: -------------------------------------------------------------------------------- 1 | There might be dragons. 2 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/my-block.selector.html: -------------------------------------------------------------------------------- 1 | static 2 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/spa/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/static-nonce-fragment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
Nonce Test
6 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/static-nonce-fragment.ref.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
Nonce Test
6 | -------------------------------------------------------------------------------- /test/fixtures/code/super-test/static.html: -------------------------------------------------------------------------------- 1 | 2 |
Hello, world.
3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/content/articles.md: -------------------------------------------------------------------------------- 1 | # Articles 2 | -------------------------------------------------------------------------------- /test/fixtures/content/blog/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Hello 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/content/description-blockquote.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | How to Create Branded Stories in Adobe Spark 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/content/description-blockquote.md: -------------------------------------------------------------------------------- 1 | # How to Create Branded Stories in Adobe Spark 2 | 3 | ![](https://main--express-website--adobe.hlx3.page/media_126d853c1af0f9d91c4dbc3d825cecd456b6d7fa4.png#width=1900\&width=1278) 4 | 5 | > Note: Currently, you need to set up your brand on the web at . But after set-up, you’ll be able to create on the go with Adobe Spark’s companion mobile apps. 6 | 7 | Branded stories are here! [Adobe Spark](https://www.adobe.com/express/pricing) allows you to inject more creativity into your visual stories than ever before. Using [Adobe Spark](http://spark.adobe.com/about/post), make your designs, web pages and videos look and feel like your brand by simply [adding your brand ingredients](https://spark.adobe.com/sp/branding/create) to your brand manager at spark.adobe.com and customizing branded assets until you land on a visual style that is uniquely you. 8 | -------------------------------------------------------------------------------- /test/fixtures/content/description-long.html: -------------------------------------------------------------------------------- 1 | Hello 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/content/description-long.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | This is the first paragraph. 4 | 5 | 6 | https://www.adobe.com/this/is/a/very/long/link/with/more/than/10/segments/so/it/sohuld/not/be/used/as/description 7 | 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis scelerisque orci vitae tellus accumsan posuere. Phasellus eget urna velit. Ut vulputate eros aliquam suscipit vehicula. Praesent sed finibus diam. Integer vitae posuere quam, sit amet rutrum ex. Donec vitae ante massa. Nullam convallis turpis volutpat ipsum faucibus, imperdiet gravida nunc condimentum. Ut sit amet pretium est. Mauris ut venenatis dui, sit amet varius nunc. Curabitur sed tincidunt elit. Etiam hendrerit ac enim ut tempus. Aliquam erat volutpat. Proin consectetur libero ut purus feugiat, sit amet pharetra sem commodo. Etiam eu scelerisque massa, non euismod mi. Quisque eget rhoncus neque. 10 | 11 | 12 | And this is the last. 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/content/description.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Return of the raspberry: New Zealand’s favourite combo: Foo-Bar New Zealand 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/fixtures/content/description.md: -------------------------------------------------------------------------------- 1 | 2 | # Return of the **raspberry**: New Zealand’s favourite combo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
Images

Once again, New Zealanders will get to enjoy the combination of Foo-Bar with raspberry from November 1st.

12 | 13 | It’s a Kiwi classic - adding a shot of raspberry syrup to your Foobar. So Foo-Bar have just launched Foobar Raspberry, adding a summertime treat for the upcoming festive season. 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
Metadata
TitleReturn of the raspberry: New Zealand’s favourite combo: Foo-Bar New Zealand
DescriptionDescription override
Tagsbrand
AuthorJourney NZ Staff
Publication Date2017/10/31
41 | -------------------------------------------------------------------------------- /test/fixtures/content/empty-table-row.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ACME CORP 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |
27 |

Empty HTML Table Row

28 |
29 |
30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/content/empty-table-row.md: -------------------------------------------------------------------------------- 1 | # Empty HTML Table Row 2 | 3 | 4 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /test/fixtures/content/fedpub-header.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /test/fixtures/content/fedpub-header.plain.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /test/fixtures/content/generic-product.md: -------------------------------------------------------------------------------- 1 | # Product Page 2 | -------------------------------------------------------------------------------- /test/fixtures/content/generic-product/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | ":version": 3, 3 | ":type": "multi-sheet", 4 | ":names": [ 5 | "default" 6 | ], 7 | "default": { 8 | "total": 2, 9 | "offset": 0, 10 | "limit": 2, 11 | "data": [ 12 | { 13 | "URL": "/page-*", 14 | "Category": "rendering-test" 15 | }, 16 | { 17 | "url": "**/page-*-blocks", 18 | "Glob Test": "match ** and * combo" 19 | }, 20 | { 21 | "Url": "**/marketing/**", 22 | "Category": "Marketing" 23 | }, 24 | { 25 | "URL": "/page-metadata-json.html", 26 | "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png", 27 | "Keywords": "Baz, Bar, Foo", 28 | "og:publisher": "Adobe" 29 | }, 30 | { 31 | "URL": "/page-metadata-json", 32 | "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png", 33 | "Keywords": "Baz, Bar, Foo", 34 | "og:publisher": "Adobe" 35 | }, 36 | { 37 | "URL": "/exact-match.html", 38 | "Keywords": "Exactomento", 39 | "og:publisher": "Adobe", 40 | "Short Title": "E" 41 | }, 42 | { 43 | "URL": "/page-metadata-block", 44 | "Short Title": "global-meta" 45 | }, 46 | { 47 | "URL": "/exact-match", 48 | "Keywords": "Exactomento", 49 | "og:publisher": "Adobe", 50 | "Short Title": "E" 51 | }, 52 | { 53 | "URL": "/exact-folder/", 54 | "Keywords": "Exactomento Folder", 55 | "og:publisher": "Adobe", 56 | "Short Title": "E" 57 | }, 58 | { 59 | "URL": "/products**", 60 | "Keywords": "Exactomento Mapped Folder", 61 | "og:publisher": "Adobe", 62 | "Short Title": "E" 63 | }, 64 | { 65 | "URL": "/products/product2", 66 | "last-modified": "2024-12-25T03:33:33Z" 67 | } 68 | ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/fixtures/content/head-with-script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 |
23 |
24 |

No head.html Test

25 |
26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /test/fixtures/content/head-with-script.md: -------------------------------------------------------------------------------- 1 | # No head.html Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/headings.html: -------------------------------------------------------------------------------- 1 |
2 |

Heading 1 (double-underline)

3 |

Heading 2 (single-underline)

4 |

Heading 1

5 |

Heading 2

6 |

Heading 3

7 |

Heading 4

8 |
Heading 5
9 |
Heading 6
10 |

one and two

11 |

bar & foo-99

12 |

frashberry bar 13 | 14 | 15 |

16 |

trashberry bar 17 | 18 | 19 |

20 |

1. Goals

21 |
22 |
23 | -------------------------------------------------------------------------------- /test/fixtures/content/headings.md: -------------------------------------------------------------------------------- 1 | Heading 1 (double-underline) 2 | ========= 3 | 4 | Heading 2 (single-underline) 5 | --------- 6 | 7 | # Heading 1 8 | 9 | ## Heading 2 10 | 11 | ### Heading 3 12 | 13 | #### Heading 4 14 | 15 | ##### Heading 5 16 | 17 | ###### Heading 6 18 | 19 | ## _one_ and _two_ 20 | 21 | ### bar & foo-99 22 | 23 | ### frashberry bar :#gf: :#v: 24 | 25 |

trashberry bar :#gf: :#v:

26 | 27 |

1. Goals

28 | -------------------------------------------------------------------------------- /test/fixtures/content/icons-ignored.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Icons

4 |

:button:

5 |
:rocket:
6 |

https://example.test/:urn:

7 |

urn:aaid:sc:VA6C2:ac6066f3-fd1d-4e00-bed3-fa3aa6d981d8

8 |
9 |
-------------------------------------------------------------------------------- /test/fixtures/content/icons-ignored.md: -------------------------------------------------------------------------------- 1 | # Icons 2 | 3 | `:button:` 4 | 5 | ``` 6 | :rocket: 7 | ``` 8 | 9 | [https://example.test/:urn:](https://example.test/:urn:) 10 | 11 | urn:aaid:sc:VA6C2:ac6066f3-fd1d-4e00-bed3-fa3aa6d981d8 12 | -------------------------------------------------------------------------------- /test/fixtures/content/icons.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Icons

4 |

Hello

5 |

Hello banner.

6 |

Hello mark.

7 |

Teamblasting off again.

8 |
9 |
-------------------------------------------------------------------------------- /test/fixtures/content/icons.md: -------------------------------------------------------------------------------- 1 | # Icons 2 | 3 | Hello :button: 4 | 5 | Hello :red: banner. 6 | 7 | Hello :#check: mark. 8 | 9 | Team:rocket:blasting off again. 10 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta-rewrite-link.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ACME CORP 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |

Hero

29 |

Test Content.

30 |
31 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta-rewrite-link.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | Test Content. 4 | 5 | +---------------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +------------------+--------------------------------------------------------------------------------+ 8 | | Image | | 9 | +------------------+--------------------------------------------------------------------------------+ 10 | | Publication Date | 09/12/2023 | 11 | +------------------+--------------------------------------------------------------------------------+ 12 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta-rewrite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hero 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |

Hero

24 |

Test Content.

25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta-rewrite.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | Test Content. 4 | 5 | +------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +------------------+-----------------------------------------------------------+ 8 | | Image | ![][image0] | 9 | +------------------+-----------------------------------------------------------+ 10 | | Publication Date | 09/12/2023 | 11 | +------------------+-----------------------------------------------------------+ 12 | 13 | [image0]: https://main--helix-pages--adobe.hlx.page/media_176cf630873d24a275d9f500a15fd32abca5be225.jpeg 14 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hero 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |

Hero

24 |

25 | 26 | 27 | 28 | 29 | Hero image 30 | 31 |

32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /test/fixtures/content/image-from-meta.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | ![Hero image](https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png) 4 | 5 | 6 | |Metadata|| 7 | |-|-| 8 | |Image|https://hlx.blob.core.windows.net/external/67af739484f3d60dc64e306ccbf9b90a6d63a24c#image.png| 9 | |Image-Alt|Alt text from metadata| 10 | -------------------------------------------------------------------------------- /test/fixtures/content/image-no-alt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hero 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |

Hero

23 |

24 | 25 | 26 | 27 | 28 | 29 | 30 |

31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /test/fixtures/content/image-no-alt.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | ![](https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png) -------------------------------------------------------------------------------- /test/fixtures/content/image-with-title.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | ![Alternative description][image0] 4 | 5 | ![Alternative description][image1] 6 | 7 | [image0]: https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png "Title attribute" 8 | 9 | [image1]: https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png "Alternative description" 10 | -------------------------------------------------------------------------------- /test/fixtures/content/image.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hero 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |

Hero

24 |

25 | 26 | 27 | 28 | 29 | Hero image 30 | 31 |

32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /test/fixtures/content/image.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | ![Hero image](https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png) -------------------------------------------------------------------------------- /test/fixtures/content/images.md: -------------------------------------------------------------------------------- 1 | # Hero 2 | 3 | ![Hero image](https://hlx.blob.core.windows.net/external/a22b1a53edf9b324465d14b2efca169a25d564a0#image.png) 4 | 5 | ## Foo 6 | 7 | ![](https://hlx.blob.core.windows.net/external/ba025e72d401d61d991debe0a2128048fabe0a4f#image.png?width=800\&height=600) 8 | 9 | Lorem ipsum dolor sit amet. 10 | 11 | ![](https://hlx.blob.core.windows.net/external/67af739484f3d60dc64e306ccbf9b90a6d63a24c#image.png) 12 | 13 | here a media link 14 | 15 | ![](https://main--pages--adobe.hlx.live/media_ba025e72d401d61d991debe0a2128048fabe0a4f.png#width=800\&height=600) 16 | 17 | here a media link with wrong fragment 18 | 19 | ![](https://main--pages--adobe.hlx.live/media_ba025e72d401d61d991debe0a2128048fabe0a4f.png#width=800\&width=600) 20 | 21 | image wrapped in em 22 | 23 | _![](https://main--pages--adobe.hlx.live/media_ba025e72d401d61d991debe0a2128048fabe0a4f.png)_ 24 | 25 | image wrapped in strong 26 | 27 | **![](https://main--pages--adobe.hlx.live/media_ba025e72d401d61d991debe0a2128048fabe0a4f.png)** 28 | 29 | -------------------------------------------------------------------------------- /test/fixtures/content/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Hello 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/content/md-headings.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 |
5 |
6 |

Our Company

7 |
8 |
9 |

Brands

10 |
11 | 14 |
15 |

News

16 |
17 |
18 | 19 |
20 |
21 |

22 |
23 |
24 | -------------------------------------------------------------------------------- /test/fixtures/content/md-headings.md: -------------------------------------------------------------------------------- 1 | :tccc: 2 | 3 | 4 | --- 5 | 6 | ## [Our Company](https://main--website--hlxsites.hlx.live/company) 7 | 8 | --- 9 | 10 | ## [Brands](https://main--website--hlxsites.hlx.live/brands) 11 | 12 | --- 13 | 14 | ## [Responsible Business](https://main--website--hlxsites.hlx.live/responsible-business) 15 | 16 | --- 17 | 18 | ## [News](https://main--website--hlxsites.hlx.live/news) 19 | 20 | --- 21 | 22 | ## [:search:](https://main--website--hlxsites.hlx.live/search) 23 | 24 | --- 25 | 26 | ## [:globe:](https://main--website--hlxsites.hlx.live/countries) 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
Metadata
robotsnoindex
38 | -------------------------------------------------------------------------------- /test/fixtures/content/meta-response-headers.html: -------------------------------------------------------------------------------- 1 | 2 | Hello Meta 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/fixtures/content/meta-response-headers.md: -------------------------------------------------------------------------------- 1 | # Hello Meta 2 | -------------------------------------------------------------------------------- /test/fixtures/content/meta-response-headers.plain.html: -------------------------------------------------------------------------------- 1 |

Hello Meta

2 | -------------------------------------------------------------------------------- /test/fixtures/content/metadata-kv.json: -------------------------------------------------------------------------------- 1 | { 2 | ":version": 3, 3 | ":type": "multi-sheet", 4 | ":names": [ 5 | "default" 6 | ], 7 | "default": { 8 | "total": 5, 9 | "offset": 0, 10 | "limit": 5, 11 | "data": [ 12 | { 13 | "URL": "/news/**", 14 | "key": "category", 15 | "value": "news" 16 | }, 17 | { 18 | "URL": "/news/**", 19 | "key": "author", 20 | "value": "ACME PR" 21 | }, 22 | { 23 | "URL": "/blog/**", 24 | "key": "category", 25 | "value": "blog" 26 | }, 27 | { 28 | "URL": "", 29 | "key": "ignored", 30 | "value": "value" 31 | }, 32 | { 33 | "URL": "/**", 34 | "key": "title", 35 | "value": "ACME CORP" 36 | }, 37 | { 38 | "URL": "/**", 39 | "key": "description", 40 | "value": "Lorem ipsum dolor sit amet." 41 | }, 42 | { 43 | "URL": "/**", 44 | "key": "keywords", 45 | "value": "ACME, CORP, PR" 46 | } 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/fixtures/content/metadata-product.json: -------------------------------------------------------------------------------- 1 | { 2 | ":version": 3, 3 | ":type": "multi-sheet", 4 | ":names": [ 5 | "default" 6 | ], 7 | "default": { 8 | "total": 2, 9 | "offset": 0, 10 | "limit": 2, 11 | "data": [ 12 | { 13 | "URL": "/**", 14 | "Title": "Product" 15 | } 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/content/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | ":version": 3, 3 | ":type": "multi-sheet", 4 | ":names": [ 5 | "default" 6 | ], 7 | "default": { 8 | "total": 2, 9 | "offset": 0, 10 | "limit": 2, 11 | "data": [ 12 | { 13 | "URL": "/page-*", 14 | "Category": "rendering-test" 15 | }, 16 | { 17 | "url": "**/page-*-blocks", 18 | "Glob Test": "match ** and * combo" 19 | }, 20 | { 21 | "Url": "**/marketing/**", 22 | "Category": "Marketing" 23 | }, 24 | { 25 | "URL": "/page-metadata-json.html", 26 | "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png", 27 | "Keywords": "Baz, Bar, Foo", 28 | "og:publisher": "Adobe" 29 | }, 30 | { 31 | "URL": "/page-metadata-json", 32 | "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png", 33 | "Keywords": "Baz, Bar, Foo", 34 | "og:publisher": "Adobe" 35 | }, 36 | { 37 | "URL": "/exact-match.html", 38 | "Keywords": "Exactomento", 39 | "og:publisher": "Adobe", 40 | "Short Title": "E" 41 | }, 42 | { 43 | "URL": "/page-metadata-block", 44 | "Short Title": "global-meta" 45 | }, 46 | { 47 | "URL": "/exact-match", 48 | "Keywords": "Exactomento", 49 | "og:publisher": "Adobe", 50 | "Short Title": "E" 51 | }, 52 | { 53 | "URL": "/exact-folder/", 54 | "Keywords": "Exactomento Folder", 55 | "og:publisher": "Adobe", 56 | "Short Title": "E" 57 | }, 58 | { 59 | "URL": "/products**", 60 | "Keywords": "Exactomento Mapped Folder", 61 | "og:publisher": "Adobe", 62 | "Short Title": "E" 63 | } 64 | ] 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/fixtures/content/no-head-html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

No head.html Test

22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/content/no-head-html.md: -------------------------------------------------------------------------------- 1 | # No head.html Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-headers-different.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

Nonce Test

28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-headers-different.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-headers-meta.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-headers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

Nonce Test

28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-headers.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta-different.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |

Nonce Test

29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta-different.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta-move-as-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

Nonce Test

28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta-move-as-header.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |

Nonce Test

29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-meta.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-script-only.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

Nonce Test

28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-script-only.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-style-only.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ACME CORP 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |

Nonce Test

27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /test/fixtures/content/nonce-style-only.md: -------------------------------------------------------------------------------- 1 | # Nonce Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/not-found-with-handler.html: -------------------------------------------------------------------------------- 1 | this should not be loaded 2 | -------------------------------------------------------------------------------- /test/fixtures/content/one-section.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Hello

4 |

This is the first section.

5 |
6 |
7 | -------------------------------------------------------------------------------- /test/fixtures/content/one-section.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | This is the first section. 4 | -------------------------------------------------------------------------------- /test/fixtures/content/one-section.plain.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello

3 |

This is the first section.

4 |
5 | -------------------------------------------------------------------------------- /test/fixtures/content/one-section/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Hello 3 | 4 | -------------------------------------------------------------------------------- /test/fixtures/content/one-section/index.plain.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello

3 |
4 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-1-col.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Single col block

4 |
5 |
6 |
7 |
8 |
9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 |

17 |

Jesus Ramirez

18 |

One of the world's top Photoshop instructors, Jesus has taught millions of creatives like you.

19 |

20 | 21 | 22 | 23 | 24 | 25 | Follow Me 26 |

27 |
28 |
29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-1-col.md: -------------------------------------------------------------------------------- 1 | # Single col block 2 | 3 | --- 4 | 5 | |About-bio| 6 | |-| 7 | |

Jesus Ramirez

One of the world's top Photoshop instructors, Jesus has taught millions of creatives like you.

Follow Me

| 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-1-col.plain.html: -------------------------------------------------------------------------------- 1 |
2 |

Single col block

3 |
4 |
5 |
6 |
7 |
8 |

9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 |

Jesus Ramirez

17 |

One of the world's top Photoshop instructors, Jesus has taught millions of creatives like you.

18 |

19 | 20 | 21 | 22 | 23 | 24 | Follow Me 25 |

26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-2-col.html: -------------------------------------------------------------------------------- 1 |
2 |

Double col block

3 |
4 |
5 |
6 |
https://www.youtube.com/watch?v=kwLTe-ueHA8
7 |
8 |

Tues, April 21st

9 |

Tips for Faster Editing with co-host Ryan Connolly

10 | (Download PDF) 11 |
12 |
13 |
14 |
https://www.youtube.com/watch?v=818roIRrZm0
15 |
16 |

Tues, April 28th

17 |

Vlogging Made Easy with co-host Shameless Maya

18 | (Download PDF) 19 |
20 |
21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-2-col.md: -------------------------------------------------------------------------------- 1 | # Double col block 2 | 3 | --- 4 | 5 | |Video|Text| 6 | |-----|----| 7 | |https://www.youtube.com/watch?v=kwLTe-ueHA8|

Tues, April 21st

Tips for Faster Editing with co-host Ryan Connolly

(Download PDF)| 8 | |https://www.youtube.com/watch?v=818roIRrZm0|

Tues, April 28th

Vlogging Made Easy with co-host Shameless Maya

(Download PDF)| 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-2-col.plain.html: -------------------------------------------------------------------------------- 1 |

Double col block

2 |
3 |
4 |
5 |
https://www.youtube.com/watch?v=kwLTe-ueHA8
6 |
7 |

Tues, April 21st

8 |

Tips for Faster Editing with co-host Ryan Connolly

9 | (Download PDF) 10 |
11 |
12 |
13 |
https://www.youtube.com/watch?v=818roIRrZm0
14 |
15 |

Tues, April 28th

16 |

Vlogging Made Easy with co-host Shameless Maya

17 | (Download PDF) 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-empty-cols.html: -------------------------------------------------------------------------------- 1 |
2 |

empty col

3 |

the page block with empty column title

4 |
5 |
6 |
a
7 |
b
8 |
c
9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-empty-cols.md: -------------------------------------------------------------------------------- 1 | # empty col 2 | 3 | the page block with empty column title 4 | 5 | | c0 | | c1 | 6 | |----|--|----| 7 | |a | b| c | 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-no-title.html: -------------------------------------------------------------------------------- 1 |
2 |

no title

3 |

the page block with no title

4 |
5 |
6 |
a
7 |
b
8 |
9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-no-title.md: -------------------------------------------------------------------------------- 1 | # no title 2 | 3 | the page block with no title 4 | 5 | | | | 6 | |--|--| 7 | |a | b| 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-strong.html: -------------------------------------------------------------------------------- 1 |
2 |

formatting

3 |

the page block with formatting

4 |
5 |
6 |
a
7 |
b
8 |
9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-strong.md: -------------------------------------------------------------------------------- 1 | # formatting 2 | 3 | the page block with formatting 4 | 5 | | **text** | | 6 | |--|--| 7 | |a | b| 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-block-table-in-table.md: -------------------------------------------------------------------------------- 1 | # Page Blocks with html tables in tables 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
Header 1Header 2

The ultimate: table in tables:

Key

Value

Emmet

King of Lego



Parrots!

What about sections?


Would this be on a new one?

17 | 18 | 19 | # Table in Markdown table 20 | 21 | |Table| 22 | |-| 23 | |

One

Two

Three

Lorem

ipsum

dolor

| 24 | 25 | 26 | # simple table wrap 27 | 28 | 29 | 32 |
30 |

One

Two

Three

Lorem

ipsum

dolor

31 |
33 | 34 | # simple table wrap in markdown 35 | 36 | |

One

Two

Three

Lorem

ipsum

dolor

| 37 | |-| 38 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-canonical.html: -------------------------------------------------------------------------------- 1 | 2 | Pricing | Adobe Spark 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-canonical.md: -------------------------------------------------------------------------------- 1 | # Metadata Block HTML Table Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Metadata
TitlePricing | Adobe Spark
DescriptionAdobe Spark lets you easily search from thousands of free photos, use themes, add filters, pick fonts, add text to photos, and make videos on mobile and web.
Canonicalhttps://www.adobe.com/express/
20 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-empty-url.html: -------------------------------------------------------------------------------- 1 | 2 | Pricing | Adobe Spark 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-empty-url.md: -------------------------------------------------------------------------------- 1 | # Metadata Block HTML Table Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Metadata
TitlePricing | Adobe Spark
DescriptionAdobe Spark lets you easily search from thousands of free photos, use themes, add filters, pick fonts, add text to photos, and make videos on mobile and web.
og:url""
20 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-html.html: -------------------------------------------------------------------------------- 1 | 2 | Pricing | Adobe Spark 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-html.md: -------------------------------------------------------------------------------- 1 | # Metadata Block HTML Table Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
Metadata
TitlePricing | Adobe Spark
DescriptionAdobe Spark lets you easily search from thousands of free photos, use themes, add filters, pick fonts, add text to photos, and make videos on mobile and web.
article:publisherhttps://www.facebook.com/Adobe
twitter:cardsummary
Feed/feed.xml
28 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-a.html: -------------------------------------------------------------------------------- 1 | Metadata Block Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-a.md: -------------------------------------------------------------------------------- 1 | # Metadata Block Test 2 | 3 | |Metadata|| 4 | |-|-| 5 | |Tags|| 6 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-ol.html: -------------------------------------------------------------------------------- 1 | Metadata Block Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-ol.md: -------------------------------------------------------------------------------- 1 | # Metadata Block Test 2 | 3 | 4 | 5 | |Metadata|| 6 | |-|-| 7 | |Tags|
  1. One
  2. Two
  3. Three
| 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-p.html: -------------------------------------------------------------------------------- 1 | Metadata Block Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-p.md: -------------------------------------------------------------------------------- 1 | # Metadata Block Test 2 | 3 | 4 | 5 | |Metadata|| 6 | |-|-| 7 | |Tags|

One

Two

Three

| 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-ul.html: -------------------------------------------------------------------------------- 1 | Metadata Block Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block-multi-ul.md: -------------------------------------------------------------------------------- 1 | # Metadata Block Test 2 | 3 | 4 | 5 | |Metadata|| 6 | |-|-| 7 | |Tags|
  • One
  • Two
  • Three
| 8 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block.html: -------------------------------------------------------------------------------- 1 | 2 | Meta title 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-block.md: -------------------------------------------------------------------------------- 1 | # Metadata Block Test 2 | 3 | 4 | 5 | |Metadata|| 6 | |-|-| 7 | |Title|Meta title| 8 | |Description|Meta description| 9 | |Keywords|Foo, Bar, Baz| 10 | |Tags|One, Two, Three| 11 | |Template|default| 12 | |article:section|Test| 13 | |short-title|local metadata wins| 14 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-content-blocks.html: -------------------------------------------------------------------------------- 1 | Resize your image for free. 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-hreflang.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home | Helix Project Boilerplate 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |

HTML lang test

25 |

This is great.

26 |
27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-hreflang.md: -------------------------------------------------------------------------------- 1 | # HTML lang test 2 | 3 | This is great. 4 | 5 | +-----------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +====================+==========================================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +--------------------+--------------------------------------------------------------------------| 10 | | hreflang-de | | 11 | +--------------------+--------------------------------------------------------------------------+ 12 | | hreflang-fr-FR | | 13 | +--------------------+--------------------------------------------------------------------------+ 14 | | hreflang-x-default | | 15 | +--------------------+--------------------------------------------------------------------------+ 16 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-htmllang-short.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home | Helix Project Boilerplate 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |

HTML lang test

22 |

This is great.

23 |
24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-htmllang-short.md: -------------------------------------------------------------------------------- 1 | # HTML lang test 2 | 3 | This is great. 4 | 5 | +-------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +================+==========================================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+--------------------------------------------------------------------------| 10 | | html-lang | de | 11 | +----------------+--------------------------------------------------------------------------+ 12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-htmllang.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home | Helix Project Boilerplate 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |

HTML lang test

22 |

This is great.

23 |
24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-htmllang.md: -------------------------------------------------------------------------------- 1 | # HTML lang test 2 | 3 | This is great. 4 | 5 | +-------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +================+==========================================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+--------------------------------------------------------------------------| 10 | | html-lang | en-US | 11 | +----------------+--------------------------------------------------------------------------+ 12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-json.html: -------------------------------------------------------------------------------- 1 | 2 | Metadata JSON Test 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-json.md: -------------------------------------------------------------------------------- 1 | # Metadata JSON Test 2 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-error.html: -------------------------------------------------------------------------------- 1 | 2 | Home | Helix Project Boilerplate 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-error.md: -------------------------------------------------------------------------------- 1 | # JSON LD Test 2 | 3 | This is great. 4 | 5 | +----------------------------------------------------+ 6 | | Metadata | 7 | +================+===================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+-----------------------------------| 10 | | Json-Ld | "@context":"http://schema.org" | 11 | +----------------+-----------------------------------+ 12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-global.html: -------------------------------------------------------------------------------- 1 | 2 | Global JSON LD Test 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-global.md: -------------------------------------------------------------------------------- 1 | # Global JSON LD Test 2 | 3 | This is great. 4 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-list.html: -------------------------------------------------------------------------------- 1 | 2 | Home | Helix Project Boilerplate 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-multi.html: -------------------------------------------------------------------------------- 1 | 2 | Home | Helix Project Boilerplate 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-multi.md: -------------------------------------------------------------------------------- 1 | # JSON LD Test 2 | 3 | This is great. 4 | 5 | +-------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +================+==========================================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+--------------------------------------------------------------------------| 10 | | json-ld | {"@context":"http://schema.org","@type":"Product","sku":"BPB-CMON-TABS"} | 11 | +----------------+--------------------------------------------------------------------------| 12 | | json-ld | {"@context":"http://schema.org","@type":"Product","sku":"FOO-BAR-12345"} | 13 | +----------------+--------------------------------------------------------------------------+ 14 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-xss.html: -------------------------------------------------------------------------------- 1 | 2 | Home | Helix Project Boilerplate 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld-xss.md: -------------------------------------------------------------------------------- 1 | # JSON LD Test 2 | 3 | This is great. 4 | 5 | +-------------------------------------------------------------------------+ 6 | | Metadata | 7 | +================+========================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+--------------------------------------------------------| 10 | | Json-Ld | { "foo:": "\ 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-jsonld.md: -------------------------------------------------------------------------------- 1 | # JSON LD Test 2 | 3 | This is great. 4 | 5 | +-------------------------------------------------------------------------------------------+ 6 | | Metadata | 7 | +================+==========================================================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+--------------------------------------------------------------------------| 10 | | json-ld | {"@context":"http://schema.org","@type":"Product","sku":"BPB-CMON-TABS"} | 11 | +----------------+--------------------------------------------------------------------------+ 12 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-no-fallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
26 |

Congrats, you are ready to go!

27 |

Your forked repo is setup as a helix project and you are ready to start developing.

28 |
29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-no-fallback.md: -------------------------------------------------------------------------------- 1 | # Congrats, you are ready to go! 2 | 3 | Your forked repo is setup as a helix project and you are ready to start developing. 4 | 5 | +---------------------------------+ 6 | | Metadata | 7 | +============================+====+ 8 | | title | | 9 | +----------------------------+----+ 10 | | description | | 11 | +----------------------------+----+ 12 | | canonical | | 13 | +----------------------------+----+ 14 | | image | | 15 | +----------------------------+----+ 16 | | og:url | | 17 | +----------------------------+----+ 18 | | twitter:card | | 19 | +----------------------------+----+ 20 | | categories | | 21 | +----------------------------+----+ 22 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-twitter-fallback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Home | Helix Project Boilerplate 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |

Congrats, you are ready to go!

26 |

Your forked repo is setup as a helix project and you are ready to start developing.

27 |
28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/content/page-metadata-twitter-fallback.md: -------------------------------------------------------------------------------- 1 | # Congrats, you are ready to go! 2 | 3 | Your forked repo is setup as a helix project and you are ready to start developing. 4 | 5 | +----------------------------------------------------+ 6 | | Metadata | 7 | +================+===================================+ 8 | | title | Home \| Helix Project Boilerplate | 9 | +----------------+-----------------------------------| 10 | | og:title | og title | 11 | +----------------+-----------------------------------+ 12 | | og:description | og description | 13 | +----------------+-----------------------------------+ 14 | | og:image | og image | 15 | +----------------+-----------------------------------+ 16 | | twitter:image | twitter image | 17 | +----------------+-----------------------------------+ 18 | -------------------------------------------------------------------------------- /test/fixtures/content/pricing.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 1, 4 | "total": 1, 5 | "data": [ 6 | { 7 | "col0": "cell(0,0)", 8 | "col1": "cell(0,1)", 9 | "col2": "cell(0,2)", 10 | "col3": "cell(0,3)" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/content/simple.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Hello

4 |

This is the first section.

5 |
6 |
7 |

Foo

8 |

Here comes the 2nd section

9 |
10 |
11 |

and the last :-)

12 |
13 |
14 | -------------------------------------------------------------------------------- /test/fixtures/content/simple.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | This is the first section. 4 | 5 | --- 6 | 7 | ## Foo 8 | 9 | Here comes the 2nd section 10 | 11 | --- 12 | 13 | and the last :-) 14 | -------------------------------------------------------------------------------- /test/fixtures/content/simple.plain.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello

3 |

This is the first section.

4 |
5 |
6 |

Foo

7 |

Here comes the 2nd section

8 |
9 |
10 |

and the last :-)

11 |
12 | -------------------------------------------------------------------------------- /test/fixtures/content/sitemap-bad-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "this is not an array" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/content/sitemap-corrupt.json: -------------------------------------------------------------------------------- 1 | this is not JSON -------------------------------------------------------------------------------- /test/fixtures/content/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "total": 2, 3 | "offset": 0, 4 | "limit": 8, 5 | "columns": [ 6 | "path", 7 | "lastModified", 8 | "robots" 9 | ], 10 | "data": [ 11 | { 12 | "path": "/", 13 | "lastModified": 1701361070, 14 | "robots": "" 15 | }, 16 | { 17 | "lastModified": 1703163776, 18 | "path": "/test", 19 | "robots": "" 20 | } 21 | ], 22 | ":type": "sheet" 23 | } -------------------------------------------------------------------------------- /test/fixtures/content/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | https://www.aem.live/ 4 | 5 | 6 | https://www.aem.live/developer 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/content/special/default-article.md: -------------------------------------------------------------------------------- 1 | # Special Article 2 | 3 | -------------------------------------------------------------------------------- /test/fixtures/content/static-content.html: -------------------------------------------------------------------------------- 1 | this is static html in content-bus 2 | -------------------------------------------------------------------------------- /test/fixtures/json/test-data-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "countries": [ 3 | { 4 | "Code": "JP", 5 | "Country": "Japan", 6 | "Number": 3 7 | }, 8 | { 9 | "Code": "DE", 10 | "Country": "Germany", 11 | "Number": 5 12 | }, 13 | { 14 | "Code": "US", 15 | "Country": "USA", 16 | "Number": 7 17 | }, 18 | { 19 | "Code": "CH", 20 | "Country": "Switzerland", 21 | "Number": 27 22 | }, 23 | { 24 | "Code": "FR", 25 | "Country": "France", 26 | "Number": 99 27 | }, 28 | { 29 | "Code": "AUS", 30 | "Country": "Australia", 31 | "Number": 12 32 | } 33 | ], 34 | "abc": [ 35 | { 36 | "A": 112, 37 | "B": 224, 38 | "C": 135 39 | }, 40 | { 41 | "A": 2244, 42 | "B": 234, 43 | "C": 53 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/forms.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [ 4 | { 5 | "type": "heading", 6 | "depth": 1, 7 | "children": [ 8 | { 9 | "type": "text", 10 | "value": "Hello " 11 | }, 12 | { 13 | "type": "html", 14 | "value": "" 15 | }, 16 | { 17 | "type": "text", 18 | "value": "World" 19 | }, 20 | { 21 | "type": "html", 22 | "value": "" 23 | } 24 | ] 25 | }, 26 | { 27 | "type": "html", 28 | "value": "
\n \n
" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/forms.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 |
4 | 5 |
-------------------------------------------------------------------------------- /test/fixtures/mdasts/heading-ids.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [{ 4 | "children": [ 5 | { 6 | "type": "text", 7 | "value": "Foo" 8 | } 9 | ], 10 | "depth": 1, 11 | "type": "heading" 12 | }, 13 | { 14 | "children": [ 15 | { 16 | "type": "text", 17 | "value": "Bar" 18 | } 19 | ], 20 | "depth": 2, 21 | "type": "heading" 22 | }, 23 | { 24 | "children": [ 25 | { 26 | "type": "text", 27 | "value": "Baz" 28 | } 29 | ], 30 | "depth": 3, 31 | "type": "heading" 32 | }, 33 | { 34 | "children": [ 35 | { 36 | "type": "text", 37 | "value": "Qux" 38 | } 39 | ], 40 | "depth": 2, 41 | "type": "heading" 42 | }, 43 | { 44 | "children": [ 45 | { 46 | "type": "text", 47 | "value": "Bar" 48 | } 49 | ], 50 | "depth": 3, 51 | "type": "heading" 52 | }, 53 | { 54 | "children": [ 55 | { 56 | "type": "text", 57 | "value": "Bar-1" 58 | } 59 | ], 60 | "depth": 4, 61 | "type": "heading" 62 | }, 63 | { 64 | "children": [ 65 | { 66 | "children": [ 67 | { 68 | "type": "text", 69 | "value": "Foo" 70 | } 71 | ], 72 | "type": "strong" 73 | }, 74 | { 75 | "type": "text", 76 | "value": " " 77 | }, 78 | { 79 | "children": [ 80 | { 81 | "type": "text", 82 | "value": "Bar" 83 | } 84 | ], 85 | "type": "emphasis" 86 | }, 87 | { 88 | "type": "text", 89 | "value": " " 90 | }, 91 | { 92 | "type": "inlineCode", 93 | "value": "Baz" 94 | } 95 | ], 96 | "depth": 1, 97 | "type": "heading" 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/headings.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [{ 4 | "children": [ 5 | { 6 | "type": "text", 7 | "value": "Heading 1 (double-underline)" 8 | } 9 | ], 10 | "depth": 1, 11 | "type": "heading" 12 | }, 13 | { 14 | "children": [ 15 | { 16 | "type": "text", 17 | "value": "Heading 2 (single-underline)" 18 | } 19 | ], 20 | "depth": 2, 21 | "type": "heading" 22 | }, 23 | { 24 | "children": [ 25 | { 26 | "type": "text", 27 | "value": "Heading 1" 28 | } 29 | ], 30 | "depth": 1, 31 | "type": "heading" 32 | }, 33 | { 34 | "children": [ 35 | { 36 | "type": "text", 37 | "value": "Heading 2" 38 | } 39 | ], 40 | "depth": 2, 41 | "type": "heading" 42 | }, 43 | { 44 | "children": [ 45 | { 46 | "type": "text", 47 | "value": "Heading 3" 48 | } 49 | ], 50 | "depth": 3, 51 | "type": "heading" 52 | }, 53 | { 54 | "children": [ 55 | { 56 | "type": "text", 57 | "value": "Heading 4" 58 | } 59 | ], 60 | "depth": 4, 61 | "type": "heading" 62 | }, 63 | { 64 | "children": [ 65 | { 66 | "type": "text", 67 | "value": "Heading 5" 68 | } 69 | ], 70 | "depth": 5, 71 | "type": "heading" 72 | }, 73 | { 74 | "children": [ 75 | { 76 | "type": "text", 77 | "value": "Heading 6" 78 | } 79 | ], 80 | "depth": 6, 81 | "type": "heading" 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/headings.md: -------------------------------------------------------------------------------- 1 | Heading 1 (double-underline) 2 | ========= 3 | 4 | Heading 2 (single-underline) 5 | --------- 6 | 7 | # Heading 1 8 | 9 | ## Heading 2 10 | 11 | ### Heading 3 12 | 13 | #### Heading 4 14 | 15 | ##### Heading 5 16 | 17 | ###### Heading 6 18 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/icon-example.md: -------------------------------------------------------------------------------- 1 | # The **Helix** :pipeline: supports icons now 2 | 3 | This :tada: will render as an icon. :thumbsup: 4 | 5 | This :#tada: will also render as an icon, but is part of an icon collection. 6 | 7 | I said: this is cool. There are smiles :) - even **big :smiles:** and [:foo:](http://www.example.com/) 8 | 9 | :: smile :smile::smile:::smile::::smile: 10 | 11 | ```javascript 12 | console.log('this is in a :code: block'); 13 | ``` 14 | `this is inline :code:` 15 | 16 | :rocket: is an icon at the beginning of the line, and here's one at the end: :heart-0: 17 | 18 | Oh, and 09:00:00 is a time code. 19 | 20 | No icon here -------------------------------------------------------------------------------- /test/fixtures/mdasts/paragraph.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "paragraph", 3 | "children": [ 4 | { 5 | "type": "link", 6 | "title": null, 7 | "url": "https://house.md/syntax-tree/mdast.md", 8 | "children": [ 9 | { 10 | "type": "text", 11 | "value": "External link", 12 | "position": { 13 | "start": { 14 | "line": 162, 15 | "column": 24, 16 | "offset": 6704 17 | }, 18 | "end": { 19 | "line": 162, 20 | "column": 36, 21 | "offset": 6716 22 | }, 23 | "indent": [] 24 | } 25 | } 26 | ], 27 | "position": { 28 | "start": { 29 | "line": 162, 30 | "column": 23, 31 | "offset": 6703 32 | }, 33 | "end": { 34 | "line": 162, 35 | "column": 75, 36 | "offset": 6755 37 | }, 38 | "indent": [] 39 | } 40 | }, 41 | { 42 | "type": "text", 43 | "value": ": the parsed ", 44 | "position": { 45 | "start": { 46 | "line": 162, 47 | "column": 10, 48 | "offset": 6690 49 | }, 50 | "end": { 51 | "line": 162, 52 | "column": 23, 53 | "offset": 6703 54 | }, 55 | "indent": [] 56 | } 57 | }, 58 | { 59 | "type": "link", 60 | "title": "My title", 61 | "url": "/mdast.md", 62 | "children": [ 63 | { 64 | "type": "image", 65 | "title": null, 66 | "url": "/dist/img/ipad.png", 67 | "alt": "ipad" 68 | } 69 | ], 70 | "position": { 71 | "start": { 72 | "line": 162, 73 | "column": 23, 74 | "offset": 6703 75 | }, 76 | "end": { 77 | "line": 162, 78 | "column": 75, 79 | "offset": 6755 80 | }, 81 | "indent": [] 82 | } 83 | } 84 | ], 85 | "position": { 86 | "start": { 87 | "line": 162, 88 | "column": 3, 89 | "offset": 6683 90 | }, 91 | "end": { 92 | "line": 162, 93 | "column": 75, 94 | "offset": 6755 95 | }, 96 | "indent": [] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/simple-links.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [ 4 | { 5 | "type": "heading", 6 | "depth": 1, 7 | "children": [ 8 | { 9 | "type": "text", 10 | "value": "Various Links" 11 | } 12 | ] 13 | }, 14 | { 15 | "type": "paragraph", 16 | "children": [ 17 | { 18 | "type": "link", 19 | "title": null, 20 | "url": "https://www.adobe.com", 21 | "children": [ 22 | { 23 | "type": "text", 24 | "value": "https://www.adobe.com" 25 | } 26 | ] 27 | } 28 | ] 29 | }, 30 | { 31 | "type": "paragraph", 32 | "children": [ 33 | { 34 | "type": "link", 35 | "title": null, 36 | "url": "https://example.com/test_suite.html", 37 | "children": [ 38 | { 39 | "type": "text", 40 | "value": "test_suite" 41 | } 42 | ] 43 | } 44 | ] 45 | }, 46 | { 47 | "type": "paragraph", 48 | "children": [ 49 | { 50 | "type": "link", 51 | "title": null, 52 | "url": "https://example.com/test.html?d=wb4c84d46c3bf40b7bf36440744f1ee6f&csf=1&web=1&e=QcIGyX", 53 | "children": [ 54 | { 55 | "type": "text", 56 | "value": "query" 57 | } 58 | ] 59 | } 60 | ] 61 | }, 62 | { 63 | "type": "paragraph", 64 | "children": [ 65 | { 66 | "type": "link", 67 | "title": null, 68 | "url": "https://www.youtube.com/watch?v=85UKLsvQEIA", 69 | "children": [ 70 | { 71 | "type": "image", 72 | "title": null, 73 | "url": "https://hlx.blob.core.windows.net/external/aa59825575016ba5bb9f1ee54be5d7efc23e3032#image.png", 74 | "alt": "Lars explains the future." 75 | } 76 | ] 77 | } 78 | ] 79 | }, 80 | { 81 | "type": "paragraph", 82 | "children": [ 83 | { 84 | "type": "text", 85 | "value": "" 86 | } 87 | ] 88 | } 89 | ] 90 | } 91 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/simple-links.md: -------------------------------------------------------------------------------- 1 | # Various Links 2 | 3 | 4 | 5 | [test_suite](https://example.com/test\_suite.html) 6 | 7 | [query](https://example.com/test.html?d=wb4c84d46c3bf40b7bf36440744f1ee6f\&csf=1\&web=1\&e=QcIGyX) 8 | 9 | [![Lars explains the future.](https://hlx.blob.core.windows.net/external/aa59825575016ba5bb9f1ee54be5d7efc23e3032#image.png)](https://www.youtube.com/watch?v=85UKLsvQEIA) 10 | 11 | \ 12 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [{ 4 | "type": "heading", 5 | "depth": 1, 6 | "children": [{ 7 | "type": "text", 8 | "value": "Hello World" 9 | }] 10 | }] 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/mdasts/simple.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | -------------------------------------------------------------------------------- /test/fixtures/sections/2images.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "helix-logo\nhelix-logo", 3 | "image": "./helix_logo.png", 4 | "intro": "helix-logo\nhelix-logo", 5 | "meta": { 6 | "types": [ 7 | "has-image", 8 | "nb-image-2", 9 | "has-only-image" 10 | ] 11 | }, 12 | "type": "root", 13 | "children": [ 14 | { 15 | "type": "paragraph", 16 | "children": [ 17 | { 18 | "type": "image", 19 | "title": null, 20 | "url": "./helix_logo.png", 21 | "alt": "helix-logo" 22 | }, 23 | { 24 | "type": "text", 25 | "value": "\n" 26 | }, 27 | { 28 | "type": "image", 29 | "title": null, 30 | "url": "./helix_logo.png", 31 | "alt": "helix-logo" 32 | } 33 | ], 34 | "meta": { 35 | "types": [ 36 | "has-image" 37 | ] 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/sections/2images.md: -------------------------------------------------------------------------------- 1 | ![helix-logo](./helix_logo.png) 2 | ![helix-logo](./helix_logo.png) -------------------------------------------------------------------------------- /test/fixtures/sections/header.json: -------------------------------------------------------------------------------- 1 | { 2 | "intro": "Header only", 3 | "title": "Header only", 4 | "meta": { 5 | "types": [ 6 | "has-heading", 7 | "nb-heading-1", 8 | "has-only-heading" 9 | ] 10 | }, 11 | "type": "root", 12 | "children": [ 13 | { 14 | "type": "heading", 15 | "depth": 1, 16 | "children": [ 17 | { 18 | "type": "text", 19 | "value": "Header only" 20 | } 21 | ], 22 | "meta": { 23 | "types": [ 24 | "is-heading" 25 | ] 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /test/fixtures/sections/header.md: -------------------------------------------------------------------------------- 1 | # Header only -------------------------------------------------------------------------------- /test/fixtures/sections/headerimage.json: -------------------------------------------------------------------------------- 1 | { 2 | "intro": "Header and one image", 3 | "image": "./helix_logo.png", 4 | "title": "Header and one image", 5 | "meta": { 6 | "types": [ 7 | "has-image", 8 | "has-heading", 9 | "nb-image-1", 10 | "nb-heading-1", 11 | "is-heading-image", 12 | "is-heading" 13 | ] 14 | }, 15 | "type": "root", 16 | "children": [ 17 | { 18 | "type": "heading", 19 | "depth": 1, 20 | "children": [ 21 | { 22 | "type": "text", 23 | "value": "Header and one image" 24 | } 25 | ], 26 | "meta": { 27 | "types": [ 28 | "is-heading" 29 | ] 30 | } 31 | }, 32 | { 33 | "type": "paragraph", 34 | "children": [ 35 | { 36 | "type": "image", 37 | "title": null, 38 | "url": "./helix_logo.png", 39 | "alt": "helix-logo" 40 | } 41 | ], 42 | "meta": { 43 | "types": [ 44 | "has-image" 45 | ] 46 | } 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerimage.md: -------------------------------------------------------------------------------- 1 | # Header and one image 2 | 3 | ![helix-logo](./helix_logo.png) 4 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerlist.md: -------------------------------------------------------------------------------- 1 | # Header and a list 2 | 3 | * list item 1 4 | * list item 2 5 | * list item 3 6 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerpara2images.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "./helix_logo.png", 3 | "intro": "This is a paragraph.", 4 | "title": "Header, a paragraph and one image", 5 | "meta": { 6 | "types": [ 7 | "has-image", 8 | "has-text", 9 | "has-heading", 10 | "nb-image-2", 11 | "nb-text-1", 12 | "nb-heading-1", 13 | "is-image-heading-text", 14 | "is-image-heading", 15 | "is-image" 16 | ] 17 | }, 18 | "type": "root", 19 | "children": [ 20 | { 21 | "type": "heading", 22 | "depth": 1, 23 | "children": [ 24 | { 25 | "type": "text", 26 | "value": "Header, a paragraph and one image" 27 | } 28 | ], 29 | "meta": { 30 | "types": [ 31 | "is-heading" 32 | ] 33 | } 34 | }, 35 | { 36 | "type": "paragraph", 37 | "children": [ 38 | { 39 | "type": "text", 40 | "value": "This is a paragraph." 41 | } 42 | ], 43 | "meta": { 44 | "types": [ 45 | "is-text" 46 | ] 47 | } 48 | }, 49 | { 50 | "type": "paragraph", 51 | "children": [ 52 | { 53 | "type": "image", 54 | "title": null, 55 | "url": "./helix_logo.png", 56 | "alt": "helix-logo" 57 | }, 58 | { 59 | "type": "text", 60 | "value": "\n" 61 | }, 62 | { 63 | "type": "image", 64 | "title": null, 65 | "url": "./helix_logo.png", 66 | "alt": "helix-logo" 67 | } 68 | ], 69 | "meta": { 70 | "types": [ 71 | "has-image" 72 | ] 73 | } 74 | } 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerpara2images.md: -------------------------------------------------------------------------------- 1 | # Header, a paragraph and one image 2 | 3 | This is a paragraph. 4 | 5 | ![helix-logo](./helix_logo.png) 6 | ![helix-logo](./helix_logo.png) 7 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerparagraph.json: -------------------------------------------------------------------------------- 1 | { 2 | "intro": "This is a paragraph.", 3 | "title": "Header and one paragraph", 4 | "meta": { 5 | "types": [ 6 | "has-text", 7 | "has-heading", 8 | "nb-text-1", 9 | "nb-heading-1", 10 | "is-heading-text", 11 | "is-heading" 12 | ] 13 | }, 14 | "type": "root", 15 | "children": [ 16 | { 17 | "type": "heading", 18 | "depth": 1, 19 | "children": [ 20 | { 21 | "type": "text", 22 | "value": "Header and one paragraph" 23 | } 24 | ], 25 | "meta": { 26 | "types": [ 27 | "is-heading" 28 | ] 29 | } 30 | }, 31 | { 32 | "type": "paragraph", 33 | "children": [ 34 | { 35 | "type": "text", 36 | "value": "This is a paragraph." 37 | } 38 | ], 39 | "meta": { 40 | "types": [ 41 | "is-text" 42 | ] 43 | } 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerparagraph.md: -------------------------------------------------------------------------------- 1 | # Header and one paragraph 2 | 3 | This is a paragraph. -------------------------------------------------------------------------------- /test/fixtures/sections/headerparaimage.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "./helix_logo.png", 3 | "intro": "This is a paragraph.", 4 | "title": "Header, a paragraph and one image", 5 | "meta": { 6 | "types": [ 7 | "has-image", 8 | "has-text", 9 | "has-heading", 10 | "nb-image-1", 11 | "nb-text-1", 12 | "nb-heading-1", 13 | "is-heading-image-text", 14 | "is-heading-image", 15 | "is-heading" 16 | ] 17 | }, 18 | "type": "root", 19 | "children": [ 20 | { 21 | "type": "heading", 22 | "depth": 1, 23 | "children": [ 24 | { 25 | "type": "text", 26 | "value": "Header, a paragraph and one image" 27 | } 28 | ], 29 | "meta": { 30 | "types": [ 31 | "is-heading" 32 | ] 33 | } 34 | }, 35 | { 36 | "type": "paragraph", 37 | "children": [ 38 | { 39 | "type": "text", 40 | "value": "This is a paragraph." 41 | } 42 | ], 43 | "meta": { 44 | "types": [ 45 | "is-text" 46 | ] 47 | } 48 | }, 49 | { 50 | "type": "paragraph", 51 | "children": [ 52 | { 53 | "type": "image", 54 | "title": null, 55 | "url": "./helix_logo.png", 56 | "alt": "helix-logo" 57 | } 58 | ], 59 | "meta": { 60 | "types": [ 61 | "has-image" 62 | ] 63 | } 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /test/fixtures/sections/headerparaimage.md: -------------------------------------------------------------------------------- 1 | # Header, a paragraph and one image 2 | 3 | This is a paragraph. 4 | 5 | ![helix-logo](./helix_logo.png) 6 | -------------------------------------------------------------------------------- /test/fixtures/sections/herosection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [ 4 | { 5 | "type": "section", 6 | "children": [ 7 | { 8 | "type": "paragraph", 9 | "children": [ 10 | { 11 | "type": "image", 12 | "title": null, 13 | "url": "./helix_logo.png", 14 | "alt": "helix-logo" 15 | } 16 | ], 17 | "meta": { 18 | "types": [ 19 | "has-image" 20 | ] 21 | } 22 | } 23 | ], 24 | "meta": { 25 | "types": [ 26 | "has-image", 27 | "nb-image-1", 28 | "has-only-image" 29 | ] 30 | }, 31 | "title": "", 32 | "intro": "", 33 | "image": "./helix_logo.png" 34 | }, 35 | { 36 | "type": "section", 37 | "children": [ 38 | { 39 | "type": "heading", 40 | "depth": 1, 41 | "children": [ 42 | { 43 | "type": "text", 44 | "value": "Header and one image" 45 | } 46 | ], 47 | "meta": { 48 | "types": [ 49 | "is-heading" 50 | ] 51 | } 52 | } 53 | ], 54 | "meta": { 55 | "types": [ 56 | "has-heading", 57 | "nb-heading-1", 58 | "has-only-heading" 59 | ] 60 | }, 61 | "title": "Header and one image", 62 | "intro": "Header and one image" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /test/fixtures/sections/herosection.md: -------------------------------------------------------------------------------- 1 | ![helix-logo](./helix_logo.png) 2 | 3 | --- 4 | 5 | # Header and one image -------------------------------------------------------------------------------- /test/fixtures/sections/paragraph.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "This is only a paragraph.", 3 | "intro": "This is only a paragraph.", 4 | "meta": { 5 | "types": [ 6 | "has-text", 7 | "nb-text-1", 8 | "has-only-text" 9 | ] 10 | }, 11 | "type": "root", 12 | "children": [ 13 | { 14 | "type": "paragraph", 15 | "children": [ 16 | { 17 | "type": "text", 18 | "value": "This is only a paragraph." 19 | } 20 | ], 21 | "meta": { 22 | "types": [ 23 | "is-text" 24 | ] 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /test/fixtures/sections/paragraph.md: -------------------------------------------------------------------------------- 1 | This is only a paragraph. -------------------------------------------------------------------------------- /test/fixtures/sections/paragraphwithlink.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "This is a paragraph with a link!", 3 | "intro": "This is a paragraph with a link!", 4 | "meta": { 5 | "types": [ 6 | "has-text", 7 | "has-link", 8 | "nb-text-2", 9 | "nb-link-1", 10 | "is-text-link", 11 | "is-text" 12 | ] 13 | }, 14 | "type": "root", 15 | "children": [ 16 | { 17 | "type": "paragraph", 18 | "children": [ 19 | { 20 | "type": "text", 21 | "value": "This is a paragraph with a " 22 | }, 23 | { 24 | "type": "link", 25 | "title": null, 26 | "url": "/index.html", 27 | "children": [ 28 | { 29 | "type": "text", 30 | "value": "link" 31 | } 32 | ] 33 | }, 34 | { 35 | "type": "text", 36 | "value": "!" 37 | } 38 | ], 39 | "meta": { 40 | "types": [ 41 | "is-text", 42 | "has-link" 43 | ] 44 | } 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /test/fixtures/sections/paragraphwithlink.md: -------------------------------------------------------------------------------- 1 | This is a paragraph with a [link](/index.html)! -------------------------------------------------------------------------------- /test/markdown-utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /* eslint-env mocha */ 13 | import path from 'path'; 14 | import assert from 'assert'; 15 | import { readFile } from 'fs/promises'; 16 | 17 | export async function assertMatchDir(dir, name, cb) { 18 | const expected = JSON.parse(await readFile(path.resolve(__testdir, 'fixtures', dir, `${name}.json`), 'utf-8')); 19 | 20 | const md = await readFile(path.resolve(__testdir, 'fixtures', dir, `${name}.md`), 'utf-8'); 21 | const actual = await cb(md); 22 | 23 | return assert.deepEqual(actual, expected); 24 | } 25 | 26 | export async function assertMatch(name, cb) { 27 | await assertMatchDir('mdasts', name, cb); 28 | } 29 | -------------------------------------------------------------------------------- /test/pipeline-request.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /* eslint-env mocha */ 14 | import assert from 'assert'; 15 | import { PipelineRequest } from '../src/index.js'; 16 | 17 | describe('PipelineRequest Tests', () => { 18 | it('can be initialized with headers map', () => { 19 | const headers = new Map(); 20 | const req = new PipelineRequest(new URL('https://html-pipeline.com/'), { 21 | headers, 22 | }); 23 | assert.strictEqual(req.headers, headers); 24 | }); 25 | 26 | it('can be initialized with headers object', () => { 27 | const req = new PipelineRequest(new URL('https://html-pipeline.com/'), { 28 | headers: { 29 | 'content-type': 'application/json', 30 | }, 31 | }); 32 | assert.strictEqual(req.headers.get('content-type'), 'application/json'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/pipeline-response.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /* eslint-env mocha */ 14 | import assert from 'assert'; 15 | import { PipelineResponse } from '../src/index.js'; 16 | 17 | describe('PipelineResponse Tests', () => { 18 | it('can be initialized with headers map', () => { 19 | const headers = new Map(); 20 | const res = new PipelineResponse('', { 21 | headers, 22 | }); 23 | assert.strictEqual(res.headers, headers); 24 | }); 25 | 26 | it('can be initialized with headers object', () => { 27 | const res = new PipelineResponse('', { 28 | headers: { 29 | 'content-type': 'application/json', 30 | }, 31 | }); 32 | assert.strictEqual(res.headers.get('content-type'), 'application/json'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/setup-env.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | import { resolve } from 'path'; 13 | import { fileURLToPath } from 'url'; 14 | 15 | // eslint-disable-next-line no-console 16 | console.log('Forcing HTTP/1.1 for Helix-Fetch'); 17 | process.env.HELIX_FETCH_FORCE_HTTP1 = 'true'; 18 | process.env.HELIX_PIPELINE_FORCE_HTTP1 = 'true'; 19 | 20 | // eslint-disable-next-line no-underscore-dangle 21 | global.__rootdir = resolve(fileURLToPath(import.meta.url), '..', '..'); 22 | // eslint-disable-next-line no-underscore-dangle 23 | global.__testdir = resolve(fileURLToPath(import.meta.url), '..'); 24 | -------------------------------------------------------------------------------- /test/steps/fetch-content.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /* eslint-env mocha */ 13 | import assert from 'assert'; 14 | import fetchContent from '../../src/steps/fetch-content.js'; 15 | import { StaticS3Loader } from '../StaticS3Loader.js'; 16 | 17 | describe('Fetch Content', () => { 18 | it('throws error on generic error', async () => { 19 | /** @type PipelineState */ 20 | const state = { 21 | log: console, 22 | contentBusId: 'foo-id', 23 | partition: 'live', 24 | info: { 25 | resourcePath: '/index.md', 26 | }, 27 | content: {}, 28 | s3Loader: new StaticS3Loader() 29 | .reply('helix-content-bus', 'foo-id/live/index.md', { 30 | status: 500, 31 | body: '', 32 | headers: new Map(), 33 | }), 34 | }; 35 | /** @type PipelineResponse */ 36 | const res = {}; 37 | 38 | await fetchContent(state, {}, res); 39 | assert.strictEqual(res.status, 502); 40 | assert.strictEqual(res.error, 'failed to load /index.md from undefined-bus: 500'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/steps/init-config.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /* eslint-env mocha */ 13 | import assert from 'assert'; 14 | import { 15 | PipelineRequest, 16 | PipelineResponse, 17 | PipelineState, 18 | } from '../../src/index.js'; 19 | import initConfig from '../../src/steps/init-config.js'; 20 | 21 | describe('Init Config', () => { 22 | it('computes host and routes correctly', async () => { 23 | const state = new PipelineState({ 24 | ref: 'main', 25 | log: console, 26 | partition: 'live', 27 | org: 'org', 28 | site: 'site', 29 | config: { 30 | contentBusId: 'foo-id', 31 | owner: 'test-owner', 32 | repo: 'test-repo', 33 | cdn: { 34 | prod: { 35 | host: 'www.adobe.com', 36 | }, 37 | preview: { 38 | host: '$ref--$repo--$owner.my.page', 39 | }, 40 | live: { 41 | host: '$ref--$site--$org.my.live', 42 | }, 43 | }, 44 | }, 45 | }); 46 | const req = new PipelineRequest('https://localhost'); 47 | const res = new PipelineResponse(); 48 | await initConfig(state, req, res); 49 | assert.strictEqual(state.previewHost, 'main--test-repo--test-owner.my.page'); 50 | assert.strictEqual(state.liveHost, 'main--site--org.my.live'); 51 | assert.strictEqual(state.prodHost, 'www.adobe.com'); 52 | }); 53 | 54 | it('throws error if property is missing', async () => { 55 | assert.throws(() => new PipelineState({ config: {} }), Error('org required')); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/steps/parse-markdown.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /* eslint-env mocha */ 13 | import parse from '../../src/steps/parse-markdown.js'; 14 | import { assertMatch } from '../markdown-utils.js'; 15 | 16 | function callback(data) { 17 | /** @type PipelineState */ 18 | const state = { log: console, content: { data } }; 19 | parse(state); 20 | return state.content.mdast; 21 | } 22 | 23 | describe('Test Markdown Parsing', () => { 24 | it('Parses simple markdown', async () => { 25 | await assertMatch('simple', callback); 26 | }); 27 | 28 | it('Parses example markdown', async () => { 29 | await assertMatch('example', callback); 30 | }); 31 | 32 | it('Parses headings correctly', async () => { 33 | await assertMatch('headings', callback); 34 | }); 35 | 36 | it('Parses HTML in Markdown', async () => { 37 | await assertMatch('forms', callback); 38 | }); 39 | 40 | it('Does not get confused by grayscale', async () => { 41 | await assertMatch('grayscale', callback); 42 | }); 43 | 44 | it('Does not get confused by escaped links', async () => { 45 | await assertMatch('simple-links', callback); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/steps/stringify-response.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | /* eslint-env mocha */ 13 | import assert from 'assert'; 14 | import stringify from '../../src/steps/stringify-response.js'; 15 | 16 | describe('Testing stringify pipeline step', () => { 17 | /** @type PipelineState */ 18 | const state = { log: console }; 19 | 20 | it('response body takes precedence over document can be transformed', () => { 21 | /** @type PipelineResponse */ 22 | const response = { 23 | body: 'foobar', 24 | }; 25 | stringify(state, undefined, response); 26 | assert.strictEqual(response.body, 'foobar'); 27 | }); 28 | 29 | it('throws error if neither body or document is present in the response', () => { 30 | assert.throws(() => stringify(state, undefined, {}), Error('no response document')); 31 | }); 32 | 33 | it('throws error if document is not serializable', () => { 34 | assert.throws(() => stringify(state, undefined, { 35 | document: {}, 36 | }), Error('Expected node, not `[object Object]`')); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/utils/id-slugger-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Adobe. All rights reserved. 3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. You may obtain a copy 5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software distributed under 8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | * OF ANY KIND, either express or implied. See the License for the specific language 10 | * governing permissions and limitations under the License. 11 | */ 12 | 13 | /* eslint-env mocha */ 14 | 15 | import assert from 'assert'; 16 | import { IDSlugger } from '../../src/utils/id-slugger.js'; 17 | 18 | describe('IDSlugger Test', () => { 19 | it('generates correct ids', () => { 20 | const s = new IDSlugger(); 21 | 22 | assert.strictEqual(s.slug('hello, world'), 'hello-world'); 23 | assert.strictEqual(s.slug('hello. world'), 'hello-world-1'); 24 | assert.strictEqual(s.slug('hello-world-1'), 'hello-world-1-1'); 25 | 26 | assert.strictEqual(s.slug('1. Goals'), 'goals'); 27 | assert.strictEqual(s.slug('2. Goals'), 'goals-1'); 28 | }); 29 | }); 30 | --------------------------------------------------------------------------------