Commit 3484ed34 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat(api): add new `removeText()` method to `ErrorFixer`

parent 17b64af0
Loading
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -42,3 +42,70 @@ declare const location: Location;
/* replace the text at given location with "lorem ipsum" */
fixer.replaceText(location, "lorem ipsum");
```

## `removeText` method

Removes the text at location, optionally trimming whitespace before or after.

**Syntax**

```ts nocompile nolint
removeText(location, [options]);
```

**Return value**

This method has no return value.

**Parameters**

- `location: Location`: The location of text to remove.
- `options.trimStart: boolean` (optional): Remove whitespace characters before the specified location, up to and including a single newline if present. Defaults to `false`.
- `options.trimEnd: boolean` (optional): Remove whitespace characters after the specified location, up to and including a single newline if present. Defaults to `false`.

**Example**

Given an element with the `foo` attribute:

```html
<div foo="bar"></div>
```

To remove the attribute:

```ts
import { type Attribute, type ErrorFixer } from "html-validate";

declare const fixer: ErrorFixer;
declare const attr: Attribute;

/* --- */

fixer.removeText(attr.location);
```

After removal the result would be:

<!-- prettier-ignore -->
```html
<div ></div>
```

The whitespace before the attribute can be trimmed:

```ts
import { type Attribute, type ErrorFixer } from "html-validate";

declare const fixer: ErrorFixer;
declare const attr: Attribute;

/* --- */

fixer.removeText(attr.location, { trimStart: true });
```

Resulting in `<div>` instead of `<div >`:

```html
<div></div>
```
+4 −0
Original line number Diff line number Diff line
@@ -449,6 +449,10 @@ export interface ErrorDescriptor<ContextType> {

// @public
export interface ErrorFixer {
    removeText(location: Location_2, options?: {
        trimStart?: boolean;
        trimEnd?: boolean;
    }): void;
    replaceText(location: Location_2, replacement: string): void;
}

+4 −0
Original line number Diff line number Diff line
@@ -499,6 +499,10 @@ export interface ErrorDescriptor<ContextType> {

// @public
export interface ErrorFixer {
    removeText(location: Location_2, options?: {
        trimStart?: boolean;
        trimEnd?: boolean;
    }): void;
    replaceText(location: Location_2, replacement: string): void;
}

+23 −1
Original line number Diff line number Diff line
import { describe, expect, it } from "@jest/globals";
import { type Location } from "../location";
import { applyTextEdits } from "./apply-text-edits";
import { type TextEditReplace, TextEditKind } from "./text-edit";
import { type TextEditRemove, type TextEditReplace, TextEditKind } from "./text-edit";

function loc(offset: number, size: number, filename = "test.html"): Location {
	return { filename, offset, line: 1, column: offset + 1, size };
@@ -11,12 +11,24 @@ function replaceText(location: Location, replacement: string): TextEditReplace {
	return { kind: TextEditKind.Replace, location, replacement };
}

function removeText(location: Location): TextEditRemove {
	return { kind: TextEditKind.Remove, location };
}

describe("applyTextEdits()", () => {
	it("should return source unchanged when there are no edits", () => {
		expect.assertions(1);
		const text = '<div foo="bar"></div>';
		expect(applyTextEdits("test.html", text, [])).toBe(text);
	});

	it("should detect overlapping edits regardless of kind", () => {
		expect.assertions(1);
		const text = "lorem ipsum dolor sit amet";
		expect(() => {
			applyTextEdits("test.html", text, [removeText(loc(0, 11)), replaceText(loc(5, 3), "x")]);
		}).toThrow(/Overlapping edits/);
	});
});

describe("replaceText()", () => {
@@ -126,3 +138,13 @@ describe("replaceText()", () => {
		expect(result).toBe('<div ab"bar"></div>');
	});
});

describe("removeText()", () => {
	it("should remove text", () => {
		expect.assertions(1);
		const text = "lorem ipsum dolor sit amet";
		const location = loc(text.indexOf("ipsum"), "ipsum".length);
		const result = applyTextEdits("test.html", text, [removeText(location)]);
		expect(result).toBe("lorem  dolor sit amet");
	});
});
+5 −0
Original line number Diff line number Diff line
@@ -37,6 +37,11 @@ function applyTextEdit(text: string, edit: TextEdit): string {
			const { offset, size } = location;
			return text.slice(0, offset) + replacement + text.slice(offset + size);
		}
		case TextEditKind.Remove: {
			const { location } = edit;
			const { offset, size } = location;
			return text.slice(0, offset) + text.slice(offset + size);
		}
	}
}

Loading