Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rdela/32603eecc215cab3374e9a973f07bca0 to your computer and use it in GitHub Desktop.
Save rdela/32603eecc215cab3374e9a973f07bca0 to your computer and use it in GitHub Desktop.

Revisions

  1. @d3v1an7 d3v1an7 created this gist Jul 30, 2024.
    72 changes: 72 additions & 0 deletions prettier-plugin-js-frontmatter.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@
    import prettier from 'prettier';
    import babelParser from 'prettier/plugins/babel';
    import htmlParser from 'prettier/plugins/html';
    const frontmatterRegex = /^---js\n([\s\S]*?)\n---\n/;

    function parse(text, options) {
    const match = text.match(frontmatterRegex);
    if (match) {
    const frontmatter = match[1];
    const content = text.slice(match[0].length);
    return {
    type: 'frontmatterDocument',
    frontmatter,
    content,
    };
    }
    return {
    type: 'root',
    text: text,
    };
    }

    async function print(path, options, print) {
    const node = path.getValue();
    if (node.type === 'frontmatterDocument') {
    // Ensure babel can interpret the frontmatter by wrapping it as an expression.
    const prependedFrontmatter = `(${node.frontmatter})`;
    const formattedFrontmatterWithReturn = await prettier.format(
    prependedFrontmatter,
    {
    ...options,
    parser: 'babel',
    plugins: [babelParser],
    },
    );
    // Switch formatted code back to object literal by removing `(` and `);\n`.
    const formattedFrontmatterWithoutReturn =
    formattedFrontmatterWithReturn.slice(1, -3);
    // Format remaining context as HTML
    const formattedContent = await prettier.format(node.content, {
    ...options,
    parser: 'html',
    plugins: [htmlParser],
    });
    return `---js\n${formattedFrontmatterWithoutReturn}\n---\n\n${formattedContent}`;
    }
    // No js frontmatter detected, just format as HTML.
    const formattedContent = await prettier.format(node.text, {
    ...options,
    parser: 'html',
    plugins: [htmlParser],
    });

    return formattedContent;
    }

    export default {
    parsers: {
    'js-frontmatter': {
    parse,
    astFormat: 'js-frontmatter',
    locStart: () => 0,
    locEnd: () => 0,
    },
    },
    printers: {
    'js-frontmatter': {
    print,
    },
    },
    options: {},
    };
    12 changes: 12 additions & 0 deletions prettier.config.example.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    /** @type {import('prettier').Config} */
    export default {
    plugins: ['./prettier-plugin-js-frontmatter.js'],
    overrides: [
    {
    files: '*.webc',
    options: {
    parser: 'js-frontmatter',
    },
    },
    ],
    };