eslint, require-no-cache now deletes all requires from plugin directory from cache
This commit is contained in:
parent
f2af1891ee
commit
81b8e7581a
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
*.js
|
||||
*.d.ts
|
46
.eslintrc.js
Normal file
46
.eslintrc.js
Normal file
@ -0,0 +1,46 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'es2021': true,
|
||||
'node': true
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended'
|
||||
],
|
||||
'parser': '@typescript-eslint/parser',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 13,
|
||||
'sourceType': 'module',
|
||||
'project': 'tsconfig.json',
|
||||
'tsconfigRootDir': __dirname,
|
||||
},
|
||||
'plugins': [
|
||||
'@typescript-eslint'
|
||||
],
|
||||
'rules': {
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
'allowEmptyCatch': true,
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'indent': [
|
||||
'error',
|
||||
2
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single'
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'always'
|
||||
]
|
||||
}
|
||||
};
|
2776
package-lock.json
generated
2776
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@squeebot/core",
|
||||
"version": "3.3.5",
|
||||
"version": "3.3.6",
|
||||
"description": "Squeebot v3 core for the execution environment",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@ -23,7 +23,8 @@
|
||||
"@types/node": "^16.7.10",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/tar": "^4.0.5",
|
||||
"tslint": "^6.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||
"eslint": "^8.4.1",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -52,11 +52,11 @@ export function httpGET(
|
||||
}
|
||||
|
||||
return httpGET(res.headers.location as string,
|
||||
headers,
|
||||
restrictToText,
|
||||
saveTo,
|
||||
lback,
|
||||
).then(resolve, reject);
|
||||
headers,
|
||||
restrictToText,
|
||||
saveTo,
|
||||
lback,
|
||||
).then(resolve, reject);
|
||||
}
|
||||
|
||||
if (saveTo) {
|
||||
|
@ -6,10 +6,10 @@
|
||||
*/
|
||||
export function sanitizeEscapedText(text: string): string {
|
||||
return text.replace(/\n/g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, '\'')
|
||||
.trim();
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, '\'')
|
||||
.trim();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ const dirs: {[key: string]: string} = {
|
||||
* @param chroot Change bot root to this instead of the path in the environment
|
||||
* @returns Squeebot environment
|
||||
*/
|
||||
export async function loadEnvironment(enviroFile: string = 'squeebot.env.json', chroot?: string): Promise<IEnvironment> {
|
||||
export async function loadEnvironment(enviroFile = 'squeebot.env.json', chroot?: string): Promise<IEnvironment> {
|
||||
if (!await fs.pathExists(enviroFile)) {
|
||||
throw new Error('Environment file does not exist.');
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export class Logger {
|
||||
const old = this.console[index];
|
||||
this.console[index] = (...data: any[]): void => {
|
||||
rl.output.write('\x1b[2K\r');
|
||||
old.apply(null, data);
|
||||
old(...data);
|
||||
rl.prompt(true);
|
||||
};
|
||||
}
|
||||
@ -42,20 +42,20 @@ export class Logger {
|
||||
}
|
||||
|
||||
switch (ltype) {
|
||||
case 'info':
|
||||
message.push('[ INFO]');
|
||||
break;
|
||||
case 'debug':
|
||||
message.push('[DEBUG]');
|
||||
break;
|
||||
case 'warn':
|
||||
message.push('[ WARN]');
|
||||
cfunc = this.console[1];
|
||||
break;
|
||||
case 'error':
|
||||
message.push('[ERROR]');
|
||||
cfunc = this.console[2];
|
||||
break;
|
||||
case 'info':
|
||||
message.push('[ INFO]');
|
||||
break;
|
||||
case 'debug':
|
||||
message.push('[DEBUG]');
|
||||
break;
|
||||
case 'warn':
|
||||
message.push('[ WARN]');
|
||||
cfunc = this.console[1];
|
||||
break;
|
||||
case 'error':
|
||||
message.push('[ERROR]');
|
||||
cfunc = this.console[2];
|
||||
break;
|
||||
}
|
||||
|
||||
// Short dance to apply formatting
|
||||
@ -65,7 +65,7 @@ export class Logger {
|
||||
final = util.format(data[0], ...fargs);
|
||||
}
|
||||
message.push(final);
|
||||
cfunc.apply(null, message);
|
||||
cfunc(...message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,6 +102,6 @@ export class NPMExecutor {
|
||||
}
|
||||
|
||||
private removeVersionWildcard(str: string): string {
|
||||
return str.replace(/\^|\>|\=/, '');
|
||||
return str.replace(/\^|>|=/, '');
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
* Declare this plugin as one that the user can configure.
|
||||
* @param defconf Default configuration
|
||||
*/
|
||||
export function Configurable(defconf: any): Function {
|
||||
return (constructor: Function): void => {
|
||||
export function Configurable(defconf: any): (...arg: any[]) => any {
|
||||
return (constructor: (...arg: any[]) => any): void => {
|
||||
constructor.prototype.__defconf = defconf;
|
||||
};
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
* Declare this plugin as one that utilises services.
|
||||
* @param servtype Service class, usually a Protocol
|
||||
*/
|
||||
export function InjectService(servtype: any): Function {
|
||||
return (constructor: Function): void => {
|
||||
export function InjectService(servtype: any): (...arg: any[]) => any {
|
||||
return (constructor: (...arg: any[]) => any): void => {
|
||||
constructor.prototype.__service = servtype;
|
||||
};
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export class PluginMetaLoader {
|
||||
throw new Error('Plugin metadata does not specify a name, for some reason');
|
||||
}
|
||||
|
||||
if (json.name === 'squeebot' || !(/^[a-zA-Z0-9_\-]+$/.test(json.name))) {
|
||||
if (json.name === 'squeebot' || !(/^[a-zA-Z0-9_-]+$/.test(json.name))) {
|
||||
throw new Error('Illegal name.');
|
||||
}
|
||||
|
||||
@ -76,12 +76,13 @@ export class PluginMetaLoader {
|
||||
public async loadAll(ignoreErrors = false): Promise<IPluginManifest[]> {
|
||||
const dirlist = await fs.readdir(this.env.pluginsPath);
|
||||
const plugins: IPluginManifest[] = [];
|
||||
|
||||
for (const file of dirlist) {
|
||||
// Ignore hidden files and non-directories
|
||||
const fpath = path.join(this.env.pluginsPath, file);
|
||||
if (file.indexOf('.') === 0 ||
|
||||
file === 'node_modules' ||
|
||||
!(await fs.lstat(fpath)).isDirectory()) {
|
||||
const isDirectory = (await fs.lstat(fpath)).isDirectory();
|
||||
|
||||
if (!isDirectory || file.startsWith('.') || file === 'node_modules') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -89,10 +90,9 @@ export class PluginMetaLoader {
|
||||
const plugin = await this.load(file);
|
||||
plugins.push(plugin);
|
||||
} catch (e) {
|
||||
if (ignoreErrors) {
|
||||
continue;
|
||||
if (!ignoreErrors) {
|
||||
logger.error(e);
|
||||
}
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
return plugins;
|
||||
|
@ -84,7 +84,7 @@ export class PluginManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(/^[a-zA-Z0-9_\-]+$/.test(manifest.name))) {
|
||||
if (!(/^[a-zA-Z0-9_-]+$/.test(manifest.name))) {
|
||||
throw new Error('Illegal name for a plugin!');
|
||||
}
|
||||
|
||||
@ -284,8 +284,9 @@ export class PluginManager {
|
||||
/**
|
||||
* Restart a loaded plugin.
|
||||
* @param mf Plugin instance, plugin manifest or plugin name
|
||||
* @param wait Waits for the plugin to be available before resolving
|
||||
*/
|
||||
public async restart(mf: IPluginManifest | IPlugin | string): Promise<void> {
|
||||
public async restart(mf: IPluginManifest | IPlugin | string, wait = false): Promise<void> {
|
||||
let manifest;
|
||||
if (typeof mf === 'string') {
|
||||
manifest = this.getAvailableByName(mf);
|
||||
@ -299,13 +300,34 @@ export class PluginManager {
|
||||
throw new Error('Plugin not found');
|
||||
}
|
||||
|
||||
if (!this.getLoadedByName(manifest.name)) {
|
||||
const pluginName = manifest.name;
|
||||
if (!this.getLoadedByName(pluginName)) {
|
||||
this.load(manifest);
|
||||
return;
|
||||
}
|
||||
|
||||
this.restartQueue.set(manifest.name, manifest);
|
||||
this.stream.emitTo(manifest.name, 'pluginUnload', manifest.name);
|
||||
this.restartQueue.set(pluginName, manifest);
|
||||
this.stream.emitTo(pluginName, 'pluginUnload', pluginName);
|
||||
|
||||
if (wait) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let retries = 0;
|
||||
const checkInterval = setInterval(() => {
|
||||
// Plugin has been loaded, resolve the promise
|
||||
if (this.getLoadedByName(pluginName)) {
|
||||
clearInterval(checkInterval);
|
||||
return resolve();
|
||||
}
|
||||
// Increment retry count and wait for next iteration
|
||||
retries++;
|
||||
if (retries >= 20) {
|
||||
// Give up after 10 seconds
|
||||
clearInterval(checkInterval);
|
||||
reject(new Error('Could not determine loaded status within a reasonable time frame.'));
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,7 @@ export class Plugin implements IPlugin {
|
||||
* Called when plugin first starts.
|
||||
* Please use this instead of the constructor.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
public initialize(): void {}
|
||||
|
||||
public get name(): string {
|
||||
|
@ -163,7 +163,7 @@ export class RepositoryManager {
|
||||
throw new Error('Invalid metadata file for repository.');
|
||||
}
|
||||
|
||||
if (!(/^[a-zA-Z0-9_\-\+]+$/.test(meta.name))) {
|
||||
if (!(/^[a-zA-Z0-9_\-+]+$/.test(meta.name))) {
|
||||
throw new Error('Illegal name for repository!');
|
||||
}
|
||||
|
||||
@ -286,7 +286,7 @@ export class RepositoryManager {
|
||||
throw new Error('Invalid repository file ' + rf);
|
||||
}
|
||||
|
||||
if (!(/^[a-zA-Z0-9_\-\+]+$/.test(contents.name))) {
|
||||
if (!(/^[a-zA-Z0-9_\-+]+$/.test(contents.name))) {
|
||||
throw new Error(`"${rf}" is an illegal name for a repository!`);
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,12 @@ export class Configuration {
|
||||
const json = await fs.readJson(this.file);
|
||||
this.config = json;
|
||||
|
||||
// Assign default values to existing configuration and resave.
|
||||
// Eliminates the need for plugins to overwrite the configuration file
|
||||
// when exiting.
|
||||
if (this.defaults) {
|
||||
this.config = Object.assign({}, this.defaults, json);
|
||||
await this.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,18 +184,18 @@ export class Formatter {
|
||||
// Special types
|
||||
if (elemParams && elemParams.type) {
|
||||
switch (elemParams.type) {
|
||||
case 'time':
|
||||
elemValue = new Date(elemValue).toString();
|
||||
break;
|
||||
case 'metric':
|
||||
elemValue = thousandsSeparator(elemValue);
|
||||
break;
|
||||
case 'timesince':
|
||||
elemValue = timeSince(elemValue);
|
||||
break;
|
||||
case 'duration':
|
||||
elemValue = toHHMMSS(elemValue);
|
||||
break;
|
||||
case 'time':
|
||||
elemValue = new Date(elemValue).toString();
|
||||
break;
|
||||
case 'metric':
|
||||
elemValue = thousandsSeparator(elemValue);
|
||||
break;
|
||||
case 'timesince':
|
||||
elemValue = timeSince(elemValue);
|
||||
break;
|
||||
case 'duration':
|
||||
elemValue = toHHMMSS(elemValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
import { EMessageType, IMessage } from './message';
|
||||
import { Protocol } from './protocol';
|
||||
|
||||
|
@ -11,7 +11,7 @@ export interface IMessageData {
|
||||
value: any;
|
||||
}
|
||||
|
||||
export type IMessageHandler = (data: IMessageData | string, reject: Function, next: IMessageHandler) => void;
|
||||
export type IMessageHandler = (data: IMessageData | string, reject: (error: Error) => void, next: IMessageHandler) => void;
|
||||
|
||||
/**
|
||||
* Staged messaging handler
|
||||
|
@ -10,9 +10,18 @@ export { IProcessData, spawnProcess, execProcess } from './run';
|
||||
*/
|
||||
export function requireNoCache(file: string): object | undefined {
|
||||
const fullPath = path.resolve(file);
|
||||
// TODO: maybe use new "import" function?
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const mod = require(fullPath);
|
||||
if (require.cache && require.cache[fullPath]) {
|
||||
delete require.cache[fullPath];
|
||||
|
||||
// Delete in-plugin-folder requires from cache as well
|
||||
const dirname = path.dirname(fullPath);
|
||||
const cacheEntries = Object.keys(require.cache).filter((entry) => entry.startsWith(dirname));
|
||||
cacheEntries.forEach((entry) => {
|
||||
delete require.cache[entry];
|
||||
});
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
122
tslint.json
122
tslint.json
@ -1,122 +0,0 @@
|
||||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rules": {
|
||||
"align": {
|
||||
"options": [
|
||||
"parameters",
|
||||
"statements"
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
"eofline": true,
|
||||
"import-spacing": true,
|
||||
"indent": {
|
||||
"options": [
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-empty": false,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"semicolon": {
|
||||
"options": [
|
||||
"always"
|
||||
]
|
||||
},
|
||||
"space-before-function-paren": {
|
||||
"options": {
|
||||
"anonymous": "never",
|
||||
"asyncArrow": "always",
|
||||
"constructor": "never",
|
||||
"method": "never",
|
||||
"named": "never"
|
||||
}
|
||||
},
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature"
|
||||
],
|
||||
"forin": false,
|
||||
"ban-types": {
|
||||
"function": false
|
||||
},
|
||||
"typedef-whitespace": {
|
||||
"options": [
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
},
|
||||
{
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"variable-name": {
|
||||
"options": [
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-pascal-case"
|
||||
]
|
||||
},
|
||||
"whitespace": {
|
||||
"options": [
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user