| 102 | * @return {VMScript['meta'] | false} |
| 103 | */ |
| 104 | export function parseMeta(code, { errors, retDefault, retMetaStr } = {}) { |
| 105 | // initialize meta |
| 106 | const meta = metaTypes::mapEntry(value => value.default()); |
| 107 | const match = matchUserScript(code); |
| 108 | if (!match) return retDefault ? meta : false; |
| 109 | // TODO: use `null` instead of `false` + null check in all callers? |
| 110 | if (errors) checkMetaItemErrors(match, 1, errors); |
| 111 | let parts; |
| 112 | while ((parts = META_ITEM_RE.exec(match[4]))) { |
| 113 | const [keyName, locale] = parts[3].slice(1).split(':'); |
| 114 | const camelKey = keyName.replace(/[-_](\w)/g, (m, g) => g.toUpperCase()); |
| 115 | const key = locale ? `${camelKey}:${locale.toLowerCase()}` : camelKey; |
| 116 | const val = parts[4].trim(); |
| 117 | const metaType = metaTypes[key] || metaOptionalTypes[key] || defaultType; |
| 118 | let oldValue = meta[key]; |
| 119 | if (typeof oldValue === 'undefined') oldValue = metaType.default(); |
| 120 | if (errors) checkMetaItemErrors(parts, 0, errors); |
| 121 | meta[key] = metaType.transform(oldValue, val); |
| 122 | } |
| 123 | if (errors) checkMetaItemErrors(match, 5, errors); |
| 124 | meta.resources = meta.resource; |
| 125 | delete meta.resource; |
| 126 | if (retMetaStr) meta[__CODE] = match[0]; |
| 127 | return meta; |
| 128 | } |
| 129 | |
| 130 | function checkMetaItemErrors(parts, index, errors) { |
| 131 | let clipped; |