Giter Club home page Giter Club logo

markdoc's Introduction


Markdoc

A powerful, flexible, Markdown-based authoring framework.

Markdoc is a Markdown-based syntax and toolchain for creating custom documentation sites and experiences.
We designed Markdoc to power Stripe's public docs, our largest and most complex content site.

Installation

To get started with Markdoc, first install the library:

npm install @markdoc/markdoc

or

yarn add @markdoc/markdoc

and import it in your app:

const Markdoc = require('@markdoc/markdoc');

or if you are using ESM

import Markdoc from '@markdoc/markdoc';

then use Markdoc in your app or tool:

const doc = `
# Markdoc README

{% image src="/logo.svg" /%}
`;

const ast = Markdoc.parse(doc);
const content = Markdoc.transform(ast);
return Markdoc.renderers.react(content, React);

Check out our docs for more guidance on how to use Markdoc.

TypeScript

This is the minimal tsconfig.json required to use Markdoc in your TypeScript project:

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "esnext", // works with es2015 or greater
    "esModuleInterop": true
  }
}

React

If you are using React, install Markdoc with:

npm install @markdoc/markdoc react @types/react

Contributing

Contributions and feedback are welcome and encouraged. Check out our contributing guidelines on how to do so.

Development

  1. Run npm install
  2. Run npm run build
  3. Run the tests using npm test

Code of conduct

This project has adopted the Stripe Code of conduct.

License

This project uses the MIT license.

Credits

Special shout out to:

markdoc's People

Contributors

addisonj avatar dependabot[bot] avatar emmatown avatar fzn0x avatar marcussorealheis avatar matv-stripe avatar mfix-stripe avatar nkohari-stripe avatar nvanexan avatar rpaul-stripe avatar techsolomon avatar thcyron avatar xiaoyang-sde avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

markdoc's Issues

Strings starting with "{%" inside code blocks are parsed as unclosed Markdoc, clogging builds

What happened?

I've been migrating our website to Markdoc. We use a bit of an esoteric programming language that does use {%term} format at times. When running next build, on the build would halt on one of 5 pages and my node would gradually use 12GB of RAM until my system froze.

Deleting files and escaping the Markdown render I've nailed it down to pages that have strings that start with {% inside a code block. Examples:

image

image

image

If I delete these lines from all these files, the build runs fine. If I retain even one, it goes into its death spiral.

To reproduce

Place one of those strings on a page. Should be enough. It looks like the Markdoc website wraps examples in a custom tag — was this an intentional workaround? We can do similar ...

Version

0.1.2

Additional context

No response

Support variables in Next.js pageProps

Would it make sense to support variables in Next.js pageProps? This would make global variables defined in /markdoc/variables.js available to /pages/_app.js. Happy to try creating a PR if this sounds sensible.

[Feature Request] Syntax plugin for VSCode?

Hi there,

I've noticed the markdoc/docs repo has an extension for code mirror to highlight the {% ... $} syntax that Markdoc adds to Markdown. Is there any possibility of bringing this to vscode?

Many thanks

Fails to compile in Angular 12

What happened?

After installing Markdoc in a new angular 12 app, I get the following error.

Error: node_modules/@markdoc/markdoc/dist/index.d.ts:104:48 - error TS2694: Namespace '"/Users/jandrews/Projects/md/node_modules/@markdoc/markdoc/dist/src/types"' has no exported member 'Function'.

104         Function: typeof import("./src/types").Function;

To reproduce

  1. Install Angular 12.
  2. Create new project ng new markdoc-test
  3. Install markdoc npm install @markdoc/markdoc
  4. Install dependencies npm i --save-dev @types/react and npm i --save-dev @types/markdown-it
  5. Run Angular ng serve --ssl

The server will start and fail with:

Error: node_modules/@markdoc/markdoc/dist/index.d.ts:104:48 - error TS2694: Namespace '"/Users/jandrews/Projects/md/node_modules/@markdoc/markdoc/dist/src/types"' has no exported member 'Function'.

104         Function: typeof import("./src/types").Function;

The problem seems to be Function isn't exported, and since it's imported in, it can't be exported with export statement. I had edited types.d.ts to include export class astFunction extends Function {} and then the index.ts file on line 104 to use Function: typeof import("./src/types").astFunction; instead, and that prevented the compile error. Not sure if there is a better fix, but I thought I'd mention this here.

Version

^0.1.1

Additional context

No response

Footnote support?

Currently there's no way to inject markdown-it plugins down to the tokenizer, so we can't just pass markdown-it-footnotes here, but I can't see any facility for supporting Footnote syntax (which are common in GFM). Any current workarounds?

TypeScript errors when using the `Schema` type for node/tag definitions

What happened?

I wanted some type safety when defining nodes and tags so I added a Schema type annotation to the callout tag definition from the Next.js starter project. I expected no type errors but got two: one for the render property and one for a description property on an attribute. When I comment out both properties I get an error for the description property of the tag.

To reproduce

  1. Clone the Next.js starter project and install dependencies using npm install
  2. Add a type annotation to the export in markdoc/tags/callout.markdoc.ts
import { Schema } from '@markdoc/markdoc';
import {Callout} from '../../components';

export const callout: Schema = {
  render: Callout,
  description: 'Display the enclosed content in a callout box',
  children: ['paragraph', 'tag', 'list'],
  attributes: {
    title: {
      type: String,
      description: 'The title displayed at the top of the callout',
    },
  },
};

You should now see two type errors (either in your editor or when starting a build). One on the render property:

Type '({ title, children }: { title: any; children: any; }) => Element' is not assignable to type 'string'.ts(2322)
types.d.ts(57, 5): The expected type comes from property 'render' which is declared here on type 'Schema<Readonly<Partial<{ nodes: Partial<Record<NodeType, Schema<Readonly<Partial<...>>, string>>>; tags: Record<string, Schema<Readonly<Partial<...>>, string>>; variables: Record<...>; functions: Record<...>; partials: Record<...>; validation?: { ...; }; }>>, string>'

and one on the description property of the title attribute:

Type '{ type: StringConstructor; description: string; }' is not assignable to type 'SchemaAttribute'.
  Object literal may only specify known properties, and 'description' does not exist in type 'SchemaAttribute'.ts(2322)

When commenting both out there's another error on the description property of the callout tag:

Type '{ description: string; children: string[]; attributes: { title: { type: StringConstructor; }; }; }' is not assignable to type 'Schema<Readonly<Partial<{ nodes: Partial<Record<NodeType, Schema<Readonly<Partial<...>>, string>>>; tags: Record<string, Schema<Readonly<Partial<...>>, string>>; variables: Record<...>; functions: Record<...>; partials: Record<...>; validation?: { ...; }; }>>, string>'.
  Object literal may only specify known properties, and 'description' does not exist in type 'Schema<Readonly<Partial<{ nodes: Partial<Record<NodeType, Schema<Readonly<Partial<...>>, string>>>; tags: Record<string, Schema<Readonly<Partial<...>>, string>>; variables: Record<...>; functions: Record<...>; partials: Record<...>; validation?: { ...; }; }>>, string>'.ts(2322)

Version

0.1.4

Additional context

The exact commit of the starter repository used is cf36368f405a41499aded8b61b136c0bda44c0e3.

Footnotes?

As a writer, I'd like to be able to use footnotes to add supporting context to the content I'm writing. Can we have footnote support in Markdoc?

Usually, when adding supporting context to a sentence, one would use the em-dash "—" to denote a momentary break in thought, a somewhat tangential drift. When this drift-break exceeds some arbitrary attention quota — would be nice to get empirical data on this — the drift breaks the reader's experience. The go-to solution for this is a footnote.

The footnote syntax is detailed in the Markdown Guide's Extended Syntax

Tabs example possibly incorrect

After implementing the Tabs code, I keep hitting children.map is not a function on the React renderer output in a Next.js client-side deployment.

image

Code is basically verbatim off the site, and removing the tags makes the page work again; it's just when I use the tabs (even the example Markdown-side tabs from the site) that the page can't render.

const tab = {
  render: "Tab",
  attributes: {
    label: {
      type: String,
    },
  },
};

const tabs = {
  render: "Tabs",
  attributes: {},
  transform(node, config) {
    const labels = node
      .transformChildren(config)
      .filter((child) => child && child.name === "Tab")
      .map((tab) => (typeof tab === "object" ? tab.attributes.label : null));

    return new Tag(this.render, { labels }, tabs);
  },
};

export default function Markdown({ post }) {
  const ast = Markdoc.parse(post.content);
  const finalAst = footnoteParse(ast);
  const content = Markdoc.transform(finalAst, {
    nodes: {
      fence,
      heading,
      footnoteItem,
      footnoteRef,
    },
    tags: {
      tabs,
      tab,
    },
  });
  return Markdoc.renderers.react(content, React, {
    components: {
      Fence,
      tabs: Tabs,
      tab: Tab,
    },
  });
}

components/Tab.js:

import React from "react";
import { TabContext } from "./Tabs";

const Tab = ({ label, children }) => {
  const currentTab = React.useContext(TabContext);

  if (label !== currentTab) {
    return null;
  }

  return children;
};

export default Tab;

components/Tabs.js:

import React from "react";

export const TabContext = React.createContext();

const Tabs = ({ labels, children }) => {
  const [currentTab, setCurrentTab] = React.useState(labels[0]);

  return (
    <TabContext.Provider value={currentTab}>
      <ul role="tablist">
        {labels.map((label) => (
          <li key={label}>
            <button
              role="tab"
              aria-selected={label === currentTab}
              onClick={() => setCurrentTab(label)}
            >
              {label}
            </button>
          </li>
        ))}
      </ul>
      {children}
    </TabContext.Provider>
  );
};

export default Tabs;

Any idea where it's trying to map some children variable that isn't defined?

Enhancement: markdoc/next.js TypeScript emit

I've been fiddling with a custom NextJS plugin (reason: I have differing opinions™ than NextJS does about how to structure my project, not your problem).

In this project I decided to use the code in https://github.com/markdoc/next.js/blob/main/src/loader.js as an example on the right way to integrate -- and it works! Great!!

In my project I'm using TypeScript, so I set about finding the right types to use, and I found myself confounded to learn that it wasn't possible. The types of Markdoc.transform's Config just don't line up with the values that are created in loader.js.

It works so clearly this is some sort of TypeScript type mismatch.

The exact error I get is:
Type '({ id, level, children, className }: HeadingProps) => Element' is not assignable to type 'string' on the nodes parameter

import * as config from "./schema/config";
import * as tags from "./schema/tags";
import * as nodes from "./schema/nodes";
import * as functions from "./schema/functions";

import type { transform } from "@markdoc/markdoc";
type SchemaConfig = Exclude<Parameters<typeof transform>[1], undefined>;

