Skip to content

Commit

Permalink
Remove the language module dependency on TypeScript (#368)
Browse files Browse the repository at this point in the history
TypeScript isn’t needed to parse MDX into virtual files. The removal of
this dependency, means that the language module could later be used in
places where TypeScript is unavailable.
  • Loading branch information
remcohaszing authored Dec 17, 2023
1 parent 5cd32d7 commit 98d71d6
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/purple-kings-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@mdx-js/language-service": minor
---

Remove the dependency on an injected TypeScript module instance.
2 changes: 1 addition & 1 deletion packages/language-server/lib/language-server-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function plugin({modules}) {
)

config.languages ||= {}
config.languages.mdx ||= getLanguageModule(modules.typescript, plugins)
config.languages.mdx ||= getLanguageModule(plugins)

config.services ||= {}
config.services.markdown = createMarkdownService()
Expand Down
64 changes: 49 additions & 15 deletions packages/language-service/lib/language-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,44 @@ import remarkMdx from 'remark-mdx'
import remarkParse from 'remark-parse'
import {unified} from 'unified'

/**
* A TypeScript compatible script snapshot that wraps a string of text.
*
* @implements {IScriptSnapshot}
*/
export class ScriptSnapshot {
/**
* @param {string} text
* The text to wrap.
*/
constructor(text) {
this.text = text
}

/**
* Not implemented.
*
* @returns {undefined}
*/
getChangeRange() {}

/**
* @returns {number}
*/
getLength() {
return this.text.length
}

/**
* @param {number} start
* @param {number} end
* @returns {string}
*/
getText(start, end) {
return this.text.slice(start, end)
}
}

/**
* @param {string} propsName
*/
Expand Down Expand Up @@ -228,11 +266,10 @@ function processExports(mdx, node, mapping, esm) {
/**
* @param {string} fileName
* @param {IScriptSnapshot} snapshot
* @param {typeof import('typescript')} ts
* @param {Processor} processor
* @returns {VirtualFile[]}
*/
function getVirtualFiles(fileName, snapshot, ts, processor) {
function getVirtualFiles(fileName, snapshot, processor) {
const mdx = snapshot.getText(0, snapshot.getLength())
/** @type {Mapping[]} */
const jsMappings = []
Expand All @@ -248,17 +285,17 @@ function getVirtualFiles(fileName, snapshot, ts, processor) {
fileName: fileName + '.jsx',
languageId: 'javascriptreact',
typescript: {
scriptKind: ts.ScriptKind.JSX
scriptKind: 2
},
mappings: jsMappings,
snapshot: ts.ScriptSnapshot.fromString(fallback)
snapshot: new ScriptSnapshot(fallback)
},
{
embeddedFiles: [],
fileName: fileName + '.md',
languageId: 'markdown',
mappings: [],
snapshot: ts.ScriptSnapshot.fromString(mdx)
snapshot: new ScriptSnapshot(mdx)
}
]
}
Expand Down Expand Up @@ -417,7 +454,7 @@ function getVirtualFiles(fileName, snapshot, ts, processor) {
}
}
],
snapshot: ts.ScriptSnapshot.fromString(node.value)
snapshot: new ScriptSnapshot(node.value)
})

break
Expand Down Expand Up @@ -525,17 +562,17 @@ function getVirtualFiles(fileName, snapshot, ts, processor) {
fileName: fileName + '.jsx',
languageId: 'javascriptreact',
typescript: {
scriptKind: ts.ScriptKind.JSX
scriptKind: 2
},
mappings: jsMappings,
snapshot: ts.ScriptSnapshot.fromString(esm)
snapshot: new ScriptSnapshot(esm)
},
{
embeddedFiles: [],
fileName: fileName + '.md',
languageId: 'markdown',
mappings: [markdownMapping],
snapshot: ts.ScriptSnapshot.fromString(markdown)
snapshot: new ScriptSnapshot(markdown)
}
)

Expand All @@ -545,15 +582,13 @@ function getVirtualFiles(fileName, snapshot, ts, processor) {
/**
* Create a [Volar](https://volarjs.dev) language module to support MDX.
*
* @param {typeof import('typescript')} ts
* The TypeScript module.
* @param {PluggableList} [plugins]
* A list of remark syntax plugins. Only syntax plugins are supported.
* Transformers are unused.
* @returns {LanguagePlugin}
* A Volar language module to support MDX.
*/
export function getLanguageModule(ts, plugins) {
export function getLanguageModule(plugins) {
const processor = unified().use(remarkParse).use(remarkMdx)
if (plugins) {
processor.use(plugins)
Expand All @@ -570,7 +605,7 @@ export function getLanguageModule(ts, plugins) {
const length = snapshot.getLength()

return {
embeddedFiles: getVirtualFiles(fileName, snapshot, ts, processor),
embeddedFiles: getVirtualFiles(fileName, snapshot, processor),
fileName,
languageId: 'mdx',
mappings: [
Expand Down Expand Up @@ -615,7 +650,6 @@ export function getLanguageModule(ts, plugins) {
mdxFile.embeddedFiles = getVirtualFiles(
mdxFile.fileName,
snapshot,
ts,
processor
)
},
Expand All @@ -632,7 +666,7 @@ export function getLanguageModule(ts, plugins) {
...host,
getCompilationSettings: () => ({
// Default to the JSX automatic runtime, because that’s what MDX does.
jsx: ts.JsxEmit.ReactJSX,
jsx: 4,
// Set these defaults to match MDX if the user explicitly sets the classic runtime.
jsxFactory: 'React.createElement',
jsxFragmentFactory: 'React.Fragment',
Expand Down
Loading

0 comments on commit 98d71d6

Please sign in to comment.