Skip to content

feat(core): allow independent registration and override of node/mark specs in extensions#990

Draft
d3m1d0v wants to merge 1 commit intomainfrom
upd-extension-builder
Draft

feat(core): allow independent registration and override of node/mark specs in extensions#990
d3m1d0v wants to merge 1 commit intomainfrom
upd-extension-builder

Conversation

@d3m1d0v
Copy link
Copy Markdown
Member

@d3m1d0v d3m1d0v commented Mar 14, 2026

Description

addNode/addMark bundle schema spec, parser spec, and serializer spec into a single callback, making it impossible for one extension to incrementally modify another — the only option was full replacement.

This PR adds granular registration and override methods to ExtensionBuilder:

New add methods:

  • addNodeSpec, addMarkSpec — register ProseMirror schema specs independently
  • addMarkdownTokenParserSpec — register markdown-it token → PM entity mapping
  • addNodeSerializerSpec, addMarkSerializerSpec — register serializer specs

New override methods:

  • overrideNodeSpec, overrideMarkSpec — modify previously registered schema specs
  • overrideMarkdownTokenParserSpec — modify parser token specs (works with both addNode and granular API)
  • overrideNodeSerializerSpec, overrideMarkSerializerSpec — modify serializer specs

addNode and addMark methods are marked as @deprecated.

@gravity-ui
Copy link
Copy Markdown

gravity-ui bot commented Mar 14, 2026

Storybook Deployed

@gravity-ui
Copy link
Copy Markdown

gravity-ui bot commented Mar 14, 2026

🎭 Playwright Report

@d3m1d0v d3m1d0v force-pushed the upd-extension-builder branch from fed0b73 to 90f79f8 Compare March 14, 2026 20:15
@d3m1d0v d3m1d0v force-pushed the upd-extension-builder branch from 90f79f8 to 9823331 Compare March 23, 2026 16:17
});

describe('granular add methods', () => {
it('should add node via granular methods', () => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it('should preserve addNode full spec when addMarkdownTokenParserSpec uses same tokenName', () => {
    // Bug scenario: tokenName === entityName in step 1b of build()
    // Step 1 adds full spec under 'code_block'.
    // Step 1b finds parserSpecsByEntity['code_block'] and calls map.addToEnd('code_block', parserOnlyEntry),
    // which overwrites the full spec with { spec: {}, toMd: () => { throw } }.
    const realToMd = jest.fn();

    const nodes = new ExtensionBuilder(logger)
        .addNode('code_block', () => ({
            spec: {group: 'block', code: true},
            fromMd: {tokenSpec: {name: 'code_block', type: 'block', noCloseToken: true}},
            toMd: realToMd,
        }))
        .addMarkdownTokenParserSpec('code_block', () => ({
            // tokenName === entityName: 'code_block' → 'code_block'
            name: 'code_block',
            type: 'block',
            noCloseToken: true,
        }))
        .build()
        .nodes();

    // Full addNode spec must survive — not be replaced by parser-only entry
    expect(nodes.size).toBe(1);

    const codeBlock = nodes.get('code_block');
    expect(codeBlock).toBeTruthy();
    // Spec must be the real one, not {} from buildParserOnlyNodeEntry
    expect(codeBlock!.spec.group).toBe('block');
    expect(codeBlock!.spec.code).toBe(true);
    // toMd must be the real function, not the throwing stub
    expect(codeBlock!.toMd).toBe(realToMd);
    expect(() => (codeBlock!.toMd as Function)()).not.toThrow();
});

* @deprecated Will be removed in the next major version.
* Use addNodeSpec() + addMarkdownTokenParserSpec() + addNodeSerializerSpec() instead.
*/
addNode(name: string, cb: AddPmNodeCallback): this {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add the same checks like:

        if (this.#rawNodeSpecs[name]) {
            throw new Error(`Node spec with name "${name}" already registered via addNodeSpec`);
        }

?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants