Skip to content

Add from annotation #214

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

Merged
merged 1 commit into from
Jul 3, 2022
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 packages/mdx/dev/content/assets/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("hello foo")
1 change: 1 addition & 0 deletions packages/mdx/dev/content/assets/foo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Hello foo")
34 changes: 34 additions & 0 deletions packages/mdx/dev/content/external.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
```js foo.js
// from ./assets/foo.js
```

```py foo.py
# from ./assets/foo.py
```

```py foo.py
print("not external")
# from ./assets/foo.py
```

<CH.Code>

```js foo.js
// from ./assets/foo.js
```

```py foo.py
# from ./assets/foo.py
```

```html index.html
<h1>Hello</h1>
```

---

```py another.py
# from ./assets/foo.py
```

</CH.Code>
12 changes: 5 additions & 7 deletions packages/mdx/dev/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@ export async function getFiles() {
.filter(file => file.endsWith(".mdx"))
.map(filename => filename.slice(0, -4))
}
export async function getContent(filename: string) {
const file = await fs.promises.readFile(
`./dev/content/${filename}.mdx`,
"utf8"
)
export async function getFile(filename: string) {
const path = `./dev/content/${filename}.mdx`
const file = await fs.promises.readFile(path, "utf8")

return file
return { value: file, path }
}

export async function getCode(file: string, config = {}) {
export async function getCode(file: any, config = {}) {
let debugLink = ""

const debugCompile = withDebugger(compile, {
Expand Down
6 changes: 3 additions & 3 deletions packages/mdx/pages/[name].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { runSync } from "@mdx-js/mdx"
import * as runtime from "react/jsx-runtime.js"
import { CH } from "../src/components"
import { getCode, getContent, getFiles } from "../dev/files"
import { getCode, getFile, getFiles } from "../dev/files"
import { ClickToComponent } from "click-to-react-component"
import { Layout } from "../dev/layout"

Expand All @@ -17,8 +17,8 @@ export async function getStaticProps({ params }) {
const { name = "test" } = params

const files = await getFiles()
const content = await getContent(name)
const { code, debugLink } = await getCode(content)
const file = await getFile(name)
const { code, debugLink } = await getCode(file)
return {
props: {
tests: files,
Expand Down
86 changes: 78 additions & 8 deletions packages/mdx/src/remark/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import {
extractAnnotationsFromCode,
extractJSXAnnotations,
} from "./annotations"
import { mergeFocus } from "../utils"
import { Code, mergeFocus } from "../utils"
import { CodeNode, SuperNode } from "./nodes"
import { CodeHikeConfig } from "./config"
import { getCommentData } from "./comment-data"

export function isEditorNode(
node: SuperNode,
Expand Down Expand Up @@ -119,12 +120,15 @@ async function mapFile(

const lang = (node.lang as string) || "text"

const code = await highlight({
let code = await highlight({
code: node.value as string,
lang,
theme,
})

// if the code is a single line with a "from" annotation
code = await getCodeFromExternalFileIfNeeded(code, config)

const [commentAnnotations, commentFocus] =
extractAnnotationsFromCode(code)

Expand All @@ -136,12 +140,12 @@ async function mapFile(
options as any
)

const linkAnnotations = extractLinks(
node,
index,
parent,
node.value as string
)
// const linkAnnotations = extractLinks(
// node,
// index,
// parent,
// nodeValue as string
// )

const jsxAnnotations = extractJSXAnnotations(
node,
Expand Down Expand Up @@ -188,3 +192,69 @@ function parseMetastring(
})
return { name: name || "", ...options }
}

async function getCodeFromExternalFileIfNeeded(
code: Code,
config: CodeHikeConfig
) {
if (code?.lines?.length != 1) {
return code
}

const firstLine = code.lines[0]
const commentData = getCommentData(firstLine, code.lang)

if (!commentData || commentData.key != "from") {
return code
}

const fileText = firstLine.tokens
.map(t => t.content)
.join("")

const codepath = commentData.data

let fs, path

try {
fs = (await import("fs")).default
path = (await import("path")).default
if (!fs || !fs.readFileSync || !path || !path.resolve) {
throw new Error("fs or path not found")
}
} catch (e) {
e.message = `Code Hike couldn't resolve this annotation:
${fileText}
Looks like node "fs" and "path" modules are not available.`
throw e
}

// if we don't know the path of the mdx file:
if (config.filepath === undefined) {
throw new Error(
`Code Hike couldn't resolve this annotation:
${fileText}
Someone is calling the mdx compile function without setting the path.
Open an issue on CodeHike's repo for help.`
)
}

const dir = path.dirname(config.filepath)
const absoluteCodepath = path.resolve(dir, codepath)

let nodeValue
try {
nodeValue = fs.readFileSync(absoluteCodepath, "utf8")
} catch (e) {
e.message = `Code Hike couldn't resolve this annotation:
${fileText}
${absoluteCodepath} doesn't exist.`
throw e
}

return await highlight({
code: nodeValue,
lang: code.lang,
theme: config.theme,
})
}
6 changes: 5 additions & 1 deletion packages/mdx/src/remark/comment-data.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Code } from "../utils"
import { annotationsMap } from "../mdx-client/annotations"

const validKeys = ["focus", ...Object.keys(annotationsMap)]
const validKeys = [
"focus",
"from",
...Object.keys(annotationsMap),
]

export function getCommentData(
line: Code["lines"][0],
Expand Down
7 changes: 6 additions & 1 deletion packages/mdx/src/remark/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@ export type CodeHikeConfig = {
skipLanguages: string[]
showExpandButton?: boolean
showCopyButton?: boolean
// path to the current file, internal use only
filepath?: string
}

/**
* Add defaults and normalize config
*/
export function addConfigDefaults(
config: Partial<CodeHikeConfig> | undefined
config: Partial<CodeHikeConfig> | undefined,
cwd?: string,
filepath?: string
): CodeHikeConfig {
// TODO warn when config looks weird
return {
...config,
theme: config?.theme || {},
autoImport: config?.autoImport === false ? false : true,
skipLanguages: config?.skipLanguages || [],
filepath,
}
}
11 changes: 8 additions & 3 deletions packages/mdx/src/remark/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ const transforms = [
transformInlineCodes,
transformCodes,
]

export function transform(unsafeConfig: CodeHikeConfig) {
return async (tree: SuperNode) => {
const config = addConfigDefaults(unsafeConfig)
return async (tree: SuperNode, file: any) => {
const config = addConfigDefaults(
unsafeConfig,
file?.cwd,
file?.history
? file.history[file.history.length - 1]
: undefined
)

try {
for (const transform of transforms) {
Expand Down
2 changes: 1 addition & 1 deletion playground/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ main {

.compile-error pre {
color: #111;
white-space: normal;
white-space: pre-wrap;
}

.with-error {
Expand Down