feat: switch to eslint and bundle with webpack

This commit is contained in:
iCrawl 2019-04-21 20:30:00 +02:00
parent 983207ae48
commit b691ac19c5
No known key found for this signature in database
GPG key ID: E41A6DB922EC2CFE
12 changed files with 2325 additions and 1322 deletions

View file

@ -1,11 +1,10 @@
.vscode/**
.vscode-test/**
test/**
.vscode
dist/**/*.map
node_modules
src
.gitattributes
.gitignore
package.json
tsconfig.json
tslint.json
src/
typings/
dist/**/*.map
gulpfile.js
webpack.config.js
yarn.lock

View file

@ -22,7 +22,7 @@
* Stable or Insiders build detection
* Debug mode detection
* Easily manually reconnect to Discord
* **(NEW)** VSCode Live Share support!
* VSCode Live Share support
## Troubleshooting

View file

@ -1,27 +0,0 @@
const gulp = require('gulp');
const fsn = require('fs-nextra');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const merge = require('merge2');
const path = require('path');
const project = ts.createProject('tsconfig.json');
async function build() {
await Promise.all([
fsn.emptydir('dist'),
fsn.emptydir('typings')
]);
const result = project.src()
.pipe(sourcemaps.init())
.pipe(project());
await fsn.copy(path.join(__dirname, 'src', 'data'), path.join(__dirname, 'dist', 'data'))
return merge([
result.dts.pipe(gulp.dest('typings')),
result.js.pipe(sourcemaps.write('.', { sourceRoot: '../src' })).pipe(gulp.dest('dist'))
]);
}
gulp.task('default', build);
gulp.task('build', build);

View file

@ -1,7 +1,7 @@
{
"name": "discord-vscode",
"displayName": "Discord Presence",
"version": "3.4.0",
"version": "3.5.0",
"description": "Update your discord status with the newly added rich presence.",
"private": true,
"author": {
@ -19,8 +19,8 @@
"main": "./dist/extension",
"scripts": {
"prebuild": "yarn lint",
"build": "gulp",
"lint": "tslint -p tsconfig.json",
"build": "webpack --mode production",
"lint": "eslint src --ext .ts",
"postinstall": "node ./node_modules/vscode/bin/install"
},
"activationEvents": [
@ -177,23 +177,28 @@
},
"dependencies": {
"clipboardy": "^2.0.0",
"discord-rpc": "iCrawl/rpc#custom",
"discord-rpc": "discordjs/RPC",
"register-scheme": "devsnek/node-register-scheme",
"vsls": "^0.3.1291"
},
"devDependencies": {
"@types/node": "^11.13.5",
"fs-nextra": "^0.4.5",
"gulp": "^3.9.1",
"gulp-sourcemaps": "^2.6.5",
"gulp-typescript": "^5.0.1",
"merge2": "^1.2.3",
"tslint": "^5.16.0",
"tslint-config-fire": "^1.0.1",
"@types/node": "^11.13.6",
"@typescript-eslint/eslint-plugin": "^1.7.0",
"@typescript-eslint/parser": "^1.7.0",
"clean-webpack-plugin": "^2.0.1",
"eslint": "^5.16.0",
"eslint-config-marine": "^2.0.0",
"terser-webpack-plugin": "^1.2.3",
"ts-loader": "^5.3.3",
"typescript": "^3.4.4",
"vscode": "^1.1.33"
"vscode": "^1.1.33",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.0"
},
"engines": {
"vscode": "^1.15.0"
},
"eslintConfig": {
"extends": "marine/node"
}
}

View file

@ -1,15 +1,15 @@
const { Client } = require('discord-rpc'); // tslint:disable-line
const { Client } = require('discord-rpc'); // eslint-disable-line
import {
Disposable,
StatusBarItem,
workspace,
Uri,
window
} from 'vscode'; // tslint:disable-line
import * as vsls from 'vsls/vscode';
} from 'vscode';
import * as vsls from 'vsls';
import Activity from '../structures/Activity';
import Logger from '../structures/Logger';
const clipboardy = require('clipboardy'); // tslint:disable-line
const clipboardy = require('clipboardy'); // eslint-disable-line
let activityTimer: NodeJS.Timer;
@ -18,74 +18,75 @@ export default class RPCClient implements Disposable {
public config = workspace.getConfiguration('discord');
private _rpc: any; // tslint:disable-line
private _rpc: any;
private readonly _activity = new Activity(); // tslint:disable-line
private readonly _activity = new Activity();
private readonly _clientId: string; // tslint:disable-line
private readonly _clientId: string;
public constructor(clientId: string, statusBarIcon: StatusBarItem) {
this._clientId = clientId;
this.statusBarIcon = statusBarIcon;
}
public get client() {
public get client(): any {
return this._rpc;
}
public setActivity(workspaceElapsedTime: boolean = false) {
public setActivity(workspaceElapsedTime: boolean = false): void {
if (!this._rpc) return;
const activity = this._activity.generate(workspaceElapsedTime);
Logger.log('Sending activity to Discord.');
this._rpc.setActivity(activity);
}
public async allowSpectate() {
public async allowSpectate(): Promise<void> {
if (!this._rpc) return;
Logger.log('Allowed spectating.');
Logger.log('Sending spectate activity to Discord.');
await this._activity.allowSpectate();
}
public async disableSpectate() {
public async disableSpectate(): Promise<void> {
if (!this._rpc) return;
Logger.log('Disabled spectating.');
await this._activity.disableSpectate();
}
public async allowJoinRequests() {
public async allowJoinRequests(): Promise<void> {
if (!this._rpc) return;
Logger.log('Allowed join requests.');
Logger.log('Sending join activity to Discord.');
await this._activity.allowJoinRequests();
}
public async disableJoinRequests() {
public async disableJoinRequests(): Promise<void> {
if (!this._rpc) return;
Logger.log('Disabled join requests.');
await this._activity.disableJoinRequests();
}
public async login() {
public async login(): Promise<void> {
if (this._rpc) return;
this._rpc = new Client({ transport: 'ipc' });
Logger.log('Logging into RPC.');
this._rpc.once('ready', async () => {
this._rpc.once('ready', async (): Promise<void> => {
Logger.log('Successfully connected to Discord.');
this.statusBarIcon.text = '$(globe) Connected to Discord';
this.statusBarIcon.tooltip = 'Connected to Discord';
setTimeout(() => this.statusBarIcon.text = '$(globe)', 5000);
// @ts-ignore
setTimeout((): void => this.statusBarIcon.text = '$(globe)', 5000);
if (activityTimer) clearInterval(activityTimer);
this.setActivity();
activityTimer = setInterval(() => {
activityTimer = setInterval((): void => {
this.config = workspace.getConfiguration('discord');
this.setActivity(this.config.get<boolean>('workspaceElapsedTime'));
}, 10000);
this._rpc.subscribe('ACTIVITY_SPECTATE', async ({ secret }: { secret: string }) => {
this._rpc.subscribe('ACTIVITY_SPECTATE', async ({ secret }: { secret: string }): Promise<void> => {
const liveshare = await vsls.getApi();
if (!liveshare) return;
try {
@ -105,17 +106,17 @@ export default class RPCClient implements Disposable {
// You might be asking yourself again: "but why?"
// Same here, this is a real nasty race condition that happens inside the discord-rpc module currently
// To circumvent this we need to timeout sending the subscribe events to the discord client
setTimeout(() => {
this._rpc.subscribe('ACTIVITY_JOIN_REQUEST', async ({ user }: { user: { username: string, discriminator: string } }) => {
setTimeout((): void => {
this._rpc.subscribe('ACTIVITY_JOIN_REQUEST', async ({ user }: { user: { username: string; discriminator: string } }): Promise<void> =>
window.showInformationMessage(`${user.username}#${user.discriminator} wants to join your session`, { title: 'Accept' }, { title: 'Decline' })
// eslint-disable-next-line
.then(async (val: { title: string } | undefined) => {
if (val && val.title === 'Accept') await this._rpc.sendJoinInvite(user);
if (val && val.title === 'Accept') await this._rpc.sendJoinInvite(user); // eslint-disable-line
else await this._rpc.closeJoinRequest(user);
});
});
}));
}, 500);
setTimeout(() => {
this._rpc.subscribe('ACTIVITY_JOIN', async ({ secret }: { secret: string }) => {
setTimeout((): void => {
this._rpc.subscribe('ACTIVITY_JOIN', async ({ secret }: { secret: string }): Promise<void> => {
const liveshare = await vsls.getApi();
if (!liveshare) return;
try {
@ -133,17 +134,21 @@ export default class RPCClient implements Disposable {
const liveshare = await vsls.getApi();
if (!liveshare) return;
liveshare.onDidChangeSession(({ session }: { session: vsls.Session }) => {
liveshare.onDidChangeSession(({ session }: { session: vsls.Session }): void => {
// @ts-ignore
if (session.id) return this._activity.changePartyId(session.id);
else return this._activity.changePartyId();
// @ts-ignore
return this._activity.changePartyId();
});
liveshare.onDidChangePeers(({ added, removed }: { added: vsls.Peer[], removed: vsls.Peer[] }) => {
liveshare.onDidChangePeers(({ added, removed }: { added: vsls.Peer[]; removed: vsls.Peer[] }): void => {
// @ts-ignore
if (added.length) return this._activity.increasePartySize(added.length);
// @ts-ignore
else if (removed.length) return this._activity.decreasePartySize(removed.length);
});
});
this._rpc.transport.once('close', async () => {
this._rpc.transport.once('close', async (): Promise<void> => {
if (!this.config.get<boolean>('enabled')) return;
await this.dispose();
this.statusBarIcon.text = '$(plug) Reconnect to Discord';
@ -154,11 +159,10 @@ export default class RPCClient implements Disposable {
await this._rpc.login({ clientId: this._clientId });
}
public async dispose() {
public async dispose(): Promise<void> {
this._activity.dispose();
try {
await this._rpc.destroy();
// tslint:disable-next-line
} catch {}
this._rpc = null;
this.statusBarIcon.tooltip = '';

View file

@ -5,10 +5,10 @@ import {
StatusBarItem,
window,
workspace
} from 'vscode'; // tslint:disable-line
} from 'vscode';
import RPCClient from './client/RPCClient';
import Logger from './structures/Logger';
const { register } = require('discord-rpc'); // tslint:disable-line
const { register } = require('discord-rpc'); // eslint-disable-line
const statusBarIcon: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
statusBarIcon.text = '$(pulse) Connecting to Discord...';
@ -17,7 +17,7 @@ const config = workspace.getConfiguration('discord');
register(config.get<string>('clientID'));
const rpc = new RPCClient(config.get<string>('clientID')!, statusBarIcon);
export async function activate(context: ExtensionContext) {
export async function activate(context: ExtensionContext): Promise<void> {
Logger.log('Discord Presence activated!');
let isWorkspaceExcluded = false;
@ -27,7 +27,7 @@ export async function activate(context: ExtensionContext) {
const regex = new RegExp(pattern);
const folders = workspace.workspaceFolders;
if (!folders) break;
if (folders.some((folder) => regex.test(folder.uri.fsPath))) {
if (folders.some((folder): boolean => regex.test(folder.uri.fsPath))) {
isWorkspaceExcluded = true;
break;
}
@ -50,7 +50,7 @@ export async function activate(context: ExtensionContext) {
}
}
const enabler = commands.registerCommand('discord.enable', async () => {
const enabler = commands.registerCommand('discord.enable', async (): Promise<void> => {
await rpc.dispose();
config.update('enabled', true);
rpc.config = workspace.getConfiguration('discord');
@ -60,7 +60,7 @@ export async function activate(context: ExtensionContext) {
window.showInformationMessage('Enabled Discord Rich Presence for this workspace.');
});
const disabler = commands.registerCommand('discord.disable', async () => {
const disabler = commands.registerCommand('discord.disable', async (): Promise<void> => {
config.update('enabled', false);
rpc.config = workspace.getConfiguration('discord');
await rpc.dispose();
@ -68,7 +68,7 @@ export async function activate(context: ExtensionContext) {
window.showInformationMessage('Disabled Discord Rich Presence for this workspace.');
});
const reconnecter = commands.registerCommand('discord.reconnect', async () => {
const reconnecter = commands.registerCommand('discord.reconnect', async (): Promise<void> => {
await rpc.dispose();
await rpc.login();
if (!config.get('silent')) window.showInformationMessage('Reconnecting to Discord RPC...');
@ -76,27 +76,27 @@ export async function activate(context: ExtensionContext) {
rpc.statusBarIcon.command = undefined;
});
const allowSpectate = commands.registerCommand('discord.allowSpectate', async () => {
const allowSpectate = commands.registerCommand('discord.allowSpectate', async (): Promise<void> => {
await rpc.allowSpectate();
});
const disableSpectate = commands.registerCommand('discord.disableSpectate', async () => {
const disableSpectate = commands.registerCommand('discord.disableSpectate', async (): Promise<void> => {
await rpc.disableSpectate();
});
const allowJoinRequests = commands.registerCommand('discord.allowJoinRequests', async () => {
const allowJoinRequests = commands.registerCommand('discord.allowJoinRequests', async (): Promise<void> => {
await rpc.allowJoinRequests();
});
const disableJoinRequests = commands.registerCommand('discord.disableJoinRequests', async () => {
const disableJoinRequests = commands.registerCommand('discord.disableJoinRequests', async (): Promise<void> => {
await rpc.disableJoinRequests();
});
context.subscriptions.push(enabler, disabler, reconnecter, allowSpectate, disableSpectate, allowJoinRequests, disableJoinRequests);
}
export async function deactivate() {
export async function deactivate(): Promise<void> {
await rpc.dispose();
}
process.on('unhandledRejection', err => Logger.log(err as string));
process.on('unhandledRejection', (err): void => Logger.log(err as string));

View file

@ -6,9 +6,9 @@ import {
env,
window,
workspace
} from 'vscode'; // tslint:disable-line
import * as vsls from 'vsls/vscode';
const lang = require('../data/languages.json'); // tslint:disable-line
} from 'vscode';
import * as vsls from 'vsls';
const lang = require('../data/languages.json'); // eslint-disable-line
const knownExtentions: { [key: string]: { image: string } } = lang.knownExtentions;
const knownLanguages: string[] = lang.knownLanguages;
@ -40,17 +40,17 @@ interface FileDetail {
}
export default class Activity implements Disposable {
private _state: State | null = null; // tslint:disable-line
private _state: State | null = null;
private readonly _config = workspace.getConfiguration('discord'); // tslint:disable-line
private readonly _config = workspace.getConfiguration('discord');
private _lastKnownFile: string = ''; // tslint:disable-line
private _lastKnownFile: string = '';
public get state() {
public get state(): State | null {
return this._state;
}
public generate(workspaceElapsedTime: boolean = false) {
public generate(workspaceElapsedTime: boolean = false): State {
let largeImageKey: any = 'vscode-big';
if (window.activeTextEditor) {
if (window.activeTextEditor.document.fileName === this._lastKnownFile) {
@ -63,7 +63,7 @@ export default class Activity implements Disposable {
}
this._lastKnownFile = window.activeTextEditor.document.fileName;
const filename = basename(window.activeTextEditor.document.fileName);
largeImageKey = knownExtentions[Object.keys(knownExtentions).find(key => {
largeImageKey = knownExtentions[Object.keys(knownExtentions).find((key): boolean => {
if (filename.endsWith(key)) return true;
const match = key.match(/^\/(.*)\/([mgiy]+)$/);
if (!match) return false;
@ -84,9 +84,9 @@ export default class Activity implements Disposable {
largeImageText: window.activeTextEditor
? this._config.get<string>('largeImage')!
.replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : 'txt')
.replace('{Lang}', largeImageKey ? (largeImageKey.image || largeImageKey).toLowerCase().replace(/^\w/, (c: string) => c.toUpperCase()) : 'Txt')
.replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT')
|| window.activeTextEditor.document.languageId.padEnd(2, '\u200b')
.replace('{Lang}', largeImageKey ? (largeImageKey.image || largeImageKey).toLowerCase().replace(/^\w/, (c: string): string => c.toUpperCase()) : 'Txt')
.replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT') ||
window.activeTextEditor.document.languageId.padEnd(2, '\u200b')
: this._config.get<string>('largeImageIdle'),
smallImageKey: debug.activeDebugSession ? 'debug' : env.appName.includes('Insiders') ? 'vscode-insiders' : 'vscode',
smallImageText: this._config.get<string>('smallImage')!.replace('{appname}', env.appName)
@ -95,7 +95,7 @@ export default class Activity implements Disposable {
return this._state;
}
public async allowSpectate() {
public async allowSpectate(): Promise<State | void> {
const liveshare = await vsls.getApi();
if (!liveshare) return;
const join = await liveshare.share({ suppressNotification: true, access: vsls.Access.ReadOnly });
@ -108,7 +108,7 @@ export default class Activity implements Disposable {
return this._state;
}
public async disableSpectate() {
public async disableSpectate(): Promise<State | void> {
const liveshare = await vsls.getApi();
if (!liveshare) return;
await liveshare.end();
@ -121,7 +121,7 @@ export default class Activity implements Disposable {
return this._state;
}
public async allowJoinRequests() {
public async allowJoinRequests(): Promise<State | void> {
const liveshare = await vsls.getApi();
if (!liveshare) return;
const join = await liveshare.share({ suppressNotification: true });
@ -137,7 +137,7 @@ export default class Activity implements Disposable {
return this._state;
}
public async disableJoinRequests() {
public async disableJoinRequests(): Promise<State | void> {
const liveshare = await vsls.getApi();
if (!liveshare) return;
await liveshare.end();
@ -153,7 +153,7 @@ export default class Activity implements Disposable {
return this._state;
}
public changePartyId(id?: string) {
public changePartyId(id?: string): State | void {
if (!this._state) return;
this._state = {
...this._state,
@ -165,7 +165,7 @@ export default class Activity implements Disposable {
return this._state;
}
public increasePartySize(size?: number) {
public increasePartySize(size?: number): State | void {
if (!this._state) return;
if (this.state && this._state.partySize === 5) return;
this._state = {
@ -176,7 +176,7 @@ export default class Activity implements Disposable {
return this._state;
}
public decreasePartySize(size?: number) {
public decreasePartySize(size?: number): State | void {
if (!this._state) return;
if (this.state && this._state.partySize === 1) return;
this._state = {
@ -187,12 +187,12 @@ export default class Activity implements Disposable {
return this._state;
}
public dispose() {
public dispose(): void {
this._state = null;
this._lastKnownFile = '';
}
private _generateDetails(debugging: string, editing: string, idling: string, largeImageKey: any) {
private _generateDetails(debugging: string, editing: string, idling: string, largeImageKey: any): string {
let raw: string = this._config.get<string>(idling)!.replace('{null}', empty);
let filename = null;
let dirname = null;
@ -231,7 +231,7 @@ export default class Activity implements Disposable {
.replace('{fulldirname}', fullDirname!)
.replace('{workspace}', checkState && workspaceFolder ? workspaceFolder.name : this._config.get<string>('lowerDetailsNotFound')!.replace('{null}', empty))
.replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : 'txt')
.replace('{Lang}', largeImageKey ? (largeImageKey.image || largeImageKey).toLowerCase().replace(/^\w/, (c: string) => c.toUpperCase()) : 'Txt')
.replace('{Lang}', largeImageKey ? (largeImageKey.image || largeImageKey).toLowerCase().replace(/^\w/, (c: string): string => c.toUpperCase()) : 'Txt')
.replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT');
if (totalLines) raw = raw!.replace('{totallines}', totalLines);
if (size) raw = raw!.replace('{filesize}', size);
@ -242,7 +242,7 @@ export default class Activity implements Disposable {
return raw;
}
private _generateFileDetails(str?: string) {
private _generateFileDetails(str?: string): FileDetail {
const fileDetail: FileDetail = {};
if (!str) return fileDetail;
@ -252,11 +252,11 @@ export default class Activity implements Disposable {
}
if (str.includes('{currentline}')) {
fileDetail.currentLine = (window.activeTextEditor.selection.active.line + 1).toLocaleString(); // tslint:disable-line
fileDetail.currentLine = (window.activeTextEditor.selection.active.line as number + 1).toLocaleString();
}
if (str.includes('{currentcolumn}')) {
fileDetail.currentColumn = (window.activeTextEditor.selection.active.character + 1).toLocaleString(); // tslint:disable-line
fileDetail.currentColumn = (window.activeTextEditor.selection.active.character as number + 1).toLocaleString();
}
if (str.includes('{filesize}')) {

View file

@ -1,14 +1,14 @@
import { OutputChannel, window } from 'vscode'; // tslint:disable-line
import { OutputChannel, window } from 'vscode';
// tslint:disable-next-line
// eslint-disable-next-line
export default class Logger {
private static _output: OutputChannel; // tslint:disable-line
private static _output: OutputChannel;
private static _setup() {
private static _setup(): void {
this._output = this._output || window.createOutputChannel('Discord Presence');
}
public static log(message: string) {
public static log(message: string): void {
if (!this._output) this._setup();
this._output.appendLine(message);
}

View file

@ -2,7 +2,7 @@
"compilerOptions": {
"strict": true,
"module": "commonjs",
"target": "es6",
"target": "es2017",
"lib": [
"esnext",
"esnext.array",
@ -10,15 +10,14 @@
"esnext.intl",
"esnext.symbol"
],
"declaration": true,
"rootDir": "src",
"outDir": "dist",
"declaration": false,
"sourceMap": true,
"removeComments": false,
"experimentalDecorators": true,
"typeRoots": [
"node_modules/@types"
]
"experimentalDecorators": true
},
"include": [
"./src"
"exclude": [
"node_modules"
]
}

View file

@ -1,3 +0,0 @@
{
"extends": "tslint-config-fire"
}

43
webpack.config.js Normal file
View file

@ -0,0 +1,43 @@
'use strict';
const CleanWebpackPlugin = require('clean-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
target: 'node',
entry: './src/extension.ts',
output: {
filename: 'extension.js',
libraryTarget: 'commonjs2'
},
devtool: 'source-map',
externals: {
vscode: 'commonjs vscode'
},
resolve: {
extensions: ['.ts', '.js', '.json']
},
plugins: [
new CleanWebpackPlugin()
],
optimization: {
minimizer: [
new TerserPlugin({
cache: false,
parallel: true,
sourceMap: true,
terserOptions: {
ecma: 8,
keep_classnames: true
}
})
]
},
module: {
rules: [{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}]
}
};

3351
yarn.lock

File diff suppressed because it is too large Load diff