* Converts a serializable VDOM object into a valid Acorn AST `ObjectExpression`. * This function is the critical bridge between the intermediate VDOM representation and the * final, executable code. It recursively builds the AST, paying special attention to the * `##__NEO_EXPR__...##` placeholder
(json)
| 42 | * @private |
| 43 | */ |
| 44 | function jsonToAst(json) { |
| 45 | if (json === null) { |
| 46 | return { type: 'Literal', value: null }; |
| 47 | } |
| 48 | switch (typeof json) { |
| 49 | case 'string': |
| 50 | const exprMatch = json.match(/^##__NEO_EXPR__(.*)##__NEO_EXPR__##$/s); |
| 51 | if (exprMatch) { |
| 52 | try { |
| 53 | return acorn.parseExpressionAt(exprMatch[1], 0, {ecmaVersion: 'latest'}); |
| 54 | } catch (e) { |
| 55 | console.error(`Failed to parse expression: ${exprMatch[1]}`, e); |
| 56 | return { type: 'Literal', value: json }; |
| 57 | } |
| 58 | } |
| 59 | return { type: 'Literal', value: json }; |
| 60 | case 'number': |
| 61 | case 'boolean': |
| 62 | return { type: 'Literal', value: json }; |
| 63 | case 'object': |
| 64 | if (json.__neo_component_name__) { |
| 65 | return { type: 'Identifier', name: json.__neo_component_name__ }; |
| 66 | } |
| 67 | if (Array.isArray(json)) { |
| 68 | return { |
| 69 | type: 'ArrayExpression', |
| 70 | elements: json.map(jsonToAst) |
| 71 | }; |
| 72 | } |
| 73 | const properties = Object.entries(json).map(([key, value]) => { |
| 74 | const keyNode = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) |
| 75 | ? { type: 'Identifier', name: key } |
| 76 | : { type: 'Literal', value: key }; |
| 77 | return { |
| 78 | type: 'Property', |
| 79 | key: keyNode, |
| 80 | value: jsonToAst(value), |
| 81 | kind: 'init', |
| 82 | computed: keyNode.type === 'Literal' |
| 83 | }; |
| 84 | }); |
| 85 | return { type: 'ObjectExpression', properties }; |
| 86 | default: |
| 87 | return { type: 'Literal', value: null }; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Performs a true post-order traversal of the AST (children before parent). |
no test coverage detected