Skip to content

Commit

Permalink
feat: add experimental support for generics directive (#477)
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi committed Mar 3, 2024
1 parent 122d318 commit 5f2b111
Show file tree
Hide file tree
Showing 61 changed files with 62,992 additions and 95 deletions.
5 changes: 5 additions & 0 deletions .changeset/twelve-bulldogs-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-eslint-parser": minor
---

feat: add experimental support for generics directive
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,24 @@ module.exports = {
}
```

### parserOptions.svelteFeatures

You can use `parserOptions.svelteFeatures` property to specify how to parse related to Svelte features. For example:

```json
{
"parser": "svelte-eslint-parser",
"parserOptions": {
"svelteFeatures": {
/* -- Experimental Svelte Features -- */
// Whether to parse the `generics` attribute.
// See https://github.com/sveltejs/rfcs/pull/38
"experimentalGenerics": false
}
}
}
```

### Runes support

***This is an experimental feature. It may be changed or removed in minor versions without notice.***
Expand Down
14 changes: 14 additions & 0 deletions docs/AST.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ interface SvelteStartTag extends Node {
| SvelteDirective
| SvelteStyleDirective
| SvelteSpecialDirective
| SvelteGenericsDirective
)[];
selfClosing: boolean;
}
Expand Down Expand Up @@ -362,6 +363,19 @@ interface SvelteSpecialDirectiveKey extends Node {
}
```

### SvelteGenericsDirective

This is the generics directive node.

```ts
interface SvelteGenericsDirective extends BaseNode {
type: "SvelteGenericsDirective";
key: SvelteName & { name: "generics" };
params: TSESTree.TSTypeParameter[];
parent: SvelteStartTag & { parent: SvelteScriptElement };
}
```

## Texts and Literals

### SvelteText
Expand Down
9 changes: 9 additions & 0 deletions src/ast/html.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type ESTree from "estree";
import type { TSESTree } from "@typescript-eslint/types";
import type { BaseNode } from "./base";
import type { Token, Comment } from "./common";

Expand Down Expand Up @@ -32,6 +33,7 @@ export type SvelteHTMLNode =
| SvelteDirective
| SvelteStyleDirective
| SvelteSpecialDirective
| SvelteGenericsDirective
| SvelteDirectiveKey
| SvelteSpecialDirectiveKey
| SvelteHTMLComment;
Expand Down Expand Up @@ -142,6 +144,7 @@ export interface SvelteStartTag extends BaseNode {
| SvelteDirective
| SvelteStyleDirective
| SvelteSpecialDirective
| SvelteGenericsDirective
)[];
selfClosing: boolean;
parent: SvelteElement | SvelteScriptElement | SvelteStyleElement;
Expand Down Expand Up @@ -651,3 +654,9 @@ export interface SvelteSpecialDirective extends BaseNode {
expression: ESTree.Expression;
parent: SvelteStartTag /* & { parent: SvelteSpecialElement } */;
}
export interface SvelteGenericsDirective extends BaseNode {
type: "SvelteGenericsDirective";
key: SvelteName & { name: "generics" };
params: TSESTree.TSTypeParameterDeclaration["params"];
parent: SvelteStartTag /* & { parent: SvelteScriptElement } */;
}
73 changes: 73 additions & 0 deletions src/context/fix-locations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type * as ESTree from "estree";
import type { Comment, Locations, Token } from "../ast";
import type { Context } from ".";
import { traverseNodes } from "../traverse";

/** Fix locations */
export function fixLocations(
node: ESTree.Node,
tokens: Token[],
comments: Comment[],
offset: number,
visitorKeys: { [type: string]: string[] } | undefined,
ctx: Context,
): void {
if (offset === 0) {
return;
}
const traversed = new Set<any>();
traverseNodes(node, {
visitorKeys,
enterNode: (n) => {
if (traversed.has(n)) {
return;
}
traversed.add(n);
if (traversed.has(n.range)) {
if (!traversed.has(n.loc)) {
// However, `Node#loc` may not be shared.
const locs = ctx.getConvertLocation({
start: n.range![0],
end: n.range![1],
});
applyLocs(n, locs);
traversed.add(n.loc);
}
} else {
const start = n.range![0] + offset;
const end = n.range![1] + offset;
const locs = ctx.getConvertLocation({ start, end });
applyLocs(n, locs);
traversed.add(n.range);
traversed.add(n.loc);
}
},
leaveNode: Function.prototype as any,
});
for (const t of tokens) {
const start = t.range[0] + offset;
const end = t.range[1] + offset;
const locs = ctx.getConvertLocation({ start, end });
applyLocs(t, locs);
}
for (const t of comments) {
const start = t.range[0] + offset;
const end = t.range[1] + offset;
const locs = ctx.getConvertLocation({ start, end });
applyLocs(t, locs);
}
}

/**
* applyLocs
*/
function applyLocs(target: Locations | ESTree.Node, locs: Locations) {
target.loc = locs.loc;
target.range = locs.range;
if (typeof (target as any).start === "number") {
delete (target as any).start;
}
if (typeof (target as any).end === "number") {
delete (target as any).end;
}
}
57 changes: 40 additions & 17 deletions src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ export class ScriptsSourceCode {

public readonly attrs: Record<string, string | undefined>;

private _separate = "";

private _appendScriptLets: string | null = null;
private _appendScriptLets: {
separate: string;
beforeSpaces: string;
render: string;
generics: string;
} | null = null;

public separateIndexes: number[] = [];

Expand All @@ -49,16 +52,28 @@ export class ScriptsSourceCode {
if (this._appendScriptLets == null) {
return this.raw;
}
return this.trimmedRaw + this._separate + this._appendScriptLets;
return (
this.trimmedRaw +
this._appendScriptLets.separate +
this._appendScriptLets.beforeSpaces +
this._appendScriptLets.render +
this._appendScriptLets.generics
);
}

public getCurrentVirtualCodeInfo(): { script: string; render: string } {
public getCurrentVirtualCodeInfo(): {
script: string;
render: string;
generics: string;
} {
if (this._appendScriptLets == null) {
return { script: this.raw, render: "" };
return { script: this.raw, render: "", generics: "" };
}
return {
script: this.trimmedRaw + this._separate,
render: this._appendScriptLets,
script: this.trimmedRaw + this._appendScriptLets.separate,
render:
this._appendScriptLets.beforeSpaces + this._appendScriptLets.render,
generics: this._appendScriptLets.generics,
};
}

Expand All @@ -68,22 +83,30 @@ export class ScriptsSourceCode {
}
return (
this.trimmedRaw.length +
this._separate.length +
this._appendScriptLets.length
this._appendScriptLets.separate.length +
this._appendScriptLets.beforeSpaces.length +
this._appendScriptLets.render.length +
this._appendScriptLets.generics.length
);
}

public addLet(letCode: string): { start: number; end: number } {
public addLet(
letCode: string,
kind: "generics" | "render",
): { start: number; end: number } {
if (this._appendScriptLets == null) {
this._appendScriptLets = "";
const currentLength = this.getCurrentVirtualCodeLength();
const currentLength = this.trimmedRaw.length;
this.separateIndexes = [currentLength, currentLength + 1];
this._separate += "\n;";
const after = this.raw.slice(this.getCurrentVirtualCodeLength());
this._appendScriptLets += after;
const after = this.raw.slice(currentLength + 2);
this._appendScriptLets = {
separate: "\n;",
beforeSpaces: after,
render: "",
generics: "",
};
}
const start = this.getCurrentVirtualCodeLength();
this._appendScriptLets += letCode;
this._appendScriptLets[kind] += letCode;
return {
start,
end: this.getCurrentVirtualCodeLength(),
Expand Down

0 comments on commit 5f2b111

Please sign in to comment.