From c105461647315f7f479091194944713b392ca729 Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Sat, 21 Feb 2026 14:05:38 -0600 Subject: [PATCH] [ie/youtube] Update ejs to 0.5.0 (#16031) Authored by: bashonly --- Makefile | 6 +- pyproject.toml | 2 +- test/test_jsc/test_ejs_integration.py | 60 ++ .../youtube/jsc/_builtin/vendor/_info.py | 6 +- .../jsc/_builtin/vendor/yt.solver.core.js | 584 +++++++++++++----- 5 files changed, 487 insertions(+), 171 deletions(-) diff --git a/Makefile b/Makefile index 11b32ab25c..c4431027fa 100644 --- a/Makefile +++ b/Makefile @@ -202,9 +202,9 @@ CONTRIBUTORS: Changelog.md # The following EJS_-prefixed variables are auto-generated by devscripts/update_ejs.py # DO NOT EDIT! -EJS_VERSION = 0.4.0 -EJS_WHEEL_NAME = yt_dlp_ejs-0.4.0-py3-none-any.whl -EJS_WHEEL_HASH = sha256:19278cff397b243074df46342bb7616c404296aeaff01986b62b4e21823b0b9c +EJS_VERSION = 0.5.0 +EJS_WHEEL_NAME = yt_dlp_ejs-0.5.0-py3-none-any.whl +EJS_WHEEL_HASH = sha256:674fc0efea741d3100cdf3f0f9e123150715ee41edf47ea7a62fbdeda204bdec EJS_PY_FOLDERS = yt_dlp_ejs yt_dlp_ejs/yt yt_dlp_ejs/yt/solver EJS_PY_FILES = yt_dlp_ejs/__init__.py yt_dlp_ejs/_version.py yt_dlp_ejs/yt/__init__.py yt_dlp_ejs/yt/solver/__init__.py EJS_JS_FOLDERS = yt_dlp_ejs/yt/solver diff --git a/pyproject.toml b/pyproject.toml index 34265dfe9b..7a4e860862 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ default = [ "requests>=2.32.2,<3", "urllib3>=2.0.2,<3", "websockets>=13.0", - "yt-dlp-ejs==0.4.0", + "yt-dlp-ejs==0.5.0", ] curl-cffi = [ "curl-cffi>=0.5.10,!=0.6.*,!=0.7.*,!=0.8.*,!=0.9.*,<0.15; implementation_name=='cpython'", diff --git a/test/test_jsc/test_ejs_integration.py b/test/test_jsc/test_ejs_integration.py index 07c1a9b242..64ecffd8fa 100644 --- a/test/test_jsc/test_ejs_integration.py +++ b/test/test_jsc/test_ejs_integration.py @@ -105,6 +105,66 @@ CHALLENGES: list[Challenge] = [ 'gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt': 'ttJC2JfQdSswRAIgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEvaepit0zJAtIEsgOV2SXZjhSHMNy0NXNGa1kOyBf6HPuAuCduh-_', }), + # 4e51e895: main variant broke sig solving; n challenge is added only for regression testing + Challenge('4e51e895', Variant.main, JsChallengeType.N, { + '0eRGgQWJGfT5rFHFj': 't5kO23_msekBur', + }), + Challenge('4e51e895', Variant.main, JsChallengeType.SIG, { + 'AL6p_8AwdY9yAhRzK8rYA_9n97Kizf7_9n97Kizf7_9n97Kizf7_9n97Kizf7_9n97Kizf7_9n97Kizf7': + 'AwdY9yAhRzK8rYA_9n97Kizf7_9n97Kizf7_9n9pKizf7_9n97Kizf7_9n97Kizf7_9n97Kizf7', + }), + # 42c5570b: tce variant broke sig solving; n challenge is added only for regression testing + Challenge('42c5570b', Variant.tce, JsChallengeType.N, { + 'ZdZIqFPQK-Ty8wId': 'CRoXjB-R-R', + }), + Challenge('42c5570b', Variant.tce, JsChallengeType.SIG, { + 'gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt': + 'EN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavcOmNdYN-wUtgEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt', + }), + # 54bd1de4: tce variant broke sig solving; n challenge is added only for regression testing + Challenge('54bd1de4', Variant.tce, JsChallengeType.N, { + 'ZdZIqFPQK-Ty8wId': 'ka-slAQ31sijFN', + }), + Challenge('54bd1de4', Variant.tce, JsChallengeType.SIG, { + 'gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt': + 'gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0titeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtp', + }), + # 94667337: tce and es6 variants broke sig solving; n and main/tv variants are added only for regression testing + Challenge('94667337', Variant.main, JsChallengeType.N, { + 'BQoJvGBkC2nj1ZZLK-': 'ib1ShEOGoFXIIw', + }), + Challenge('94667337', Variant.main, JsChallengeType.SIG, { + 'NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz': + 'AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=', + }), + Challenge('94667337', Variant.tv, JsChallengeType.N, { + 'BQoJvGBkC2nj1ZZLK-': 'ib1ShEOGoFXIIw', + }), + Challenge('94667337', Variant.tv, JsChallengeType.SIG, { + 'NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz': + 'AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=', + }), + Challenge('94667337', Variant.es6, JsChallengeType.N, { + 'BQoJvGBkC2nj1ZZLK-': 'ib1ShEOGoFXIIw', + }), + Challenge('94667337', Variant.es6, JsChallengeType.SIG, { + 'NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz': + 'AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=', + }), + Challenge('94667337', Variant.tce, JsChallengeType.N, { + 'BQoJvGBkC2nj1ZZLK-': 'ib1ShEOGoFXIIw', + }), + Challenge('94667337', Variant.tce, JsChallengeType.SIG, { + 'NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz': + 'AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=', + }), + Challenge('94667337', Variant.es6_tce, JsChallengeType.N, { + 'BQoJvGBkC2nj1ZZLK-': 'ib1ShEOGoFXIIw', + }), + Challenge('94667337', Variant.es6_tce, JsChallengeType.SIG, { + 'NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz': + 'AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=', + }), ] requests: list[JsChallengeRequest] = [] diff --git a/yt_dlp/extractor/youtube/jsc/_builtin/vendor/_info.py b/yt_dlp/extractor/youtube/jsc/_builtin/vendor/_info.py index 14c867c86f..46e52dc94a 100644 --- a/yt_dlp/extractor/youtube/jsc/_builtin/vendor/_info.py +++ b/yt_dlp/extractor/youtube/jsc/_builtin/vendor/_info.py @@ -1,10 +1,10 @@ # This file is generated by devscripts/update_ejs.py. DO NOT MODIFY! -VERSION = '0.4.0' +VERSION = '0.5.0' HASHES = { 'yt.solver.bun.lib.js': '6ff45e94de9f0ea936a183c48173cfa9ce526ee4b7544cd556428427c1dd53c8073ef0174e79b320252bf0e7c64b0032cc1cf9c4358f3fda59033b7caa01c241', - 'yt.solver.core.js': '05964b458d92a65d4fb7a90bcb5921c9fed2370f4e4f2f25badb41f28aff9069e0b3c4e5bf1baf2d3021787b67fc6093cefa44de30cffdc6f9fb25532484003b', - 'yt.solver.core.min.js': '0cd3c0b37e095d3cca99443b58fe03980ac3bf2e777c2485c23e1f6052b5ede9f07c7f1c79a9c3af3258ea91a228f099741e7eb07b53125b5dcc84bb4c0054f3', + 'yt.solver.core.js': '9742868113d7b0c29e24a95c8eb2c2bec7cdf95513dc7f55f523ba053c0ecf2af7dcb0138b1d933578304f0dda633a6b3bfff64e912b4c547b99dad083428c4b', + 'yt.solver.core.min.js': 'aee8c3354cfd535809c871c2a517d03231f89cd184e903af82ee274bcc2e90991ef19cb3f65f2ccc858c4963856ea87f8692fe16d71209f4fc7f41c44b828e36', 'yt.solver.deno.lib.js': '9c8ee3ab6c23e443a5a951e3ac73c6b8c1c8fb34335e7058a07bf99d349be5573611de00536dcd03ecd3cf34014c4e9b536081de37af3637c5390c6a6fd6a0f0', 'yt.solver.lib.js': '1ee3753a8222fc855f5c39db30a9ccbb7967dbe1fb810e86dc9a89aa073a0907f294c720e9b65427d560a35aa1ce6af19ef854d9126a05ca00afe03f72047733', 'yt.solver.lib.min.js': '8420c259ad16e99ce004e4651ac1bcabb53b4457bf5668a97a9359be9a998a789fee8ab124ee17f91a2ea8fd84e0f2b2fc8eabcaf0b16a186ba734cf422ad053', diff --git a/yt_dlp/extractor/youtube/jsc/_builtin/vendor/yt.solver.core.js b/yt_dlp/extractor/youtube/jsc/_builtin/vendor/yt.solver.core.js index ee167fe163..7d37310537 100644 --- a/yt_dlp/extractor/youtube/jsc/_builtin/vendor/yt.solver.core.js +++ b/yt_dlp/extractor/youtube/jsc/_builtin/vendor/yt.solver.core.js @@ -60,26 +60,29 @@ var jsc = (function (meriyah, astring) { } return value; } - const nsigExpression = { - type: 'VariableDeclaration', - kind: 'var', - declarations: [ + const nsig = { + type: 'CallExpression', + callee: { or: [{ type: 'Identifier' }, { type: 'SequenceExpression' }] }, + arguments: [ + {}, { - type: 'VariableDeclarator', - init: { - type: 'CallExpression', - callee: { type: 'Identifier' }, - arguments: [ - { type: 'Literal' }, - { - type: 'CallExpression', - callee: { type: 'Identifier', name: 'decodeURIComponent' }, - }, - ], - }, + type: 'CallExpression', + callee: { type: 'Identifier', name: 'decodeURIComponent' }, + arguments: [{}], }, ], }; + const nsigAssignment = { + type: 'AssignmentExpression', + left: { type: 'Identifier' }, + operator: '=', + right: nsig, + }; + const nsigDeclarator = { + type: 'VariableDeclarator', + id: { type: 'Identifier' }, + init: nsig, + }; const logicalExpression = { type: 'ExpressionStatement', expression: { @@ -97,6 +100,17 @@ var jsc = (function (meriyah, astring) { callee: { type: 'Identifier' }, arguments: { or: [ + [ + { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'decodeURIComponent', + }, + arguments: [{ type: 'Identifier' }], + optional: false, + }, + ], [ { type: 'Literal' }, { @@ -110,6 +124,8 @@ var jsc = (function (meriyah, astring) { }, ], [ + { type: 'Literal' }, + { type: 'Literal' }, { type: 'CallExpression', callee: { @@ -138,18 +154,18 @@ var jsc = (function (meriyah, astring) { expression: { type: 'AssignmentExpression', operator: '=', - left: { type: 'Identifier' }, - right: { type: 'FunctionExpression', params: [{}, {}, {}] }, + left: { or: [{ type: 'Identifier' }, { type: 'MemberExpression' }] }, + right: { type: 'FunctionExpression' }, }, }, - { type: 'FunctionDeclaration', params: [{}, {}, {}] }, + { type: 'FunctionDeclaration' }, { type: 'VariableDeclaration', declarations: { anykey: [ { type: 'VariableDeclarator', - init: { type: 'FunctionExpression', params: [{}, {}, {}] }, + init: { type: 'FunctionExpression' }, }, ], }, @@ -157,124 +173,150 @@ var jsc = (function (meriyah, astring) { ], }; function extract$1(node) { - if (!matchesStructure(node, identifier$1)) { - return null; - } - let block; - if ( + const blocks = []; + if (matchesStructure(node, identifier$1)) { + if ( + node.type === 'ExpressionStatement' && + node.expression.type === 'AssignmentExpression' && + node.expression.right.type === 'FunctionExpression' && + node.expression.right.params.length >= 3 + ) { + blocks.push(node.expression.right.body); + } else if (node.type === 'VariableDeclaration') { + for (const decl of node.declarations) { + if ( + _optionalChain$2([ + decl, + 'access', + (_) => _.init, + 'optionalAccess', + (_2) => _2.type, + ]) === 'FunctionExpression' && + decl.init.params.length >= 3 + ) { + blocks.push(decl.init.body); + } + } + } else if ( + node.type === 'FunctionDeclaration' && + node.params.length >= 3 + ) { + blocks.push(node.body); + } else { + return null; + } + } else if ( node.type === 'ExpressionStatement' && - node.expression.type === 'AssignmentExpression' && - node.expression.right.type === 'FunctionExpression' + node.expression.type === 'SequenceExpression' ) { - block = node.expression.right.body; - } else if (node.type === 'VariableDeclaration') { - for (const decl of node.declarations) { + for (const expr of node.expression.expressions) { if ( - decl.type === 'VariableDeclarator' && - _optionalChain$2([ - decl, - 'access', - (_) => _.init, - 'optionalAccess', - (_2) => _2.type, - ]) === 'FunctionExpression' && - _optionalChain$2([ - decl, - 'access', - (_3) => _3.init, - 'optionalAccess', - (_4) => _4.params, - 'access', - (_5) => _5.length, - ]) === 3 + expr.type === 'AssignmentExpression' && + expr.right.type === 'FunctionExpression' && + expr.right.params.length === 3 ) { - block = decl.init.body; - break; + blocks.push(expr.right.body); } } - } else if (node.type === 'FunctionDeclaration') { - block = node.body; } else { return null; } - const relevantExpression = _optionalChain$2([ - block, - 'optionalAccess', - (_6) => _6.body, - 'access', - (_7) => _7.at, - 'call', - (_8) => _8(-2), - ]); - let call = null; - if (matchesStructure(relevantExpression, logicalExpression)) { - if ( - _optionalChain$2([ - relevantExpression, - 'optionalAccess', - (_9) => _9.type, - ]) !== 'ExpressionStatement' || - relevantExpression.expression.type !== 'LogicalExpression' || - relevantExpression.expression.right.type !== 'SequenceExpression' || - relevantExpression.expression.right.expressions[0].type !== - 'AssignmentExpression' || - relevantExpression.expression.right.expressions[0].right.type !== - 'CallExpression' - ) { - return null; - } - call = relevantExpression.expression.right.expressions[0].right; - } else if ( - _optionalChain$2([ - relevantExpression, - 'optionalAccess', - (_10) => _10.type, - ]) === 'IfStatement' && - relevantExpression.consequent.type === 'BlockStatement' - ) { - for (const n of relevantExpression.consequent.body) { - if (!matchesStructure(n, nsigExpression)) { - continue; + for (const block of blocks) { + let call = null; + for (const stmt of block.body) { + if (matchesStructure(stmt, logicalExpression)) { + if ( + stmt.type === 'ExpressionStatement' && + stmt.expression.type === 'LogicalExpression' && + stmt.expression.right.type === 'SequenceExpression' && + stmt.expression.right.expressions[0].type === + 'AssignmentExpression' && + stmt.expression.right.expressions[0].right.type === 'CallExpression' + ) { + call = stmt.expression.right.expressions[0].right; + } + } else if (stmt.type === 'IfStatement') { + let consequent = stmt.consequent; + while (consequent.type === 'LabeledStatement') { + consequent = consequent.body; + } + if (consequent.type !== 'BlockStatement') { + continue; + } + for (const n of consequent.body) { + if (n.type !== 'VariableDeclaration') { + continue; + } + for (const decl of n.declarations) { + if ( + matchesStructure(decl, nsigDeclarator) && + _optionalChain$2([ + decl, + 'access', + (_3) => _3.init, + 'optionalAccess', + (_4) => _4.type, + ]) === 'CallExpression' + ) { + call = decl.init; + break; + } + } + if (call) { + break; + } + } + } else if (stmt.type === 'ExpressionStatement') { + if ( + stmt.expression.type !== 'LogicalExpression' || + stmt.expression.operator !== '&&' || + stmt.expression.right.type !== 'SequenceExpression' + ) { + continue; + } + for (const expr of stmt.expression.right.expressions) { + if (matchesStructure(expr, nsigAssignment) && expr.type) { + if ( + expr.type === 'AssignmentExpression' && + expr.right.type === 'CallExpression' + ) { + call = expr.right; + break; + } + } + } } - if ( - n.type !== 'VariableDeclaration' || - _optionalChain$2([ - n, - 'access', - (_11) => _11.declarations, - 'access', - (_12) => _12[0], - 'access', - (_13) => _13.init, - 'optionalAccess', - (_14) => _14.type, - ]) !== 'CallExpression' - ) { - continue; + if (call) { + break; } - call = n.declarations[0].init; - break; } + if (!call) { + continue; + } + return { + type: 'ArrowFunctionExpression', + params: [{ type: 'Identifier', name: 'sig' }], + body: { + type: 'CallExpression', + callee: call.callee, + arguments: call.arguments.map((arg) => { + if ( + arg.type === 'CallExpression' && + arg.callee.type === 'Identifier' && + arg.callee.name === 'decodeURIComponent' + ) { + return { type: 'Identifier', name: 'sig' }; + } + return arg; + }), + optional: false, + }, + async: false, + expression: false, + generator: false, + }; } - if (call === null) { - return null; - } - return { - type: 'ArrowFunctionExpression', - params: [{ type: 'Identifier', name: 'sig' }], - body: { - type: 'CallExpression', - callee: { type: 'Identifier', name: call.callee.name }, - arguments: - call.arguments.length === 1 - ? [{ type: 'Identifier', name: 'sig' }] - : [call.arguments[0], { type: 'Identifier', name: 'sig' }], - optional: false, - }, - async: false, - expression: false, - generator: false, - }; + return null; } function _optionalChain$1(ops) { let lastAccessLHS = undefined; @@ -472,8 +514,31 @@ var jsc = (function (meriyah, astring) { return value; } function preprocessPlayer(data) { - const ast = meriyah.parse(data); - const body = ast.body; + const program = meriyah.parse(data); + const plainStatements = modifyPlayer(program); + const solutions = getSolutions(plainStatements); + for (const [name, options] of Object.entries(solutions)) { + plainStatements.push({ + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'MemberExpression', + computed: false, + object: { type: 'Identifier', name: '_result' }, + property: { type: 'Identifier', name: name }, + optional: false, + }, + right: multiTry(options), + }, + }); + } + program.body.splice(0, 0, ...setupNodes); + return astring.generate(program); + } + function modifyPlayer(program) { + const body = program.body; const block = (() => { switch (body.length) { case 1: { @@ -506,16 +571,7 @@ var jsc = (function (meriyah, astring) { } throw 'unexpected structure'; })(); - const found = { n: [], sig: [] }; - const plainExpressions = block.body.filter((node) => { - const n = extract(node); - if (n) { - found.n.push(n); - } - const sig = extract$1(node); - if (sig) { - found.sig.push(sig); - } + block.body = block.body.filter((node) => { if (node.type === 'ExpressionStatement') { if (node.expression.type === 'AssignmentExpression') { return true; @@ -524,41 +580,241 @@ var jsc = (function (meriyah, astring) { } return true; }); - block.body = plainExpressions; - for (const [name, options] of Object.entries(found)) { - const unique = new Set(options.map((x) => JSON.stringify(x))); - if (unique.size !== 1) { - const message = `found ${unique.size} ${name} function possibilities`; - throw ( - message + - (unique.size - ? `: ${options.map((x) => astring.generate(x)).join(', ')}` - : '') - ); + return block.body; + } + function getSolutions(statements) { + const found = { n: [], sig: [] }; + for (const statement of statements) { + const n = extract(statement); + if (n) { + found.n.push(n); + } + const sig = extract$1(statement); + if (sig) { + found.sig.push(sig); } - plainExpressions.push({ - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: { - type: 'MemberExpression', - computed: false, - object: { type: 'Identifier', name: '_result' }, - property: { type: 'Identifier', name: name }, - }, - right: options[0], - }, - }); } - ast.body.splice(0, 0, ...setupNodes); - return astring.generate(ast); + return found; } function getFromPrepared(code) { const resultObj = { n: null, sig: null }; Function('_result', code)(resultObj); return resultObj; } + function multiTry(generators) { + return { + type: 'ArrowFunctionExpression', + params: [{ type: 'Identifier', name: '_input' }], + body: { + type: 'BlockStatement', + body: [ + { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { type: 'Identifier', name: '_results' }, + init: { + type: 'NewExpression', + callee: { type: 'Identifier', name: 'Set' }, + arguments: [], + }, + }, + ], + }, + { + type: 'ForOfStatement', + left: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { type: 'Identifier', name: '_generator' }, + init: null, + }, + ], + }, + right: { type: 'ArrayExpression', elements: generators }, + body: { + type: 'BlockStatement', + body: [ + { + type: 'TryStatement', + block: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { type: 'Identifier', name: '_results' }, + computed: false, + property: { type: 'Identifier', name: 'add' }, + optional: false, + }, + arguments: [ + { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '_generator', + }, + arguments: [ + { type: 'Identifier', name: '_input' }, + ], + optional: false, + }, + ], + optional: false, + }, + }, + ], + }, + handler: { + type: 'CatchClause', + param: null, + body: { type: 'BlockStatement', body: [] }, + }, + finalizer: null, + }, + ], + }, + await: false, + }, + { + type: 'IfStatement', + test: { + type: 'UnaryExpression', + operator: '!', + argument: { + type: 'MemberExpression', + object: { type: 'Identifier', name: '_results' }, + computed: false, + property: { type: 'Identifier', name: 'size' }, + optional: false, + }, + prefix: true, + }, + consequent: { + type: 'BlockStatement', + body: [ + { + type: 'ThrowStatement', + argument: { + type: 'TemplateLiteral', + expressions: [], + quasis: [ + { + type: 'TemplateElement', + value: { cooked: 'no solutions', raw: 'no solutions' }, + tail: true, + }, + ], + }, + }, + ], + }, + alternate: null, + }, + { + type: 'IfStatement', + test: { + type: 'BinaryExpression', + left: { + type: 'MemberExpression', + object: { type: 'Identifier', name: '_results' }, + computed: false, + property: { type: 'Identifier', name: 'size' }, + optional: false, + }, + right: { type: 'Literal', value: 1 }, + operator: '!==', + }, + consequent: { + type: 'BlockStatement', + body: [ + { + type: 'ThrowStatement', + argument: { + type: 'TemplateLiteral', + expressions: [ + { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { type: 'Identifier', name: '_results' }, + computed: false, + property: { type: 'Identifier', name: 'join' }, + optional: false, + }, + arguments: [{ type: 'Literal', value: ', ' }], + optional: false, + }, + ], + quasis: [ + { + type: 'TemplateElement', + value: { + cooked: 'invalid solutions: ', + raw: 'invalid solutions: ', + }, + tail: false, + }, + { + type: 'TemplateElement', + value: { cooked: '', raw: '' }, + tail: true, + }, + ], + }, + }, + ], + }, + alternate: null, + }, + { + type: 'ReturnStatement', + argument: { + type: 'MemberExpression', + object: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { type: 'Identifier', name: '_results' }, + computed: false, + property: { type: 'Identifier', name: 'values' }, + optional: false, + }, + arguments: [], + optional: false, + }, + computed: false, + property: { type: 'Identifier', name: 'next' }, + optional: false, + }, + arguments: [], + optional: false, + }, + computed: false, + property: { type: 'Identifier', name: 'value' }, + optional: false, + }, + }, + ], + }, + async: false, + expression: false, + generator: false, + }; + } function main(input) { const preprocessedPlayer = input.type === 'player'