Skip to content

Commit c1d3cab

Browse files
authored
Merge pull request #476 from marp-team/enable-html-enum
[v3] `markdown.marp.html` setting to control which HTML elements are rendered
2 parents 9e98433 + b85816c commit c1d3cab

File tree

8 files changed

+142
-28
lines changed

8 files changed

+142
-28
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
- Upgrade Marp Core to [v4.0.1](https://github.com/marp-team/marp-core/releases/v4.0.1) ([#472](https://github.com/marp-team/marp-vscode/pull/472), [#474](https://github.com/marp-team/marp-vscode/pull/474))
1111
- Upgrade Marp CLI to [v4.0.4](https://github.com/marp-team/marp-cli/releases/v4.0.4) ([#473](https://github.com/marp-team/marp-vscode/pull/473), [#474](https://github.com/marp-team/marp-vscode/pull/474))
1212

13+
### Added
14+
15+
- `markdown.marp.html` setting to control rendering HTML within Marp Markdown ([#476](https://github.com/marp-team/marp-vscode/pull/476))
16+
17+
### Deprecated
18+
19+
- `markdown.marp.enableHtml` setting ([#476](https://github.com/marp-team/marp-vscode/pull/476))
20+
1321
### Changed
1422

1523
- Upgrade development Node.js and dependent packages to the latest version ([#474](https://github.com/marp-team/marp-vscode/pull/474))

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,16 @@ Features may be restricted are marked by the shield icon 🛡️ in this documen
205205

206206
[workspace trust]: https://code.visualstudio.com/docs/editor/workspace-trust
207207

208-
#### Enable HTML in Marp Markdown 🛡️
208+
#### HTML elements in Markdown 🛡️
209209

210-
You can enable previsualization of HTML code within Marp Markdown with the `markdown.marp.enableHtml` option.
210+
In the trusted workspace, if Marp Markdown was included HTML elements, [only selectivity HTML elements by Marp](https://github.com/marp-team/marp-core/blob/main/src/html/allowlist.ts) can render by default. You can control which HTML elements will be rendered by setting the `markdown.marp.html` option,
211211

212-
It could allow script injection from untrusted Markdown files. Thus, this feature is disabled as a default and will be _always ignored in the untrusted workspace_. Use with caution.
212+
You can control which HTML elements will be rendered by setting the `markdown.marp.html` option. You can set it as `all` to allow all HTML elements, but could allow script injection from untrusted Markdown files. Use with caution.
213+
214+
In the untrusted workspace, HTML elements in Marp Markdown will be always ignored regardless of the selected option in `markdown.marp.html`.
215+
216+
> [!NOTE]
217+
> A legacy setting `markdown.marp.enableHtml` is deprecated since v2. Please use `markdown.marp.html` instead.
213218
214219
## Web extension
215220

package.json

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"supported": "limited",
5151
"description": "Workspace trust is required for exporting slide deck, and using themes configured in the workspace.",
5252
"restrictedConfigurations": [
53+
"markdown.marp.html",
5354
"markdown.marp.enableHtml",
5455
"markdown.marp.themes"
5556
]
@@ -119,10 +120,20 @@
119120
"default": "",
120121
"description": "Sets the custom path for Chrome or Chromium-based browser to export PDF, PPTX, and image. If it's empty, Marp will find out the installed Google Chrome / Chromium / Microsoft Edge."
121122
},
122-
"markdown.marp.enableHtml": {
123-
"type": "boolean",
124-
"default": false,
125-
"description": "Enables all HTML elements in Marp Markdown. This setting is working only in the trusted workspace."
123+
"markdown.marp.html": {
124+
"type": "string",
125+
"enum": [
126+
"off",
127+
"default",
128+
"all"
129+
],
130+
"markdownEnumDescriptions": [
131+
"Disable all HTML elements, including originally allowed HTML elements by Marp.",
132+
"Enable only selectively enabled HTML elements by Marp. _([See the list of HTML elements](https://github.com/marp-team/marp-core/blob/main/src/html/allowlist.ts))_",
133+
"Enable all HTML elements. This setting may become the slide rendering insecure."
134+
],
135+
"default": "default",
136+
"description": "Sets which HTML elements within Marp Markdown are enabled in rendered slides. If the workspace is not trusted, this setting treats as always \"off\"."
126137
},
127138
"markdown.marp.exportType": {
128139
"type": "string",
@@ -197,6 +208,12 @@
197208
"items": {
198209
"type": "string"
199210
}
211+
},
212+
"markdown.marp.enableHtml": {
213+
"type": "boolean",
214+
"default": false,
215+
"description": "Enables all HTML elements in Marp Markdown. This setting is working only in the trusted workspace.",
216+
"deprecationMessage": "The setting \"markdown.marp.enableHtml\" is deprecated. Please use \"markdown.marp.html\" instead."
200217
}
201218
}
202219
},

src/__mocks__/vscode.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const defaultConf: MockedConf = {
77
'markdown.marp.breaks': 'on',
88
'markdown.marp.chromePath': '',
99
'markdown.marp.enableHtml': false,
10+
'markdown.marp.html': 'default',
1011
'markdown.marp.exportType': 'pdf',
1112
'markdown.marp.outlineExtension': true,
1213
'markdown.marp.pdf.noteAnnotations': false,
@@ -227,7 +228,7 @@ export const window = {
227228
showQuickPick: jest.fn(),
228229
showSaveDialog: jest.fn(),
229230
showTextDocument: jest.fn(async () => ({})),
230-
showWarningMessage: jest.fn(),
231+
showWarningMessage: jest.fn(async () => undefined),
231232
withProgress: jest.fn(),
232233
}
233234

src/extension.test.ts

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Marp } from '@marp-team/marp-core'
55
import dedent from 'dedent'
66
import markdownIt from 'markdown-it'
77
import * as nodeFetch from 'node-fetch'
8-
import { Memento, Uri, commands, workspace, env } from 'vscode'
8+
import { Memento, Uri, commands, window, workspace, env } from 'vscode'
99

1010
jest.mock('node-fetch')
1111
jest.mock('vscode')
@@ -177,23 +177,37 @@ describe('#extendMarkdownIt', () => {
177177
})
178178
})
179179

180-
describe('markdown.marp.enableHtml', () => {
181-
it('does not render not allowed HTML elements when disabled', () => {
182-
setConfiguration({ 'markdown.marp.enableHtml': false })
180+
describe('markdown.marp.html', () => {
181+
it('does not render not allowed HTML elements when the setting is "off"', () => {
182+
setConfiguration({ 'markdown.marp.html': 'off' })
183183

184184
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
185185
expect(html).not.toContain('<script>console.log("Hi")</script>')
186186
})
187187

188-
it("allows Marp Core's allowed HTML elements even if disabled", () => {
189-
setConfiguration({ 'markdown.marp.enableHtml': false })
188+
it(`does not render Marp Core allowed HTML elements when the setting is "off"`, () => {
189+
setConfiguration({ 'markdown.marp.html': 'off' })
190+
191+
const html = md().render(marpMd('line<br>break'))
192+
expect(html).not.toContain('line<br />break')
193+
})
194+
195+
it('does not render not allowed HTML elements when the setting is "default"', () => {
196+
setConfiguration({ 'markdown.marp.html': 'default' })
197+
198+
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
199+
expect(html).not.toContain('<script>console.log("Hi")</script>')
200+
})
201+
202+
it(`allows Marp Core's allowed HTML elements even if the setting is "default"`, () => {
203+
setConfiguration({ 'markdown.marp.html': 'default' })
190204

191205
const html = md().render(marpMd('line<br>break'))
192206
expect(html).toContain('line<br />break')
193207
})
194208

195-
it('renders not allowed HTML elements when enabled', () => {
196-
setConfiguration({ 'markdown.marp.enableHtml': true })
209+
it('renders not allowed HTML elements when the setting is "all"', () => {
210+
setConfiguration({ 'markdown.marp.html': 'all' })
197211

198212
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
199213
expect(html).toContain('<script>console.log("Hi")</script>')
@@ -210,12 +224,51 @@ describe('#extendMarkdownIt', () => {
210224

211225
afterEach(() => isTrustedMock?.mockRestore())
212226

213-
it('does not render not allowed HTML elements even if enabled', () => {
214-
setConfiguration({ 'markdown.marp.enableHtml': true })
227+
it('does not render not allowed HTML elements even the setting is "all"', () => {
228+
setConfiguration({ 'markdown.marp.html': 'all' })
229+
230+
const br = md().render(marpMd('line<br>break'))
231+
expect(br).not.toContain('line<br />break')
232+
233+
const script = md().render(
234+
marpMd('<script>console.log("Hi")</script>'),
235+
)
236+
expect(script).not.toContain('<script>console.log("Hi")</script>')
237+
})
238+
})
239+
})
240+
241+
describe('[Deprecated] markdown.marp.enableHtml', () => {
242+
it('renders not allowed HTML elements when the value is true', () => {
243+
setConfiguration({ 'markdown.marp.enableHtml': true })
244+
245+
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
246+
expect(html).toContain('<script>console.log("Hi")</script>')
247+
})
215248

216-
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
217-
expect(html).not.toContain('<script>console.log("Hi")</script>')
249+
it('prefers explicit "markdown.marp.html" setting than "markdown.marp.enableHtml" setting', () => {
250+
setConfiguration({
251+
'markdown.marp.html': 'off',
252+
'markdown.marp.enableHtml': true,
218253
})
254+
255+
const html = md().render(marpMd('<script>console.log("Hi")</script>'))
256+
expect(html).not.toContain('<script>console.log("Hi")</script>')
257+
})
258+
259+
it('shows deprecation warning while rendering if "markdown.marp.html" is the default value and "markdown.marp.enableHtml" is enabled', () => {
260+
setConfiguration({
261+
'markdown.marp.html': 'default',
262+
'markdown.marp.enableHtml': true,
263+
})
264+
265+
md().render(marpMd('<script>console.log("Hi")</script>'))
266+
expect(window.showWarningMessage).toHaveBeenCalledWith(
267+
expect.stringContaining(
268+
'The setting "markdown.marp.enableHtml" is deprecated',
269+
),
270+
expect.anything(),
271+
)
219272
})
220273
})
221274

src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { detectMarpFromMarkdown, marpConfiguration } from './utils'
1717
const shouldRefreshConfs = [
1818
'markdown.marp.breaks',
1919
'markdown.marp.enableHtml',
20+
'markdown.marp.html',
2021
'markdown.marp.mathTypesetting',
2122
'markdown.marp.outlineExtension',
2223
'markdown.marp.themes',

src/option.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ describe('Option', () => {
168168

169169
afterEach(() => isTrustedMock?.mockRestore())
170170

171-
it('ignores potentially malicious options', async () => {
172-
setConfiguration({ 'markdown.marp.enableHtml': true })
173-
expect((await subject({ uri: untitledUri })).html).toBeUndefined()
171+
it('disallows potentially malicious options', async () => {
172+
setConfiguration({ 'markdown.marp.html': 'all' })
173+
expect((await subject({ uri: untitledUri })).html).toBe(false)
174174
})
175175
})
176176
})

src/option.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import path from 'node:path'
33
import { MarpOptions } from '@marp-team/marp-core'
44
import { Options } from 'markdown-it'
55
import { nanoid } from 'nanoid'
6-
import { TextDocument, Uri, workspace } from 'vscode'
6+
import { TextDocument, Uri, window, workspace } from 'vscode'
7+
import openExtensionSettings from './commands/open-extension-settings'
78
import themes, { ThemeType } from './themes'
89
import {
910
marpConfiguration,
@@ -30,8 +31,22 @@ const breaks = (inheritedValue: boolean): boolean => {
3031
}
3132
}
3233

33-
const enableHtml = () =>
34-
marpConfiguration().get<boolean>('enableHtml') && workspace.isTrusted
34+
const html = () => {
35+
if (workspace.isTrusted) {
36+
const htmlConf = marpConfiguration().get<string>('html')
37+
38+
if (htmlConf === 'all') return { value: true }
39+
if (htmlConf === 'off') return { value: false }
40+
41+
// Legacy configuration compatibility
42+
const legacyConf = marpConfiguration().get<boolean>('enableHtml')
43+
if (legacyConf) return { value: true, legacy: true }
44+
45+
return { value: undefined }
46+
} else {
47+
return { value: false }
48+
}
49+
}
3550

3651
const math = () => {
3752
const conf = mathTypesettingConfiguration()
@@ -55,10 +70,24 @@ export const marpCoreOptionForPreview = (
5570
baseOption: Options & MarpOptions,
5671
): MarpOptions => {
5772
if (!cachedPreviewOption) {
73+
const htmlOption = html()
74+
75+
if (htmlOption.legacy) {
76+
// Show warning for legacy configuration
77+
window
78+
.showWarningMessage(
79+
'The setting "markdown.marp.enableHtml" is deprecated. Please use "markdown.marp.html" instead. Please review your settings JSON to make silence this warning.',
80+
'Open Extension Settings',
81+
)
82+
.then((selected) => {
83+
if (selected) void openExtensionSettings()
84+
})
85+
}
86+
5887
cachedPreviewOption = {
5988
container: { tag: 'div', id: '__marp-vscode' },
6089
slideContainer: { tag: 'div', 'data-marp-vscode-slide-wrapper': '' },
61-
html: enableHtml() || undefined,
90+
html: htmlOption.value,
6291
inlineSVG: {
6392
backdropSelector: false,
6493
},
@@ -87,7 +116,7 @@ export const marpCoreOptionForCLI = async (
87116
allowLocalFiles,
88117
pdfNotes,
89118
pdfOutlines: pdfOutlines(),
90-
html: enableHtml() || undefined,
119+
html: html().value,
91120
options: {
92121
markdown: {
93122
breaks: breaks(!!confMdPreview.get<boolean>('breaks')),

0 commit comments

Comments
 (0)