1 | import * as fs from 'fs';
|
2 | import * as t from 'io-ts';
|
3 | import { isRight } from 'fp-ts/lib/Either';
|
4 | import { PathReporter } from 'io-ts/lib/PathReporter';
|
5 |
|
6 | const EmbellishOverridesProps = t.partial({
|
7 | licenseHolder: t.string,
|
8 | });
|
9 |
|
10 | const RepositoryProps = t.union([
|
11 | t.string,
|
12 | t.type({
|
13 | type: t.string,
|
14 | url: t.string,
|
15 | }),
|
16 | ]);
|
17 |
|
18 | const PackageStabilityProps = t.keyof({
|
19 | deprecated: null,
|
20 | experimental: null,
|
21 | unstable: null,
|
22 | stable: null,
|
23 | frozen: null,
|
24 | locked: null,
|
25 | });
|
26 |
|
27 | const PackageDataOptionalProps = t.partial({
|
28 | license: t.string,
|
29 | embellish: EmbellishOverridesProps,
|
30 | private: t.boolean,
|
31 | repository: RepositoryProps,
|
32 | stability: PackageStabilityProps,
|
33 | });
|
34 |
|
35 | const PackageDataProps = t.intersection([
|
36 | t.type({
|
37 | author: t.string,
|
38 | name: t.string,
|
39 | }),
|
40 | PackageDataOptionalProps,
|
41 | ]);
|
42 |
|
43 | const REPO_REGEXES = [
|
44 | /^.*(github\.com)\/(.*)\.git.*$/,
|
45 | /^.*(bitbucket\.org)\/(.*)\.git.*$/,
|
46 | ];
|
47 |
|
48 | export type PackageData = t.TypeOf<typeof PackageDataProps>;
|
49 |
|
50 | export class Package {
|
51 | constructor(public readonly data: PackageData) {}
|
52 |
|
53 | static deserialize(json: unknown) {
|
54 | const result = PackageDataProps.decode(json);
|
55 | if (isRight(result)) {
|
56 | return result.right;
|
57 | }
|
58 |
|
59 | throw new Error(`Unable to decode package data: ${PathReporter.report(result)}`);
|
60 | }
|
61 |
|
62 | static readFromFile(filename: string) {
|
63 | return new Promise<PackageData>((resolve, reject) => {
|
64 | fs.readFile(filename, 'utf-8', (err, content) => {
|
65 | if (err) {
|
66 | return reject(err);
|
67 | }
|
68 |
|
69 | try {
|
70 | resolve(Package.deserialize(JSON.parse(content)));
|
71 | } catch (e) {
|
72 | reject(e);
|
73 | }
|
74 | });
|
75 | });
|
76 | }
|
77 | }
|
78 |
|
79 | export const getRepository = (data: PackageData) => {
|
80 | const { repository } = data;
|
81 | if (!repository) {
|
82 | return undefined;
|
83 | }
|
84 |
|
85 | const url = typeof repository === 'string' ? repository : repository.url;
|
86 | const match = REPO_REGEXES.reduce<RegExpExecArray | null>((memo, regex) => {
|
87 | return memo || regex.exec(url);
|
88 | }, null);
|
89 |
|
90 | return match
|
91 | ? {
|
92 | host: match[1] as string,
|
93 | path: match[2].split('/').splice(0, 2).join('/') as string,
|
94 | }
|
95 | : undefined;
|
96 | };
|
97 |
|
\ | No newline at end of file |