* @param {VMScript} script * @param {VMInjection.EnvStart} env * @return {VMInjection.Script}
(script, env)
| 491 | * @return {VMInjection.Script} |
| 492 | */ |
| 493 | function prepareScript(script, env) { |
| 494 | const { custom, meta, props } = script; |
| 495 | const { id } = props; |
| 496 | const { [S_REQUIRE]: require, [RUN_AT]: runAt } = env; |
| 497 | const code = env[S_CODE][id]; |
| 498 | const dataKey = getUniqId(); |
| 499 | const winKey = getUniqId(); |
| 500 | const plantKey = { data: dataKey, win: winKey }; |
| 501 | const displayName = getScriptName(script); |
| 502 | const pathMap = custom.pathMap || {}; |
| 503 | const wrap = !meta[UNWRAP]; |
| 504 | const wrapTryCatch = wrap && IS_FIREFOX; // FF doesn't show errors in content script's console |
| 505 | const { grant, [TL_AWAIT]: topLevelAwait } = meta; |
| 506 | const startIIFE = topLevelAwait ? 'await(async' : '('; |
| 507 | const grantNone = grant.includes('none'); |
| 508 | const shouldUpdate = !!script.config.shouldUpdate; |
| 509 | // Storing slices separately to reuse JS-internalized strings for code in our storage cache |
| 510 | const injectedCode = []; |
| 511 | const metaCopy = meta::mapEntry(null, pluralizeMeta); |
| 512 | const metaStrMatch = METABLOCK_RE.exec(code); |
| 513 | let codeIndex; |
| 514 | let tmp; |
| 515 | for (const key of META_KEYS_TO_ENSURE) { |
| 516 | if (metaCopy[key] == null) metaCopy[key] = ''; |
| 517 | } |
| 518 | for (const [key, from] of META_KEYS_TO_ENSURE_FROM) { |
| 519 | if (!metaCopy[key] && (tmp = metaCopy[from])) { |
| 520 | metaCopy[key] = tmp; |
| 521 | } |
| 522 | } |
| 523 | metaCopy.options = { // TM-compatibility |
| 524 | check_for_updates: shouldUpdate, |
| 525 | inject_into: custom[INJECT_INTO] || null, |
| 526 | noframes: custom.noframes ?? null, |
| 527 | override: { |
| 528 | merge_excludes: custom.origExclude, |
| 529 | merge_includes: custom.origInclude, |
| 530 | merge_matches: custom.origMatch, |
| 531 | merge_exclude_matches: custom.origExcludeMatch, |
| 532 | merge_tags: custom[kOrigTag], |
| 533 | use_excludes: custom.exclude || [], |
| 534 | use_includes: custom.include || [], |
| 535 | use_matches: custom.match || [], |
| 536 | use_exclude_matches: custom.excludeMatch || [], |
| 537 | }, |
| 538 | run_at: custom[RUN_AT] || null, |
| 539 | tags: custom[kTag] || [], |
| 540 | user_modified: script.props.lastModified || 0, |
| 541 | }; |
| 542 | if (wrap) { |
| 543 | // TODO: push winKey/dataKey as separate chunks so we can change them for each injection? |
| 544 | injectedCode.push('window.', winKey, '=', |
| 545 | wrapTryCatch && topLevelAwait ? 'async ' : '', |
| 546 | 'function ', dataKey, '(', |
| 547 | // using a shadowed name to avoid scope pollution |
| 548 | grantNone ? GRANT_NONE_VARS : 'GM', |
| 549 | wrapTryCatch ? `,${dataKey}){try{` : '){', |
| 550 | grantNone ? '' : 'with(this)with(c)delete c,', |
no test coverage detected