diff --git a/.babelrc.js b/.babelrc.js deleted file mode 100644 index 21f6d4e..0000000 --- a/.babelrc.js +++ /dev/null @@ -1,23 +0,0 @@ -const ignore = process.env.IGNORE_FILES ? ['**/*.test.ts', '**/*.d.ts'] : []; - -module.exports = { - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - '@babel/preset-typescript', - '@babel/preset-react', - ], - env: { - esm: { - presets: [ - [ - '@babel/preset-env', - { - modules: false, - targets: { node: 'current' }, - }, - ], - ], - }, - }, - ignore, -}; diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 89493c5..0000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/**/*.js -storybook-static/**/*.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 66750fc..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - extends: ['@storybook/eslint-config-storybook'], - overrides: [ - { - files: ['**/*.tsx'], - rules: { - 'react/prop-types': 'off', - 'react/require-default-props': 'off', - 'react/default-props-match-prop-types': 'off', - }, - }, - ], - parserOptions: { - project: ['tsconfig.json'], - }, -}; diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 891c617..8786bfe 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..2f28cea 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,6 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2b0f6e2..fa2ffae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,10 +12,10 @@ jobs: - name: Prepare repository run: git fetch --unshallow --tags - - name: Use Node.js 14.x + - name: Use Node.js 16.x uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 16.x - name: Install dependencies uses: bahmutov/npm-install@v1 @@ -25,4 +25,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - yarn release \ No newline at end of file + yarn release diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 216aa01..bf4b0dc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,19 +8,14 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Use Node.js 14.x + - name: Use Node.js 16.x uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 16.x - name: Install dependencies uses: bahmutov/npm-install@v1 - - name: Run lint - run: | - yarn lint - - name: Run tests run: | yarn test - diff --git a/.storybook/main.js b/.storybook/main.js index b7c5662..83e3820 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,12 +1,7 @@ -const { createCompiler } = require('../dist/cjs'); module.exports = { - stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: [ - '@storybook/addon-links', - '@storybook/addon-essentials', - '@storybook/addon-interactions', - ], - framework: '@storybook/react', + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + framework: '@storybook/react-webpack5', webpackFinal: async (config) => { const rules = (config.module.rules || []).filter( (rule) => !rule.test?.toString().endsWith('\\.mdx$/') @@ -26,6 +21,9 @@ module.exports = { }, { loader: require.resolve('../loader'), + options: { + mdxCompileOptions: {}, + }, }, ], }); diff --git a/.storybook/preview.js b/.storybook/preview.js index 48afd56..d391458 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,9 +1,9 @@ export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, -} \ No newline at end of file +}; diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6534f37 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deepscan.enable": true +} diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 0000000..e6ffbd4 --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], +}; diff --git a/jest.config.js b/jest.config.js index 851b11b..94b9a9b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,10 @@ module.exports = { testMatch: ['**/*.test.ts'], + // transform everything including node_modules + transformIgnorePatterns: [], + // deal with missing main fields + moduleNameMapper: { + 'estree-walker': 'estree-walker/src', + 'is-reference': 'is-reference/src', + }, }; diff --git a/loader.js b/loader.js index c9a80cb..f9749e6 100644 --- a/loader.js +++ b/loader.js @@ -1,10 +1,18 @@ -const { getOptions } = require('loader-utils'); -const mdx = require('@mdx-js/mdx'); -const { createCompiler } = require('./dist/cjs'); +const { dirname } = require('path'); +const { compile } = require('./dist/index'); +// FIXME: we shouldn't be doing this, but we need it +// for react MDX story definitions, e.g. +// +//
hi>
+// +// Which generates the code: +// +// export const foo = () =>
hi
; +const mdxReactPackage = dirname(require.resolve('@mdx-js/react/package.json')); const DEFAULT_RENDERER = ` -import React from 'react' -import { mdx } from '@mdx-js/react' +import React from 'react'; +import { mdx } from '${mdxReactPackage}'; `; // Lifted from MDXv1 loader @@ -15,26 +23,19 @@ import { mdx } from '@mdx-js/react' // - MDX compiler built in const loader = async function (content) { const callback = this.async(); - // this.getOptions() is webpack5 only - const queryOptions = this.getOptions ? this.getOptions() : getOptions(this); - const options = Object.assign({}, queryOptions, { + const options = Object.assign({}, this.getOptions(), { filepath: this.resourcePath, }); - if (!options.skipCsf) { - options.compilers = [createCompiler(options), ...(options.compilers || [])]; - } let result; - try { - result = await mdx(content, options); + result = await compile(content, options); } catch (err) { + console.error('Error loading:', this.resourcePath); return callback(err); } - const { renderer = DEFAULT_RENDERER } = options; - - const code = `${renderer}\n${result}`; + const code = `${DEFAULT_RENDERER}\n${result}`; return callback(null, code); }; diff --git a/package.json b/package.json index e453bc2..d510803 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "description": "MDXv1 to CSF webpack compiler and loader", "repository": { "type": "git", - "url": "https://github.com/storybookjs/csf-mdx1" + "url": "https://github.com/storybookjs/csf-mdx2" }, "author": "Michael Shilman ", "license": "MIT", - "main": "dist/cjs/index.js", - "module": "dist/esm/index.js", - "types": "dist/ts/index.d.ts", + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", "files": [ "dist/**/*", "README.md", @@ -18,86 +18,69 @@ "*.d.ts" ], "scripts": { - "clean": "rimraf ./dist", - "buildBabel": "IGNORE_FILES=true concurrently \"yarn buildBabel:cjs\" \"yarn buildBabel:esm\"", - "buildBabel:cjs": "babel ./src -d ./dist/cjs --extensions \".js,.jsx,.ts,.tsx\"", - "buildBabel:esm": "babel ./src -d ./dist/esm --env-name esm --extensions \".js,.jsx,.ts,.tsx\"", - "buildTsc": "tsc --declaration --emitDeclarationOnly --outDir ./dist/ts", - "prebuild": "yarn clean", - "build": "concurrently \"yarn buildBabel\" \"yarn buildTsc\"", - "build:watch": "concurrently \"yarn buildBabel:cjs -- --watch\" \"yarn buildTsc -- --watch\"", "test": "jest", - "start": "yarn \"build:watch\" \"yarn storybook -- --no-manager-cache --quiet\"", - "release": "yarn build && auto shipit", - "lint": "eslint --cache --cache-location=.cache/eslint --ext .js,.jsx,.html,.ts,.tsx,.mjs", + "build": "tsup", + "start": "yarn build && yarn storybook -- --quiet\"", + "release": "STORYBOOK_DISABLE_TELEMETRY=1 yarn build && auto shipit", + "storybook": "STORYBOOK_DISABLE_TELEMETRY=1 STORYBOOK_ENABLE_CRASH_REPORTS=false storybook dev -p 6006", + "build-storybook": "storybook build", "prettier": "prettier", - "prepare": "husky install", - "storybook": "start-storybook -p 6006", - "build-storybook": "build-storybook" + "prepare": "husky install" }, "dependencies": { - "@babel/generator": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/preset-env": "^7.12.11", - "@babel/types": "^7.12.11", "@mdx-js/mdx": "^1.6.22", - "@mdx-js/react": "^1.6.22", - "@types/lodash": "^4.14.167", - "js-string-escape": "^1.0.1", - "loader-utils": "^2.0.4", - "lodash": "^4.17.21", - "prettier": ">=2.2.1 <=2.3.0", - "ts-dedent": "^2.0.0" + "@mdx-js/react": "^1.6.22" }, "devDependencies": { - "@auto-it/released": "^10.32.6", - "@babel/cli": "^7.12.1", "@babel/core": "^7.12.3", + "@babel/generator": "^7.12.11", + "@babel/parser": "^7.12.11", "@babel/preset-env": "^7.12.1", "@babel/preset-react": "^7.12.5", "@babel/preset-typescript": "^7.13.0", - "@babel/template": "^7.14.5", + "@babel/types": "^7.14.8", "@jest/types": "^27.0.6", - "@storybook/addon-actions": "^6.4.19", - "@storybook/addon-essentials": "^6.4.19", - "@storybook/addon-interactions": "^6.4.19", - "@storybook/addon-links": "^6.4.19", - "@storybook/eslint-config-storybook": "^3.1.2", - "@storybook/react": "^6.4.19", - "@storybook/testing-library": "^0.0.9", + "@storybook/addon-actions": "next", + "@storybook/addon-essentials": "next", + "@storybook/addon-interactions": "next", + "@storybook/addon-links": "next", + "@storybook/react": "next", + "@storybook/react-webpack5": "next", + "@storybook/testing-library": "next", "@testing-library/dom": "^8.1.0", "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", "@types/jest": "^27.0.3", "@types/js-string-escape": "^1.0.1", + "@types/lodash": "^4.14.167", "@types/node": "^16.4.1", "auto": "^10.3.0", "babel-jest": "^27.0.6", "babel-loader": "^8.1.0", "concurrently": "^7.0.0", - "eslint": "^7.32.0", "husky": ">=6", "jest": "^27.0.6", "jest-environment-jsdom": "^27.0.6", + "js-string-escape": "^1.0.1", "lint-staged": ">=10", - "prompts": "^2.4.2", + "lodash": "^4.17.21", + "prettier": "^2.3.1", "react": "^17.0.1", "react-dom": "^17.0.1", - "rimraf": "^3.0.2", + "storybook": "next", "ts-dedent": "^2.2.0", "ts-jest": "^27.0.4", + "tsup": "^6.2.2", "typescript": "^4.2.4" }, + "resolutions": { + "@types/estree": "1.0.0" + }, "lint-staged": { "*.{ts,js,css,md}": "prettier --write" }, - "auto": { - "plugins": [ - "npm", - "released" - ] - }, "publishConfig": { "access": "public" - } + }, + "packageManager": "yarn@1.22.9" } diff --git a/src/index.ts b/src/index.ts index 3f5139b..615a345 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,17 @@ import mdx from '@mdx-js/mdx'; import { createCompiler, MdxOptions } from './sb-mdx-plugin'; -export const compile = async (code: string, options?: MdxOptions) => - mdx(code, { compilers: options?.skipCsf ? [] : [createCompiler(options)] }); +import type { CompileOptions, MdxCompileOptions, JSXOptions } from './types'; +import { transformJSXAsync, transformJSXSync } from './jsx'; -export const compileSync = (code: string, options?: MdxOptions) => - mdx.sync(code, { compilers: options?.skipCsf ? [] : [createCompiler(options)] }); +export type { CompileOptions, MdxCompileOptions, JSXOptions }; -export * from './sb-mdx-plugin'; +export const compile = async (code: string, options?: MdxOptions) => { + const result = await mdx(code, { compilers: options?.skipCsf ? [] : [createCompiler(options)] }); + return transformJSXAsync(result, options?.jsxOptions); +}; + +export const compileSync = (code: string, options?: MdxOptions) => { + const result = mdx.sync(code, { compilers: options?.skipCsf ? [] : [createCompiler(options)] }); + return transformJSXSync(result, options?.jsxOptions); +}; diff --git a/src/jsx.ts b/src/jsx.ts new file mode 100644 index 0000000..3e4a560 --- /dev/null +++ b/src/jsx.ts @@ -0,0 +1,36 @@ +import { transformAsync, transformSync } from '@babel/core'; +// @ts-expect-error (no types, but perfectly valid) +import presetReact from '@babel/preset-react'; +import type { JSXOptions, BabelOptions } from './types'; + +function getBabelOptions(jsxOptions: JSXOptions): BabelOptions { + return { + filename: 'file.js', + sourceType: 'module', + configFile: false, + babelrc: false, + presets: [ + [ + presetReact, + { + runtime: 'automatic', + ...jsxOptions, + }, + ], + ], + }; +} + +export const transformJSXAsync = async (input: string, jsxOptions: JSXOptions) => { + const babelOptions = getBabelOptions(jsxOptions); + const { code } = await transformAsync(input, babelOptions); + + return code; +}; + +export const transformJSXSync = (input: string, jsxOptions: JSXOptions) => { + const babelOptions = getBabelOptions(jsxOptions); + const { code } = transformSync(input, babelOptions); + + return code; +}; diff --git a/src/sb-mdx-plugin.test.ts b/src/sb-mdx-plugin.test.ts index f7f25a2..798f111 100644 --- a/src/sb-mdx-plugin.test.ts +++ b/src/sb-mdx-plugin.test.ts @@ -30,6 +30,24 @@ function clean(content: any) { .trim(); } +function compile(content: any) { + const code = mdx.sync(content, { + // filepath: filePath, + compilers: [createCompiler({})], + }); + + return prettier + .format(code, { + parser: 'babel', + printWidth: 100, + tabWidth: 2, + bracketSpacing: true, + trailingComma: 'es5', + singleQuote: true, + }) + .trim(); +} + const fixturesDir = path.join(__dirname, '..', '..', '__testfixtures__', 'mdx'); const snap = (prefix: string) => path.join(fixturesDir, `${prefix}.output.snapshot`); @@ -68,6 +86,7 @@ describe('docs-mdx-compiler-plugin', () => { name: 'B', }, }, + tags: ['stories-mdx'], includeStories: ['componentNotes'], }; @@ -96,6 +115,7 @@ describe('docs-mdx-compiler-plugin', () => { title: 'Button', id: 'button-id', component: Button, + tags: ['stories-mdx'], includeStories: ['componentNotes'], }; @@ -131,7 +151,11 @@ describe('docs-mdx-compiler-plugin', () => { export const _Foo_ = MyStories.Foo; _Foo_.storyName = 'renamed'; - const componentMeta = { title: 'MDX/CSF imports', includeStories: ['_Basic_', '_Other_', '_Foo_'] }; + const componentMeta = { + title: 'MDX/CSF imports', + tags: ['stories-mdx'], + includeStories: ['_Basic_', '_Other_', '_Foo_'], + }; const mdxStoryNameToKey = { _Basic_: '_Basic_', _Other_: '_Other_', renamed: '_Foo_' }; `); @@ -173,6 +197,7 @@ describe('docs-mdx-compiler-plugin', () => { ), ], + tags: ['stories-mdx'], includeStories: ['one'], }; @@ -198,7 +223,7 @@ describe('docs-mdx-compiler-plugin', () => { __page.parameters = { docsOnly: true }; - const componentMeta = { title: 'docs-only', includeStories: ['__page'] }; + const componentMeta = { title: 'docs-only', tags: ['stories-mdx'], includeStories: ['__page'] }; const mdxStoryNameToKey = {}; `); @@ -235,6 +260,7 @@ describe('docs-mdx-compiler-plugin', () => { foo: 1, }), ], + tags: ['stories-mdx'], includeStories: ['one'], }; @@ -256,7 +282,11 @@ describe('docs-mdx-compiler-plugin', () => { __page.parameters = { docsOnly: true }; - const componentMeta = { title: "Addons/Docs/what's in a title?", includeStories: ['__page'] }; + const componentMeta = { + title: "Addons/Docs/what's in a title?", + tags: ['stories-mdx'], + includeStories: ['__page'], + }; const mdxStoryNameToKey = {}; `); @@ -291,7 +321,11 @@ describe('docs-mdx-compiler-plugin', () => { helloStory.storyName = 'hello story'; helloStory.parameters = { storySource: { source: '' } }; - const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] }; + const componentMeta = { + title: 'Button', + tags: ['stories-mdx'], + includeStories: ['one', 'helloStory'], + }; const mdxStoryNameToKey = { one: 'one', 'hello story': 'helloStory' }; `); @@ -333,6 +367,7 @@ describe('docs-mdx-compiler-plugin', () => { notes: 'component notes', }, component: Button, + tags: ['stories-mdx'], includeStories: ['componentNotes', 'storyNotes'], }; @@ -384,6 +419,7 @@ describe('docs-mdx-compiler-plugin', () => { notes: 'component notes', }, component: Button, + tags: ['stories-mdx'], includeStories: ['helloButton', 'two'], }; @@ -428,7 +464,11 @@ describe('docs-mdx-compiler-plugin', () => { }; componentNotes.parameters = { storySource: { source: 'args => ' } }; - const componentMeta = { title: 'Button', includeStories: ['componentNotes'] }; + const componentMeta = { + title: 'Button', + tags: ['stories-mdx'], + includeStories: ['componentNotes'], + }; const mdxStoryNameToKey = { 'component notes': 'componentNotes' }; `); @@ -466,7 +506,7 @@ describe('docs-mdx-compiler-plugin', () => { text.storyName = 'text'; text.parameters = { storySource: { source: "'Plain text'" } }; - const componentMeta = { title: 'Text', includeStories: ['text'] }; + const componentMeta = { title: 'Text', tags: ['stories-mdx'], includeStories: ['text'] }; const mdxStoryNameToKey = { text: 'text' }; `); @@ -517,6 +557,7 @@ describe('docs-mdx-compiler-plugin', () => { const componentMeta = { title: 'Button', + tags: ['stories-mdx'], includeStories: ['one', 'helloStory', 'wPunctuation', '_1FineDay'], }; @@ -549,7 +590,11 @@ describe('docs-mdx-compiler-plugin', () => { basic.storyName = 'basic'; basic.parameters = { storySource: { source: 'basicFn' } }; - const componentMeta = { title: 'story-function-var', includeStories: ['basic'] }; + const componentMeta = { + title: 'story-function-var', + tags: ['stories-mdx'], + includeStories: ['basic'], + }; const mdxStoryNameToKey = { basic: 'basic' }; `); @@ -614,7 +659,11 @@ describe('docs-mdx-compiler-plugin', () => { storySource: { source: '

