Skip to content

Make BaseTarget parameters getters stricter #1534

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

Merged
merged 1 commit into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -15,20 +15,32 @@ import {
createContinuousRangeUntypedTarget,
} from "../targetUtil/createContinuousRange";

/** Parameters supported by most target classes */
export interface CommonTargetParameters {
/** Parameters supported by all target classes */
export interface MinimumTargetParameters {
readonly editor: TextEditor;
readonly isReversed: boolean;
readonly contentRange: Range;
readonly thatTarget?: Target;
}

/** Parameters supported by most target classes */
export interface CommonTargetParameters extends MinimumTargetParameters {
readonly contentRange: Range;
}

export interface CloneWithParameters {
readonly thatTarget?: Target;
readonly contentRange?: Range;
}

export default abstract class BaseTarget implements Target {
/**
* An abstract target. All targets subclass this.
*
* @template TParameters The constructor parameters.
*/
export default abstract class BaseTarget<
in out TParameters extends MinimumTargetParameters,
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain why you used in out here?

> implements Target
{
protected readonly state: CommonTargetParameters;
isLine = false;
isToken = true;
Expand All @@ -39,7 +51,7 @@ export default abstract class BaseTarget implements Target {
isNotebookCell = false;
isWord = false;

constructor(parameters: CommonTargetParameters) {
constructor(parameters: TParameters & CommonTargetParameters) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This ensures that whatever type is declared actually ends up existing in the subclass constructor somehow.

Copy link
Member

@pokey pokey Jun 15, 2023

Choose a reason for hiding this comment

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

oh really? so the type signature of the base class constructor influences the type signature of derived class constructors? That's surprising to me. And I'm not sure how that works in the case where the derived class uses minimum parameters instead of common parameters

this.state = {
editor: parameters.editor,
isReversed: parameters.isReversed,
Expand Down Expand Up @@ -112,16 +124,16 @@ export default abstract class BaseTarget implements Target {
throw new NoContainingScopeError("boundary");
}

readonly cloneWith = (parameters: CloneWithParameters) => {
private cloneWith(parameters: CloneWithParameters) {
const constructor = Object.getPrototypeOf(this).constructor;

return new constructor({
...this.getCloneParameters(),
...parameters,
});
};
}

protected abstract getCloneParameters(): object;
protected abstract getCloneParameters(): TParameters;

createContinuousRangeTarget(
isReversed: boolean,
Expand Down Expand Up @@ -170,9 +182,8 @@ export default abstract class BaseTarget implements Target {
*
* @returns The object to be used for determining equality
*/
protected getEqualityParameters(): object {
const { thatTarget, ...otherCloneParameters } =
this.getCloneParameters() as { thatTarget?: Target };
protected getEqualityParameters(): Omit<TParameters, "thatTarget"> {
const { thatTarget, ...otherCloneParameters } = this.getCloneParameters();

return {
...otherCloneParameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { shrinkRangeToFitContent } from "../../util/selectionUtils";
import BaseTarget, { CommonTargetParameters } from "./BaseTarget";
import PlainTarget from "./PlainTarget";

export default class DocumentTarget extends BaseTarget {
export default class DocumentTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "\n";
isLine = true;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { CommonTargetParameters } from "./BaseTarget";
import BaseTarget from "./BaseTarget";

/**
Expand All @@ -6,7 +7,7 @@ import BaseTarget from "./BaseTarget";
* - The implicit destination in the command `"bring air"`
* - The implicit anchor in the range `"take past air"`
*/
export default class ImplicitTarget extends BaseTarget {
export default class ImplicitTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "";
isRaw = true;
hasExplicitScopeType = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import {
createContinuousRangeFromRanges,
createContinuousRangeUntypedTarget,
} from "../targetUtil/createContinuousRange";
import BaseTarget, { CommonTargetParameters } from "./BaseTarget";
import type { MinimumTargetParameters } from "./BaseTarget";
import BaseTarget from "./BaseTarget";

export interface InteriorTargetParameters
extends Omit<CommonTargetParameters, "contentRange"> {
export interface InteriorTargetParameters extends MinimumTargetParameters {
readonly fullInteriorRange: Range;
}

export default class InteriorTarget extends BaseTarget {
export default class InteriorTarget extends BaseTarget<InteriorTargetParameters> {
insertionDelimiter = " ";
private readonly fullInteriorRange: Range;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Target } from "../../typings/target.types";
import { expandToFullLine } from "../../util/rangeUtils";
import { tryConstructPlainTarget } from "../../util/tryConstructTarget";
import { createContinuousLineRange } from "../targetUtil/createContinuousRange";
import type { CommonTargetParameters } from "./BaseTarget";
import BaseTarget from "./BaseTarget";

export default class LineTarget extends BaseTarget {
export default class LineTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "\n";
isLine = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TargetPosition } from "@cursorless/common";
import BaseTarget, { CommonTargetParameters } from "./BaseTarget";
import { removalUnsupportedForPosition } from "./PositionTarget";

export default class NotebookCellTarget extends BaseTarget {
export default class NotebookCellTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "\n";
isNotebookCell = true;

Expand Down Expand Up @@ -32,7 +32,7 @@ interface NotebookCellPositionTargetParameters extends CommonTargetParameters {
readonly position: TargetPosition;
}

export class NotebookCellPositionTarget extends BaseTarget {
export class NotebookCellPositionTarget extends BaseTarget<NotebookCellPositionTargetParameters> {
insertionDelimiter = "\n";
isNotebookCell = true;
public position: TargetPosition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import { expandToFullLine } from "../../util/rangeUtils";
import { constructLineTarget } from "../../util/tryConstructTarget";
import { isSameType } from "../../util/typeUtils";
import { createContinuousLineRange } from "../targetUtil/createContinuousRange";
import type { CommonTargetParameters } from "./BaseTarget";
import BaseTarget from "./BaseTarget";
import LineTarget from "./LineTarget";

export default class ParagraphTarget extends BaseTarget {
export default class ParagraphTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "\n\n";
isLine = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface PlainTargetParameters extends CommonTargetParameters {
* A target that has no leading or trailing delimiters so it's removal range
* just consists of the content itself. Its insertion delimiter is empty string.
*/
export default class PlainTarget extends BaseTarget {
export default class PlainTarget extends BaseTarget<PlainTargetParameters> {
insertionDelimiter = "";

constructor(parameters: PlainTargetParameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface PositionTargetParameters extends CommonTargetParameters {
readonly isRaw: boolean;
}

export default class PositionTarget extends BaseTarget {
export default class PositionTarget extends BaseTarget<PositionTargetParameters> {
insertionDelimiter: string;
isRaw: boolean;
private position: TargetPosition;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { CommonTargetParameters } from "./BaseTarget";
import BaseTarget from "./BaseTarget";

/**
* A target that has no leading or trailing delimiters so it's removal range
* just consists of the content itself. Its insertion delimiter will be
* inherited from the source in the case of a bring after a bring before
*/
export default class RawSelectionTarget extends BaseTarget {
export default class RawSelectionTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = "";
isRaw = true;
isToken = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface ScopeTypeTargetParameters extends CommonTargetParameters {
readonly trailingDelimiterRange?: Range;
}

export default class ScopeTypeTarget extends BaseTarget {
export default class ScopeTypeTarget extends BaseTarget<ScopeTypeTargetParameters> {
private scopeTypeType_: SimpleScopeTypeType;
private removalRange_?: Range;
private interiorRange_?: Range;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface SubTokenTargetParameters extends CommonTargetParameters {
readonly trailingDelimiterRange?: Range;
}

export default class SubTokenWordTarget extends BaseTarget {
export default class SubTokenWordTarget extends BaseTarget<SubTokenTargetParameters> {
private leadingDelimiterRange_?: Range;
private trailingDelimiterRange_?: Range;
insertionDelimiter: string;
Expand Down Expand Up @@ -43,11 +43,12 @@ export default class SubTokenWordTarget extends BaseTarget {
return getDelimitedSequenceRemovalRange(this);
}

protected getCloneParameters() {
protected getCloneParameters(): SubTokenTargetParameters {
return {
...this.state,
leadingDelimiterRange: this.leadingDelimiterRange_,
trailingDelimiterRange: this.trailingDelimiterRange_,
insertionDelimiter: this.insertionDelimiter,
Copy link
Member Author

Choose a reason for hiding this comment

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

All this ceremony wasn't for nothing, it seems! I added the return type here for autocomplete.

Copy link
Member

@pokey pokey Jun 15, 2023

Choose a reason for hiding this comment

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

So you don't get autocomplete for free from the generic at the top / base class function? Not that I'm opposed to extra return type annotations 🤷‍♂️

};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface SurroundingPairTargetParameters extends CommonTargetParameters {
readonly boundary: [Range, Range];
}

export default class SurroundingPairTarget extends BaseTarget {
export default class SurroundingPairTarget extends BaseTarget<SurroundingPairTargetParameters> {
insertionDelimiter = " ";
private interiorRange_: Range;
private boundary_: [Range, Range];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
getTokenRemovalRange,
getTokenTrailingDelimiterTarget,
} from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior";
import type { CommonTargetParameters } from "./BaseTarget";

export default class TokenTarget extends BaseTarget {
export default class TokenTarget extends BaseTarget<CommonTargetParameters> {
insertionDelimiter = " ";

getLeadingDelimiterTarget(): Target | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface UntypedTargetParameters extends CommonTargetParameters {
* - Use token delimiters (space) for removal and insertion
* - Expand to nearest containing pair when asked for boundary or interior
*/
export default class UntypedTarget extends BaseTarget {
export default class UntypedTarget extends BaseTarget<UntypedTargetParameters> {
insertionDelimiter = " ";
hasExplicitScopeType = false;

Expand Down