export const defaultSchema: SchemaConfig = {
	tags,
	nodes, // Error occurs here
	functions,
	...config,
};

Some questions:

  • Is there a better type I could use in this position?
  • Are we worried about loader.js/runtime.js / the NextJS plugin getting out of sync with Markdoc's core? -- Should we convert the whole webpack-loader into TypeScript to at least get TypeScript compile-time validation?
  • Could (should?) markdoc/NextJS emit .tsx files?

Is there a way to set attributes on a list?

What happened?

There is no way to set attributes on a list, i.e. to get an AST like:

{
  "type": "list",
  "attributes": {
    "ordered": false,
    "foo": "bar"
  }
}

To reproduce

I tried various ways to set attributes on a list, such as

{% #mylist %}
- one
- two

However, none resulted in a list node with attribute "id": "mylist".

Version

0.1.4

Additional context

I know I can set attributes on heading and paragraph nodes with syntax like:

# Header {% #custom-id %}

However, I don't know how to set such attributes on other node types, like list, image, em, etc., or whether this is even possible.

(If it's not possible, that's basically fine. I'll instead define a custom tag that accepts these attributes. But I would like to know whether it's possible to set these attributes directly on a list first.)

Deploy with Next.js on Vercel & Netlify not working

What happened?

Trying to deploy Markdoc with next.js from the docs page to Vercel or Netlify from the buttons doesn't work. Both fail with this error:

Failed to compile.

11:47:37.110 |  
11:47:37.110 | ./components/CodeBlock.tsx:10:22
11:47:37.110 | Type error: Cannot find name 'Prism'.
11:47:37.110 |  
11:47:37.111 | 8 |
11:47:37.111 | 9 | React.useEffect(() => {
11:47:37.111 | > 10 | if (ref.current) Prism.highlightElement(ref.current, false);
11:47:37.111 | | ^
11:47:37.111 | 11 | }, [children]);
11:47:37.111 | 12 |
11:47:37.136 | error Command failed with exit code 1.
11:47:37.136 | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
11:47:37.148 | Error: Command "yarn run build" exited with 1

To reproduce

  1. Go to https://markdoc.io/docs/nextjs
  2. Press the Vercel Deploy button
  3. Set up Vercel deployment with Github
  4. Deploy fails with error

Version

No response

Additional context

Full build logs from Vercel:

[11:47:19.282] Cloning github.com/shanamatthews/marcdoc-versel (Branch: main, Commit: 611077c)
[11:47:20.009] Cloning completed: 726.652ms
[11:47:20.430] Installing build runtime...
[11:47:22.520] Build runtime installed: 2.090s
[11:47:23.261] Looking up build cache...
[11:47:23.551] Build Cache not found
[11:47:23.738] Installing dependencies...
[11:47:24.089] yarn install v1.22.17
[11:47:24.119] info No lockfile found.
[11:47:24.125] [1/4] Resolving packages...
[11:47:26.943] [2/4] Fetching packages...
[11:47:32.256] [3/4] Linking dependencies...
[11:47:33.498] [4/4] Building fresh packages...
[11:47:33.503] success Saved lockfile.
[11:47:33.506] Done in 9.42s.
[11:47:33.531] Detected Next.js version: 12.1.6
[11:47:33.534] Running "yarn run build"
[11:47:33.808] yarn run v1.22.17
[11:47:33.842] $ next build
[11:47:34.521] Attention: Next.js now collects completely anonymous telemetry regarding usage.
[11:47:34.521] This information is used to shape Next.js' roadmap and prioritize features.
[11:47:34.521] You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
[11:47:34.521] https://nextjs.org/telemetry
[11:47:34.521]
[11:47:34.565] info - Checking validity of types...
[11:47:37.109] Failed to compile.
[11:47:37.110]
[11:47:37.110] ./components/CodeBlock.tsx:10:22
[11:47:37.110] Type error: Cannot find name 'Prism'.
[11:47:37.110]
[11:47:37.111] �[0m �[90m 8 | �[39m�[0m
[11:47:37.111] �[0m �[90m 9 | �[39m �[33mReact�[39m�[33m.�[39museEffect(() �[33m=>�[39m {�[0m
[11:47:37.111] �[0m�[31m�[1m>�[22m�[39m�[90m 10 | �[39m �[36mif�[39m (ref�[33m.�[39mcurrent) �[33mPrism�[39m�[33m.�[39mhighlightElement(ref�[33m.�[39mcurrent�[33m,�[39m �[36mfalse�[39m)�[33m;�[39m�[0m
[11:47:37.111] �[0m �[90m | �[39m �[31m�[1m^�[22m�[39m�[0m
[11:47:37.111] �[0m �[90m 11 | �[39m }�[33m,�[39m [children])�[33m;�[39m�[0m
[11:47:37.111] �[0m �[90m 12 | �[39m�[0m
[11:47:37.136] error Command failed with exit code 1.
[11:47:37.136] info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
[11:47:37.148] Error: Command "yarn run build" exited with 1

(question) Can customized React components are used instead of default components?

Currently, components that start with a lowercase letter are not customizable.

Is there a good way to customize "h2", for example?

import { parse, renderers, transform } from "@markdoc/markdoc";

const node = parse('## Header 2');

const readableTreeNode = transform(node);

const component = renderers.react(readableTreeNode, React, {
  components: {
    // Ignored.
    h2: (props) => <h2 {...props} style={{ color: "red" }} />,
  },
});

Thanks.


I have tried these solutions.

(1) Map components to components that start with UPPERCASE letter.

import { nodes, parse, renderers, Tag, transform } from "@markdoc/markdoc";

const node = parse(`## Header 2`);

// Thanks for https://markdoc.io/docs/nodes#customizing-markdoc-nodes
const readableTreeNode = transform(node, {
  nodes: {
    heading: {
      ...nodes.heading,
      // Required to transform from "heading" to "Heading".
      transform: (node, config) => {
        const attributes = node.transformAttributes(config);
        const children = node.transformChildren(config);
        return new Tag(`Heading${node.attributes.level}`, attributes, children);
      },
    },
  },
});

const component = renderers.react(readableTreeNode, React, {
  components: {
    // OK. (However, required to transform from heading/level2 to H2)
    Heading2: (props: any) => <h2 {...props} style={{ color: "blue" }} />,
  },
});

(2) Change the priority of using default components, customized components and the function.

(Update to use the default component only if no customized component is found.)

Swap return name and return components[name] in src/renderers/react/shared.ts

Typo in docs site code example

What happened?

In the Parse section of the Phases of rendering page, the code example for walking through the AST nodes looks like this:

const ast = Markdoc.parse(document);

for (const node of document.walk()) {
  // do something with each node
}

I believe .walk() should be called on ast instead, like so:

const ast = Markdoc.parse(document);

for (const node of ast.walk()) {
  // do something with each node
}

To reproduce

See code example above

Version

No response

Additional context

No response

Search bar support

First off, thank you for open sourcing this! I'm a big fan and a long-time user of Stripe, mainly because of the extensive developer-friendly docs.

I noticed that the docs don't have a built-in search bar. I work on Typesense which is an open source alternative to Algolia / Elasticsearch and I'd love to build a search-bar + scraper integration, similar to the one we have for Docusaurus: https://docusaurus.io/docs/search#using-typesense-docsearch

Would you be open to this?

Nextjs markdoc starter failing

What happened?

The current nextjs starter repo are not working on windows.

I expect to work.

To reproduce

Download the next repo starter.
Run on machine Windows

Version

Latest of nextjs and markdoc

Additional context

This is the error throwing in the browser, I also tested in another project mine

image

Improve image and link nodes

  • Update image syntax so that if it is on a line by itself, it is treated as a block, otherwise treat it as an inline element.
    • The default schema would render block-level images in a figure instead of a p, but this behavior would be possible to override in a custom node definition’s transform function
  • Update image syntax to allow passing additional attributes
    • E.g. ![alt](/href width=10 height=10 foo={arbitrary: "markdoc stuff"})
  • Test that the image/link syntax works with GitHub flavored Markdown, or we have a story for that.

Replacing Existing Node with Next.js Fails to Pass Attributes

What happened?

Following the docs on nodes and next js nodes is confusing.

Goal: replace the default heading node as the nodes doc demonstrates.

Following the examples in the nodes seems to lead to either the render function being called with no props other than children, or only the transform step being called and not the render step.

Suggestion

Provide more details on the way the nextjs integration interacts with the described transform and render steps, and provide more complete examples for nextjs.

To reproduce

  1. Create a markdoc file with a h1, h2, h3.
  2. Try this basic example (as implied by the combination of nextjs and non-nextjs docs)
import { Title } from '../title';
import { Tag } from '@markdoc/markdoc';


const TitleWrapper = ({ level, id, children }) => {
    console.log('Wrapper called')
    return (
        <Title level={level} id={id}>{children}</Title>
    )
}

export const heading = {
    render: TitleWrapper,
    children: ['inline'],
    attibutes: {
        id: { type: String },
        level: {type: Number, required: true, default: 1}
    }
}
  1. This does render the component however it is never passed any value for level other than the default.

  2. Attempt #2 Try the following

import { Title } from '../title';
import { Tag } from '@markdoc/markdoc';

const TitleWrapper = ({ level, id, children }) => {
    console.log('wrapper')
    const order = Math.min((level || 1) +1, 6) as TitleOrder;
    return (
    
        <Title order={order} id={id}>{children}</Title>
    )
}


function generateID(children, attributes) {
 //... skipped for brevity as not relevant
}

export const heading = {
    render: TitleWrapper,
    children: ['inline'],
    attibutes: {
        id: { type: String },
        level: {type: Number, required: true, default: 1}
    },
    transform(node, config) {
        const attributes = node.transformAttributes(config);
        const children = node.transformChildren(config);

        const id = generateID(children, attributes);

        return new Tag(
        `h${node.attributes['level']}`,
        { ...attributes, id },
        children
        );
  }
}

This does allow for multi-level headings however the render function is never called (no log lines printed or component rendered).

Version

@markdoc/markdoc": 0.1.2, @markdoc/next.js: 0.1.4

Additional context

No response

Enhancement / Bug: Missing CommonMark node type 'code_block'

What happened?

I added a (test) markdown file that had the following expressions:

    # https://spec.commonmark.org/0.30/#indented-code-block
    4-space indented code

When I rendered it with the react renderer under nextjs, this document threw the error:

Error: Undefined node 'code_block'

To reproduce

  1. Enter the content in a markdown file as described above
  2. Render it in your markdoc-based nextjs site
  3. See the error!

Will submit a PR with test cases shortly.

Version

0.1.2 -- reproducible in this repo

Additional context

I expected this to be supported because the documentation says that the nodes supported are the CommonMark nodes.

That said, it is indeed true that the exact nodes supported table does not include 'code_block' so the documentation may be "technically correct"

Workarounds include:

  • Provide my own code_block implementation in my schema
  • Avoid validating my markdown document and just swallow the error

Parsing of link node doesn't return title attribute

What happened?

I was trying to create a custom transform on "link" nodes to support adding additional custom attributes and in doing so, I noticed that the title attribute declared in markdown was never returned when calling Markdoc.parse.

In the Commonmark spec, link-titles can be declared with the following syntax:

[link](/uri "title")

When running the parse function on a link with this syntax, however, only the href attribute is returned. No title attribute is ever returned from the parser.

Based on the documentation for link node, I expected href and optionally the title attribute to be available in the node attributes when the markdown is parsed.

To reproduce

The issue can be reproduced by running the following file.

import Markdoc, { Node } from "@markdoc/markdoc";

function printNodeAttributes(ast: Node) {
  if (ast.type === "link") {
    console.log(`Node type: ${ast.type}`);
    console.log(`Node attributes: ${JSON.stringify(ast.attributes)}`);
  }
  if (ast.children) {
    ast.children.forEach((child) => printNodeAttributes(child));
  }
}

const testLink = `[Markdoc](https://markdoc.io "markdoc link title")`;
const ast = Markdoc.parse(testLink);
printNodeAttributes(ast);

The output is

Node type: link
Node attributes: {"href":"https://markdoc.io"}

I was expecting

Node type: link
Node attributes: {"href":"https://markdoc.io", title: "markdoc link title"}

Version

0.1.1

Additional context

It looks like the source of the issue may be here

It looks like the handleAttrs function is only returning href for link nodes.

Not parsing regular markdown file tags

Hi Folks,

I am trying to assess markdoc for my react project on documentation. Custom tags look great! But I am worried about the regular markdown support. When I try to parse a markdown file I see below error as part of Markdoc.validate(ast). Is this something to do with any configuration or Am I missing anything here?

[{ type: 'tag', lines: [16, 17, 21, 22], location: { file: undefined, start: [Object], end: [Object] }, error: { id: 'tag-undefined', level: 'critical', message: "Undefined tag 'code'" } }, { type: 'tag', lines: [18, 20], location: { file: undefined, start: [Object], end: [Object] }, error: { id: 'tag-undefined', level: 'critical', message: "Undefined tag 'highlight'" } }, { type: 'tag', lines: [18, 20], location: { file: undefined, start: [Object], end: [Object] }, error: { id: 'tag-undefined', level: 'critical', message: "Undefined tag 'highlight'" } } ]

And below is my markdown content

`
{% code %}

{% highlight %}Inline tag 1{% /highlight %}
{% highlight %}Inline tag 2{% /highlight %}

{% /code %}
`

-TIA

How can I make markdoc with Next.js work like mdx with Next.js?

What happened?

I set up a demo repo for my purpose in here: markdoc-nextjs-demo.

From what I understand, @markdoc/next.js transforms markdown files into React components. So I should be able to import a md file and treat it as a React component in any place suitable, just like the way @next/mdx works.

Just like this:

// pages/getting-started.js

import MarkdownComponent from '../components/getting-started.md';

export default function GettingStarted(props) {
  return (
    <>
      <header>This is header</header>
      <main>
        <MarkdownComponent></MarkdownComponent>
      </main>
      <footer>This is footer</footer>
    </>
  );
}

But when I did that, an error occurred.

Server Error
TypeError: Cannot read properties of undefined (reading 'content')

This error happened while generating the page. Any console logs will be displayed in the terminal window.

CleanShot 2022-06-27 at 22 22 40@2x

The documentation on Next.js Layout does not have the same use case. I want to apply additional layouts in other routes other than App.component.

Is there another way to achieve this?

To reproduce

Demo repo markdoc-nextjs-demo.

Version

0.1.4

Additional context

No response

Unable to add custom tags in Next.js app on Windows

What happened?

When running a new NextJS app on a Windows machine running Node v14.19.3 using the markdoc example, the app fails to load, throwing a failed to compile error:

image

After some tinkering - I found that by removing the tags, the app / page would finally render.

To reproduce

  • run npx create-next-app --example https://github.com/markdoc/markdoc-starter
  • run npm run dev
  • App will fail to load and show the error above.

Version

0.1.2

Additional context

I tried setting up the project on a M1 Mac running node v16.13.0 and the app was able to compile and render. So I'm wondering if this is related to the OS or possibly the node version.

Confusing error on multiple markdoc sites

What happened?

@benguz and I need set up a markdoc site for a nonprofit.

We are getting this cryptic error, and the error message text cuts off strangely:

C:Users�enjaOneDriveDocumentsGitHub
eactjs.org�eta
ode_modules@markdoc
ext.jssrc
untime.js is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "c:" URIs.

To reproduce

@benguz followed the quick start docs.

Version

Latest

Additional context

Deploying on GitHub pages.

Next.js plugin - Does not contain a default export (imported as 'tags').

What happened?

I see the following error when building Next.js

Attempted import error: '/home/starptech/repositories/test/website/markdoc/tags/index.ts' does not contain a default export (imported as 'tags').

markdoc/tags/index.ts

/* Use this file to export your markdoc tags */
export * from './callout.markdoc'
export * from './cover.markdoc'
export * from './codeblock.markdoc'

I use the markdoc Next.js integration

To reproduce

  1. Create a markdoc example with Next.js integration
  2. Build the Next.js project.

Version

0.1.3

Additional context

"@markdoc/next.js": "^0.1.4",

Can't deploy markdoc.dev demo site

What happened?

Tried to deploy test site on a fresh Macbook pro but get an error.

Dependencies:

  • Installed node with brew install node

Trying to deploy markdoc.dev following the instructions at https://github.com/markdoc/docs:

Error message:

 jaan@laptop   ~/Dropbox/projects/onefact.org     deploy  npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"17.0.2" from the root project
npm ERR!   peer react@">= 16.8.0 < 19.0.0" from @docsearch/[email protected]
npm ERR!   node_modules/@docsearch/react
npm ERR!     @docsearch/react@"^3.1.0" from the root project
npm ERR!   5 more (@markdoc/next.js, next, react-dom, styled-jsx, use-sync-external-store)
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@">=15.5 <=16.x" from [email protected]
npm ERR! node_modules/react-codemirror2
npm ERR!   react-codemirror2@"^7.2.1" from the root project
npm ERR!
npm ERR! Conflicting peer dependency: [email protected]
npm ERR! node_modules/react
npm ERR!   peer react@">=15.5 <=16.x" from [email protected]
npm ERR!   node_modules/react-codemirror2
npm ERR!     react-codemirror2@"^7.2.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/jaan/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/jaan/.npm/_logs/2022-08-01T16_38_54_611Z-debug-0.log

Please see the file here:
eresolve-report.txt
2022-08-01T16_38_54_611Z-debug-0.log

Any help on how to debug? Need to finish this today :( @benguz and I deployed markdoc in the past so not sure what changed -- maybe a clean install on the new macbook??

To reproduce

See above.

Version

latest

Additional context

No response

Markdoc docs broken on Firefox for Android

What happened?

I visited the docs website and could only see about 5 pages. Turns out the navigation bar has broken breakpoint or broken Firefox support... There is no way to make it show without going into Desktop mode.

I found it quite bizarre that a documentation framework had such bare bones documentation... Until I received a link to the FAQ from @mfix-stripe and realized, 99% of the docs were not showing up for me.

Screenshot_20220512-075421

To reproduce

Open on a Pixel 6 Pro with Firefox for Android (It uses the Gecko rendering engine).

Version

1

Additional context

I presume it's just a desktop/mobile continuum breakpoint issue... Could be more a more serious presumption that all Mobile browsers run a WebKit based HTML rendering engine, or that all Android phones use V8.

can't compile next.js starter

What happened?

just cloned the repo, ran npm install followed by npm run dev and got this error after loading localhost:3000

./pages/index.md
C:\github\markdoc\next.js-starter\node_modules@markdoc\next.js\node_modules@markdoc\markdoc\dist\index.js:6648
return !!value?.$$mdtype;
^

SyntaxError: Unexpected token '.'

To reproduce

npm install
npm run dev

Version

latest

Additional context

No response

Markdoc formatter

I need to write a script that modifies Markdoc files. Specifically, it will add an id attribute to nodes that do not yet have one. For example, given the file:

# Debugging

# Running {% #running %}

I want to modify the file to:

# Debugging {% #d3adb33f %}

# Running {% #running %}

(Where d3adb33f is some fresh identifier, e.g. a UUID.)

I want to do this transform with a pipeline like

input --[Markdoc.parse]--> AST -> --[custom logic]--> AST --[Markdown.stringify]--> output

However, I don't see a Markdoc.stringify, or a Node.toString, or a Markdoc renderer, or anything like that.

Has anyone written a Markdown.stringify or similar? Or could you recommend some other way to achieve my goals?

Grammar railroad diagram

What happened?

Only an enhancement for documenting/understand the grammar with this tool https://www.bottlecaps.de/convert/ we can convert the tags.pegjs grammar to a format understood by https://www.bottlecaps.de/rr/ui and have a nice railroad diagram (https://en.wikipedia.org/wiki/Syntax_diagram).

Copy https://github.com/markdoc/markdoc/blob/main/src/grammar/tag.pegjs in to https://www.bottlecaps.de/convert/ on the Input grammar: textarea then click the Convert button then click the View Diagram to see the navigable railroad diagram, it can also be generated offline (see https://www.bottlecaps.de/rr/ui Welcome tab at the bottom).

To reproduce

See above

Version

No response

Additional context

No response

Can't create custom Image Node for Next.js

What happened?

Markdown automatically wraps a <p> around the whole image component. This results in a Hydration mismatch

Hydration failed because the initial UI does not match what was rendered on the server.

`Expected server HTML to contain a matching <div> in <p>` because I need a `div` in my component to make it work with `next/image`.
import * as React from 'react'
import NextImage from 'next/image'

export function Image({ src, alt }: { src: string; alt: string }) {
  return (
    <div style={{ position: 'relative', width: '300px', height: '500px' }}>
      <NextImage
        src={src}
        alt={alt}
        layout="fill"
        objectFit="contain"
        className="rounded object-cover shadow"
      />
    </div>
  )
}

To reproduce

See above.

Version

No response

Additional context

No response

Allow using variables for link hrefs

What happened?

What I'm trying

I'm trying to use a variable to populate a link. More complete example below, but something like:

'[Link]({% $linkVariable %})'

What I'd expect

I'd expect that the end result is a link element pointing to linkVariable.

e.g. If $linkVariable is "https://markdoc.io", something like:
<a href="https://markdoc.io">Link</a>

Actual result

Instead the resulting output is:

[Link](https://markdoc.io/)

That's the rendered output from Markdoc.renderers.react(), not an intermediary step which gets parsed further.

Question

Or maybe there's some other way of handling this? I'll probably create a custom tag in the meantime, but I'm not sure if it's expected that Markdoc should handle a variable in this way or not.

PS. Thanks for releasing Markdoc!

To reproduce

I started with a create-react-app output, and then replaced App.js with:

import Markdoc from '@markdoc/markdoc';
import React from 'react';

function App() {
  const md = [
    '- [Link 1](https://markdoc.io/)',
    '- [Link 2]({% $linkVariable %})',
  ].join('\n');

  const ast = Markdoc.parse(md);
  const content = Markdoc.transform(
    ast,
    {
      variables: {
        linkVariable: 'https://markdoc.io/',
      },
    },
  );

  return (
    <div className="App">
      {Markdoc.renderers.react(content, React, {  })}
    </div>
  );
}

export default App;

The output is:

* Link 1
* [Link 2](https://markdoc.io/)

Where "Link 1" is a proper link and the 2nd line looks like that output verbatim. It prints the markdown, not the rendered markdown.

Version

0.1.2

Additional context

Possible Test Case

I added the following to src/parser.test.ts

+    it('in a link', function () {
+      const example = convert(`
+      [foo]({% bar %})
+      `);
+
+      expect(example).toDeepEqualSubset({
+        type: 'document',
+        children: [
+          {
+            type: 'paragraph',
+            children: [
+              {
+                type: 'inline',
+                children: [
+                  {
+                    type: 'link',
+                    attributes: { href: new Variable(['bar'], null) },
+                    children:  [{
+                      type: 'text',
+                      attributes: { content: 'foo' },
+                    }],
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      });
+    });
+

markdown-it

It seems to me that this occurs because of the way markdown-it does the parsing. Because the parsing comes before Markdoc's own variable substitution, I'm not sure if this is something that's actually addressable.

Types for async transform

What happened?

Seem typings were not updated for async transform(node, config)

[2022-07-18T06:09:47.224Z] cli/src/services/markdoc/imageUpload.ts(55,9): error TS2322: Type '(node: Node, config: Readonly<Partial<{ nodes: Partial<Record<NodeType, Schema<Readonly<Partial<...>>, string>>>; tags: Record<string, Schema<...>>; variables: Record<...>; functions: Record<...>; partials: Record<...>; validation?: { ...; } | undefined; }>>) => Promise<...>' is not assignable to type '(node: Node, config: Readonly<Partial<{ nodes: Partial<Record<NodeType, Schema<Readonly<Partial<...>>, string>>>; tags: Record<string, Schema<...>>; variables: Record<...>; functions: Record<...>; partials: Record<...>; validation?: { ...; } | undefined; }>>) => RenderableTreeNodes'.
[2022-07-18T06:09:47.224Z]   Type 'Promise<Tag>' is not assignable to type 'RenderableTreeNodes'.

To reproduce

Declare custom configuration with async method:

export const replaceImagesOnTransform = (directory: string): Schema => ({
  render: 'img',
  async transform(node, config) {
    const attributes = node.transformAttributes(config);
    const location = getLocation(attributes.src, directory);
    const src = await uploadSingleFile(location);

    return new Tag('img', {...attributes, src}, node.transformChildren(config));
  },
});

Version

0.1.4

Additional context

#90

No validation on partials

What happened?

Using a partial that doesnt exist fails silently, I don't know if this is intended, but I think since integrity of the docs depends on every piece "working" partials should have a validation error.

Is this intended for some specific reason?

I ended up adding the validation on my side, but if this is something that could go inside of the default functionality I'll be glad to make a PR.

import { tags } from '@markdoc/markdoc';

const config: Config = {
    tags: {
        ...tags,
        partial: {
            ...tags.partial,
            validate: (node, config) => {
                const { partials = {} } = config;
                const { file } = node.attributes;
                const partial: Node | Node[] = partials[file];

                if (!partial) {
                    return [
                        {
                            id: 'partial-children',
                            level: 'critical',
                            message: `Partial ${file} not found`,
                            location: node.location
                        }
                    ];
                }

                return [];
            }
        }
    }
};

To reproduce

const doc = `{% partial file="non-existent.md" /%}`;
const ast = Markdoc.parse(doc);
const errors = Markdoc.validate(ast, config);
console.log(errors) // []

Version

0.1.3

Additional context

No response

Thank you! I think this library is very interesting, I'm currently evaluating if it fits our needs

Crash with particular title input

What happened?

Providing specific content related to the title crashes the application: "Application error: a client-side exception has occurred (see the browser console for more information)."

framework-5f4595e5518b5600.js:1 TypeError: Cannot read properties of null (reading 'title')
    at 605040ef-5bf360b804c2c400.js:1:117210
    at Array.reduce (<anonymous>)
    at Se.resolve (605040ef-5bf360b804c2c400.js:1:117191)
    at Te (605040ef-5bf360b804c2c400.js:1:117674)
    at Te (605040ef-5bf360b804c2c400.js:1:117792)
    at rt.resolve (605040ef-5bf360b804c2c400.js:1:123029)
    at 605040ef-5bf360b804c2c400.js:1:123005
    at Array.map (<anonymous>)
    at rt.resolve (605040ef-5bf360b804c2c400.js:1:122995)
    at 605040ef-5bf360b804c2c400.js:1:123005

To reproduce

The following content crashes the demo app:

---
#
---

(i.e. deleting title: What is Markdoc? and replacing it with #)

Version

Unsure, but whichever the demo page is using.

Additional context

No response

Attempted import error when deploying to vercel

What happened?

Attempted import error: '/vercel/path0/markdoc/tags/index.ts' does not contain a default export (imported as 'tags'). Also unable to deploy to vercel

To reproduce

Clone this repository and npm run build/yarn build

Version

0.1.2

Additional context

No response

Typescript for Validation of Attributes

I am reading the documentation and see that a large part of the validation logic for attributes is to create a Javascript object that basically has the same information that Typescript would have.

I am curious if there is a goal to create a Typescript plugin or better built-in support for Typescript? As you can imagine, writing all that code is tedious, and Typescript is a very powerful and widely adopted tool to convey that same information.

Support for inline and block HTML content

The commonMark spec describes how HTML blocks and Raw HTML should be treated:

4.6 HTML blocks

An HTML block is a group of lines that is treated as raw HTML (and will not be escaped in HTML output).

6.6 Raw HTML

Text between < and > that looks like an HTML tag is parsed as a raw HTML tag and will be rendered in HTML without escaping. Tag and attribute names are not limited to current HTML tags, so custom tags (and even, say, DocBook tags) may be used.

Example:

# Test <em>Emphasis</em>

<a href="http://github.com/markdoc/markdoc">GitHub</a>

Are there plans to support this aspect of the spec?

If so, it's worth noting that other markdown implementations I've seen tend to follow the spec literally and do not parse HTML content in any way. In other words, raw HTML content is just treated as a string in the AST. The downside to this approach is that it prevents you from introspecting raw HTML content.

For example, if you wish to write a validator that ensures the integrity of links on a page you don't really care whether the links are authored natively in markdown or as raw <a> tags. Likewise, when generating a table of contents, you want to generate IDs for and include all header tags.

Cheers, and congrats on the first release!

Passing variables to transformChildren()

I'm attempting to pass in additional variables when calling node.transformChildren(), but they seem to be ignored in favor of the variables passed in on transform(). I expected it to work similar to the partial tag, but it doesn't seem to.

Example

const source = `
{% custom %}
# {% $name %}
{% /custom %}
`;

const custom = {
  transform(node, config) {
    const variables = { ...config.variables, name: "custom" };
    const scopedConfig = { ...config, variables };
    return node.transformChildren(scopedConfig);
  },
};

const ast = Markdoc.parse(source);
const config = { tags: { custom }, variables: { name: "original" } };
const content = Markdoc.transform(ast, config);
const html = Markdoc.renderers.html(content);

Output

<article><h1>original</h1></article>

Any ideas what I'm doing wrong here?

Use registered schema in Next.js validation

What happened?

I changed a fresh Next.js started clone in a way that should (as far as I understand) clearly trigger a schema validation error but I didn't get any error from npm run dev or npm run build. I expected the build to fail both using the dev and the build script.

To reproduce

  1. Clone the Next.js starter project and install dependencies using npm install
  2. Modify the callout tag to only allow paragraphs as children
export const callout = {
   render: Callout,
   description: 'Display the enclosed content in a callout box',
-  children: ['paragraph', 'tag', 'list'],
+  children: ['paragraph'],
   attributes: {
     title: {
       type: String,
  1. Start the development server with npm run dev and open the page in a browser
  2. Nest two callout tags on a page (which should be disallowed)
{% callout %}
{% callout %}
This is a full-featured boilerplate for a creating a documentation website using Markdoc and Next.js.
{% /callout %}
{% /callout %}
  1. The page refreshes with the nested callout tags and no error is shown

You can also add a validation function that always fails to the definition of callout which appears to have no effect either.

import {Callout} from '../../components';

export const callout = {
  render: Callout,
  description: 'Display the enclosed content in a callout box',
  children: ['paragraph', 'tag', 'list'],
  attributes: {
    title: {
      type: String,
      description: 'The title displayed at the top of the callout',
    },
  },
  validate(node, config) {
    return [
      {
        id: "my-error",
        level: 'critical',
        message: "This should fail",
      }
    ]
  },
};

All of this also applies to nodes.

Version

0.1.4

Additional context

The exact commit of the starter repository used is cf36368f405a41499aded8b61b136c0bda44c0e3.

Translations and i18n

What’s the best way to handle translations, internationalization i18n, etc. with markdoc?

Hot reloading breaks after one minute with the Next.js starter

What happened?

Whenever I run npm run dev and leave the page untouched in the browser and editor for about a minute, hot reloading doesn't have an effect anymore. The Next.js reload indicator in the lower right corner still shows up but the page does not update when I change something in my sources. Refreshing the page or performing any sort of page navigation (without a full reload) fixes hot reloading until it breaks again after one minute.

To reproduce

  1. Clone the Next.js starter project and install dependencies using npm install
  2. Start npm run dev
  3. Load the page in a browser
  4. Wait for one minute
  5. Change something in a page file
  6. The Next.js reloading indicator shows up but the page is not updated

Version

0.1.4

Additional context

The exact commit of the starter repository used is cf36368f405a41499aded8b61b136c0bda44c0e3.

This problem doesn't occur with a Next.js starter project without Markdoc, so it doesn't seem to be a Next.js issue.

I'm also not seeing any errors or warnings in the browser console or network tab.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.