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

feat: fallback to async API on processSync error via synckit #307

Merged
merged 4 commits into from
Apr 29, 2021
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: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ before_install:
install: yarn --frozen-lockfile

script:
- yarn build
- yarn lint
- yarn test

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"lint:es": "cross-env PARSER_NO_WATCH=true eslint . --cache --ext js,md,ts -f friendly",
"lint:ts": "tslint -p . -t stylish",
"postinstall": "simple-git-hooks && yarn-deduplicate --strategy fewer || exit 0",
"prelint": "yarn build",
"prerelease": "yarn build",
"release": "lerna publish --conventional-commits --create-release github --yes",
"test": "jest",
Expand All @@ -35,6 +36,7 @@
"lerna": "^4.0.0",
"npm-run-all": "^4.1.5",
"react": "^17.0.2",
"remark-validate-links": "^10.0.4",
"ts-jest": "^26.5.5",
"ts-node": "^9.1.1",
"tslint": "^6.1.3",
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin-mdx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"remark-mdx": "^1.6.22",
"remark-parse": "^8.0.3",
"remark-stringify": "^8.1.1",
"synckit": "^0.1.5",
"tslib": "^2.2.0",
"unified": "^9.2.1",
"vfile": "^4.2.1"
Expand Down
64 changes: 48 additions & 16 deletions packages/eslint-plugin-mdx/src/rules/remark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import path from 'path'
import type { Rule } from 'eslint'
import type { ParserOptions } from 'eslint-mdx'
import { DEFAULT_EXTENSIONS, MARKDOWN_EXTENSIONS } from 'eslint-mdx'
import { createSyncFn } from 'synckit'
import type { FrozenProcessor } from 'unified'
import vfile from 'vfile'

import { getPhysicalFilename, getRemarkProcessor } from './helpers'
import type { RemarkLintMessage } from './types'
import type { ProcessSync, RemarkLintMessage } from './types'

const processSync = createSyncFn(require.resolve('../worker')) as ProcessSync

const brokenCache = new WeakMap<FrozenProcessor, true>()

