mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.64
* Added: Setting to make emotes twice as big in chat. * Added: Setting for hiding Prediction banners in chat. * Fixed: Current channel, category, and title not being detected correctly on the Stream Dashboard page. * Fixed: Tweak the clip URL regex again to support more possible characters. * Fixed: Cyclic dependency error with the CSS Tweaks module. * Fixed: Cyclic dependencies in modules not being detected due to how the enable/load/disable/unload promises work. * Changed: In Switchboard, try finding a route with no parameters first to minimize errors in the log. * Changed: Attempt to detect Firefox with `InstallTrigger` for users that change their User-Agent.
This commit is contained in:
parent
9cecab8dd4
commit
01e7a95cd8
13 changed files with 194 additions and 107 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.20.63",
|
||||
"version": "4.20.64",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
"name": "New Link Tokenization",
|
||||
"description": "Update to Twitch's latest link regex. Experiment while this is checked for bugs.",
|
||||
"groups": [
|
||||
{"value": true, "weight": 50},
|
||||
{"value": false, "weight": 50}
|
||||
{"value": true, "weight": 100},
|
||||
{"value": false, "weight": 0}
|
||||
]
|
||||
},
|
||||
"api_load": {
|
||||
|
@ -19,8 +19,8 @@
|
|||
"name": "API-Based Link Lookups",
|
||||
"description": "Use the new API to look up links instead of the socket cluster.",
|
||||
"groups": [
|
||||
{"value": true, "weight": 50},
|
||||
{"value": false, "weight": 50}
|
||||
{"value": true, "weight": 30},
|
||||
{"value": false, "weight": 70}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -84,6 +84,16 @@ export default class Emotes extends Module {
|
|||
this._set_refs = {};
|
||||
this._set_timers = {};
|
||||
|
||||
this.settings.add('chat.emotes.2x', {
|
||||
default: false,
|
||||
ui: {
|
||||
path: 'Chat > Appearance >> Emotes',
|
||||
title: 'Larger Emotes',
|
||||
description: 'This setting will make emotes appear twice as large in chat. It\'s good for use with larger fonts or just if you really like emotes.',
|
||||
component: 'setting-check-box'
|
||||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.fix-bad-emotes', {
|
||||
default: true,
|
||||
ui: {
|
||||
|
@ -721,6 +731,14 @@ export default class Emotes extends Module {
|
|||
if ( emote.urls[4] )
|
||||
emote.srcSet += `, ${emote.urls[4]} 4x`;
|
||||
|
||||
if ( emote.urls[2] ) {
|
||||
emote.can_big = true;
|
||||
emote.src2 = emote.urls[2];
|
||||
emote.srcSet2 = `${emote.urls[2]} 1x`;
|
||||
if ( emote.urls[4] )
|
||||
emote.srcSet2 += `, ${emote.urls[4]} 2x`;
|
||||
}
|
||||
|
||||
emote.token = {
|
||||
type: 'emote',
|
||||
id: emote.id,
|
||||
|
@ -728,8 +746,12 @@ export default class Emotes extends Module {
|
|||
provider: 'ffz',
|
||||
src: emote.urls[1],
|
||||
srcSet: emote.srcSet,
|
||||
can_big: !! emote.urls[2],
|
||||
src2: emote.src2,
|
||||
srcSet2: emote.srcSet2,
|
||||
text: emote.hidden ? '???' : emote.name,
|
||||
length: emote.name.length
|
||||
length: emote.name.length,
|
||||
height: emote.height
|
||||
};
|
||||
|
||||
if ( has(MODIFIERS, emote.id) )
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
//const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)(?:\/)?(\w+)?(?:\/edit)?/;
|
||||
//const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/\w+\/clip\/(\w+)/;
|
||||
const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/([a-z0-9-]+)(?:\/)?(\w+)?(?:\/edit)?/i;
|
||||
const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/\w+\/clip\/([a-z0-9-]+)/i;
|
||||
const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/([a-z0-9-_=]+)(?:\/)?(\w+)?(?:\/edit)?/i;
|
||||
const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:(?:www|m)\.)?twitch\.tv\/\w+\/clip\/([a-z0-9-_=]+)/i;
|
||||
const VIDEO_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/(?:\w+\/v|videos)\/(\w+)/;
|
||||
const USER_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/([^/]+)$/;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {CATEGORIES} from './emoji';
|
|||
|
||||
|
||||
const EMOTE_CLASS = 'chat-image chat-line__message--emote',
|
||||
WHITESPACE = /^\s*$/,
|
||||
LINK_REGEX = /([^\w@#%\-+=:~])?((?:(https?:\/\/)?(?:[\w@#%\-+=:~]+\.)+[a-z]{2,6}(?:\/[\w./@#%&()\-+=:?~]*)?))([^\w./@#%&()\-+=:?~]|\s|$)/g,
|
||||
NEW_LINK_REGEX = /(?:(https?:\/\/)?((?:[\w#%\-+=:~]+\.)+[a-z]{2,10}(?:\/[\w./#%&@()\-+=:?~]*)?))/g,
|
||||
//MENTION_REGEX = /([^\w@#%\-+=:~])?(@([^\u0000-\u007F]+|\w+)+)([^\w./@#%&()\-+=:?~]|\s|$)/g; // eslint-disable-line no-control-regex
|
||||
|
@ -1057,9 +1058,10 @@ const render_emote = (token, createElement, wrapped) => {
|
|||
emote = createElement('img', {
|
||||
class: `${EMOTE_CLASS} ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`,
|
||||
attrs: {
|
||||
src: token.src,
|
||||
srcSet: token.srcSet,
|
||||
src: token.big && token.src2 || token.src,
|
||||
srcSet: token.big && token.srcSet2 || token.srcSet,
|
||||
alt: token.text,
|
||||
height: (token.big && ! token.can_big && token.height) ? `${token.height * 2}px` : undefined,
|
||||
'data-tooltip-type': 'emote',
|
||||
'data-provider': token.provider,
|
||||
'data-id': token.id,
|
||||
|
@ -1111,8 +1113,9 @@ export const AddonEmotes = {
|
|||
const mods = token.modifiers || [], ml = mods.length,
|
||||
emote = (<img
|
||||
class={`${EMOTE_CLASS} ffz--pointer-events ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`}
|
||||
src={token.src}
|
||||
srcSet={token.srcSet}
|
||||
src={token.big && token.src2 || token.src}
|
||||
srcSet={token.big && token.srcSet2 || token.srcSet}
|
||||
height={(token.big && ! token.can_big && token.height) ? `${token.height * 2}px` : undefined}
|
||||
alt={token.text}
|
||||
data-tooltip-type="emote"
|
||||
data-provider={token.provider}
|
||||
|
@ -1295,20 +1298,24 @@ export const AddonEmotes = {
|
|||
msg.user.login,
|
||||
msg.roomID,
|
||||
msg.roomLogin
|
||||
),
|
||||
out = [];
|
||||
);
|
||||
|
||||
if ( ! emotes )
|
||||
return tokens;
|
||||
|
||||
const big = this.context.get('chat.emotes.2x'),
|
||||
out = [];
|
||||
|
||||
let last_token, emote;
|
||||
for(const token of tokens) {
|
||||
if ( ! token )
|
||||
continue;
|
||||
|
||||
if ( token.type !== 'text' ) {
|
||||
if ( token.type === 'emote' && ! token.modifiers )
|
||||
if ( token.type === 'emote' ) {
|
||||
if ( ! token.modifiers )
|
||||
token.modifiers = [];
|
||||
}
|
||||
|
||||
out.push(token);
|
||||
last_token = token;
|
||||
|
@ -1323,8 +1330,14 @@ export const AddonEmotes = {
|
|||
|
||||
// Is this emote a modifier?
|
||||
if ( emote.modifier && last_token && last_token.modifiers && (!text.length || (text.length === 1 && text[0] === '')) ) {
|
||||
if ( last_token.modifiers.indexOf(emote.token) === -1 )
|
||||
if ( last_token.modifiers.indexOf(emote.token) === -1 ) {
|
||||
if ( big )
|
||||
last_token.modifiers.push(Object.assign({
|
||||
big
|
||||
}, emote.token));
|
||||
else
|
||||
last_token.modifiers.push(emote.token);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -1339,7 +1352,10 @@ export const AddonEmotes = {
|
|||
text = [];
|
||||
}
|
||||
|
||||
const t = Object.assign({modifiers: []}, emote.token);
|
||||
const t = Object.assign({
|
||||
modifiers: [],
|
||||
big
|
||||
}, emote.token);
|
||||
out.push(t);
|
||||
last_token = t;
|
||||
|
||||
|
@ -1349,8 +1365,10 @@ export const AddonEmotes = {
|
|||
text.push(segment);
|
||||
}
|
||||
|
||||
if ( text.length > 1 || (text.length === 1 && text[0] !== '') )
|
||||
out.push({type: 'text', text: text.join(' ')});
|
||||
if ( text.length > 1 || (text.length === 1 && text[0] !== '') ) {
|
||||
const t = {type: 'text', text: text.join(' ')};
|
||||
out.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -1445,6 +1463,8 @@ export const TwitchEmotes = {
|
|||
return tokens;
|
||||
|
||||
const data = msg.ffz_emotes,
|
||||
big = this.context.get('chat.emotes.2x'),
|
||||
use_replacements = this.context.get('chat.fix-bad-emotes'),
|
||||
emotes = [];
|
||||
|
||||
for(const emote_id in data)
|
||||
|
@ -1516,15 +1536,21 @@ export const TwitchEmotes = {
|
|||
});
|
||||
|
||||
let src, srcSet;
|
||||
let src2, srcSet2;
|
||||
|
||||
const replacement = REPLACEMENTS[e_id];
|
||||
if ( replacement && this.context.get('chat.fix-bad-emotes') ) {
|
||||
if ( replacement && use_replacements ) {
|
||||
src = `${REPLACEMENT_BASE}${replacement}`;
|
||||
srcSet = '';
|
||||
|
||||
} else {
|
||||
src = `${TWITCH_EMOTE_BASE}${e_id}/1.0`;
|
||||
srcSet = `${TWITCH_EMOTE_BASE}${e_id}/1.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/2.0 2x`;
|
||||
|
||||
if ( big ) {
|
||||
src2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0`;
|
||||
srcSet2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/3.0 2x`;
|
||||
}
|
||||
}
|
||||
|
||||
out.push({
|
||||
|
@ -1533,6 +1559,9 @@ export const TwitchEmotes = {
|
|||
provider: 'twitch',
|
||||
src,
|
||||
srcSet,
|
||||
src2,
|
||||
srcSet2,
|
||||
big,
|
||||
text: text.slice(e_start - t_start, e_end - t_start).join(''),
|
||||
modifiers: []
|
||||
});
|
||||
|
|
|
@ -33,7 +33,7 @@ export default class Channel extends Module {
|
|||
|
||||
|
||||
this.settings.add('channel.panel-tips', {
|
||||
default: true,
|
||||
default: false,
|
||||
ui: {
|
||||
path: 'Channel > Behavior >> Panels',
|
||||
title: 'Display rich tool-tips for links in channel panels.',
|
||||
|
|
|
@ -354,6 +354,15 @@ export default class ChatHook extends Module {
|
|||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.banners.prediction', {
|
||||
default: true,
|
||||
ui: {
|
||||
path: 'Chat > Appearance >> Community',
|
||||
title: 'Allow Predictions to be displayed in chat.',
|
||||
component: 'setting-check-box'
|
||||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.community-chest.show', {
|
||||
default: true,
|
||||
ui: {
|
||||
|
@ -773,6 +782,7 @@ export default class ChatHook extends Module {
|
|||
this.chat.context.on('changed:chat.banners.hype-train', this.cleanHighlights, this);
|
||||
this.chat.context.on('changed:chat.subs.gift-banner', this.cleanHighlights, this);
|
||||
this.chat.context.on('changed:chat.banners.polls', this.cleanHighlights, this);
|
||||
this.chat.context.on('changed:chat.banners.prediction', this.cleanHighlights, this);
|
||||
|
||||
this.chat.context.on('changed:chat.subs.gift-banner', () => this.GiftBanner.forceUpdate(), this);
|
||||
this.chat.context.on('changed:chat.width', this.updateChatCSS, this);
|
||||
|
@ -1258,6 +1268,7 @@ export default class ChatHook extends Module {
|
|||
'community_sub_gift': this.chat.context.get('chat.subs.gift-banner'),
|
||||
'megacheer': this.chat.context.get('chat.bits.show'),
|
||||
'hype_train': this.chat.context.get('chat.banners.hype-train'),
|
||||
'prediction': this.chat.context.get('chat.banners.prediction'),
|
||||
'poll': this.chat.context.get('chat.banners.polls')
|
||||
};
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ export default class ChatLine extends Module {
|
|||
this.on('chat:update-lines', this.updateLines, this);
|
||||
this.on('i18n:update', this.updateLines, this);
|
||||
|
||||
this.chat.context.on('changed:chat.emotes.2x', this.updateLines, this);
|
||||
this.chat.context.on('changed:chat.emoji.style', this.updateLines, this);
|
||||
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);
|
||||
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
||||
|
|
|
@ -53,8 +53,6 @@ export default class CSSTweaks extends Module {
|
|||
this.should_enable = true;
|
||||
|
||||
this.inject('settings');
|
||||
this.inject('site.chat');
|
||||
this.inject('site.theme');
|
||||
|
||||
this.style = new ManagedStyle;
|
||||
this.chunks = {};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import { get } from 'utilities/object';
|
||||
import { get, has } from 'utilities/object';
|
||||
|
||||
import Twilight from 'site';
|
||||
|
||||
|
@ -19,83 +19,69 @@ export default class Dashboard extends Module {
|
|||
this.inject('site.fine');
|
||||
this.inject('site.channel');
|
||||
|
||||
this.HostBar = this.fine.define(
|
||||
'sunlight-host-bar',
|
||||
n => n.props && n.props.channel && n.props.hostedChannel !== undefined,
|
||||
this.SunlightBroadcast = this.fine.define(
|
||||
'sunlight-bcast',
|
||||
n => n.getGame && n.getTitle && n.props?.data,
|
||||
Twilight.SUNLIGHT_ROUTES
|
||||
)
|
||||
);
|
||||
|
||||
this.Dashboard = this.fine.define(
|
||||
'sunlight-dash',
|
||||
n => n.getIsChannelEditor && n.getIsChannelModerator && n.getIsAdsEnabled && n.getIsSquadStreamsEnabled,
|
||||
this.SunlightManager = this.fine.define(
|
||||
'sunlight-manager',
|
||||
n => n.props?.channelID && n.handleChange && has(n, 'hasVisitedStreamManager'),
|
||||
Twilight.SUNLIGHT_ROUTES
|
||||
);
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.Dashboard.on('mount', this.onDashUpdate, this);
|
||||
this.Dashboard.on('update', this.onDashUpdate, this);
|
||||
this.Dashboard.on('unmount', this.onDashUnmount, this);
|
||||
|
||||
this.HostBar.on('mount', this.onHostBarUpdate, this);
|
||||
this.HostBar.on('update', this.onHostBarUpdate, this);
|
||||
this.HostBar.on('unmount', this.onHostBarUnmount, this);
|
||||
|
||||
this.Dashboard.ready((cls, instances) => {
|
||||
this.SunlightManager.on('mount', this.updateSunlight, this);
|
||||
this.SunlightManager.on('update', this.updateSunlight, this);
|
||||
this.SunlightManager.on('unmount', this.removeSunlight, this);
|
||||
this.SunlightManager.ready((cls, instances) => {
|
||||
for(const inst of instances)
|
||||
this.onDashUpdate(inst);
|
||||
this.updateSunlight(inst);
|
||||
});
|
||||
|
||||
this.HostBar.ready((cls, instances) => {
|
||||
this.SunlightBroadcast.on('mount', this.updateBroadcast, this);
|
||||
this.SunlightBroadcast.on('update', this.updateBroadcast, this);
|
||||
this.SunlightBroadcast.on('unmount', this.removeBroadcast, this);
|
||||
this.SunlightBroadcast.ready((cls, instances) => {
|
||||
for(const inst of instances)
|
||||
this.onHostBarUpdate(inst);
|
||||
this.updateBroadcast(inst);
|
||||
});
|
||||
}
|
||||
|
||||
onDashUpdate(inst) {
|
||||
updateSunlight(inst) {
|
||||
this.settings.updateContext({
|
||||
channel: get('props.channelLogin', inst),
|
||||
channelID: get('props.channelID', inst)
|
||||
channelID: get('props.channelID', inst),
|
||||
hosting: !! inst.props?.hostedChannel?.id
|
||||
});
|
||||
}
|
||||
|
||||
onDashUnmount() {
|
||||
removeSunlight() {
|
||||
this.settings.updateContext({
|
||||
channel: null,
|
||||
channelID: null
|
||||
});
|
||||
}
|
||||
|
||||
onHostBarUpdate(inst) {
|
||||
const channel = inst.props?.channel,
|
||||
source = channel?.stream || channel?.broadcastSettings;
|
||||
|
||||
const game = source?.game,
|
||||
title = source?.title || null,
|
||||
color = channel?.primaryColorHex || null;
|
||||
|
||||
this.channel.updateChannelColor(color);
|
||||
|
||||
this.settings.updateContext({
|
||||
/*channel: channel?.login,
|
||||
channelID: channel?.id,*/
|
||||
category: game?.name,
|
||||
categoryID: game?.id,
|
||||
title,
|
||||
channelColor: color,
|
||||
hosting: !! inst.props?.hostedChannel
|
||||
});
|
||||
}
|
||||
|
||||
onHostBarUnmount() {
|
||||
this.settings.updateContext({
|
||||
/*channel: null,
|
||||
channelID: null,*/
|
||||
channelColor: null,
|
||||
category: null,
|
||||
categoryID: null,
|
||||
title: null,
|
||||
channelID: null,
|
||||
hosting: false
|
||||
});
|
||||
}
|
||||
|
||||
updateBroadcast(inst) {
|
||||
const data = inst.props?.data?.user?.broadcastSettings,
|
||||
game = data?.game;
|
||||
|
||||
this.settings.updateContext({
|
||||
category: game?.name,
|
||||
categoryID: game?.id,
|
||||
title: data?.title
|
||||
});
|
||||
}
|
||||
|
||||
removeBroadcast() {
|
||||
this.settings.updateContext({
|
||||
category: null,
|
||||
categoryID: null,
|
||||
title: null
|
||||
});
|
||||
}
|
||||
}
|
|
@ -66,10 +66,18 @@ export default class Switchboard extends Module {
|
|||
this.log.info(`Found Route and Switch with ${da_switch.props.children.length} routes.`);
|
||||
const location = router.props.location.pathname;
|
||||
|
||||
if ( ! this.loadRoute(da_switch, location, false) )
|
||||
this.loadRoute(da_switch, location, true);
|
||||
}
|
||||
|
||||
loadRoute(da_switch, location, with_params) {
|
||||
for(const route of da_switch.props.children) {
|
||||
if ( ! route.props || ! route.props.component )
|
||||
continue;
|
||||
|
||||
if ( with_params !== null && with_params !== route.props.path.includes(':') )
|
||||
continue;
|
||||
|
||||
try {
|
||||
const reg = pathToRegexp(route.props.path);
|
||||
if ( ! reg.exec || reg.exec(location) )
|
||||
|
@ -124,7 +132,9 @@ export default class Switchboard extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@ export const WS_CLUSTERS = {
|
|||
export const IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent);
|
||||
export const IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent);
|
||||
export const IS_WEBKIT = navigator.userAgent.indexOf('AppleWebKit/') !== -1 && navigator.userAgent.indexOf('Edge/') === -1;
|
||||
export const IS_FIREFOX = navigator.userAgent.indexOf('Firefox/') !== -1;
|
||||
export const IS_FIREFOX = (navigator.userAgent.indexOf('Firefox/') !== -1) || (window.InstallTrigger !== undefined);
|
||||
|
||||
export const WEBKIT_CSS = IS_WEBKIT ? '-webkit-' : '';
|
||||
|
||||
|
|
|
@ -116,6 +116,17 @@ export class Module extends EventEmitter {
|
|||
const path = this.__path || this.name,
|
||||
state = this.__load_state;
|
||||
|
||||
if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, [...chain, this]));
|
||||
else if ( this.load_requires )
|
||||
for(const name of this.load_requires) {
|
||||
const module = this.resolve(name);
|
||||
if ( module && chain.includes(module) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, [...chain, this, module]));
|
||||
}
|
||||
|
||||
chain.push(this);
|
||||
|
||||
if ( state === State.LOADING )
|
||||
return this.__load_promise;
|
||||
|
||||
|
@ -125,11 +136,6 @@ export class Module extends EventEmitter {
|
|||
else if ( state === State.UNLOADING )
|
||||
return Promise.reject(new ModuleError(`attempted to load module ${path} while module is being unloaded`));
|
||||
|
||||
else if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, chain));
|
||||
|
||||
chain.push(this);
|
||||
|
||||
this.__time('load-start');
|
||||
this.__load_state = State.LOADING;
|
||||
return this.__load_promise = (async () => {
|
||||
|
@ -170,6 +176,17 @@ export class Module extends EventEmitter {
|
|||
const path = this.__path || this.name,
|
||||
state = this.__load_state;
|
||||
|
||||
if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, [...chain, this]));
|
||||
else if ( this.load_dependents )
|
||||
for(const dep of this.load_dependents) {
|
||||
const module = this.resolve(dep);
|
||||
if ( module && chain.includes(module) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, [...chain, this, module]));
|
||||
}
|
||||
|
||||
chain.push(this);
|
||||
|
||||
if ( state === State.UNLOADING )
|
||||
return this.__load_promise;
|
||||
|
||||
|
@ -182,10 +199,6 @@ export class Module extends EventEmitter {
|
|||
else if ( state === State.LOADING )
|
||||
return Promise.reject(new ModuleError(`attempted to unload module ${path} while module is being loaded`));
|
||||
|
||||
else if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, chain));
|
||||
|
||||
chain.push(this);
|
||||
this.__time('unload-start');
|
||||
this.__load_state = State.UNLOADING;
|
||||
return this.__load_promise = (async () => {
|
||||
|
@ -197,7 +210,8 @@ export class Module extends EventEmitter {
|
|||
for(const name of this.load_dependents) {
|
||||
const module = this.resolve(name);
|
||||
if ( ! module )
|
||||
throw new ModuleError(`cannot find depending module ${name} when unloading ${path}`);
|
||||
//throw new ModuleError(`cannot find depending module ${name} when unloading ${path}`);
|
||||
continue;
|
||||
|
||||
promises.push(module.__unload([], initial, Array.from(chain)));
|
||||
}
|
||||
|
@ -227,6 +241,17 @@ export class Module extends EventEmitter {
|
|||
const path = this.__path || this.name,
|
||||
state = this.__state;
|
||||
|
||||
if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, [...chain, this]));
|
||||
else if ( this.requires )
|
||||
for(const name of this.requires) {
|
||||
const module = this.resolve(name);
|
||||
if ( module && chain.includes(module) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, [...chain, this, module]));
|
||||
}
|
||||
|
||||
chain.push(this);
|
||||
|
||||
if ( state === State.ENABLING )
|
||||
return this.__state_promise;
|
||||
|
||||
|
@ -236,10 +261,6 @@ export class Module extends EventEmitter {
|
|||
else if ( state === State.DISABLING )
|
||||
return Promise.reject(new ModuleError(`attempted to enable module ${path} while module is being disabled`));
|
||||
|
||||
else if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, chain));
|
||||
|
||||
chain.push(this);
|
||||
this.__time('enable-start');
|
||||
this.__state = State.ENABLING;
|
||||
return this.__state_promise = (async () => {
|
||||
|
@ -290,6 +311,17 @@ export class Module extends EventEmitter {
|
|||
const path = this.__path || this.name,
|
||||
state = this.__state;
|
||||
|
||||
if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, [...chain, this]));
|
||||
else if ( this.dependents )
|
||||
for(const dep of this.dependents) {
|
||||
const module = this.resolve(dep);
|
||||
if ( module && chain.includes(module) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, [...chain, this, dep]));
|
||||
}
|
||||
|
||||
chain.push(this);
|
||||
|
||||
if ( state === State.DISABLING )
|
||||
return this.__state_promise;
|
||||
|
||||
|
@ -302,10 +334,6 @@ export class Module extends EventEmitter {
|
|||
else if ( state === State.ENABLING )
|
||||
return Promise.reject(new ModuleError(`attempted to disable module ${path} but module is being enabled`));
|
||||
|
||||
else if ( chain.includes(this) )
|
||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, chain));
|
||||
|
||||
chain.push(this);
|
||||
this.__time('disable-start');
|
||||
this.__state = State.DISABLING;
|
||||
return this.__state_promise = (async () => {
|
||||
|
@ -319,7 +347,9 @@ export class Module extends EventEmitter {
|
|||
for(const name of this.dependents) {
|
||||
const module = this.resolve(name);
|
||||
if ( ! module )
|
||||
throw new ModuleError(`cannot find depending module ${name} when disabling ${path}`);
|
||||
// Assume a non-existent module isn't enabled.
|
||||
//throw new ModuleError(`cannot find depending module ${name} when disabling ${path}`);
|
||||
continue;
|
||||
|
||||
promises.push(module.__disable([], initial, Array.from(chain)));
|
||||
}
|
||||
|
@ -665,7 +695,7 @@ export class ModuleError extends Error { }
|
|||
|
||||
export class CyclicDependencyError extends ModuleError {
|
||||
constructor(message, modules) {
|
||||
super(message);
|
||||
super(`${message} (${modules.map(x => x.path).join(' => ')})`);
|
||||
this.modules = modules;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue