Migrate to eslint

This commit is contained in:
Vinicius Fortuna 2022-03-10 01:50:59 +00:00
parent 17d1a63f2d
commit 7389ce724f
51 changed files with 2217 additions and 643 deletions

2
.eslintignore Normal file
View file

@ -0,0 +1,2 @@
/build/
node_modules/

65
.eslintrc.json Normal file
View file

@ -0,0 +1,65 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"no-prototype-builtins": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
]
},
"overrides": [
{
"files": [
"check-version-tracker.js",
"rollup-common.js",
"rollup.config.js",
"web-test-runner.config.js"
],
"env": {
"node": true
}
},
{
"files": [
"packages/lit-html/src/test/version-stability_test.js"
],
"env": {
"mocha": true
}
},
{
"files": [
"*_test.ts",
"packages/labs/ssr/custom_typings/node.d.ts",
"packages/labs/ssr/src/test/integration/tests/**",
"packages/labs/ssr/src/lib/util/parse5-utils.ts"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off"
}
}
]
}

2462
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,12 +3,14 @@
"private": true,
"devDependencies": {
"@types/jasmine": "^3.5.10",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"eslint": "^8.10.0",
"generate-license-file": "^1.2.0",
"husky": "^1.3.1",
"jasmine": "^3.5.0",
"prettier": "^2.4.1",
"pretty-quick": "^3.1.1",
"tslint": "^5.9.1",
"typescript": "^4"
},
"engines": {
@ -24,7 +26,7 @@
"format:all": "prettier --write \"**/*.{cjs,html,js,json,md,ts}\"",
"lint": "npm run lint:sh && npm run lint:ts",
"lint:sh": "bash ./scripts/shellcheck.sh",
"lint:ts": "npx tslint 'src/**/*.ts' -e '**/node_modules/**'",
"lint:ts": "npx eslint \"**/*.{js,ts}\"",
"test": "npm run lint && npm run action metrics_server/test && npm run action sentry_webhook/build && npm run action server_manager/test && npm run action shadowbox/test"
},
"workspaces": [

View file

@ -18,7 +18,6 @@ import {
postConnectionMetrics,
} from './connection_metrics';
import {InsertableTable} from './infrastructure/table';
import {HourlyConnectionMetricsReport} from './model';
class FakeConnectionsTable implements InsertableTable<ConnectionRow> {
public rows: ConnectionRow[] | undefined;

View file

@ -14,7 +14,7 @@
import {Table} from '@google-cloud/bigquery';
import {InsertableTable} from './infrastructure/table';
import {HourlyConnectionMetricsReport, HourlyUserConnectionMetricsReport} from './model';
import {HourlyConnectionMetricsReport} from './model';
export interface ConnectionRow {
serverId: string;
@ -36,7 +36,7 @@ export class BigQueryConnectionsTable implements InsertableTable<ConnectionRow>
export function postConnectionMetrics(
table: InsertableTable<ConnectionRow>,
report: HourlyConnectionMetricsReport
) {
): Promise<void> {
return table.insert(getConnectionRowsFromReport(report));
}
@ -59,7 +59,7 @@ function getConnectionRowsFromReport(report: HourlyConnectionMetricsReport): Con
// Returns true iff testObject contains a valid HourlyConnectionMetricsReport.
export function isValidConnectionMetricsReport(
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
testObject: any
): testObject is HourlyConnectionMetricsReport {
if (!testObject) {

View file

@ -47,7 +47,7 @@ export async function postFeatureMetrics(
}
// Returns true iff `obj` contains a valid DailyFeatureMetricsReport.
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isValidFeatureMetricsReport(obj: any): obj is DailyFeatureMetricsReport {
if (!obj) {
return false;

View file

@ -73,7 +73,7 @@ const SALESFORCE_FORM_VALUES_PROD: SalesforceFormValues = {
// Returns whether a Sentry event should be sent to Salesforce by checking that it contains an
// email address.
export function shouldPostEventToSalesforce(event: sentry.SentryEvent) {
export function shouldPostEventToSalesforce(event: sentry.SentryEvent): boolean {
return !!event.user && !!event.user.email;
}
@ -141,7 +141,7 @@ function getSalesforceFormData(
form.push(encodeFormData(formFields.sentryEventUrl, getSentryEventUrl(project, event.event_id)));
form.push(encodeFormData(formFields.description, event.message));
form.push(encodeFormData(formFields.type, isClient ? 'Outline client' : 'Outline manager'));
if (!!event.tags) {
if (event.tags) {
const tags = getTagsMap(event.tags);
form.push(encodeFormData(formFields.category, tags.get('category')));
form.push(encodeFormData(formFields.os, tags.get('os.name')));

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -74,7 +75,7 @@ exports.makeConfig = (options) => {
// @sentry/electron depends on electron code, even though it's never activated
// in the browser. Webpack still tries to build it, but fails with missing APIs.
// The IgnorePlugin prevents the compilation of the electron dependency.
new webpack.IgnorePlugin(/^electron$/),
new webpack.IgnorePlugin({resourceRegExp: /^electron$/, contextRegExp: /@sentry\/electron/}),
new CopyPlugin(
[
{from: 'index.html', to: '.'},

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -248,5 +248,5 @@ export class RestApiSession implements DigitalOceanSession {
// DigitalOcean APIs.
function makeValidDropletName(name: string): string {
// Remove all characters outside of A-Z, a-z, 0-9 and '-'.
return name.replace(/[^A-Za-z0-9\-]/g, '');
return name.replace(/[^A-Za-z0-9-]/g, '');
}

View file

@ -615,7 +615,7 @@ export class RestApiClient {
// 'GET', new URL('https://oauth2.googleapis.com/revoke'), headers, parameters);
// }
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async fetchAuthenticated<T>(method: string, url: URL, headers: Map<string, string>, parameters?: Map<string, string>, data?: any): Promise<T> {
const httpHeaders = new Map(headers);
@ -627,7 +627,7 @@ export class RestApiClient {
return this.fetchUnauthenticated(method, url, httpHeaders, parameters, data);
}
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async fetchUnauthenticated<T>(method: string, url: URL, headers: Map<string, string>, parameters?: Map<string, string>, data?: any): Promise<T> {
const customHeaders = new Headers();
headers.forEach((value, key) => {

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -27,7 +28,7 @@ function generateRtlCss(css) {
}
// This is a Webpack loader that searches for <style> blocks and edits the CSS to support RTL
// in a Polymer element.
module.exports = function loader(content, map, meta) {
module.exports = function loader(content, _map, _meta) {
const callback = this.async();
const styleRe = RegExp(/(<style[^>]*>)(\s*[^<\s](.*\n)*?\s*)(<\/style>)/gm);
try {

View file

@ -143,7 +143,7 @@ export function runOauth(): OauthSession {
</html>`);
});
const rejectWrapper = {reject: (error: Error) => {}};
const rejectWrapper = {reject: (_error: Error) => {}};
const result = new Promise<string>((resolve, reject) => {
rejectWrapper.reject = reject;
// This is the POST endpoint that receives the access token and redirects to either DigitalOcean

View file

@ -82,7 +82,7 @@ export function runOauth(): OauthSession {
// Handle OAuth redirect callback
let isCancelled = false;
const rejectWrapper = {reject: (error: Error) => {}};
const rejectWrapper = {reject: (_error: Error) => {}};
const tokenPromise = new Promise<string>((resolve, reject) => {
rejectWrapper.reject = reject;
app.get(REDIRECT_PATH, async (request: express.Request, response: express.Response) => {

View file

@ -210,7 +210,7 @@ function main() {
});
const UPDATE_DOWNLOADED_EVENT = 'update-downloaded';
autoUpdater.on(UPDATE_DOWNLOADED_EVENT, (ev, info) => {
autoUpdater.on(UPDATE_DOWNLOADED_EVENT, (_ev, _info) => {
if (mainWindow) {
mainWindow.webContents.send(UPDATE_DOWNLOADED_EVENT);
}
@ -228,7 +228,7 @@ function main() {
});
// Restores the mainWindow if minimized and brings it into focus.
ipcMain.on('bring-to-front', (event: IpcEvent) => {
ipcMain.on('bring-to-front', (_event: IpcEvent) => {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -27,7 +27,7 @@ export class InMemoryStorage implements Storage {
return this.store.get(key) || null;
}
key(index: number): string|null {
key(_index: number): string|null {
throw new Error('InMemoryStorage.key not implemented');
}

View file

@ -14,6 +14,7 @@
'use strict';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
const tarballBinary = fs.readFileSync(process.argv[2]);

View file

@ -14,6 +14,7 @@
'use strict';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
const tarballBinary = fs.readFileSync(process.argv[2]);

View file

@ -24,9 +24,9 @@ import {Region} from '../model/digitalocean';
// Define functions from preload.ts.
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(global as any).onUpdateDownloaded = () => {};
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(global as any).bringToFront = () => {};
// Inject app-root element into DOM once before each test.

View file

@ -121,10 +121,10 @@ export class App {
private cloudAccounts: accounts.CloudAccounts) {
appRoot.setAttribute('outline-version', this.version);
appRoot.addEventListener('ConnectDigitalOceanAccountRequested', (event: CustomEvent) => {
appRoot.addEventListener('ConnectDigitalOceanAccountRequested', (_: CustomEvent) => {
this.handleConnectDigitalOceanAccountRequest();
});
appRoot.addEventListener('CreateDigitalOceanServerRequested', (event: CustomEvent) => {
appRoot.addEventListener('CreateDigitalOceanServerRequested', (_: CustomEvent) => {
const digitalOceanAccount = this.cloudAccounts.getDigitalOceanAccount();
if (digitalOceanAccount) {
this.showDigitalOceanCreateServer(digitalOceanAccount);
@ -135,8 +135,8 @@ export class App {
});
appRoot.addEventListener(
'ConnectGcpAccountRequested',
async (event: CustomEvent) => this.handleConnectGcpAccountRequest());
appRoot.addEventListener('CreateGcpServerRequested', async (event: CustomEvent) => {
async (_: CustomEvent) => this.handleConnectGcpAccountRequest());
appRoot.addEventListener('CreateGcpServerRequested', async (_: CustomEvent) => {
this.appRoot.getAndShowGcpCreateServerApp().start(this.gcpAccount);
});
appRoot.addEventListener('GcpServerCreated', (event: CustomEvent) => {
@ -144,11 +144,11 @@ export class App {
this.addServer(this.gcpAccount.getId(), server);
this.showServer(server);
});
appRoot.addEventListener('DigitalOceanSignOutRequested', (event: CustomEvent) => {
appRoot.addEventListener('DigitalOceanSignOutRequested', (_: CustomEvent) => {
this.disconnectDigitalOceanAccount();
this.showIntro();
});
appRoot.addEventListener('GcpSignOutRequested', (event: CustomEvent) => {
appRoot.addEventListener('GcpSignOutRequested', (_: CustomEvent) => {
this.disconnectGcpAccount();
this.showIntro();
});
@ -165,7 +165,7 @@ export class App {
this.forgetServer(event.detail.serverId);
});
appRoot.addEventListener('AddAccessKeyRequested', (event: CustomEvent) => {
appRoot.addEventListener('AddAccessKeyRequested', (_: CustomEvent) => {
this.addAccessKey();
});
@ -184,7 +184,7 @@ export class App {
this.setDefaultDataLimit(displayDataAmountToDataLimit(event.detail.limit));
});
appRoot.addEventListener('RemoveDefaultDataLimitRequested', (event: CustomEvent) => {
appRoot.addEventListener('RemoveDefaultDataLimitRequested', (_: CustomEvent) => {
this.removeDefaultDataLimit();
});
@ -239,11 +239,11 @@ export class App {
});
});
appRoot.addEventListener('EnableMetricsRequested', (event: CustomEvent) => {
appRoot.addEventListener('EnableMetricsRequested', (_: CustomEvent) => {
this.setMetricsEnabled(true);
});
appRoot.addEventListener('DisableMetricsRequested', (event: CustomEvent) => {
appRoot.addEventListener('DisableMetricsRequested', (_: CustomEvent) => {
this.setMetricsEnabled(false);
});
@ -270,7 +270,7 @@ export class App {
this.renameServer(event.detail.newName);
});
appRoot.addEventListener('CancelServerCreationRequested', (event: CustomEvent) => {
appRoot.addEventListener('CancelServerCreationRequested', (_: CustomEvent) => {
this.cancelServerCreation(this.selectedServer);
});
@ -437,7 +437,8 @@ export class App {
// Wait for server config to load, then update the server view and list.
if (isManagedServer(server)) {
try {
for await (const _ of server.monitorInstallProgress()) {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const _ of server.monitorInstallProgress()) {/* empty */}
} catch (error) {
if (error instanceof errors.ServerInstallCanceledError) {
// User clicked "Cancel" on the loading screen.
@ -486,7 +487,7 @@ export class App {
this.disconnectDigitalOceanAccount();
};
const oauthUi = this.appRoot.getDigitalOceanOauthFlow(signOutAction);
while (true) {
for (;;) {
const status = await this.digitalOceanRetry(async () => {
if (cancelled) {
throw CANCELLED_ERROR;
@ -787,7 +788,7 @@ export class App {
// Asynchronously load "My Connection" and other access keys in order to no block showing the
// server.
setTimeout(async () => {
this.showMetricsOptInWhenNeeded(server, view);
this.showMetricsOptInWhenNeeded(server);
try {
const serverAccessKeys = await server.listAccessKeys();
view.accessKeyRows = serverAccessKeys.map(this.convertToUiAccessKey.bind(this));
@ -822,13 +823,13 @@ export class App {
view.serverName = this.makeDisplayName(server);
view.selectedPage = 'progressView';
try {
for await (view.installProgress of server.monitorInstallProgress()) {}
for await (view.installProgress of server.monitorInstallProgress()) {/* empty */}
} catch {
// Ignore any errors; they will be handled by `this.addServer`.
}
}
private showMetricsOptInWhenNeeded(selectedServer: server.Server, serverView: ServerView) {
private showMetricsOptInWhenNeeded(selectedServer: server.Server) {
const showMetricsOptInOnce = () => {
// Sanity check to make sure the running server is still displayed, i.e.
// it hasn't been deleted.
@ -1094,7 +1095,7 @@ export class App {
// Don't let `ManualServerRepository.addServer` throw to avoid redundant error handling if we
// are adding an existing server. Query the repository instead to treat the UI accordingly.
const storedServer = this.manualServerRepository.findServer(serverConfig);
if (!!storedServer) {
if (storedServer) {
this.appRoot.showNotification(this.appRoot.localize('notification-server-exists'), 5000);
this.showServer(storedServer);
return;
@ -1201,7 +1202,7 @@ export class App {
this.appRoot.showError(this.appRoot.localize('error-server-rename'));
const oldName = this.selectedServer.getName();
view.serverName = oldName;
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(view.$.serverSettings as any).serverName = oldName;
}
}

View file

@ -12,25 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).trustCertificate = (fingerprint: string) => {
console.log(`Requested to trust certificate with fingerprint ${fingerprint}`);
};
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).openImage = (basename: string) => {
window.open(`./images/${basename})`);
};
// tslint:disable-next-line:no-any
(window as any).onUpdateDownloaded = (callback: () => void) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).onUpdateDownloaded = (_callback: () => void) => {
console.info(`Requested registration of callbak for update download`);
};
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).runDigitalOceanOauth = () => {
let isCancelled = false;
const rejectWrapper = {reject: (error: Error) => {}};
const rejectWrapper = {reject: (_error: Error) => {}};
const result = new Promise((resolve, reject) => {
rejectWrapper.reject = reject;
window.open('https://cloud.digitalocean.com/account/api/tokens/new', 'noopener,noreferrer');
@ -54,7 +54,7 @@
};
};
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).bringToFront = () => {
console.info(`Requested bringToFront`);
};

View file

@ -89,7 +89,8 @@ export class DigitalOceanAccount implements digitalocean.Account {
const server = this.createDigitalOceanServer(this.digitalOcean, response.droplet);
server.onceDropletActive.then(async () => {
console.timeEnd('activeServer');
for await (const _ of server.monitorInstallProgress()) {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const _ of server.monitorInstallProgress()) {/* do nothing */}
console.timeEnd('servingServer');
}).catch(e => console.log('Couldn\'t time installation', e));
return server;
@ -122,7 +123,7 @@ export class DigitalOceanAccount implements digitalocean.Account {
function sanitizeDigitalOceanToken(input: string): string {
const sanitizedInput = input.trim();
const pattern = /^[A-Za-z0-9_\/-]+$/;
const pattern = /^[A-Za-z0-9_/-]+$/;
if (!pattern.test(sanitizedInput)) {
throw new Error('Invalid DigitalOcean Token');
}

View file

@ -44,7 +44,7 @@ async function makeLocalize(language: string) {
window.alert(`Could not load messages for language "${language}"`);
}
return (msgId: string, ...args: string[]): string => {
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const params = {} as {[key: string]: any};
for (let i = 0; i < args.length; i += 2) {
params[args[i]] = args[i + 1];
@ -134,7 +134,7 @@ export class TestApp extends LitElement {
this.language = newLanguage;
}
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private select(querySelector: string): any {
return this.shadowRoot.querySelector(querySelector);
}

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -31,14 +31,14 @@ describe('getShortName', () => {
});
it('returns the ID when geoId is null', () => {
expect(getShortName({id: 'fake-id', location: null}, msgId => {
expect(getShortName({id: 'fake-id', location: null}, _msgId => {
fail();
return null;
})).toEqual('fake-id');
});
it('returns empty string when the location is null', () => {
expect(getShortName(null, msgId => {
expect(getShortName(null, _msgId => {
fail();
return null;
})).toEqual('');
@ -46,7 +46,7 @@ describe('getShortName', () => {
});
describe('localizeCountry', () => {
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!(Intl as any).DisplayNames) {
console.log('country localization requires modern Intl features');
return;

View file

@ -38,7 +38,7 @@ export function localizeCountry(geoLocation: GeoLocation, language: string): str
return '';
}
// TODO: Remove typecast after https://github.com/microsoft/TypeScript/pull/44022
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const displayName = new (Intl as any).DisplayNames([language], {type: 'region'});
return displayName.of(geoLocation.countryCode);
}

View file

@ -52,7 +52,7 @@ export class ManualServerRepository implements server.ManualServerRepository {
addServer(config: server.ManualServerConfig): Promise<server.ManualServer> {
const existingServer = this.findServer(config);
if (!!existingServer) {
if (existingServer) {
console.debug('server already added');
return Promise.resolve(existingServer);
}

View file

@ -185,7 +185,7 @@ export class ShadowboxServer implements server.Server {
}
isHealthy(timeoutMs = 30000): Promise<boolean> {
return new Promise<boolean>((fulfill, reject) => {
return new Promise<boolean>((fulfill, _reject) => {
// Query the API and expect a successful response to validate that the
// service is up and running.
this.getServerConfig().then(
@ -193,7 +193,7 @@ export class ShadowboxServer implements server.Server {
this.serverConfig = serverConfig;
fulfill(true);
},
(e) => {
(_e) => {
fulfill(false);
});
// Return not healthy if API doesn't complete within timeoutMs.
@ -287,7 +287,7 @@ export class ShadowboxServer implements server.Server {
}
return response.text();
},
(error) => {
(_error) => {
throw new errors.ServerApiError(
`API request to ${path} failed due to network error`);
})

View file

@ -70,22 +70,22 @@ export class FakeGcpAccount implements gcp.Account {
getRefreshToken(): string {
return this.refreshToken;
}
createServer(projectId: string, name: string, zone: gcp.Zone): Promise<server.ManagedServer> {
createServer(_projectId: string, _name: string, _zone: gcp.Zone): Promise<server.ManagedServer> {
return undefined;
}
async listLocations(projectId: string): Promise<Readonly<gcp.ZoneOption[]>> {
async listLocations(_projectId: string): Promise<Readonly<gcp.ZoneOption[]>> {
return this.locations;
}
async listServers(projectId: string): Promise<server.ManagedServer[]> {
async listServers(_projectId: string): Promise<server.ManagedServer[]> {
return [];
}
async createProject(id: string, billingAccountId: string): Promise<gcp.Project> {
async createProject(_id: string, _billingAccountId: string): Promise<gcp.Project> {
return {
id: 'project-id',
name: 'project-name',
};
}
async isProjectHealthy(projectId: string): Promise<boolean> {
async isProjectHealthy(_projectId: string): Promise<boolean> {
return true;
}
async listOpenBillingAccounts(): Promise<gcp.BillingAccount[]> {
@ -142,13 +142,13 @@ export class FakeServer implements server.Server {
addAccessKey() {
return Promise.reject(new Error('FakeServer.addAccessKey not implemented'));
}
renameAccessKey(accessKeyId: server.AccessKeyId, name: string) {
renameAccessKey(_accessKeyId: server.AccessKeyId, _name: string) {
return Promise.reject(new Error('FakeServer.renameAccessKey not implemented'));
}
removeAccessKey(accessKeyId: server.AccessKeyId) {
removeAccessKey(_accessKeyId: server.AccessKeyId) {
return Promise.reject(new Error('FakeServer.removeAccessKey not implemented'));
}
setHostnameForAccessKeys(hostname: string) {
setHostnameForAccessKeys(_hostname: string) {
return Promise.reject(new Error('FakeServer.setHostname not implemented'));
}
getHostnameForAccessKeys() {
@ -163,13 +163,13 @@ export class FakeServer implements server.Server {
setPortForNewAccessKeys(): Promise<void> {
return Promise.reject(new Error('FakeServer.setPortForNewAccessKeys not implemented'));
}
setAccessKeyDataLimit(accessKeyId: string, limit: server.DataLimit): Promise<void> {
setAccessKeyDataLimit(_accessKeyId: string, _limit: server.DataLimit): Promise<void> {
return Promise.reject(new Error('FakeServer.setAccessKeyDataLimit not implemented'));
}
removeAccessKeyDataLimit(accessKeyId: string): Promise<void> {
removeAccessKeyDataLimit(_accessKeyId: string): Promise<void> {
return Promise.reject(new Error('FakeServer.removeAccessKeyDataLimit not implemented'));
}
setDefaultDataLimit(limit: server.DataLimit): Promise<void> {
setDefaultDataLimit(_limit: server.DataLimit): Promise<void> {
return Promise.reject(new Error('FakeServer.setDefaultDataLimit not implemented'));
}
removeDefaultDataLimit(): Promise<void> {

View file

@ -640,12 +640,11 @@ export class AppRoot extends polymerElementWithLocalize {
// resolve or reject the Promise. Note that they need to clean up whichever event handler
// didn't fire so we don't leak it, which could cause future language changes to not work
// properly by triggering old event listeners.
let successHandler: () => void, failureHandler: () => void;
successHandler = () => {
const successHandler = () => {
this.removeEventListener('app-localize-resources-error', failureHandler);
resolve();
};
failureHandler = () => {
const failureHandler = () => {
this.removeEventListener('app-localize-resources-loaded', successHandler);
reject(new Error(`Failed to load resources for language ${language}`));
};

View file

@ -146,8 +146,7 @@ export class GcpCreateServerApp extends LitElement {
return this.renderProjectSetup();
case 'regionPicker':
return this.renderRegionPicker();
default: {
}
default:
}
}

View file

@ -306,7 +306,7 @@ Polymer({
}
},
_handleNameInputBlur(event: FocusEvent) {
_handleNameInputBlur(_event: FocusEvent) {
const newName = this.serverName;
if (!newName) {
this.serverName = this.initialName;

View file

@ -940,7 +940,7 @@ export class ServerView extends DirMixin(PolymerElement) {
return `${utilizationPercentage}%`;
}
_accessKeysAddedOrRemoved(changeRecord: unknown) {
_accessKeysAddedOrRemoved(_changeRecord: unknown) {
// Check for myConnection and regular access keys.
let hasNonAdminAccessKeys = false;
for (const ui in this.accessKeyRows) {

View file

@ -25,8 +25,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element';
import type {PolymerElementProperties} from '@polymer/polymer/interfaces';
import type {PaperDialogElement} from '@polymer/paper-dialog/paper-dialog';
class OutlineSurveyDialog extends DirMixin
(PolymerElement) {
class OutlineSurveyDialog extends DirMixin(PolymerElement) {
static get template() {
return html`
<style include="cloud-install-styles"></style>

View file

@ -15,15 +15,15 @@
export interface Clock {
// Returns the current time in milliseconds from the epoch.
now(): number;
setInterval(callback, intervalMs): void;
setInterval(callback: () => void, intervalMs: number): void;
}
export class RealClock implements Clock {
now() {
now(): number {
return Date.now();
}
setInterval(callback, intervalMs) {
setInterval(callback, intervalMs: number): void {
setInterval(callback, intervalMs);
}
}
@ -32,15 +32,13 @@ export class RealClock implements Clock {
// Useful for tests.
export class ManualClock implements Clock {
public nowMs = 0;
private callbacks = [] as Function[];
private callbacks = [] as (() => void)[];
constructor() {}
now() {
now(): number {
return this.nowMs;
}
setInterval(callback, intervalMs) {
setInterval(callback, _intervalMs): void {
this.callbacks.push(callback);
}

View file

@ -76,7 +76,7 @@ describe('isPortUsed', () => {
function listen(): Promise<net.Server> {
const server = net.createServer();
return new Promise((resolve, reject) => {
return new Promise((resolve, _reject) => {
server.listen({host: 'localhost', port: 0, exclusive: true}, () => {
resolve(server);
});

View file

@ -41,7 +41,7 @@ export class PortProvider {
async reserveNewPort(): Promise<number> {
// TODO: consider using a set of available ports, so we don't randomly
// try the same port multiple times.
while (true) {
for (;;) {
const port = getRandomPortOver1023();
if (this.reservedPorts.has(port)) {
continue;

View file

@ -28,7 +28,7 @@ function getCallsite(): Callsite {
};
const error = new Error();
Error.captureStackTrace(error, getCallsite);
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stack = error.stack as any as Callsite[];
Error.prepareStackTrace = originalPrepareStackTrace;
return stack[1];

View file

@ -125,12 +125,12 @@ async function waitForPrometheusReady(prometheusEndpoint: string) {
}
function isHttpEndpointHealthy(endpoint: string): Promise<boolean> {
return new Promise((resolve, reject) => {
return new Promise((resolve, _) => {
http
.get(endpoint, (response) => {
resolve(response.statusCode >= 200 && response.statusCode < 300);
})
.on('error', (e) => {
.on('error', () => {
// Prometheus is not ready yet.
resolve(false);
});

View file

@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {PrometheusClient, QueryResultData} from '../infrastructure/prometheus_scraper';
import {DataUsageByUser} from '../model/metrics';
import {PrometheusManagerMetrics} from './manager_metrics';
import {FakePrometheusClient} from './mocks/mocks';

View file

@ -43,6 +43,8 @@ const EXPECTED_ACCESS_KEY_PROPERTIES = [
'dataLimit',
].sort();
const SEND_NOTHING = (_httpCode, _data) => {/* do nothing */};
describe('ShadowsocksManagerService', () => {
// After processing the response callback, we should set
// responseProcessed=true. This is so we can detect that first the response
@ -149,7 +151,7 @@ describe('ShadowsocksManagerService', () => {
'2606:2800:220:1:248:1893:25c8:1946',
];
for (const hostname of goodHostnames) {
service.setHostnameForAccessKeys({params: {hostname}}, res, () => {});
service.setHostnameForAccessKeys({params: {hostname}}, res, () => {/* do nothing */});
}
responseProcessed = true;
@ -162,7 +164,7 @@ describe('ShadowsocksManagerService', () => {
.accessKeys(getAccessKeyRepository())
.build();
const res = {send: (httpCode) => {}};
const res = {send: SEND_NOTHING};
const next = (error) => {
expect(error.statusCode).toEqual(400);
};
@ -205,7 +207,7 @@ describe('ShadowsocksManagerService', () => {
.serverConfig(serverConfig)
.accessKeys(getAccessKeyRepository())
.build();
const res = {send: (httpCode) => {}};
const res = {send: SEND_NOTHING};
const next = (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true;
@ -220,13 +222,13 @@ describe('ShadowsocksManagerService', () => {
.serverConfig(serverConfig)
.accessKeys(getAccessKeyRepository())
.build();
const res = {send: (httpCode) => {}};
const res = {send: SEND_NOTHING};
const next = (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true;
done();
};
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const badHostname = {params: {hostname: 123}} as any as {params: {hostname: string}};
service.setHostnameForAccessKeys(badHostname, res, next);
});
@ -296,7 +298,7 @@ describe('ShadowsocksManagerService', () => {
spyOn(repo, 'createNewAccessKey').and.throwError('cannot write to disk');
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.createNewAccessKey({params: {}}, res, (error) => {
expect(error.statusCode).toEqual(500);
responseProcessed = true; // required for afterEach to pass.
@ -319,7 +321,7 @@ describe('ShadowsocksManagerService', () => {
expect(httpCode).toEqual(204);
},
};
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, res, () => {});
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, res, () => {/* do nothing */});
const newKey = await repo.createNewAccessKey();
expect(newKey.proxyParams.portNumber).toEqual(NEW_PORT);
expect(oldKey.proxyParams.portNumber).not.toEqual(NEW_PORT);
@ -410,8 +412,8 @@ describe('ShadowsocksManagerService', () => {
.accessKeys(repo)
.build();
await service.createNewAccessKey({params: {}}, {send: () => {}}, () => {});
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, {send: () => {}}, () => {});
await service.createNewAccessKey({params: {}}, {send: () => {/* do nothing */}}, () => {/* do nothing */});
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, {send: () => {/* do nothing */}}, () => {/* do nothing */});
const res = {
send: (httpCode) => {
expect(httpCode).toEqual(204);
@ -421,7 +423,7 @@ describe('ShadowsocksManagerService', () => {
const firstKeyConnection = new net.Server();
firstKeyConnection.listen(OLD_PORT, async () => {
await service.setPortForNewAccessKeys({params: {port: OLD_PORT}}, res, () => {});
await service.setPortForNewAccessKeys({params: {port: OLD_PORT}}, res, () => {/* do nothing */});
firstKeyConnection.close();
done();
});
@ -451,7 +453,7 @@ describe('ShadowsocksManagerService', () => {
const nonNumericPort = {params: {port: 'abc'}};
await service.setPortForNewAccessKeys(
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
nonNumericPort as any as {params: {port: number}},
res,
next
@ -469,7 +471,7 @@ describe('ShadowsocksManagerService', () => {
const key1 = await repo.createNewAccessKey();
const key2 = await repo.createNewAccessKey();
const res = {
send: (httpCode, data) => {
send: (httpCode, _data) => {
expect(httpCode).toEqual(204);
// expect that the only remaining key is the 2nd key we created.
const keys = repo.listAccessKeys();
@ -486,7 +488,7 @@ describe('ShadowsocksManagerService', () => {
spyOn(repo, 'removeAccessKey').and.throwError('cannot write to disk');
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const key = await createNewAccessKeyWithName(repo, 'keyName1');
const res = {send: (httpCode, data) => {}};
const res = {send: (_httpCode, _data) => {/* do nothing */}};
service.removeAccessKey({params: {id: key.id}}, res, (error) => {
expect(error.statusCode).toEqual(500);
responseProcessed = true; // required for afterEach to pass.
@ -505,7 +507,7 @@ describe('ShadowsocksManagerService', () => {
const key = await createNewAccessKeyWithName(repo, OLD_NAME);
expect(key.name === OLD_NAME);
const res = {
send: (httpCode, data) => {
send: (httpCode, _) => {
expect(httpCode).toEqual(204);
expect(key.name === NEW_NAME);
responseProcessed = true; // required for afterEach to pass.
@ -517,8 +519,8 @@ describe('ShadowsocksManagerService', () => {
const repo = getAccessKeyRepository();
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const key = await repo.createNewAccessKey();
const res = {send: (httpCode, data) => {}};
await repo.createNewAccessKey();
const res = {send: SEND_NOTHING};
service.renameAccessKey({params: {id: 123}}, res, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true; // required for afterEach to pass.
@ -531,7 +533,7 @@ describe('ShadowsocksManagerService', () => {
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const key = await createNewAccessKeyWithName(repo, 'oldName');
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.renameAccessKey({params: {id: key.id, name: 'newName'}}, res, (error) => {
expect(error.statusCode).toEqual(500);
responseProcessed = true; // required for afterEach to pass.
@ -554,7 +556,7 @@ describe('ShadowsocksManagerService', () => {
done();
},
};
service.setAccessKeyDataLimit({params: {id: key.id, limit}}, res, () => {});
service.setAccessKeyDataLimit({params: {id: key.id, limit}}, res, () => {/* do nothing */});
});
it('rejects negative numbers', async (done) => {
@ -562,7 +564,7 @@ describe('ShadowsocksManagerService', () => {
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const keyId = (await repo.createNewAccessKey()).id;
const limit = {bytes: -1};
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true;
done();
@ -574,7 +576,7 @@ describe('ShadowsocksManagerService', () => {
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const keyId = (await repo.createNewAccessKey()).id;
const limit = {bytes: '1'};
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true;
done();
@ -586,7 +588,7 @@ describe('ShadowsocksManagerService', () => {
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const keyId = (await repo.createNewAccessKey()).id;
const limit = {} as DataLimit;
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true;
done();
@ -600,7 +602,7 @@ describe('ShadowsocksManagerService', () => {
const limit: DataLimit = {bytes: 1000};
service.setAccessKeyDataLimit(
{params: {id: 'not an id', limit}},
{send: () => {}},
{send: () => {/* do nothing */}},
(error) => {
expect(error.statusCode).toEqual(404);
responseProcessed = true;
@ -625,13 +627,13 @@ describe('ShadowsocksManagerService', () => {
done();
},
};
service.removeAccessKeyDataLimit({params: {id: key.id}}, res, () => {});
service.removeAccessKeyDataLimit({params: {id: key.id}}, res, () => {/* do nothing */});
});
it('returns 404 for a nonexistent key', async (done) => {
const repo = getAccessKeyRepository();
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
await repo.createNewAccessKey();
service.removeAccessKeyDataLimit({params: {id: 'not an id'}}, {send: () => {}}, (error) => {
service.removeAccessKeyDataLimit({params: {id: 'not an id'}}, {send: () => {/* do nothing */}}, (error) => {
expect(error.statusCode).toEqual(404);
responseProcessed = true;
done();
@ -650,7 +652,7 @@ describe('ShadowsocksManagerService', () => {
.build();
const limit = {bytes: 10000};
const res = {
send: (httpCode, data) => {
send: (httpCode, _data) => {
expect(httpCode).toEqual(204);
expect(serverConfig.data().accessKeyDataLimit).toEqual(limit);
expect(repo.setDefaultDataLimit).toHaveBeenCalledWith(limit);
@ -672,9 +674,9 @@ describe('ShadowsocksManagerService', () => {
it('returns 400 when limit is missing values', async (done) => {
const repo = getAccessKeyRepository();
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const accessKey = await repo.createNewAccessKey();
await repo.createNewAccessKey();
const limit = {} as DataLimit;
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true; // required for afterEach to pass.
@ -684,9 +686,9 @@ describe('ShadowsocksManagerService', () => {
it('returns 400 when limit has negative values', async (done) => {
const repo = getAccessKeyRepository();
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const accessKey = await repo.createNewAccessKey();
await repo.createNewAccessKey();
const limit = {bytes: -1};
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
expect(error.statusCode).toEqual(400);
responseProcessed = true; // required for afterEach to pass.
@ -699,7 +701,7 @@ describe('ShadowsocksManagerService', () => {
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
await repo.createNewAccessKey();
const limit = {bytes: 10000};
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
expect(error.statusCode).toEqual(500);
responseProcessed = true; // required for afterEach to pass.
@ -720,7 +722,7 @@ describe('ShadowsocksManagerService', () => {
.build();
await repo.setDefaultDataLimit(limit);
const res = {
send: (httpCode, data) => {
send: (httpCode, _data) => {
expect(httpCode).toEqual(204);
expect(serverConfig.data().accessKeyDataLimit).toBeUndefined();
expect(repo.removeDefaultDataLimit).toHaveBeenCalled();
@ -734,7 +736,7 @@ describe('ShadowsocksManagerService', () => {
spyOn(repo, 'removeDefaultDataLimit').and.throwError('cannot write to disk');
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
const accessKey = await repo.createNewAccessKey();
const res = {send: (httpCode, data) => {}};
const res = {send: SEND_NOTHING};
service.removeDefaultDataLimit({params: {id: accessKey.id}}, res, (error) => {
expect(error.statusCode).toEqual(500);
responseProcessed = true; // required for afterEach to pass.

View file

@ -259,7 +259,7 @@ export class ShadowsocksManagerService {
// Hostnames can have any number of segments of alphanumeric characters and hyphens, separated
// by periods. No segment may start or end with a hyphen.
const hostnameRegex =
/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)*[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?$/;
/^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)*[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$/;
if (!hostnameRegex.test(hostname) && !ipRegex({includeBoundaries: true}).test(hostname)) {
return next(
new restifyErrors.InvalidArgumentError(

View file

@ -13,7 +13,6 @@
// limitations under the License.
import {PrometheusClient, QueryResultData} from '../../infrastructure/prometheus_scraper';
import {DataUsageByUser} from '../../model/metrics';
import {ShadowsocksAccessKey, ShadowsocksServer} from '../../model/shadowsocks_server';
import {TextFile} from '../../model/text_file';
@ -25,7 +24,7 @@ export class InMemoryFile implements TextFile {
return this.savedText;
} else {
const err = new Error('no such file or directory');
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(err as any).code = 'ENOENT';
throw err;
}
@ -54,7 +53,7 @@ export class FakePrometheusClient extends PrometheusClient {
super('');
}
async query(query: string): Promise<QueryResultData> {
async query(_query: string): Promise<QueryResultData> {
const queryResultData = {result: []} as QueryResultData;
for (const accessKeyId of Object.keys(this.bytesTransferredById)) {
const bytesTransferred = this.bytesTransferredById[accessKeyId] || 0;

View file

@ -17,7 +17,7 @@ import * as net from 'net';
import {ManualClock} from '../infrastructure/clock';
import {PortProvider} from '../infrastructure/get_port';
import {InMemoryConfig} from '../infrastructure/json_config';
import {AccessKey, AccessKeyId, AccessKeyRepository, DataLimit} from '../model/access_key';
import {AccessKeyId, AccessKeyRepository, DataLimit} from '../model/access_key';
import * as errors from '../model/errors';
import {FakePrometheusClient, FakeShadowsocksServer} from './mocks/mocks';
@ -57,7 +57,7 @@ describe('ServerAccessKeyRepository', () => {
it('removeAccessKey throws for missing keys', (done) => {
const repo = new RepoBuilder().build();
repo.createNewAccessKey().then((accessKey) => {
repo.createNewAccessKey().then((_accessKey) => {
expect(countAccessKeys(repo)).toEqual(1);
expect(repo.removeAccessKey.bind(repo, 'badId')).toThrowError(errors.AccessKeyNotFound);
expect(countAccessKeys(repo)).toEqual(1);
@ -79,7 +79,7 @@ describe('ServerAccessKeyRepository', () => {
it('renameAccessKey throws for missing keys', (done) => {
const repo = new RepoBuilder().build();
repo.createNewAccessKey().then((accessKey) => {
repo.createNewAccessKey().then((_accessKey) => {
const NEW_NAME = 'newName';
expect(repo.renameAccessKey.bind(repo, 'badId', NEW_NAME)).toThrowError(
errors.AccessKeyNotFound
@ -515,11 +515,11 @@ describe('ServerAccessKeyRepository', () => {
.defaultDataLimit({bytes: 200})
.build();
const accessKey1 = await repo.createNewAccessKey();
await repo.createNewAccessKey();
const accessKey2 = await repo.createNewAccessKey();
await repo.enforceAccessKeyDataLimits();
const accessKeys = await repo.listAccessKeys();
await repo.listAccessKeys();
let serverAccessKeys = server.getAccessKeys();
expect(serverAccessKeys.length).toEqual(1);
expect(serverAccessKeys[0].id).toEqual(accessKey2.id);
@ -641,7 +641,7 @@ async function expectNoAsyncThrow(fn: Function) {
// Convenience function to expect that an asynchronous function throws an error. Fails if the thrown
// error does not match `errorType`, when defined.
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function expectAsyncThrow(fn: Function, errorType?: new (...args: any[]) => Error) {
try {
await fn();

View file

@ -185,7 +185,7 @@ describe('OutlineSharedMetricsPublisher', () => {
serverConfig,
keyConfig,
new ManualUsageMetrics(),
(id: AccessKeyId) => '',
(_id: AccessKeyId) => '',
metricsCollector
);
@ -229,12 +229,12 @@ describe('OutlineSharedMetricsPublisher', () => {
const metricsCollector = new FakeMetricsCollector();
spyOn(metricsCollector, 'collectServerUsageMetrics').and.callThrough();
spyOn(metricsCollector, 'collectFeatureMetrics').and.callThrough();
const publisher = new OutlineSharedMetricsPublisher(
new OutlineSharedMetricsPublisher(
clock,
serverConfig,
new InMemoryConfig<AccessKeyConfigJson>({}),
new ManualUsageMetrics(),
(id: AccessKeyId) => '',
(_id: AccessKeyId) => '',
metricsCollector
);

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -1,48 +0,0 @@
// Copied from google.tslint.json, with internal rules removed
{
"rules": {
"array-type": [true, "array-simple"],
"arrow-return-shorthand": true,
"ban-types": [
true,
["Object", "Use {} instead."],
["String", "Use 'string' instead."],
["Number", "Use 'number' instead."],
["Boolean", "Use 'boolean' instead."]
],
"class-name": true,
"forin": true,
"interface-name": [true, "never-prefix"],
"jsdoc-format": true,
"label-position": true,
"new-parens": true,
"no-angle-bracket-type-assertion": true,
"no-any": true,
"no-construct": true,
"no-debugger": true,
"no-default-export": true,
"no-inferrable-types": true,
"no-namespace": [true, "allow-declarations"],
"no-reference": true,
"no-require-imports": true,
"no-unused-expression": true,
"no-use-before-declare": false,
"no-var-keyword": true,
"object-literal-shorthand": true,
"only-arrow-functions": [true, "allow-declarations", "allow-named-functions"],
"prefer-const": true,
"radix": true,
"semicolon": [true, "always", "ignore-bound-class-methods"],
"no-string-throw": true,
"switch-default": true,
"triple-equals": [true, "allow-null-check"],
"use-isnan": true,
"variable-name": [
true,
"check-format",
"ban-keywords",
"allow-leading-underscore",
"allow-trailing-underscore"
]
}
}