linear-ls 1.2.0 → 1.3.0

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.
Files changed (2) hide show
  1. package/dist/server.js +98 -34
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -9,6 +9,41 @@ const teams = new Map();
9
9
  const issues = new Map();
10
10
  const positions = new Map();
11
11
  let client;
12
+ async function diagnostics(textDocument) {
13
+ if (!client) {
14
+ return;
15
+ }
16
+ const docPositions = positions.get(textDocument.uri);
17
+ if (!docPositions) {
18
+ return;
19
+ }
20
+ const diagnostics = [];
21
+ for (const p of docPositions) {
22
+ let issue = issues.get(p.issueKey);
23
+ if (!issue) {
24
+ issue = await client.issue(p.issueKey).catch(() => undefined);
25
+ if (issue)
26
+ issues.set(p.issueKey, issue);
27
+ }
28
+ if (issue?.completedAt) {
29
+ diagnostics.push({
30
+ severity: node_1.DiagnosticSeverity.Information,
31
+ range: { start: p.positionStart, end: p.positionEnd },
32
+ message: `${p.issueKey} is completed`,
33
+ source: "Linear",
34
+ });
35
+ }
36
+ else if (issue?.archivedAt) {
37
+ diagnostics.push({
38
+ severity: node_1.DiagnosticSeverity.Information,
39
+ range: { start: p.positionStart, end: p.positionEnd },
40
+ message: `${p.issueKey} is archived`,
41
+ source: "Linear",
42
+ });
43
+ }
44
+ }
45
+ conn.sendDiagnostics({ uri: textDocument.uri, diagnostics });
46
+ }
12
47
  conn.onInitialize(async () => {
13
48
  const apiKey = process.env.LINEAR_API_KEY;
14
49
  if (!apiKey) {
@@ -26,7 +61,7 @@ conn.onInitialize(async () => {
26
61
  textDocumentSync: node_1.TextDocumentSyncKind.Incremental,
27
62
  codeActionProvider: {},
28
63
  executeCommandProvider: {
29
- commands: ["linear-ls.createTicket"],
64
+ commands: ["linear-ls.createIssue", "linear-ls.openIssue"],
30
65
  },
31
66
  hoverProvider: {},
32
67
  completionProvider: { resolveProvider: true },
@@ -40,29 +75,59 @@ conn.onInitialize(async () => {
40
75
  },
41
76
  };
42
77
  });
43
- conn.onCodeAction((params) => {
78
+ conn.onCodeAction(async (params) => {
79
+ const actions = [];
44
80
  if (params.context.triggerKind === node_1.CodeActionTriggerKind.Invoked) {
45
- const textDocument = docs.get(params.textDocument.uri);
46
- if (!textDocument) {
47
- return;
81
+ const doc = docs.get(params.textDocument.uri);
82
+ if (doc) {
83
+ const text = doc.getText(params.range);
84
+ if (text) {
85
+ actions.push({
86
+ title: "Create Issue from Selection",
87
+ kind: node_1.CodeActionKind.RefactorRewrite,
88
+ command: {
89
+ command: "linear-ls.createIssue",
90
+ title: "Create Issue",
91
+ arguments: [params.textDocument.uri, params.range, text.trim()],
92
+ },
93
+ });
94
+ }
48
95
  }
49
- const text = textDocument.getText(params.range);
50
- if (!text) {
51
- return;
96
+ }
97
+ const docPositions = positions.get(params.textDocument.uri);
98
+ for (const p of docPositions ?? []) {
99
+ if (p.positionStart.line === params.range.start.line) {
100
+ if (params.range.start.character >= p.positionStart.character &&
101
+ params.range.start.character <= p.positionEnd.character) {
102
+ let issue = issues.get(p.issueKey);
103
+ if (!issue) {
104
+ issue = await client.issue(p.issueKey).catch(() => undefined);
105
+ if (issue)
106
+ issues.set(p.issueKey, issue);
107
+ }
108
+ if (issue?.url) {
109
+ actions.push({
110
+ title: `Open ${p.issueKey} in Linear`,
111
+ kind: node_1.CodeActionKind.Empty,
112
+ command: {
113
+ command: "linear-ls.openIssue",
114
+ title: "Open in Linear",
115
+ arguments: [issue.url],
116
+ },
117
+ });
118
+ }
119
+ }
52
120
  }
53
- const action = {
54
- title: "Create Ticket from Selection",
55
- kind: node_1.CodeActionKind.RefactorRewrite,
56
- command: {
57
- command: "linear-ls.createTicket",
58
- title: "Create Ticket",
59
- arguments: [params.textDocument.uri, params.range, text.trim()],
60
- },
61
- };
62
- return [action];
63
121
  }
122
+ return actions;
64
123
  });
65
124
  conn.onExecuteCommand(async (params) => {
125
+ if (params.command === "linear-ls.openIssue") {
126
+ const [url] = params.arguments || [];
127
+ if (url) {
128
+ conn.window.showDocument({ uri: url, external: true });
129
+ }
130
+ }
66
131
  if (params.command === "linear-ls.createTicket") {
67
132
  const [uri, range, title] = params.arguments || [];
68
133
  if (!uri || !range || !title) {
@@ -117,7 +182,7 @@ conn.onExecuteCommand(async (params) => {
117
182
  let documentChangeTimeout;
118
183
  docs.onDidChangeContent((change) => {
119
184
  clearTimeout(documentChangeTimeout);
120
- documentChangeTimeout = setTimeout(() => {
185
+ documentChangeTimeout = setTimeout(async () => {
121
186
  const text = change.document.getText();
122
187
  const documentPositions = [];
123
188
  const teamKeys = Array.from(teams.keys());
@@ -144,33 +209,32 @@ docs.onDidChangeContent((change) => {
144
209
  });
145
210
  });
146
211
  positions.set(change.document.uri, documentPositions);
147
- }, 200);
212
+ await diagnostics(change.document);
213
+ }, 1000);
148
214
  });
149
215
  conn.onHover(async (params) => {
150
- const documentPositions = positions.get(params.textDocument.uri);
151
- if (!documentPositions) {
216
+ const docPositions = positions.get(params.textDocument.uri);
217
+ if (!docPositions) {
152
218
  return;
153
219
  }
154
- const textDocument = docs.get(params.textDocument.uri);
155
- if (!textDocument) {
220
+ const doc = docs.get(params.textDocument.uri);
221
+ if (!doc) {
156
222
  return;
157
223
  }
158
- const cursorOffset = textDocument.offsetAt(params.position);
159
- const targetIssue = documentPositions.find((dp) => dp.offsetStart <= cursorOffset && dp.offsetEnd > cursorOffset);
160
- if (!targetIssue) {
224
+ const cursorOffset = doc.offsetAt(params.position);
225
+ const pos = docPositions.find((dp) => dp.offsetStart <= cursorOffset && dp.offsetEnd > cursorOffset);
226
+ if (!pos) {
161
227
  return;
162
228
  }
163
- const issueFromCache = issues.get(targetIssue.issueKey);
164
- if (issueFromCache) {
165
- return {
166
- contents: issueFromCache.description ?? "Not available",
167
- };
229
+ let issue = issues.get(pos.issueKey);
230
+ if (!issue) {
231
+ issue = await client.issue(pos.issueKey).catch(() => undefined);
232
+ if (issue)
233
+ issues.set(pos.issueKey, issue);
168
234
  }
169
- const issue = await client.issue(targetIssue.issueKey);
170
235
  if (!issue) {
171
236
  return;
172
237
  }
173
- issues.set(targetIssue.issueKey, issue);
174
238
  return {
175
239
  contents: issue.description ?? "Not available",
176
240
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linear-ls",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Linear Language Server",
5
5
  "bin": "index.js",
6
6
  "main": "index.js",