将 Markdown 表格迁移到 Contentful 中的富文本创建内联条目

Migrating Markdown Tables to Rich Text in Contentful creating inline Entries

我想将用 Markdown 编写的长文章迁移到富文本字段。除了 table 之外,我可以处理所有事情。 In the documentation it says:

Migrate the content into a linked entry which only has a Markdown field with the supported content, which is similar to the action performed in step 8

但我无法让它工作。在提到的第 8 步中,没有创建新条目,仅链接现有条目。我还没有弄清楚如何即时创建类型为 table 的新条目(这只是一个带有名称内容的 Markdown 类型的字段)并在富文本内容中引用它。 deriveLinkedEntries() 想要将引用放入特定字段,但这是内联的并且可以存在多次。

我可以在富文本字段中手动创建一个 table 并内联对内容的引用,但我想用迁移脚本创建它,但不知道如何创建。

这些是我的内容类型:

这就是我在 table 的控制台上得到的:

{
    type: 'table',
    align: [ null, 'center', 'right' ],
    children: [
        { type: 'tableRow', children: [Array], position: [Position] },
        { type: 'tableRow', children: [Array], position: [Position] }
    ],
    position: Position {
        start: { line: 14, column: 1, offset: 970 },
        end: { line: 25, column: 58, offset: 1660 },
        indent: [
            1, 1
        ]
    }
}

这是我到目前为止的代码(为简洁起见进行了清理):

const {richTextFromMarkdown} = require('@contentful/rich-text-from-markdown')
        
module.exports = function(migration) {
    
    migration.transformEntries({
        contentType: 'article',
        from: ['content'],
        to: ['contentV2'],
        transformEntryForLocale: async function(fromFields, currentLocale)
        {
            let copy        = fromFields.content[currentLocale]

            const content = await richTextFromMarkdown(copy,
                (node) => {
                    let ret = null
                    let didSomething = true

                    node.deriveLinkedEntries()

                    switch (node.type) {
                        case 'image':
                            // ...
                            break;
                        case 'html':
                            // ...
                            break;
                        default:
                            didSomething = false
                    }

                    if (false === didSomething) {
                        console.log(node)
                    }

                    return ret
                }
            )

            return {
                contentV2: {
                    nodeType: 'document',
                    content: content.content,
                    data: {}
                },
            }
        }
    })
}

经过更多的头痛和良好的睡眠后,我找到了解决方案:

const { richTextFromMarkdown } = require('@contentful/rich-text-from-markdown')
const { createClient } = require('contentful-management')
        
module.exports = function(migration) 
{
    const managementClient = createClient({ accessToken: context.accessToken })
    const space            = await managementClient.getSpace(context.spaceId)
    const environment      = await space.getEnvironment(config.activeEnvironmentId)

     /**
     * Creates a simple hash for a string
     * @param string
     */
    function createHash(string)
    {
        let hash = 0,
            i,
            chr

        if (string.length === 0) {
            return hash
        }

        for (i = 0; i < string.length; i++)
        {
            chr   = string.charCodeAt(i);
            hash  = ((hash << 5) - hash) + chr;
            hash |= 0 // Convert to 32bit integer
        }

        return hash
    }

    /**
     * Extracts part from MarkDown that is the table, transfers content into an
     * entry that is just a MarkDown field. Entry is created if does not exist
     * @param table
     * @param copy
     */
    async function linkTableEntry(table, copy)
    {
        // extract MarkDown for the table from the entered text
        const pos      = table.position
        const strLen   = pos.end.offset - pos.start.offset
        const tableStr = copy.substr(pos.start.offset, strLen)
        const id       = createHash(tableStr) // avoid creating same table twice
        let   entry

        try {
            entry = await environment.getEntry(id)
        } catch (e) { }

        // create new since it does not exist yet
        if ('undefined' === typeof entry) {
            entry = await createTableEntry(tableStr, id)
        }

        return {
            nodeType: 'embedded-entry-block',
            content: [],
            data: {
                target: {
                    sys: {
                        type: 'Link',
                        linkType: 'Entry',
                        id: entry.sys.id
                    }
                }
            }
        }
    }

    /**
     * Creates a new Entry element with a string representing the table MarkDown
     * The table header is transformed into a title for the Entry
     * @param tablestring
     * @param id
     */
    async function createTableEntry(tablestring, id)
    {
        // create entry title from table header
        const title = tablestring
                        .match(/^.+|\n/g)[0]     // first line
                        .split('|')
                        .filter(Boolean)         // remove empty elements
                        .join(', ')              // Column-Names joined by comma
                        .replace(/\t/g, '')      // remove tabs
                        .replace(/[ ]+,/g, ', ') // no spaces before comma
                        .replace(/[ ]+/g, ' ')   // no multiple spaces
                        .trim()

        let entry = await environment.createEntryWithId('table', id, {
            fields: {
                title: {
                    'de-DE': title
                },
                content: {
                    'de-DE': tablestring
                    }
                }
        })

        return await entry.publish()
    }

    migration.transformEntries({
        contentType: 'article',
        from: ['content'],
        to: ['contentV2'],
        transformEntryForLocale: async function(fromFields, currentLocale)
        {
            let copy = fromFields.content[currentLocale]

            const content = await richTextFromMarkdown(copy,
                async (node) => {
                    let ret = null
                    let didSomething = true

                    node.deriveLinkedEntries()

                    switch (node.type) {
                        case 'image':
                            // ...
                            break;
                        case 'html':
                            // ...
                            break;
                        case 'table':
                            ret = await linkTableEntry(node, copy)
                            break
                        default:
                            didSomething = false
                    }

                    if (false === didSomething) {
                        console.log(node)
                    }

                    return ret
                }
            )

            return {
                contentV2: {
                    nodeType: 'document',
                    content: content.content,
                    data: {}
                },
            }
        }
    })
}

基本上这里发生了什么:

  • 我创建了一个新的内容模型 table,它只有一个 title 和一个长文本字段 content
  • 我们使用 richTextFromMarkdown() 给出的位置信息(例如参见问题)从内容
  • 中提取 table 的 MarkDown 字符串
  • 我们为该字符串生成一个简单的散列,因此如果我们需要重新运行 迁移
  • ,我们不会创建相同的 table 两次
  • 如果 table 已经存在,我们内联现有的,如果不存在,我们使用 ContentFul 的 managementClient 动态创建一个新的
  • 通过此条目的 sys.id,我们可以将链接条目放入富文本字段

我希望这对某些人有所帮助,因为我找不到有关将 tables 从 MarkDown 迁移到 Contentful 中的富文本的任何内容。