Apply formatter

This commit is contained in:
Simon Sawicki
2025-09-27 17:23:20 +02:00
parent 5f23fc89fc
commit 1adbcc85e3
9 changed files with 388 additions and 377 deletions

View File

@@ -1,22 +1,23 @@
{
"name": "ejs",
"type": "module",
"scripts": {
"bundle": "rollup -c"
},
"dependencies": {
"astring": "1.9.0",
"meriyah": "6.1.4"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-sucrase": "5.0.2",
"@rollup/plugin-terser": "0.4.4",
"rollup-plugin-license": "^3.6.0",
"@types/bun": "1.2.21",
"@types/deno": "2.3.0",
"@types/node": "24.3.0",
"rollup": "4.50.0",
"prettier": "^3.6.2"
}
"name": "ejs",
"type": "module",
"scripts": {
"bundle": "rollup -c",
"fmt": "prettier --write \"src/**.ts\" \"tests/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\""
},
"dependencies": {
"astring": "1.9.0",
"meriyah": "6.1.4"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-sucrase": "5.0.2",
"@rollup/plugin-terser": "0.4.4",
"rollup-plugin-license": "^3.6.0",
"@types/bun": "1.2.21",
"@types/deno": "2.3.0",
"@types/node": "24.3.0",
"rollup": "4.50.0",
"prettier": "^3.6.2"
}
}

View File

