@tinacms/mdx 0.0.0-20220718185604 → 0.60.3
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/dist/index.cjs +887 -738
- package/dist/index.es.js +546 -406
- package/dist/{parse/plate-spec.d.ts → index.js} +4 -2
- package/dist/mdx.es.js +1092 -0
- package/dist/mdx.umd.js +1097 -0
- package/dist/parse/acorn.d.ts +2 -3
- package/dist/parse/acorn.js +201 -0
- package/dist/parse/index.d.ts +8 -2
- package/dist/parse/index.js +144 -0
- package/dist/parse/mdx.js +75 -0
- package/dist/parse/plate.d.ts +15 -2
- package/dist/parse/plate.js +1 -0
- package/dist/parse/remarkToPlate.d.ts +16 -1
- package/dist/parse/remarkToPlate.js +380 -0
- package/dist/stringify/acorn.d.ts +7 -2
- package/dist/stringify/acorn.js +241 -0
- package/dist/stringify/index.d.ts +15 -0
- package/dist/stringify/index.js +195 -0
- package/dist/stringify/marks.js +250 -0
- package/dist/tests/autotest/_config.d.ts +4 -0
- package/dist/tests/autotest/_config.js +159 -0
- package/dist/tests/autotest/_runner.test.d.ts +1 -0
- package/dist/tests/autotest/_runner.test.js +77 -0
- package/dist/tests/autotest/autoformat block elements in list items.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat block elements in list items.test.js +33 -0
- package/dist/tests/autotest/autoformat blockquote.result.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat blockquote.result.test.js +18 -0
- package/dist/tests/autotest/autoformat blockquote.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat blockquote.test.js +18 -0
- package/dist/tests/autotest/autoformat list item.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat list item.test.js +31 -0
- package/dist/tests/autotest/autoformat mdx with nested null children.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat mdx with nested null children.test.js +23 -0
- package/dist/tests/autotest/autoformat syntax changes.test.d.ts +1 -0
- package/dist/tests/autotest/autoformat syntax changes.test.js +90 -0
- package/dist/tests/autotest/blockquote.test.d.ts +1 -0
- package/dist/tests/autotest/blockquote.test.js +17 -0
- package/dist/tests/autotest/break.test.d.ts +1 -0
- package/dist/tests/autotest/break.test.js +26 -0
- package/dist/tests/autotest/code block.test.d.ts +1 -0
- package/dist/tests/autotest/code block.test.js +27 -0
- package/dist/tests/autotest/image.test.d.ts +1 -0
- package/dist/tests/autotest/image.test.js +52 -0
- package/dist/tests/autotest/invalid mdx with a closing tag.test.d.ts +1 -0
- package/dist/tests/autotest/invalid mdx with a closing tag.test.js +27 -0
- package/dist/tests/autotest/invalid mdx with a const expression.test.d.ts +1 -0
- package/dist/tests/autotest/invalid mdx with a const expression.test.js +27 -0
- package/dist/tests/autotest/invalid mdx with an expression {{}}.test.d.ts +1 -0
- package/dist/tests/autotest/invalid mdx with an expression {{}}.test.js +27 -0
- package/dist/tests/autotest/invalid mdx with an expression.test.d.ts +1 -0
- package/dist/tests/autotest/invalid mdx with an expression.test.js +27 -0
- package/dist/tests/autotest/invalid mdx with an import statment.test.d.ts +1 -0
- package/dist/tests/autotest/invalid mdx with an import statment.test.js +27 -0
- package/dist/tests/autotest/kitchen sink.test.d.ts +1 -0
- package/dist/tests/autotest/kitchen sink.test.js +144 -0
- package/dist/tests/autotest/links.test.d.ts +1 -0
- package/dist/tests/autotest/links.test.js +29 -0
- package/dist/tests/autotest/lists.test.d.ts +1 -0
- package/dist/tests/autotest/lists.test.js +110 -0
- package/dist/tests/autotest/marks.test.d.ts +1 -0
- package/dist/tests/autotest/marks.test.js +102 -0
- package/dist/tests/autotest/mdx field with a scalar field as a list.test.d.ts +1 -0
- package/dist/tests/autotest/mdx field with a scalar field as a list.test.js +22 -0
- package/dist/tests/autotest/mdx which hasnt been registered returns html.test.d.ts +1 -0
- package/dist/tests/autotest/mdx which hasnt been registered returns html.test.js +26 -0
- package/dist/tests/autotest/mdx with a boolean field.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with a boolean field.test.js +22 -0
- package/dist/tests/autotest/mdx with a number field.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with a number field.test.js +22 -0
- package/dist/tests/autotest/mdx with a srtring field.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with a srtring field.test.js +28 -0
- package/dist/tests/autotest/mdx with multiple rich-text fields.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with multiple rich-text fields.test.js +53 -0
- package/dist/tests/autotest/mdx with nested children.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with nested children.test.js +35 -0
- package/dist/tests/autotest/mdx with nested null children.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with nested null children.test.js +23 -0
- package/dist/tests/autotest/mdx with number list field.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with number list field.test.js +22 -0
- package/dist/tests/autotest/mdx with object list field.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with object list field.test.js +25 -0
- package/dist/tests/autotest/mdx with object with templates.test.d.ts +1 -0
- package/dist/tests/autotest/mdx with object with templates.test.js +41 -0
- package/dist/tests/autotest/shortcodes.test.d.ts +1 -0
- package/dist/tests/autotest/shortcodes.test.js +51 -0
- package/dist/tests/setup.d.ts +14 -0
- package/dist/tests/setup.js +70 -0
- package/package.json +13 -14
- package/dist/stringify/mdx.d.ts +0 -38
package/dist/parse/acorn.d.ts
CHANGED
|
@@ -15,7 +15,6 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
|
|
17
17
|
*/
|
|
18
|
-
import type { MdxJsxAttribute } from 'mdast-util-mdx-jsx';
|
|
18
|
+
import type { MdxJsxAttribute, MdxJsxExpressionAttribute } from 'mdast-util-mdx-jsx';
|
|
19
19
|
import type { TinaFieldBase } from '@tinacms/schema-tools';
|
|
20
|
-
export declare const extractAttributes: (attributes: MdxJsxAttribute[], fields: TinaFieldBase[], imageCallback: (image: string) => string) => Record<string, unknown>;
|
|
21
|
-
export declare const extractAttribute: (attribute: MdxJsxAttribute, field: TinaFieldBase, imageCallback: (image: string) => string) => string | number | bigint | boolean | RegExp | Record<string, unknown> | (string | number | bigint | boolean | RegExp | null | undefined)[] | Record<string, unknown>[] | null | undefined;
|
|
20
|
+
export declare const extractAttributes: (attributes: (MdxJsxAttribute | MdxJsxExpressionAttribute)[], fields: TinaFieldBase[], imageCallback: (image: string) => string) => Record<string, unknown>;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { MDX_PARSE_ERROR_MSG, parseMDX } from '.';
|
|
2
|
+
export var extractAttributes = function (attributes, fields, imageCallback) {
|
|
3
|
+
var properties = {};
|
|
4
|
+
attributes.forEach(function (attribute) {
|
|
5
|
+
assertType(attribute, 'mdxJsxAttribute');
|
|
6
|
+
var field = fields.find(function (field) { return field.name === attribute.name; });
|
|
7
|
+
if (!field) {
|
|
8
|
+
throw new Error("Unable to find field definition for property \"" + attribute.name + "\"");
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
properties[attribute.name] = extractAttribute(attribute, field, imageCallback);
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
if (e instanceof Error) {
|
|
15
|
+
throw new Error("Unable to parse field value for field \"" + field.name + "\" (type: " + field.type + "). " + e.message);
|
|
16
|
+
}
|
|
17
|
+
throw e;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return properties;
|
|
21
|
+
};
|
|
22
|
+
var extractAttribute = function (attribute, field, imageCallback) {
|
|
23
|
+
switch (field.type) {
|
|
24
|
+
case 'boolean':
|
|
25
|
+
case 'number':
|
|
26
|
+
return extractScalar(extractExpression(attribute), field);
|
|
27
|
+
case 'datetime':
|
|
28
|
+
case 'string':
|
|
29
|
+
if (field.list) {
|
|
30
|
+
return extractScalar(extractExpression(attribute), field);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return extractString(attribute, field);
|
|
34
|
+
}
|
|
35
|
+
case 'image':
|
|
36
|
+
if (field.list) {
|
|
37
|
+
var values = extractScalar(extractExpression(attribute), field);
|
|
38
|
+
return values.split(',').map(function (value) { return imageCallback(value); });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
var value = extractString(attribute, field);
|
|
42
|
+
return imageCallback(value);
|
|
43
|
+
}
|
|
44
|
+
case 'reference':
|
|
45
|
+
if (field.list) {
|
|
46
|
+
return extractScalar(extractExpression(attribute), field);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return extractString(attribute, field);
|
|
50
|
+
}
|
|
51
|
+
case 'object':
|
|
52
|
+
return extractObject(extractExpression(attribute), field);
|
|
53
|
+
case 'rich-text':
|
|
54
|
+
var JSXString = extractJSXFragment(
|
|
55
|
+
// @ts-ignore FIXME: estree-jsx needs to be merged with estree
|
|
56
|
+
extractExpression(attribute), attribute, field);
|
|
57
|
+
if (JSXString) {
|
|
58
|
+
return parseMDX(JSXString, field, imageCallback);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
default:
|
|
64
|
+
// @ts-expect-error
|
|
65
|
+
throw new Error("Extract attribute: Unhandled field type " + field.type);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var extractScalar = function (attribute, field) {
|
|
69
|
+
if (field.list) {
|
|
70
|
+
assertType(attribute.expression, 'ArrayExpression');
|
|
71
|
+
return attribute.expression.elements.map(function (element) {
|
|
72
|
+
assertHasType(element);
|
|
73
|
+
assertType(element, 'Literal');
|
|
74
|
+
return element.value;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
assertType(attribute.expression, 'Literal');
|
|
79
|
+
return attribute.expression.value;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var extractObject = function (attribute, field) {
|
|
83
|
+
if (field.list) {
|
|
84
|
+
assertType(attribute.expression, 'ArrayExpression');
|
|
85
|
+
return attribute.expression.elements.map(function (element) {
|
|
86
|
+
assertHasType(element);
|
|
87
|
+
assertType(element, 'ObjectExpression');
|
|
88
|
+
return extractObjectExpression(element, field);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
assertType(attribute.expression, 'ObjectExpression');
|
|
93
|
+
return extractObjectExpression(attribute.expression, field);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var extractObjectExpression = function (expression, field) {
|
|
97
|
+
var properties = {};
|
|
98
|
+
expression.properties.forEach(function (property) {
|
|
99
|
+
assertType(property, 'Property');
|
|
100
|
+
var _a = extractKeyValue(property, field), key = _a.key, value = _a.value;
|
|
101
|
+
properties[key] = value;
|
|
102
|
+
});
|
|
103
|
+
return properties;
|
|
104
|
+
};
|
|
105
|
+
var getField = function (objectField, name) {
|
|
106
|
+
if (objectField.fields) {
|
|
107
|
+
if (typeof objectField.fields === 'string') {
|
|
108
|
+
throw new Error('Global templates not supported');
|
|
109
|
+
}
|
|
110
|
+
return objectField.fields.find(function (f) { return f.name === name; });
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var extractJSXFragment = function (attribute, baseAttribute, field) {
|
|
114
|
+
if (field.list) {
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if (attribute.expression.type === 'JSXFragment') {
|
|
118
|
+
assertHasType(attribute.expression);
|
|
119
|
+
if (attribute.expression.children[0]) {
|
|
120
|
+
var firstChild = attribute.expression.children[0];
|
|
121
|
+
if (attribute.expression.children[0].type === 'JSXText') {
|
|
122
|
+
var child = firstChild;
|
|
123
|
+
return child.value.trim();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
throwError(field);
|
|
129
|
+
};
|
|
130
|
+
var extractKeyValue = function (property, parentField) {
|
|
131
|
+
assertType(property.key, 'Identifier');
|
|
132
|
+
var key = property.key.name;
|
|
133
|
+
var field = getField(parentField, key);
|
|
134
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === 'object') {
|
|
135
|
+
if (field.list) {
|
|
136
|
+
assertType(property.value, 'ArrayExpression');
|
|
137
|
+
var value = property.value.elements.map(function (element) {
|
|
138
|
+
assertHasType(element);
|
|
139
|
+
assertType(element, 'ObjectExpression');
|
|
140
|
+
return extractObjectExpression(element, field);
|
|
141
|
+
});
|
|
142
|
+
return { key: key, value: value };
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
assertType(property.value, 'ObjectExpression');
|
|
146
|
+
var value = extractObjectExpression(property.value, field);
|
|
147
|
+
return { key: key, value: value };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
assertType(property.value, 'Literal');
|
|
152
|
+
return { key: key, value: property.value.value };
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var extractStatement = function (attribute) {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
var body = (_b = (_a = attribute.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body;
|
|
158
|
+
if (body) {
|
|
159
|
+
if (body[0]) {
|
|
160
|
+
assertType(body[0], 'ExpressionStatement');
|
|
161
|
+
// @ts-ignore incomplete types available Directive | ExpressionStatement
|
|
162
|
+
return body[0];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
throw new Error("Unable to extract body from expression");
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
*
|
|
169
|
+
* JSX props can be either expressions, or in the case of non-list strings, literals
|
|
170
|
+
* eg. `<Cta label="hello" />` or `<Cta label={"hello"} />` are both valid
|
|
171
|
+
*/
|
|
172
|
+
var extractString = function (attribute, field) {
|
|
173
|
+
if (attribute.type === 'mdxJsxAttribute') {
|
|
174
|
+
if (typeof attribute.value === 'string') {
|
|
175
|
+
return attribute.value;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return extractScalar(extractExpression(attribute), field);
|
|
179
|
+
};
|
|
180
|
+
var extractExpression = function (attribute) {
|
|
181
|
+
assertType(attribute, 'mdxJsxAttribute');
|
|
182
|
+
assertHasType(attribute.value);
|
|
183
|
+
assertType(attribute.value, 'mdxJsxAttributeValueExpression');
|
|
184
|
+
return extractStatement(attribute.value);
|
|
185
|
+
};
|
|
186
|
+
function assertType(val, type) {
|
|
187
|
+
if (val.type !== type) {
|
|
188
|
+
throw new Error("Expected type to be " + type + " but received " + val.type + ". " + MDX_PARSE_ERROR_MSG);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function assertHasType(val) {
|
|
192
|
+
if (val) {
|
|
193
|
+
if (typeof val !== 'string') {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw new Error("Expect value to be an object with property \"type\"");
|
|
198
|
+
}
|
|
199
|
+
var throwError = function (field) {
|
|
200
|
+
throw new Error("Unexpected expression for field \"" + field.name + "\"" + (field.list ? ' with "list": true' : ''));
|
|
201
|
+
};
|
package/dist/parse/index.d.ts
CHANGED
|
@@ -15,7 +15,10 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
|
|
17
17
|
*/
|
|
18
|
+
import { RichTextParseError } from './remarkToPlate';
|
|
18
19
|
import type { RichTypeInner } from '@tinacms/schema-tools';
|
|
20
|
+
import type * as Md from 'mdast';
|
|
21
|
+
import type * as Plate from './plate';
|
|
19
22
|
/**
|
|
20
23
|
* ### Convert the MDXAST into an API-friendly format
|
|
21
24
|
*
|
|
@@ -65,5 +68,8 @@ import type { RichTypeInner } from '@tinacms/schema-tools';
|
|
|
65
68
|
* 2. We don't need to do any client-side parsing. Since TinaMarkdown and the slate editor work with the same
|
|
66
69
|
* format we can just allow Tina to do it's thing and update the form valuse with no additional work.
|
|
67
70
|
*/
|
|
68
|
-
export declare const markdownToAst: (value: string,
|
|
69
|
-
export declare const
|
|
71
|
+
export declare const markdownToAst: (value: string, field: RichTypeInner) => Md.Root;
|
|
72
|
+
export declare const MDX_PARSE_ERROR_MSG = "TinaCMS supports a stricter version of markdown and a subset of MDX. https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations";
|
|
73
|
+
export declare const MDX_PARSE_ERROR_MSG_HTML = "TinaCMS supports a stricter version of markdown and a subset of MDX. <a href=\"https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations\" target=\"_blank\" rel=\"noopener noreferrer\">Learn More</a>";
|
|
74
|
+
export declare const parseMDX: (value: string, field: RichTypeInner, imageCallback: (s: string) => string) => Plate.RootElement;
|
|
75
|
+
export declare const invalidMarkdown: (e: RichTextParseError, value: string) => Plate.RootElement;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
|
|
3
|
+
Copyright 2021 Forestry.io Holdings, Inc.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
*/
|
|
18
|
+
var __assign = (this && this.__assign) || function () {
|
|
19
|
+
__assign = Object.assign || function(t) {
|
|
20
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
21
|
+
s = arguments[i];
|
|
22
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
23
|
+
t[p] = s[p];
|
|
24
|
+
}
|
|
25
|
+
return t;
|
|
26
|
+
};
|
|
27
|
+
return __assign.apply(this, arguments);
|
|
28
|
+
};
|
|
29
|
+
import { remark } from 'remark';
|
|
30
|
+
import remarkMdx from 'remark-mdx';
|
|
31
|
+
import { remarkToSlate, RichTextParseError } from './remarkToPlate';
|
|
32
|
+
/**
|
|
33
|
+
* ### Convert the MDXAST into an API-friendly format
|
|
34
|
+
*
|
|
35
|
+
* When we parse with Remark + MDX we get an AST which has a ton of JS capabilities, meaning
|
|
36
|
+
* we could pass this back into a JS runtime and evaluate it. Ex.
|
|
37
|
+
*
|
|
38
|
+
* ```mdx
|
|
39
|
+
* ## Hello world! The time and date is: {(new Date().toLocaleString())}
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* However, as an intentional constraint we don't want this information as part of our API, as
|
|
43
|
+
* we don't intend to support the true JS runtime properties of MDX. Rather, we're using MDX for
|
|
44
|
+
* it's expressive syntax and it's advanced tooling with how it parses JSX inside Markdown.
|
|
45
|
+
*
|
|
46
|
+
* Parsing here does 2 things:
|
|
47
|
+
*
|
|
48
|
+
* #### Remove non-literal uses of JSX
|
|
49
|
+
* Things like <MyComponent myProp={() => alert("HI")} /> are not supported and will be ignored
|
|
50
|
+
*
|
|
51
|
+
* #### Convert remark nodes to slate-compatible nodes
|
|
52
|
+
*
|
|
53
|
+
* A remark node might look like this:
|
|
54
|
+
* ```js
|
|
55
|
+
* {
|
|
56
|
+
* type: "heading",
|
|
57
|
+
* depth: 1
|
|
58
|
+
* children: [{type: 'text', value: 'Hello'}]
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
* A slate-compatible node would be:
|
|
62
|
+
* ```js
|
|
63
|
+
* {
|
|
64
|
+
* type: "heading_one",
|
|
65
|
+
* children: [{type: 'text', text: 'Hello'}]
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
* It's not a huge difference, but in general slate does better with less layers of indirection.
|
|
69
|
+
*
|
|
70
|
+
* While it may be desirable to ultimately serve a remark AST shape as part of the API response,
|
|
71
|
+
* it's currently much easier to only support the shape that works with Slate. This is ok for now for 2
|
|
72
|
+
* reasons.
|
|
73
|
+
*
|
|
74
|
+
* 1. Us providing the `TinaMarkdown` component on the frontend abstracts away an work the developer
|
|
75
|
+
* would need to do, so it doesn't really matter what shape the response is as long as the external API
|
|
76
|
+
* doesn't change
|
|
77
|
+
*
|
|
78
|
+
* 2. We don't need to do any client-side parsing. Since TinaMarkdown and the slate editor work with the same
|
|
79
|
+
* format we can just allow Tina to do it's thing and update the form valuse with no additional work.
|
|
80
|
+
*/
|
|
81
|
+
export var markdownToAst = function (value, field) {
|
|
82
|
+
var _a;
|
|
83
|
+
var templatesWithMatchers = (_a = field.templates) === null || _a === void 0 ? void 0 : _a.filter(function (template) { return template.match; });
|
|
84
|
+
var preprocessedString = value;
|
|
85
|
+
templatesWithMatchers === null || templatesWithMatchers === void 0 ? void 0 : templatesWithMatchers.forEach(function (template) {
|
|
86
|
+
if (typeof template === 'string') {
|
|
87
|
+
throw new Error('Global templates are not supported');
|
|
88
|
+
}
|
|
89
|
+
if (template.match) {
|
|
90
|
+
preprocessedString = preprocessedString.replaceAll(template.match.start, "<" + template.name + ">`");
|
|
91
|
+
preprocessedString = preprocessedString.replaceAll(template.match.end, "`</" + template.name + ">");
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
// Remark Root is not the same as mdast for some reason
|
|
96
|
+
var tree = remark().use(remarkMdx).parse(preprocessedString);
|
|
97
|
+
if (!tree) {
|
|
98
|
+
throw new Error('Error parsing markdown');
|
|
99
|
+
}
|
|
100
|
+
// NOTE: if we want to provide error highlighing in the raw editor
|
|
101
|
+
// we could keep this info around in edit mode
|
|
102
|
+
// Delete useless position info
|
|
103
|
+
// visit(tree, (node) => {
|
|
104
|
+
// delete node.position
|
|
105
|
+
// })
|
|
106
|
+
return tree;
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
// @ts-ignore VMessage is the error type but it's not accessible
|
|
110
|
+
throw new RichTextParseError(e, e.position);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
export var MDX_PARSE_ERROR_MSG = 'TinaCMS supports a stricter version of markdown and a subset of MDX. https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations';
|
|
114
|
+
export var MDX_PARSE_ERROR_MSG_HTML = 'TinaCMS supports a stricter version of markdown and a subset of MDX. <a href="https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations" target="_blank" rel="noopener noreferrer">Learn More</a>';
|
|
115
|
+
export var parseMDX = function (value, field, imageCallback) {
|
|
116
|
+
var tree;
|
|
117
|
+
try {
|
|
118
|
+
tree = markdownToAst(value, field);
|
|
119
|
+
if (tree) {
|
|
120
|
+
return remarkToSlate(tree, field, imageCallback);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
return { type: 'root', children: [] };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
if (e instanceof RichTextParseError) {
|
|
128
|
+
return invalidMarkdown(e, value);
|
|
129
|
+
}
|
|
130
|
+
throw e;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
export var invalidMarkdown = function (e, value) {
|
|
134
|
+
var extra = {};
|
|
135
|
+
if (e.position && Object.keys(e.position).length) {
|
|
136
|
+
extra['position'] = e.position;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
type: 'root',
|
|
140
|
+
children: [
|
|
141
|
+
__assign({ type: 'invalid_markdown', value: value, message: e.message || "Error parsing markdown " + MDX_PARSE_ERROR_MSG, children: [{ type: 'text', text: '' }] }, extra),
|
|
142
|
+
]
|
|
143
|
+
};
|
|
144
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { extractAttributes } from './acorn';
|
|
2
|
+
import { remarkToSlate, RichTextParseError } from './remarkToPlate';
|
|
3
|
+
import { toMarkdown } from 'mdast-util-to-markdown';
|
|
4
|
+
import { mdxJsxToMarkdown } from 'mdast-util-mdx-jsx';
|
|
5
|
+
export function mdxJsxElement(node, field, imageCallback) {
|
|
6
|
+
var _a;
|
|
7
|
+
try {
|
|
8
|
+
var template = (_a = field.templates) === null || _a === void 0 ? void 0 : _a.find(function (template) {
|
|
9
|
+
var templateName = typeof template === 'string' ? template : template.name;
|
|
10
|
+
return templateName === node.name;
|
|
11
|
+
});
|
|
12
|
+
if (typeof template === 'string') {
|
|
13
|
+
throw new Error('Global templates not yet supported');
|
|
14
|
+
}
|
|
15
|
+
if (!template) {
|
|
16
|
+
var string = toMarkdown({ type: 'root', children: [node] }, {
|
|
17
|
+
extensions: [mdxJsxToMarkdown()],
|
|
18
|
+
listItemIndent: 'one'
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
type: node.type === 'mdxJsxFlowElement' ? 'html' : 'html_inline',
|
|
22
|
+
value: string.trim(),
|
|
23
|
+
children: [{ type: 'text', text: '' }]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (template.match) {
|
|
27
|
+
var firstChild = node === null || node === void 0 ? void 0 : node.children[0];
|
|
28
|
+
if ((firstChild === null || firstChild === void 0 ? void 0 : firstChild.type) === 'inlineCode') {
|
|
29
|
+
var value = firstChild.value;
|
|
30
|
+
if (node.type === 'mdxJsxFlowElement') {
|
|
31
|
+
// NOTE: Since we cast the children to `inline code`
|
|
32
|
+
// I don't think this code will ever run.
|
|
33
|
+
// And I'm not sure care either way
|
|
34
|
+
return {
|
|
35
|
+
type: node.type,
|
|
36
|
+
name: node.name,
|
|
37
|
+
children: [{ type: 'text', text: '' }],
|
|
38
|
+
props: { text: value }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return {
|
|
43
|
+
type: node.type,
|
|
44
|
+
name: node.name,
|
|
45
|
+
children: [{ type: 'text', text: '' }],
|
|
46
|
+
props: { text: value }
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error("Unable to parse value for template match pattern - start: " + template.match.start + ", end: " + template.match.end);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// FIXME: these should be passed through to the field resolver in @tinacms/graphql (via dependency injection)
|
|
55
|
+
var props = extractAttributes(node.attributes, template.fields, imageCallback);
|
|
56
|
+
var childField = template.fields.find(function (field) { return field.name === 'children'; });
|
|
57
|
+
if (childField) {
|
|
58
|
+
if (childField.type === 'rich-text') {
|
|
59
|
+
props.children = remarkToSlate(node, childField, imageCallback);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
type: node.type,
|
|
64
|
+
name: node.name,
|
|
65
|
+
children: [{ type: 'text', text: '' }],
|
|
66
|
+
props: props
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e instanceof Error) {
|
|
71
|
+
throw new RichTextParseError(e.message, node.position);
|
|
72
|
+
}
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/parse/plate.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
|
|
17
17
|
*/
|
|
18
|
+
import { Position } from './remarkToPlate';
|
|
18
19
|
export declare type RootElement = {
|
|
19
20
|
type: 'root';
|
|
20
21
|
children: BlockElement[];
|
|
@@ -42,6 +43,18 @@ export declare type HTMLElement = {
|
|
|
42
43
|
value: string;
|
|
43
44
|
children: [EmptyTextElement];
|
|
44
45
|
};
|
|
46
|
+
export declare type HTMLInlineElement = {
|
|
47
|
+
type: 'html_inline';
|
|
48
|
+
value: string;
|
|
49
|
+
children: [EmptyTextElement];
|
|
50
|
+
};
|
|
51
|
+
export declare type InvalidMarkdownElement = {
|
|
52
|
+
type: 'invalid_markdown';
|
|
53
|
+
value: string;
|
|
54
|
+
message: string;
|
|
55
|
+
position?: Position;
|
|
56
|
+
children: [EmptyTextElement];
|
|
57
|
+
};
|
|
45
58
|
export declare type CodeBlockElement = {
|
|
46
59
|
type: 'code_block';
|
|
47
60
|
lang?: string;
|
|
@@ -70,7 +83,7 @@ export declare type OrderedListElement = {
|
|
|
70
83
|
children: ListItemElement[];
|
|
71
84
|
};
|
|
72
85
|
export declare type List = OrderedListElement | UnorderedListElement;
|
|
73
|
-
export declare type BlockElement = HeadingElement | ParagraphElement | CodeBlockElement | BlockquoteElement | MdxBlockElement | HTMLElement | UnorderedListElement | OrderedListElement | ListItemElement | HrElement;
|
|
86
|
+
export declare type BlockElement = HeadingElement | ParagraphElement | CodeBlockElement | BlockquoteElement | MdxBlockElement | HTMLElement | UnorderedListElement | OrderedListElement | ListItemElement | HrElement | InvalidMarkdownElement;
|
|
74
87
|
export declare type MdxInlineElement = {
|
|
75
88
|
type: 'mdxJsxTextElement';
|
|
76
89
|
name: string | null;
|
|
@@ -106,4 +119,4 @@ export declare type BreakElement = {
|
|
|
106
119
|
children: [EmptyTextElement];
|
|
107
120
|
};
|
|
108
121
|
export declare type LicElement = InlineElement;
|
|
109
|
-
export declare type InlineElement = TextElement | MdxInlineElement | BreakElement | LinkElement | ImageElement;
|
|
122
|
+
export declare type InlineElement = TextElement | MdxInlineElement | BreakElement | LinkElement | ImageElement | HTMLInlineElement;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -33,4 +33,19 @@ declare module 'mdast' {
|
|
|
33
33
|
mdxJsxFlowElement: MdxJsxFlowElement;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
export declare const remarkToSlate: (root: Md.Root, field: RichTypeInner, imageCallback: (url: string) => string) => Plate.RootElement;
|
|
36
|
+
export declare const remarkToSlate: (root: Md.Root | MdxJsxFlowElement | MdxJsxTextElement, field: RichTypeInner, imageCallback: (url: string) => string) => Plate.RootElement;
|
|
37
|
+
export declare type PositionItem = {
|
|
38
|
+
line?: number | null;
|
|
39
|
+
column?: number | null;
|
|
40
|
+
offset?: number | null;
|
|
41
|
+
_index?: number | null;
|
|
42
|
+
_bufferIndex?: number | null;
|
|
43
|
+
};
|
|
44
|
+
export declare type Position = {
|
|
45
|
+
start: PositionItem;
|
|
46
|
+
end: PositionItem;
|
|
47
|
+
};
|
|
48
|
+
export declare class RichTextParseError extends Error {
|
|
49
|
+
position?: Position;
|
|
50
|
+
constructor(message: string, position?: Position);
|
|
51
|
+
}
|