rewrite (#101)
* rewrite: initial commit * feat: add constants for live share * feat: add first letter uppercase #88 * chore: remove automatic reconnects * chore: add troubleshooting to readme
This commit is contained in:
parent
916c596478
commit
0195cde103
14 changed files with 2073 additions and 558 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -18,5 +18,5 @@ test/
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
.vscode-test/
|
.vscode-test/
|
||||||
dist/
|
dist/
|
||||||
out/
|
typings/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
|
@ -1,4 +1,3 @@
|
||||||
// A launch configuration that compiles the extension and then opens it inside a new window
|
|
||||||
{
|
{
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
@ -10,8 +9,8 @@
|
||||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
||||||
"stopOnEntry": false,
|
"stopOnEntry": false,
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"outFiles": [ "${workspaceRoot}/out/src/**/*.js" ],
|
"outFiles": [ "${workspaceRoot}/dist/**/*.js" ],
|
||||||
"preLaunchTask": "npm"
|
"preLaunchTask": "build"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
41
.vscode/tasks.json
vendored
41
.vscode/tasks.json
vendored
|
@ -1,30 +1,15 @@
|
||||||
// Available variables which can be used inside of strings.
|
|
||||||
// ${workspaceRoot}: the root folder of the team
|
|
||||||
// ${file}: the current opened file
|
|
||||||
// ${fileBasename}: the current opened file's basename
|
|
||||||
// ${fileDirname}: the current opened file's dirname
|
|
||||||
// ${fileExtname}: the current opened file's extension
|
|
||||||
// ${cwd}: the current working directory of the spawned process
|
|
||||||
|
|
||||||
// A task runner that calls a custom npm script that compiles the extension.
|
|
||||||
{
|
{
|
||||||
"version": "0.1.0",
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
// we want to run npm
|
"version": "2.0.0",
|
||||||
"command": "npm",
|
"tasks": [
|
||||||
|
{
|
||||||
// the command is a shell script
|
"label": "build",
|
||||||
"isShellCommand": true,
|
"type": "gulp",
|
||||||
|
"task": "build",
|
||||||
// show the output window only if unrecognized errors occur.
|
"problemMatcher": [
|
||||||
"showOutput": "silent",
|
"$gulp-tsc"
|
||||||
|
]
|
||||||
// we run the custom script "compile" as defined in package.json
|
}
|
||||||
"args": ["run", "compile", "--loglevel", "silent"],
|
]
|
||||||
|
|
||||||
// The tsc compiler is started in watching mode
|
|
||||||
"isBackground": true,
|
|
||||||
|
|
||||||
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
|
|
||||||
"problemMatcher": "$tsc-watch"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,11 @@
|
||||||
* Debug mode detection
|
* Debug mode detection
|
||||||
* Easily manually reconnect to discord
|
* Easily manually reconnect to discord
|
||||||
|
|
||||||
## The rich presence won't show after sleep / connection issues!
|
## Troubleshooting
|
||||||
|
|
||||||
It will only attempt to reconnect 20 times.
|
### Can't connect to Discord? Check those:
|
||||||
After it hit that threshold you will have to manually click the `Reconnect to Discord` button in the bottom left of the window.
|
https://github.com/iCrawl/discord-vscode/issues/77#issuecomment-435622205
|
||||||
|
https://github.com/iCrawl/discord-vscode/issues/85#issuecomment-417895483
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
27
gulpfile.js
Normal file
27
gulpfile.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
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);
|
20
package.json
20
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "discord-vscode",
|
"name": "discord-vscode",
|
||||||
"displayName": "Discord Presence",
|
"displayName": "Discord Presence",
|
||||||
"version": "2.12.1",
|
"version": "3.0.0",
|
||||||
"description": "Update your discord status with the newly added rich presence.",
|
"description": "Update your discord status with the newly added rich presence.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -16,12 +16,10 @@
|
||||||
],
|
],
|
||||||
"publisher": "icrawl",
|
"publisher": "icrawl",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./out/src/extension",
|
"main": "./dist/extension",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "tsc -p ./",
|
"build": "gulp",
|
||||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||||
"test": "node ./node_modules/vscode/bin/test",
|
|
||||||
"lint": "tslint -p tsconfig.json -c tslint.json 'src/**/*.ts'"
|
|
||||||
},
|
},
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"*"
|
"*"
|
||||||
|
@ -54,11 +52,6 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Controls if the Discord Presence should show across all workspaces"
|
"description": "Controls if the Discord Presence should show across all workspaces"
|
||||||
},
|
},
|
||||||
"discord.reconnectThreshold": {
|
|
||||||
"type": "number",
|
|
||||||
"default": 20,
|
|
||||||
"description": "Decides how many reconnect attempts should be made before stopping"
|
|
||||||
},
|
|
||||||
"discord.detailsEditing": {
|
"discord.detailsEditing": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "Editing {filename}",
|
"default": "Editing {filename}",
|
||||||
|
@ -152,6 +145,11 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^10.12.2",
|
"@types/node": "^10.12.2",
|
||||||
|
"fs-nextra": "^0.3.7",
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-sourcemaps": "^2.6.4",
|
||||||
|
"gulp-typescript": "^5.0.0-alpha.3",
|
||||||
|
"merge2": "^1.2.3",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"typescript": "^3.1.6",
|
"typescript": "^3.1.6",
|
||||||
"vscode": "^1.1.21"
|
"vscode": "^1.1.21"
|
||||||
|
|
42
src/client/RPCClient.ts
Normal file
42
src/client/RPCClient.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
const { Client } = require('discord-rpc');
|
||||||
|
import {
|
||||||
|
Disposable,
|
||||||
|
workspace
|
||||||
|
} from 'vscode';
|
||||||
|
import Acivity from '../structures/Activity';
|
||||||
|
import Logger from '../structures/Logger';
|
||||||
|
|
||||||
|
export default class RPCClient implements Disposable {
|
||||||
|
private _rpc: any = new Client({ transport: 'ipc' });
|
||||||
|
|
||||||
|
private _activity = new Acivity();
|
||||||
|
|
||||||
|
private _config = workspace.getConfiguration('discord');
|
||||||
|
|
||||||
|
private _clientId: string;
|
||||||
|
|
||||||
|
public constructor(clientId: string) {
|
||||||
|
this._clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get client() {
|
||||||
|
return this._rpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setActivity(workspaceElapsedTime: boolean = false) {
|
||||||
|
if (!this._rpc) return;
|
||||||
|
const activity = this._activity.generate(workspaceElapsedTime);
|
||||||
|
Logger.log('Sending activity to Discord.');
|
||||||
|
this._rpc.setActivity(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login() {
|
||||||
|
Logger.log('Logging into RPC.');
|
||||||
|
return this._rpc.login({ clientId: this._clientId });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async dispose() {
|
||||||
|
this._activity.dispose();
|
||||||
|
await this._rpc.destroy();
|
||||||
|
}
|
||||||
|
}
|
8
src/constants.ts
Normal file
8
src/constants.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export const LIVE_SHARE_BASE_URL = 'insiders.liveshare.vsengsaas.visualstudio.com';
|
||||||
|
export const VSLS_EXTENSION_ID = 'ms-vsliveshare.vsliveshare';
|
||||||
|
|
||||||
|
export const LIVE_SHARE_COMMANDS = {
|
||||||
|
START: 'liveshare.start',
|
||||||
|
END: 'liveshare.end',
|
||||||
|
JOIN: 'liveshare.join'
|
||||||
|
}
|
426
src/extension.ts
426
src/extension.ts
|
@ -1,401 +1,93 @@
|
||||||
// Import the required functions & object types from various packages.
|
import RPCClient from './client/RPCClient';
|
||||||
import { Client } from 'discord-rpc';
|
import Logger from './structures/Logger';
|
||||||
import { basename, extname, parse, sep } from 'path';
|
|
||||||
import { setInterval, clearInterval } from 'timers';
|
|
||||||
import {
|
import {
|
||||||
commands,
|
commands,
|
||||||
debug,
|
|
||||||
env,
|
|
||||||
ExtensionContext,
|
ExtensionContext,
|
||||||
StatusBarItem,
|
StatusBarItem,
|
||||||
StatusBarAlignment,
|
StatusBarAlignment,
|
||||||
window,
|
window,
|
||||||
workspace,
|
workspace
|
||||||
WorkspaceFolder
|
|
||||||
} from 'vscode';
|
} from 'vscode';
|
||||||
import { statSync } from 'fs';
|
import { setInterval, clearInterval } from 'timers';
|
||||||
const lang = require('./data/languages.json');
|
|
||||||
|
|
||||||
interface FileDetail {
|
|
||||||
size: string | null;
|
|
||||||
totalLines: string | null;
|
|
||||||
currentLine: string | null;
|
|
||||||
currentColumn: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Activity {
|
|
||||||
details: string;
|
|
||||||
state: string;
|
|
||||||
startTimestamp: number | null;
|
|
||||||
largeImageKey: string;
|
|
||||||
largeImageText: string;
|
|
||||||
smallImageKey: string;
|
|
||||||
smallImageText: string;
|
|
||||||
instance: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const knownExtentions: { [x: string]: { image: string } } = lang.knownExtentions;
|
|
||||||
const knownLanguages: string[] = lang.knownLanguages;
|
|
||||||
|
|
||||||
// Define the RPC variable and its type.
|
|
||||||
let rpc: Client;
|
|
||||||
// Define the config variable and its type.
|
|
||||||
let config;
|
|
||||||
// Define the reconnecting var and its type.
|
|
||||||
let reconnecting: boolean;
|
|
||||||
// Define the reconnect counter and its type.
|
|
||||||
let reconnectCounter = 0;
|
|
||||||
// Define the last known file and its type.
|
|
||||||
let lastKnownFile: string;
|
|
||||||
// Define the activity object.
|
|
||||||
let activity: Activity;
|
|
||||||
// Define the activity timer to not spam the API with requests.
|
|
||||||
let activityTimer: NodeJS.Timer;
|
let activityTimer: NodeJS.Timer;
|
||||||
// Define the status bar icon
|
|
||||||
let statusBarIcon: StatusBarItem;
|
let statusBarIcon: StatusBarItem;
|
||||||
|
|
||||||
// `Activate` is fired when the extension is enabled. This SHOULD only fire once.
|
const config = workspace.getConfiguration('discord');
|
||||||
export function activate(context: ExtensionContext) {
|
const rpc = new RPCClient(config.get<string>('clientID')!);
|
||||||
console.log('[Discord Presence]: Activated!');
|
|
||||||
// Get the workspace's configuration for "discord".
|
|
||||||
config = workspace.getConfiguration('discord');
|
|
||||||
|
|
||||||
// Obtain whether or not the extension is activated.
|
export async function activate(context: ExtensionContext) {
|
||||||
if (config.get('enabled')) initRPC(config.get('clientID'));
|
Logger.log('Discord Presence activated!');
|
||||||
|
|
||||||
// Register the `discord.enable` command, and set the `enabled` config option to true.
|
rpc.client.once('ready', () => {
|
||||||
const enabler = commands.registerCommand('discord.enable', async () => {
|
Logger.log('Successfully connected to Discord.');
|
||||||
if (rpc) await destroyRPC();
|
if (!config.get<boolean>('silent')) window.showInformationMessage('Successfully reconnected to Discord RPC');
|
||||||
await config.update('enabled', true);
|
|
||||||
config = workspace.getConfiguration('discord');
|
if (statusBarIcon) statusBarIcon.dispose();
|
||||||
initRPC(config.get('clientID'));
|
if (activityTimer) clearInterval(activityTimer);
|
||||||
window.showInformationMessage('Enabled Discord Rich Presence for this workspace.');
|
rpc.setActivity();
|
||||||
|
|
||||||
|
rpc.client.transport.once('close', async () => {
|
||||||
|
if (!config.get<boolean>('enabled')) return;
|
||||||
|
await rpc.dispose();
|
||||||
|
await rpc.login();
|
||||||
|
if (!statusBarIcon) {
|
||||||
|
statusBarIcon = window.createStatusBarItem(StatusBarAlignment.Left);
|
||||||
|
statusBarIcon.text = '$(plug) Reconnect to Discord';
|
||||||
|
statusBarIcon.command = 'discord.reconnect';
|
||||||
|
statusBarIcon.show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register the `discord.disable` command, and set the `enabled` config option to false.
|
|
||||||
const disabler = commands.registerCommand('discord.disable', async () => {
|
|
||||||
if (!rpc) return window.showWarningMessage('Discord Rich Presence is already disabled in this workspace.');
|
|
||||||
await config.update('enabled', false);
|
|
||||||
config = workspace.getConfiguration('discord');
|
|
||||||
await destroyRPC();
|
|
||||||
window.showInformationMessage('Disabled Discord Rich Presence for this workspace.');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register the `discord.reconnect` command
|
|
||||||
const reconnecter = commands.registerCommand('discord.reconnect', async () => {
|
|
||||||
if (rpc) try { await destroyRPC(); } catch {}
|
|
||||||
initRPC(config.get('clientID'), true);
|
|
||||||
|
|
||||||
if (!config.get('silent')) window.showInformationMessage('Reconnecting to Discord RPC');
|
|
||||||
|
|
||||||
if (statusBarIcon) statusBarIcon.text = '$(pulse) Reconnecting';
|
|
||||||
});
|
|
||||||
|
|
||||||
// Push the new commands into the subscriptions.
|
|
||||||
context.subscriptions.push(enabler, disabler, reconnecter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// `Deactivate` is fired whenever the extension is deactivated.
|
|
||||||
export async function deactivate() {
|
|
||||||
// If there's an RPC Client initalized, destroy it.
|
|
||||||
await destroyRPC();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initalize the RPC systems.
|
|
||||||
function initRPC(clientID: string, loud?: boolean): void {
|
|
||||||
// Update the RPC variable with a new RPC Client.
|
|
||||||
rpc = new Client({ transport: 'ipc' });
|
|
||||||
|
|
||||||
// Once the RPC Client is ready, set the activity.
|
|
||||||
rpc.once('ready', () => {
|
|
||||||
console.log('[Discord Presence]: Successfully connected to Discord');
|
|
||||||
// Announce the reconnection
|
|
||||||
if (loud && !config.get('silent')) window.showInformationMessage('Successfully reconnected to Discord RPC');
|
|
||||||
|
|
||||||
// Remove icon if connected
|
|
||||||
if (statusBarIcon) {
|
|
||||||
statusBarIcon.dispose();
|
|
||||||
statusBarIcon = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop from reconnecing.
|
|
||||||
reconnecting = false;
|
|
||||||
// This is purely for safety measures.
|
|
||||||
if (activityTimer) {
|
|
||||||
// Clear the activity interval.
|
|
||||||
clearInterval(activityTimer);
|
|
||||||
// Null activity variable.
|
|
||||||
activityTimer = null;
|
|
||||||
}
|
|
||||||
// Reset the reconnect counter to 0 on a successful reconnect.
|
|
||||||
reconnectCounter = 0;
|
|
||||||
setActivity();
|
|
||||||
// Set the activity once on ready
|
|
||||||
setTimeout(() => rpc.setActivity(activity).catch(err => console.error(`[Discord Presence]: ${err}`)), 500);
|
|
||||||
// Make sure to listen to the close event and dispose and destroy everything accordingly.
|
|
||||||
rpc.transport.once('close', async () => {
|
|
||||||
if (!config.get('enabled')) return;
|
|
||||||
await destroyRPC();
|
|
||||||
|
|
||||||
// Set the client to begin reconnecting
|
|
||||||
reconnecting = true;
|
|
||||||
initRPC(config.get('clientID'));
|
|
||||||
// Create reconnecting button
|
|
||||||
createButton(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the user's activity to the `activity` variable.
|
|
||||||
activityTimer = setInterval(() => {
|
activityTimer = setInterval(() => {
|
||||||
// Update the config before updating the activity
|
rpc.setActivity(config.get<boolean>('workspaceElapsedTime'));
|
||||||
config = workspace.getConfiguration('discord');
|
}, 10000);
|
||||||
setActivity(Boolean(config.get('workspaceElapsedTime')));
|
})
|
||||||
rpc.setActivity(activity).catch(err => console.error(`[Discord Presence]: ${err}`));
|
|
||||||
}, 15000);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log in to the RPC Client, and check whether or not it errors.
|
if (config.get<boolean>('enabled')) {
|
||||||
rpc.login({ clientId: clientID }).catch(async error => {
|
try {
|
||||||
// Check if the client is reconnecting
|
await rpc.login();
|
||||||
console.error(`[Discord Presence]: ${error}`);
|
} catch (error) {
|
||||||
if (reconnecting) {
|
Logger.log(`Encountered following error after trying to login:\n${error}`);
|
||||||
// Destroy and dispose of everything after the set reconnect attempts
|
|
||||||
if (reconnectCounter >= config.get('reconnectThreshold')) {
|
|
||||||
// Create reconnect button
|
|
||||||
createButton();
|
|
||||||
await destroyRPC();
|
|
||||||
} else {
|
|
||||||
// Increment the counter
|
|
||||||
reconnectCounter++;
|
|
||||||
// Create reconnecting button
|
|
||||||
createButton(true);
|
|
||||||
// Retry connection
|
|
||||||
initRPC(config.get('clientID'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Announce failure
|
|
||||||
if (!config.get('silent')) {
|
if (!config.get('silent')) {
|
||||||
if (error.message.includes('ENOENT')) window.showErrorMessage('No Discord Client detected!');
|
if (error.message.includes('ENOENT')) window.showErrorMessage('No Discord Client detected!');
|
||||||
else window.showErrorMessage(`Couldn't connect to Discord via RPC: ${error.toString()}`);
|
else window.showErrorMessage(`Couldn't connect to Discord via RPC: ${error.toString()}`);
|
||||||
createButton();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create reconnect button
|
|
||||||
function createButton(isReconnecting?: boolean): void {
|
|
||||||
// Check if the button exists already
|
|
||||||
if (!statusBarIcon) {
|
if (!statusBarIcon) {
|
||||||
// Create the icon
|
|
||||||
statusBarIcon = window.createStatusBarItem(StatusBarAlignment.Left);
|
statusBarIcon = window.createStatusBarItem(StatusBarAlignment.Left);
|
||||||
// Check if the client is reconnecting
|
|
||||||
if (isReconnecting) {
|
|
||||||
// Show attempts left
|
|
||||||
const attempts = config.get('reconnectThreshold') - reconnectCounter;
|
|
||||||
statusBarIcon.text = `$(issue-reopened) Reconnecting: ${attempts} attempt${attempts === 1 ? '' : 's'} left`;
|
|
||||||
statusBarIcon.command = '';
|
|
||||||
} else {
|
|
||||||
// Show button to reconnect
|
|
||||||
statusBarIcon.text = '$(plug) Reconnect to Discord';
|
statusBarIcon.text = '$(plug) Reconnect to Discord';
|
||||||
statusBarIcon.command = 'discord.reconnect';
|
statusBarIcon.command = 'discord.reconnect';
|
||||||
}
|
|
||||||
// Show the button
|
|
||||||
statusBarIcon.show();
|
statusBarIcon.show();
|
||||||
} else {
|
}
|
||||||
// Check if the client is reconnecting
|
|
||||||
if (isReconnecting) {
|
|
||||||
// Show attempts left
|
|
||||||
const attempts = config.get('reconnectThreshold') - reconnectCounter;
|
|
||||||
statusBarIcon.text = `$(issue-reopened) Reconnecting: ${attempts} attempt${attempts === 1 ? '' : 's'} left`;
|
|
||||||
statusBarIcon.command = '';
|
|
||||||
} else {
|
|
||||||
// Show button to reconnect
|
|
||||||
statusBarIcon.text = '$(plug) Reconnect to Discord';
|
|
||||||
statusBarIcon.command = 'discord.reconnect';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanly destroy the RPC client (if it isn't already) && add icon to reconnect
|
const enabler = commands.registerCommand('discord.enable', async () => {
|
||||||
async function destroyRPC(): Promise<void> {
|
await rpc.dispose();
|
||||||
// Do not continue if RPC isn't initalized.
|
await config.update('enabled', true);
|
||||||
if (!rpc) return;
|
await rpc.login();
|
||||||
// Stop reconnecting.
|
window.showInformationMessage('Enabled Discord Rich Presence for this workspace.');
|
||||||
reconnecting = false;
|
});
|
||||||
// Clear the activity interval.
|
|
||||||
if (activityTimer) clearInterval(activityTimer);
|
const disabler = commands.registerCommand('discord.disable', async () => {
|
||||||
// Null the activity timer.
|
await config.update('enabled', false);
|
||||||
activityTimer = null;
|
await rpc.dispose();
|
||||||
// If there's an RPC Client initalized, destroy it.
|
window.showInformationMessage('Disabled Discord Rich Presence for this workspace.');
|
||||||
await rpc.destroy();
|
});
|
||||||
// Null the RPC variable.
|
|
||||||
rpc = null;
|
const reconnecter = commands.registerCommand('discord.reconnect', async () => {
|
||||||
// Null the last known file.
|
await rpc.dispose();
|
||||||
lastKnownFile = null;
|
await rpc.login();
|
||||||
|
if (!config.get('silent')) window.showInformationMessage('Reconnecting to Discord RPC...');
|
||||||
|
if (statusBarIcon) statusBarIcon.text = '$(pulse) reconnecting...';
|
||||||
|
});
|
||||||
|
|
||||||
|
context.subscriptions.push(enabler, disabler, reconnecter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function updates the activity (The Client's Rich Presence status).
|
export async function deactivate() {
|
||||||
function setActivity(workspaceElapsedTime: boolean = false): void {
|
clearInterval(activityTimer);
|
||||||
// Do not continue if RPC isn't initalized.
|
await rpc.dispose();
|
||||||
if (!rpc) return;
|
|
||||||
|
|
||||||
if (window.activeTextEditor && window.activeTextEditor.document.fileName === lastKnownFile) {
|
|
||||||
activity = {
|
|
||||||
...activity,
|
|
||||||
details: generateDetails('detailsDebugging', 'detailsEditing', 'detailsIdle', activity.largeImageKey),
|
|
||||||
state: generateDetails('lowerDetailsDebugging', 'lowerDetailsEditing', 'lowerDetailsIdle', activity.largeImageKey),
|
|
||||||
smallImageKey: debug.activeDebugSession
|
|
||||||
? 'debug'
|
|
||||||
: env.appName.includes('Insiders')
|
|
||||||
? 'vscode-insiders'
|
|
||||||
: 'vscode',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastKnownFile = window.activeTextEditor ? window.activeTextEditor.document.fileName : null;
|
|
||||||
|
|
||||||
const fileName: string = window.activeTextEditor ? basename(window.activeTextEditor.document.fileName) : null;
|
|
||||||
const largeImageKey: any = window.activeTextEditor
|
|
||||||
? knownExtentions[Object.keys(knownExtentions).find(key => {
|
|
||||||
if (key.startsWith('.') && fileName.endsWith(key)) return true;
|
|
||||||
const match = key.match(/^\/(.*)\/([mgiy]+)$/);
|
|
||||||
if (!match) return false;
|
|
||||||
const regex = new RegExp(match[1], match[2]);
|
|
||||||
return regex.test(fileName);
|
|
||||||
})] || (knownLanguages.includes(window.activeTextEditor.document.languageId) ? window.activeTextEditor.document.languageId : null)
|
|
||||||
: 'vscode-big';
|
|
||||||
|
|
||||||
// Get the previous activity start timestamp (if available) to preserve workspace elapsed time
|
|
||||||
let previousTimestamp = null;
|
|
||||||
if (activity) previousTimestamp = activity['startTimestamp'];
|
|
||||||
// Create a JSON Object with the user's activity information.
|
|
||||||
activity = {
|
|
||||||
details: generateDetails('detailsDebugging', 'detailsEditing', 'detailsIdle', largeImageKey),
|
|
||||||
state: generateDetails('lowerDetailsDebugging', 'lowerDetailsEditing', 'lowerDetailsIdle', largeImageKey),
|
|
||||||
startTimestamp: window.activeTextEditor && previousTimestamp && workspaceElapsedTime ? previousTimestamp : window.activeTextEditor ? new Date().getTime() : null,
|
|
||||||
largeImageKey: largeImageKey
|
|
||||||
? largeImageKey.image
|
|
||||||
|| largeImageKey
|
|
||||||
: 'txt',
|
|
||||||
largeImageText: window.activeTextEditor
|
|
||||||
? config.get('largeImage').replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : 'txt').replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT')
|
|
||||||
|| window.activeTextEditor.document.languageId.padEnd(2, '\u200b')
|
|
||||||
: config.get('largeImageIdle'),
|
|
||||||
smallImageKey: debug.activeDebugSession
|
|
||||||
? 'debug'
|
|
||||||
: env.appName.includes('Insiders')
|
|
||||||
? 'vscode-insiders'
|
|
||||||
: 'vscode',
|
|
||||||
smallImageText: config.get('smallImage').replace('{appname}', env.appName),
|
|
||||||
instance: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateDetails(debugging, editing, idling, largeImageKey): string {
|
|
||||||
const emptySpaces = '\u200b\u200b';
|
|
||||||
let string: string = config.get(idling).replace('{null}', emptySpaces);
|
|
||||||
|
|
||||||
const fileName: string = window.activeTextEditor ? basename(window.activeTextEditor.document.fileName) : null;
|
|
||||||
let dirName: string = null;
|
|
||||||
if (window.activeTextEditor) {
|
|
||||||
const { dir } = parse(window.activeTextEditor.document.fileName);
|
|
||||||
const split = dir.split(sep);
|
|
||||||
dirName = split[split.length - 1];
|
|
||||||
}
|
|
||||||
const checkState: boolean = window.activeTextEditor
|
|
||||||
? Boolean(workspace.getWorkspaceFolder(window.activeTextEditor.document.uri))
|
|
||||||
: false;
|
|
||||||
|
|
||||||
const workspaceFolder: WorkspaceFolder = checkState ? workspace.getWorkspaceFolder(window.activeTextEditor.document.uri) : null;
|
|
||||||
|
|
||||||
let fullDirName: string = null;
|
|
||||||
if (workspaceFolder) {
|
|
||||||
const { name } = workspaceFolder;
|
|
||||||
const relativePath = workspace.asRelativePath(window.activeTextEditor.document.fileName).split(sep);
|
|
||||||
relativePath.splice(-1, 1);
|
|
||||||
fullDirName = `${name}${sep}${relativePath.join(sep)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.activeTextEditor) {
|
|
||||||
if (debug.activeDebugSession) {
|
|
||||||
let rawString = config.get(debugging);
|
|
||||||
const { totalLines, size, currentLine, currentColumn } = getFileDetails(rawString);
|
|
||||||
rawString = rawString
|
|
||||||
.replace('{null}', emptySpaces)
|
|
||||||
.replace('{filename}', fileName)
|
|
||||||
.replace('{dirname}', dirName)
|
|
||||||
.replace('{fulldirname}', fullDirName)
|
|
||||||
.replace('{workspace}',
|
|
||||||
checkState ?
|
|
||||||
workspaceFolder.name :
|
|
||||||
config.get('lowerDetailsNotFound').replace('{null}', emptySpaces)
|
|
||||||
)
|
|
||||||
.replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : 'txt')
|
|
||||||
.replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT');
|
|
||||||
if (totalLines) rawString = rawString.replace('{totallines}', totalLines);
|
|
||||||
if (size) rawString = rawString.replace('{filesize}', size);
|
|
||||||
if (currentLine) rawString = rawString.replace('{currentline}', currentLine);
|
|
||||||
if (currentColumn) rawString = rawString.replace('{currentcolumn}', currentColumn);
|
|
||||||
string = rawString;
|
|
||||||
} else {
|
|
||||||
let rawString = config.get(editing);
|
|
||||||
const { totalLines, size, currentLine, currentColumn } = getFileDetails(rawString);
|
|
||||||
rawString = rawString
|
|
||||||
.replace('{null}', emptySpaces)
|
|
||||||
.replace('{filename}', fileName)
|
|
||||||
.replace('{dirname}', dirName)
|
|
||||||
.replace('{fulldirname}', fullDirName)
|
|
||||||
.replace('{workspace}',
|
|
||||||
checkState ?
|
|
||||||
workspaceFolder.name :
|
|
||||||
config.get('lowerDetailsNotFound').replace('{null}', emptySpaces)
|
|
||||||
)
|
|
||||||
.replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : 'txt')
|
|
||||||
.replace('{LANG}', largeImageKey ? (largeImageKey.image || largeImageKey).toUpperCase() : 'TXT');
|
|
||||||
if (totalLines) rawString = rawString.replace('{totallines}', totalLines);
|
|
||||||
if (size) rawString = rawString.replace('{filesize}', size);
|
|
||||||
if (currentLine) rawString = rawString.replace('{currentline}', currentLine);
|
|
||||||
if (currentColumn) rawString = rawString.replace('{currentcolumn}', currentColumn);
|
|
||||||
string = rawString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFileDetails(rawString): FileDetail {
|
|
||||||
const obj = {
|
|
||||||
size: null,
|
|
||||||
totalLines: null,
|
|
||||||
currentLine: null,
|
|
||||||
currentColumn: null,
|
|
||||||
};
|
|
||||||
if (!rawString) return obj;
|
|
||||||
if (rawString.includes('{totallines}')) {
|
|
||||||
obj.totalLines = window.activeTextEditor.document.lineCount.toLocaleString();
|
|
||||||
}
|
|
||||||
if (rawString.includes('{currentline}')) {
|
|
||||||
obj.currentLine = (window.activeTextEditor.selection.active.line + 1).toLocaleString();
|
|
||||||
}
|
|
||||||
if (rawString.includes('{currentcolumn}')) {
|
|
||||||
obj.currentColumn = (window.activeTextEditor.selection.active.character + 1).toLocaleString();
|
|
||||||
}
|
|
||||||
if (rawString.includes('{filesize}')) {
|
|
||||||
const sizes = [' bytes', 'kb', 'mb', 'gb', 'tb'];
|
|
||||||
let currentDivision = 0;
|
|
||||||
let { size } = statSync(window.activeTextEditor.document.fileName);
|
|
||||||
const originalSize = size;
|
|
||||||
if (originalSize > 1000) {
|
|
||||||
size = size / 1000;
|
|
||||||
currentDivision++;
|
|
||||||
while (size > 1000) {
|
|
||||||
currentDivision++;
|
|
||||||
size = size / 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj.size = `${originalSize > 1000 ? size.toFixed(2) : size}${sizes[currentDivision]}`;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on('unhandledRejection', console.error);
|
process.on('unhandledRejection', console.error);
|
||||||
|
|
174
src/structures/Activity.ts
Normal file
174
src/structures/Activity.ts
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
import {
|
||||||
|
debug,
|
||||||
|
Disposable,
|
||||||
|
env,
|
||||||
|
window,
|
||||||
|
workspace
|
||||||
|
} from 'vscode';
|
||||||
|
import { basename, sep, parse } from 'path';
|
||||||
|
import { statSync } from 'fs';
|
||||||
|
const lang = require('../data/languages.json');
|
||||||
|
const knownExtentions: { [key: string]: { image: string } } = lang.knownExtentions;
|
||||||
|
const knownLanguages: string[] = lang.knownLanguages;
|
||||||
|
|
||||||
|
interface Activity {
|
||||||
|
details?: string;
|
||||||
|
state?: string;
|
||||||
|
startTimestamp?: number | null;
|
||||||
|
largeImageKey?: string;
|
||||||
|
largeImageText?: string;
|
||||||
|
smallImageKey?: string;
|
||||||
|
smallImageText?: string;
|
||||||
|
instance?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileDetail {
|
||||||
|
size?: string;
|
||||||
|
totalLines?: string;
|
||||||
|
currentLine?: string;
|
||||||
|
currentColumn?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Acivity implements Disposable {
|
||||||
|
private _state: Activity | null = null;
|
||||||
|
|
||||||
|
private _config = workspace.getConfiguration('discord');
|
||||||
|
|
||||||
|
private _lastKnownFile: string = '';
|
||||||
|
|
||||||
|
public get state() {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public generate(workspaceElapsedTime: boolean = false) {
|
||||||
|
let largeImageKey: any = 'vscode-big';
|
||||||
|
if (window.activeTextEditor) {
|
||||||
|
if (window.activeTextEditor.document.fileName === this._lastKnownFile) {
|
||||||
|
return this._state = {
|
||||||
|
...this._state,
|
||||||
|
details: this._generateDetails('detailsDebugging', 'detailsEditing', 'detailsIdle', this._state!.largeImageKey),
|
||||||
|
state: this._generateDetails('lowerDetailsDebugging', 'lowerDetailsEditing', 'lowerDetailsIdle', this._state!.largeImageKey),
|
||||||
|
smallImageKey: debug.activeDebugSession ? 'debug' : env.appName.includes('Insiders') ? 'vscode-insiders' : 'vscode'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._lastKnownFile = window.activeTextEditor.document.fileName;
|
||||||
|
const filename = basename(window.activeTextEditor.document.fileName);
|
||||||
|
largeImageKey = knownExtentions[Object.keys(knownExtentions).find(key => {
|
||||||
|
if (key.startsWith('.') && filename.endsWith(key)) return true;
|
||||||
|
const match = key.match(/^\/(.*)\/([mgiy]+)$/);
|
||||||
|
if (!match) return false;
|
||||||
|
const regex = new RegExp(match[1], match[2]);
|
||||||
|
return regex.test(filename);
|
||||||
|
})!] || (knownLanguages.includes(window.activeTextEditor.document.languageId) ? window.activeTextEditor.document.languageId : null)
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousTimestamp = null;
|
||||||
|
if (this.state && this.state.startTimestamp) previousTimestamp = this.state.startTimestamp;
|
||||||
|
|
||||||
|
this._state = {
|
||||||
|
details: this._generateDetails('detailsDebugging', 'detailsEditing', 'detailsIdle', largeImageKey),
|
||||||
|
state: this._generateDetails('lowerDetailsDebugging', 'lowerDetailsEditing', 'lowerDetailsIdle', largeImageKey),
|
||||||
|
startTimestamp: window.activeTextEditor && previousTimestamp && workspaceElapsedTime ? previousTimestamp : window.activeTextEditor ? new Date().getTime() : null,
|
||||||
|
largeImageKey: largeImageKey ? largeImageKey.image || largeImageKey : 'txt',
|
||||||
|
largeImageText: window.activeTextEditor
|
||||||
|
? this._config.get<string>('largeImage')!.replace('{lang}', largeImageKey ? largeImageKey.image || largeImageKey : '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),
|
||||||
|
instance: false
|
||||||
|
};
|
||||||
|
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateDetails(debugging: string, editing: string, idling: string, largeImageKey: any) {
|
||||||
|
const empty = '\u200b\u200b';
|
||||||
|
let raw = this._config.get<string>(idling);
|
||||||
|
let filename = null;
|
||||||
|
let dirname = null;
|
||||||
|
let checkState = false;
|
||||||
|
let workspaceFolder = null;
|
||||||
|
let fullDirname = null;
|
||||||
|
if (window.activeTextEditor) {
|
||||||
|
filename = basename(window.activeTextEditor.document.fileName);
|
||||||
|
|
||||||
|
const { dir } = parse(window.activeTextEditor.document.fileName);
|
||||||
|
const split = dir.split(sep);
|
||||||
|
dirname = split[split.length - 1];
|
||||||
|
|
||||||
|
checkState = Boolean(workspace.getWorkspaceFolder(window.activeTextEditor.document.uri));
|
||||||
|
|
||||||
|
workspaceFolder = checkState ? workspace.getWorkspaceFolder(window.activeTextEditor.document.uri) : null;
|
||||||
|
|
||||||
|
if (workspaceFolder) {
|
||||||
|
const { name } = workspaceFolder;
|
||||||
|
const relativePath = workspace.asRelativePath(window.activeTextEditor.document.fileName).split(sep);
|
||||||
|
relativePath.splice(-1, 1);
|
||||||
|
fullDirname = `${name}${sep}${relativePath.join(sep)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug.activeDebugSession) {
|
||||||
|
raw = this._config.get<string>(debugging);
|
||||||
|
} else {
|
||||||
|
raw = this._config.get<string>(editing);
|
||||||
|
}
|
||||||
|
const { totalLines, size, currentLine, currentColumn } = this._generateFileDetails(raw);
|
||||||
|
raw = raw!
|
||||||
|
.replace('{null}', empty)
|
||||||
|
.replace('{filename}', filename)
|
||||||
|
.replace('{dirname}', dirname)
|
||||||
|
.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).toUpperCase() : 'TXT');
|
||||||
|
if (totalLines) raw = raw!.replace('{totalline}', totalLines);
|
||||||
|
if (size) raw = raw!.replace('{filsize}', size);
|
||||||
|
if (currentLine) raw = raw!.replace('{currentline}', currentLine);
|
||||||
|
if (currentColumn) raw = raw!.replace('{currentcolumn}', currentColumn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateFileDetails(str?: string) {
|
||||||
|
const fileDetail: FileDetail = {};
|
||||||
|
if (!str) return fileDetail;
|
||||||
|
|
||||||
|
if (window.activeTextEditor) {
|
||||||
|
if (str.includes('{totallines}')) {
|
||||||
|
fileDetail.totalLines = window.activeTextEditor.document.lineCount.toLocaleString();
|
||||||
|
}
|
||||||
|
if (str.includes('{currentline}')) {
|
||||||
|
fileDetail.currentLine = (window.activeTextEditor.selection.active.line + 1).toLocaleString();
|
||||||
|
}
|
||||||
|
if (str.includes('{currentcolumn}')) {
|
||||||
|
fileDetail.currentColumn = (window.activeTextEditor.selection.active.character + 1).toLocaleString();
|
||||||
|
}
|
||||||
|
if (str.includes('{filesize}')) {
|
||||||
|
const sizes = [' bytes', 'kb', 'mb', 'gb', 'tb'];
|
||||||
|
let currentDivision = 0;
|
||||||
|
let { size } = statSync(window.activeTextEditor.document.fileName);
|
||||||
|
const originalSize = size;
|
||||||
|
if (originalSize > 1000) {
|
||||||
|
size /= 1000;
|
||||||
|
currentDivision++;
|
||||||
|
while (size > 1000) {
|
||||||
|
currentDivision++;
|
||||||
|
size /= 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileDetail.size = `${originalSize > 1000 ? size.toFixed(2) : size}${sizes[currentDivision]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this._state = null;
|
||||||
|
this._lastKnownFile = '';
|
||||||
|
}
|
||||||
|
}
|
14
src/structures/Logger.ts
Normal file
14
src/structures/Logger.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { OutputChannel, window } from 'vscode';
|
||||||
|
|
||||||
|
export default class Logger {
|
||||||
|
static output: OutputChannel;
|
||||||
|
|
||||||
|
static setup() {
|
||||||
|
this.output = this.output || window.createOutputChannel('Discord Presence');
|
||||||
|
}
|
||||||
|
|
||||||
|
static log(message: string) {
|
||||||
|
if (!this.output) this.setup();
|
||||||
|
this.output.appendLine(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,21 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"lib": [
|
"lib": [
|
||||||
"esnext",
|
"esnext",
|
||||||
"esnext.asynciterable"
|
"esnext.array",
|
||||||
|
"esnext.asynciterable",
|
||||||
|
"esnext.intl",
|
||||||
|
"esnext.symbol"
|
||||||
],
|
],
|
||||||
"outDir": "out",
|
|
||||||
"rootDir": ".",
|
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"include": [
|
||||||
"node_modules",
|
"./src"
|
||||||
".vscode-test",
|
|
||||||
"out"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
111
tslint.json
111
tslint.json
|
@ -1,111 +0,0 @@
|
||||||
{
|
|
||||||
"rules": {
|
|
||||||
"arrow-return-shorthand": true,
|
|
||||||
"callable-types": true,
|
|
||||||
"class-name": true,
|
|
||||||
"comment-format": [
|
|
||||||
true,
|
|
||||||
"check-space"
|
|
||||||
],
|
|
||||||
"curly": false,
|
|
||||||
"eofline": true,
|
|
||||||
"forin": true,
|
|
||||||
"import-blacklist": [
|
|
||||||
true,
|
|
||||||
"rxjs"
|
|
||||||
],
|
|
||||||
"import-spacing": true,
|
|
||||||
"indent": [
|
|
||||||
true,
|
|
||||||
"tabs"
|
|
||||||
],
|
|
||||||
"interface-over-type-literal": false,
|
|
||||||
"label-position": true,
|
|
||||||
"member-access": false,
|
|
||||||
"member-ordering": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"order": [
|
|
||||||
"static-field",
|
|
||||||
"instance-field",
|
|
||||||
"static-method",
|
|
||||||
"instance-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-arg": true,
|
|
||||||
"no-bitwise": true,
|
|
||||||
"no-console": [
|
|
||||||
true,
|
|
||||||
"debug",
|
|
||||||
"info",
|
|
||||||
"time",
|
|
||||||
"timeEnd",
|
|
||||||
"trace"
|
|
||||||
],
|
|
||||||
"no-construct": true,
|
|
||||||
"no-debugger": true,
|
|
||||||
"no-duplicate-super": true,
|
|
||||||
"no-empty": false,
|
|
||||||
"no-empty-interface": true,
|
|
||||||
"no-eval": true,
|
|
||||||
"no-inferrable-types": [
|
|
||||||
true,
|
|
||||||
"ignore-params"
|
|
||||||
],
|
|
||||||
"no-misused-new": true,
|
|
||||||
"no-non-null-assertion": true,
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-string-literal": false,
|
|
||||||
"no-string-throw": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-trailing-whitespace": true,
|
|
||||||
"no-unnecessary-initializer": true,
|
|
||||||
"no-unused-expression": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-var-keyword": true,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"one-line": [
|
|
||||||
true,
|
|
||||||
"check-open-brace",
|
|
||||||
"check-catch",
|
|
||||||
"check-else",
|
|
||||||
"check-whitespace"
|
|
||||||
],
|
|
||||||
"prefer-const": true,
|
|
||||||
"quotemark": [
|
|
||||||
true,
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"radix": true,
|
|
||||||
"semicolon": [
|
|
||||||
true,
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"triple-equals": [
|
|
||||||
true,
|
|
||||||
"allow-null-check"
|
|
||||||
],
|
|
||||||
"typedef-whitespace": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"call-signature": "nospace",
|
|
||||||
"index-signature": "nospace",
|
|
||||||
"parameter": "nospace",
|
|
||||||
"property-declaration": "nospace",
|
|
||||||
"variable-declaration": "nospace"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typeof-compare": true,
|
|
||||||
"unified-signatures": true,
|
|
||||||
"variable-name": false,
|
|
||||||
"whitespace": [
|
|
||||||
true,
|
|
||||||
"check-branch",
|
|
||||||
"check-decl",
|
|
||||||
"check-operator",
|
|
||||||
"check-separator",
|
|
||||||
"check-type"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue