OXYGENHUB

File links keep line ranges and readable state-address permalinks; API types brought up to date; 0.6.2 426ddc5039b5

refs andymccall/oxygen-vscode#3
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-28 16:12 UTC
Signature
✔ signed by Andy McCall
Hash
426ddc5039b50be714335419d8b8f1416740e27644c365b0a26e714d186bb46c
Depends on
092b8bf9f2ac 95f69b4a3ac2 b2dd082c57e4 f0b06deac4b9
Depended on by
991516a107fa d21a85954a34 263de209e5ba 5888949525ec e04950748142
In bookmarks
main
In tags
v0.10.0 v0.10.1 v0.10.2 v0.11.0 v0.11.1 v0.11.2 v0.13.0
Edits
11 atoms, 0 tree operations, 6 files

Browse the tree at this change

modified CHANGELOG.md +5 −0
1 1
# Changelog
2 2
3 +
## 0.6.2
4 +
5 +
- File links keep line ranges (`#L10-L20`) and permalinks to a state (`hash+hash`) readable, for Oxygen's Copy Permalink.
6 +
- API types match OxygenHub 0.1 with issue editing, labels and projects.
7 +
3 8
## 0.6.1
4 9
5 10
- The name is written OxygenHub throughout.
…
48 unchanged lines
modified package.json +1 −1
…
1 unchanged lines
2 2
  "name": "oxygenhub-vscode",
3 3
  "displayName": "OxygenHub",
4 4
  "description": "Proposals, reviews, issues and checks from an OxygenHub, in the editor. Builds on the Oxygen extension.",
5 -
  "version": "0.6.1",
5 +
  "version": "0.6.2",
6 6
  "publisher": "andymccall",
7 7
  "license": "MIT OR Apache-2.0",
8 8
  "icon": "assets/images/oxygenhub.png",
…
366 unchanged lines
modified src/hub.ts +2 −1
…
203 unchanged lines
204 204
    case "file": {
205 205
      const end = typeof target.endLine === "number" && target.endLine !== target.line ? `-L${target.endLine}` : "";
206 206
      const line = typeof target.line === "number" ? `#L${target.line}${end}` : "";
207 -
      return `${repo}/file/${encodeURIComponent(String(target.reference))}/${String(target.path)}${line}`;
207 +
      // A state address (`hash+hash`) keeps its `+`, as the hub writes permalinks.
208 +
      return `${repo}/file/${encodeURIComponent(String(target.reference)).replace(/%2B/g, "+")}/${String(target.path)}${line}`;
208 209
    }
209 210
    case "proposals":
210 211
      return `${repo}/proposals`;
…
79 unchanged lines
modified src/hubapi.d.ts +70 −0
…
334 unchanged lines
335 335
};
336 336
337 337
export type NewIssue = {
338 +
  assignees?: string[];
338 339
  body?: string;
340 +
  labels?: string[];
341 +
  milestone?: string | null;
342 +
  title: string;
343 +
};
344 +
345 +
export type IssueEdit = {
346 +
  assignees?: string[] | null;
347 +
  body?: string | null;
348 +
  labels?: string[] | null;
349 +
  milestone?: string | null;
350 +
  title?: string | null;
351 +
};
352 +
353 +
export type NewLabel = {
354 +
  colour?: string | null;
355 +
  description?: string;
356 +
  name: string;
357 +
};
358 +
359 +
export type Project = {
360 +
  closed: boolean;
361 +
  description: string;
362 +
  number: number;
363 +
  owner: string;
364 +
  public: boolean;
365 +
  title: string;
366 +
  updated_ms: number;
367 +
  url: string;
368 +
};
369 +
370 +
export type ProjectCard = {
371 +
  id: number;
372 +
  kind: string;
373 +
  reference: string;
374 +
  state: string;
375 +
  title: string;
376 +
};
377 +
378 +
export type ProjectColumn = {
379 +
  cards: ProjectCard[];
380 +
  id: number;
381 +
  name: string;
382 +
};
383 +
384 +
export type Board = {
385 +
  columns: ProjectColumn[];
386 +
  project: Project;
387 +
};
388 +
389 +
export type NewProject = {
390 +
  description?: string;
391 +
  private?: boolean;
339 392
  title: string;
393 +
};
394 +
395 +
export type ProjectEdit = {
396 +
  closed?: boolean | null;
397 +
  description?: string | null;
398 +
  private?: boolean | null;
399 +
  title?: string | null;
400 +
};
401 +
402 +
export type NewCard = {
403 +
  column?: string | null;
404 +
  note?: string;
405 +
  reference?: string;
406 +
};
407 +
408 +
export type CardMove = {
409 +
  column: string;
340 410
};
341 411
342 412
export type NewComment = {
…
69 unchanged lines
modified src/oxygenapi.ts +1 −1
…
11 unchanged lines
12 12
  | { kind: "repository" }
13 13
  | { kind: "bookmark"; name: string }
14 14
  | { kind: "change"; hash: string }
15 -
  | { kind: "file"; reference: string; path: string; line?: number }
15 +
  | { kind: "file"; reference: string; path: string; line?: number; endLine?: number }
16 16
  | { kind: "proposals" }
17 17
  | { kind: "issues" };
18 18
…
19 unchanged lines
modified test/hub.test.mjs +11 −0
…
136 unchanged lines
137 137
    assert.ok(!looksPrerelease(t), t);
138 138
  }
139 139
});
140 +
141 +
test("file links: line ranges and state-address permalinks", async () => {
142 +
  const { hubUrl } = await import("../out/hub.mjs");
143 +
  const a = "a".repeat(64), b = "b".repeat(64);
144 +
  assert.equal(
145 +
    hubUrl("https://h:7343", "andy", "oxy", { kind: "file", reference: `${a}+${b}`, path: "src/main.rs", line: 10, endLine: 20 }),
146 +
    `https://h:7343/andy/oxy/file/${a}+${b}/src/main.rs#L10-L20`,
147 +
  );
148 +
  assert.equal(hubUrl("https://h", "a", "r", { kind: "file", reference: "main", path: "x.rs", line: 3, endLine: 3 }), "https://h/a/r/file/main/x.rs#L3");
149 +
  assert.equal(hubUrl("https://h", "a", "r", { kind: "file", reference: "feature/x", path: "x.rs" }), "https://h/a/r/file/feature%2Fx/x.rs");
150 +
});