Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markdownz: replace remark with markdownz #5352

Merged
merged 21 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/arch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
- [ADR 53: Logged-In User Homepage](adr-53.md)
- [ADR 54: app-root](adr-54.md)
- [ADR 55: lib-user](adr-55.md)
- [ADR 56: Use markdownz to parse markdown](adr-56.md)
21 changes: 21 additions & 0 deletions docs/arch/adr-56.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ADR 56: use markdownz to parse markdown

## Context
[ADR 11](./adr-11.md) introduced Remark, to parse markdown in our custom `Markdownz` component. Replacing `markdown-it` with `remark` changed [some features of the Zooniverse markdown parser](./adr-11.md#consequences). Since that decision:
- `remark-react` is now deprecated. It's now recommended to parse markdown to HTML, then use `rehype-react` to map that HTML to a React component tree.
- `markdownz` now sanitises its output HTML with DOMPurify ([v8.3.3](https://github.com/zooniverse/markdownz/releases/tag/v8.3.3)), and exports a `useMarkdownz` hook ([v8.5.0](https://github.com/zooniverse/markdownz/releases/tag/v8.5.0)), removing the security concerns around `dangerouslySetInnerHTML` in ADR 11.
- With ([v9.0.0](https://github.com/zooniverse/markdownz/releases/tag/v9.0.0)), the `Markdown` component, exported by `markdownz`, uses `rehype-react` to render HTML as a React component tree.
- there has been confusion among project teams about how to write Zooniverse-flavoured markdown for their projects. Markdown that's written and previewed in the project builder needs changes in order to work in the new parser.

## Decision
[PR #5352](https://github.com/zooniverse/front-end-monorepo/pull/5352) updates `@zooniverse/react-components/Markdownz` to parse Zooniverse-flavoured markdown with `markdownz`, then map the output HTML to Zooniverse Grommet components with `react-rehype`.

## Consequences
- Markdown is parsed with `markdown-it`, not Remark.
- Links must be prepended with `+tab+` in order to open in a new tab/window.
- Custom table-of-contents is supported with `[[toc]]`.
- Fragment links to page headings are supported by default (eg. `/about/faq#2.-objects-in-image-margins`.)
- Markdown images with audio and video URLs are automatically converted to `<audio>` and `<video>` tags.

## Status
Accepted
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
"nyc": "~15.1.0",
"snazzy": "~9.0.0"
},
"resolutions": {
"**/trim": "~1.0"
},
"scripts": {
"bootstrap": "./bin/bootstrap.sh",
"bootstrap:es6": "./bin/bootstrap:es6.sh",
Expand Down
4 changes: 4 additions & 0 deletions packages/app-content-pages/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ const nextConfig = {
alias: {
...config.resolve.alias,
...webpackConfig.resolve.alias
},
fallback: {
...config.resolve.fallback,
...webpackConfig.resolve.fallback
}
}
return config
Expand Down
2 changes: 1 addition & 1 deletion packages/app-content-pages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@zooniverse/async-states": "~0.0.1",
"@zooniverse/grommet-theme": "~3.2.0",
"@zooniverse/panoptes-js": "~0.5.0",
"@zooniverse/react-components": "~1.7.0",
"@zooniverse/react-components": "~1.8.0",
"contentful": "~10.6.0",
"dotenv": "~16.3.0",
"dotenv-webpack": "~8.0.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/app-content-pages/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ module.exports = {
'@helpers': path.resolve(__dirname, 'src/helpers'),
'@screens': path.resolve(__dirname, 'src/screens'),
'@shared': path.resolve(__dirname, 'src/shared')
},
fallback: {
fs: false
}
}
}
4 changes: 4 additions & 0 deletions packages/app-project/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ const nextConfig = {
alias: {
...config.resolve.alias,
...webpackConfig.resolve.alias
},
fallback: {
...config.resolve.fallback,
...webpackConfig.resolve.fallback
}
}
return config
Expand Down
2 changes: 1 addition & 1 deletion packages/app-project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@zooniverse/classifier": "^0.0.1",
"@zooniverse/grommet-theme": "~3.2.0",
"@zooniverse/panoptes-js": "~0.5.0",
"@zooniverse/react-components": "~1.7.0",
"@zooniverse/react-components": "~1.8.0",
"cookie": "~0.5.0",
"d3": "~6.7.0",
"engine.io-client": "~6.5.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/app-project/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ module.exports = {
'@stores': path.resolve(__dirname, 'stores'),
'@test': path.resolve(__dirname, 'test'),
'sentry.edge.config.js': path.resolve(__dirname, 'sentry.edge.config.js')
},
fallback: {
fs: false
}
}
}
6 changes: 3 additions & 3 deletions packages/app-root/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"type": "module",
"dependencies": {
"@zooniverse/async-states": "~0.0.1",
"@zooniverse/grommet-theme": "~3.1.1",
"@zooniverse/panoptes-js": "~0.4.1",
"@zooniverse/react-components": "~1.6.1",
"@zooniverse/grommet-theme": "~3.2.0",
"@zooniverse/panoptes-js": "~0.5.0",
"@zooniverse/react-components": "~1.8.0",
"express": "~4.18.2",
"grommet": "~2.34.0",
"grommet-icons": "~4.11.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/lib-classifier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"@wojtekmaj/enzyme-adapter-react-17": "~0.8.0",
"@zooniverse/grommet-theme": "~3.2.0",
"@zooniverse/panoptes-js": "~0.5.0",
"@zooniverse/react-components": "~1.7.0",
"@zooniverse/react-components": "~1.8.0",
"@zooniverse/standard": "~2.0.0",
"babel-loader": "~9.1.0",
"babel-plugin-module-resolver": "~5.0.0",
Expand All @@ -105,6 +105,7 @@
"mst-middlewares": "~5.2.0",
"nock": "~13.3.0",
"panoptes-client": "~5.5.1",
"path-browserify": "~1.0.1",
"polished": "~4.2.2",
"process": "~0.11.10",
"prop-types": "^15.8.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function formatValue(value) {
return <Anchor target='_blank' rel='nofollow noopener noreferrer' href={value}>{value}</Anchor>
}
if (stringValue) {
return <Markdownz options={{ forceInline: true }}>{stringValue}</Markdownz>
return <Markdownz inline>{stringValue}</Markdownz>
}

