diff --git a/README.md b/README.md index de2b4c5..58e5496 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,10 @@ Example code blocks are rendered with a [Svelte component](./src/lib/Example.sve examples, { defaults: { - Wrapper: '/src/lib/Example.svelte' + Wrapper: '/src/lib/Example.svelte', + + // or if the component is a named export + Wrapper: ['some-package', 'CustomExample'] // -> import { CustomExample } from 'some-package' } } ] diff --git a/playwright.config.js b/playwright.config.js index 679624d..2f2a8d1 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,6 +1,7 @@ /** @type {import('@playwright/test').PlaywrightTestConfig} */ const config = { testDir: './src/routes/tests', + timeout: 10000, webServer: { command: 'npm run build:site && npm run preview', port: 4173 diff --git a/src/lib/remark.js b/src/lib/remark.js index a1a107e..ed3b9e2 100644 --- a/src/lib/remark.js +++ b/src/lib/remark.js @@ -14,6 +14,9 @@ const RE_SCRIPT_START = const RE_SCRIPT_BLOCK = /()([\s\S]*?)(<\/script>)/g const RE_STYLE_BLOCK = /()([\s\S]*?)(<\/style>)/g +// parses key=value pairs from a string. supports strings, numbers, booleans, and arrays +const RE_PARSE_META = /(\w+=\d+|\w+="[^"]*"|\w+=\[[^\]]*\]|\w+)/g + export const EXAMPLE_MODULE_PREFIX = '___mdsvexample___' export const EXAMPLE_COMPONENT_PREFIX = 'Mdsvexample___' @@ -66,7 +69,10 @@ export default function (options = {}) { // add imports for each generated example let scripts = '' examples.forEach((example, i) => { - const imp = `import Example from "${example.Wrapper}";\n` + const imp = + typeof example.Wrapper === 'string' + ? `import Example from "${example.Wrapper}";\n` + : `import { ${example.Wrapper[1]} as Example } from "${example.Wrapper[0]}";\n` if (!scripts.includes(imp)) { scripts += imp @@ -101,12 +107,18 @@ export default function (options = {}) { function parseMeta(meta) { const result = {} - const meta_parts = meta.match(/(?:[^\s"]+|"[^"]*")+/g) ?? [] + const meta_parts = meta.match(RE_PARSE_META) ?? [] for (let i = 0; i < meta_parts.length; i++) { const [key, value = 'true'] = meta_parts[i].split('=') - result[key] = JSON.parse(value) + try { + result[key] = JSON.parse(value) + } catch (e) { + const error = new Error(`Unable to parse meta \`${key}=${value}\` - ${e.message}`) + error.stack = e.stack + throw error + } } return result diff --git a/src/routes/tests/meta/array/+page.svx b/src/routes/tests/meta/array/+page.svx index a1f41eb..35a091a 100644 --- a/src/routes/tests/meta/array/+page.svx +++ b/src/routes/tests/meta/array/+page.svx @@ -1,3 +1,3 @@ -```svelte example custom=["hello/world"] Wrapper="../MetaWrapper.svelte" +```svelte example space=["hello", "world"] nospace=["hello","world"] Wrapper="../MetaWrapper.svelte" ``` diff --git a/src/routes/tests/meta/meta.spec.mjs b/src/routes/tests/meta/meta.spec.mjs index 2dd7e05..d45716d 100644 --- a/src/routes/tests/meta/meta.spec.mjs +++ b/src/routes/tests/meta/meta.spec.mjs @@ -33,9 +33,11 @@ test('wrapper and custom meta', async ({ page }) => { test('array meta', async ({ page }) => { await page.goto('/tests/meta/array') + const meta = await getMeta(page) - expect(meta.custom).toEqual(['hello/world']) + expect(meta.space).toEqual(['hello', 'world']) + expect(meta.nospace).toEqual(['hello', 'world']) }) test('filename meta', async ({ page }) => { diff --git a/src/routes/tests/meta/wrapper-named-export/+page.svx b/src/routes/tests/meta/wrapper-named-export/+page.svx new file mode 100644 index 0000000..9b9cbd6 --- /dev/null +++ b/src/routes/tests/meta/wrapper-named-export/+page.svx @@ -0,0 +1,3 @@ +```svelte example Wrapper=["../wrappers.js", "MetaWrapper"] + +``` diff --git a/src/routes/tests/meta/wrappers.js b/src/routes/tests/meta/wrappers.js new file mode 100644 index 0000000..d4a66ef --- /dev/null +++ b/src/routes/tests/meta/wrappers.js @@ -0,0 +1,3 @@ +import MetaWrapper from './MetaWrapper.svelte' + +export { MetaWrapper }