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

Mark well-known magic comments in linter and formatter as parsed #199

Merged
merged 3 commits into from
Oct 10, 2019
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Changed

- Ignore well-known magic comments in collected comments ([#191](https://github.com/marp-team/marpit/issues/191), [#199](https://github.com/marp-team/marpit/pull/199))
- Upgrade dependent packages to the latest version ([#196](https://github.com/marp-team/marpit/pull/196))

## v1.4.0 - 2019-09-12
Expand Down
28 changes: 25 additions & 3 deletions src/markdown/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ const commentMatcher = /<!--+\s*([\s\S]*?)\s*--+>/
const commentMatcherOpening = /^<!--/
const commentMatcherClosing = /-->/

const magicCommentMatchers = [
// Prettier
/^prettier-ignore(-(start|end))?$/,

// markdownlint
/^markdownlint-((disable|enable).*|capture|restore)$/,

// remark-lint (remark-message-control)
/^lint (disable|enable|ignore).*$/,
]

export function markAsParsed(token, kind) {
token.meta = token.meta || {}
token.meta.marpitCommentParsed = kind
}

/**
* Marpit comment plugin.
*
Expand All @@ -19,9 +35,15 @@ function comment(md) {
const parse = (token, content) => {
const parsed = yaml(content, !!md.marpit.options.looseYAML)

token.meta = {
...(token.meta || {}),
marpitParsedDirectives: parsed === false ? {} : parsed,
token.meta = token.meta || {}
token.meta.marpitParsedDirectives = parsed === false ? {} : parsed

// Mark well-known magic comments as parsed comment
for (const magicCommentMatcher of magicCommentMatchers) {
if (magicCommentMatcher.test(content.trim())) {
markAsParsed(token, 'well-known-magic-comment')
break
}
}
}

Expand Down
30 changes: 16 additions & 14 deletions src/markdown/directives/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
import MarkdownItFrontMatter from 'markdown-it-front-matter'
import yaml from './yaml'
import * as directives from './directives'
import { markAsParsed } from '../comment'
import marpitPlugin from '../marpit_plugin'

const isComment = token =>
const isDirectiveComment = token =>
token.type === 'marpit_comment' && token.meta.marpitParsedDirectives

const markAsParsed = token => {
token.meta = token.meta || {}
token.meta.marpitCommentParsed = 'directive'
}

/**
* Parse Marpit directives and store result to the slide token meta.
*
Expand Down Expand Up @@ -101,14 +97,17 @@ function parse(md, opts = {}) {

for (const token of state.tokens) {
if (
isComment(token) &&
isDirectiveComment(token) &&
applyDirectives(token.meta.marpitParsedDirectives)
) {
markAsParsed(token)
markAsParsed(token, 'directive')
} else if (token.type === 'inline') {
for (const t of token.children) {
if (isComment(t) && applyDirectives(t.meta.marpitParsedDirectives))
markAsParsed(t)
if (
isDirectiveComment(t) &&
applyDirectives(t.meta.marpitParsedDirectives)
)
markAsParsed(t, 'directive')
}
}
}
Expand Down Expand Up @@ -190,14 +189,17 @@ function parse(md, opts = {}) {

cursor.spot = {}
} else if (
isComment(token) &&
isDirectiveComment(token) &&
applyDirectives(token.meta.marpitParsedDirectives)
) {
markAsParsed(token)
markAsParsed(token, 'directive')
} else if (token.type === 'inline') {
for (const t of token.children) {
if (isComment(t) && applyDirectives(t.meta.marpitParsedDirectives))
markAsParsed(t)
if (
isDirectiveComment(t) &&
applyDirectives(t.meta.marpitParsedDirectives)
)
markAsParsed(t, 'directive')
}
}
}
Expand Down
127 changes: 89 additions & 38 deletions test/markdown/collect.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dedent from 'dedent'
import MarkdownIt from 'markdown-it'
import applyDirectives from '../../src/markdown/directives/apply'
import collect from '../../src/markdown/collect'
import comment from '../../src/markdown/comment'
import comment, { markAsParsed } from '../../src/markdown/comment'
import inlineSVG from '../../src/markdown/inline_svg'
import parseDirectives from '../../src/markdown/directives/parse'
import slide from '../../src/markdown/slide'
Expand Down Expand Up @@ -109,46 +109,97 @@ describe('Marpit collect plugin', () => {
expect(lastComments[3]).toStrictEqual(['inline comment'])
})

context(
'when comment token is marked marpitCommentParsed meta in other plugin',
() => {
it('ignores collecting comment', () => {
const marpit = marpitStub()

md(marpit)
.use(mdIt => {
mdIt.core.ruler.before(
'marpit_slide',
'marpit_test_inject',
state => {
const markParsed = token => {
token.meta = {
...(token.meta || {}),
marpitCommentParsed: 'test',
}
}
context('when comment token is marked as parsed by #markAsParsed', () => {
it('ignores collecting comment', () => {
const marpit = marpitStub()

for (const token of state.tokens) {
if (token.content === 'This is comment') {
markParsed(token)
} else if (token.type === 'inline') {
for (const t of token.children)
if (t.content === 'inline comment') markParsed(t)
}
md(marpit)
.use(mdIt => {
mdIt.core.ruler.before(
'marpit_slide',
'marpit_test_inject',
state => {
for (const token of state.tokens) {
if (token.content === 'This is comment') {
markAsParsed(token, 'test')
} else if (token.type === 'inline') {
for (const t of token.children)
if (t.content === 'inline comment') markAsParsed(t, 'test')
}
}
)
})
.render(text)

const { lastComments } = marpit

expect(lastComments[0]).toHaveLength(1)
expect(lastComments[0]).not.toContain('This is comment')
expect(lastComments[3]).toHaveLength(0)
})
}
)
}
)
})
.render(text)

const { lastComments } = marpit

expect(lastComments[0]).toHaveLength(1)
expect(lastComments[0]).not.toContain('This is comment')
expect(lastComments[3]).toHaveLength(0)
})

it('ignores comments for well-known linters and formatters by default', () => {
const comments = markdown => {
const marpit = marpitStub()
md(marpit).render(markdown)

return marpit.lastComments[0]
}

expect(comments('<!-- regular comment -->')).toHaveLength(1)

// Prettier
expect(comments('<!-- prettier-ignore -->')).toHaveLength(0)
expect(
comments(dedent`
<!-- prettier-ignore-start -->
<!-- test -->
<!--prettier-ignore-end-->
`)
).toHaveLength(1)

// markdownlint
expect(
comments(dedent`
<!-- markdownlint-disable no-space-in-emphasis -->
deliberate space * in * emphasis
<!-- markdownlint-enable no-space-in-emphasis -->
`)
).toHaveLength(0)
expect(
comments(dedent`
<!-- markdownlint-capture -->
<!-- markdownlint-disable -->
any violations you want
<!-- markdownlint-restore -->
`)
).toHaveLength(0)

// remark-lint (remark-message-control)
expect(comments('<!--lint disable-->')).toHaveLength(0)
expect(comments('<!--lint enable-->')).toHaveLength(0)
expect(
comments(dedent`
# Hello

<!--lint disable no-duplicate-headings-->

## Hello

<!-- lint enable no-duplicate-headings -->
`)
).toHaveLength(0)
expect(
comments(dedent`
<!--lint ignore list-item-bullet-indent strong-marker-->

* **foo**
* __bar__
`)
).toHaveLength(0)
})
})

context('with inline SVG mode', () => {
it('includes inline SVG tokens in collected result', () => {
Expand Down