feat(Parser): just-in-time YTNode generation (#310)

* refactor: merge NavigatableText into Text

* fix(Text): data might not be object

* refactor: remove GetParserByName from map

* feat(Parser): just-in-time YTNode generation

* refactor: cleanup YTNodeGenerator

* fix: YTNode map imports

* feat(YTNodeGenerator): primative types

Add support for inferring primatives types

* fix(YTNodeGenerator): NavigationEndpoint detection

* fix(YTNodeGenerator): fix generated typescript

Correct types and linting for generated typescript class

* chore: update parsers after merge

* feat: add support for object type inference

* fix: object type def

* docs: basic YTNodeGenerator explanation

* docs: tsdoc for YTNodeGenerator

* docs: update parser updating guide

* fix: apply suggested changes

* docs: accessing generated nodes
This commit is contained in:
Daniel Wykerd
2023-03-15 08:39:36 +02:00
committed by GitHub
parent ffd7d79308
commit 2cee59024c
20 changed files with 1201 additions and 1169 deletions

View File

@@ -21,7 +21,8 @@ import Thumbnail from './classes/misc/Thumbnail.js';
import { InnertubeError, ParsingError, Platform } from '../utils/Utils.js';
import { Memo, observe, ObservedArray, SuperParsedResult, YTNode, YTNodeConstructor } from './helpers.js';
import GetParserByName from './map.js';
import * as YTNodes from './nodes.js';
import { YTNodeGenerator } from './generator.js';
export type ParserError = { classname: string, classdata: any, err: any };
export type ParserErrorHandler = (error: ParserError) => void;
@@ -290,7 +291,9 @@ export default class Parser {
if (!this.shouldIgnore(classname)) {
try {
const TargetClass = GetParserByName(classname);
const has_target_class = this.hasParser(classname);
const TargetClass = has_target_class ? this.getParserByName(classname) : YTNodeGenerator.generateRuntimeClass(classname, data[keys[0]]);
if (validTypes) {
if (Array.isArray(validTypes)) {
@@ -495,6 +498,34 @@ export default class Parser {
static shouldIgnore(classname: string) {
return this.ignore_list.has(classname);
}
static #rt_nodes = new Map<string, YTNodeConstructor>(Array.from(Object.entries(YTNodes)));
static #dynamic_nodes = new Map<string, YTNodeConstructor>();
static getParserByName(classname: string) {
const ParserConstructor = this.#rt_nodes.get(classname);
if (!ParserConstructor) {
const error = new Error(`Module not found: ${classname}`);
(error as any).code = 'MODULE_NOT_FOUND';
throw error;
}
return ParserConstructor;
}
static hasParser(classname: string) {
return this.#rt_nodes.has(classname);
}
static addRuntimeParser(classname: string, ParserConstructor: YTNodeConstructor) {
this.#rt_nodes.set(classname, ParserConstructor);
this.#dynamic_nodes.set(classname, ParserConstructor);
}
static getDynamicParsers() {
return Object.fromEntries(this.#dynamic_nodes);
}
}
// Continuation