@astrojs/markdown-remark 2.0.0-beta.0 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/CHANGELOG.md +63 -0
  3. package/dist/index.js +11 -25
  4. package/dist/rehype-collect-headings.js +4 -14
  5. package/dist/remark-content-rel-image-error.js +2 -0
  6. package/dist/remark-shiki.js +2 -2
  7. package/dist/types.d.ts +1 -3
  8. package/package.json +7 -15
  9. package/src/index.ts +11 -30
  10. package/src/rehype-collect-headings.ts +3 -19
  11. package/src/remark-content-rel-image-error.ts +2 -0
  12. package/src/remark-shiki.ts +2 -2
  13. package/src/types.ts +1 -3
  14. package/test/autolinking.test.js +10 -75
  15. package/test/entities.test.js +5 -14
  16. package/test/plugins.test.js +2 -0
  17. package/test/test-utils.js +3 -0
  18. package/dist/mdast-util-mdxish.d.ts +0 -2
  19. package/dist/mdast-util-mdxish.js +0 -14
  20. package/dist/mdxjs.d.ts +0 -3
  21. package/dist/mdxjs.js +0 -20
  22. package/dist/rehype-escape.d.ts +0 -2
  23. package/dist/rehype-escape.js +0 -21
  24. package/dist/rehype-expressions.d.ts +0 -1
  25. package/dist/rehype-expressions.js +0 -20
  26. package/dist/rehype-islands.d.ts +0 -1
  27. package/dist/rehype-islands.js +0 -27
  28. package/dist/rehype-jsx.d.ts +0 -2
  29. package/dist/rehype-jsx.js +0 -51
  30. package/dist/remark-escape.d.ts +0 -1
  31. package/dist/remark-escape.js +0 -13
  32. package/dist/remark-mark-and-unravel.d.ts +0 -17
  33. package/dist/remark-mark-and-unravel.js +0 -45
  34. package/dist/remark-mdxish.d.ts +0 -1
  35. package/dist/remark-mdxish.js +0 -53
  36. package/dist/remark-unwrap.d.ts +0 -1
  37. package/dist/remark-unwrap.js +0 -31
  38. package/src/mdast-util-mdxish.ts +0 -12
  39. package/src/mdxjs.ts +0 -27
  40. package/src/rehype-escape.ts +0 -22
  41. package/src/rehype-expressions.ts +0 -18
  42. package/src/rehype-islands.ts +0 -43
  43. package/src/rehype-jsx.ts +0 -65
  44. package/src/remark-escape.ts +0 -15
  45. package/src/remark-mark-and-unravel.ts +0 -72
  46. package/src/remark-mdxish.ts +0 -61
  47. package/src/remark-unwrap.ts +0 -44
  48. package/test/components.test.js +0 -78
  49. package/test/expressions.test.js +0 -125
  50. package/test/strictness.test.js +0 -98