@@ -1,261 +1,266 @@
import {defineConfig} from "rollup";
import { defineConfig } from "rollup";
import nodeResolve from "@rollup/plugin-node-resolve";
import sucrase from "@rollup/plugin-sucrase";
import terser from "@rollup/plugin-terser";
import {createHash} from "node:crypto";
import {Buffer} from "node:buffer";
import license from 'rollup-plugin-license';
import {readFileSync} from "node:fs";
import { createHash } from "node:crypto";
import { Buffer } from "node:buffer";
import license from "rollup-plugin-license";
import { readFileSync } from "node:fs";
import prettier from "prettier";
const pkg = JSON.parse(readFileSync('./package.json'));
const pkg = JSON.parse(readFileSync("./package.json"));
const LICENSE_BANNER =
"SPDX-License-Identifier: Unlicense\n" +
"This file was automatically generated by https://github.com/yt-dlp/ejs on <%= moment().toISOString() %>" +
"<% if (dependencies && dependencies.length) { %>" +
"\n\nBundled Dependencies:" +
"<% _.forEach(dependencies, function (dependency) { if (!dependency.private) { %>" +
"\n\n---\nName: <%= dependency.name %>" +
"<% if (dependency.version) { %>\nVersion: <%= dependency.version %><% } %>" +
"\nLicense: <%= dependency.license %>" +
"<% if (dependency.repository && dependency.repository.url) { %>\nRepository: <%= dependency.repository.url %><% } %>" +
"<% if (dependency.homepage && dependency.homepage.url) { %>\nHomepage: <%= dependency.homepage.url %><% } %>" +
"<% if (dependency.author) { %>\nAuthor: <%= dependency.author.text() %><% } %>" +
"<% if (dependency.licenseText) { %>\n\n<%= dependency.licenseText %><% } %>" +
"\n---<% } }) %>\n<% } %>"
"SPDX-License-Identifier: Unlicense\n" +
"This file was automatically generated by https://github.com/yt-dlp/ejs on <%= moment().toISOString() %>" +
"<% if (dependencies && dependencies.length) { %>" +
"\n\nBundled Dependencies:" +
"<% _.forEach(dependencies, function (dependency) { if (!dependency.private) { %>" +
"\n\n---\nName: <%= dependency.name %>" +
"<% if (dependency.version) { %>\nVersion: <%= dependency.version %><% } %>" +
"\nLicense: <%= dependency.license %>" +
"<% if (dependency.repository && dependency.repository.url) { %>\nRepository: <%= dependency.repository.url %><% } %>" +
"<% if (dependency.homepage && dependency.homepage.url) { %>\nHomepage: <%= dependency.homepage.url %><% } %>" +
"<% if (dependency.author) { %>\nAuthor: <%= dependency.author.text() %><% } %>" +
"<% if (dependency.licenseText) { %>\n\n<%= dependency.licenseText %><% } %>" +
"\n---<% } }) %>\n<% } %>";
const ALLOWED_COMMENTS_RE = /SPDX-License-Identifier:/
const ALLOWED_COMMENTS_RE = /SPDX-License-Identifier:/;
function printHash() {
return {
name: "hash-output-plugin",
writeBundle(_options, bundle) {
for (const [fileName, assetInfo] of Object.entries(bundle)) {
if (assetInfo.code) {
try {
const data = Buffer.from(assetInfo.code)
const hash = createHash("sha3-512").update(data).digest("hex");
console.log(`SHA3-512 for ${assetInfo.fileName}: ${hash}`);
} catch (err) {
console.error(`Error hashing ${fileName}:`, err.message);
}
}
}
},
};
return {
name: "hash-output-plugin",
writeBundle(_options, bundle) {
for (const [fileName, assetInfo] of Object.entries(bundle)) {
if (assetInfo.code) {
try {
const data = Buffer.from(assetInfo.code);
const hash = createHash("sha3-512").update(data).digest("hex");
console.log(`SHA3-512 for ${assetInfo.fileName}: ${hash}`);
} catch (err) {
console.error(`Error hashing ${fileName}:`, err.message);
}
}
}
},
};
}
function dynamicImportRewrite({format = "deno"} = {}) {
return {
name: "dynamic-import-rewrite-plugin",
resolveId(source) {
if (pkg.dependencies[source]) {
if (format === "deno") {
return {id: `npm:${source}@${pkg.dependencies[source]}`, external: true};
} else if (format === "bun") {
return {id: `${source}@${pkg.dependencies[source]}`, external: true};
}
return null
}
return null;
},
renderDynamicImport() {
return null;
function dynamicImportRewrite({ format = "deno" } = {}) {
return {
name: "dynamic-import-rewrite-plugin",
resolveId(source) {
if (pkg.dependencies[source]) {
if (format === "deno") {
return {
id: `npm:${source}@${pkg.dependencies[source]}`,
external: true,
};
} else if (format === "bun") {
return {
id: `${source}@${pkg.dependencies[source]}`,
external: true,
};
}
};
return null;
}
return null;
},
renderDynamicImport() {
return null;
},
};
}
function prettifyOutput() {
return {
name: 'prettify-output',
renderChunk(code) {
return prettier.format(code, {parser: 'babel', singleQuote: true});
}
}
return {
name: "prettify-output",
renderChunk(code) {
return prettier.format(code, { parser: "babel", singleQuote: true });
},
};
}
export default defineConfig([
{
input: "src/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.js",
format: "iife",
},
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
content: LICENSE_BANNER
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
{
input: "src/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.js",
format: "iife",
},
{
input: "src/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
content: LICENSE_BANNER,
},
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
terser({
format: {
comments: ALLOWED_COMMENTS_RE
}
}),
license({
banner: {
content: LICENSE_BANNER
},
}),
printHash(),
],
},
{
input: "src/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.js",
format: "iife",
exports: "named",
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
content: LICENSE_BANNER
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
},
{
input: "src/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
terser({
format: {
comments: ALLOWED_COMMENTS_RE
}
}),
license({
banner: {
content: LICENSE_BANNER
},
}),
printHash(),
],
},
{
input: "src/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.deno.lib.js",
format: "es",
}),
license({
banner: {
content: LICENSE_BANNER,
},
plugins: [
dynamicImportRewrite({format: "deno"}),
license({
banner: {
content: LICENSE_BANNER
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
}),
printHash(),
],
},
{
input: "src/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.js",
format: "iife",
exports: "named",
},
{
input: "src/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.bun.lib.js",
format: "es",
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
content: LICENSE_BANNER,
},
plugins: [
dynamicImportRewrite({format: "bun"}),
license({
banner: {
content: LICENSE_BANNER
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
},
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
}),
license({
banner: {
content: LICENSE_BANNER,
},
}),
printHash(),
],
},
{
input: "src/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.deno.lib.js",
format: "es",
},
plugins: [
dynamicImportRewrite({ format: "deno" }),
license({
banner: {
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.bun.lib.js",
format: "es",
},
plugins: [
dynamicImportRewrite({ format: "bun" }),
license({
banner: {
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
format: {
comments: ALLOWED_COMMENTS_RE,
},
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
]);

22
run.ts
View File

@@ -27,12 +27,16 @@ for (const request of args.slice(1)) {
}
requests[type].push(challenge);
}
console.log(JSON.stringify(main({
type: "player",
player,
output_preprocessed: false,
requests: [
{ type: "n", challenges: requests.n },
{ type: "sig", challenges: requests.sig },
],
})));
console.log(
JSON.stringify(
main({
type: "player",
player,
output_preprocessed: false,
requests: [
{ type: "n", challenges: requests.n },
{ type: "sig", challenges: requests.sig },
],
}),
),
);

View File

@@ -1,5 +1,5 @@
// Used for generating deno/bun auto-imports
export const lib = {
meriyah: (await import('meriyah')),
astring: (await import('astring'))
meriyah: await import("meriyah"),
astring: await import("astring"),
};

View File

@@ -2,43 +2,43 @@ import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
import { isOneOf } from "./utils.ts";
export default function main(input: Input): Output {
const preprocessedPlayer = input.type === "player"
? preprocessPlayer(input.player)
: input.preprocessed_player;
const preprocessedPlayer =
input.type === "player"
? preprocessPlayer(input.player)
: input.preprocessed_player;
const solvers = getFromPrepared(preprocessedPlayer);
const responses = input.requests.map(
(input): Response => {
if (!isOneOf(input.type, "n", "sig")) {
return {
type: "error",
error: `Unknown request type: ${input.type}`,
};
}
const solver = solvers[input.type];
if (!solver) {
return {
type: "error",
error: `Failed to extract ${input.type} function`,
};
}
try {
return {
type: "result",
data: Object.fromEntries(
input.challenges.map((challenge) => [challenge, solver(challenge)]),
),
};
} catch (error) {
return {
type: "error",
error: error instanceof Error
const responses = input.requests.map((input): Response => {
if (!isOneOf(input.type, "n", "sig")) {
return {
type: "error",
error: `Unknown request type: ${input.type}`,
};
}
const solver = solvers[input.type];
if (!solver) {
return {
type: "error",
error: `Failed to extract ${input.type} function`,
};
}
try {
return {
type: "result",
data: Object.fromEntries(
input.challenges.map((challenge) => [challenge, solver(challenge)]),
),
};
} catch (error) {
return {
type: "error",
error:
error instanceof Error
? `${error.message}\n${error.stack}`
: `${error}`,
};
}
},
);
};
}
});
const output: Output = {
type: "result",
@@ -52,16 +52,16 @@ export default function main(input: Input): Output {
export type Input =
| {
type: "player";
player: string;
requests: Request[];
output_preprocessed: boolean;
}
type: "player";
player: string;
requests: Request[];
output_preprocessed: boolean;
}
| {
type: "preprocessed";
preprocessed_player: string;
requests: Request[];
};
type: "preprocessed";
preprocessed_player: string;
requests: Request[];
};
type Request = {
type: "n" | "sig";
@@ -70,21 +70,21 @@ type Request = {
type Response =
| {
type: "result";
data: Record<string, string>;
}
type: "result";
data: Record<string, string>;
}
| {
type: "error";
error: string;
};
type: "error";
error: string;
};
export type Output =
| {
type: "result";
preprocessed_player?: string;
responses: Response[];
}
type: "result";
preprocessed_player?: string;
responses: Response[];
}
| {
type: "error";
error: string;
};
type: "error";
error: string;
};

View File

@@ -97,7 +97,8 @@ export function extract(
}
const declaration = node.declarations[0];
if (
declaration.type !== "VariableDeclarator" || !declaration.init ||
declaration.type !== "VariableDeclarator" ||
!declaration.init ||
declaration.init.type !== "ArrayExpression" ||
declaration.init.elements.length !== 1
) {

View File

@@ -63,23 +63,26 @@ const logicalExpression: DeepPartial<ESTree.ExpressionStatement> = {
};
const identifier = {
or: [{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "Identifier",
},
right: {
type: "FunctionExpression",
params: [{}, {}, {}],
or: [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "Identifier",
},
right: {
type: "FunctionExpression",
params: [{}, {}, {}],
},
},
},
}, {
type: "FunctionDeclaration",
params: [{}, {}, {}],
}],
{
type: "FunctionDeclaration",
params: [{}, {}, {}],
},
],
} as const;
export function extract(
@@ -90,23 +93,22 @@ export function extract(
) {
return null;
}
const block = (node.type === "ExpressionStatement" &&
node.expression.type === "AssignmentExpression" &&
node.expression.right.type === "FunctionExpression")
? node.expression.right.body
: node.type === "FunctionDeclaration"
? node.body
: null;
const block =
node.type === "ExpressionStatement" &&
node.expression.type === "AssignmentExpression" &&
node.expression.right.type === "FunctionExpression"
? node.expression.right.body
: node.type === "FunctionDeclaration"
? node.body
: null;
const relevantExpression = block?.body.at(-2);
if (!matchesStructure(relevantExpression!, logicalExpression)) {
return null;
}
if (
relevantExpression?.type !== "ExpressionStatement" ||
relevantExpression.expression.type !==
"LogicalExpression" ||
relevantExpression.expression.right.type !==
"SequenceExpression" ||
relevantExpression.expression.type !== "LogicalExpression" ||
relevantExpression.expression.right.type !== "SequenceExpression" ||
relevantExpression.expression.right.expressions[0].type !==
"AssignmentExpression"
) {
@@ -131,20 +133,21 @@ export function extract(
type: "Identifier",
name: call.callee.name,
},
arguments: call.arguments.length === 1
? [
{
type: "Identifier",
name: "sig",
},
]
: [
call.arguments[0],
{
type: "Identifier",
name: "sig",
},
],
arguments:
call.arguments.length === 1
? [
{
type: "Identifier",
name: "sig",
},
]
: [
call.arguments[0],
{
type: "Identifier",
name: "sig",
},
],
optional: false,
},
async: false,

View File

@@ -1,8 +1,7 @@
export type DeepPartial<T> = T extends object ? Or<
{
export type DeepPartial<T> = T extends object
? Or<{
[P in keyof T]?: DeepPartial<T[P]>;
}
>
}>
: Or<T>;
type Or<T> = T | { or: T[] };

View File

@@ -253,18 +253,16 @@ export const tests: {
},
];
export const players = new Map(
[
["main", "player_ias.vflset/en_US/base.js"],
["tcc", "player_ias_tcc.vflset/en_US/base.js"],
["tce", "player_ias_tce.vflset/en_US/base.js"],
["es5", "player_es5.vflset/en_US/base.js"],
["es6", "player_es6.vflset/en_US/base.js"],
["tv", "tv-player-ias.vflset/tv-player-ias.js"],
["tv_es6", "tv-player-es6.vflset/tv-player-es6.js"],
["phone", "player-plasma-ias-phone-en_US.vflset/base.js"],
["tablet", "player-plasma-ias-tablet-en_US.vflset/base.js"],
] as const,
);
export const players = new Map([
["main", "player_ias.vflset/en_US/base.js"],
["tcc", "player_ias_tcc.vflset/en_US/base.js"],
["tce", "player_ias_tce.vflset/en_US/base.js"],
["es5", "player_es5.vflset/en_US/base.js"],
["es6", "player_es6.vflset/en_US/base.js"],
["tv", "tv-player-ias.vflset/tv-player-ias.js"],
["tv_es6", "tv-player-es6.vflset/tv-player-es6.js"],
["phone", "player-plasma-ias-phone-en_US.vflset/base.js"],
["tablet", "player-plasma-ias-tablet-en_US.vflset/base.js"],
] as const);
export type Variant = typeof players extends Map<infer T, unknown> ? T : never;