(locale, input)
| 32 | > { |
| 33 | return createLoader({ |
| 34 | async pull(locale, input) { |
| 35 | const result: Record<string, any> = {}; |
| 36 | |
| 37 | // Handle empty input |
| 38 | if (!input || input.trim() === "") { |
| 39 | return result; |
| 40 | } |
| 41 | |
| 42 | try { |
| 43 | const parsed = await parseStringPromise(input, { |
| 44 | explicitArray: true, |
| 45 | explicitChildren: true, |
| 46 | preserveChildrenOrder: true, |
| 47 | charsAsChildren: true, |
| 48 | includeWhiteChars: true, |
| 49 | mergeAttrs: false, |
| 50 | trim: false, |
| 51 | attrkey: "$", |
| 52 | charkey: "_", |
| 53 | childkey: "$$", |
| 54 | }); |
| 55 | |
| 56 | if (!parsed || typeof parsed !== "object") { |
| 57 | console.error("Failed to parse MJML: invalid parsed structure"); |
| 58 | return result; |
| 59 | } |
| 60 | |
| 61 | const rootKey = Object.keys(parsed).find(key => !key.startsWith("_") && !key.startsWith("$")); |
| 62 | const rootNode = rootKey ? parsed[rootKey] : parsed; |
| 63 | const rootPath = rootNode["#name"] || rootKey || ""; |
| 64 | |
| 65 | traverse(rootNode, (node, path, componentName) => { |
| 66 | if (typeof node !== "object") return; |
| 67 | |
| 68 | const localizableAttrs = LOCALIZABLE_ATTRIBUTES[componentName]; |
| 69 | if (localizableAttrs && node.$) { |
| 70 | localizableAttrs.forEach((attr) => { |
| 71 | const attrValue = node.$[attr]; |
| 72 | if (attrValue) { |
| 73 | result[`${path}#${attr}`] = attrValue; |
| 74 | } |
| 75 | }); |
| 76 | } |
| 77 | |
| 78 | if (LOCALIZABLE_COMPONENTS.includes(componentName)) { |
| 79 | const innerHTML = getInnerHTML(node); |
| 80 | if (innerHTML) { |
| 81 | result[path] = innerHTML; |
| 82 | return "SKIP_CHILDREN"; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | return undefined; |
| 87 | }, rootPath); |
| 88 | } catch (error) { |
| 89 | console.error("Failed to parse MJML:", error); |
| 90 | } |
| 91 |
nothing calls this directly
no test coverage detected