@@ -1,61 +0,0 @@
1
- import type * as fromMarkdown from 'mdast-util-from-markdown';
2
- import type { Tag } from 'mdast-util-mdx-jsx';
3
- import { mdxFromMarkdown, mdxToMarkdown } from './mdast-util-mdxish.js';
4
- import { mdxjs } from './mdxjs.js';
5
-
6
- // Prepare markdown extensions once to prevent performance issues
7
- const extMdxJs = mdxjs({});
8
- const extMdxFromMarkdown = makeFromMarkdownLessStrict(mdxFromMarkdown());
9
- const extMdxToMarkdown = mdxToMarkdown();
10
-
11
- export default function remarkMdxish(this: any) {
12
- const data = this.data();
13
-
14
- add('micromarkExtensions', extMdxJs);
15
- add('fromMarkdownExtensions', extMdxFromMarkdown);
16
- add('toMarkdownExtensions', extMdxToMarkdown);
17
-
18
- function add(field: string, value: unknown) {
19
- const list = data[field] ? data[field] : (data[field] = []);
20
- list.push(value);
21
- }
22
- }
23
-
24
- function makeFromMarkdownLessStrict(extensions: fromMarkdown.Extension[]) {
25
- extensions.forEach((extension) => {
26
- // Fix exit handlers that are too strict
27
- ['mdxJsxFlowTag', 'mdxJsxTextTag'].forEach((exitHandler) => {
28
- if (!extension.exit || !extension.exit[exitHandler]) return;
29
- extension.exit[exitHandler] = chainHandlers(fixSelfClosing, extension.exit[exitHandler]);
30
- });
31
- });
32
-
33
- return extensions;
34
- }
35
-
36
- const selfClosingTags = new Set([
37
- 'area',
38
- 'base',
39
- 'br',
40
- 'col',
41
- 'embed',
42
- 'hr',
43
- 'img',
44
- 'input',
45
- 'link',
46
- 'meta',
47
- 'source',
48
- 'track',
49
- 'wbr',
50
- ]);
51
-
52
- function fixSelfClosing(this: fromMarkdown.CompileContext) {
53
- const tag = this.getData('mdxJsxTag') as Tag;
54
- if (tag.name && selfClosingTags.has(tag.name)) tag.selfClosing = true;
55
- }
56
-
57
- function chainHandlers(...handlers: fromMarkdown.Handle[]) {
58
- return function handlerChain(this: fromMarkdown.CompileContext, token: fromMarkdown.Token) {
59
- handlers.forEach((handler) => handler.call(this, token));
60
- };
61
- }
@@ -1,44 +0,0 @@
1
- import { SKIP, visit as _visit } from 'unist-util-visit';
2
-
3
- // This is a workaround.
4
- // It fixes a compatibility issue between different, incompatible ASTs given by plugins to Unist
5
- const visit = _visit as (
6
- node: any,
7
- type: string,
8
- callback?: (node: any, index: number, parent: any) => any
9
- ) => any;
10
-
11
- // Remove the wrapping paragraph for <astro-island> islands
12
- export default function remarkUnwrap() {
13
- const astroRootNodes = new Set();
14
- let insideAstroRoot = false;
15
-
16
- return (tree: any) => {
17
- // reset state
18
- insideAstroRoot = false;
19
- astroRootNodes.clear();
20
-
21
- visit(tree, 'html', (node) => {
22
- if (node.value.indexOf('<astro-island') > -1 && !insideAstroRoot) {
23
- insideAstroRoot = true;
24
- }
25
- if (node.value.indexOf('</astro-island') > -1 && insideAstroRoot) {
26
- insideAstroRoot = false;
27
- }
28
- astroRootNodes.add(node);
29
- });
30
-
31
- visit(tree, 'paragraph', (node, index, parent) => {
32
- if (parent && typeof index === 'number' && containsAstroRootNode(node)) {
33
- parent.children.splice(index, 1, ...node.children);
34
- return [SKIP, index];
35
- }
36
- });
37
- };
38
-
39
- function containsAstroRootNode(node: any) {
40
- return node.children
41
- .map((child: any) => astroRootNodes.has(child))
42
- .reduce((all: boolean, v: boolean) => (all ? all : v), false);
43
- }
44
- }
@@ -1,78 +0,0 @@
1
- import { renderMarkdown } from '../dist/index.js';
2
- import chai from 'chai';
3
-
4
- describe('components', () => {
5
- const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: true });
6
-
7
- it('should be able to serialize string', async () => {
8
- const { code } = await renderAstroMd(`<Component str="cool!" />`);
9
-
10
- chai.expect(code).to.equal(`<Component str="cool!" />`);
11
- });
12
-
13
- it('should be able to serialize boolean attribute', async () => {
14
- const { code } = await renderAstroMd(`<Component bool={true} />`);
15
-
16
- chai.expect(code).to.equal(`<Component bool={true} />`);
17
- });
18
-
19
- it('should be able to serialize array', async () => {
20
- const { code } = await renderAstroMd(`<Component prop={["a", "b", "c"]} />`);
21
-
22
- chai.expect(code).to.equal(`<Component prop={["a", "b", "c"]} />`);
23
- });
24
-
25
- it('should be able to serialize object', async () => {
26
- const { code } = await renderAstroMd(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
27
-
28
- chai.expect(code).to.equal(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
29
- });
30
-
31
- it('should be able to serialize empty attribute', async () => {
32
- const { code } = await renderAstroMd(`<Component empty />`);
33
-
34
- chai.expect(code).to.equal(`<Component empty />`);
35
- });
36
-
37
- // Notable omission: shorthand attribute
38
-
39
- it('should be able to serialize spread attribute', async () => {
40
- const { code } = await renderAstroMd(`<Component {...spread} />`);
41
-
42
- chai.expect(code).to.equal(`<Component {...spread} />`);
43
- });
44
-
45
- it('should allow client:* directives', async () => {
46
- const { code } = await renderAstroMd(`<Component client:load />`);
47
-
48
- chai.expect(code).to.equal(`<Component client:load />`);
49
- });
50
-
51
- it('should normalize children', async () => {
52
- const { code } = await renderAstroMd(`<Component bool={true}>Hello world!</Component>`);
53
-
54
- chai.expect(code).to.equal(`<Component bool={true}>Hello world!</Component>`);
55
- });
56
-
57
- it('should be able to nest components', async () => {
58
- const { code } = await renderAstroMd(
59
- `<Component bool={true}><Component>Hello world!</Component></Component>`,
60
- {}
61
- );
62
-
63
- chai
64
- .expect(code)
65
- .to.equal(`<Component bool={true}><Component>Hello world!</Component></Component>`);
66
- });
67
-
68
- it('should allow markdown without many spaces', async () => {
69
- const { code } = await renderAstroMd(
70
- `<Component>
71
- # Hello world!
72
- </Component>`,
73
- {}
74
- );
75
-
76
- chai.expect(code).to.equal(`<Component><h1 id="hello-world">Hello world!</h1></Component>`);
77
- });
78
- });
@@ -1,125 +0,0 @@
1
- import { renderMarkdown } from '../dist/index.js';
2
- import chai from 'chai';
3
-
4
- describe('expressions', () => {
5
- const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
6
-
7
- it('should be able to serialize bare expression', async () => {
8
- const { code } = await renderAstroMd(`{a}`, {});
9
-
10
- chai.expect(code).to.equal(`{a}`);
11
- });
12
-
13
- it('should be able to serialize expression inside component', async () => {
14
- const { code } = await renderAstroMd(`<Component>{a}</Component>`, {});
15
-
16
- chai.expect(code).to.equal(`<Component>{a}</Component>`);
17
- });
18
-
19
- it('should be able to serialize expression inside markdown', async () => {
20
- const { code } = await renderAstroMd(`# {frontmatter.title}`, {});
21
-
22
- chai
23
- .expect(code)
24
- .to.equal(`<h1 id={$$slug(\`\${frontmatter.title}\`)}>{frontmatter.title}</h1>`);
25
- });
26
-
27
- it('should be able to serialize complex expression inside markdown', async () => {
28
- const { code } = await renderAstroMd(`# Hello {frontmatter.name}`, {});
29
-
30
- chai
31
- .expect(code)
32
- .to.equal(`<h1 id={$$slug(\`Hello \${frontmatter.name}\`)}>Hello {frontmatter.name}</h1>`);
33
- });
34
-
35
- it('should be able to serialize complex expression with markup inside markdown', async () => {
36
- const { code } = await renderAstroMd(`# Hello <span>{frontmatter.name}</span>`, {});
37
-
38
- chai
39
- .expect(code)
40
- .to.equal(
41
- `<h1 id={$$slug(\`Hello \${frontmatter.name}\`)}>Hello <span>{frontmatter.name}</span></h1>`
42
- );
43
- });
44
-
45
- it('should be able to avoid evaluating JSX-like expressions in an inline code & generate a slug for id', async () => {
46
- const { code } = await renderAstroMd(`# \`{frontmatter.title}\``, {});
47
-
48
- chai
49
- .expect(code)
50
- .to.equal('<h1 id="frontmattertitle"><code is:raw>{frontmatter.title}</code></h1>');
51
- });
52
-
53
- it('should be able to avoid evaluating JSX-like expressions in inline codes', async () => {
54
- const { code } = await renderAstroMd(`# \`{ foo }\` is a shorthand for \`{ foo: foo }\``, {});
55
-
56
- chai
57
- .expect(code)
58
- .to.equal(
59
- '<h1 id="-foo--is-a-shorthand-for--foo-foo"><code is:raw>{ foo }</code> is a shorthand for <code is:raw>{ foo: foo }</code></h1>'
60
- );
61
- });
62
-
63
- it('should be able to avoid evaluating JSX-like expressions & escape HTML tag characters in inline codes', async () => {
64
- const { code } = await renderAstroMd(
65
- `###### \`{}\` is equivalent to \`Record<never, never>\` <small>(at TypeScript v{frontmatter.version})</small>`,
66
- {}
67
- );
68
-
69
- chai
70
- .expect(code)
71
- .to.equal(
72
- `<h6 id={$$slug(\`{} is equivalent to Record&lt;never, never&gt; (at TypeScript v\${frontmatter.version})\`)}><code is:raw>{}</code> is equivalent to <code is:raw>Record&lt;never, never&gt;</code> <small>(at TypeScript v{frontmatter.version})</small></h6>`
73
- );
74
- });
75
-
76
- it('should be able to encode ampersand characters in code blocks', async () => {
77
- const { code } = await renderAstroMd(
78
- 'The ampersand in `&nbsp;` must be encoded in code blocks.',
79
- {}
80
- );
81
-
82
- chai
83
- .expect(code)
84
- .to.equal(
85
- '<p>The ampersand in <code is:raw>&amp;nbsp;</code> must be encoded in code blocks.</p>'
86
- );
87
- });
88
-
89
- it('should be able to encode ampersand characters in fenced code blocks', async () => {
90
- const { code } = await renderAstroMd(`
91
- \`\`\`md
92
- The ampersand in \`&nbsp;\` must be encoded in code blocks.
93
- \`\`\`
94
- `);
95
-
96
- chai.expect(code).to.match(/^<pre is:raw.*<code>.*The ampersand in `&amp;nbsp;`/);
97
- });
98
-
99
- it('should be able to serialize function expression', async () => {
100
- const { code } = await renderAstroMd(
101
- `{frontmatter.list.map(item => <p id={item}>{item}</p>)}`,
102
- {}
103
- );
104
-
105
- chai.expect(code).to.equal(`{frontmatter.list.map(item => <p id={item}>{item}</p>)}`);
106
- });
107
-
108
- it('should unwrap HTML comments in inline code blocks', async () => {
109
- const { code } = await renderAstroMd(`\`{/*<!-- HTML comment -->*/}\``);
110
-
111
- chai.expect(code).to.equal('<p><code is:raw>&lt;!-- HTML comment --&gt;</code></p>');
112
- });
113
-
114
- it('should unwrap HTML comments in code fences', async () => {
115
- const { code } = await renderAstroMd(
116
- `
117
- \`\`\`
118
- <!-- HTML comment -->
119
- \`\`\`
120
- `
121
- );
122
-
123
- chai.expect(code).to.match(/(?<!{\/\*)&lt;!-- HTML comment --&gt;(?!\*\/})/);
124
- });
125
- });
@@ -1,98 +0,0 @@
1
- import { renderMarkdown } from '../dist/index.js';
2
- import chai from 'chai';
3
-
4
- describe('strictness in Astro-flavored markdown', () => {
5
- const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
6
-
7
- it('should allow self-closing HTML tags (void elements)', async () => {
8
- const { code } = await renderAstroMd(
9
- `Use self-closing void elements<br>like word<wbr>break and images: <img src="hi.jpg">`,
10
- {}
11
- );
12
-
13
- chai
14
- .expect(code)
15
- .to.equal(
16
- `<p>Use self-closing void elements<br />like word<wbr />break and images: ` +
17
- `<img src="hi.jpg" /></p>`
18
- );
19
- });
20
-
21
- it('should allow attribute names starting with ":" after element names', async () => {
22
- const { code } = await renderAstroMd(`<div :class="open ? '' : 'hidden'">Test</div>`, {});
23
-
24
- chai.expect(code.trim()).to.equal(`<div :class="open ? '' : 'hidden'">Test</div>`);
25
- });
26
-
27
- it('should allow attribute names starting with ":" after local element names', async () => {
28
- const { code } = await renderAstroMd(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`, {});
29
-
30
- chai.expect(code.trim()).to.equal(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`);
31
- });
32
-
33
- it('should allow attribute names starting with ":" after attribute names', async () => {
34
- const { code } = await renderAstroMd(`<input type="text" disabled :placeholder="hi">`, {});
35
-
36
- chai.expect(code.trim()).to.equal(`<input type="text" disabled :placeholder="hi" />`);
37
- });
38
-
39
- it('should allow attribute names starting with ":" after local attribute names', async () => {
40
- const { code } = await renderAstroMd(
41
- `<input type="text" x-test:disabled :placeholder="hi">`,
42
- {}
43
- );
44
-
45
- chai.expect(code.trim()).to.equal(`<input type="text" x-test:disabled :placeholder="hi" />`);
46
- });
47
-
48
- it('should allow attribute names starting with ":" after attribute values', async () => {
49
- const { code } = await renderAstroMd(`<input type="text" :placeholder="placeholder">`, {});
50
-
51
- chai.expect(code.trim()).to.equal(`<input type="text" :placeholder="placeholder" />`);
52
- });
53
-
54
- it('should allow attribute names starting with "@" after element names', async () => {
55
- const { code } = await renderAstroMd(`<button @click="handleClick">Test</button>`, {});
56
-
57
- chai.expect(code.trim()).to.equal(`<button @click="handleClick">Test</button>`);
58
- });
59
-
60
- it('should allow attribute names starting with "@" after local element names', async () => {
61
- const { code } = await renderAstroMd(
62
- `<button.local @click="handleClick">Test</button.local>`,
63
- {}
64
- );
65
-
66
- chai.expect(code.trim()).to.equal(`<button.local @click="handleClick">Test</button.local>`);
67
- });
68
-
69
- it('should allow attribute names starting with "@" after attribute names', async () => {
70
- const { code } = await renderAstroMd(`<button disabled @click="handleClick">Test</button>`, {});
71
-
72
- chai.expect(code.trim()).to.equal(`<button disabled @click="handleClick">Test</button>`);
73
- });
74
-
75
- it('should allow attribute names starting with "@" after local attribute names', async () => {
76
- const { code } = await renderAstroMd(
77
- `<button x-test:disabled @click="handleClick">Test</button>`,
78
- {}
79
- );
80
-
81
- chai.expect(code.trim()).to.equal(`<button x-test:disabled @click="handleClick">Test</button>`);
82
- });
83
-
84
- it('should allow attribute names starting with "@" after attribute values', async () => {
85
- const { code } = await renderAstroMd(
86
- `<button type="submit" @click="handleClick">Test</button>`,
87
- {}
88
- );
89
-
90
- chai.expect(code.trim()).to.equal(`<button type="submit" @click="handleClick">Test</button>`);
91
- });
92
-
93
- it('should allow attribute names containing dots', async () => {
94
- const { code } = await renderAstroMd(`<input x-on:input.debounce.500ms="fetchResults">`, {});
95
-
96
- chai.expect(code.trim()).to.equal(`<input x-on:input.debounce.500ms="fetchResults" />`);
97
- });
98
- });