Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(container-runtime): Enable various eslint rules from our "recommended" config and fix violations #23609

Open
wants to merge 46 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0075c94
tools: Enable `@typescript-eslint/explicit-module-boundary-types` rule
Josmithr Jan 16, 2025
e6f0bea
refactor: Add explicit return types
Josmithr Jan 17, 2025
0db2f45
refactor: Add missing return types
Josmithr Jan 17, 2025
8ec1c28
refactor: Add missing return types
Josmithr Jan 17, 2025
6ceb240
refactor: Add missing return types
Josmithr Jan 17, 2025
29a0478
refactor: Add missing return types
Josmithr Jan 17, 2025
665a2ad
refactor: Add missing return types
Josmithr Jan 17, 2025
b8fe27d
docs: Update comment syntax
Josmithr Jan 17, 2025
66bad2c
refactor: Add missing return types
Josmithr Jan 17, 2025
ce5ea31
docs: Revert docs changes
Josmithr Jan 17, 2025
afb9b1e
refactor: Add missing return types
Josmithr Jan 17, 2025
a19695c
docs: Fix comment syntax
Josmithr Jan 17, 2025
e89080e
refactor: Add explicit return types
Josmithr Jan 17, 2025
90b9ea9
docs: Comment cleanup
Josmithr Jan 17, 2025
78916eb
refactor: Add explicit return types
Josmithr Jan 17, 2025
05cbdf9
refactor: Add missing return types
Josmithr Jan 17, 2025
3fe78ee
revert: Type signature change
Josmithr Jan 17, 2025
80374c1
fix: Linter issue
Josmithr Jan 17, 2025
78aa022
Merge branch 'main' into container-runtime/eslint/more-recommended-rules
Josmithr Jan 17, 2025
b6346f9
docs: Fix link
Josmithr Jan 17, 2025
1d2beed
refactor: Add missing return types
Josmithr Jan 17, 2025
4ef6b69
tools: Update config
Josmithr Jan 17, 2025
a4821be
refactor: Add missing return types
Josmithr Jan 17, 2025
c654f15
refactor: Add missing return types
Josmithr Jan 17, 2025
d5deb1a
refactor: Add missing return types
Josmithr Jan 17, 2025
e571f95
refactor: Add missing return types
Josmithr Jan 17, 2025
996b5a1
Merge branch 'main' into container-runtime/eslint/more-recommended-ru…
Josmithr Jan 17, 2025
a44d6e8
Merge branch 'main' into container-runtime/eslint/more-recommended-ru…
Josmithr Jan 17, 2025
bb32988
refactor: Enable `unicorn/catch-error-name` and fix violations
Josmithr Jan 17, 2025
c316bee
refactor: Enable `unicorn/new-for-builtins` rule and fix violations
Josmithr Jan 17, 2025
0bda13e
refactor: Enable `unicorn/no-array-callback-reference` rule and fix v…
Josmithr Jan 17, 2025
2a2f48b
refactor: Enable `unicorn/no-array-for-each` rule and fix violations
Josmithr Jan 17, 2025
ae5591c
tools: Disable `unicorn/no-array-push-push` rule
Josmithr Jan 17, 2025
fd4ff79
refactor: Enable `unicorn/no-zero-fractions` rule and fix violations
Josmithr Jan 17, 2025
05e84a1
refactor: Enable `unicorn/prefer-node-protocol` rule and fix violations
Josmithr Jan 17, 2025
1936b9e
refactor: Enable `unicorn/prefer-number-properties` rule and fix viol…
Josmithr Jan 17, 2025
8f1ca39
refactor: Enable `unicorn/prefer-optional-catch-binding` rule and fix…
Josmithr Jan 17, 2025
8a7dd98
refactor: Enable `unicorn/prefer-spread` rule and fix violations
Josmithr Jan 17, 2025
a7cb6bd
refactor: Enable `unicorn/switch-case-braces` rule and fix violations
Josmithr Jan 17, 2025
c28fcd8
tools: Enable `unicorn/throw-new-error` rule (no violations)
Josmithr Jan 17, 2025
125a325
refactor: Enable `unicorn/no-null` rule and fix/ignore violations
Josmithr Jan 17, 2025
54e802e
refactor: Enable `unicorn/consistent-destructuring` rule and fix/igno…
Josmithr Jan 17, 2025
58bf24a
refactor: Enable `unicorn/prefer-string-slice` rule and fix violation
Josmithr Jan 17, 2025
032f9b8
docs: Update TODOs
Josmithr Jan 17, 2025
d6a85ab
Merge branch 'main' into container-runtime/eslint/more-recommended-ru…
Josmithr Jan 17, 2025
48b0a8d
docs: Add work item numbers to TODOs
Josmithr Jan 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1297,7 +1297,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1371,7 +1371,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1297,7 +1297,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
2 changes: 1 addition & 1 deletion common/build/eslint-config-fluid/printed-configs/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -1302,7 +1302,7 @@
"error"
],
"unicorn/no-array-push-push": [
"error"
"off"
],
"unicorn/no-array-reduce": [
"error"
Expand Down
7 changes: 7 additions & 0 deletions common/build/eslint-config-fluid/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ module.exports = {
},
],

// #region `unicorn` rule overrides

// False positives on non-array `push` methods.
"unicorn/no-array-push-push": "off",

"unicorn/empty-brace-spaces": "off",

// Rationale: Destructuring of `Array.entries()` in order to get the index variable results in a
Expand Down Expand Up @@ -108,6 +113,8 @@ module.exports = {
*/
"unicorn/expiring-todo-comments": "off",

// #endregion

/**
* Disallows the `any` type.
* Using the `any` type defeats the purpose of using TypeScript.
Expand Down
30 changes: 29 additions & 1 deletion packages/runtime/container-runtime/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ module.exports = {
"@typescript-eslint/strict-boolean-expressions": "off",
"@fluid-internal/fluid/no-unchecked-record-access": "warn",

// False positives on non-array `push` methods.
// TODO:AB#28686: remove this override once this rule has been disabled in the root config.
"unicorn/no-array-push-push": "off",

// #region TODO:AB#3027: remove overrides and upgrade config to `recommended`

"@typescript-eslint/explicit-function-return-type": [
Expand Down Expand Up @@ -46,6 +50,30 @@ module.exports = {
"jsdoc/multiline-blocks": ["error", { noSingleLineBlocks: true }],
"jsdoc/require-description": ["error", { checkConstructors: false }],

"unicorn/catch-error-name": "error",
"unicorn/consistent-destructuring": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-array-callback-reference": "error",
"unicorn/no-array-for-each": "error",
"unicorn/no-null": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-spread": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/switch-case-braces": "error",
"unicorn/throw-new-error": "error",

// TODO:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future PR (trying to keep these PRs somewhat scoped so they're easier to review)

// unicorn/consistent-function-scoping
// unicorn/no-negated-condition
// unicorn/no-lonely-if
// unicorn/no-new-array
// unicorn/prefer-includes
// unicorn/error-message
// unicorn/explicit-length-check

// #endregion
},
overrides: [
Expand All @@ -57,7 +85,7 @@ module.exports = {
"@typescript-eslint/explicit-function-return-type": "off",

// Test files are run in node only so additional node libraries can be used.
"import/no-nodejs-modules": ["error", { allow: ["assert", "crypto"] }],
"import/no-nodejs-modules": ["error", { allow: ["node:assert", "node:crypto"] }],
Josmithr marked this conversation as resolved.
Show resolved Hide resolved
},
},
],
Expand Down
22 changes: 11 additions & 11 deletions packages/runtime/container-runtime/src/blobManager/blobManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
this.redirectTable = toRedirectTable(snapshot, this.mc.logger, this.runtime.attachState);

// Begin uploading stashed blobs from previous container instance
Object.entries(stashedBlobs ?? {}).forEach(([localId, entry]) => {
for (const [localId, entry] of Object.entries(stashedBlobs ?? {})) {
const { acked, storageId, minTTLInSeconds, uploadTime } = entry;
const blob = stringToBuffer(entry.blob, "base64");
const pendingEntry: PendingBlob = {
Expand All @@ -260,7 +260,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
const timeLapseSinceLocalUpload = (Date.now() - uploadTime) / 1000;
// stashed entries with more than half-life in storage will not be reuploaded
if (minTTLInSeconds - timeLapseSinceLocalUpload > minTTLInSeconds / 2) {
return;
continue;
}
}
this.pendingStashedBlobs.set(localId, this.uploadBlob(localId, blob));
Expand All @@ -269,7 +269,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
...stashedPendingBlobOverrides,
uploadP: this.pendingStashedBlobs.get(localId),
});
});
}

this.stashedBlobsUploadP = new LazyPromise(async () =>
PerformanceEvent.timedExecAsync(
Expand Down Expand Up @@ -337,7 +337,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
}

public hasPendingStashedUploads(): boolean {
return Array.from(this.pendingBlobs.values()).some((e) => e.stashedUpload === true);
return [...this.pendingBlobs.values()].some((e) => e.stashedUpload === true);
}

public async getBlob(blobId: string): Promise<ArrayBufferLike> {
Expand Down Expand Up @@ -588,10 +588,10 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
// If there is already an op for this storage ID, append the local ID to the list. Once any op for
// this storage ID is ack'd, all pending blobs for it can be resolved since the op will keep the
// blob alive in storage.
this.opsInFlight.set(
response.id,
(this.opsInFlight.get(response.id) ?? []).concat(localId),
);
this.opsInFlight.set(response.id, [
...(this.opsInFlight.get(response.id) ?? []),
localId,
]);
}
return response;
}
Expand Down Expand Up @@ -648,7 +648,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
// For each op corresponding to this storage ID that we are waiting for, resolve the pending blob.
// This is safe because the server will keep the blob alive and the op containing the local ID to
// storage ID is already in flight and any op containing this local ID will be sequenced after that.
waitingBlobs.forEach((pendingLocalId) => {
for (const pendingLocalId of waitingBlobs) {
const entry = this.pendingBlobs.get(pendingLocalId);
assert(
entry !== undefined,
Expand All @@ -658,7 +658,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
entry.acked = true;
entry.handleP.resolve(this.getBlobHandle(pendingLocalId));
this.deletePendingBlobMaybe(pendingLocalId);
});
}
this.opsInFlight.delete(blobId);
}
const localEntry = this.pendingBlobs.get(localId);
Expand Down Expand Up @@ -703,7 +703,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
*/
public deleteSweepReadyNodes(sweepReadyBlobRoutes: readonly string[]): readonly string[] {
this.deleteBlobsFromRedirectTable(sweepReadyBlobRoutes);
return Array.from(sweepReadyBlobRoutes);
return [...sweepReadyBlobRoutes];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export const toRedirectTable = (
if (snapshot.ids) {
// If we are detached, we don't have storage IDs yet, so set to undefined
// Otherwise, set identity (id -> id) entries.
snapshot.ids.forEach((entry) => redirectTable.set(entry, detached ? undefined : entry));
for (const entry of snapshot.ids) {
redirectTable.set(entry, detached ? undefined : entry);
}
}
return redirectTable;
};
Expand All @@ -90,22 +92,19 @@ const summarizeV1 = (
const storageIds = getStorageIds(redirectTable, attachState);

// if storageIds is empty, it means we are detached and have only local IDs, or that there are no blobs attached
const blobIds =
storageIds.size > 0 ? Array.from(storageIds) : Array.from(redirectTable.keys());
const blobIds = storageIds.size > 0 ? [...storageIds] : [...redirectTable.keys()];
const builder = new SummaryTreeBuilder();
blobIds.forEach((blobId) => {
for (const blobId of blobIds) {
builder.addAttachment(blobId);
});
}

// Any non-identity entries in the table need to be saved in the summary
if (redirectTable.size > blobIds.length) {
builder.addBlob(
redirectTableBlobName,
// filter out identity entries
JSON.stringify(
Array.from(redirectTable.entries()).filter(
([localId, storageId]) => localId !== storageId,
),
[...redirectTable.entries()].filter(([localId, storageId]) => localId !== storageId),
),
);
}
Expand Down
59 changes: 34 additions & 25 deletions packages/runtime/container-runtime/src/channelCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,13 +707,16 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
public reSubmit(type: string, content: unknown, localOpMetadata: unknown): void {
switch (type) {
case ContainerMessageType.Attach:
case ContainerMessageType.Alias:
case ContainerMessageType.Alias: {
this.parentContext.submitMessage(type, content, localOpMetadata);
return;
case ContainerMessageType.FluidDataStoreOp:
}
case ContainerMessageType.FluidDataStoreOp: {
return this.reSubmitChannelOp(type, content, localOpMetadata);
default:
}
default: {
assert(false, 0x907 /* unknown op type */);
}
}
}

Expand Down Expand Up @@ -757,14 +760,18 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
public async applyStashedOp(content: unknown): Promise<unknown> {
const opContents = content as LocalContainerRuntimeMessage;
switch (opContents.type) {
case ContainerMessageType.Attach:
case ContainerMessageType.Attach: {
return this.applyStashedAttachOp(opContents.contents);
case ContainerMessageType.Alias:
}
case ContainerMessageType.Alias: {
return;
case ContainerMessageType.FluidDataStoreOp:
}
case ContainerMessageType.FluidDataStoreOp: {
return this.applyStashedChannelChannelOp(opContents.contents);
default:
}
default: {
assert(false, 0x908 /* unknon type of op */);
}
}
}

Expand Down Expand Up @@ -821,7 +828,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
// if the client is not detached put in the pending attach list
// so that on ack of the stashed op, the context is found.
// detached client don't send ops, so should not expect and ack.
this.pendingAttach.set(message.id, message);
this.pendingAttach.set(id, message);
}
}

Expand All @@ -831,17 +838,21 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
*/
public processMessages(messageCollection: IRuntimeMessageCollection): void {
switch (messageCollection.envelope.type) {
case ContainerMessageType.FluidDataStoreOp:
case ContainerMessageType.FluidDataStoreOp: {
this.processChannelMessages(messageCollection);
break;
case ContainerMessageType.Attach:
}
case ContainerMessageType.Attach: {
this.processAttachMessages(messageCollection);
break;
case ContainerMessageType.Alias:
}
case ContainerMessageType.Alias: {
this.processAliasMessages(messageCollection);
break;
default:
}
default: {
assert(false, 0x8e9 /* unreached */);
}
}
}

Expand Down Expand Up @@ -874,7 +885,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
* @param messageCollection - The collection of messages to process.
*/
private processChannelMessages(messageCollection: IRuntimeMessageCollection): void {
const { messagesContent, local } = messageCollection;
const { envelope, messagesContent, local } = messageCollection;
let currentMessageState: { address: string; type: string } | undefined;
let currentMessagesContent: IRuntimeMessagesContent[] = [];

Expand All @@ -888,7 +899,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
assert(!!currentContext, 0xa66 /* Context not found */);

currentContext.processMessages({
envelope: { ...messageCollection.envelope, type: currentMessageState.type },
envelope: { ...envelope, type: currentMessageState.type },
messagesContent: currentMessagesContent,
local,
});
Expand Down Expand Up @@ -916,11 +927,11 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
throw DataProcessingError.create(
"No context for op",
"processFluidDataStoreOp",
messageCollection.envelope as ISequencedDocumentMessage,
envelope as ISequencedDocumentMessage,
{
local,
messageDetails: JSON.stringify({
type: messageCollection.envelope.type,
type: envelope.type,
contentType: typeof contents,
}),
...tagCodeArtifacts({ address }),
Expand Down Expand Up @@ -948,16 +959,12 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
this.gcNodeUpdated({
node: { type: "DataStore", path: `/${address}` },
reason: "Changed",
timestampMs: messageCollection.envelope.timestamp,
timestampMs: envelope.timestamp,
packagePath: context.isLoaded ? context.packagePath : undefined,
});

detectOutboundReferences(address, contextContents, (fromPath: string, toPath: string) =>
this.parentContext.addedGCOutboundRoute(
fromPath,
toPath,
messageCollection.envelope.timestamp,
),
this.parentContext.addedGCOutboundRoute(fromPath, toPath, envelope.timestamp),
);
}

Expand Down Expand Up @@ -1200,7 +1207,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
},
);
// Get the outbound routes (aliased data stores) and add a GC node for this channel.
builder.addNode("/", Array.from(this.aliasedDataStores));
builder.addNode("/", [...this.aliasedDataStores]);
return builder.getGCData();
}

Expand Down Expand Up @@ -1412,7 +1419,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {

this.deleteChild(dataStoreId);
}
return Array.from(sweepReadyDataStoreRoutes);
return [...sweepReadyDataStoreRoutes];
}

/**
Expand Down Expand Up @@ -1613,7 +1620,9 @@ export function detectOutboundReferences(
// GC node paths are all absolute paths, hence the "" prefix.
// e.g. this will yield "/dataStoreId/ddsId"
const fromPath = ["", address, ddsAddress].join("/");
outboundPaths.forEach((toPath) => addedOutboundReference(fromPath, toPath));
for (const toPath of outboundPaths) {
addedOutboundReference(fromPath, toPath);
}
}

/**
Expand Down
Loading
Loading