Skip to content

Commit 38064ac

Browse files
authored
feat: move schema, parser and serializer specs to separate extensions (#80)
1 parent bf8d961 commit 38064ac

File tree

184 files changed

+2524
-1891
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

184 files changed

+2524
-1891
lines changed

src/extensions/base/BaseSchema/BaseSchema.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {builders} from 'prosemirror-test-builder';
22
import {createMarkupChecker} from '../../../../tests/sameMarkup';
33
import {ExtensionsManager} from '../../../core';
4-
import {BaseNode, BaseSchema} from './index';
4+
import {BaseNode, BaseSchemaSpecs} from './BaseSchemaSpecs';
55

66
const {schema, parser, serializer} = new ExtensionsManager({
7-
extensions: (builder) => builder.use(BaseSchema, {}),
7+
extensions: (builder) => builder.use(BaseSchemaSpecs, {}),
88
}).buildDeps();
99

1010
const {doc, p} = builders(schema, {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type {NodeSpec} from 'prosemirror-model';
2+
import type {ExtensionAuto} from '../../../../core';
3+
import {nodeTypeFactory} from '../../../../utils/schema';
4+
5+
export enum BaseNode {
6+
Doc = 'doc',
7+
Text = 'text',
8+
Paragraph = 'paragraph',
9+
}
10+
11+
export const pType = nodeTypeFactory(BaseNode.Paragraph);
12+
13+
export type BaseSchemaSpecsOptions = {
14+
paragraphPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
15+
};
16+
17+
export const BaseSchemaSpecs: ExtensionAuto<BaseSchemaSpecsOptions> = (builder, opts) => {
18+
const {paragraphPlaceholder} = opts;
19+
20+
builder
21+
.addNode(BaseNode.Doc, () => ({
22+
spec: {
23+
content: 'block+',
24+
},
25+
fromYfm: {tokenSpec: {name: BaseNode.Doc, type: 'block', ignore: true}},
26+
toYfm: () => {
27+
throw new Error('Unexpected toYfm() call on doc node');
28+
},
29+
}))
30+
.addNode(BaseNode.Text, () => ({
31+
spec: {
32+
group: 'inline',
33+
},
34+
fromYfm: {tokenSpec: {name: BaseNode.Text, type: 'node', ignore: true}},
35+
toYfm: (state, node, parent) => {
36+
const {escapeText} = parent.type.spec;
37+
state.text(node.text, escapeText ?? !state.isAutolink);
38+
},
39+
}))
40+
.addNode(BaseNode.Paragraph, () => ({
41+
spec: {
42+
content: 'inline*',
43+
group: 'block',
44+
parseDOM: [{tag: 'p'}],
45+
toDOM() {
46+
return ['p', 0];
47+
},
48+
placeholder: paragraphPlaceholder
49+
? {
50+
content: paragraphPlaceholder,
51+
alwaysVisible: false,
52+
}
53+
: undefined,
54+
},
55+
fromYfm: {tokenSpec: {name: BaseNode.Paragraph, type: 'block'}},
56+
toYfm: (state, node) => {
57+
state.renderInline(node);
58+
state.closeBlock(node);
59+
},
60+
}));
61+
};

src/extensions/base/BaseSchema/index.ts

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,24 @@
1-
import type {NodeSpec} from 'prosemirror-model';
21
import type {Command} from 'prosemirror-state';
32
import {setBlockType} from 'prosemirror-commands';
43
import {hasParentNodeOfType} from 'prosemirror-utils';
54
import type {Action, ExtensionAuto} from '../../../core';
6-
import {nodeTypeFactory} from '../../../utils/schema';
5+
import {BaseSchemaSpecs, BaseSchemaSpecsOptions, pType} from './BaseSchemaSpecs';
76

8-
export enum BaseNode {
9-
Doc = 'doc',
10-
Text = 'text',
11-
Paragraph = 'paragraph',
12-
}
7+
export {BaseNode, pType} from './BaseSchemaSpecs';
138

14-
export const pType = nodeTypeFactory(BaseNode.Paragraph);
159
const pAction = 'toParagraph';
1610

1711
export const toParagraph: Command = (state, dispatch) =>
1812
setBlockType(pType(state.schema))(state, dispatch);
1913

20-
export type BaseSchemaOptions = {
14+
export type BaseSchemaOptions = BaseSchemaSpecsOptions & {
2115
paragraphKey?: string | null;
22-
paragraphPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
2316
};
2417

2518
export const BaseSchema: ExtensionAuto<BaseSchemaOptions> = (builder, opts) => {
26-
const {paragraphKey, paragraphPlaceholder} = opts;
27-
28-
builder
29-
.addNode(BaseNode.Doc, () => ({
30-
spec: {
31-
content: 'block+',
32-
},
33-
fromYfm: {tokenSpec: {name: BaseNode.Doc, type: 'block', ignore: true}},
34-
toYfm: () => {
35-
throw new Error('Unexpected toYfm() call on doc node');
36-
},
37-
}))
38-
.addNode(BaseNode.Text, () => ({
39-
spec: {
40-
group: 'inline',
41-
},
42-
fromYfm: {tokenSpec: {name: BaseNode.Text, type: 'node', ignore: true}},
43-
toYfm: (state, node, parent) => {
44-
const {escapeText} = parent.type.spec;
45-
state.text(node.text, escapeText ?? !state.isAutolink);
46-
},
47-
}))
48-
.addNode(BaseNode.Paragraph, () => ({
49-
spec: {
50-
content: 'inline*',
51-
group: 'block',
52-
parseDOM: [{tag: 'p'}],
53-
toDOM() {
54-
return ['p', 0];
55-
},
56-
placeholder: paragraphPlaceholder
57-
? {
58-
content: paragraphPlaceholder,
59-
alwaysVisible: false,
60-
}
61-
: undefined,
62-
},
63-
fromYfm: {tokenSpec: {name: BaseNode.Paragraph, type: 'block'}},
64-
toYfm: (state, node) => {
65-
state.renderInline(node);
66-
state.closeBlock(node);
67-
},
68-
}));
19+
builder.use(BaseSchemaSpecs, opts);
6920

21+
const {paragraphKey} = opts;
7022
if (paragraphKey) {
7123
builder.addKeymap(({schema}) => ({[paragraphKey]: setBlockType(pType(schema))}));
7224
}

src/extensions/base/specs.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type {ExtensionAuto} from '../../core';
2+
3+
import {BaseSchemaSpecs, BaseSchemaSpecsOptions} from './BaseSchema/BaseSchemaSpecs';
4+
5+
export * from './BaseSchema/BaseSchemaSpecs';
6+
7+
export type BaseSpecPresetOptions = {
8+
baseSchema?: BaseSchemaSpecsOptions;
9+
};
10+
11+
export const BaseSpecsPreset: ExtensionAuto<BaseSpecPresetOptions> = (builder, opts) => {
12+
builder.use(BaseSchemaSpecs, opts.baseSchema ?? {});
13+
};

src/extensions/behavior/Placeholder/index.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@ import {cn} from '../../../classname';
77
import type {ExtensionAuto} from '../../../core';
88
import {isNodeEmpty} from '../../../utils/nodes';
99
import {isTextSelection} from '../../../utils/selection';
10+
import {getPlaceholderContent} from '../../../utils/placeholder';
1011

1112
import './index.scss';
1213

13-
export const getPlaceholderContent = (node: Node, parent?: Node | null) => {
14-
const content = node.type.spec.placeholder?.content || '';
15-
16-
return typeof content === 'function' ? content(node, parent) : content;
17-
};
18-
1914
const getPlaceholderPluginKeys = (schema: Schema) => {
2015
const pluginKeys = [];
2116
for (const node in schema.nodes) {

src/extensions/markdown/Blockquote/Blockquote.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import {builders} from 'prosemirror-test-builder';
22
import {createMarkupChecker} from '../../../../tests/sameMarkup';
33
import {parseDOM} from '../../../../tests/parse-dom';
44
import {ExtensionsManager} from '../../../core';
5-
import {BaseNode, BaseSchema} from '../../base/BaseSchema';
6-
import {blockquote, Blockquote} from './index';
5+
import {BaseNode, BaseSpecsPreset} from '../../base/specs';
6+
import {blockquoteNodeName, BlockquoteSpecs} from './BlockquoteSpecs';
77

88
const {schema, parser, serializer} = new ExtensionsManager({
9-
extensions: (builder) => builder.use(BaseSchema, {}).use(Blockquote, {}),
9+
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(BlockquoteSpecs),
1010
}).buildDeps();
1111

1212
const {doc, p, q} = builders(schema, {
1313
doc: {nodeType: BaseNode.Doc},
1414
p: {nodeType: BaseNode.Paragraph},
15-
q: {nodeType: blockquote},
15+
q: {nodeType: blockquoteNodeName},
1616
}) as PMTestBuilderResult<'doc' | 'p' | 'q'>;
1717

1818
const {same} = createMarkupChecker({parser, serializer});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type {ExtensionAuto} from '../../../../core';
2+
import {nodeTypeFactory} from '../../../../utils/schema';
3+
4+
export const blockquoteNodeName = 'blockquote';
5+
export const blockquoteType = nodeTypeFactory(blockquoteNodeName);
6+
7+
export const BlockquoteSpecs: ExtensionAuto = (builder) => {
8+
builder.addNode(blockquoteNodeName, () => ({
9+
spec: {
10+
content: 'block+',
11+
group: 'block',
12+
defining: true,
13+
parseDOM: [{tag: 'blockquote'}],
14+
toDOM() {
15+
return ['blockquote', 0];
16+
},
17+
},
18+
fromYfm: {tokenSpec: {name: blockquoteNodeName, type: 'block'}},
19+
toYfm: (state, node) => {
20+
state.wrapBlock('> ', null, node, () => state.renderContent(node));
21+
},
22+
}));
23+
};
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import {nodeTypeFactory} from '../../../utils/schema';
1+
import {blockquoteNodeName, blockquoteType} from './BlockquoteSpecs';
22

3-
export const blockquote = 'blockquote';
4-
export const bqType = nodeTypeFactory(blockquote);
3+
export {blockquoteNodeName, blockquoteType} from './BlockquoteSpecs';
4+
/** @deprecated Use `blockquoteNodeName` instead */
5+
export const blockquote = blockquoteNodeName;
6+
/** @deprecated Use `blockquoteType` instead */
7+
export const bqType = blockquoteType;

src/extensions/markdown/Blockquote/index.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,31 @@ import {wrappingInputRule} from 'prosemirror-inputrules';
44
import {hasParentNodeOfType} from 'prosemirror-utils';
55
import type {Action, ExtensionAuto} from '../../../core';
66
import {selectQuoteBeforeCursor, liftFromQuote, toggleQuote} from './commands';
7-
import {blockquote, bqType} from './const';
7+
import {BlockquoteSpecs, blockquoteType} from './BlockquoteSpecs';
88

9-
export {blockquote};
9+
export {blockquote, blockquoteNodeName, blockquoteType} from './const';
1010
const bqAction = 'quote';
1111

1212
export type BlockquoteOptions = {
1313
qouteKey?: string | null;
1414
};
1515

1616
export const Blockquote: ExtensionAuto<BlockquoteOptions> = (builder, opts) => {
17-
builder.addNode(blockquote, () => ({
18-
spec: {
19-
content: 'block+',
20-
group: 'block',
21-
defining: true,
22-
parseDOM: [{tag: 'blockquote'}],
23-
toDOM() {
24-
return ['blockquote', 0];
25-
},
26-
},
27-
fromYfm: {tokenSpec: {name: blockquote, type: 'block'}},
28-
toYfm: (state, node) => {
29-
state.wrapBlock('> ', null, node, () => state.renderContent(node));
30-
},
31-
}));
17+
builder.use(BlockquoteSpecs);
3218

3319
if (opts?.qouteKey) {
3420
const {qouteKey} = opts;
35-
builder.addKeymap(({schema}) => ({[qouteKey]: wrapIn(bqType(schema))}));
21+
builder.addKeymap(({schema}) => ({[qouteKey]: wrapIn(blockquoteType(schema))}));
3622
}
3723

3824
builder.addKeymap(() => ({
3925
Backspace: chainCommands(liftFromQuote, selectQuoteBeforeCursor),
4026
}));
4127

42-
builder.addInputRules(({schema}) => ({rules: [blockQuoteRule(bqType(schema))]}));
28+
builder.addInputRules(({schema}) => ({rules: [blockQuoteRule(blockquoteType(schema))]}));
4329

4430
builder.addAction(bqAction, ({schema}) => {
45-
const bq = bqType(schema);
31+
const bq = blockquoteType(schema);
4632
return {
4733
isActive: (state) => hasParentNodeOfType(bq)(state.selection),
4834
isEnable: toggleQuote,

src/extensions/markdown/Bold/Bold.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import {builders} from 'prosemirror-test-builder';
22
import {createMarkupChecker} from '../../../../tests/sameMarkup';
33
import {parseDOM} from '../../../../tests/parse-dom';
44
import {ExtensionsManager} from '../../../core';
5-
import {BaseNode, BaseSchema} from '../../base/BaseSchema';
6-
import {bold, Bold} from './index';
5+
import {BaseNode, BaseSpecsPreset} from '../../base/specs';
6+
import {boldMarkName, BoldSpecs} from './BoldSpecs';
77

88
const {schema, parser, serializer} = new ExtensionsManager({
9-
extensions: (builder) => builder.use(BaseSchema, {}).use(Bold, {}),
9+
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(BoldSpecs),
1010
}).buildDeps();
1111

1212
const {doc, p, b} = builders(schema, {
1313
doc: {nodeType: BaseNode.Doc},
1414
p: {nodeType: BaseNode.Paragraph},
15-
b: {nodeType: bold},
15+
b: {nodeType: boldMarkName},
1616
}) as PMTestBuilderResult<'doc' | 'p', 'b'>;
1717

1818
const {same} = createMarkupChecker({parser, serializer});

0 commit comments

Comments
 (0)