(node)
| 83 | } |
| 84 | |
| 85 | function assertJsonNode(node) { |
| 86 | switch (node.type) { |
| 87 | case "ArrayExpression": |
| 88 | for (const element of node.elements) { |
| 89 | if (element !== null) { |
| 90 | assertJsonNode(element); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | return; |
| 95 | case "ObjectExpression": |
| 96 | for (const property of node.properties) { |
| 97 | assertJsonNode(property); |
| 98 | } |
| 99 | |
| 100 | return; |
| 101 | case "ObjectProperty": |
| 102 | if (node.computed) { |
| 103 | throw createJsonError(node.key, "Computed key"); |
| 104 | } |
| 105 | |
| 106 | if (node.shorthand) { |
| 107 | throw createJsonError(node.key, "Shorthand property"); |
| 108 | } |
| 109 | |
| 110 | if (node.key.type !== "Identifier") { |
| 111 | assertJsonNode(node.key); |
| 112 | } |
| 113 | |
| 114 | assertJsonNode(node.value); |
| 115 | |
| 116 | return; |
| 117 | case "UnaryExpression": { |
| 118 | const { operator, argument } = node; |
| 119 | if (operator !== "+" && operator !== "-") { |
| 120 | throw createJsonError(node, `Operator '${node.operator}'`); |
| 121 | } |
| 122 | |
| 123 | if ( |
| 124 | argument.type === "NumericLiteral" || |
| 125 | (argument.type === "Identifier" && |
| 126 | (argument.name === "Infinity" || argument.name === "NaN")) |
| 127 | ) { |
| 128 | return; |
| 129 | } |
| 130 | |
| 131 | throw createJsonError( |
| 132 | argument, |
| 133 | `Operator '${operator}' before '${argument.type}'`, |
| 134 | ); |
| 135 | } |
| 136 | case "Identifier": |
| 137 | if ( |
| 138 | // JSON5 https://spec.json5.org/#numbers |
| 139 | node.name !== "Infinity" && |
| 140 | node.name !== "NaN" && |
| 141 | // JSON6 https://github.com/d3x0r/JSON6 |
| 142 | node.name !== "undefined" |
no test coverage detected