Skip to content

Commit

Permalink
feat: respect latest and retired versions
Browse files Browse the repository at this point in the history
  • Loading branch information
benvp committed Nov 25, 2021
1 parent e425c70 commit e5ca033
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 21 deletions.
47 changes: 45 additions & 2 deletions src/hexpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,50 @@ import axios from 'axios';

const BASE_URL = 'https://hex.pm/api';

export function getPackage(name: String) {
export function getPackage(name: String): Promise<HexPackage> {
const url = `${BASE_URL}/packages/${name}`;
return axios.get(url).then(res => res.data);
return axios.get(url).then((res) => res.data);
}

export type HexPackage = {
configs: Record<string, string>;
docs_html_url: string;
downloads: {
all: number;
day: number;
recent: number;
week: number;
};
html_url: string;
inserted_at: string;
latest_stable_version: string;
latest_version: string;
meta: Record<string, unknown>;
name: string;
owners: HexAuthor[];
releases: HexRelease[];
repository: string;
retirements: HexRetirements;
updated_at: string;
url: string;
};

export type HexAuthor = {
email: string;
url: string;
username: string;
};

export type HexRelease = {
has_docs: boolean;
inserted_at: string;
url: string;
version: string;
};

export type HexRetirement = {
message: string;
reason: string;
};

export type HexRetirements = Record<string, HexRetirement>;
81 changes: 62 additions & 19 deletions src/provide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import * as hexpm from './hexpm';

const semver = require('semver');

export function provide(document: vscode.TextDocument, position: vscode.Position): Thenable<vscode.CompletionItem[]> {
export function provide(
document: vscode.TextDocument,
position: vscode.Position,
): Thenable<vscode.CompletionItem[]> {
const line = document.lineAt(position.line);
const packageName = getPackageName(line, position);

Expand All @@ -15,10 +18,11 @@ export function provide(document: vscode.TextDocument, position: vscode.Position
}

function getVersionsForPackage(packageName: String): Promise<vscode.CompletionItem[]> {
return hexpm.getPackage(packageName)
.then(res => completionItemsForReleases(res.releases))
.then(sortCompletionItems)
.catch(error => {
return hexpm
.getPackage(packageName)
.then(partitionReleases)
.then(createCompletionItems)
.catch((error) => {
if (error.response.status === 404) {
return [];
}
Expand Down Expand Up @@ -46,23 +50,62 @@ function tupleBeginIndex(line: vscode.TextLine, position: vscode.Position): numb
return tupleBeginIndex;
}

function sortCompletionItems(completionItems: vscode.CompletionItem[]): vscode.CompletionItem[] {
// descending sort using semver: most recent version first
const sorted = completionItems.sort((a, b) =>
semver.rcompare(a.label, b.label)
);
// comply with js lexicographic sorting as vscode does not allow alternative sorting
// maintain sort using 0-9 prefixed with z for each place value
sorted.forEach((item, idx) =>
item.sortText = `${'z'.repeat(Math.trunc(idx/10))}${idx%10}`
type PartitionedRelease = {
stable?: hexpm.HexRelease;
rest: hexpm.HexRelease[];
retired: hexpm.HexRelease[];
};

function partitionReleases(p: hexpm.HexPackage): PartitionedRelease {
// filter out retired packages
const retired = p.releases.filter((r) => Object.keys(p.retirements).includes(r.version));
const stable = p.releases.find((r) => r.version === p.latest_stable_version);
const rest = p.releases.filter(
(r) => retired.every((x) => x.version !== r.version) && r.version !== stable?.version,
);

return sorted;
return {
stable,
retired,
rest,
};
}

function completionItemsForReleases(releases: any[]): vscode.CompletionItem[] {
return releases.map((rel, index, arr) => {
const completionItem = new vscode.CompletionItem(rel.version, vscode.CompletionItemKind.Property);
return completionItem;
function createCompletionItems(releases: PartitionedRelease): vscode.CompletionItem[] {
const stable = releases.stable
? new vscode.CompletionItem(releases.stable.version, vscode.CompletionItemKind.Property)
: null;

if (stable) {
stable.detail = 'latest stable';
}

const retired = releases.retired.map((r) => {
const item = new vscode.CompletionItem(r.version, vscode.CompletionItemKind.Property);
item.detail = 'retired';
return item;
});

const rest = releases.rest.map((r) => {
return new vscode.CompletionItem(r.version, vscode.CompletionItemKind.Property);
});

const sortBySemver = (a: vscode.CompletionItem, b: vscode.CompletionItem) =>
semver.compare(b.label, a.label);

const sorted = [
...(stable ? [stable] : []),
...[...rest].sort(sortBySemver),
...[...retired].sort(sortBySemver),
];

sorted.forEach(applySortText);

return sorted;
}

function applySortText(item: vscode.CompletionItem, index: number) {
item.sortText = `${'z'.repeat(Math.trunc(index / 10))}${index % 10}`;

return item;
}

0 comments on commit e5ca033

Please sign in to comment.