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 committed 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
@@ -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
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
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

0 comments on commit 98d71d6

Please sign in to comment.