(data, options = {})
| 76 | const identifierNameRE = /^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u; |
| 77 | |
| 78 | const dataToEsm: DataToEsm = function dataToEsm(data, options = {}) { |
| 79 | const t = options.compact ? '' : 'indent' in options ? options.indent : '\t'; |
| 80 | const _ = options.compact ? '' : ' '; |
| 81 | const n = options.compact ? '' : '\n'; |
| 82 | const declarationType = options.preferConst ? 'const' : 'var'; |
| 83 | |
| 84 | if ( |
| 85 | options.namedExports === false || |
| 86 | typeof data !== 'object' || |
| 87 | Array.isArray(data) || |
| 88 | data instanceof Date || |
| 89 | data instanceof RegExp || |
| 90 | data === null |
| 91 | ) { |
| 92 | const code = serialize(data, options.compact ? null : t, ''); |
| 93 | const magic = _ || (/^[{[\-\/]/.test(code) ? '' : ' '); // eslint-disable-line no-useless-escape |
| 94 | return `export default${magic}${code};`; |
| 95 | } |
| 96 | |
| 97 | let maxUnderbarPrefixLength = 0; |
| 98 | for (const key of Object.keys(data)) { |
| 99 | const underbarPrefixLength = /^(_+)/.exec(key)?.[0].length ?? 0; |
| 100 | if (underbarPrefixLength > maxUnderbarPrefixLength) { |
| 101 | maxUnderbarPrefixLength = underbarPrefixLength; |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | const arbitraryNamePrefix = `${'_'.repeat(maxUnderbarPrefixLength + 1)}arbitrary`; |
| 106 | |
| 107 | let namedExportCode = ''; |
| 108 | const defaultExportRows = []; |
| 109 | const arbitraryNameExportRows: string[] = []; |
| 110 | for (const [key, value] of Object.entries(data)) { |
| 111 | if (key === makeLegalIdentifier(key)) { |
| 112 | if (options.objectShorthand) defaultExportRows.push(key); |
| 113 | else defaultExportRows.push(`${key}:${_}${key}`); |
| 114 | namedExportCode += `export ${declarationType} ${key}${_}=${_}${serialize( |
| 115 | value, |
| 116 | options.compact ? null : t, |
| 117 | '' |
| 118 | )};${n}`; |
| 119 | } else { |
| 120 | defaultExportRows.push( |
| 121 | `${stringify(key)}:${_}${serialize(value, options.compact ? null : t, '')}` |
| 122 | ); |
| 123 | // A `default` key is exposed only through the default export object: a |
| 124 | // `... as default` re-export would clash with the trailing `export default` |
| 125 | // and produce a duplicate default export (a SyntaxError). |
| 126 | if (key !== 'default') { |
| 127 | // A valid `IdentifierName` that is not a legal binding identifier (a |
| 128 | // reserved word or global, e.g. `switch`, `await`) is re-exported with the |
| 129 | // unquoted `export { _x as switch }` form, valid since ES2015. Any other |
| 130 | // key needs the quoted arbitrary-namespace form (ES2022+), which remains |
| 131 | // opt-in via `includeArbitraryNames`. |
| 132 | const isIdentifierName = identifierNameRE.test(key); |
| 133 | if (isIdentifierName || (options.includeArbitraryNames && isWellFormedString(key))) { |
| 134 | const variableName = `${arbitraryNamePrefix}${arbitraryNameExportRows.length}`; |
| 135 | namedExportCode += `${declarationType} ${variableName}${_}=${_}${serialize( |
no test coverage detected