@alexgorbatchev/typescript-ai-policy 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,20 @@
1
1
  import { readFileSync, writeFileSync } from "node:fs";
2
2
  import ts from "typescript";
3
- import type { ITextEdit } from "./types.ts";
3
+ import type { TextEdit } from "./types.ts";
4
4
 
5
- type IOffsetTextEdit = {
5
+ type OffsetTextEdit = {
6
6
  endOffset: number;
7
7
  newText: string;
8
8
  startOffset: number;
9
9
  };
10
10
 
11
- type IFileEditEntry = {
11
+ type FileEditEntry = {
12
12
  filePath: string;
13
- textEdits: readonly ITextEdit[];
13
+ textEdits: readonly TextEdit[];
14
14
  };
15
15
 
16
- function readFileEditEntries(textEdits: readonly ITextEdit[]): readonly IFileEditEntry[] {
17
- const textEditsByFilePath = new Map<string, ITextEdit[]>();
16
+ function readFileEditEntries(textEdits: readonly TextEdit[]): readonly FileEditEntry[] {
17
+ const textEditsByFilePath = new Map<string, TextEdit[]>();
18
18
 
19
19
  for (const textEdit of textEdits) {
20
20
  const existingTextEdits = textEditsByFilePath.get(textEdit.filePath);
@@ -32,7 +32,7 @@ function readFileEditEntries(textEdits: readonly ITextEdit[]): readonly IFileEdi
32
32
  }));
33
33
  }
34
34
 
35
- function compareOffsetTextEditsAscending(left: IOffsetTextEdit, right: IOffsetTextEdit): number {
35
+ function compareOffsetTextEditsAscending(left: OffsetTextEdit, right: OffsetTextEdit): number {
36
36
  if (left.startOffset !== right.startOffset) {
37
37
  return left.startOffset - right.startOffset;
38
38
  }
@@ -44,7 +44,7 @@ function compareOffsetTextEditsAscending(left: IOffsetTextEdit, right: IOffsetTe
44
44
  return left.newText.localeCompare(right.newText);
45
45
  }
46
46
 
47
- function compareOffsetTextEditsDescending(left: IOffsetTextEdit, right: IOffsetTextEdit): number {
47
+ function compareOffsetTextEditsDescending(left: OffsetTextEdit, right: OffsetTextEdit): number {
48
48
  return compareOffsetTextEditsAscending(right, left);
49
49
  }
50
50
 
@@ -53,7 +53,7 @@ function readOffset(positionContent: string, line: number, character: number): n
53
53
  return ts.getPositionOfLineAndCharacter(sourceFile, line, character);
54
54
  }
55
55
 
56
- function readOffsetTextEdit(content: string, textEdit: ITextEdit): IOffsetTextEdit {
56
+ function readOffsetTextEdit(content: string, textEdit: TextEdit): OffsetTextEdit {
57
57
  return {
58
58
  endOffset: readOffset(content, textEdit.end.line, textEdit.end.character),
59
59
  newText: textEdit.newText,
@@ -61,31 +61,31 @@ function readOffsetTextEdit(content: string, textEdit: ITextEdit): IOffsetTextEd
61
61
  };
62
62
  }
63
63
 
64
- function haveSameRange(left: IOffsetTextEdit, right: IOffsetTextEdit): boolean {
64
+ function haveSameRange(left: OffsetTextEdit, right: OffsetTextEdit): boolean {
65
65
  return left.startOffset === right.startOffset && left.endOffset === right.endOffset;
66
66
  }
67
67
 
68
- function isInsertion(edit: IOffsetTextEdit): boolean {
68
+ function isInsertion(edit: OffsetTextEdit): boolean {
69
69
  return edit.startOffset === edit.endOffset;
70
70
  }
71
71
 
72
- function haveSameInsertionPoint(left: IOffsetTextEdit, right: IOffsetTextEdit): boolean {
72
+ function haveSameInsertionPoint(left: OffsetTextEdit, right: OffsetTextEdit): boolean {
73
73
  return isInsertion(left) && isInsertion(right) && left.startOffset === right.startOffset;
74
74
  }
75
75
 
76
- function rangesOverlap(left: IOffsetTextEdit, right: IOffsetTextEdit): boolean {
76
+ function rangesOverlap(left: OffsetTextEdit, right: OffsetTextEdit): boolean {
77
77
  return left.startOffset < right.endOffset && right.startOffset < left.endOffset;
78
78
  }
79
79
 
80
- function containsRange(container: IOffsetTextEdit, candidate: IOffsetTextEdit): boolean {
80
+ function containsRange(container: OffsetTextEdit, candidate: OffsetTextEdit): boolean {
81
81
  return container.startOffset <= candidate.startOffset && container.endOffset >= candidate.endOffset;
82
82
  }
83
83
 
84
84
  function readNormalizedOffsetTextEdits(
85
85
  filePath: string,
86
- offsetTextEdits: readonly IOffsetTextEdit[],
87
- ): readonly IOffsetTextEdit[] {
88
- const normalizedOffsetTextEdits: IOffsetTextEdit[] = [];
86
+ offsetTextEdits: readonly OffsetTextEdit[],
87
+ ): readonly OffsetTextEdit[] {
88
+ const normalizedOffsetTextEdits: OffsetTextEdit[] = [];
89
89
 
90
90
  for (const offsetTextEdit of [...offsetTextEdits].sort(compareOffsetTextEditsAscending)) {
91
91
  const previousOffsetTextEdit = normalizedOffsetTextEdits.at(-1);
@@ -123,7 +123,7 @@ function readNormalizedOffsetTextEdits(
123
123
  return normalizedOffsetTextEdits;
124
124
  }
125
125
 
126
- export function readUpdatedContent(filePath: string, content: string, textEdits: readonly ITextEdit[]): string {
126
+ export function readUpdatedContent(filePath: string, content: string, textEdits: readonly TextEdit[]): string {
127
127
  const offsetTextEdits = [
128
128
  ...readNormalizedOffsetTextEdits(
129
129
  filePath,
@@ -143,7 +143,7 @@ export function readUpdatedContent(filePath: string, content: string, textEdits:
143
143
  return updatedContent;
144
144
  }
145
145
 
146
- function applyFileTextEdits(filePath: string, textEdits: readonly ITextEdit[]): void {
146
+ function applyFileTextEdits(filePath: string, textEdits: readonly TextEdit[]): void {
147
147
  const content = readFileSync(filePath, "utf8");
148
148
  const updatedContent = readUpdatedContent(filePath, content, textEdits);
149
149
 
@@ -152,7 +152,7 @@ function applyFileTextEdits(filePath: string, textEdits: readonly ITextEdit[]):
152
152
  }
153
153
  }
154
154
 
155
- export function applyTextEdits(textEdits: readonly ITextEdit[]): readonly string[] {
155
+ export function applyTextEdits(textEdits: readonly TextEdit[]): readonly string[] {
156
156
  const changedFilePaths: string[] = [];
157
157
 
158
158
  for (const fileEditEntry of readFileEditEntries(textEdits)) {
@@ -1,95 +1,95 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { once } from "node:events";
3
3
  import { pathToFileURL } from "node:url";
4
- import type { ILineAndCharacter } from "../../types.ts";
4
+ import type { LineAndCharacter } from "../../types.ts";
5
5
 
6
- type IJsonRpcIdentifier = number | string | null;
6
+ type JsonRpcIdentifier = number | string | null;
7
7
 
8
- type IJsonRpcError = {
8
+ type JsonRpcError = {
9
9
  code: number;
10
10
  message: string;
11
11
  };
12
12
 
13
- type IJsonRpcErrorResponse = {
14
- error: IJsonRpcError;
15
- id: IJsonRpcIdentifier;
13
+ type JsonRpcErrorResponse = {
14
+ error: JsonRpcError;
15
+ id: JsonRpcIdentifier;
16
16
  jsonrpc: string;
17
17
  };
18
18
 
19
- type IJsonRpcRequestMessage = {
20
- id?: IJsonRpcIdentifier;
19
+ type JsonRpcRequestMessage = {
20
+ id?: JsonRpcIdentifier;
21
21
  jsonrpc: string;
22
22
  method: string;
23
23
  params?: unknown;
24
24
  };
25
25
 
26
- type IJsonRpcSuccessResponse = {
27
- id: IJsonRpcIdentifier;
26
+ type JsonRpcSuccessResponse = {
27
+ id: JsonRpcIdentifier;
28
28
  jsonrpc: string;
29
29
  result?: unknown;
30
30
  };
31
31
 
32
- type IJsonRpcResponse = IJsonRpcErrorResponse | IJsonRpcSuccessResponse;
32
+ type JsonRpcResponse = JsonRpcErrorResponse | JsonRpcSuccessResponse;
33
33
 
34
- type ILspTextDocumentIdentifier = {
34
+ type LspTextDocumentIdentifier = {
35
35
  uri: string;
36
36
  };
37
37
 
38
- type ILspPosition = {
38
+ type LspPosition = {
39
39
  character: number;
40
40
  line: number;
41
41
  };
42
42
 
43
- type ILspWorkspaceFolder = {
43
+ type LspWorkspaceFolder = {
44
44
  name: string;
45
45
  uri: string;
46
46
  };
47
47
 
48
- type ILspWorkspaceEditCapabilities = {
48
+ type LspWorkspaceEditCapabilities = {
49
49
  documentChanges: boolean;
50
50
  };
51
51
 
52
- type ILspWorkspaceCapabilities = {
53
- workspaceEdit: ILspWorkspaceEditCapabilities;
52
+ type LspWorkspaceCapabilities = {
53
+ workspaceEdit: LspWorkspaceEditCapabilities;
54
54
  };
55
55
 
56
- type ILspRenameCapabilities = {
56
+ type LspRenameCapabilities = {
57
57
  prepareSupport: boolean;
58
58
  };
59
59
 
60
- type ILspTextDocumentCapabilities = {
61
- rename: ILspRenameCapabilities;
60
+ type LspTextDocumentCapabilities = {
61
+ rename: LspRenameCapabilities;
62
62
  };
63
63
 
64
- type ILspClientCapabilities = {
65
- textDocument: ILspTextDocumentCapabilities;
66
- workspace: ILspWorkspaceCapabilities;
64
+ type LspClientCapabilities = {
65
+ textDocument: LspTextDocumentCapabilities;
66
+ workspace: LspWorkspaceCapabilities;
67
67
  };
68
68
 
69
- type ILspInitializeParams = {
70
- capabilities: ILspClientCapabilities;
69
+ type LspInitializeParams = {
70
+ capabilities: LspClientCapabilities;
71
71
  processId: number;
72
72
  rootUri: string;
73
- workspaceFolders: readonly ILspWorkspaceFolder[];
73
+ workspaceFolders: readonly LspWorkspaceFolder[];
74
74
  };
75
75
 
76
- type ILspPrepareRenameParams = {
77
- position: ILspPosition;
78
- textDocument: ILspTextDocumentIdentifier;
76
+ type LspPrepareRenameParams = {
77
+ position: LspPosition;
78
+ textDocument: LspTextDocumentIdentifier;
79
79
  };
80
80
 
81
- type ILspRenameParams = {
81
+ type LspRenameParams = {
82
82
  newName: string;
83
- position: ILspPosition;
84
- textDocument: ILspTextDocumentIdentifier;
83
+ position: LspPosition;
84
+ textDocument: LspTextDocumentIdentifier;
85
85
  };
86
86
 
87
- type ITsgoLspClientOptions = {
87
+ type TsgoLspClientOptions = {
88
88
  tsgoExecutablePath: string;
89
89
  workspacePath: string;
90
90
  };
91
91
 
92
- type IPendingRequest = {
92
+ type PendingRequest = {
93
93
  reject: (error: Error) => void;
94
94
  resolve: (result: unknown) => void;
95
95
  };
@@ -98,7 +98,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
98
98
  return typeof value === "object" && value !== null;
99
99
  }
100
100
 
101
- function isJsonRpcError(value: unknown): value is IJsonRpcError {
101
+ function isJsonRpcError(value: unknown): value is JsonRpcError {
102
102
  if (!isRecord(value)) {
103
103
  return false;
104
104
  }
@@ -106,7 +106,7 @@ function isJsonRpcError(value: unknown): value is IJsonRpcError {
106
106
  return typeof value.code === "number" && typeof value.message === "string";
107
107
  }
108
108
 
109
- function isJsonRpcRequestMessage(value: unknown): value is IJsonRpcRequestMessage {
109
+ function isJsonRpcRequestMessage(value: unknown): value is JsonRpcRequestMessage {
110
110
  if (!isRecord(value)) {
111
111
  return false;
112
112
  }
@@ -114,7 +114,7 @@ function isJsonRpcRequestMessage(value: unknown): value is IJsonRpcRequestMessag
114
114
  return value.jsonrpc === "2.0" && typeof value.method === "string";
115
115
  }
116
116
 
117
- function isJsonRpcResponse(value: unknown): value is IJsonRpcResponse {
117
+ function isJsonRpcResponse(value: unknown): value is JsonRpcResponse {
118
118
  if (!isRecord(value)) {
119
119
  return false;
120
120
  }
@@ -135,7 +135,7 @@ function isJsonRpcResponse(value: unknown): value is IJsonRpcResponse {
135
135
  return Reflect.has(value, "result");
136
136
  }
137
137
 
138
- function readLspPosition(position: ILineAndCharacter): ILspPosition {
138
+ function readLspPosition(position: LineAndCharacter): LspPosition {
139
139
  return {
140
140
  character: position.character,
141
141
  line: position.line,
@@ -143,13 +143,13 @@ function readLspPosition(position: ILineAndCharacter): ILspPosition {
143
143
  }
144
144
 
145
145
  export class TsgoLspClient {
146
- private readonly pendingRequests = new Map<number, IPendingRequest>();
146
+ private readonly pendingRequests = new Map<number, PendingRequest>();
147
147
  private readonly process: ReturnType<typeof spawn>;
148
148
  private readonly stderrChunks: string[] = [];
149
149
  private stdoutBuffer = Buffer.alloc(0);
150
150
  private requestId = 0;
151
151
 
152
- public constructor(private readonly options: ITsgoLspClientOptions) {
152
+ public constructor(private readonly options: TsgoLspClientOptions) {
153
153
  this.process = spawn(this.options.tsgoExecutablePath, ["--lsp", "--stdio"], {
154
154
  cwd: this.options.workspacePath,
155
155
  stdio: ["pipe", "pipe", "pipe"],
@@ -187,7 +187,7 @@ export class TsgoLspClient {
187
187
 
188
188
  public async initialize(): Promise<void> {
189
189
  const rootUri = pathToFileURL(this.options.workspacePath).toString();
190
- const initializeParams: ILspInitializeParams = {
190
+ const initializeParams: LspInitializeParams = {
191
191
  capabilities: {
192
192
  textDocument: {
193
193
  rename: {
@@ -214,8 +214,8 @@ export class TsgoLspClient {
214
214
  this.sendNotification("initialized");
215
215
  }
216
216
 
217
- public prepareRename(filePath: string, position: ILineAndCharacter): Promise<unknown> {
218
- const params: ILspPrepareRenameParams = {
217
+ public prepareRename(filePath: string, position: LineAndCharacter): Promise<unknown> {
218
+ const params: LspPrepareRenameParams = {
219
219
  position: readLspPosition(position),
220
220
  textDocument: {
221
221
  uri: pathToFileURL(filePath).toString(),
@@ -225,8 +225,8 @@ export class TsgoLspClient {
225
225
  return this.sendRequest("textDocument/prepareRename", params);
226
226
  }
227
227
 
228
- public rename(filePath: string, position: ILineAndCharacter, newName: string): Promise<unknown> {
229
- const params: ILspRenameParams = {
228
+ public rename(filePath: string, position: LineAndCharacter, newName: string): Promise<unknown> {
229
+ const params: LspRenameParams = {
230
230
  newName,
231
231
  position: readLspPosition(position),
232
232
  textDocument: {
@@ -289,7 +289,7 @@ export class TsgoLspClient {
289
289
  }
290
290
  }
291
291
 
292
- private handleResponse(message: IJsonRpcResponse): void {
292
+ private handleResponse(message: JsonRpcResponse): void {
293
293
  if (typeof message.id !== "number") {
294
294
  return;
295
295
  }
@@ -309,7 +309,7 @@ export class TsgoLspClient {
309
309
  pendingRequest.resolve(message.result ?? null);
310
310
  }
311
311
 
312
- private handleServerRequest(message: IJsonRpcRequestMessage): void {
312
+ private handleServerRequest(message: JsonRpcRequestMessage): void {
313
313
  if (message.id === undefined) {
314
314
  return;
315
315
  }
@@ -401,7 +401,7 @@ export class TsgoLspClient {
401
401
  clearTimeout(killTimer);
402
402
  }
403
403
 
404
- private writeMessage(method: string, id?: IJsonRpcIdentifier, params?: unknown): void {
404
+ private writeMessage(method: string, id?: JsonRpcIdentifier, params?: unknown): void {
405
405
  const message: Record<string, unknown> = {
406
406
  jsonrpc: "2.0",
407
407
  method,
@@ -418,7 +418,7 @@ export class TsgoLspClient {
418
418
  this.writeSerializedMessage(message);
419
419
  }
420
420
 
421
- private writeResponse(id: IJsonRpcIdentifier, result: unknown): void {
421
+ private writeResponse(id: JsonRpcIdentifier, result: unknown): void {
422
422
  this.writeSerializedMessage({
423
423
  id,
424
424
  jsonrpc: "2.0",
@@ -3,46 +3,46 @@ import { fileURLToPath } from "node:url";
3
3
  import { readMovedFileTextEdits } from "../../readMovedFileTextEdits.ts";
4
4
  import { TsgoLspClient } from "./TsgoLspClient.ts";
5
5
  import type {
6
- IApplySemanticFixesOptions,
7
- IFileMove,
8
- IMoveFileOperation,
9
- ISemanticFixBackend,
10
- ISemanticFixBackendContext,
11
- ISemanticFixOperation,
12
- ISemanticFixPlan,
13
- ISemanticFixPlanResult,
14
- ISymbolRenameOperation,
15
- ITextEdit,
6
+ ApplySemanticFixesOptions,
7
+ FileMove,
8
+ MoveFileOperation,
9
+ SemanticFixBackend,
10
+ SemanticFixBackendContext,
11
+ SemanticFixOperation,
12
+ SemanticFixPlan,
13
+ SemanticFixPlanResult,
14
+ SymbolRenameOperation,
15
+ TextEdit,
16
16
  } from "../../types.ts";
17
17
 
18
- type ILspPosition = {
18
+ type LspPosition = {
19
19
  character: number;
20
20
  line: number;
21
21
  };
22
22
 
23
- type ILspRange = {
24
- end: ILspPosition;
25
- start: ILspPosition;
23
+ type LspRange = {
24
+ end: LspPosition;
25
+ start: LspPosition;
26
26
  };
27
27
 
28
- type ILspTextEdit = {
28
+ type LspTextEdit = {
29
29
  newText: string;
30
- range: ILspRange;
30
+ range: LspRange;
31
31
  };
32
32
 
33
- type ILspWorkspaceChanges = Record<string, readonly ILspTextEdit[]>;
33
+ type LspWorkspaceChanges = Record<string, readonly LspTextEdit[]>;
34
34
 
35
- type ILspWorkspaceEdit = {
36
- changes: ILspWorkspaceChanges;
35
+ type LspWorkspaceEdit = {
36
+ changes: LspWorkspaceChanges;
37
37
  };
38
38
 
39
- type IClientCache = Map<string, TsgoLspClient>;
39
+ type ClientCache = Map<string, TsgoLspClient>;
40
40
 
41
41
  function isRecord(value: unknown): value is Record<string, unknown> {
42
42
  return typeof value === "object" && value !== null;
43
43
  }
44
44
 
45
- function isLspPosition(value: unknown): value is ILspPosition {
45
+ function isLspPosition(value: unknown): value is LspPosition {
46
46
  if (!isRecord(value)) {
47
47
  return false;
48
48
  }
@@ -50,7 +50,7 @@ function isLspPosition(value: unknown): value is ILspPosition {
50
50
  return typeof value.line === "number" && typeof value.character === "number";
51
51
  }
52
52
 
53
- function isLspRange(value: unknown): value is ILspRange {
53
+ function isLspRange(value: unknown): value is LspRange {
54
54
  if (!isRecord(value)) {
55
55
  return false;
56
56
  }
@@ -58,7 +58,7 @@ function isLspRange(value: unknown): value is ILspRange {
58
58
  return isLspPosition(value.start) && isLspPosition(value.end);
59
59
  }
60
60
 
61
- function isLspTextEdit(value: unknown): value is ILspTextEdit {
61
+ function isLspTextEdit(value: unknown): value is LspTextEdit {
62
62
  if (!isRecord(value)) {
63
63
  return false;
64
64
  }
@@ -66,7 +66,7 @@ function isLspTextEdit(value: unknown): value is ILspTextEdit {
66
66
  return typeof value.newText === "string" && isLspRange(value.range);
67
67
  }
68
68
 
69
- function isLspWorkspaceEdit(value: unknown): value is ILspWorkspaceEdit {
69
+ function isLspWorkspaceEdit(value: unknown): value is LspWorkspaceEdit {
70
70
  if (!isRecord(value) || !isRecord(value.changes)) {
71
71
  return false;
72
72
  }
@@ -86,7 +86,7 @@ function isLspWorkspaceEdit(value: unknown): value is ILspWorkspaceEdit {
86
86
  return true;
87
87
  }
88
88
 
89
- function compareTextEdit(left: ITextEdit, right: ITextEdit): number {
89
+ function compareTextEdit(left: TextEdit, right: TextEdit): number {
90
90
  if (left.filePath !== right.filePath) {
91
91
  return left.filePath.localeCompare(right.filePath);
92
92
  }
@@ -102,7 +102,7 @@ function compareTextEdit(left: ITextEdit, right: ITextEdit): number {
102
102
  return left.newText.localeCompare(right.newText);
103
103
  }
104
104
 
105
- function readTextEdit(uri: string, textEdit: ILspTextEdit): ITextEdit {
105
+ function readTextEdit(uri: string, textEdit: LspTextEdit): TextEdit {
106
106
  return {
107
107
  end: textEdit.range.end,
108
108
  filePath: fileURLToPath(uri),
@@ -111,8 +111,8 @@ function readTextEdit(uri: string, textEdit: ILspTextEdit): ITextEdit {
111
111
  };
112
112
  }
113
113
 
114
- function readTextEdits(workspaceEdit: ILspWorkspaceEdit): readonly ITextEdit[] {
115
- const textEdits: ITextEdit[] = [];
114
+ function readTextEdits(workspaceEdit: LspWorkspaceEdit): readonly TextEdit[] {
115
+ const textEdits: TextEdit[] = [];
116
116
 
117
117
  for (const [uri, edits] of Object.entries(workspaceEdit.changes)) {
118
118
  for (const textEdit of edits) {
@@ -132,9 +132,9 @@ function readFailureReason(error: unknown): string {
132
132
  }
133
133
 
134
134
  async function readClient(
135
- clientCache: IClientCache,
136
- context: ISemanticFixBackendContext,
137
- options: Pick<IApplySemanticFixesOptions, "tsgoExecutablePath">,
135
+ clientCache: ClientCache,
136
+ context: SemanticFixBackendContext,
137
+ options: Pick<ApplySemanticFixesOptions, "tsgoExecutablePath">,
138
138
  ): Promise<TsgoLspClient> {
139
139
  const cachedClient = clientCache.get(context.targetDirectoryPath);
140
140
  if (cachedClient) {
@@ -150,19 +150,19 @@ async function readClient(
150
150
  return client;
151
151
  }
152
152
 
153
- function readRenameSymbolDescription(operation: ISymbolRenameOperation): string {
153
+ function readRenameSymbolDescription(operation: SymbolRenameOperation): string {
154
154
  return `Rename ${operation.symbolName} to ${operation.newName}`;
155
155
  }
156
156
 
157
- function readMoveFileDescription(operation: IMoveFileOperation): string {
157
+ function readMoveFileDescription(operation: MoveFileOperation): string {
158
158
  return `Move ${operation.filePath} to ${operation.newFilePath}`;
159
159
  }
160
160
 
161
161
  function readPlan(
162
- operation: ISemanticFixOperation,
163
- textEdits: readonly ITextEdit[],
164
- fileMoves: readonly IFileMove[] = [],
165
- ): ISemanticFixPlan {
162
+ operation: SemanticFixOperation,
163
+ textEdits: readonly TextEdit[],
164
+ fileMoves: readonly FileMove[] = [],
165
+ ): SemanticFixPlan {
166
166
  return {
167
167
  description:
168
168
  operation.kind === "rename-symbol" ? readRenameSymbolDescription(operation) : readMoveFileDescription(operation),
@@ -174,12 +174,12 @@ function readPlan(
174
174
  }
175
175
 
176
176
  export function createTsgoLspSemanticFixBackend(
177
- options: Pick<IApplySemanticFixesOptions, "tsgoExecutablePath">,
178
- ): ISemanticFixBackend {
179
- const clientCache: IClientCache = new Map();
177
+ options: Pick<ApplySemanticFixesOptions, "tsgoExecutablePath">,
178
+ ): SemanticFixBackend {
179
+ const clientCache: ClientCache = new Map();
180
180
 
181
181
  return {
182
- async createPlan(operation, context): Promise<ISemanticFixPlanResult> {
182
+ async createPlan(operation, context): Promise<SemanticFixPlanResult> {
183
183
  switch (operation.kind) {
184
184
  case "rename-symbol": {
185
185
  const client = await readClient(clientCache, context, options);
@@ -1,71 +1,15 @@
1
- import { readFileSync } from "node:fs";
2
- import { isAbsolute, resolve } from "node:path";
3
1
  import ts from "typescript";
4
2
  import type {
5
- IOxlintDiagnostic,
6
- ISemanticFixOperation,
7
- ISemanticFixProvider,
8
- ISemanticFixProviderContext,
3
+ OxlintDiagnostic,
4
+ SemanticFixOperation,
5
+ SemanticFixProvider,
6
+ SemanticFixProviderContext,
9
7
  } from "../types.ts";
10
-
11
- function readAbsoluteDiagnosticFilePath(diagnostic: IOxlintDiagnostic, context: ISemanticFixProviderContext): string {
12
- if (isAbsolute(diagnostic.filename)) {
13
- return diagnostic.filename;
14
- }
15
-
16
- return resolve(context.targetDirectoryPath, diagnostic.filename);
17
- }
18
-
19
- function readInterfaceDeclarationAtOffset(node: ts.Node, offset: number): ts.InterfaceDeclaration | null {
20
- if (ts.isInterfaceDeclaration(node)) {
21
- const start = node.name.getStart();
22
- const end = node.name.getEnd();
23
- if (offset >= start && offset <= end) {
24
- return node;
25
- }
26
- }
27
-
28
- let matchingDeclaration: ts.InterfaceDeclaration | null = null;
29
-
30
- ts.forEachChild(node, (childNode) => {
31
- if (matchingDeclaration) {
32
- return;
33
- }
34
-
35
- matchingDeclaration = readInterfaceDeclarationAtOffset(childNode, offset);
36
- });
37
-
38
- return matchingDeclaration;
39
- }
40
-
41
- function readOffsetFromLineAndColumn(sourceFile: ts.SourceFile, line: number, column: number): number | null {
42
- if (line < 1 || column < 1) {
43
- return null;
44
- }
45
-
46
- try {
47
- return ts.getPositionOfLineAndCharacter(sourceFile, line - 1, column - 1);
48
- } catch {
49
- return null;
50
- }
51
- }
52
-
53
- function readInterfaceDeclarationFromLabel(
54
- sourceFile: ts.SourceFile,
55
- label: IOxlintDiagnostic["labels"][number],
56
- ): ts.InterfaceDeclaration | null {
57
- const declarationAtReportedOffset = readInterfaceDeclarationAtOffset(sourceFile, label.span.offset);
58
- if (declarationAtReportedOffset) {
59
- return declarationAtReportedOffset;
60
- }
61
-
62
- const offsetFromLineAndColumn = readOffsetFromLineAndColumn(sourceFile, label.span.line, label.span.column);
63
- if (offsetFromLineAndColumn === null || offsetFromLineAndColumn === label.span.offset) {
64
- return null;
65
- }
66
-
67
- return readInterfaceDeclarationAtOffset(sourceFile, offsetFromLineAndColumn);
68
- }
8
+ import {
9
+ readDiagnosticSourceFile,
10
+ readNamedDeclarationFromDiagnosticLabel,
11
+ readRenameSymbolOperation,
12
+ } from "./helpers.ts";
69
13
 
70
14
  function readNormalizedInterfaceName(interfaceName: string): string | null {
71
15
  const rawBaseName = /^[Ii]/.test(interfaceName) ? interfaceName.slice(1) : interfaceName;
@@ -83,19 +27,14 @@ function readNormalizedInterfaceName(interfaceName: string): string | null {
83
27
  return normalizedInterfaceName;
84
28
  }
85
29
 
86
- function readOperation(
87
- diagnostic: IOxlintDiagnostic,
88
- context: ISemanticFixProviderContext,
89
- ): ISemanticFixOperation | null {
30
+ function readOperation(diagnostic: OxlintDiagnostic, context: SemanticFixProviderContext): SemanticFixOperation | null {
90
31
  const label = diagnostic.labels[0];
91
32
  if (!label) {
92
33
  return null;
93
34
  }
94
35
 
95
- const filePath = readAbsoluteDiagnosticFilePath(diagnostic, context);
96
- const content = readFileSync(filePath, "utf8");
97
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
98
- const interfaceDeclaration = readInterfaceDeclarationFromLabel(sourceFile, label);
36
+ const sourceFile = readDiagnosticSourceFile(diagnostic, context);
37
+ const interfaceDeclaration = readNamedDeclarationFromDiagnosticLabel(sourceFile, label, ts.isInterfaceDeclaration);
99
38
  if (!interfaceDeclaration) {
100
39
  return null;
101
40
  }
@@ -106,25 +45,12 @@ function readOperation(
106
45
  return null;
107
46
  }
108
47
 
109
- const start = ts.getLineAndCharacterOfPosition(sourceFile, interfaceDeclaration.name.getStart());
110
-
111
- return {
112
- filePath,
113
- id: `${diagnostic.code}:${filePath}:${start.line}:${start.character}:${newName}`,
114
- kind: "rename-symbol",
115
- newName,
116
- position: {
117
- character: start.character,
118
- line: start.line,
119
- },
120
- ruleCode: diagnostic.code,
121
- symbolName,
122
- };
48
+ return readRenameSymbolOperation(diagnostic, sourceFile, interfaceDeclaration.name, newName);
123
49
  }
124
50
 
125
- export function createInterfaceNamingConventionSemanticFixProvider(): ISemanticFixProvider {
51
+ export function createInterfaceNamingConventionSemanticFixProvider(): SemanticFixProvider {
126
52
  return {
127
- createOperation(diagnostic, context): ISemanticFixOperation | null {
53
+ createOperation(diagnostic, context): SemanticFixOperation | null {
128
54
  return readOperation(diagnostic, context);
129
55
  },
130
56
  ruleCode: "@alexgorbatchev/interface-naming-convention",