Hello Child #1

\\n

Hello Child #2

' }, }; - const componentMeta = { title: 'Multiple', includeStories: ['multipleChildren'] }; + const componentMeta = { + title: 'Multiple', + tags: ['stories-mdx'], + includeStories: ['multipleChildren'], + }; const mdxStoryNameToKey = { 'multiple children': 'multipleChildren' }; `); @@ -661,7 +710,11 @@ describe('docs-mdx-compiler-plugin', () => { }, }; - const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] }; + const componentMeta = { + title: 'MDX|Welcome', + tags: ['stories-mdx'], + includeStories: ['toStorybook'], + }; const mdxStoryNameToKey = { 'to storybook': 'toStorybook' }; `); @@ -701,7 +754,11 @@ describe('docs-mdx-compiler-plugin', () => { __page.parameters = { docsOnly: true }; - const componentMeta = { title: \`\${titleFunction('template')}\`, includeStories: ['__page'] }; + const componentMeta = { + title: \`\${titleFunction('template')}\`, + tags: ['stories-mdx'], + includeStories: ['__page'], + }; const mdxStoryNameToKey = {}; `); @@ -778,7 +835,7 @@ describe('docs-mdx-compiler-plugin', () => { basic.storyName = 'Basic'; basic.parameters = { storySource: { source: '' } }; - const componentMeta = { component: Button, includeStories: ['basic'] }; + const componentMeta = { component: Button, tags: ['stories-mdx'], includeStories: ['basic'] }; const mdxStoryNameToKey = { Basic: 'basic' }; `); @@ -799,7 +856,12 @@ describe('docs-mdx-compiler-plugin', () => { basic.storyName = 'Basic'; basic.parameters = { storySource: { source: '{}' } }; - const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] }; + const componentMeta = { + title: 'Button', + component: Button, + tags: ['stories-mdx'], + includeStories: ['basic'], + }; const mdxStoryNameToKey = { Basic: 'basic' }; `); @@ -824,6 +886,7 @@ describe('docs-mdx-compiler-plugin', () => { title: 'Button', component: Button, render: (args) =>