export const remark: Rule.RuleModule = {
meta: {
Expand Down Expand Up @@ -36,22 +42,45 @@ export const remark: Rule.RuleModule = {
if (!isMdx && !isMarkdown) {
return
}

const physicalFilename = getPhysicalFilename(filename)

const sourceText = sourceCode.getText(node)
const remarkProcessor = getRemarkProcessor(
getPhysicalFilename(filename),
isMdx,
)
const file = vfile({
const remarkProcessor = getRemarkProcessor(physicalFilename, isMdx)

const fileOptions = {
path: filename,
contents: sourceText,
})
}

try {
remarkProcessor.processSync(file)
} catch (err) {
/* istanbul ignore next */
if (!file.messages.includes(err)) {
file.message(err).fatal = true
const file = vfile(fileOptions)

let broken = brokenCache.get(remarkProcessor)

if (broken) {
const { messages } = processSync(fileOptions, physicalFilename, isMdx)
file.messages = messages
} else {
try {
remarkProcessor.processSync(file)
} catch (err) {
/* istanbul ignore else */
if (
(err as Error).message ===
'`processSync` finished async. Use `process` instead'
) {
brokenCache.set(remarkProcessor, (broken = true))
const { messages } = processSync(
fileOptions,
physicalFilename,
isMdx,
)
file.messages = messages
} else {
if (!file.messages.includes(err)) {
file.message(err).fatal = true
}
}
}
}

Expand Down Expand Up @@ -102,11 +131,14 @@ export const remark: Rule.RuleModule = {
end.offset == null ? start.offset + 1 : end.offset,
]
const partialText = sourceText.slice(...range)
const fixed = remarkProcessor.processSync(partialText).toString()
const fixed = broken
? processSync(partialText, physicalFilename, isMdx)
: remarkProcessor.processSync(partialText).toString()
return fixer.replaceTextRange(
range,
/* istanbul ignore next */
partialText.endsWith('\n') ? fixed : fixed.slice(0, -1), // remove redundant new line
partialText.endsWith('\n')
? /* istanbul ignore next */ fixed
: fixed.slice(0, -1), // remove redundant new line
)
},
})
Expand Down
14 changes: 14 additions & 0 deletions packages/eslint-plugin-mdx/src/rules/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Linter } from 'eslint'
import type { ExpressionStatement, Node } from 'estree'
import type { Attacher } from 'unified'
import type { VFile, VFileOptions } from 'vfile'

export interface WithParent {
parent: NodeWithParent
Expand All @@ -25,3 +26,16 @@ export interface RemarkLintMessage {
ruleId: string
severity: Linter.Severity
}

export interface ProcessSync {
(text: string, physicalFilename: string, isFile: boolean): string
(fileOptions: VFileOptions, physicalFilename: string, isFile: boolean): Pick<
VFile,
'messages'
>
(
textOrFileOptions: string | VFileOptions,
physicalFilename: string,
isFile: boolean,
): string | VFileOptions
}
27 changes: 27 additions & 0 deletions packages/eslint-plugin-mdx/src/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { runAsWorker } from 'synckit'
import type { VFileOptions } from 'vfile'
import vfile from 'vfile'

import { getRemarkProcessor } from './rules'

// eslint-disable-next-line @typescript-eslint/no-floating-promises
runAsWorker(
async (
textOrFileOptions: string | VFileOptions,
physicalFilename: string,
isMdx: boolean,
) => {
const remarkProcessor = getRemarkProcessor(physicalFilename, isMdx)
const file = vfile(textOrFileOptions)
try {
await remarkProcessor.process(file)
} catch (err) {
if (!file.messages.includes(err)) {
file.message(err).fatal = true
}
}
return typeof textOrFileOptions === 'string'
? file.toString()
: { messages: file.messages }
},
)
8 changes: 8 additions & 0 deletions test/fixtures/async/.remarkrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"plugins": [
[
"validate-links",
2
]
]
}
27 changes: 26 additions & 1 deletion test/remark.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ ruleTester.run('remark 1', remark, {
parserOptions,
// dark hack
get filename() {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
processorCache.clear()
return path.resolve(userDir, '../test.md')
},
},
{
code: '<header>Header6</header>',
parser,
parserOptions,
filename: path.resolve(__dirname, 'fixtures/async/test.mdx'),
},
],
invalid: [
{
Expand All @@ -68,5 +73,25 @@ ruleTester.run('remark 1', remark, {
},
],
},
{
code: '[CHANGELOG](./CHANGELOG.md)',
parser,
parserOptions,
filename: path.resolve(__dirname, 'fixtures/async/test.mdx'),
errors: [
{
message: JSON.stringify({
reason: 'Link to unknown file: `CHANGELOG.md`',
source: 'remark-validate-links',
ruleId: 'missing-file',
severity: 1,
}),
line: 1,
column: 1,
endLine: 1,
endColumn: 28,
},
],
},
],
})
10 changes: 10 additions & 0 deletions tsconfig.eslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.base",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"eslint-mdx": ["packages/eslint-mdx/src"],
"eslint-plugin-mdx": ["packages/eslint-plugin-mdx/src"]
}
}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "./tsconfig.base.json",
"extends": "./tsconfig.base",
"compilerOptions": {
"noEmit": true
},
Expand Down
64 changes: 62 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4847,6 +4847,11 @@ emittery@^0.7.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82"
integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==

"emoji-regex@>=6.0.0 <=6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e"
integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=

emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
Expand Down Expand Up @@ -5855,6 +5860,13 @@ gitconfiglocal@^1.0.0:
dependencies:
ini "^1.3.2"

github-slugger@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.3.0.tgz#9bd0a95c5efdfc46005e82a906ef8e2a059124c9"
integrity sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==
dependencies:
emoji-regex ">=6.0.0 <=6.1.1"

glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
Expand Down Expand Up @@ -6054,6 +6066,13 @@ hosted-git-info@^2.1.4:
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==

hosted-git-info@^3.0.0:
version "3.0.8"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d"
integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==
dependencies:
lru-cache "^6.0.0"

hosted-git-info@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961"
Expand Down Expand Up @@ -7362,6 +7381,11 @@ leven@^3.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==

levenshtein-edit-distance@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/levenshtein-edit-distance/-/levenshtein-edit-distance-1.0.0.tgz#895baf478cce8b5c1a0d27e45d7c1d978a661e49"
integrity sha1-iVuvR4zOi1waDSfkXXwdl4pmHkk=

levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
Expand Down Expand Up @@ -7733,7 +7757,7 @@ mdast-util-heading-style@^1.0.2:
resolved "https://registry.yarnpkg.com/mdast-util-heading-style/-/mdast-util-heading-style-1.0.6.tgz#6410418926fd5673d40f519406b35d17da10e3c5"
integrity sha512-8ZuuegRqS0KESgjAGW8zTx4tJ3VNIiIaGFNEzFpRSAQBavVc7AvOo9I4g3crcZBfYisHs4seYh0rAVimO6HyOw==

mdast-util-to-string@^1.0.2:
mdast-util-to-string@^1.0.0, mdast-util-to-string@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527"
integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==
Expand Down Expand Up @@ -9287,6 +9311,13 @@ prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"

propose@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/propose/-/propose-0.0.5.tgz#48a065d9ec7d4c8667f4050b15c4a2d85dbca56b"
integrity sha1-SKBl2ex9TIZn9AULFcSi2F28pWs=
dependencies:
levenshtein-edit-distance "^1.0.0"

proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
Expand Down Expand Up @@ -10343,6 +10374,19 @@ remark-stringify@^8.1.1:
unherit "^1.0.4"
xtend "^4.0.1"

remark-validate-links@^10.0.4:
version "10.0.4"
resolved "https://registry.yarnpkg.com/remark-validate-links/-/remark-validate-links-10.0.4.tgz#a2711fa794f691c944faf8126767152dcfee0c47"
integrity sha512-oNGRcsoQkL35WoZKLMMBugDwvHfyu0JPA5vSYkEcvR6YBsFKBo4RedpecuokTK1wgD9l01rPxaQ9dPmRQYFhyg==
dependencies:
github-slugger "^1.0.0"
hosted-git-info "^3.0.0"
mdast-util-to-string "^1.0.0"
propose "0.0.5"
to-vfile "^6.0.0"
trough "^1.0.0"
unist-util-visit "^2.0.0"

remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
Expand Down Expand Up @@ -11325,6 +11369,14 @@ symbol-tree@^3.2.4:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==

synckit@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.1.5.tgz#f34462b2e3686bba3dbea2ae13b6e01adff2ffb8"
integrity sha512-s9rDbMJAF5SDEwBGH/DvbN/fb5N1Xu1boL4Uv66idbCbtosNX3ikUsFvGhROmPXsvlMYMcT5ksmkU5RSnkFi9Q==
dependencies:
tslib "^2.2.0"
uuid "^8.3.2"

table@^6.0.4:
version "6.0.9"
resolved "https://registry.yarnpkg.com/table/-/table-6.0.9.tgz#790a12bf1e09b87b30e60419bafd6a1fd85536fb"
Expand Down Expand Up @@ -11504,6 +11556,14 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"

to-vfile@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/to-vfile/-/to-vfile-6.1.0.tgz#5f7a3f65813c2c4e34ee1f7643a5646344627699"
integrity sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==
dependencies:
is-buffer "^2.0.0"
vfile "^4.0.0"

tough-cookie@^2.3.3, tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
Expand Down Expand Up @@ -12064,7 +12124,7 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==

uuid@^8.3.0:
uuid@^8.3.0, uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
Expand Down