From 526b0ad33e06cb7c08de8dc596db90a75f10415c Mon Sep 17 00:00:00 2001 From: Dmitry S Date: Mon, 26 Apr 2021 17:54:09 -0400 Subject: [PATCH] (core) Configure more comprehensive eslint rules for Typescript Summary: - Update rules to be more like we've had with tslint - Switch tsserver plugin to eslint (tsserver makes for a much faster way to lint in editors) - Apply suggested auto-fixes - Fix all lint errors and warnings in core/, app/, test/ Test Plan: Some behavior may change subtly (e.g. added missing awaits), relying on existing tests to catch problems. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2785 --- app/client/components/AceEditor.js | 4 ++-- app/client/components/ActionLog.ts | 2 +- app/client/components/ColumnTransform.ts | 8 ++++---- app/client/components/GridView.js | 4 ++-- app/client/components/Importer.ts | 4 ++-- app/client/components/SearchBar.ts | 6 +++--- app/client/components/Selector.js | 2 +- app/client/components/TypeTransform.ts | 2 +- app/client/components/ViewConfigTab.js | 2 +- app/client/declarations.d.ts | 10 +++------- app/client/lib/autocomplete.ts | 2 +- app/client/models/BillingModel.ts | 2 +- app/client/models/DataTableModelWithDiff.ts | 16 ++++++++-------- app/client/models/DocData.ts | 4 ++-- app/client/models/DocPageModel.ts | 14 +++++++++----- app/client/models/QuerySet.ts | 2 +- app/client/models/SearchModel.ts | 2 +- app/client/models/TableData.ts | 2 +- app/client/ui/BillingForm.ts | 4 ++-- app/client/ui/VisibleFieldsConfig.ts | 2 +- app/client/ui2018/cssVars.ts | 4 ++-- app/client/widgets/DiffBox.ts | 2 +- app/client/widgets/FieldBuilder.ts | 4 ++-- app/common/ACLRuleCollection.ts | 2 +- app/common/DocActions.ts | 3 ++- app/common/DocListAPI.ts | 2 +- app/common/PluginInstance.ts | 2 +- app/common/UserAPI.ts | 4 ++-- app/common/tbind.ts | 4 +++- app/common/tpromisified.ts | 3 ++- app/gen-server/lib/DocApiForwarder.ts | 4 +++- app/gen-server/lib/DocWorkerMap.ts | 2 +- app/gen-server/lib/HomeDBManager.ts | 15 +++++++++------ app/gen-server/lib/Housekeeper.ts | 4 +++- app/plugin/grist-plugin-api.ts | 2 +- app/server/lib/ActiveDoc.ts | 8 ++++---- app/server/lib/AppEndpoint.ts | 2 +- app/server/lib/DocApi.ts | 5 ++--- app/server/lib/DocManager.ts | 5 +++-- app/server/lib/DocPluginManager.ts | 7 ++++++- app/server/lib/DocStorage.ts | 10 ++++++---- app/server/lib/DocStorageManager.ts | 2 +- app/server/lib/ExternalStorage.ts | 2 +- app/server/lib/FlexServer.ts | 2 +- app/server/lib/GranularAccess.ts | 15 ++++++++++----- app/server/lib/HostedStorageManager.ts | 2 +- app/server/lib/ITestingHooks-ti.ts | 9 ++------- app/server/lib/ITestingHooks.ts | 4 ++-- app/server/lib/OnDemandActions.ts | 2 +- app/server/lib/Sharing.ts | 12 +++++++----- app/server/lib/TestingHooks.ts | 20 +++++++++++--------- app/server/lib/uploads.ts | 2 +- buildtools/tsconfig-base.json | 2 +- stubs/app/client/ui/CustomThemes.ts | 2 +- test/nbrowser/gristUtils.ts | 6 +++--- test/nbrowser/testServer.ts | 2 +- 56 files changed, 147 insertions(+), 125 deletions(-) diff --git a/app/client/components/AceEditor.js b/app/client/components/AceEditor.js index bab22a0c..7db8edf6 100644 --- a/app/client/components/AceEditor.js +++ b/app/client/components/AceEditor.js @@ -241,9 +241,9 @@ AceEditor.prototype._getContentHeight = function() { let _RangeConstructor = null; //singleton, load it lazily -AceEditor.makeRange = function(a,b,c,d) { +AceEditor.makeRange = function(a, b, c, d) { _RangeConstructor = _RangeConstructor || ace.acequire('ace/range').Range; - return new _RangeConstructor(a,b,c,d); + return new _RangeConstructor(a, b, c, d); }; module.exports = AceEditor; diff --git a/app/client/components/ActionLog.ts b/app/client/components/ActionLog.ts index 6bdb8ec0..7515e6e9 100644 --- a/app/client/components/ActionLog.ts +++ b/app/client/components/ActionLog.ts @@ -262,7 +262,7 @@ export class ActionLog extends dispose.Disposable implements IDomComponent { if (this._loaded || !this._gristDoc) { return; } this._loading(true); // Returned actions are ordered with earliest actions first. - const result = await this._gristDoc!.docComm.getActionSummaries(); + const result = await this._gristDoc.docComm.getActionSummaries(); this._loading(false); this._loaded = true; // Add the actions to our action log. diff --git a/app/client/components/ColumnTransform.ts b/app/client/components/ColumnTransform.ts index 59ba782c..6a00bc4d 100644 --- a/app/client/components/ColumnTransform.ts +++ b/app/client/components/ColumnTransform.ts @@ -15,7 +15,7 @@ import * as ko from 'knockout'; import noop = require('lodash/noop'); // To simplify diff (avoid rearranging methods to satisfy private/public order). -// tslint:disable:member-ordering +/* eslint-disable @typescript-eslint/member-ordering */ type AceEditor = any; @@ -130,7 +130,7 @@ export class ColumnTransform extends Disposable { this.transformColumn = this.field.column(); this.transformColumn.origColRef(this.origColumn.getRowId()); this._setTransforming(true); - return await this.postAddTransformColumn(); + return this.postAddTransformColumn(); } finally { this.isCallPending(false); } @@ -167,7 +167,7 @@ export class ColumnTransform extends Disposable { /** * A derived class can override to do some processing after this.transformColumn has been set. */ - protected postAddTransformColumn() { + protected postAddTransformColumn(): void { // Nothing in base class. } @@ -207,7 +207,7 @@ export class ColumnTransform extends Disposable { } finally { // Wait until the change completed to set column back, to avoid value flickering. field.colRef(origRef); - tableData.sendTableAction(['RemoveColumn', transformColId]); + void tableData.sendTableAction(['RemoveColumn', transformColId]); this.dispose(); } } diff --git a/app/client/components/GridView.js b/app/client/components/GridView.js index 4f349a45..a2d990dc 100644 --- a/app/client/components/GridView.js +++ b/app/client/components/GridView.js @@ -350,11 +350,11 @@ GridView.prototype.fillSelectionDown = function() { }).filter(colId => colId); var colInfo = _.object(colIds, colIds.map(colId => { - var val = this.tableModel.tableData.getValue(rowIds[0],colId); + var val = this.tableModel.tableData.getValue(rowIds[0], colId); return rowIds.map(() => val); })); - this.tableModel.sendTableAction(["BulkUpdateRecord",rowIds,colInfo]); + this.tableModel.sendTableAction(["BulkUpdateRecord", rowIds, colInfo]); }; diff --git a/app/client/components/Importer.ts b/app/client/components/Importer.ts index 1dddd38e..6ee6ec9b 100644 --- a/app/client/components/Importer.ts +++ b/app/client/components/Importer.ts @@ -153,7 +153,7 @@ export class Importer extends Disposable { } else if (item.kind === "url") { uploadResult = await fetchURL(this._docComm, item.url); } else { - throw new Error(`Import source of kind ${item!.kind} are not yet supported!`); + throw new Error(`Import source of kind ${(item as any).kind} are not yet supported!`); } } } @@ -391,7 +391,7 @@ export class Importer extends Disposable { } function getSourceDescription(sourceInfo: SourceInfo, upload: UploadResult) { - const origName = upload!.files[sourceInfo.uploadFileIndex].origName; + const origName = upload.files[sourceInfo.uploadFileIndex].origName; return sourceInfo.origTableName ? origName + ' - ' + sourceInfo.origTableName : origName; } diff --git a/app/client/components/SearchBar.ts b/app/client/components/SearchBar.ts index e9c6905f..b5319f10 100644 --- a/app/client/components/SearchBar.ts +++ b/app/client/components/SearchBar.ts @@ -25,8 +25,8 @@ export function makeSearchToolbarGroup(gristDoc: GristDoc) { // Active normally. const commandGroup = createGroup({ find: () => { input.focus(); }, - findNext: () => { searcher.findNext(); }, // tslint:disable-line:no-floating-promises TODO - findPrev: () => { searcher.findPrev(); }, // tslint:disable-line:no-floating-promises TODO + findNext: () => { searcher.findNext(); }, // eslint-disable-line @typescript-eslint/no-floating-promises + findPrev: () => { searcher.findPrev(); }, // eslint-disable-line @typescript-eslint/no-floating-promises }, null, true); // Return an array of one item (for a toolbar group of a single item). The item is an array of @@ -49,7 +49,7 @@ export function makeSearchToolbarGroup(gristDoc: GristDoc) { // the searchbox is created so early that the actions like accept/cancel get overridden). dom.on('keydown', (e: KeyboardEvent) => { switch (e.keyCode) { - case 13: searcher.findNext(); break; // tslint:disable-line:no-floating-promises TODO + case 13: searcher.findNext(); break; // eslint-disable-line @typescript-eslint/no-floating-promises case 27: input.blur(); break; } }) diff --git a/app/client/components/Selector.js b/app/client/components/Selector.js index 8cc7745b..ca827a8b 100644 --- a/app/client/components/Selector.js +++ b/app/client/components/Selector.js @@ -264,7 +264,7 @@ CellSelector.prototype.rowCount = function() { return this.rowUpper() - this.rowLower() + 1; }; -CellSelector.prototype.selectArea = function(rowStartIdx,colStartIdx,rowEndIdx,colEndIdx) { +CellSelector.prototype.selectArea = function(rowStartIdx, colStartIdx, rowEndIdx, colEndIdx) { this.row.start(rowStartIdx); this.col.start(colStartIdx); this.row.end(rowEndIdx); diff --git a/app/client/components/TypeTransform.ts b/app/client/components/TypeTransform.ts index 6e93a30d..a8c43e37 100644 --- a/app/client/components/TypeTransform.ts +++ b/app/client/components/TypeTransform.ts @@ -22,7 +22,7 @@ import isEmpty = require('lodash/isEmpty'); import pickBy = require('lodash/pickBy'); // To simplify diff (avoid rearranging methods to satisfy private/public order). -// tslint:disable:member-ordering +/* eslint-disable @typescript-eslint/member-ordering */ /** * Creates an instance of TypeTransform for a single field. Extends ColumnTransform. diff --git a/app/client/components/ViewConfigTab.js b/app/client/components/ViewConfigTab.js index 974985fd..f4f1de0f 100644 --- a/app/client/components/ViewConfigTab.js +++ b/app/client/components/ViewConfigTab.js @@ -58,7 +58,7 @@ function ViewConfigTab(options) { }) || self.viewSectionData.at(0); })); this.isDetail = this.autoDispose(ko.computed(function() { - return ['detail','single'].includes(this.viewModel.activeSection().parentKey()); + return ['detail', 'single'].includes(this.viewModel.activeSection().parentKey()); }, this)); this.isChart = this.autoDispose(ko.computed(function() { return this.viewModel.activeSection().parentKey() === 'chart';}, this)); diff --git a/app/client/declarations.d.ts b/app/client/declarations.d.ts index 3492bed9..2c135177 100644 --- a/app/client/declarations.d.ts +++ b/app/client/declarations.d.ts @@ -35,7 +35,6 @@ declare module "app/client/components/BaseView" { import {Cursor, CursorPos} from 'app/client/components/Cursor'; import {GristDoc} from 'app/client/components/GristDoc'; import {Disposable} from 'app/client/lib/dispose'; - import {KoArray} from "app/client/lib/koArray"; import * as BaseRowModel from "app/client/models/BaseRowModel"; import {DataRowModel} from 'app/client/models/DataRowModel'; import {LazyArrayModel} from "app/client/models/DataTableModel"; @@ -72,10 +71,8 @@ declare module "app/client/components/BaseView" { } declare module "app/client/components/RefSelect" { - import {GristDoc, TabContent} from 'app/client/components/GristDoc'; import {Disposable} from 'app/client/lib/dispose'; import {ColumnRec} from "app/client/models/DocModel"; - import {DomArg} from 'grainjs'; import {DocModel} from "app/client/models/DocModel"; import {FieldBuilder} from "app/client/widgets/FieldBuilder"; @@ -161,11 +158,11 @@ declare module "app/client/models/BaseRowModel" { class BaseRowModel extends Disposable { public id: ko.Computed; public _index: ko.Observable; - public getRowId(): number; - public updateColValues(colValues: ColValues): Promise; public _table: TableModel; protected _rowId: number | 'new' | null; protected _fields: string[]; + public getRowId(): number; + public updateColValues(colValues: ColValues): Promise; } export = BaseRowModel; } @@ -286,10 +283,9 @@ declare module "app/client/models/DataTableModel" { import * as BaseRowModel from "app/client/models/BaseRowModel"; import {DocModel, TableRec} from "app/client/models/DocModel"; import {TableQuerySets} from 'app/client/models/QuerySet'; - import {RowSource, SortedRowSet} from "app/client/models/rowset"; + import {SortedRowSet} from "app/client/models/rowset"; import {TableData} from "app/client/models/TableData"; import * as TableModel from "app/client/models/TableModel"; - import {CellValue} from "app/common/DocActions"; namespace DataTableModel { interface LazyArrayModel extends KoArray { diff --git a/app/client/lib/autocomplete.ts b/app/client/lib/autocomplete.ts index fd493d48..6b15e256 100644 --- a/app/client/lib/autocomplete.ts +++ b/app/client/lib/autocomplete.ts @@ -1,7 +1,7 @@ /** * Implements an autocomplete dropdown. */ -import {createPopper, Instance as Popper, Modifier, Options as PopperOptions} from '@popperjs/core'; +import {createPopper, Modifier, Instance as Popper, Options as PopperOptions} from '@popperjs/core'; import {ACItem, ACResults, HighlightFunc} from 'app/client/lib/ACIndex'; import {reportError} from 'app/client/models/errors'; import {Disposable, dom, EventCB, IDisposable} from 'grainjs'; diff --git a/app/client/models/BillingModel.ts b/app/client/models/BillingModel.ts index 97924425..d9651b65 100644 --- a/app/client/models/BillingModel.ts +++ b/app/client/models/BillingModel.ts @@ -174,7 +174,7 @@ export class BillingModelImpl extends Disposable implements BillingModel { await this._billingAPI.updateAddress(newAddr || undefined, newSettings || undefined); } // If there is an org update, re-initialize the org in the client. - if (newSettings) { await this._appModel.topAppModel.initialize(); } + if (newSettings) { this._appModel.topAppModel.initialize(); } } else { throw new Error('BillingPage _submit error: no task in progress'); } diff --git a/app/client/models/DataTableModelWithDiff.ts b/app/client/models/DataTableModelWithDiff.ts index a1d0704c..74b839c4 100644 --- a/app/client/models/DataTableModelWithDiff.ts +++ b/app/client/models/DataTableModelWithDiff.ts @@ -27,13 +27,6 @@ const ROW_ID_SKIP = -1; * This should be the only part of the code that knows that. */ export class ExtraRows { - readonly leftTableDelta?: TableDelta; - readonly rightTableDelta?: TableDelta; - readonly rightAddRows: Set; - readonly rightRemoveRows: Set; - readonly leftAddRows: Set; - readonly leftRemoveRows: Set; - /** * Map back from a possibly synthetic row id to an original strictly-positive row id. */ @@ -44,7 +37,14 @@ export class ExtraRows { return { type: 'local-remove', id: -(rowId + 2) / 2 }; } - public constructor(readonly tableId: string, readonly comparison?: DocStateComparisonDetails) { + public readonly leftTableDelta?: TableDelta; + public readonly rightTableDelta?: TableDelta; + public readonly rightAddRows: Set; + public readonly rightRemoveRows: Set; + public readonly leftAddRows: Set; + public readonly leftRemoveRows: Set; + + public constructor(public readonly tableId: string, public readonly comparison?: DocStateComparisonDetails) { const remoteTableId = getRemoteTableId(tableId, comparison); this.leftTableDelta = this.comparison?.leftChanges?.tableDeltas[tableId]; if (remoteTableId) { diff --git a/app/client/models/DocData.ts b/app/client/models/DocData.ts index b1fb06d2..68d24280 100644 --- a/app/client/models/DocData.ts +++ b/app/client/models/DocData.ts @@ -100,7 +100,7 @@ export class DocData extends BaseDocData { this._nextDesc = options.description; this._lastActionNum = null; this._triggerBundleFinalize = triggerFinalize; - await prepareResolve(options.prepare()); + prepareResolve(options.prepare()); this._shouldIncludeInBundle = options.shouldIncludeInBundle; await triggerFinalizePromise; @@ -162,7 +162,7 @@ export class DocData extends BaseDocData { public sendActions(actions: UserAction[], optDesc?: string): Promise { // Some old code relies on this promise being a bluebird Promise. // TODO Remove bluebird and this cast. - return bluebird.Promise.resolve(this._sendActionsImpl(actions, optDesc)) as any; + return bluebird.Promise.resolve(this._sendActionsImpl(actions, optDesc)) as unknown as Promise; } /** diff --git a/app/client/models/DocPageModel.ts b/app/client/models/DocPageModel.ts index 6fae46ae..0edff831 100644 --- a/app/client/models/DocPageModel.ts +++ b/app/client/models/DocPageModel.ts @@ -94,7 +94,8 @@ export class DocPageModelImpl extends Disposable implements DocPageModel { public readonly isReadonly = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isReadonly : false); public readonly isPrefork = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isPreFork : false); public readonly isFork = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isFork : false); - public readonly isRecoveryMode = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isRecoveryMode : false); + public readonly isRecoveryMode = Computed.create(this, this.currentDoc, + (use, doc) => doc ? doc.isRecoveryMode : false); public readonly userOverride = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.userOverride : null); public readonly isBareFork = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isBareFork : false); public readonly isSample = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isSample : false); @@ -133,8 +134,9 @@ export class DocPageModelImpl extends Disposable implements DocPageModel { if (!urlId) { this._openerHolder.clear(); } else { - FlowRunner.create(this._openerHolder, (flow: AsyncFlow) => this._openDoc(flow, urlId, urlOpenMode, - state.params?.compare, linkParameters)) + FlowRunner.create(this._openerHolder, + (flow: AsyncFlow) => this._openDoc(flow, urlId, urlOpenMode, state.params?.compare, linkParameters) + ) .resultPromise.catch(err => this._onOpenError(err)); } } @@ -305,8 +307,10 @@ function addMenu(importSources: ImportSource[], gristDoc: GristDoc, isReadonly: menuIcon("Widget"), "Add Widget to Page", testId('dp-add-widget-to-page'), dom.cls('disabled', isReadonly) ), - menuItem(() => gristDoc.addEmptyTable().catch(reportError), menuIcon("TypeTable"), "Add Empty Table", testId('dp-empty-table'), - dom.cls('disabled', isReadonly)), + menuItem(() => gristDoc.addEmptyTable().catch(reportError), + menuIcon("TypeTable"), "Add Empty Table", testId('dp-empty-table'), + dom.cls('disabled', isReadonly) + ), menuDivider(), ...importSources.map((importSource, i) => menuItem(importSource.action, diff --git a/app/client/models/QuerySet.ts b/app/client/models/QuerySet.ts index e4da1fab..7a3777d2 100644 --- a/app/client/models/QuerySet.ts +++ b/app/client/models/QuerySet.ts @@ -314,7 +314,7 @@ function convertQueryToRefs(docModel: DocModel, query: Query): QueryRefs { const tableRec: any = docModel.dataTables[query.tableId].tableMetaRow; const colRefsByColId: {[colId: string]: number} = {}; - for (const col of (tableRec as any).columns.peek().peek()) { + for (const col of tableRec.columns.peek().peek()) { colRefsByColId[col.colId.peek()] = col.getRowId(); } diff --git a/app/client/models/SearchModel.ts b/app/client/models/SearchModel.ts index 4646127a..ef0d0868 100644 --- a/app/client/models/SearchModel.ts +++ b/app/client/models/SearchModel.ts @@ -84,7 +84,7 @@ export class SearchModelImpl extends Disposable implements SearchModel { // Listen to input value changes (debounced) to activate searching. const findFirst = debounce((_value: string) => this._findFirst(_value), 100); - this.autoDispose(this.value.addListener(v => { findFirst(v); })); + this.autoDispose(this.value.addListener(v => { void findFirst(v); })); } public async findNext() { diff --git a/app/client/models/TableData.ts b/app/client/models/TableData.ts index 06d71be6..2c5ff118 100644 --- a/app/client/models/TableData.ts +++ b/app/client/models/TableData.ts @@ -7,7 +7,7 @@ import {DocData} from 'app/client/models/DocData'; import {DocAction, ReplaceTableData, TableDataAction, UserAction} from 'app/common/DocActions'; import {isRaisedException} from 'app/common/gristTypes'; import {countIf} from 'app/common/gutil'; -import {ColTypeMap, TableData as BaseTableData} from 'app/common/TableData'; +import {TableData as BaseTableData, ColTypeMap} from 'app/common/TableData'; import {BaseFormatter} from 'app/common/ValueFormatter'; import {Emitter} from 'grainjs'; diff --git a/app/client/ui/BillingForm.ts b/app/client/ui/BillingForm.ts index e4b84fc3..84a04a1f 100644 --- a/app/client/ui/BillingForm.ts +++ b/app/client/ui/BillingForm.ts @@ -153,7 +153,7 @@ class BillingPaymentForm extends BillingSubForm { }) { super(); const autofill = this._options.autofill; - const stripeAPIKey = (G.window as any).gristConfig.stripeAPIKey; + const stripeAPIKey = G.window.gristConfig.stripeAPIKey; try { this._stripe = G.Stripe(stripeAPIKey); this._elements = this._stripe.elements(); @@ -462,7 +462,7 @@ function checkRequired(propertyName: string) { // if the current observable value is valid. function createValidated( owner: IDisposableOwnerT, - checkValidity: (value: string) => void + checkValidity: (value: string) => void|Promise, ): IValidated { const value = Observable.create(owner, ''); const isInvalid = Observable.create(owner, false); diff --git a/app/client/ui/VisibleFieldsConfig.ts b/app/client/ui/VisibleFieldsConfig.ts index 037175cb..4dbdf63f 100644 --- a/app/client/ui/VisibleFieldsConfig.ts +++ b/app/client/ui/VisibleFieldsConfig.ts @@ -352,7 +352,7 @@ function getFieldNewPosition(fields: KoArray, item: IField, return tableUtil.fieldInsertPositions(fields, index, 1)[0]; } -function getItemIndex(collection: KoArray, item: ViewFieldRec|null): number { +function getItemIndex(collection: KoArray, item: ViewFieldRec|null): number { if (item !== null) { return collection.peek().indexOf(item); } diff --git a/app/client/ui2018/cssVars.ts b/app/client/ui2018/cssVars.ts index 983b334c..1ddc7582 100644 --- a/app/client/ui2018/cssVars.ts +++ b/app/client/ui2018/cssVars.ts @@ -194,8 +194,8 @@ export const cssHideForNarrowScreen = styled('div', ` * Attaches the global css properties to the document's root to them available in the page. */ export function attachCssRootVars(productFlavor: ProductFlavor, varsOnly: boolean = false) { - dom.update(document.documentElement!, varsOnly ? dom.cls(cssVarsOnly.className) : dom.cls(cssRootVars)); - document.documentElement!.classList.add(cssRoot.className); + dom.update(document.documentElement, varsOnly ? dom.cls(cssVarsOnly.className) : dom.cls(cssRootVars)); + document.documentElement.classList.add(cssRoot.className); document.body.classList.add(cssBody.className); const theme = getTheme(productFlavor); if (theme.bodyClassName) { diff --git a/app/client/widgets/DiffBox.ts b/app/client/widgets/DiffBox.ts index 2abcb9e3..badb98ce 100644 --- a/app/client/widgets/DiffBox.ts +++ b/app/client/widgets/DiffBox.ts @@ -4,7 +4,7 @@ import { CellValue } from 'app/common/DocActions'; import { isVersions } from 'app/common/gristTypes'; import { inlineStyle } from 'app/common/gutil'; import { BaseFormatter } from 'app/common/ValueFormatter'; -import { Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch as DiffMatchPatch, DIFF_EQUAL } from 'diff-match-patch'; +import { Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch as DiffMatchPatch } from 'diff-match-patch'; import { Computed, dom } from 'grainjs'; /** diff --git a/app/client/widgets/FieldBuilder.ts b/app/client/widgets/FieldBuilder.ts index 4fd7c341..9ead15a2 100644 --- a/app/client/widgets/FieldBuilder.ts +++ b/app/client/widgets/FieldBuilder.ts @@ -27,7 +27,7 @@ import * as gristTypes from 'app/common/gristTypes'; import * as gutil from 'app/common/gutil'; import { CellValue } from 'app/plugin/GristData'; import { delay } from 'bluebird'; -import { Computed, Disposable, dom as grainjsDom, fromKo, Holder, IDisposable, makeTestId } from 'grainjs'; +import { Computed, Disposable, fromKo, dom as grainjsDom, Holder, IDisposable, makeTestId } from 'grainjs'; import * as ko from 'knockout'; import * as _ from 'underscore'; @@ -77,7 +77,7 @@ export class FieldBuilder extends Disposable { private readonly widgetCons: ko.Computed<{create: (...args: any[]) => NewAbstractWidget}>; private readonly docModel: DocModel; - public constructor(readonly gristDoc: GristDoc, readonly field: ViewFieldRec, + public constructor(public readonly gristDoc: GristDoc, public readonly field: ViewFieldRec, private _cursor: Cursor) { super(); diff --git a/app/common/ACLRuleCollection.ts b/app/common/ACLRuleCollection.ts index c66b8e68..67e8502f 100644 --- a/app/common/ACLRuleCollection.ts +++ b/app/common/ACLRuleCollection.ts @@ -315,7 +315,7 @@ function readAclRules(docData: DocData, {log, compile}: ReadAclOptions): ReadAcl } for (const [resourceId, rules] of rulesByResource.entries()) { - const resourceRec = resourcesTable.getRecord(resourceId as number); + const resourceRec = resourcesTable.getRecord(resourceId); if (!resourceRec) { throw new Error(`ACLRule ${rules[0].id} refers to an invalid ACLResource ${resourceId}`); continue; diff --git a/app/common/DocActions.ts b/app/common/DocActions.ts index 78603888..01a6a9a8 100644 --- a/app/common/DocActions.ts +++ b/app/common/DocActions.ts @@ -82,7 +82,8 @@ const SCHEMA_ACTIONS = new Set(['AddTable', 'RemoveTable', 'RenameTable', 'AddCo /** * Determines whether a given action is a schema action or not. */ -export function isSchemaAction(action: DocAction): action is AddTable | RemoveTable | RenameTable | AddColumn | RemoveColumn | RenameColumn | ModifyColumn { +export function isSchemaAction(action: DocAction): + action is AddTable | RemoveTable | RenameTable | AddColumn | RemoveColumn | RenameColumn | ModifyColumn { return SCHEMA_ACTIONS.has(action[0]); } diff --git a/app/common/DocListAPI.ts b/app/common/DocListAPI.ts index ce96df27..883ecc8b 100644 --- a/app/common/DocListAPI.ts +++ b/app/common/DocListAPI.ts @@ -48,7 +48,7 @@ export interface OpenLocalDocResult { userOverride?: UserOverride; } -export class UserOverride { +export interface UserOverride { user: FullUser|null; access: Role|null; } diff --git a/app/common/PluginInstance.ts b/app/common/PluginInstance.ts index 78cd5165..dcacdad8 100644 --- a/app/common/PluginInstance.ts +++ b/app/common/PluginInstance.ts @@ -76,7 +76,7 @@ export abstract class BaseComponent implements IForwarderDest { public async forwardMessage(msg: IMsgCustom): Promise { if (!this._activated) { await this.activate(); } this.inactivityTimer.ping(); - this.doForwardMessage(msg); // tslint:disable-line:no-floating-promises TODO + this.doForwardMessage(msg); // eslint-disable-line @typescript-eslint/no-floating-promises } protected abstract doForwardCall(c: IMsgRpcCall): Promise; diff --git a/app/common/UserAPI.ts b/app/common/UserAPI.ts index 99a3ccb9..ceb4ae4b 100644 --- a/app/common/UserAPI.ts +++ b/app/common/UserAPI.ts @@ -629,7 +629,7 @@ export class UserAPIImpl extends BaseAPI implements UserAPI { } export class DocWorkerAPIImpl extends BaseAPI implements DocWorkerAPI { - constructor(readonly url: string, _options: IOptions = {}) { + constructor(public readonly url: string, _options: IOptions = {}) { super(_options); } @@ -682,7 +682,7 @@ export class DocWorkerAPIImpl extends BaseAPI implements DocWorkerAPI { export class DocAPIImpl extends BaseAPI implements DocAPI { private _url: string; - constructor(url: string, readonly docId: string, options: IOptions = {}) { + constructor(url: string, public readonly docId: string, options: IOptions = {}) { super(options); this._url = `${url}/api/docs/${docId}`; } diff --git a/app/common/tbind.ts b/app/common/tbind.ts index a066da66..011d5dee 100644 --- a/app/common/tbind.ts +++ b/app/common/tbind.ts @@ -8,7 +8,9 @@ export function tbind(func: (this: T, ...a: Args) => R, context: T): (...a: Args) => R; // Bind context and first arg for a function of up to 5 args. -export function tbind(func: (this: T, x: X, ...a: Args) => R, context: T, x: X): (...a: Args) => R; +export function tbind( + func: (this: T, x: X, ...a: Args) => R, context: T, x: X +): (...a: Args) => R; export function tbind(func: any, context: any, ...boundArgs: any[]): any { return func.bind(context, ...boundArgs); diff --git a/app/common/tpromisified.ts b/app/common/tpromisified.ts index 4ef7c6e3..314cb6c1 100644 --- a/app/common/tpromisified.ts +++ b/app/common/tpromisified.ts @@ -12,7 +12,8 @@ type PromisifiedFunction = T extends (a1: infer A1) => infer U ? (a1: A1) => Promise> : T extends (a1: infer A1, a2: infer A2) => infer U ? (a1: A1, a2: A2) => Promise> : T extends (a1: infer A1, a2: infer A2, a3: infer A3) => infer U ? (a1: A1, a2: A2, a3: A3) => Promise> : - T extends (a1: infer A1, a2: infer A2, a3: infer A3, a4: infer A4) => infer U ? (a1: A1, a2: A2, a3: A3, a4: A4) => Promise> : + T extends (a1: infer A1, a2: infer A2, a3: infer A3, a4: infer A4) => + infer U ? (a1: A1, a2: A2, a3: A3, a4: A4) => Promise> : // ... T extends (...args: any[]) => infer U ? (...args: any[]) => Promise> : T; diff --git a/app/gen-server/lib/DocApiForwarder.ts b/app/gen-server/lib/DocApiForwarder.ts index d5b68286..c3947c4d 100644 --- a/app/gen-server/lib/DocApiForwarder.ts +++ b/app/gen-server/lib/DocApiForwarder.ts @@ -55,7 +55,9 @@ export class DocApiForwarder { app.use('^/api/docs$', withoutDoc); } - private async _forwardToDocWorker(withDocId: boolean, role: 'viewers'|null, req: express.Request, res: express.Response): Promise { + private async _forwardToDocWorker( + withDocId: boolean, role: 'viewers'|null, req: express.Request, res: express.Response, + ): Promise { let docId: string|null = null; if (withDocId) { const docAuth = await getOrSetDocAuth(req as RequestWithLogin, this._dbManager, req.params.docId); diff --git a/app/gen-server/lib/DocWorkerMap.ts b/app/gen-server/lib/DocWorkerMap.ts index c3fb6f23..a692d906 100644 --- a/app/gen-server/lib/DocWorkerMap.ts +++ b/app/gen-server/lib/DocWorkerMap.ts @@ -424,7 +424,7 @@ export class DocWorkerMap implements IDocWorkerMap { } public async updateDocStatus(docId: string, checksum: string): Promise { - this.updateChecksum('doc', docId, checksum); + return this.updateChecksum('doc', docId, checksum); } public async updateChecksum(family: string, key: string, checksum: string) { diff --git a/app/gen-server/lib/HomeDBManager.ts b/app/gen-server/lib/HomeDBManager.ts index b8065d50..bd15be31 100644 --- a/app/gen-server/lib/HomeDBManager.ts +++ b/app/gen-server/lib/HomeDBManager.ts @@ -8,8 +8,8 @@ import {checkSubdomainValidity} from 'app/common/orgNameUtils'; import * as roles from 'app/common/roles'; // TODO: API should implement UserAPI import {ANONYMOUS_USER_EMAIL, DocumentProperties, EVERYONE_EMAIL, - ManagerDelta, NEW_DOCUMENT_CODE, Organization as OrgInfo, - OrganizationProperties, PermissionData, PermissionDelta, SUPPORT_EMAIL, UserAccessData, + ManagerDelta, NEW_DOCUMENT_CODE, OrganizationProperties, + Organization as OrgInfo, PermissionData, PermissionDelta, SUPPORT_EMAIL, UserAccessData, WorkspaceProperties} from "app/common/UserAPI"; import {AclRule, AclRuleDoc, AclRuleOrg, AclRuleWs} from "app/gen-server/entity/AclRule"; import {Alias} from "app/gen-server/entity/Alias"; @@ -1903,7 +1903,7 @@ export class HomeDBManager extends EventEmitter { name: u.name, email: u.logins.map((login: Login) => login.displayEmail)[0], picture: u.picture, - access: userRoleMap[u.id] as roles.Role + access: userRoleMap[u.id] })); return { status: 200, @@ -2811,7 +2811,7 @@ export class HomeDBManager extends EventEmitter { let effectiveUserId = userId; let threshold = options.markPermissions; if (options.allowSpecialPermit && scope.specialPermit && scope.specialPermit.docId) { - query = query.andWhere('docs.id = :docId', {docId: scope.specialPermit.docId!}); + query = query.andWhere('docs.id = :docId', {docId: scope.specialPermit.docId}); effectiveUserId = this.getPreviewerUserId(); threshold = Permissions.VIEW; } @@ -3051,7 +3051,7 @@ export class HomeDBManager extends EventEmitter { if (!groupProps.orgOnly || !inherit) { // Skip this group if it's an org only group and the resource inherits from a parent. const group = new Group(); - group.name = groupProps.name as roles.Role; + group.name = groupProps.name; if (inherit) { this._setInheritance(group, inherit); } @@ -3333,7 +3333,10 @@ export class HomeDBManager extends EventEmitter { `${everyoneId} IN (gu0.user_id, gu1.user_id, gu2.user_id, gu3.user_id) ` + `then ${everyoneContribution} else (case when ` + `${anonId} IN (gu0.user_id, gu1.user_id, gu2.user_id, gu3.user_id) ` + - `then ${Permissions.PUBLIC} | acl_rules.permissions else acl_rules.permissions end) end)`, 8), 'permissions'); + `then ${Permissions.PUBLIC} | acl_rules.permissions else acl_rules.permissions end) end)`, 8 + ), + 'permissions' + ); } q = q.from('acl_rules', 'acl_rules'); q = this._getUsersAcls(q, users, accessStyle); diff --git a/app/gen-server/lib/Housekeeper.ts b/app/gen-server/lib/Housekeeper.ts index e7d39436..0b735229 100644 --- a/app/gen-server/lib/Housekeeper.ts +++ b/app/gen-server/lib/Housekeeper.ts @@ -210,7 +210,9 @@ export class Housekeeper { // Call a document endpoint with a permit, cleaning up after the call. // Checks that the user is the support user. - private _withSupport(callback: (docId: string, headers: Record) => Promise): express.RequestHandler { + private _withSupport( + callback: (docId: string, headers: Record) => Promise + ): express.RequestHandler { return expressWrap(async (req, res) => { const userId = getAuthorizedUserId(req); if (userId !== this._dbManager.getSupportUserId()) { diff --git a/app/plugin/grist-plugin-api.ts b/app/plugin/grist-plugin-api.ts index 6cede2ac..1325631e 100644 --- a/app/plugin/grist-plugin-api.ts +++ b/app/plugin/grist-plugin-api.ts @@ -133,7 +133,7 @@ export async function addImporter(name: string, path: string, mode: 'fullscreen' */ export function ready(): void { rpc.processIncoming(); - rpc.sendReadyMessage(); + void rpc.sendReadyMessage(); } function getPluginPath(location: Location) { diff --git a/app/server/lib/ActiveDoc.ts b/app/server/lib/ActiveDoc.ts index 9b7c7c08..cd2cdc73 100644 --- a/app/server/lib/ActiveDoc.ts +++ b/app/server/lib/ActiveDoc.ts @@ -715,7 +715,7 @@ export class ActiveDoc extends EventEmitter { */ public async getFormulaError(docSession: DocSession, tableId: string, colId: string, rowId: number): Promise { - if (!this._granularAccess.hasTableAccess(docSession, tableId)) { return null; } + if (!await this._granularAccess.hasTableAccess(docSession, tableId)) { return null; } this.logInfo(docSession, "getFormulaError(%s, %s, %s, %s)", docSession, tableId, colId, rowId); await this.waitForInitialization(); @@ -1094,7 +1094,7 @@ export class ActiveDoc extends EventEmitter { ]); // Migrate the document if needed. - const values = marshal.loads(docInfoData!); + const values = marshal.loads(docInfoData); const versionCol = values.schemaVersion; const docSchemaVersion = (versionCol && versionCol.length === 1 ? versionCol[0] : 0); if (docSchemaVersion < schemaVersion) { @@ -1126,7 +1126,7 @@ export class ActiveDoc extends EventEmitter { const tableNames: string[] = await this._rawPyCall('load_meta_tables', tablesData, columnsData); // Figure out which tables are on-demand. - const tablesParsed: BulkColValues = marshal.loads(tablesData!); + const tablesParsed: BulkColValues = marshal.loads(tablesData); const onDemandMap = zipObject(tablesParsed.tableId as string[], tablesParsed.onDemand); const onDemandNames = remove(tableNames, (t) => onDemandMap[t]); @@ -1183,7 +1183,7 @@ export class ActiveDoc extends EventEmitter { const result: ApplyUAResult = await new Promise( (resolve, reject) => - this._sharing!.addUserAction({action, docSession, resolve, reject})); + this._sharing.addUserAction({action, docSession, resolve, reject})); this.logDebug(docSession, "_applyUserActions returning %s", shortDesc(result)); if (result.isModification) { diff --git a/app/server/lib/AppEndpoint.ts b/app/server/lib/AppEndpoint.ts index 1041b209..b3c92d65 100644 --- a/app/server/lib/AppEndpoint.ts +++ b/app/server/lib/AppEndpoint.ts @@ -4,7 +4,7 @@ * of the client-side code. */ import * as express from 'express'; -import fetch, {RequestInit, Response as FetchResponse} from 'node-fetch'; +import fetch, {Response as FetchResponse, RequestInit} from 'node-fetch'; import {ApiError} from 'app/common/ApiError'; import {getSlugIfNeeded, parseSubdomainStrictly} from 'app/common/gristUrls'; diff --git a/app/server/lib/DocApi.ts b/app/server/lib/DocApi.ts index 05a34031..5078b2ab 100644 --- a/app/server/lib/DocApi.ts +++ b/app/server/lib/DocApi.ts @@ -215,10 +215,9 @@ export class DocWorkerApi { // Initiate a fork. Used internally to implement ActiveDoc.fork. Only usable via a Permit. this._app.post('/api/docs/:docId/create-fork', canEdit, throttled(async (req, res) => { - const mreq = req as RequestWithLogin; const docId = stringParam(req.params.docId); const srcDocId = stringParam(req.body.srcDocId); - if (srcDocId !== mreq.specialPermit?.otherDocId) { throw new Error('access denied'); } + if (srcDocId !== req.specialPermit?.otherDocId) { throw new Error('access denied'); } await this._docManager.storageManager.prepareFork(srcDocId, docId); res.json({srcDocId, docId}); })); @@ -249,7 +248,7 @@ export class DocWorkerApi { this._app.post('/api/docs/:docId/recover', canEdit, throttled(async (req, res) => { const recoveryModeRaw = req.body.recoveryMode; const recoveryMode = (typeof recoveryModeRaw === 'boolean') ? recoveryModeRaw : undefined; - if (!this._isOwner(req)) { throw new Error('Only owners can control recovery mode'); } + if (!await this._isOwner(req)) { throw new Error('Only owners can control recovery mode'); } const activeDoc = await this._docManager.fetchDoc(docSessionFromRequest(req), getDocId(req), recoveryMode); res.json({ recoveryMode: activeDoc.recoveryMode diff --git a/app/server/lib/DocManager.ts b/app/server/lib/DocManager.ts index f4c0d227..6bde5b83 100644 --- a/app/server/lib/DocManager.ts +++ b/app/server/lib/DocManager.ts @@ -16,7 +16,8 @@ import {HomeDBManager} from 'app/gen-server/lib/HomeDBManager'; import {assertAccess, Authorizer, DocAuthorizer, DummyAuthorizer, isSingleUserMode} from 'app/server/lib/Authorizer'; import {Client} from 'app/server/lib/Client'; -import {getDocSessionCachedDoc, makeExceptionalDocSession, makeOptDocSession, OptDocSession} from 'app/server/lib/DocSession'; +import {getDocSessionCachedDoc, makeExceptionalDocSession, makeOptDocSession} from 'app/server/lib/DocSession'; +import {OptDocSession} from 'app/server/lib/DocSession'; import * as docUtils from 'app/server/lib/docUtils'; import {GristServer} from 'app/server/lib/GristServer'; import {IDocStorageManager} from 'app/server/lib/IDocStorageManager'; @@ -498,7 +499,7 @@ export class DocManager extends EventEmitter { // TODO: We should be skeptical of the upload file to close a possible // security vulnerability. See https://phab.getgrist.com/T457. const docName = await this._createNewDoc(id); - const docPath = await this.storageManager.getPath(docName); + const docPath: string = this.storageManager.getPath(docName); await docUtils.copyFile(uploadInfo.files[0].absPath, docPath); await this.storageManager.addToStorage(docName); return {title: basename, id: docName}; diff --git a/app/server/lib/DocPluginManager.ts b/app/server/lib/DocPluginManager.ts index 51f2c3dc..390a3403 100644 --- a/app/server/lib/DocPluginManager.ts +++ b/app/server/lib/DocPluginManager.ts @@ -65,7 +65,12 @@ export class DocPluginManager { private _pluginInstances: PluginInstance[]; - constructor(private _localPlugins: LocalPlugin[], private _appRoot: string, private _activeDoc: ActiveDoc, private _server: GristServer) { + constructor( + private _localPlugins: LocalPlugin[], + private _appRoot: string, + private _activeDoc: ActiveDoc, + private _server: GristServer + ) { this.gristDocAPI = new GristDocAPIImpl(_activeDoc); this._pluginInstances = []; this.ready = this._initialize(); diff --git a/app/server/lib/DocStorage.ts b/app/server/lib/DocStorage.ts index 9e895091..a06d5b06 100644 --- a/app/server/lib/DocStorage.ts +++ b/app/server/lib/DocStorage.ts @@ -439,7 +439,9 @@ export class DocStorage implements ISQLiteDB { * Note that SQLite may contain tables that aren't used for Grist data (e.g. attachments), for * which such encoding/marshalling is not used, and e.g. binary data is stored to BLOBs directly. */ - private static _encodeValue(marshaller: marshal.Marshaller, sqlType: string, val: any): Uint8Array|string|number|boolean { + private static _encodeValue( + marshaller: marshal.Marshaller, sqlType: string, val: any + ): Uint8Array|string|number|boolean { const marshalled = () => { marshaller.marshal(val); return marshaller.dump(); @@ -1376,7 +1378,7 @@ export class DocStorage implements ISQLiteDB { // columns, or adding or removing or changing default values on a column." const row = await this.get("PRAGMA schema_version"); assert(row && row.schema_version, "Could not retrieve schema_version."); - const newSchemaVersion = row!.schema_version + 1; + const newSchemaVersion = row.schema_version + 1; const tmpTableId = DocStorage._makeTmpTableId(tableId); await this._getDB().runEach( "PRAGMA writable_schema=ON", @@ -1462,7 +1464,7 @@ export class DocStorage implements ISQLiteDB { * should be reasonably fast: * https://sqlite.org/tempfiles.html#temp_databases */ - public async _fetchQueryWithManyParameters(query: ExpandedQuery): Promise { + private async _fetchQueryWithManyParameters(query: ExpandedQuery): Promise { const db = this._getDB(); return db.execTransaction(async () => { const tableNames: string[] = []; @@ -1490,7 +1492,7 @@ export class DocStorage implements ISQLiteDB { * Construct SQL for an ExpandedQuery. Expects that filters have been converted into * a set of WHERE terms that should be ANDed. */ - public _getSqlForQuery(query: ExpandedQuery, whereParts: string[]) { + private _getSqlForQuery(query: ExpandedQuery, whereParts: string[]) { const whereClause = whereParts.length > 0 ? `WHERE ${whereParts.join(' AND ')}` : ''; const limitClause = (typeof query.limit === 'number') ? `LIMIT ${query.limit}` : ''; const joinClauses = query.joins ? query.joins.join(' ') : ''; diff --git a/app/server/lib/DocStorageManager.ts b/app/server/lib/DocStorageManager.ts index d070f5e2..1795da05 100644 --- a/app/server/lib/DocStorageManager.ts +++ b/app/server/lib/DocStorageManager.ts @@ -196,7 +196,7 @@ export class DocStorageManager implements IDocStorageManager { * Electron version only. Shows the given doc in the file explorer. */ public async showItemInFolder(docName: string): Promise { - this._shell.showItemInFolder(await this.getPath(docName)); + this._shell.showItemInFolder(this.getPath(docName)); } public async closeStorage() { diff --git a/app/server/lib/ExternalStorage.ts b/app/server/lib/ExternalStorage.ts index 515e89c3..87bd5157 100644 --- a/app/server/lib/ExternalStorage.ts +++ b/app/server/lib/ExternalStorage.ts @@ -133,7 +133,7 @@ export class KeyMappedExternalStorage implements ExternalStorage { export class ChecksummedExternalStorage implements ExternalStorage { private _closed: boolean = false; - constructor(readonly label: string, private _ext: ExternalStorage, private _options: { + constructor(public readonly label: string, private _ext: ExternalStorage, private _options: { maxRetries: number, // how many time to retry inconsistent downloads initialDelayMs: number, // how long to wait before retrying localHash: PropStorage, // key/value store for hashes of downloaded content diff --git a/app/server/lib/FlexServer.ts b/app/server/lib/FlexServer.ts index 2c43c1c1..9cbfaed1 100644 --- a/app/server/lib/FlexServer.ts +++ b/app/server/lib/FlexServer.ts @@ -145,7 +145,7 @@ export class FlexServer implements GristServer { private _sendAppPage: (req: express.Request, resp: express.Response, options: ISendAppPageOptions) => Promise; constructor(public port: number, public name: string = 'flexServer', - readonly options: FlexServerOptions = {}) { + public readonly options: FlexServerOptions = {}) { this.app = express(); this.app.set('port', port); this.appRoot = getAppRoot(); diff --git a/app/server/lib/GranularAccess.ts b/app/server/lib/GranularAccess.ts index 1ebe33f4..8ff9e4f6 100644 --- a/app/server/lib/GranularAccess.ts +++ b/app/server/lib/GranularAccess.ts @@ -724,7 +724,9 @@ export class GranularAccess implements GranularAccessForBundle { const ruler = await this._getRuler(cursor); const tableId = getTableId(action); const ruleSets = ruler.ruleCollection.getAllColumnRuleSets(tableId); - const colIds = new Set(([] as string[]).concat(...ruleSets.map(ruleSet => ruleSet.colIds === '*' ? [] : ruleSet.colIds))); + const colIds = new Set(([] as string[]).concat( + ...ruleSets.map(ruleSet => ruleSet.colIds === '*' ? [] : ruleSet.colIds) + )); const access = await ruler.getAccess(cursor.docSession); // Check columns in a consistent order, for determinism (easier testing). // TODO: could pool some work between columns by doing them together rather than one by one. @@ -1164,7 +1166,9 @@ export class GranularAccess implements GranularAccessForBundle { const rowsBefore = cloneDeep(tableData?.getTableDataAction() || ['TableData', '', [], {}] as TableDataAction); docData.receiveAction(docAction); // If table is deleted, state afterwards doesn't matter. - const rowsAfter = docData.getTable(tableId) ? cloneDeep(tableData?.getTableDataAction() || ['TableData', '', [], {}] as TableDataAction) : rowsBefore; + const rowsAfter = docData.getTable(tableId) ? + cloneDeep(tableData?.getTableDataAction() || ['TableData', '', [], {}] as TableDataAction) : + rowsBefore; const step: ActionStep = {action: docAction, rowsBefore, rowsAfter}; steps.push(step); } @@ -1208,7 +1212,7 @@ export class GranularAccess implements GranularAccessForBundle { if (applied) { // Rules may have changed - back them off to a copy of their original state. ruler = new Ruler(this); - ruler.update(metaDocData); + await ruler.update(metaDocData); } let replaceRuler = false; for (const docAction of docActions) { @@ -1228,7 +1232,7 @@ export class GranularAccess implements GranularAccessForBundle { replaceRuler = true; } else if (replaceRuler) { ruler = new Ruler(this); - ruler.update(metaDocData); + await ruler.update(metaDocData); replaceRuler = false; } step.ruler = ruler; @@ -1625,7 +1629,8 @@ export class CensorshipInfo { const tableId = tableRefToTableId.get(tableRef); if (!tableId) { throw new Error('table not found'); } const colId = rec.get('colId') as string; - if (this.censoredTables.has(tableRef) || (colId !== 'manualSort' && permInfo.getColumnAccess(tableId, colId).perms.read === 'deny')) { + if (this.censoredTables.has(tableRef) || + (colId !== 'manualSort' && permInfo.getColumnAccess(tableId, colId).perms.read === 'deny')) { censoredColumnCodes.add(columnCode(tableRef, colId)); } } diff --git a/app/server/lib/HostedStorageManager.ts b/app/server/lib/HostedStorageManager.ts index cf4b6aad..982851b0 100644 --- a/app/server/lib/HostedStorageManager.ts +++ b/app/server/lib/HostedStorageManager.ts @@ -239,7 +239,7 @@ export class HostedStorageManager implements IDocStorageManager { await this.prepareLocalDoc(docName, 'new'); if (this._inventory) { await this._inventory.create(docName); - this._onInventoryChange(docName); + await this._onInventoryChange(docName); } this.markAsChanged(docName); } diff --git a/app/server/lib/ITestingHooks-ti.ts b/app/server/lib/ITestingHooks-ti.ts index a0c67f4d..f0b2efc1 100644 --- a/app/server/lib/ITestingHooks-ti.ts +++ b/app/server/lib/ITestingHooks-ti.ts @@ -10,18 +10,14 @@ export const ITestingHooks = t.iface([], { "updateAuthToken": t.func("void", t.param("instId", "string"), t.param("authToken", "string")), "getAuthToken": t.func(t.union("string", "null"), t.param("instId", "string")), "useTestToken": t.func("void", t.param("instId", "string"), t.param("token", "string")), - "setLoginSessionProfile": t.func("void", t.param("gristSidCookie", "string"), - t.param("profile", t.union("UserProfile", "null")), t.param("org", "string", true)), + "setLoginSessionProfile": t.func("void", t.param("gristSidCookie", "string"), t.param("profile", t.union("UserProfile", "null")), t.param("org", "string", true)), "setServerVersion": t.func("void", t.param("version", t.union("string", "null"))), "disconnectClients": t.func("void"), "commShutdown": t.func("void"), "commRestart": t.func("void"), "commSetClientPersistence": t.func("void", t.param("ttlMs", "number")), "closeDocs": t.func("void"), - "setDocWorkerActivation": t.func("void", t.param("workerId", "string"), - t.param("active", t.union(t.lit('active'), - t.lit('inactive'), - t.lit('crash')))), + "setDocWorkerActivation": t.func("void", t.param("workerId", "string"), t.param("active", t.union(t.lit('active'), t.lit('inactive'), t.lit('crash')))), "flushAuthorizerCache": t.func("void"), "getDocClientCounts": t.func(t.array(t.tuple("string", "number"))), "setActiveDocTimeout": t.func("number", t.param("seconds", "number")), @@ -29,6 +25,5 @@ export const ITestingHooks = t.iface([], { const exportedTypeSuite: t.ITypeSuite = { ITestingHooks, - UserProfile: t.name("object"), }; export default exportedTypeSuite; diff --git a/app/server/lib/ITestingHooks.ts b/app/server/lib/ITestingHooks.ts index 9a3a587f..a15f8cb8 100644 --- a/app/server/lib/ITestingHooks.ts +++ b/app/server/lib/ITestingHooks.ts @@ -1,8 +1,8 @@ import {UserProfile} from 'app/common/LoginSessionAPI'; export interface ITestingHooks { - getOwnPort(): number; - getPort(): number; + getOwnPort(): Promise; + getPort(): Promise; updateAuthToken(instId: string, authToken: string): Promise; getAuthToken(instId: string): Promise; useTestToken(instId: string, token: string): Promise; diff --git a/app/server/lib/OnDemandActions.ts b/app/server/lib/OnDemandActions.ts index 3e9f0b36..8dcd5831 100644 --- a/app/server/lib/OnDemandActions.ts +++ b/app/server/lib/OnDemandActions.ts @@ -62,7 +62,7 @@ export class OnDemandActions { // Check that the actionType can be applied without the sandbox and also that the action // is on a data table. const isOnDemandAction = ACTION_TYPES.has(a[0] as string); - const isDataTableAction = typeof a[1] === 'string' && !(a[1] as string).startsWith('_grist_'); + const isDataTableAction = typeof a[1] === 'string' && !a[1].startsWith('_grist_'); if (a[0] === 'ApplyUndoActions') { // Split actions inside the undo action array. const [undoNormal, undoOnDemand] = this.splitByOnDemand(a[1] as UserAction[]); diff --git a/app/server/lib/Sharing.ts b/app/server/lib/Sharing.ts index eb8889a2..b9af14f2 100644 --- a/app/server/lib/Sharing.ts +++ b/app/server/lib/Sharing.ts @@ -155,7 +155,7 @@ export class Sharing { private async _rebaseLocalActions(): Promise { const rebaseQueue: Deque = new Deque(); try { - await this.createCheckpoint(); + this.createCheckpoint(); const actions: LocalActionBundle[] = await this._actionHistory.fetchAllLocal(); assert(actions.length > 0); await this.doApplyUserActionBundle(this._createUndo(actions), null); @@ -163,7 +163,7 @@ export class Sharing { await this._actionHistory.clearLocalActions(); } catch (e) { log.error("Can't undo local actions; sharing is off"); - await this.rollbackToCheckpoint(); + this.rollbackToCheckpoint(); // TODO this.disconnect(); // TODO errorState = true; return; @@ -185,11 +185,11 @@ export class Sharing { } } if (rebaseFailures.length > 0) { - await this.createBackupAtCheckpoint(); + this.createBackupAtCheckpoint(); // TODO we should notify the user too. log.error('Rebase failed to reapply some of your actions, backup of local at...'); } - await this.releaseCheckpoint(); + this.releaseCheckpoint(); } // ====================================================================== @@ -374,7 +374,9 @@ export class Sharing { const docActions = getEnvContent(sandboxActionBundle.stored).concat( getEnvContent(sandboxActionBundle.calc)); - const accessControl = this._activeDoc.getGranularAccessForBundle(docSession || makeExceptionalDocSession('share'), docActions, undo, userActions); + const accessControl = this._activeDoc.getGranularAccessForBundle( + docSession || makeExceptionalDocSession('share'), docActions, undo, userActions + ); try { // TODO: see if any of the code paths that have no docSession are relevant outside // of tests. diff --git a/app/server/lib/TestingHooks.ts b/app/server/lib/TestingHooks.ts index 15cebf32..aeedf7c1 100644 --- a/app/server/lib/TestingHooks.ts +++ b/app/server/lib/TestingHooks.ts @@ -6,13 +6,15 @@ import * as Comm from 'app/server/lib/Comm'; import {ILoginSession} from 'app/server/lib/ILoginSession'; import * as log from 'app/server/lib/log'; import {IMessage, Rpc} from 'grain-rpc'; -import {createCheckers} from 'ts-interface-checker'; +import * as t from 'ts-interface-checker'; import {FlexServer} from './FlexServer'; import {IInstanceManager} from './IInstanceManager'; import {ITestingHooks} from './ITestingHooks'; import ITestingHooksTI from './ITestingHooks-ti'; import {connect, fromCallback} from './serverUtils'; +const tiCheckers = t.createCheckers(ITestingHooksTI, {UserProfile: t.name("object")}); + export function startTestingHooks(socketPath: string, port: number, instanceManager: IInstanceManager, comm: Comm, flexServer: FlexServer, workerServers: FlexServer[]): Promise { @@ -27,7 +29,7 @@ export function startTestingHooks(socketPath: string, port: number, instanceMana // Register the testing implementation. rpc.registerImpl('testing', new TestingHooks(port, instanceManager, comm, flexServer, workerServers), - createCheckers(ITestingHooksTI).ITestingHooks); + tiCheckers.ITestingHooks); }); server.listen(socketPath); }); @@ -47,7 +49,7 @@ export interface TestingHooksClient extends ITestingHooks { export async function connectTestingHooks(socketPath: string): Promise { const socket = await connect(socketPath); const rpc = connectToSocket(new Rpc({logger: {}}), socket); - return Object.assign(rpc.getStub('testing', createCheckers(ITestingHooksTI).ITestingHooks), { + return Object.assign(rpc.getStub('testing', tiCheckers.ITestingHooks), { close: () => socket.end(), }); } @@ -61,12 +63,12 @@ export class TestingHooks implements ITestingHooks { private _workerServers: FlexServer[] ) {} - public getOwnPort(): number { + public async getOwnPort(): Promise { log.info("TestingHooks.getOwnPort called"); return this._server.getOwnPort(); } - public getPort(): number { + public async getPort(): Promise { log.info("TestingHooks.getPort called"); return this._port; } @@ -100,7 +102,7 @@ export class TestingHooks implements ITestingHooks { log.info("TestingHooks.setServerVersion called with", version); this._comm.setServerVersion(version); for (const server of this._workerServers) { - await server.comm.setServerVersion(version); + server.comm.setServerVersion(version); } } @@ -108,7 +110,7 @@ export class TestingHooks implements ITestingHooks { log.info("TestingHooks.disconnectClients called"); this._comm.destroyAllClients(); for (const server of this._workerServers) { - await server.comm.destroyAllClients(); + server.comm.destroyAllClients(); } } @@ -134,7 +136,7 @@ export class TestingHooks implements ITestingHooks { log.info("TestingHooks.setClientPersistence called with", ttlMs); this._comm.testSetClientPersistence(ttlMs); for (const server of this._workerServers) { - await server.comm.testSetClientPersistence(ttlMs); + server.comm.testSetClientPersistence(ttlMs); } } @@ -174,7 +176,7 @@ export class TestingHooks implements ITestingHooks { log.info("TestingHooks.flushAuthorizerCache called"); this._server.dbManager.flushDocAuthCache(); for (const server of this._workerServers) { - await server.dbManager.flushDocAuthCache(); + server.dbManager.flushDocAuthCache(); } } diff --git a/app/server/lib/uploads.ts b/app/server/lib/uploads.ts index 783a9db5..d265a3bf 100644 --- a/app/server/lib/uploads.ts +++ b/app/server/lib/uploads.ts @@ -316,7 +316,7 @@ export async function createTmpDir(options: tmp.Options): Promise try { // Still call the original callback, so that `tmp` module doesn't keep remembering about // this directory and doesn't try to delete it again on exit. - tmpCleanup(); + await tmpCleanup(); } catch (err) { // OK if it fails because the dir is already removed. } diff --git a/buildtools/tsconfig-base.json b/buildtools/tsconfig-base.json index be751b6b..093af4f5 100644 --- a/buildtools/tsconfig-base.json +++ b/buildtools/tsconfig-base.json @@ -21,7 +21,7 @@ }, "composite": true, "plugins": [{ - "name": "typescript-tslint-plugin" + "name": "typescript-eslint-language-service" }], "emitDecoratorMetadata": true, "experimentalDecorators": true, diff --git a/stubs/app/client/ui/CustomThemes.ts b/stubs/app/client/ui/CustomThemes.ts index bbf8d591..443ea965 100644 --- a/stubs/app/client/ui/CustomThemes.ts +++ b/stubs/app/client/ui/CustomThemes.ts @@ -4,7 +4,7 @@ export type ProductFlavor = string; export interface CustomTheme { bodyClassName?: string; wideLogo?: boolean; -}; +} export function getTheme(flavor: string): CustomTheme { return { diff --git a/test/nbrowser/gristUtils.ts b/test/nbrowser/gristUtils.ts index d8ca1328..09c2c07c 100644 --- a/test/nbrowser/gristUtils.ts +++ b/test/nbrowser/gristUtils.ts @@ -15,7 +15,7 @@ import { decodeUrl } from 'app/common/gristUrls'; import { FullUser, UserProfile } from 'app/common/LoginSessionAPI'; import { resetOrg } from 'app/common/resetOrg'; import { TestState } from 'app/common/TestState'; -import { DocStateComparison, Organization as APIOrganization, UserAPIImpl, Workspace } from 'app/common/UserAPI'; +import { Organization as APIOrganization, DocStateComparison, UserAPIImpl, Workspace } from 'app/common/UserAPI'; import { Organization } from 'app/gen-server/entity/Organization'; import { Product } from 'app/gen-server/entity/Product'; import { create } from 'app/server/lib/create'; @@ -163,7 +163,7 @@ export async function selectAll() { * Returns a WebElementPromise for the .viewsection_content element for the section which contains * the given RegExp content. */ -export function getSection(sectionOrTitle: string|WebElement): WebElement { +export function getSection(sectionOrTitle: string|WebElement): WebElement|WebElementPromise { if (typeof sectionOrTitle !== 'string') { return sectionOrTitle; } return driver.find(`.test-viewsection-title[value="${sectionOrTitle}" i]`) .findClosest('.viewsection_content'); @@ -1187,7 +1187,7 @@ export class Session { // Wipe the current site. The current user ends up being its only owner and manager. public async resetSite() { - return resetOrg(await this.createHomeApi(), this.settings.org); + return resetOrg(this.createHomeApi(), this.settings.org); } // Return a session configured for the current session's site but a different user. diff --git a/test/nbrowser/testServer.ts b/test/nbrowser/testServer.ts index 0e99c91b..9556bcf8 100644 --- a/test/nbrowser/testServer.ts +++ b/test/nbrowser/testServer.ts @@ -55,7 +55,7 @@ export class TestServerMerged implements IMochaServer { public async restart(reset: boolean = false) { if (this.isExternalServer()) { return; } if (this._starts > 0) { - await this.resume(); + this.resume(); await this.stop(); } this._starts++;