Skip to content

Commit

Permalink
feat: fallback to async API on processSync error via synckit (#307)
Browse files Browse the repository at this point in the history
* feat: fallback to async API on processSync error via synckit

* refactor: catch process error in worker instead

* feat: cache broken sync processor

* fix: mark processor broken
  • Loading branch information
JounQin authored Apr 29, 2021
1 parent a893aa7 commit 94a08af
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 21 deletions.
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

0 comments on commit 94a08af

Please sign in to comment.