Skip to content
This repository has been archived by the owner on Dec 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #15 from meisZWFLZ/master
Browse files Browse the repository at this point in the history
Add rudimentary package resolution via Github
  • Loading branch information
meisZWFLZ authored Dec 19, 2023
2 parents bafc61f + 34d6eb1 commit cd39f8c
Show file tree
Hide file tree
Showing 9 changed files with 818 additions and 282 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run check-format
npm run pre-commit
908 changes: 631 additions & 277 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"devDependencies": {
"@commitlint/cli": "^18.4.3",
"@commitlint/config-conventional": "^18.4.3",
"@types/adm-zip": "^0.5.5",
"@types/semver": "^7.5.6",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
Expand All @@ -40,9 +42,6 @@
"semantic-release": "^22.0.8",
"typescript": "^5.0.2"
},
"bin": {
"lem-link": "out/index.js"
},
"release": {
"branches": [
"stable",
Expand All @@ -58,5 +57,10 @@
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"adm-zip": "^0.5.10",
"octokit": "^3.1.2",
"semver": "^7.5.4"
}
}
3 changes: 3 additions & 0 deletions src/packages/github/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { GithubPackage, type GithubPackageReleaseData } from "./package";
export { GithubPackageResolver } from "./resolver";
export { GithubPackageVersion } from "./version";
43 changes: 43 additions & 0 deletions src/packages/github/package.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { type Octokit } from "octokit";
import { Package, type PackageIdentifier } from "../package";
import { GithubPackageVersion } from "./version";

export type GithubPackageReleaseData = Awaited<
ReturnType<Octokit["rest"]["repos"]["listReleases"]>
>["data"][number];

export class GithubPackage extends Package<
GithubPackageVersion,
PackageIdentifier
> {
constructor(
protected readonly client: Octokit,
protected readonly id: PackageIdentifier,
) {
super(id);
}

public override async getVersions(): Promise<GithubPackageVersion[]> {
return (
await this.client.rest.repos.listReleases({
...this.id,
})
).data
.map((release) =>
GithubPackageVersion.create(this.client, this.id, release),
)
.filter((release): release is GithubPackageVersion => release != null);
}

public async getLatest(): Promise<GithubPackageVersion | null> {
return GithubPackageVersion.create(
this.client,
this.id,
(
await this.client.rest.repos.getLatestRelease({
...this.id,
})
).data,
);
}
}
15 changes: 15 additions & 0 deletions src/packages/github/resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { type Octokit } from "octokit";
import { type PackageIdentifier, PackageResolver } from "../package";
import { GithubPackage } from "./package";

export class GithubPackageResolver extends PackageResolver<GithubPackage> {
public constructor(protected readonly client: Octokit) {
super();
}

public override async resolvePackage(
id: PackageIdentifier,
): Promise<GithubPackage> {
return new GithubPackage(this.client, id);
}
}
49 changes: 49 additions & 0 deletions src/packages/github/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { type Octokit } from "octokit";
import { PackageVersion, type PackageIdentifier } from "../package";
import { type SemVer, parse } from "semver";
import { type GithubPackageReleaseData } from "./package";

export class GithubPackageVersion extends PackageVersion {
protected constructor(
protected readonly client: Octokit,
public readonly packId: PackageIdentifier,
public readonly data: GithubPackageReleaseData,
version: SemVer,
) {
super(packId, version);
}

public static create(
client: Octokit,
packId: PackageIdentifier,
data: GithubPackageReleaseData,
): GithubPackageVersion | null {
const version = parse(data.tag_name);
if (version == null) return null;
return new GithubPackageVersion(client, packId, data, version);
}

protected getAssetIndex(): number {
return 0;
}

public override async download(): Promise<Buffer | undefined> {
const index = this.getAssetIndex();

const res = await this.client.rest.repos.getReleaseAsset({
repo: this.packId.repo,
owner: this.packId.owner,
asset_id: this.data.assets[index].id,
headers: { accept: "application/octet-stream" },
});

const data = res.data;

if (data instanceof ArrayBuffer) {
return Buffer.from(data);
}
throw new Error(
"github api response was not Array. res status: " + res.status,
);
}
}
66 changes: 66 additions & 0 deletions src/packages/package.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { eq as verEquals, type Range, type SemVer } from "semver";

export interface PackageIdentifier {
/**
* does not include @ sign
* @example lemlib
*/
readonly owner: string;
/**
* @example lemlink
*/
readonly repo: string;
}

export abstract class PackageVersion implements PackageIdentifier {
readonly owner: string;
readonly repo: string;
public constructor(
packId: PackageIdentifier,
public readonly version: SemVer,
) {
this.owner = packId.owner;
this.repo = packId.repo;
}
public abstract download(): Promise<Buffer | undefined>;
}

export abstract class Package<
V extends PackageVersion,
ID extends PackageIdentifier,
> implements PackageIdentifier
{
public readonly owner: string;
public readonly repo: string;

constructor(id: ID) {
this.owner = id.owner;
this.repo = id.repo;
}

public abstract getVersions(): Promise<V[]>;
public abstract getLatest(): Promise<V | null>;

public async getVersion(version: SemVer): Promise<V | undefined> {
return (await this.getVersions()).find((v) =>
verEquals(v.version, version),
);
}

public async getVersionsInRange(range: Range): Promise<V[]> {
const versions = await this.getVersions();
return versions.filter((v) => range.test(v.version));
}

public async getLatestInRange(range: Range): Promise<V | undefined> {
return (await this.getVersionsInRange(range))
.sort((a, b) => a.version.compare(b.version))
.pop();
}
}

export abstract class PackageResolver<
P extends Package<PackageVersion, PackageIdentifier>,
> {
public abstract resolvePackage(id: PackageIdentifier): Promise<P | null>;
}
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

/* Language and Environment */
"target": "es2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"lib": [
"es2020"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
Expand Down

0 comments on commit cd39f8c

Please sign in to comment.