@rpgm-tools/neo-angband-mod-sdk 0.10.0
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 +43 -0
- package/README.md +72 -0
- package/dist/capabilities.d.ts +116 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +170 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/compose.d.ts +71 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +118 -0
- package/dist/compose.js.map +1 -0
- package/dist/conflicts.d.ts +78 -0
- package/dist/conflicts.d.ts.map +1 -0
- package/dist/conflicts.js +160 -0
- package/dist/conflicts.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +83 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +314 -0
- package/dist/loader.js.map +1 -0
- package/dist/manifest.d.ts +261 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +264 -0
- package/dist/manifest.js.map +1 -0
- package/dist/patch.d.ts +90 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +195 -0
- package/dist/patch.js.map +1 -0
- package/dist/record-key.d.ts +99 -0
- package/dist/record-key.d.ts.map +1 -0
- package/dist/record-key.js +157 -0
- package/dist/record-key.js.map +1 -0
- package/dist/resolve.d.ts +42 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +161 -0
- package/dist/resolve.js.map +1 -0
- package/dist/semver.d.ts +37 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +212 -0
- package/dist/semver.js.map +1 -0
- package/package.json +58 -0
- package/src/capabilities.ts +205 -0
- package/src/compose.ts +186 -0
- package/src/conflicts.ts +242 -0
- package/src/index.ts +73 -0
- package/src/loader.ts +393 -0
- package/src/manifest.ts +523 -0
- package/src/patch.ts +257 -0
- package/src/record-key.ts +180 -0
- package/src/resolve.ts +175 -0
- package/src/semver.ts +231 -0
package/src/semver.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small, dependency-free semver range matcher.
|
|
3
|
+
*
|
|
4
|
+
* This package bundles into a browser build, so it cannot pull in the
|
|
5
|
+
* `semver` npm package; this file implements just enough of the range
|
|
6
|
+
* grammar for pack manifests (MOD_LIFECYCLE.md section 3):
|
|
7
|
+
*
|
|
8
|
+
* - `*` or `x` (any case): matches any version.
|
|
9
|
+
* - an exact version, `1.2.3`: matches only that version.
|
|
10
|
+
* - a partial version used bare, `1.2` or `1`: matches any version with
|
|
11
|
+
* that prefix (`1.2` matches `1.2.0`..`1.2.x`; `1` matches `1.0.0`..`1.x.x`).
|
|
12
|
+
* - caret ranges, `^1.2.3`: compatible-with, following npm's rule that the
|
|
13
|
+
* leftmost nonzero component may not change (`^1.2.3` allows up to but
|
|
14
|
+
* not including `2.0.0`; `^0.2.3` allows up to but not including `0.3.0`;
|
|
15
|
+
* `^0.0.3` allows only `0.0.3`).
|
|
16
|
+
* - tilde ranges, `~1.2.3`: patch-level allowed (up to but not including
|
|
17
|
+
* `1.3.0`); `~1.2` is the same; `~1` allows up to but not including `2.0.0`.
|
|
18
|
+
* - comparator sets: `>=`, `>`, `<=`, `<`, `=`, combined with spaces and
|
|
19
|
+
* ANDed together, e.g. `>=1.0.0 <2.0.0`.
|
|
20
|
+
*
|
|
21
|
+
* Limitation (documented, not fixed): prerelease tags (`1.0.0-beta.2`) are
|
|
22
|
+
* compared naively as a single lexicographic string once the numeric
|
|
23
|
+
* major.minor.patch triple is equal, rather than the full dot-separated,
|
|
24
|
+
* numeric-vs-alphanumeric identifier comparison the semver spec defines.
|
|
25
|
+
* A version with no prerelease is always treated as newer than one with a
|
|
26
|
+
* prerelease at the same major.minor.patch, matching the spec; the ordering
|
|
27
|
+
* among different prerelease strings themselves does not. Pack authors who
|
|
28
|
+
* need exact prerelease ordering should not rely on it here.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export class SemverError extends Error {}
|
|
32
|
+
|
|
33
|
+
interface FullVersion {
|
|
34
|
+
major: number;
|
|
35
|
+
minor: number;
|
|
36
|
+
patch: number;
|
|
37
|
+
prerelease: string | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface PartialVersion {
|
|
41
|
+
major: number | null;
|
|
42
|
+
minor: number | null;
|
|
43
|
+
patch: number | null;
|
|
44
|
+
prerelease: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const PARTIAL_RE =
|
|
48
|
+
/^(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?$/;
|
|
49
|
+
|
|
50
|
+
function isWildcardToken(s: string): boolean {
|
|
51
|
+
return s === "x" || s === "X" || s === "*";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Parse a (possibly partial, possibly wildcarded) version-shaped string. */
|
|
55
|
+
function parsePartial(s: string): PartialVersion {
|
|
56
|
+
const match = PARTIAL_RE.exec(s);
|
|
57
|
+
if (!match) {
|
|
58
|
+
throw new SemverError(`malformed version: ${s}`);
|
|
59
|
+
}
|
|
60
|
+
const [, majorStr, minorStr, patchStr, prerelease] = match;
|
|
61
|
+
const major =
|
|
62
|
+
majorStr === undefined || isWildcardToken(majorStr) ? null : Number(majorStr);
|
|
63
|
+
const minor =
|
|
64
|
+
minorStr === undefined || isWildcardToken(minorStr) ? null : Number(minorStr);
|
|
65
|
+
const patch =
|
|
66
|
+
patchStr === undefined || isWildcardToken(patchStr) ? null : Number(patchStr);
|
|
67
|
+
return { major, minor, patch, prerelease: prerelease ?? null };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Parse a full, exact version (all three components required); throws SemverError. */
|
|
71
|
+
function parseVersion(s: string): FullVersion {
|
|
72
|
+
const p = parsePartial(s);
|
|
73
|
+
if (p.major === null || p.minor === null || p.patch === null) {
|
|
74
|
+
throw new SemverError(`expected a full major.minor.patch version, got: ${s}`);
|
|
75
|
+
}
|
|
76
|
+
return { major: p.major, minor: p.minor, patch: p.patch, prerelease: p.prerelease };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** -1 if a < b, 0 if equal, 1 if a > b. See the prerelease limitation above. */
|
|
80
|
+
function compareVersions(a: FullVersion, b: FullVersion): number {
|
|
81
|
+
if (a.major !== b.major) return a.major - b.major < 0 ? -1 : 1;
|
|
82
|
+
if (a.minor !== b.minor) return a.minor - b.minor < 0 ? -1 : 1;
|
|
83
|
+
if (a.patch !== b.patch) return a.patch - b.patch < 0 ? -1 : 1;
|
|
84
|
+
if (a.prerelease === b.prerelease) return 0;
|
|
85
|
+
if (a.prerelease === null) return 1; // no prerelease outranks any prerelease
|
|
86
|
+
if (b.prerelease === null) return -1;
|
|
87
|
+
return a.prerelease < b.prerelease ? -1 : 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type Checker = (v: FullVersion) => boolean;
|
|
91
|
+
|
|
92
|
+
/** Fill an absent minor/patch with 0, e.g. for comparator/caret/tilde bounds. */
|
|
93
|
+
function fullFromPartial(p: PartialVersion, major: number): FullVersion {
|
|
94
|
+
return {
|
|
95
|
+
major,
|
|
96
|
+
minor: p.minor ?? 0,
|
|
97
|
+
patch: p.patch ?? 0,
|
|
98
|
+
prerelease: p.prerelease,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function caretChecker(p: PartialVersion, major: number): Checker {
|
|
103
|
+
const lower = fullFromPartial(p, major);
|
|
104
|
+
let upper: FullVersion;
|
|
105
|
+
if (major > 0) {
|
|
106
|
+
upper = { major: major + 1, minor: 0, patch: 0, prerelease: null };
|
|
107
|
+
} else if (lower.minor > 0) {
|
|
108
|
+
upper = { major: 0, minor: lower.minor + 1, patch: 0, prerelease: null };
|
|
109
|
+
} else {
|
|
110
|
+
upper = { major: 0, minor: 0, patch: lower.patch + 1, prerelease: null };
|
|
111
|
+
}
|
|
112
|
+
return (v) => compareVersions(v, lower) >= 0 && compareVersions(v, upper) < 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function tildeChecker(p: PartialVersion, major: number): Checker {
|
|
116
|
+
const lower = fullFromPartial(p, major);
|
|
117
|
+
const upper: FullVersion =
|
|
118
|
+
p.minor === null
|
|
119
|
+
? { major: major + 1, minor: 0, patch: 0, prerelease: null }
|
|
120
|
+
: { major, minor: lower.minor + 1, patch: 0, prerelease: null };
|
|
121
|
+
return (v) => compareVersions(v, lower) >= 0 && compareVersions(v, upper) < 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function comparatorChecker(op: string, p: PartialVersion, major: number): Checker {
|
|
125
|
+
const bound = fullFromPartial(p, major);
|
|
126
|
+
switch (op) {
|
|
127
|
+
case ">=":
|
|
128
|
+
return (v) => compareVersions(v, bound) >= 0;
|
|
129
|
+
case ">":
|
|
130
|
+
return (v) => compareVersions(v, bound) > 0;
|
|
131
|
+
case "<=":
|
|
132
|
+
return (v) => compareVersions(v, bound) <= 0;
|
|
133
|
+
case "<":
|
|
134
|
+
return (v) => compareVersions(v, bound) < 0;
|
|
135
|
+
case "=":
|
|
136
|
+
return (v) => compareVersions(v, bound) === 0;
|
|
137
|
+
default:
|
|
138
|
+
// Unreachable: parseToken only dispatches here with a known operator.
|
|
139
|
+
throw new SemverError(`unknown comparator: ${op}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** A bare token with no operator: an exact version, or a wildcard prefix. */
|
|
144
|
+
function bareChecker(p: PartialVersion, major: number): Checker {
|
|
145
|
+
if (p.minor === null) {
|
|
146
|
+
const lower: FullVersion = { major, minor: 0, patch: 0, prerelease: null };
|
|
147
|
+
const upper: FullVersion = { major: major + 1, minor: 0, patch: 0, prerelease: null };
|
|
148
|
+
return (v) => compareVersions(v, lower) >= 0 && compareVersions(v, upper) < 0;
|
|
149
|
+
}
|
|
150
|
+
if (p.patch === null) {
|
|
151
|
+
const lower: FullVersion = { major, minor: p.minor, patch: 0, prerelease: null };
|
|
152
|
+
const upper: FullVersion = {
|
|
153
|
+
major,
|
|
154
|
+
minor: p.minor + 1,
|
|
155
|
+
patch: 0,
|
|
156
|
+
prerelease: null,
|
|
157
|
+
};
|
|
158
|
+
return (v) => compareVersions(v, lower) >= 0 && compareVersions(v, upper) < 0;
|
|
159
|
+
}
|
|
160
|
+
const exact: FullVersion = { major, minor: p.minor, patch: p.patch, prerelease: p.prerelease };
|
|
161
|
+
return (v) => compareVersions(v, exact) === 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Parse one whitespace-delimited comparator token into a checker function. */
|
|
165
|
+
function parseToken(token: string): Checker {
|
|
166
|
+
if (token === "*" || token.toLowerCase() === "x") {
|
|
167
|
+
return () => true;
|
|
168
|
+
}
|
|
169
|
+
let op = "";
|
|
170
|
+
let rest = token;
|
|
171
|
+
if (rest.startsWith(">=")) {
|
|
172
|
+
op = ">=";
|
|
173
|
+
rest = rest.slice(2);
|
|
174
|
+
} else if (rest.startsWith("<=")) {
|
|
175
|
+
op = "<=";
|
|
176
|
+
rest = rest.slice(2);
|
|
177
|
+
} else if (rest.startsWith("^")) {
|
|
178
|
+
op = "^";
|
|
179
|
+
rest = rest.slice(1);
|
|
180
|
+
} else if (rest.startsWith("~")) {
|
|
181
|
+
op = "~";
|
|
182
|
+
rest = rest.slice(1);
|
|
183
|
+
} else if (rest.startsWith(">")) {
|
|
184
|
+
op = ">";
|
|
185
|
+
rest = rest.slice(1);
|
|
186
|
+
} else if (rest.startsWith("<")) {
|
|
187
|
+
op = "<";
|
|
188
|
+
rest = rest.slice(1);
|
|
189
|
+
} else if (rest.startsWith("=")) {
|
|
190
|
+
op = "=";
|
|
191
|
+
rest = rest.slice(1);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const partial = parsePartial(rest);
|
|
195
|
+
if (partial.major === null) {
|
|
196
|
+
// A wildcard major combined with an operator ("^x", ">=x") degrades to
|
|
197
|
+
// "any version"; there is no meaningful bound to compute.
|
|
198
|
+
return () => true;
|
|
199
|
+
}
|
|
200
|
+
switch (op) {
|
|
201
|
+
case "^":
|
|
202
|
+
return caretChecker(partial, partial.major);
|
|
203
|
+
case "~":
|
|
204
|
+
return tildeChecker(partial, partial.major);
|
|
205
|
+
case ">=":
|
|
206
|
+
case ">":
|
|
207
|
+
case "<=":
|
|
208
|
+
case "<":
|
|
209
|
+
case "=":
|
|
210
|
+
return comparatorChecker(op, partial, partial.major);
|
|
211
|
+
default:
|
|
212
|
+
return bareChecker(partial, partial.major);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Does `version` satisfy `range`? Throws SemverError if either string is
|
|
218
|
+
* malformed (an unparseable version, or a range with an unparseable token).
|
|
219
|
+
*/
|
|
220
|
+
export function satisfies(version: string, range: string): boolean {
|
|
221
|
+
const trimmed = range.trim();
|
|
222
|
+
if (trimmed.length === 0) {
|
|
223
|
+
throw new SemverError("empty version range");
|
|
224
|
+
}
|
|
225
|
+
if (trimmed === "*" || trimmed.toLowerCase() === "x") {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
const v = parseVersion(version);
|
|
229
|
+
const tokens = trimmed.split(/\s+/);
|
|
230
|
+
return tokens.every((token) => parseToken(token)(v));
|
|
231
|
+
}
|