@astrojs/markdoc 0.0.0-10745-20240410180016
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.
- package/LICENSE +59 -0
- package/README.md +38 -0
- package/components/Renderer.astro +24 -0
- package/components/TreeNode.ts +160 -0
- package/components/index.ts +2 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.js +26 -0
- package/dist/content-entry-type.d.ts +8 -0
- package/dist/content-entry-type.js +317 -0
- package/dist/extensions/prism.d.ts +2 -0
- package/dist/extensions/prism.js +21 -0
- package/dist/extensions/shiki.d.ts +3 -0
- package/dist/extensions/shiki.js +21 -0
- package/dist/heading-ids.d.ts +10 -0
- package/dist/heading-ids.js +55 -0
- package/dist/html/css/parse-inline-css-to-react.d.ts +1 -0
- package/dist/html/css/parse-inline-css-to-react.js +21 -0
- package/dist/html/css/parse-inline-styles.d.ts +8 -0
- package/dist/html/css/parse-inline-styles.js +153 -0
- package/dist/html/css/style-to-object.d.ts +12 -0
- package/dist/html/css/style-to-object.js +53 -0
- package/dist/html/index.d.ts +2 -0
- package/dist/html/index.js +6 -0
- package/dist/html/tagdefs/html.tag.d.ts +2 -0
- package/dist/html/tagdefs/html.tag.js +21 -0
- package/dist/html/transform/html-token-transform.d.ts +3 -0
- package/dist/html/transform/html-token-transform.js +154 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +39 -0
- package/dist/load-config.d.ts +8 -0
- package/dist/load-config.js +91 -0
- package/dist/options.d.ts +4 -0
- package/dist/options.js +0 -0
- package/dist/runtime-assets-config.d.ts +2 -0
- package/dist/runtime-assets-config.js +25 -0
- package/dist/runtime.d.ts +29 -0
- package/dist/runtime.js +152 -0
- package/dist/tokenizer.d.ts +3 -0
- package/dist/tokenizer.js +27 -0
- package/dist/utils.d.ts +46 -0
- package/dist/utils.js +47 -0
- package/package.json +94 -0
- package/template/content-module-types.d.ts +8 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
|
|
2
|
+
import { unescapeHTML } from "astro/runtime/server/index.js";
|
|
3
|
+
import { Markdoc } from "../config.js";
|
|
4
|
+
function prism() {
|
|
5
|
+
return {
|
|
6
|
+
nodes: {
|
|
7
|
+
fence: {
|
|
8
|
+
attributes: Markdoc.nodes.fence.attributes,
|
|
9
|
+
transform({ attributes: { language, content } }) {
|
|
10
|
+
const { html, classLanguage } = runHighlighterWithAstro(language, content);
|
|
11
|
+
return unescapeHTML(
|
|
12
|
+
`<pre class="${classLanguage}"><code class="${classLanguage}">${html}</code></pre>`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
prism as default
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createShikiHighlighter } from "@astrojs/markdown-remark";
|
|
2
|
+
import Markdoc from "@markdoc/markdoc";
|
|
3
|
+
import { unescapeHTML } from "astro/runtime/server/index.js";
|
|
4
|
+
async function shiki(config) {
|
|
5
|
+
const highlighter = await createShikiHighlighter(config);
|
|
6
|
+
return {
|
|
7
|
+
nodes: {
|
|
8
|
+
fence: {
|
|
9
|
+
attributes: Markdoc.nodes.fence.attributes,
|
|
10
|
+
async transform({ attributes }) {
|
|
11
|
+
const lang = typeof attributes.language === "string" ? attributes.language : "plaintext";
|
|
12
|
+
const html = await highlighter.highlight(attributes.content, lang);
|
|
13
|
+
return unescapeHTML(html);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
shiki as default
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Config as MarkdocConfig, type Schema } from '@markdoc/markdoc';
|
|
2
|
+
import Slugger from 'github-slugger';
|
|
3
|
+
type HeadingIdConfig = MarkdocConfig & {
|
|
4
|
+
ctx: {
|
|
5
|
+
headingSlugger: Slugger;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export declare const heading: Schema;
|
|
9
|
+
export declare function setupHeadingConfig(): HeadingIdConfig;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import Markdoc, {
|
|
2
|
+
} from "@markdoc/markdoc";
|
|
3
|
+
import Slugger from "github-slugger";
|
|
4
|
+
import { getTextContent } from "./runtime.js";
|
|
5
|
+
import { MarkdocError } from "./utils.js";
|
|
6
|
+
function getSlug(attributes, children, headingSlugger) {
|
|
7
|
+
if (attributes.id && typeof attributes.id === "string") {
|
|
8
|
+
return attributes.id;
|
|
9
|
+
}
|
|
10
|
+
const textContent = attributes.content ?? getTextContent(children);
|
|
11
|
+
let slug = headingSlugger.slug(textContent);
|
|
12
|
+
if (slug.endsWith("-"))
|
|
13
|
+
slug = slug.slice(0, -1);
|
|
14
|
+
return slug;
|
|
15
|
+
}
|
|
16
|
+
const heading = {
|
|
17
|
+
children: ["inline"],
|
|
18
|
+
attributes: {
|
|
19
|
+
id: { type: String },
|
|
20
|
+
level: { type: Number, required: true, default: 1 }
|
|
21
|
+
},
|
|
22
|
+
transform(node, config) {
|
|
23
|
+
const { level, ...attributes } = node.transformAttributes(config);
|
|
24
|
+
const children = node.transformChildren(config);
|
|
25
|
+
if (!config.ctx?.headingSlugger) {
|
|
26
|
+
throw new MarkdocError({
|
|
27
|
+
message: "Unexpected problem adding heading IDs to Markdoc file. Did you modify the `ctx.headingSlugger` property in your Markdoc config?"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const slug = getSlug(attributes, children, config.ctx.headingSlugger);
|
|
31
|
+
const render = config.nodes?.heading?.render ?? `h${level}`;
|
|
32
|
+
const tagProps = (
|
|
33
|
+
// For components, pass down `level` as a prop,
|
|
34
|
+
// alongside `__collectHeading` for our `headings` collector.
|
|
35
|
+
// Avoid accidentally rendering `level` as an HTML attribute otherwise!
|
|
36
|
+
typeof render === "string" ? { ...attributes, id: slug } : { ...attributes, id: slug, __collectHeading: true, level }
|
|
37
|
+
);
|
|
38
|
+
return new Markdoc.Tag(render, tagProps, children);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function setupHeadingConfig() {
|
|
42
|
+
const headingSlugger = new Slugger();
|
|
43
|
+
return {
|
|
44
|
+
ctx: {
|
|
45
|
+
headingSlugger
|
|
46
|
+
},
|
|
47
|
+
nodes: {
|
|
48
|
+
heading
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
heading,
|
|
54
|
+
setupHeadingConfig
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseInlineCSSToReactLikeObject(css: string | undefined | null): React.CSSProperties | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { styleToObject } from "./style-to-object.js";
|
|
2
|
+
function parseInlineCSSToReactLikeObject(css) {
|
|
3
|
+
if (typeof css === "string") {
|
|
4
|
+
const cssObject = {};
|
|
5
|
+
styleToObject(css, (originalCssDirective, value) => {
|
|
6
|
+
const reactCssDirective = convertCssDirectiveNameToReactCamelCase(originalCssDirective);
|
|
7
|
+
cssObject[reactCssDirective] = value;
|
|
8
|
+
});
|
|
9
|
+
return cssObject;
|
|
10
|
+
}
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
function convertCssDirectiveNameToReactCamelCase(original) {
|
|
14
|
+
const replaced = original.replace(/-([a-z\d])/gi, (_match, char) => {
|
|
15
|
+
return char.toUpperCase();
|
|
16
|
+
});
|
|
17
|
+
return replaced;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
parseInlineCSSToReactLikeObject
|
|
21
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
*
|
|
4
|
+
* (The MIT License)
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
*
|
|
10
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
13
|
+
*/
|
|
14
|
+
const COMMENT_REGEX = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g;
|
|
15
|
+
const NEWLINE_REGEX = /\n/g;
|
|
16
|
+
const WHITESPACE_REGEX = /^\s*/;
|
|
17
|
+
const PROPERTY_REGEX = /^([-#/*\\\w]+(\[[\da-z_-]+\])?)\s*/;
|
|
18
|
+
const COLON_REGEX = /^:\s*/;
|
|
19
|
+
const VALUE_REGEX = /^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*\)|[^};])+)/;
|
|
20
|
+
const SEMICOLON_REGEX = /^[;\s]*/;
|
|
21
|
+
const TRIM_REGEX = /^\s+|\s+$/g;
|
|
22
|
+
const NEWLINE = "\n";
|
|
23
|
+
const FORWARD_SLASH = "/";
|
|
24
|
+
const ASTERISK = "*";
|
|
25
|
+
const EMPTY_STRING = "";
|
|
26
|
+
const TYPE_COMMENT = "comment";
|
|
27
|
+
const TYPE_DECLARATION = "declaration";
|
|
28
|
+
function parseInlineStyles(style, options) {
|
|
29
|
+
if (typeof style !== "string") {
|
|
30
|
+
throw new TypeError("First argument must be a string");
|
|
31
|
+
}
|
|
32
|
+
if (!style)
|
|
33
|
+
return [];
|
|
34
|
+
options = options || {};
|
|
35
|
+
let lineno = 1;
|
|
36
|
+
let column = 1;
|
|
37
|
+
function updatePosition(str) {
|
|
38
|
+
let lines = str.match(NEWLINE_REGEX);
|
|
39
|
+
if (lines)
|
|
40
|
+
lineno += lines.length;
|
|
41
|
+
let i = str.lastIndexOf(NEWLINE);
|
|
42
|
+
column = ~i ? str.length - i : column + str.length;
|
|
43
|
+
}
|
|
44
|
+
function position() {
|
|
45
|
+
let start = { line: lineno, column };
|
|
46
|
+
return function(node) {
|
|
47
|
+
node.position = new Position(start);
|
|
48
|
+
whitespace();
|
|
49
|
+
return node;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function Position(start) {
|
|
53
|
+
this.start = start;
|
|
54
|
+
this.end = { line: lineno, column };
|
|
55
|
+
this.source = options.source;
|
|
56
|
+
}
|
|
57
|
+
Position.prototype.content = style;
|
|
58
|
+
const errorsList = [];
|
|
59
|
+
function error(msg) {
|
|
60
|
+
const err = new Error(options.source + ":" + lineno + ":" + column + ": " + msg);
|
|
61
|
+
err.reason = msg;
|
|
62
|
+
err.filename = options.source;
|
|
63
|
+
err.line = lineno;
|
|
64
|
+
err.column = column;
|
|
65
|
+
err.source = style;
|
|
66
|
+
if (options.silent) {
|
|
67
|
+
errorsList.push(err);
|
|
68
|
+
} else {
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function match(re) {
|
|
73
|
+
const m = re.exec(style);
|
|
74
|
+
if (!m)
|
|
75
|
+
return;
|
|
76
|
+
const str = m[0];
|
|
77
|
+
updatePosition(str);
|
|
78
|
+
style = style.slice(str.length);
|
|
79
|
+
return m;
|
|
80
|
+
}
|
|
81
|
+
function whitespace() {
|
|
82
|
+
match(WHITESPACE_REGEX);
|
|
83
|
+
}
|
|
84
|
+
function comments(rules) {
|
|
85
|
+
let c;
|
|
86
|
+
rules = rules || [];
|
|
87
|
+
while (c = comment()) {
|
|
88
|
+
if (c !== false) {
|
|
89
|
+
rules.push(c);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return rules;
|
|
93
|
+
}
|
|
94
|
+
function comment() {
|
|
95
|
+
const pos = position();
|
|
96
|
+
if (FORWARD_SLASH != style.charAt(0) || ASTERISK != style.charAt(1))
|
|
97
|
+
return;
|
|
98
|
+
let i = 2;
|
|
99
|
+
while (EMPTY_STRING != style.charAt(i) && (ASTERISK != style.charAt(i) || FORWARD_SLASH != style.charAt(i + 1))) {
|
|
100
|
+
++i;
|
|
101
|
+
}
|
|
102
|
+
i += 2;
|
|
103
|
+
if (EMPTY_STRING === style.charAt(i - 1)) {
|
|
104
|
+
return error("End of comment missing");
|
|
105
|
+
}
|
|
106
|
+
const str = style.slice(2, i - 2);
|
|
107
|
+
column += 2;
|
|
108
|
+
updatePosition(str);
|
|
109
|
+
style = style.slice(i);
|
|
110
|
+
column += 2;
|
|
111
|
+
return pos({
|
|
112
|
+
type: TYPE_COMMENT,
|
|
113
|
+
comment: str
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function declaration() {
|
|
117
|
+
const pos = position();
|
|
118
|
+
const prop = match(PROPERTY_REGEX);
|
|
119
|
+
if (!prop)
|
|
120
|
+
return;
|
|
121
|
+
comment();
|
|
122
|
+
if (!match(COLON_REGEX))
|
|
123
|
+
return error("property missing ':'");
|
|
124
|
+
const val = match(VALUE_REGEX);
|
|
125
|
+
const ret = pos({
|
|
126
|
+
type: TYPE_DECLARATION,
|
|
127
|
+
property: trim(prop[0].replace(COMMENT_REGEX, EMPTY_STRING)),
|
|
128
|
+
value: val ? trim(val[0].replace(COMMENT_REGEX, EMPTY_STRING)) : EMPTY_STRING
|
|
129
|
+
});
|
|
130
|
+
match(SEMICOLON_REGEX);
|
|
131
|
+
return ret;
|
|
132
|
+
}
|
|
133
|
+
function declarations() {
|
|
134
|
+
const decls = [];
|
|
135
|
+
comments(decls);
|
|
136
|
+
let decl;
|
|
137
|
+
while (decl = declaration()) {
|
|
138
|
+
if (decl !== false) {
|
|
139
|
+
decls.push(decl);
|
|
140
|
+
comments(decls);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return decls;
|
|
144
|
+
}
|
|
145
|
+
whitespace();
|
|
146
|
+
return declarations();
|
|
147
|
+
}
|
|
148
|
+
function trim(str) {
|
|
149
|
+
return str ? str.replace(TRIM_REGEX, EMPTY_STRING) : EMPTY_STRING;
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
parseInlineStyles
|
|
153
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses inline style to object.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // returns { 'line-height': '42' }
|
|
6
|
+
* styleToObject('line-height: 42;');
|
|
7
|
+
*
|
|
8
|
+
* @param {String} style - The inline style.
|
|
9
|
+
* @param {Function} [iterator] - The iterator function.
|
|
10
|
+
* @return {null|Object}
|
|
11
|
+
*/
|
|
12
|
+
export declare function styleToObject(style: any, iterator: any): {} | null;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
*
|
|
4
|
+
* The MIT License (MIT)
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2017 Menglin "Mark" Xu <mark@remarkablemark.org>
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
9
|
+
* a copy of this software and associated documentation files (the
|
|
10
|
+
* "Software"), to deal in the Software without restriction, including
|
|
11
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
|
12
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
13
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
|
14
|
+
* the following conditions:
|
|
15
|
+
*
|
|
16
|
+
* The above copyright notice and this permission notice shall be
|
|
17
|
+
* included in all copies or substantial portions of the Software.
|
|
18
|
+
*
|
|
19
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
20
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
21
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
22
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
23
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
24
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
25
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
26
|
+
*/
|
|
27
|
+
import { parseInlineStyles } from "./parse-inline-styles.js";
|
|
28
|
+
function styleToObject(style, iterator) {
|
|
29
|
+
let output = null;
|
|
30
|
+
if (!style || typeof style !== "string") {
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
33
|
+
let declaration;
|
|
34
|
+
let declarations = parseInlineStyles(style);
|
|
35
|
+
let hasIterator = typeof iterator === "function";
|
|
36
|
+
let property;
|
|
37
|
+
let value;
|
|
38
|
+
for (let i = 0, len = declarations.length; i < len; i++) {
|
|
39
|
+
declaration = declarations[i];
|
|
40
|
+
property = declaration.property;
|
|
41
|
+
value = declaration.value;
|
|
42
|
+
if (hasIterator) {
|
|
43
|
+
iterator(property, value, declaration);
|
|
44
|
+
} else if (value) {
|
|
45
|
+
output || (output = {});
|
|
46
|
+
output[property] = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return output;
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
styleToObject
|
|
53
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Markdoc from "@markdoc/markdoc";
|
|
2
|
+
import { parseInlineCSSToReactLikeObject } from "../css/parse-inline-css-to-react.js";
|
|
3
|
+
const htmlTag = {
|
|
4
|
+
attributes: {
|
|
5
|
+
name: { type: String, required: true },
|
|
6
|
+
attrs: { type: Object }
|
|
7
|
+
},
|
|
8
|
+
transform(node, config) {
|
|
9
|
+
const { name, attrs: unsafeAttributes } = node.attributes;
|
|
10
|
+
const children = node.transformChildren(config);
|
|
11
|
+
const { style, ...safeAttributes } = unsafeAttributes;
|
|
12
|
+
if (typeof style === "string") {
|
|
13
|
+
const styleObject = parseInlineCSSToReactLikeObject(style);
|
|
14
|
+
safeAttributes.style = styleObject;
|
|
15
|
+
}
|
|
16
|
+
return new Markdoc.Tag(name, safeAttributes, children);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export {
|
|
20
|
+
htmlTag
|
|
21
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Parser } from "htmlparser2";
|
|
2
|
+
function htmlTokenTransform(tokenizer, tokens) {
|
|
3
|
+
const output = [];
|
|
4
|
+
let textBuffer = "";
|
|
5
|
+
let inCDATA = false;
|
|
6
|
+
const appendText = (text) => {
|
|
7
|
+
textBuffer += text;
|
|
8
|
+
};
|
|
9
|
+
const processTextBuffer = () => {
|
|
10
|
+
if (textBuffer.length > 0) {
|
|
11
|
+
const toks = tokenizer.tokenize(textBuffer);
|
|
12
|
+
if (toks.length === 3) {
|
|
13
|
+
const first = toks[0];
|
|
14
|
+
const second = toks[1];
|
|
15
|
+
const third = toks.at(2);
|
|
16
|
+
if (first.type === "paragraph_open" && second.type === "inline" && third && third.type === "paragraph_close" && Array.isArray(second.children)) {
|
|
17
|
+
for (const tok of second.children) {
|
|
18
|
+
if (tok.type === "text") {
|
|
19
|
+
if (tok.content.trim() == textBuffer.trim()) {
|
|
20
|
+
tok.content = textBuffer;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
output.push(tok);
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
for (const tok of toks) {
|
|
27
|
+
output.push(tok);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
for (const tok of toks) {
|
|
32
|
+
output.push(tok);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
textBuffer = "";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const parser = new Parser(
|
|
39
|
+
{
|
|
40
|
+
oncdatastart() {
|
|
41
|
+
inCDATA = true;
|
|
42
|
+
},
|
|
43
|
+
oncdataend() {
|
|
44
|
+
inCDATA = false;
|
|
45
|
+
},
|
|
46
|
+
// when an HTML tag opens...
|
|
47
|
+
onopentag(name, attrs) {
|
|
48
|
+
processTextBuffer();
|
|
49
|
+
output.push({
|
|
50
|
+
type: "tag_open",
|
|
51
|
+
nesting: 1,
|
|
52
|
+
meta: {
|
|
53
|
+
tag: "html-tag",
|
|
54
|
+
attributes: [
|
|
55
|
+
{ type: "attribute", name: "name", value: name },
|
|
56
|
+
{ type: "attribute", name: "attrs", value: attrs }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
ontext(content) {
|
|
62
|
+
if (inCDATA) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (typeof content === "string") {
|
|
66
|
+
appendText(content);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
// when an HTML tag closes...
|
|
70
|
+
onclosetag(name) {
|
|
71
|
+
processTextBuffer();
|
|
72
|
+
output.push({
|
|
73
|
+
type: "tag_close",
|
|
74
|
+
nesting: -1,
|
|
75
|
+
meta: {
|
|
76
|
+
tag: "html-tag",
|
|
77
|
+
attributes: [{ type: "attribute", name: "name", value: name }]
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
decodeEntities: false,
|
|
84
|
+
recognizeCDATA: true,
|
|
85
|
+
recognizeSelfClosing: true
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
for (const token of tokens) {
|
|
89
|
+
if (token.type.startsWith("html")) {
|
|
90
|
+
parser.write(token.content);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (token.type === "inline") {
|
|
94
|
+
if (token.children) {
|
|
95
|
+
token.children = htmlTokenTransform(tokenizer, token.children);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
output.push(token);
|
|
99
|
+
}
|
|
100
|
+
processTextBuffer();
|
|
101
|
+
mutateAndCollapseExtraParagraphsUnderHtml(output);
|
|
102
|
+
return output;
|
|
103
|
+
}
|
|
104
|
+
function mutateAndCollapseExtraParagraphsUnderHtml(tokens) {
|
|
105
|
+
let done = false;
|
|
106
|
+
while (!done) {
|
|
107
|
+
const idx = findExtraParagraphUnderHtml(tokens);
|
|
108
|
+
if (typeof idx === "number") {
|
|
109
|
+
const actualChildTokens = tokens[idx + 2].children ?? [];
|
|
110
|
+
tokens.splice(idx, 5, ...actualChildTokens);
|
|
111
|
+
} else {
|
|
112
|
+
done = true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function findExtraParagraphUnderHtml(tokens) {
|
|
117
|
+
if (tokens.length < 5) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
121
|
+
const last = i + 4;
|
|
122
|
+
if (last > tokens.length - 1) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const slice = tokens.slice(i, last + 1);
|
|
126
|
+
const isMatch = isExtraParagraphPatternMatch(slice);
|
|
127
|
+
if (isMatch) {
|
|
128
|
+
return i;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
function isExtraParagraphPatternMatch(slice) {
|
|
134
|
+
const match = isHtmlTagOpen(slice[0]) && isParagraphOpen(slice[1]) && isInline(slice[2]) && isParagraphClose(slice[3]) && isHtmlTagClose(slice[4]);
|
|
135
|
+
return match;
|
|
136
|
+
}
|
|
137
|
+
function isHtmlTagOpen(token) {
|
|
138
|
+
return token.type === "tag_open" && token.meta && token.meta.tag === "html-tag";
|
|
139
|
+
}
|
|
140
|
+
function isHtmlTagClose(token) {
|
|
141
|
+
return token.type === "tag_close" && token.meta && token.meta.tag === "html-tag";
|
|
142
|
+
}
|
|
143
|
+
function isParagraphOpen(token) {
|
|
144
|
+
return token.type === "paragraph_open";
|
|
145
|
+
}
|
|
146
|
+
function isParagraphClose(token) {
|
|
147
|
+
return token.type === "paragraph_close";
|
|
148
|
+
}
|
|
149
|
+
function isInline(token) {
|
|
150
|
+
return token.type === "inline";
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
htmlTokenTransform
|
|
154
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getContentEntryType } from "./content-entry-type.js";
|
|
2
|
+
import {
|
|
3
|
+
SUPPORTED_MARKDOC_CONFIG_FILES,
|
|
4
|
+
loadMarkdocConfig
|
|
5
|
+
} from "./load-config.js";
|
|
6
|
+
function markdocIntegration(options) {
|
|
7
|
+
let markdocConfigResult;
|
|
8
|
+
let astroConfig;
|
|
9
|
+
return {
|
|
10
|
+
name: "@astrojs/markdoc",
|
|
11
|
+
hooks: {
|
|
12
|
+
"astro:config:setup": async (params) => {
|
|
13
|
+
const { updateConfig, addContentEntryType } = params;
|
|
14
|
+
astroConfig = params.config;
|
|
15
|
+
markdocConfigResult = await loadMarkdocConfig(astroConfig);
|
|
16
|
+
addContentEntryType(
|
|
17
|
+
await getContentEntryType({ markdocConfigResult, astroConfig, options })
|
|
18
|
+
);
|
|
19
|
+
updateConfig({
|
|
20
|
+
vite: {
|
|
21
|
+
ssr: {
|
|
22
|
+
external: ["@astrojs/markdoc/prism", "@astrojs/markdoc/shiki"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
"astro:server:setup": async ({ server }) => {
|
|
28
|
+
server.watcher.on("all", (event, entry) => {
|
|
29
|
+
if (SUPPORTED_MARKDOC_CONFIG_FILES.some((f) => entry.endsWith(f))) {
|
|
30
|
+
server.restart();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
markdocIntegration as default
|
|
39
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AstroConfig } from 'astro';
|
|
2
|
+
import type { AstroMarkdocConfig } from './config.js';
|
|
3
|
+
export declare const SUPPORTED_MARKDOC_CONFIG_FILES: string[];
|
|
4
|
+
export type MarkdocConfigResult = {
|
|
5
|
+
config: AstroMarkdocConfig;
|
|
6
|
+
fileUrl: URL;
|
|
7
|
+
};
|
|
8
|
+
export declare function loadMarkdocConfig(astroConfig: Pick<AstroConfig, 'root'>): Promise<MarkdocConfigResult | undefined>;
|