mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
@ -138,6 +138,7 @@
|
|||||||
"@cliqz/adblocker-electron": "1.26.11",
|
"@cliqz/adblocker-electron": "1.26.11",
|
||||||
"@cliqz/adblocker-electron-preload": "1.26.11",
|
"@cliqz/adblocker-electron-preload": "1.26.11",
|
||||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||||
|
"@electron/remote": "2.1.0",
|
||||||
"@ffmpeg.wasm/core-mt": "0.12.0",
|
"@ffmpeg.wasm/core-mt": "0.12.0",
|
||||||
"@ffmpeg.wasm/main": "0.12.0",
|
"@ffmpeg.wasm/main": "0.12.0",
|
||||||
"@foobar404/wave": "2.0.4",
|
"@foobar404/wave": "2.0.4",
|
||||||
|
|||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@ -22,6 +22,9 @@ dependencies:
|
|||||||
'@electron-toolkit/tsconfig':
|
'@electron-toolkit/tsconfig':
|
||||||
specifier: ^1.0.1
|
specifier: ^1.0.1
|
||||||
version: 1.0.1(@types/node@20.8.6)
|
version: 1.0.1(@types/node@20.8.6)
|
||||||
|
'@electron/remote':
|
||||||
|
specifier: 2.1.0
|
||||||
|
version: 2.1.0(electron@27.0.4)
|
||||||
'@ffmpeg.wasm/core-mt':
|
'@ffmpeg.wasm/core-mt':
|
||||||
specifier: 0.12.0
|
specifier: 0.12.0
|
||||||
version: 0.12.0
|
version: 0.12.0
|
||||||
@ -568,6 +571,14 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@electron/remote@2.1.0(electron@27.0.4):
|
||||||
|
resolution: {integrity: sha512-38jzz2beoYTo0DNS+aoaGyLS/fHeNTAc1Aom6HlYsxKnvVWjcg4xriC7J2IUkYSEDHGKX/D7jUst+mH4dHR6QA==}
|
||||||
|
peerDependencies:
|
||||||
|
electron: '>= 13.0.0'
|
||||||
|
dependencies:
|
||||||
|
electron: 27.0.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@electron/universal@1.4.5:
|
/@electron/universal@1.4.5:
|
||||||
resolution: {integrity: sha512-3vE9WBQnvlulKylrPbyc+9M4xnD7t1JxuCOF0nrFz00XrrkgbqeqxDf90PNcjLiuB4hAZKr1JooVA6KwsXj94w==}
|
resolution: {integrity: sha512-3vE9WBQnvlulKylrPbyc+9M4xnD7t1JxuCOF0nrFz00XrrkgbqeqxDf90PNcjLiuB4hAZKr1JooVA6KwsXj94w==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
|
|||||||
@ -163,13 +163,7 @@ const migrations = {
|
|||||||
export default new Store({
|
export default new Store({
|
||||||
defaults: {
|
defaults: {
|
||||||
...defaults,
|
...defaults,
|
||||||
plugins: Object.entries(allPlugins).reduce(
|
// README: 'plugin' uses deepmerge to populate the default values, so it is not necessary to include it here
|
||||||
(prev, [id, plugin]) => ({
|
|
||||||
...prev,
|
|
||||||
[id]: plugin.config,
|
|
||||||
}),
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
clearInvalidConfig: false,
|
clearInvalidConfig: false,
|
||||||
migrations,
|
migrations,
|
||||||
|
|||||||
@ -163,7 +163,7 @@ const initHook = (win: BrowserWindow) => {
|
|||||||
const mainPlugin = getAllLoadedMainPlugins()[id];
|
const mainPlugin = getAllLoadedMainPlugins()[id];
|
||||||
if (mainPlugin) {
|
if (mainPlugin) {
|
||||||
if (config.enabled && typeof mainPlugin.backend !== 'function') {
|
if (config.enabled && typeof mainPlugin.backend !== 'function') {
|
||||||
mainPlugin.backend?.onConfigChange?.(config);
|
mainPlugin.backend?.onConfigChange?.bind(mainPlugin.backend)?.(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,16 +96,18 @@ export const forceLoadMainPlugin = async (
|
|||||||
loadedPluginMap[id] = plugin;
|
loadedPluginMap[id] = plugin;
|
||||||
resolve();
|
resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(
|
console.error(
|
||||||
'[YTMusic]',
|
'[YTMusic]',
|
||||||
`Cannot initialize "${id}" plugin: ${String(err)}`,
|
`Cannot initialize "${id}" plugin: `,
|
||||||
);
|
);
|
||||||
|
console.trace(err);
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
||||||
|
console.log('[YTMusic]', 'Loading all plugins');
|
||||||
const pluginConfigs = config.plugins.getPlugins();
|
const pluginConfigs = config.plugins.getPlugins();
|
||||||
const queue: Promise<void>[] = [];
|
const queue: Promise<void>[] = [];
|
||||||
|
|
||||||
@ -118,7 +120,7 @@ export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(queue);
|
await Promise.allSettled(queue);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const unloadAllMainPlugins = (win: BrowserWindow) => {
|
export const unloadAllMainPlugins = (win: BrowserWindow) => {
|
||||||
|
|||||||
@ -35,7 +35,8 @@ export const forceLoadMenuPlugin = async (id: string, win: BrowserWindow) => {
|
|||||||
|
|
||||||
console.log('[YTMusic]', `Successfully loaded '${id}::menu'`);
|
console.log('[YTMusic]', `Successfully loaded '${id}::menu'`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('[YTMusic]', `Cannot initialize '${id}::menu': ${String(err)}`);
|
console.error('[YTMusic]', `Cannot initialize '${id}::menu': `);
|
||||||
|
console.trace(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -42,10 +42,11 @@ export const forceLoadPreloadPlugin = (id: string) => {
|
|||||||
|
|
||||||
console.log('[YTMusic]', `"${id}" plugin is loaded`);
|
console.log('[YTMusic]', `"${id}" plugin is loaded`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(
|
console.error(
|
||||||
'[YTMusic]',
|
'[YTMusic]',
|
||||||
`Cannot initialize "${id}" plugin: ${String(err)}`,
|
`Cannot initialize "${id}" plugin: `,
|
||||||
);
|
);
|
||||||
|
console.trace(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -28,12 +28,11 @@ interface CaptionsSelectorConfig {
|
|||||||
lastCaptionsCode: string;
|
lastCaptionsCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const captionsSettingsButton = ElementFromHtml(CaptionsSettingsButtonHTML);
|
|
||||||
|
|
||||||
export default createPlugin<
|
export default createPlugin<
|
||||||
unknown,
|
unknown,
|
||||||
unknown,
|
unknown,
|
||||||
{
|
{
|
||||||
|
captionsSettingsButton: HTMLElement;
|
||||||
captionTrackList: LanguageOptions[] | null;
|
captionTrackList: LanguageOptions[] | null;
|
||||||
api: YoutubePlayer | null;
|
api: YoutubePlayer | null;
|
||||||
config: CaptionsSelectorConfig | null;
|
config: CaptionsSelectorConfig | null;
|
||||||
@ -98,6 +97,7 @@ export default createPlugin<
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderer: {
|
renderer: {
|
||||||
|
captionsSettingsButton: ElementFromHtml(CaptionsSettingsButtonHTML),
|
||||||
captionTrackList: null,
|
captionTrackList: null,
|
||||||
api: null,
|
api: null,
|
||||||
config: null,
|
config: null,
|
||||||
@ -133,7 +133,7 @@ export default createPlugin<
|
|||||||
captionsButtonClickListener() {
|
captionsButtonClickListener() {
|
||||||
if (this.config!.disableCaptions) {
|
if (this.config!.disableCaptions) {
|
||||||
setTimeout(() => this.api!.unloadModule('captions'), 100);
|
setTimeout(() => this.api!.unloadModule('captions'), 100);
|
||||||
captionsSettingsButton.style.display = 'none';
|
this.captionsSettingsButton.style.display = 'none';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ export default createPlugin<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
captionsSettingsButton.style.display = this.captionTrackList?.length
|
this.captionsSettingsButton.style.display = this.captionTrackList?.length
|
||||||
? 'inline-block'
|
? 'inline-block'
|
||||||
: 'none';
|
: 'none';
|
||||||
}, 250);
|
}, 250);
|
||||||
@ -158,20 +158,20 @@ export default createPlugin<
|
|||||||
this.setConfig = setConfig;
|
this.setConfig = setConfig;
|
||||||
},
|
},
|
||||||
stop() {
|
stop() {
|
||||||
document.querySelector('.right-controls-buttons')?.removeChild(captionsSettingsButton);
|
document.querySelector('.right-controls-buttons')?.removeChild(this.captionsSettingsButton);
|
||||||
document.querySelector<YoutubePlayer & HTMLElement>('#movie_player')?.unloadModule('captions');
|
document.querySelector<YoutubePlayer & HTMLElement>('#movie_player')?.unloadModule('captions');
|
||||||
document.querySelector('video')?.removeEventListener('srcChanged', this.videoChangeListener);
|
document.querySelector('video')?.removeEventListener('srcChanged', this.videoChangeListener);
|
||||||
captionsSettingsButton.removeEventListener('click', this.captionsButtonClickListener);
|
this.captionsSettingsButton.removeEventListener('click', this.captionsButtonClickListener);
|
||||||
},
|
},
|
||||||
onPlayerApiReady(playerApi) {
|
onPlayerApiReady(playerApi) {
|
||||||
this.api = playerApi;
|
this.api = playerApi;
|
||||||
|
|
||||||
document.querySelector('.right-controls-buttons')?.append(captionsSettingsButton);
|
document.querySelector('.right-controls-buttons')?.append(this.captionsSettingsButton);
|
||||||
|
|
||||||
this.captionTrackList = this.api.getOption<LanguageOptions[]>('captions', 'tracklist') ?? [];
|
this.captionTrackList = this.api.getOption<LanguageOptions[]>('captions', 'tracklist') ?? [];
|
||||||
|
|
||||||
document.querySelector('video')?.addEventListener('srcChanged', this.videoChangeListener);
|
document.querySelector('video')?.addEventListener('srcChanged', this.videoChangeListener);
|
||||||
captionsSettingsButton.addEventListener('click', this.captionsButtonClickListener);
|
this.captionsSettingsButton.addEventListener('click', this.captionsButtonClickListener);
|
||||||
},
|
},
|
||||||
onConfigChange(newConfig) {
|
onConfigChange(newConfig) {
|
||||||
this.config = newConfig;
|
this.config = newConfig;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ import { cache } from '@/providers/decorators';
|
|||||||
|
|
||||||
import { YoutubeFormatList, type Preset, DefaultPresetList } from '../types';
|
import { YoutubeFormatList, type Preset, DefaultPresetList } from '../types';
|
||||||
|
|
||||||
import { defaultConfig, type DownloaderPluginConfig } from '../index';
|
import type { DownloaderPluginConfig } from '../index';
|
||||||
|
|
||||||
import type { BackendContext } from '@/types/contexts';
|
import type { BackendContext } from '@/types/contexts';
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ export const getCookieFromWindow = async (win: BrowserWindow) => {
|
|||||||
.join(';');
|
.join(';');
|
||||||
};
|
};
|
||||||
|
|
||||||
let config: DownloaderPluginConfig = defaultConfig;
|
let config: DownloaderPluginConfig;
|
||||||
|
|
||||||
export const onMainLoad = async ({ window: _win, getConfig, ipc }: BackendContext<DownloaderPluginConfig>) => {
|
export const onMainLoad = async ({ window: _win, getConfig, ipc }: BackendContext<DownloaderPluginConfig>) => {
|
||||||
win = _win;
|
win = _win;
|
||||||
|
|||||||
@ -5,12 +5,12 @@ import is from 'electron-is';
|
|||||||
import { notificationImage } from './utils';
|
import { notificationImage } from './utils';
|
||||||
import interactive from './interactive';
|
import interactive from './interactive';
|
||||||
|
|
||||||
import { defaultConfig, type NotificationsPluginConfig } from './index';
|
|
||||||
import registerCallback, { type SongInfo } from '@/providers/song-info';
|
import registerCallback, { type SongInfo } from '@/providers/song-info';
|
||||||
|
|
||||||
|
import type { NotificationsPluginConfig } from './index';
|
||||||
import type { BackendContext } from '@/types/contexts';
|
import type { BackendContext } from '@/types/contexts';
|
||||||
|
|
||||||
let config: NotificationsPluginConfig = defaultConfig;
|
let config: NotificationsPluginConfig;
|
||||||
|
|
||||||
const notify = (info: SongInfo) => {
|
const notify = (info: SongInfo) => {
|
||||||
// Send the notification
|
// Send the notification
|
||||||
|
|||||||
@ -78,7 +78,7 @@ function onApiLoaded() {
|
|||||||
Object.entries(getAllLoadedRendererPlugins())
|
Object.entries(getAllLoadedRendererPlugins())
|
||||||
.forEach(([id, plugin]) => {
|
.forEach(([id, plugin]) => {
|
||||||
if (typeof plugin.renderer !== 'function') {
|
if (typeof plugin.renderer !== 'function') {
|
||||||
plugin.renderer?.onPlayerApiReady?.(api!, createContext(id));
|
plugin.renderer?.onPlayerApiReady?.bind(plugin.renderer)?.(api!, createContext(id));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ function onApiLoaded() {
|
|||||||
if (api) {
|
if (api) {
|
||||||
const plugin = getLoadedRendererPlugin(id);
|
const plugin = getLoadedRendererPlugin(id);
|
||||||
if (plugin && typeof plugin.renderer !== 'function') {
|
if (plugin && typeof plugin.renderer !== 'function') {
|
||||||
plugin.renderer?.onPlayerApiReady?.(api, createContext(id));
|
plugin.renderer?.onPlayerApiReady?.bind(plugin.renderer)?.(api, createContext(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -146,7 +146,7 @@ function onApiLoaded() {
|
|||||||
(_event, id: string, newConfig: PluginConfig) => {
|
(_event, id: string, newConfig: PluginConfig) => {
|
||||||
const plugin = getAllLoadedRendererPlugins()[id];
|
const plugin = getAllLoadedRendererPlugins()[id];
|
||||||
if (plugin && typeof plugin.renderer !== 'function') {
|
if (plugin && typeof plugin.renderer !== 'function') {
|
||||||
plugin.renderer?.onConfigChange?.(newConfig);
|
plugin.renderer?.onConfigChange?.bind(plugin.renderer)?.(newConfig);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export const startPlugin = <Config extends PluginConfig>(id: string, def: Plugin
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
lifecycle(options.context as Config & typeof options.context);
|
lifecycle.bind(def[options.ctx])(options.context as Config & typeof options.context);
|
||||||
|
|
||||||
console.log(`[YTM] Executed ${id}::${options.ctx} in ${performance.now() - start} ms`);
|
console.log(`[YTM] Executed ${id}::${options.ctx} in ${performance.now() - start} ms`);
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ export const stopPlugin = <Config extends PluginConfig>(id: string, def: PluginD
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
stop(options.context as Config & typeof options.context);
|
stop.bind(def[options.ctx])(options.context as Config & typeof options.context);
|
||||||
|
|
||||||
console.log(`[YTM] Executed ${id}::${options.ctx} in ${performance.now() - start} ms`);
|
console.log(`[YTM] Executed ${id}::${options.ctx} in ${performance.now() - start} ms`);
|
||||||
|
|
||||||
|
|||||||
1
src/virtual-module.d.ts
vendored
1
src/virtual-module.d.ts
vendored
@ -4,7 +4,6 @@ declare module 'virtual:plugins' {
|
|||||||
type Plugin = PluginDef<unknown, unknown, unknown, PluginConfig>;
|
type Plugin = PluginDef<unknown, unknown, unknown, PluginConfig>;
|
||||||
|
|
||||||
export const mainPlugins: Record<string, Plugin>;
|
export const mainPlugins: Record<string, Plugin>;
|
||||||
export const menuPlugins: Record<string, Plugin>;
|
|
||||||
export const preloadPlugins: Record<string, Plugin>;
|
export const preloadPlugins: Record<string, Plugin>;
|
||||||
export const rendererPlugins: Record<string, Plugin>;
|
export const rendererPlugins: Record<string, Plugin>;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const snakeToCamel = (text: string) =>
|
|||||||
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase());
|
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase());
|
||||||
|
|
||||||
export const pluginVirtualModuleGenerator = (
|
export const pluginVirtualModuleGenerator = (
|
||||||
mode: 'main' | 'preload' | 'renderer' | 'menu',
|
mode: 'main' | 'preload' | 'renderer',
|
||||||
) => {
|
) => {
|
||||||
const project = new Project({
|
const project = new Project({
|
||||||
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
|
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
|
||||||
@ -37,7 +37,7 @@ export const pluginVirtualModuleGenerator = (
|
|||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
for (const { name, path } of plugins) {
|
for (const { name, path } of plugins) {
|
||||||
const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/');
|
const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/');
|
||||||
writer.writeLine(`import ${snakeToCamel(name)}Plugin from "./${relativePath}";`);
|
writer.writeLine(`import ${snakeToCamel(name)}Plugin, { pluginStub as ${snakeToCamel(name)}PluginStub } from "./${relativePath}";`);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.blankLine();
|
writer.blankLine();
|
||||||
@ -45,15 +45,17 @@ export const pluginVirtualModuleGenerator = (
|
|||||||
// Context-specific exports
|
// Context-specific exports
|
||||||
writer.writeLine(`export const ${mode}Plugins = {`);
|
writer.writeLine(`export const ${mode}Plugins = {`);
|
||||||
for (const { name } of plugins) {
|
for (const { name } of plugins) {
|
||||||
writer.writeLine(` "${name}": ${snakeToCamel(name)}Plugin,`);
|
const checkMode = mode === 'main' ? 'backend' : mode;
|
||||||
|
// HACK: To avoid situation like importing renderer plugins in main
|
||||||
|
writer.writeLine(` ...(${snakeToCamel(name)}Plugin['${checkMode}'] ? { "${name}": ${snakeToCamel(name)}Plugin } : {}),`);
|
||||||
}
|
}
|
||||||
writer.writeLine('};');
|
writer.writeLine('};');
|
||||||
writer.blankLine();
|
writer.blankLine();
|
||||||
|
|
||||||
// All plugins export
|
// All plugins export (stub only) // Omit<Plugin, 'backend' | 'preload' | 'renderer'>
|
||||||
writer.writeLine('export const allPlugins = {');
|
writer.writeLine('export const allPlugins = {');
|
||||||
for (const { name } of plugins) {
|
for (const { name } of plugins) {
|
||||||
writer.writeLine(` "${name}": ${snakeToCamel(name)}Plugin,`);
|
writer.writeLine(` "${name}": ${snakeToCamel(name)}PluginStub,`);
|
||||||
}
|
}
|
||||||
writer.writeLine('};');
|
writer.writeLine('};');
|
||||||
writer.blankLine();
|
writer.blankLine();
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
|
|||||||
import { resolve, basename } from 'node:path';
|
import { resolve, basename } from 'node:path';
|
||||||
|
|
||||||
import { createFilter } from 'vite';
|
import { createFilter } from 'vite';
|
||||||
import { Project, ts, ObjectLiteralExpression } from 'ts-morph';
|
import { Project, ts, ObjectLiteralExpression, VariableDeclarationKind } from 'ts-morph';
|
||||||
|
|
||||||
import type { PluginOption } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ export default function (mode: 'backend' | 'preload' | 'renderer' | 'none'): Plu
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const contexts = ['backend', 'preload', 'renderer'];
|
const contexts = ['backend', 'preload', 'renderer', 'menu'];
|
||||||
for (const ctx of contexts) {
|
for (const ctx of contexts) {
|
||||||
if (mode === 'none') {
|
if (mode === 'none') {
|
||||||
const index = propertyNames.indexOf(ctx);
|
const index = propertyNames.indexOf(ctx);
|
||||||
@ -89,6 +89,7 @@ export default function (mode: 'backend' | 'preload' | 'renderer' | 'none'): Plu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctx === mode) continue;
|
if (ctx === mode) continue;
|
||||||
|
if (ctx === 'menu' && mode === 'backend') continue;
|
||||||
|
|
||||||
const index = propertyNames.indexOf(ctx);
|
const index = propertyNames.indexOf(ctx);
|
||||||
if (index === -1) continue;
|
if (index === -1) continue;
|
||||||
@ -96,6 +97,45 @@ export default function (mode: 'backend' | 'preload' | 'renderer' | 'none'): Plu
|
|||||||
objExpr.getProperty(propertyNames[index])?.remove();
|
objExpr.getProperty(propertyNames[index])?.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stubObjExpr = src.addVariableStatement({
|
||||||
|
isExported: true,
|
||||||
|
declarationKind: VariableDeclarationKind.Const,
|
||||||
|
declarations: [{
|
||||||
|
name: 'pluginStub',
|
||||||
|
initializer: (writer) => writer.write(objExpr!.getText()),
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.getDeclarations()[0]
|
||||||
|
.getInitializer() as ObjectLiteralExpression;
|
||||||
|
|
||||||
|
const stubProperties = stubObjExpr.getProperties();
|
||||||
|
const stubPropertyNames = stubProperties.map((prop) => {
|
||||||
|
switch (prop.getKind()) {
|
||||||
|
case ts.SyntaxKind.PropertyAssignment:
|
||||||
|
return prop
|
||||||
|
.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
|
||||||
|
.getName();
|
||||||
|
case ts.SyntaxKind.ShorthandPropertyAssignment:
|
||||||
|
return prop
|
||||||
|
.asKindOrThrow(ts.SyntaxKind.ShorthandPropertyAssignment)
|
||||||
|
.getName();
|
||||||
|
case ts.SyntaxKind.MethodDeclaration:
|
||||||
|
return prop
|
||||||
|
.asKindOrThrow(ts.SyntaxKind.MethodDeclaration)
|
||||||
|
.getName();
|
||||||
|
default:
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mode === 'backend') contexts.pop();
|
||||||
|
for (const ctx of contexts) {
|
||||||
|
const index = stubPropertyNames.indexOf(ctx);
|
||||||
|
if (index === -1) continue;
|
||||||
|
|
||||||
|
stubObjExpr.getProperty(stubPropertyNames[index])?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: src.getText(),
|
code: src.getText(),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user