if (value === null) {
Expand Down
5 changes: 4 additions & 1 deletion packages/lib-classifier/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ module.exports = {
'@viewers': path.resolve(__dirname, 'src/components/Classifier/components/SubjectViewer')
},
fallback: {
url: false,
fs: false,
// for markdown-it plugins
path: require.resolve("path-browserify"),
process: false,
}
},
module: {
Expand Down
62 changes: 0 additions & 62 deletions packages/lib-react-components/.storybook/lib/example.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,3 @@
|content|markdown|rendered|
|---------|----------|-------------|
|emoji|`:smile: :-)`|:smile: :-)|
|bold|`**bold**`|**bold**|
|italicized|`_italicized_`|_italicized_|
|anchor|`[link](https://www.zooniverse.org/)`|[link](https://www.zooniverse.org/)|
|relative link|`[relative-link](/relative)`|[relative-link](/relative)|
|image|`![imagealttext](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg)`|![imagealttext](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg)|
|image resized like TESS|`![like TESS](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x)`|![like TESS](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x)|
|image resized in alt text|`![imagealttext =100x100](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg)`|![imagealttext =100x100](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg)|
|image resized in url|`![imagealttext](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x100)`|![imagealttext](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x100)|
|image with equals sign in the alt text|`![A blackboard showing the expression 2x2=4](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x100)`|![A blackboard showing the expression 2x2=4](https://panoptes-uploads.zooniverse.org/production/subject_location/66094a64-8823-4314-8ef4-1ee228e49470.jpeg =100x100)|
|video (using image syntax)|`![alt](https://static.zooniverse.org/www.zooniverse.org/assets/home-video.mp4)`|![alt](https://static.zooniverse.org/www.zooniverse.org/assets/home-video.mp4)|
|audio (using image syntax)|`![alt](https://panoptes-uploads.zooniverse.org/production/subject_location/1c93591f-5d7e-4129-a6da-a65419b88048.mpga)`|![alt](https://panoptes-uploads.zooniverse.org/production/subject_location/1c93591f-5d7e-4129-a6da-a65419b88048.mpga)|
|superscript|`super^script^`|super^script^|
|subscript|`sub~script~`|sub~script~|
|Typed Email Address|`[email protected]`|[email protected]|
|Zooniverse user mention|`@srallen @team`|@srallen @team|
|Zooniverse Talk Tag mention|`#tiger`|#tiger|
|Zooniverse Subject mention (only works in project context)|`^S1234`|^S1234|
|Link inside a link|`[foo @username bar](http://example.com)`|[foo @username bar](http://example.com)|

---

> blockquote

Unordered list:
- item one
- item two
- item three

Ordered list:
1. item one
2. item two
3. item three

# header 1

## header 2

### header 3

#### header 4

##### header 5

###### header 6

## Table of Contents

## News

## Links

Here is a footnote reference,[^1] and another.[^longnote]

[^1]: Here is the footnote.

[^longnote]: Here's one with multiple blocks.

Another note.

## Testing for vulnerabilities

Taken from https://shubs.io/exploiting-markdown-syntax-and-telescope-persistent-xss-through-markdown-cve-2014-5144/
Expand Down
8 changes: 5 additions & 3 deletions packages/lib-react-components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [1.8.0] 2023-10-30

### Changed
- `Markdownz`: replace `remark` with `markdownz` and `rehype`.

## [1.7.0] 2023-10-26
### Changed
- build with Node 20.

### Fixed
- export `package.json` for build tools.

## [1.6.4] 2023-10-05

### Fixed
Expand Down
16 changes: 3 additions & 13 deletions packages/lib-react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Zooniverse React Components",
"license": "Apache-2.0",
"author": "Zooniverse <[email protected]> (https://www.zooniverse.org/)",
"version": "1.7.0",
"version": "1.8.0",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"exports": {
Expand Down Expand Up @@ -46,21 +46,13 @@
"cuid": "~3.0.0",
"formik": "~2.4.0",
"i18next": "~23.6.0",
"markdownz": "~9.1.3",
"mime": "~3.0.0",
"polished": "~4.2.2",
"prop-types": "~15.8.1",
"react-i18next": "~13.3.0",
"react-resize-detector": "~9.1.0",
"react-rnd": "10.4.1",
"remark": "~12.0.1",
"remark-breaks": "~2.0.2",
"remark-emoji": "~2.0.2",
"remark-external-links": "~3.1.1",
"remark-footnotes": "2.0.0",
"remark-react": "~8.0.0",
"remark-sub-super": "~1.0.16",
"remark-toc": "~5.1.1",
"unist-util-visit": "~1.4.0"
"react-rnd": "10.4.1"
},
"peerDependencies": {
"@zooniverse/grommet-theme": "3.x.x",
Expand Down Expand Up @@ -101,8 +93,6 @@
"mocha": "~10.2.0",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"rehype-stringify": "~8.0.0",
"remark-rehype": "~8.1.0",
"sinon": "~17.0.0",
"sinon-chai": "~3.7.0",
"snazzy": "~9.0.0",
Expand Down
Loading