@bscotch/gamemaker-releases 0.4.0 → 0.4.2
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.
- package/LICENSE.md +23 -0
- package/README.md +1 -1
- package/dist/browser.d.ts +7 -7
- package/dist/browser.js +6 -6
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +4 -4
- package/dist/feeds.d.ts +4 -4
- package/dist/feeds.d.ts.map +1 -1
- package/dist/feeds.js +80 -77
- package/dist/feeds.js.map +1 -1
- package/dist/feeds.lib.d.ts +3 -3
- package/dist/feeds.lib.js +52 -52
- package/dist/feeds.types.d.ts +542 -547
- package/dist/feeds.types.d.ts.map +1 -1
- package/dist/feeds.types.js +68 -68
- package/dist/fetch.d.ts +5 -5
- package/dist/fetch.js +36 -36
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/notes.d.ts +33 -33
- package/dist/notes.d.ts.map +1 -1
- package/dist/notes.js +142 -140
- package/dist/notes.js.map +1 -1
- package/dist/releases.d.ts +49 -49
- package/dist/releases.d.ts.map +1 -1
- package/dist/releases.js +19 -19
- package/dist/releases.js.map +1 -1
- package/dist/urls.d.ts +12 -12
- package/dist/urls.js +19 -19
- package/dist/utils.d.ts +8 -8
- package/dist/utils.js +43 -43
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feeds.types.d.ts","sourceRoot":"","sources":["../src/feeds.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9C,eAAO,MAAM,QAAQ,gDAAiD,CAAC;AACvE,eAAO,MAAM,aAAa,kDAAmB,CAAC;AAG9C,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AACxD,eAAO,MAAM,aAAa,6BAA8B,CAAC;AAGzD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBxB,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;EASlC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAC9C,OAAO,gCAAgC,CACxC,CAAC;AACF,eAAO,MAAM,gCAAgC
|
|
1
|
+
{"version":3,"file":"feeds.types.d.ts","sourceRoot":"","sources":["../src/feeds.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9C,eAAO,MAAM,QAAQ,gDAAiD,CAAC;AACvE,eAAO,MAAM,aAAa,kDAAmB,CAAC;AAG9C,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AACxD,eAAO,MAAM,aAAa,6BAA8B,CAAC;AAGzD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBxB,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;EASlC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAC9C,OAAO,gCAAgC,CACxC,CAAC;AACF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU3C,CAAC;AAUH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAC7C,OAAO,+BAA+B,CACvC,CAAC;AACF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIxC,CAAC;AAEL,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGjC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAMtB,CAAC;AAEZ,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAClE,eAAO,MAAM,0BAA0B;;;;;;;;;;;;GAAiC,CAAC"}
|
package/dist/feeds.types.js
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { htmlString } from './utils.js';
|
|
3
|
-
export const channels = ['lts', 'stable', 'beta', 'unstable'];
|
|
4
|
-
export const channelSchema = z.enum(channels);
|
|
5
|
-
Object.freeze(channels);
|
|
6
|
-
export const artifactTypes = ['ide', 'runtime'];
|
|
7
|
-
Object.freeze(artifactTypes);
|
|
8
|
-
export const rssFeedSchema = z.object({
|
|
9
|
-
rss: z.object({
|
|
10
|
-
channel: z.object({
|
|
11
|
-
title: htmlString(),
|
|
12
|
-
description: htmlString(),
|
|
13
|
-
link: z.string(),
|
|
14
|
-
item: z.preprocess((arg) => {
|
|
15
|
-
if (!Array.isArray(arg)) {
|
|
16
|
-
return [arg];
|
|
17
|
-
}
|
|
18
|
-
return arg;
|
|
19
|
-
}, z.array(z.object({
|
|
20
|
-
title: z.string().regex(/^Version \d+\.\d+\.\d+\.\d+$/),
|
|
21
|
-
pubDate: z.string(),
|
|
22
|
-
link: z.string().optional(),
|
|
23
|
-
comments: z.string(),
|
|
24
|
-
description: htmlString().optional(),
|
|
25
|
-
}))),
|
|
26
|
-
}),
|
|
27
|
-
}),
|
|
28
|
-
});
|
|
29
|
-
export const gameMakerArtifactSchema = z.object({
|
|
30
|
-
type: z.enum(artifactTypes),
|
|
31
|
-
version: z.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
|
|
32
|
-
channel: channelSchema,
|
|
33
|
-
summary: z.string().optional(),
|
|
34
|
-
feedUrl: z.string(),
|
|
35
|
-
publishedAt: z.string(),
|
|
36
|
-
link: z.string().optional(),
|
|
37
|
-
notesUrl: z.string(),
|
|
38
|
-
});
|
|
39
|
-
export const gameMakerArtifactWithNotesSchema = gameMakerArtifactSchema.extend({
|
|
40
|
-
notes: z.object({
|
|
41
|
-
since: z.string().nullable(),
|
|
42
|
-
groups: z.array(z.object({
|
|
43
|
-
title: htmlString(),
|
|
44
|
-
changes: z.array(htmlString()),
|
|
45
|
-
})),
|
|
46
|
-
}),
|
|
47
|
-
});
|
|
48
|
-
const gameMakerReleaseBaseSchema = z.object({
|
|
49
|
-
channel: channelSchema,
|
|
50
|
-
publishedAt: z.string().describe('Date of release for the IDE in this pair'),
|
|
51
|
-
summary: htmlString().describe('Summary of the release, from the RSS feed for the IDE'),
|
|
52
|
-
});
|
|
53
|
-
export const gameMakerReleaseWithNotesSchema = gameMakerReleaseBaseSchema.extend({
|
|
54
|
-
ide: gameMakerArtifactWithNotesSchema.omit({ summary: true }),
|
|
55
|
-
runtime: gameMakerArtifactWithNotesSchema.omit({ summary: true }),
|
|
56
|
-
});
|
|
57
|
-
export const gameMakerReleaseSchema = gameMakerReleaseBaseSchema.extend({
|
|
58
|
-
ide: gameMakerArtifactSchema.omit({ summary: true }),
|
|
59
|
-
runtime: gameMakerArtifactSchema.omit({ summary: true }),
|
|
60
|
-
});
|
|
61
|
-
export const rawReleaseNoteSchema = z
|
|
62
|
-
.object({
|
|
63
|
-
type: z.enum(artifactTypes).optional(),
|
|
64
|
-
version: z.string(),
|
|
65
|
-
release_notes: z.array(z.string()),
|
|
66
|
-
})
|
|
67
|
-
.strict();
|
|
68
|
-
export const rawReleaseNotesCacheSchema = z.record(rawReleaseNoteSchema);
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { htmlString } from './utils.js';
|
|
3
|
+
export const channels = ['lts', 'stable', 'beta', 'unstable'];
|
|
4
|
+
export const channelSchema = z.enum(channels);
|
|
5
|
+
Object.freeze(channels);
|
|
6
|
+
export const artifactTypes = ['ide', 'runtime'];
|
|
7
|
+
Object.freeze(artifactTypes);
|
|
8
|
+
export const rssFeedSchema = z.object({
|
|
9
|
+
rss: z.object({
|
|
10
|
+
channel: z.object({
|
|
11
|
+
title: htmlString(),
|
|
12
|
+
description: htmlString(),
|
|
13
|
+
link: z.string(),
|
|
14
|
+
item: z.preprocess((arg) => {
|
|
15
|
+
if (!Array.isArray(arg)) {
|
|
16
|
+
return [arg];
|
|
17
|
+
}
|
|
18
|
+
return arg;
|
|
19
|
+
}, z.array(z.object({
|
|
20
|
+
title: z.string().regex(/^Version \d+\.\d+\.\d+\.\d+$/),
|
|
21
|
+
pubDate: z.string(),
|
|
22
|
+
link: z.string().optional(),
|
|
23
|
+
comments: z.string(),
|
|
24
|
+
description: htmlString().optional(),
|
|
25
|
+
}))),
|
|
26
|
+
}),
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
export const gameMakerArtifactSchema = z.object({
|
|
30
|
+
type: z.enum(artifactTypes),
|
|
31
|
+
version: z.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
|
|
32
|
+
channel: channelSchema,
|
|
33
|
+
summary: z.string().optional(),
|
|
34
|
+
feedUrl: z.string(),
|
|
35
|
+
publishedAt: z.string(),
|
|
36
|
+
link: z.string().optional(),
|
|
37
|
+
notesUrl: z.string(),
|
|
38
|
+
});
|
|
39
|
+
export const gameMakerArtifactWithNotesSchema = gameMakerArtifactSchema.extend({
|
|
40
|
+
notes: z.object({
|
|
41
|
+
since: z.string().nullable(),
|
|
42
|
+
groups: z.array(z.object({
|
|
43
|
+
title: htmlString(),
|
|
44
|
+
changes: z.array(htmlString()),
|
|
45
|
+
})),
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
const gameMakerReleaseBaseSchema = z.object({
|
|
49
|
+
channel: channelSchema,
|
|
50
|
+
publishedAt: z.string().describe('Date of release for the IDE in this pair'),
|
|
51
|
+
summary: htmlString().describe('Summary of the release, from the RSS feed for the IDE'),
|
|
52
|
+
});
|
|
53
|
+
export const gameMakerReleaseWithNotesSchema = gameMakerReleaseBaseSchema.extend({
|
|
54
|
+
ide: gameMakerArtifactWithNotesSchema.omit({ summary: true }),
|
|
55
|
+
runtime: gameMakerArtifactWithNotesSchema.omit({ summary: true }),
|
|
56
|
+
});
|
|
57
|
+
export const gameMakerReleaseSchema = gameMakerReleaseBaseSchema.extend({
|
|
58
|
+
ide: gameMakerArtifactSchema.omit({ summary: true }),
|
|
59
|
+
runtime: gameMakerArtifactSchema.omit({ summary: true }),
|
|
60
|
+
});
|
|
61
|
+
export const rawReleaseNoteSchema = z
|
|
62
|
+
.object({
|
|
63
|
+
type: z.enum(artifactTypes).optional(),
|
|
64
|
+
version: z.string(),
|
|
65
|
+
release_notes: z.array(z.string()),
|
|
66
|
+
})
|
|
67
|
+
.strict();
|
|
68
|
+
export const rawReleaseNotesCacheSchema = z.record(rawReleaseNoteSchema);
|
|
69
69
|
//# sourceMappingURL=feeds.types.js.map
|
package/dist/fetch.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type Validator<T> = {
|
|
2
|
-
parse: (data: any) => T;
|
|
3
|
-
};
|
|
4
|
-
export declare function fetchXml<T = unknown>(url: string, validator?: Validator<T>): Promise<T>;
|
|
5
|
-
export declare function fetchJson<T = unknown>(url: string, validator?: Validator<T>): Promise<T>;
|
|
1
|
+
export type Validator<T> = {
|
|
2
|
+
parse: (data: any) => T;
|
|
3
|
+
};
|
|
4
|
+
export declare function fetchXml<T = unknown>(url: string, validator?: Validator<T>): Promise<T>;
|
|
5
|
+
export declare function fetchJson<T = unknown>(url: string, validator?: Validator<T>): Promise<T>;
|
|
6
6
|
//# sourceMappingURL=fetch.d.ts.map
|
package/dist/fetch.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import fetch from 'node-fetch';
|
|
2
|
-
import { XMLParser } from 'fast-xml-parser';
|
|
3
|
-
import { isError } from './utils.js';
|
|
4
|
-
export async function fetchXml(url, validator) {
|
|
5
|
-
const res = await fetchUrl(url);
|
|
6
|
-
try {
|
|
7
|
-
const data = await res.text();
|
|
8
|
-
const asJson = new XMLParser().parse(data);
|
|
9
|
-
return validator ? validator.parse(asJson) : asJson;
|
|
10
|
-
}
|
|
11
|
-
catch (err) {
|
|
12
|
-
throw new Error(`Error parsing XML from ${url}: ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export async function fetchJson(url, validator) {
|
|
16
|
-
const res = await fetchUrl(url);
|
|
17
|
-
try {
|
|
18
|
-
const parsed = await res.json();
|
|
19
|
-
return validator ? validator.parse(parsed) : parsed;
|
|
20
|
-
}
|
|
21
|
-
catch (err) {
|
|
22
|
-
throw new Error(`Error parsing JSON from ${url}: ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
async function fetchUrl(url) {
|
|
26
|
-
try {
|
|
27
|
-
const res = await fetch(url);
|
|
28
|
-
if (res.status >= 300) {
|
|
29
|
-
throw new Error(`Error fetching "${url}": ${res.status} ${res.statusText}`);
|
|
30
|
-
}
|
|
31
|
-
return res;
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
throw new Error(`Error fetching "${url}": ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
3
|
+
import { isError } from './utils.js';
|
|
4
|
+
export async function fetchXml(url, validator) {
|
|
5
|
+
const res = await fetchUrl(url);
|
|
6
|
+
try {
|
|
7
|
+
const data = await res.text();
|
|
8
|
+
const asJson = new XMLParser().parse(data);
|
|
9
|
+
return validator ? validator.parse(asJson) : asJson;
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
throw new Error(`Error parsing XML from ${url}: ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function fetchJson(url, validator) {
|
|
16
|
+
const res = await fetchUrl(url);
|
|
17
|
+
try {
|
|
18
|
+
const parsed = await res.json();
|
|
19
|
+
return validator ? validator.parse(parsed) : parsed;
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new Error(`Error parsing JSON from ${url}: ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function fetchUrl(url) {
|
|
26
|
+
try {
|
|
27
|
+
const res = await fetch(url);
|
|
28
|
+
if (res.status >= 300) {
|
|
29
|
+
throw new Error(`Error fetching "${url}": ${res.status} ${res.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
return res;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
throw new Error(`Error fetching "${url}": ${isError(err) ? err.message : 'UNKNOWN'}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
37
|
//# sourceMappingURL=fetch.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export * from './browser.js';
|
|
2
|
-
export {
|
|
1
|
+
export * from './browser.js';
|
|
2
|
+
export { computeReleasesSummary, computeReleasesSummaryWithNotes, } from './feeds.js';
|
|
3
|
+
export { fetchReleasesSummaryWithNotes } from './releases.js';
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,+BAA+B,GAChC,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export * from './browser.js';
|
|
2
|
-
export {
|
|
1
|
+
export * from './browser.js';
|
|
2
|
+
export { computeReleasesSummary, computeReleasesSummaryWithNotes, } from './feeds.js';
|
|
3
|
+
export { fetchReleasesSummaryWithNotes } from './releases.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,+BAA+B,GAChC,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/notes.d.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { Pathy } from '@bscotch/pathy';
|
|
2
|
-
import { ArtifactType, GameMakerRelease } from './feeds.types.js';
|
|
3
|
-
export declare function listReleaseNotes(releases: GameMakerRelease[], cache?: Pathy | string): Promise<Record<string, {
|
|
4
|
-
version: string;
|
|
5
|
-
url: string;
|
|
6
|
-
title: string | null;
|
|
7
|
-
type: "ide" | "runtime";
|
|
8
|
-
changes: {
|
|
9
|
-
since: string | null;
|
|
10
|
-
groups: {
|
|
11
|
-
title: string;
|
|
12
|
-
changes: string[];
|
|
13
|
-
}[];
|
|
14
|
-
};
|
|
15
|
-
}>>;
|
|
16
|
-
export declare function cleanNote(note: {
|
|
17
|
-
type?: ArtifactType;
|
|
18
|
-
version: string;
|
|
19
|
-
url: string;
|
|
20
|
-
release_notes: string[];
|
|
21
|
-
}): {
|
|
22
|
-
version: string;
|
|
23
|
-
url: string;
|
|
24
|
-
title: string | null;
|
|
25
|
-
type: "ide" | "runtime";
|
|
26
|
-
changes: {
|
|
27
|
-
since: string | null;
|
|
28
|
-
groups: {
|
|
29
|
-
title: string;
|
|
30
|
-
changes: string[];
|
|
31
|
-
}[];
|
|
32
|
-
};
|
|
33
|
-
};
|
|
1
|
+
import { Pathy } from '@bscotch/pathy';
|
|
2
|
+
import { ArtifactType, GameMakerRelease } from './feeds.types.js';
|
|
3
|
+
export declare function listReleaseNotes(releases: GameMakerRelease[], cache?: Pathy | string): Promise<Record<string, {
|
|
4
|
+
version: string;
|
|
5
|
+
url: string;
|
|
6
|
+
title: string | null;
|
|
7
|
+
type: "ide" | "runtime";
|
|
8
|
+
changes: {
|
|
9
|
+
since: string | null;
|
|
10
|
+
groups: {
|
|
11
|
+
title: string;
|
|
12
|
+
changes: string[];
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
}>>;
|
|
16
|
+
export declare function cleanNote(note: {
|
|
17
|
+
type?: ArtifactType;
|
|
18
|
+
version: string;
|
|
19
|
+
url: string;
|
|
20
|
+
release_notes: string[];
|
|
21
|
+
}): {
|
|
22
|
+
version: string;
|
|
23
|
+
url: string;
|
|
24
|
+
title: string | null;
|
|
25
|
+
type: "ide" | "runtime";
|
|
26
|
+
changes: {
|
|
27
|
+
since: string | null;
|
|
28
|
+
groups: {
|
|
29
|
+
title: string;
|
|
30
|
+
changes: string[];
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
34
|
//# sourceMappingURL=notes.d.ts.map
|
package/dist/notes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,
|
|
1
|
+
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EACN,YAAY,EACZ,gBAAgB,EAIhB,MAAM,kBAAkB,CAAC;AAI1B,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,KAAK,GAAE,KAAK,GAAG,MAA8B;;;;;;;;;;;;IAgC7C;AAqDD,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAC/B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;;;;;;;;;;;;EAiBA"}
|
package/dist/notes.js
CHANGED
|
@@ -1,141 +1,143 @@
|
|
|
1
|
-
import { Pathy } from '@bscotch/pathy';
|
|
2
|
-
import { assert } from '@bscotch/utility/browser';
|
|
3
|
-
import { defaultNotesCachePath } from './constants.js';
|
|
4
|
-
import { rawReleaseNotesCacheSchema, rawReleaseNoteSchema, } from './feeds.types.js';
|
|
5
|
-
import { fetchJson } from './fetch.js';
|
|
6
|
-
import { countNonUnique, findMax } from './utils.js';
|
|
7
|
-
export async function listReleaseNotes(releases, cache = defaultNotesCachePath) {
|
|
8
|
-
const cachePath = Pathy.asInstance(cache).withValidator(rawReleaseNotesCacheSchema);
|
|
9
|
-
assert(cachePath.hasExtension('json'), `Cache path must have a .json extension`);
|
|
10
|
-
const cacheData = await cachePath.read({ fallback: {} });
|
|
11
|
-
for (const release of releases) {
|
|
12
|
-
for (const type of ['ide', 'runtime']) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
1
|
+
import { Pathy } from '@bscotch/pathy';
|
|
2
|
+
import { assert } from '@bscotch/utility/browser';
|
|
3
|
+
import { defaultNotesCachePath } from './constants.js';
|
|
4
|
+
import { rawReleaseNotesCacheSchema, rawReleaseNoteSchema, } from './feeds.types.js';
|
|
5
|
+
import { fetchJson } from './fetch.js';
|
|
6
|
+
import { countNonUnique, findMax } from './utils.js';
|
|
7
|
+
export async function listReleaseNotes(releases, cache = defaultNotesCachePath) {
|
|
8
|
+
const cachePath = Pathy.asInstance(cache).withValidator(rawReleaseNotesCacheSchema);
|
|
9
|
+
assert(cachePath.hasExtension('json'), `Cache path must have a .json extension`);
|
|
10
|
+
const cacheData = await cachePath.read({ fallback: {} });
|
|
11
|
+
for (const release of releases) {
|
|
12
|
+
for (const type of ['ide', 'runtime']) {
|
|
13
|
+
let url = release[type].notesUrl;
|
|
14
|
+
// URL can be malformed
|
|
15
|
+
url = url.replace(/^(.+\.cloudfront\.net)(release.*)$/, '$1/$2');
|
|
16
|
+
if (cacheData[url]) {
|
|
17
|
+
if (!cacheData[url].type) {
|
|
18
|
+
cacheData[url].type = type;
|
|
19
|
+
await cachePath.write(cacheData);
|
|
20
|
+
}
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
console.info('Notes cache miss:', url);
|
|
24
|
+
const note = await fetchJson(url, rawReleaseNoteSchema);
|
|
25
|
+
cacheData[url] = {
|
|
26
|
+
type,
|
|
27
|
+
...rawReleaseNoteSchema.parse(note),
|
|
28
|
+
};
|
|
29
|
+
await cachePath.write(cacheData);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return cleanNotes(cacheData);
|
|
33
|
+
}
|
|
34
|
+
function cleanNotes(cachedNotes) {
|
|
35
|
+
const rawNotes = Object.entries(cachedNotes).map(([url, note]) => ({
|
|
36
|
+
...note,
|
|
37
|
+
url,
|
|
38
|
+
}));
|
|
39
|
+
// As of writing, all versions from downloaded notes are unique.
|
|
40
|
+
// We'll assume that moving forward, but also throw if that assumption is broken.
|
|
41
|
+
const versions = rawNotes.map((note) => `${note.version} (${note.type})`);
|
|
42
|
+
assert(countNonUnique(versions) === 0, `Duplicate versions found in release notes`);
|
|
43
|
+
// Convert each note into a well-defined structured document.
|
|
44
|
+
const cleanedNotes = rawNotes.map(cleanNote);
|
|
45
|
+
// Try to normalize "since" versions, since they're often only the *last* digits
|
|
46
|
+
for (const note of cleanedNotes) {
|
|
47
|
+
if (!note.changes.since?.match(/^\d+$/)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const possibleMatches = versions.filter((v) => v.endsWith(`.${note.changes.since}`));
|
|
51
|
+
if (possibleMatches.length === 1) {
|
|
52
|
+
note.changes.since = possibleMatches[0];
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!possibleMatches.length) {
|
|
56
|
+
// Then just replace the current version with those digits
|
|
57
|
+
note.changes.since = note.version.replace(/\d+$/, note.changes.since);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
// Score matches by digits in common
|
|
61
|
+
const versionParts = note.version.split('.');
|
|
62
|
+
note.changes.since = findMax(possibleMatches, (possibleMatch) => {
|
|
63
|
+
const matchParts = possibleMatch.split('.');
|
|
64
|
+
let score = 0;
|
|
65
|
+
for (let j = 0; j < matchParts.length; j++) {
|
|
66
|
+
score += matchParts[j] === versionParts[j] ? 1 : 0;
|
|
67
|
+
}
|
|
68
|
+
return score;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Re-organize into a map for indexing by notes-URL, so that these can be merged
|
|
72
|
+
// into the release feed data.
|
|
73
|
+
const notesByUrl = cleanedNotes.reduce((acc, note) => {
|
|
74
|
+
acc[note.url] = note;
|
|
75
|
+
return acc;
|
|
76
|
+
}, {});
|
|
77
|
+
return notesByUrl;
|
|
78
|
+
}
|
|
79
|
+
export function cleanNote(note) {
|
|
80
|
+
assert(note.type, 'Note type must be set');
|
|
81
|
+
const { body, title } = parseHeader(note.release_notes.join(''));
|
|
82
|
+
const groups = parseBody(body);
|
|
83
|
+
const sinceVersion = relativeToVersion(title);
|
|
84
|
+
// Normalize the HTML
|
|
85
|
+
return {
|
|
86
|
+
version: note.version,
|
|
87
|
+
url: note.url,
|
|
88
|
+
title,
|
|
89
|
+
type: note.type,
|
|
90
|
+
changes: {
|
|
91
|
+
since: sinceVersion,
|
|
92
|
+
groups,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function relativeToVersion(title) {
|
|
97
|
+
if (!title) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const sinceMatch = title.match(/([0-9.]+)/i);
|
|
101
|
+
return sinceMatch?.[1] || null;
|
|
102
|
+
}
|
|
103
|
+
function parseBody(html) {
|
|
104
|
+
// Split on h3 elements, and then pull out the lists within each
|
|
105
|
+
const parts = html.split(/<h3>\s*(.+?)\s*<\/h3>\s*<ul>\s*(.+?)\s*<\/ul>/gs);
|
|
106
|
+
const changes = [];
|
|
107
|
+
for (let groupIdx = 0; groupIdx < parts.length - 2; groupIdx += 3) {
|
|
108
|
+
const [title, list] = [parts[groupIdx + 1], parts[groupIdx + 2]];
|
|
109
|
+
changes.push({ title, changes: parseList(list) });
|
|
110
|
+
}
|
|
111
|
+
return changes;
|
|
112
|
+
}
|
|
113
|
+
function parseList(htmlList) {
|
|
114
|
+
const parts = htmlList.split(/<li>\s*(.+?)\s*<\/li>/gs);
|
|
115
|
+
const changes = [];
|
|
116
|
+
for (let groupIdx = 0; groupIdx < parts.length - 1; groupIdx += 2) {
|
|
117
|
+
const change = parts[groupIdx + 1];
|
|
118
|
+
changes.push(change);
|
|
119
|
+
}
|
|
120
|
+
return changes;
|
|
121
|
+
}
|
|
122
|
+
function parseHeader(html) {
|
|
123
|
+
// Remove changelogs from other versions (if there are additional h2 headings, remove
|
|
124
|
+
// those and all below them)
|
|
125
|
+
html = html.trim();
|
|
126
|
+
// If there is an h2 with the word "since" in it (otherwise the first h2), treat that
|
|
127
|
+
// one as the one describing this version and remove everything above and all headers
|
|
128
|
+
// below it.
|
|
129
|
+
const h2s = html.match(/<h2>\s*(.+?)\s*<\/h2>/gs);
|
|
130
|
+
if (!h2s?.length) {
|
|
131
|
+
return { title: null, body: html };
|
|
132
|
+
}
|
|
133
|
+
const thisVersionH2 = h2s.find((h2) => h2.match(/\bsince\b/i)) || h2s[0];
|
|
134
|
+
let [, after] = html.split(thisVersionH2);
|
|
135
|
+
const firstH2Index = after.indexOf('<h2>');
|
|
136
|
+
if (firstH2Index > 0) {
|
|
137
|
+
after = after.slice(0, firstH2Index);
|
|
138
|
+
}
|
|
139
|
+
assert(!after.includes('<h2>'), `Somehow still has an h2 after parsing`);
|
|
140
|
+
const [, title] = thisVersionH2.match(/^<h2>\s*(?<title>.+?)\s*<\/h2>/ms);
|
|
141
|
+
return { title, body: after };
|
|
142
|
+
}
|
|
141
143
|
//# sourceMappingURL=notes.js.map
|