prettier-plugin-mdc 0.1.1 → 0.1.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.
- package/README.md +17 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.mjs +79 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,15 @@ Add the plugin to your Prettier configuration:
|
|
|
27
27
|
```json
|
|
28
28
|
// .prettierrc
|
|
29
29
|
{
|
|
30
|
-
"plugins": ["prettier-plugin-mdc"]
|
|
30
|
+
"plugins": ["prettier-plugin-mdc"],
|
|
31
|
+
"overrides": [
|
|
32
|
+
{
|
|
33
|
+
"files": ["*.md"],
|
|
34
|
+
"options": {
|
|
35
|
+
"parser": "mdc"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
]
|
|
31
39
|
}
|
|
32
40
|
```
|
|
33
41
|
|
|
@@ -36,6 +44,14 @@ Or in `prettier.config.js`:
|
|
|
36
44
|
```js
|
|
37
45
|
export default {
|
|
38
46
|
plugins: ["prettier-plugin-mdc"],
|
|
47
|
+
overrides: [
|
|
48
|
+
{
|
|
49
|
+
files: ["*.md"],
|
|
50
|
+
options: {
|
|
51
|
+
parser: "mdc",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
],
|
|
39
55
|
};
|
|
40
56
|
```
|
|
41
57
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Printer } from "prettier";
|
|
1
|
+
import { Parser, Printer, SupportLanguage } from "prettier";
|
|
2
2
|
import { Node } from "unist";
|
|
3
3
|
|
|
4
4
|
//#region src/constants.d.ts
|
|
@@ -10,4 +10,7 @@ declare const parsers: Record<typeof AST_FORMAT, Parser<Node>>;
|
|
|
10
10
|
//#region src/printers.d.ts
|
|
11
11
|
declare const printers: Record<typeof AST_FORMAT, Printer<Node>>;
|
|
12
12
|
//#endregion
|
|
13
|
-
|
|
13
|
+
//#region src/index.d.ts
|
|
14
|
+
declare const languages: Partial<SupportLanguage>[];
|
|
15
|
+
//#endregion
|
|
16
|
+
export { languages, parsers, printers };
|
package/dist/index.mjs
CHANGED
|
@@ -12,17 +12,6 @@ import { createSyncFn } from "synckit";
|
|
|
12
12
|
//#region src/constants.ts
|
|
13
13
|
const AST_FORMAT = "mdc";
|
|
14
14
|
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/parsers.ts
|
|
17
|
-
const parsers = { [AST_FORMAT]: {
|
|
18
|
-
...markdown.parsers.markdown,
|
|
19
|
-
astFormat: AST_FORMAT,
|
|
20
|
-
parse: async (text) => {
|
|
21
|
-
const processor = unified().use(remarkParse, { commonmark: true }).use(remarkMath).use(remarkGfm).use(remarkMdc);
|
|
22
|
-
return await processor.run(processor.parse(text));
|
|
23
|
-
}
|
|
24
|
-
} };
|
|
25
|
-
|
|
26
15
|
//#endregion
|
|
27
16
|
//#region src/is.ts
|
|
28
17
|
const isTextComponentNode = (node) => node.type === "textComponent";
|
|
@@ -52,6 +41,39 @@ function linkNeedsCustomPrinting(node) {
|
|
|
52
41
|
return false;
|
|
53
42
|
}
|
|
54
43
|
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/validate.ts
|
|
46
|
+
function validateYamlBlocks(ast, text) {
|
|
47
|
+
function visit(node) {
|
|
48
|
+
if (isContainerComponentNode(node)) {
|
|
49
|
+
const pos = node.position;
|
|
50
|
+
if (pos) {
|
|
51
|
+
const startLine = pos.start.line;
|
|
52
|
+
const lines = text.split("\n");
|
|
53
|
+
if (startLine < lines.length) {
|
|
54
|
+
if (lines[startLine]?.trim() === "---" && !node.rawData) throw new Error(`Invalid YAML block in component "${node.name}" at line ${startLine + 1}: YAML block is
|
|
55
|
+
not properly closed`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (node.children) for (const child of node.children) visit(child);
|
|
59
|
+
} else if ("children" in node && Array.isArray(node.children)) for (const child of node.children) visit(child);
|
|
60
|
+
}
|
|
61
|
+
visit(ast);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/parsers.ts
|
|
66
|
+
const parsers = { [AST_FORMAT]: {
|
|
67
|
+
...markdown.parsers.markdown,
|
|
68
|
+
astFormat: AST_FORMAT,
|
|
69
|
+
parse: async (text) => {
|
|
70
|
+
const processor = unified().use(remarkParse, { commonmark: true }).use(remarkMath).use(remarkGfm).use(remarkMdc);
|
|
71
|
+
const ast = await processor.run(processor.parse(text));
|
|
72
|
+
validateYamlBlocks(ast, text);
|
|
73
|
+
return ast;
|
|
74
|
+
}
|
|
75
|
+
} };
|
|
76
|
+
|
|
55
77
|
//#endregion
|
|
56
78
|
//#region src/visitor-keys.ts
|
|
57
79
|
const visitorKeys = {
|
|
@@ -73,6 +95,21 @@ const extendedInlineNodes = [
|
|
|
73
95
|
];
|
|
74
96
|
const extendedInlineNodesHaveAttributes = (node) => extendedInlineNodes.includes(node.type) && "attributes" in node;
|
|
75
97
|
const escapeQuotes = (value, quote) => value.replace(new RegExp(quote, "g"), `\\${quote}`);
|
|
98
|
+
/**
|
|
99
|
+
* Quote a string value using Prettier's quote selection logic:
|
|
100
|
+
*
|
|
101
|
+
* - Use preferred quote if value doesn't contain it
|
|
102
|
+
* - Switch to alternative quote if value contains preferred but not alternative
|
|
103
|
+
* - Use preferred quote with escaping if value contains both
|
|
104
|
+
*/
|
|
105
|
+
function quoteString(value, options) {
|
|
106
|
+
const preferredQuote = options.singleQuote ? "'" : "\"";
|
|
107
|
+
const alternativeQuote = options.singleQuote ? "\"" : "'";
|
|
108
|
+
const hasPreferred = value.includes(preferredQuote);
|
|
109
|
+
const hasAlternative = value.includes(alternativeQuote);
|
|
110
|
+
const quote = hasPreferred && !hasAlternative ? alternativeQuote : preferredQuote;
|
|
111
|
+
return `${quote}${escapeQuotes(value.replace(/\\/g, "\\\\"), quote)}${quote}`;
|
|
112
|
+
}
|
|
76
113
|
|
|
77
114
|
//#endregion
|
|
78
115
|
//#region src/yaml.ts
|
|
@@ -92,16 +129,15 @@ const formatYaml = (text, options) => {
|
|
|
92
129
|
const { hardline, join } = doc.builders;
|
|
93
130
|
const mapChildren = (path, print) => path.map(print, "children");
|
|
94
131
|
function serializeValue(value, options) {
|
|
95
|
-
|
|
96
|
-
if (typeof value === "string") return `${quote}${escapeQuotes(value.replace(/\\/g, "\\\\"), quote)}${quote}`;
|
|
132
|
+
if (typeof value === "string") return quoteString(value, options);
|
|
97
133
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
98
|
-
|
|
134
|
+
const preferredQuote = options.singleQuote ? "'" : "\"";
|
|
135
|
+
return `${preferredQuote}${escapeQuotes(JSON.stringify(value), preferredQuote)}${preferredQuote}`;
|
|
99
136
|
}
|
|
100
|
-
function printAttributes(
|
|
101
|
-
|
|
102
|
-
if (!attrs || Object.keys(attrs).length === 0) return "";
|
|
137
|
+
function printAttributes({ attributes }, options) {
|
|
138
|
+
if (!attributes || Object.keys(attributes).length === 0) return "";
|
|
103
139
|
const parts = [];
|
|
104
|
-
for (const [key, value] of Object.entries(
|
|
140
|
+
for (const [key, value] of Object.entries(attributes)) if (key === "id") parts.push(`#${value}`);
|
|
105
141
|
else if (key === "class") {
|
|
106
142
|
const classes = String(value).split(/\s+/).filter(Boolean);
|
|
107
143
|
for (const cls of classes) parts.push(`.${cls}`);
|
|
@@ -115,8 +151,7 @@ function printAttributes(node, options) {
|
|
|
115
151
|
function printBinding(node, options) {
|
|
116
152
|
const value = node.attributes?.value ?? "";
|
|
117
153
|
const defaultValue = node.attributes?.defaultValue;
|
|
118
|
-
|
|
119
|
-
if (defaultValue !== void 0 && defaultValue !== "undefined") return [`{{ ${value} || ${quote}${escapeQuotes(String(defaultValue), quote)}${quote} }}`];
|
|
154
|
+
if (defaultValue !== void 0 && defaultValue !== "undefined") return [`{{ ${value} || ${quoteString(String(defaultValue), options)} }}`];
|
|
120
155
|
return [`{{ ${value} }}`];
|
|
121
156
|
}
|
|
122
157
|
/**
|
|
@@ -134,6 +169,7 @@ function isShorthandSpan(node) {
|
|
|
134
169
|
}
|
|
135
170
|
return nodeLength <= 3;
|
|
136
171
|
}
|
|
172
|
+
const EMPTY_PROPS_RE = /\{\s*\}\s*$/;
|
|
137
173
|
/**
|
|
138
174
|
* Print inline text component: :name[content]{attrs} Special cases:
|
|
139
175
|
*
|
|
@@ -165,6 +201,10 @@ function printTextComponent(path, print, options) {
|
|
|
165
201
|
const parts = [`:${node.name}`];
|
|
166
202
|
if (node.children && node.children.length > 0) parts.push("[", ...printChildrenWithEscapedBrackets(), "]");
|
|
167
203
|
if (attrStr) parts.push(attrStr);
|
|
204
|
+
else if (node.position) {
|
|
205
|
+
const text = options.originalText.slice(node.position.start.offset, node.position.end.offset);
|
|
206
|
+
if (EMPTY_PROPS_RE.test(text)) parts.push("{}");
|
|
207
|
+
}
|
|
168
208
|
return parts;
|
|
169
209
|
}
|
|
170
210
|
/**
|
|
@@ -180,7 +220,7 @@ function getContainerDepth(path) {
|
|
|
180
220
|
*/
|
|
181
221
|
function printRawData(rawData, options) {
|
|
182
222
|
if (!rawData) return [];
|
|
183
|
-
let content = rawData.slice(1, -3).trimEnd();
|
|
223
|
+
let content = rawData.trimEnd().slice(1, -3).trimEnd();
|
|
184
224
|
if (!content) return [];
|
|
185
225
|
content = formatYaml(content, options);
|
|
186
226
|
return [
|
|
@@ -203,8 +243,15 @@ function printContainerComponent(path, print, options) {
|
|
|
203
243
|
const attrStr = printAttributes(node, options);
|
|
204
244
|
if (attrStr) parts.push(attrStr);
|
|
205
245
|
parts.push(hardline);
|
|
206
|
-
|
|
246
|
+
const rawDataDoc = printRawData(node.rawData, options);
|
|
247
|
+
parts.push(...rawDataDoc);
|
|
207
248
|
if (node.children && node.children.length > 0) {
|
|
249
|
+
if (rawDataDoc.length > 0 && node.rawData) {
|
|
250
|
+
const componentStartLine = node.position?.start.line ?? 0;
|
|
251
|
+
const rawDataNewlines = (node.rawData.match(/\n/g) ?? []).length;
|
|
252
|
+
const rawDataEndLine = componentStartLine + 1 + rawDataNewlines;
|
|
253
|
+
if ((node.children[0].position?.start.line ?? 0) > rawDataEndLine + 1) parts.push(hardline);
|
|
254
|
+
}
|
|
208
255
|
const childDocs = mapChildren(path, print);
|
|
209
256
|
parts.push(join(hardline, childDocs));
|
|
210
257
|
parts.push(hardline);
|
|
@@ -283,4 +330,13 @@ const printers = { [AST_FORMAT]: {
|
|
|
283
330
|
} };
|
|
284
331
|
|
|
285
332
|
//#endregion
|
|
286
|
-
|
|
333
|
+
//#region src/index.ts
|
|
334
|
+
const languages = [{
|
|
335
|
+
name: "mdc",
|
|
336
|
+
parsers: [AST_FORMAT],
|
|
337
|
+
extensions: [".mdc"],
|
|
338
|
+
vscodeLanguageIds: ["mdc"]
|
|
339
|
+
}];
|
|
340
|
+
|
|
341
|
+
//#endregion
|
|
342
|
+
export { languages, parsers, printers };
|