refactor(Player)!: Use AST-based JS extraction with side-effect safe code emission (#1052)

* chore(deps): Add `meriyah`

* feat(utils): Implement AST-based JS extractors

* chore(utils): Remove old ast walker code

* fix(Player): Migrate js extraction logic

* chore(JsExtractor): Fix typo in tsdoc

* perf(JsAnalyzer): Simplify main AST analysis logic

* fix(JsAnalyzer): Change `break` to `return` in AST matching logic

* chore: Update docs

* chore: Don't export `PlayerInitializationOptions`

* chore(evaluate): Update error message to include doc link

* perf: Use a `for-loop` to find iife
This commit is contained in:
Luan
2025-10-12 09:08:51 -03:00
committed by GitHub
parent bffa92d96e
commit 25d0876b91
873 changed files with 10992 additions and 8345 deletions

View File

@@ -1,6 +1,6 @@
import type { ICache } from '../types/Cache.js';
import { Platform } from '../utils/Utils.js';
import evaluate from './jsruntime/jinter.js';
import evaluate from './jsruntime/default.js';
import sha1Hash from './polyfills/web-crypto.js';
class Cache implements ICache {

View File

@@ -1,7 +1,7 @@
// Deno Platform Support
import type { ICache } from '../types/Cache.js';
import { Platform } from '../utils/Utils.js';
import evaluate from './jsruntime/jinter.js';
import evaluate from './jsruntime/default.js';
import sha1Hash from './polyfills/web-crypto.js';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -50,7 +50,7 @@ class Cache implements ICache {
const stat = await Deno.stat(file);
if (stat.isFile) {
const data: Uint8Array = await Deno.readFile(file);
return data.buffer;
return data.buffer as ArrayBuffer;
}
throw new Error('An unexpected file was found in place of the cache key');

View File

@@ -0,0 +1,9 @@
import type { VMPrimative } from '../../types/index.js';
import type { BuildScriptResult } from '../../utils/javascript/JsExtractor.js';
export default function evaluate(_data: BuildScriptResult, _env: Record<string, VMPrimative>) {
throw new Error(
'To decipher URLs, you must provide your own JavaScript evaluator. ' +
'See https://ytjs.dev/guide/getting-started.html#providing-a-custom-javascript-interpreter for more details.'
);
}

View File

@@ -1,21 +0,0 @@
import { Jinter } from 'jintr';
import type { VMPrimative } from '../../types/PlatformShim.js';
import { Log } from '../lib.js';
const TAG = 'JsRuntime';
export default function evaluate(code: string, env: Record<string, VMPrimative>) {
Log.debug(TAG, 'Evaluating JavaScript:\n', code);
const runtime = new Jinter();
for (const [ key, value ] of Object.entries(env)) {
runtime.scope.set(key, value);
}
const result = runtime.evaluate(code);
Log.debug(TAG, 'Done. Result:', result);
return result;
}

View File

@@ -8,7 +8,7 @@ import os from 'os';
import fs from 'fs/promises';
import CustomEvent from './polyfills/node-custom-event.js';
import { fileURLToPath } from 'url';
import evaluate from './jsruntime/jinter.js';
import evaluate from './jsruntime/default.js';
const meta_url = import.meta.url;
const is_cjs = !meta_url;
@@ -56,7 +56,7 @@ class Cache implements ICache {
const stat = await fs.stat(file);
if (stat.isFile()) {
const data: Buffer = await fs.readFile(file);
return data.buffer;
return data.buffer as ArrayBuffer;
}
throw new Error('An unexpected file was found in place of the cache key');

View File

@@ -2,7 +2,7 @@
import type { ICache } from '../types/Cache.js';
import { Platform } from '../utils/Utils.js';
import sha1Hash from './polyfills/web-crypto.js';
import evaluate from './jsruntime/jinter.js';
import evaluate from './jsruntime/default.js';
class Cache implements ICache {
#persistent_directory: string;

View File

@@ -2,7 +2,7 @@
import type { ICache } from '../types/Cache.js';
import { Platform } from '../utils/Utils.js';
import sha1Hash from './polyfills/web-crypto.js';
import evaluate from './jsruntime/jinter.js';
import evaluate from './jsruntime/default.js';
import * as Log from '../utils/Log.js';
const CACHE_TAG = 'Cache';
@@ -60,7 +60,7 @@ class Cache implements ICache {
if (result instanceof ArrayBuffer) {
resolve(result);
} else if (ArrayBuffer.isView(result)) {
resolve(result.buffer);
resolve(result.buffer as ArrayBuffer);
} else {
resolve(undefined);
}