arcadible 0.1.45 → 0.1.47
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/bin/arc-build.js +9 -17
- package/bin/arc-deploy.js +20 -36
- package/bin/arc-init.js +6 -16
- package/bin/arc-inspect.js +3 -7
- package/bin/arc-login.js +5 -5
- package/bin/arc-logout.js +4 -8
- package/bin/arc-open.js +7 -20
- package/bin/arc-pack.js +4 -14
- package/bin/arc-play.js +6 -20
- package/bin/arc-validate.js +8 -17
- package/bin/arc-whoami.js +5 -9
- package/bin/arc.js +7 -2
- package/package.json +1 -1
- package/src/account.js +5 -5
- package/src/action/build/tool.js +8 -15
- package/src/action/deploy/tool-git.js +1 -6
- package/src/action/deploy/wait.js +5 -11
- package/src/action/init/manifest.js +9 -37
- package/src/action/login/flow.js +3 -10
- package/src/action/open/tool.js +2 -1
- package/src/action/pack/limits.js +4 -6
- package/src/action/pack/tool.js +27 -5
- package/src/action/play/tool.js +3 -3
- package/src/action/predeploy/ac.js +28 -43
- package/src/action/predeploy/git.js +4 -4
- package/src/action/predeploy/pm.js +1 -1
- package/src/action/predeploy/published.js +4 -4
- package/src/action/predeploy/tool-git.js +10 -10
- package/src/action/validate/unknown.js +11 -10
- package/src/config/code.js +1 -0
- package/src/config/file.js +23 -0
- package/src/config/limit.js +21 -0
- package/src/parser/env.js +0 -2
- package/src/parser/manifest.js +15 -13
- package/src/parser/media.js +9 -11
- package/src/parser/project.js +31 -9
- package/src/phrase.js +178 -39
- package/src/schema/check/workflow.js +15 -0
- package/src/schema/game.js +65 -42
- package/src/schema/workflow.js +21 -8
- package/src/util/argv.js +27 -1
- package/src/util/command.js +18 -0
- package/src/util/delay.js +5 -21
- package/src/util/doc.js +4 -13
- package/src/util/links.js +17 -2
- package/src/util/media.js +2 -2
- package/src/util/objs.js +8 -1
- package/src/util/output.js +24 -2
- package/src/util/rc.js +2 -2
- package/src/util/request.js +1 -1
- package/src/util/s3.js +1 -1
- package/src/util/schema.js +9 -3
- package/src/util/uris.js +1 -1
- package/src/util/zip.js +2 -2
- package/src/config/doc.js +0 -7
|
@@ -13,6 +13,7 @@ const fs = require("fs-extra");
|
|
|
13
13
|
const isAbsolute = path.isAbsolute;
|
|
14
14
|
const join = path.join;
|
|
15
15
|
const pathExistsSync = fs.pathExistsSync; // eslint-disable-line no-sync
|
|
16
|
+
const readdirSync = fs.readdirSync; // eslint-disable-line no-sync
|
|
16
17
|
const relative = path.relative;
|
|
17
18
|
const resolve = path.resolve;
|
|
18
19
|
|
|
@@ -71,6 +72,19 @@ const lacksFiles = function (root, target, names) {
|
|
|
71
72
|
return names.every((name) => !exists(join(root, target), name));
|
|
72
73
|
};
|
|
73
74
|
|
|
75
|
+
// [function]
|
|
76
|
+
|
|
77
|
+
// whether an existing `target` lacks a folder named `name` at its root, in any
|
|
78
|
+
// letter case, since a build's paths are case-sensitive once it's served.
|
|
79
|
+
const lacksFolder = function (root, target, name) {
|
|
80
|
+
if (!exists(root, target)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return !readdirSync(join(root, target), { withFileTypes: true }).some(
|
|
84
|
+
(entry) => entry.isDirectory() && entry.name.toLowerCase() === name,
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
74
88
|
// [export]
|
|
75
89
|
|
|
76
90
|
module.exports = {
|
|
@@ -81,4 +95,5 @@ module.exports = {
|
|
|
81
95
|
isRelative,
|
|
82
96
|
isRoot,
|
|
83
97
|
lacksFiles,
|
|
98
|
+
lacksFolder,
|
|
84
99
|
};
|
package/src/schema/game.js
CHANGED
|
@@ -14,13 +14,12 @@ const z = require("zod");
|
|
|
14
14
|
const cfgai = require("../config/ai");
|
|
15
15
|
const cfgaudience = require("../config/audience");
|
|
16
16
|
const cfgcode = require("../config/code");
|
|
17
|
-
const
|
|
17
|
+
const cfgfile = require("../config/file");
|
|
18
18
|
const cfggenre = require("../config/genre");
|
|
19
19
|
const cfghtml = require("../config/html");
|
|
20
20
|
const cfgimage = require("../config/image");
|
|
21
21
|
const cfginput = require("../config/input");
|
|
22
22
|
const cfgorientation = require("../config/orientation");
|
|
23
|
-
const cfgproduct = require("../config/product");
|
|
24
23
|
const cfgvideo = require("../config/video");
|
|
25
24
|
const cfgvisibility = require("../config/visibility");
|
|
26
25
|
const chars = require("../util/chars");
|
|
@@ -38,6 +37,7 @@ const cleanSemver = semver.clean;
|
|
|
38
37
|
const docCheck = check.doc;
|
|
39
38
|
const existsCheck = check.exists;
|
|
40
39
|
const extname = path.extname;
|
|
40
|
+
const posixDirname = path.posix.dirname;
|
|
41
41
|
const ISSUE = cfgcode.ISSUE;
|
|
42
42
|
const imageCheck = check.image;
|
|
43
43
|
const invalidChars = chars.invalid;
|
|
@@ -51,13 +51,12 @@ const videoCheck = check.video;
|
|
|
51
51
|
|
|
52
52
|
// [declare]
|
|
53
53
|
|
|
54
|
-
const HANDLE = cfgproduct.handle;
|
|
55
54
|
const message = schemaMessage.messages("game");
|
|
56
55
|
|
|
57
56
|
// [declare]
|
|
58
57
|
|
|
59
|
-
const GALLERY =
|
|
60
|
-
const MEDIA =
|
|
58
|
+
const GALLERY = cfgfile.GALLERY;
|
|
59
|
+
const MEDIA = cfgfile.MEDIA;
|
|
61
60
|
|
|
62
61
|
// [declare]
|
|
63
62
|
|
|
@@ -144,15 +143,16 @@ const required = function (field, lines) {
|
|
|
144
143
|
// [function]
|
|
145
144
|
|
|
146
145
|
// a list of distinct values. Without a max, its length is up to the values.
|
|
147
|
-
const zSet = function (field, schema, { max
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
146
|
+
const zSet = function (field, schema, { max, min }) {
|
|
147
|
+
const list = z.array(schema).min(min, atLeast(field, min, "element"));
|
|
148
|
+
return (
|
|
149
|
+
max
|
|
150
|
+
? list.max(max, message(field, [`Must not exceed: ${max} elements`]))
|
|
151
|
+
: list
|
|
152
|
+
).refine(
|
|
153
|
+
(items) => new Set(items).size === items.length,
|
|
154
|
+
message(field, ["Must not contain duplicate elements."], ISSUE.DUPLICATE),
|
|
155
|
+
);
|
|
156
156
|
};
|
|
157
157
|
|
|
158
158
|
// [function]
|
|
@@ -174,11 +174,17 @@ const zSetBasefile = function (field, schema, { max, min }) {
|
|
|
174
174
|
|
|
175
175
|
// [function]
|
|
176
176
|
|
|
177
|
+
// a string of `min` to `max` characters, counted as Arcadible counts them: a
|
|
178
|
+
// character outside the Basic Multilingual Plane, such as an emoji, is one,
|
|
179
|
+
// though JavaScript's length counts it as two.
|
|
177
180
|
const zString = function (field, char, { max, min }) {
|
|
178
181
|
return z
|
|
179
182
|
.string()
|
|
180
183
|
.min(min, { ...atLeast(field, min, "character"), abort: min === 1 })
|
|
181
|
-
.
|
|
184
|
+
.refine(
|
|
185
|
+
(str) => [...str].length <= max,
|
|
186
|
+
message(field, [`Must not exceed: ${max} characters`], ISSUE.TOO_LONG),
|
|
187
|
+
)
|
|
182
188
|
.superRefine((str, ctx) => {
|
|
183
189
|
const invalid = invalidChars(str, char);
|
|
184
190
|
if (invalid.length) {
|
|
@@ -197,8 +203,12 @@ const zString = function (field, char, { max, min }) {
|
|
|
197
203
|
|
|
198
204
|
// [function]
|
|
199
205
|
|
|
206
|
+
// plain text, which can't be only spaces.
|
|
200
207
|
const zText = function (field, opts) {
|
|
201
|
-
return zString(field, /[\p{L}0-9 .,!?'"():;-]/u, opts)
|
|
208
|
+
return zString(field, /[\p{L}0-9 .,!?'"():;-]/u, opts).refine(
|
|
209
|
+
(str) => str.trim() !== "",
|
|
210
|
+
message(field, ["Must not be blank."], ISSUE.EMPTY),
|
|
211
|
+
);
|
|
202
212
|
};
|
|
203
213
|
|
|
204
214
|
// [function]
|
|
@@ -206,7 +216,7 @@ const zText = function (field, opts) {
|
|
|
206
216
|
const zHtml = function (field, root, { max, min, ...opts }) {
|
|
207
217
|
const char = /[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}\r\n]/u;
|
|
208
218
|
return zString(field, char, { max, min }).superRefine((str, ctx) => {
|
|
209
|
-
const issues = docCheck(root, str,
|
|
219
|
+
const issues = docCheck(root, str, opts);
|
|
210
220
|
if (issues.length) {
|
|
211
221
|
ctx.addIssue({
|
|
212
222
|
code: "custom",
|
|
@@ -284,27 +294,34 @@ const zMp4 = function (field, root, opts) {
|
|
|
284
294
|
const zPngMp4 = function (field, root, optsPng, optsMp4) {
|
|
285
295
|
const pngSchema = zPng(field, root, optsPng);
|
|
286
296
|
const mp4Schema = zMp4(field, root, optsMp4);
|
|
287
|
-
return z
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
297
|
+
return z
|
|
298
|
+
.string()
|
|
299
|
+
.min(1, { ...atLeast(field, 1), abort: true })
|
|
300
|
+
.superRefine((file, ctx) => {
|
|
301
|
+
const ext = extname(file);
|
|
302
|
+
let schema = null;
|
|
303
|
+
if (Object.hasOwn(cfgimage, ext)) {
|
|
304
|
+
schema = pngSchema;
|
|
305
|
+
}
|
|
306
|
+
if (Object.hasOwn(cfgvideo, ext)) {
|
|
307
|
+
schema = mp4Schema;
|
|
308
|
+
}
|
|
309
|
+
if (!schema) {
|
|
310
|
+
ctx.addIssue({
|
|
311
|
+
code: "custom",
|
|
312
|
+
...message(
|
|
313
|
+
field,
|
|
314
|
+
["Must be a PNG or MP4 file."],
|
|
315
|
+
ISSUE.MEDIA_INVALID,
|
|
316
|
+
),
|
|
317
|
+
});
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const result = schema.safeParse(file);
|
|
321
|
+
if (!result.success) {
|
|
322
|
+
result.error.issues.forEach((issue) => ctx.addIssue(issue));
|
|
323
|
+
}
|
|
324
|
+
});
|
|
308
325
|
};
|
|
309
326
|
|
|
310
327
|
// [function]
|
|
@@ -383,6 +400,10 @@ const checkSrc = function (root, src, tag) {
|
|
|
383
400
|
) {
|
|
384
401
|
return false;
|
|
385
402
|
}
|
|
403
|
+
// the store page finds it by the gallery's path, exactly.
|
|
404
|
+
if (posixDirname(src) !== GALLERY) {
|
|
405
|
+
return phrase.docMediaPath(src, GALLERY);
|
|
406
|
+
}
|
|
386
407
|
return existsCheck(root, src) || phrase.docMediaMissing(src);
|
|
387
408
|
};
|
|
388
409
|
|
|
@@ -465,6 +486,7 @@ const zId = function () {
|
|
|
465
486
|
.string(
|
|
466
487
|
required(field, [`Run ${phrase.cmdInit()} to generate a new game ID.`]),
|
|
467
488
|
)
|
|
489
|
+
.min(1, { ...atLeast(field, 1), abort: true })
|
|
468
490
|
.uuid(message(field, ["Must be a valid UUID."]))
|
|
469
491
|
.refine(
|
|
470
492
|
(value) => value === value.toLowerCase(),
|
|
@@ -542,10 +564,11 @@ const zVersion = function () {
|
|
|
542
564
|
.string(
|
|
543
565
|
required(field, ["A version is required unless one can be derived."]),
|
|
544
566
|
)
|
|
545
|
-
.
|
|
546
|
-
|
|
547
|
-
message(field, ["Must be valid semver."], ISSUE.VERSION_INVALID),
|
|
548
|
-
|
|
567
|
+
.min(1, { ...atLeast(field, 1), abort: true })
|
|
568
|
+
.refine((value) => validSemver(value) !== null, {
|
|
569
|
+
...message(field, ["Must be valid semver."], ISSUE.VERSION_INVALID),
|
|
570
|
+
abort: true,
|
|
571
|
+
})
|
|
549
572
|
.refine(
|
|
550
573
|
// lowercase too, since the database refuses an uppercase prerelease.
|
|
551
574
|
(value) => cleanSemver(value) === value && value === value.toLowerCase(),
|
package/src/schema/workflow.js
CHANGED
|
@@ -7,14 +7,17 @@ const z = require("zod");
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
9
|
const cfgcode = require("../config/code");
|
|
10
|
+
const cfgfile = require("../config/file");
|
|
10
11
|
const cfgproduct = require("../config/product");
|
|
11
12
|
const check = require("./check/workflow");
|
|
13
|
+
const commands = require("../util/command");
|
|
12
14
|
const phrase = require("../phrase");
|
|
13
15
|
const schemaMessage = require("./message");
|
|
14
16
|
|
|
15
17
|
// [use]
|
|
16
18
|
|
|
17
19
|
const avoidsCheck = check.avoids;
|
|
20
|
+
const buildCommand = commands.buildCommand;
|
|
18
21
|
const ISSUE = cfgcode.ISSUE;
|
|
19
22
|
const existsCheck = check.exists;
|
|
20
23
|
const hasFileCheck = check.hasFile;
|
|
@@ -22,23 +25,23 @@ const isInsideCheck = check.isInside;
|
|
|
22
25
|
const isRelativeCheck = check.isRelative;
|
|
23
26
|
const isRootCheck = check.isRoot;
|
|
24
27
|
const lacksFilesCheck = check.lacksFiles;
|
|
28
|
+
const lacksFolderCheck = check.lacksFolder;
|
|
25
29
|
|
|
26
30
|
// [declare]
|
|
27
31
|
|
|
28
|
-
const HANDLE = cfgproduct.handle;
|
|
29
32
|
const message = schemaMessage.messages("workflow");
|
|
30
|
-
const MEDIA =
|
|
33
|
+
const MEDIA = cfgfile.MEDIA;
|
|
31
34
|
const INDEX = "index.html";
|
|
32
|
-
const RESERVED = [
|
|
35
|
+
const RESERVED = [cfgfile.PACKAGED, MEDIA];
|
|
36
|
+
// the folder every build's origin keeps for Arcadible's own files, such as
|
|
37
|
+
// the script games include. arc pack checks it again after the build.
|
|
38
|
+
const RESERVED_FOLDER = cfgproduct.handle;
|
|
33
39
|
|
|
34
40
|
// [function]
|
|
35
41
|
|
|
36
|
-
// whether `build` runs anything
|
|
37
|
-
// trims and drops blank ones (action/build/tool.js).
|
|
42
|
+
// whether `build` runs anything, as `arc build` runs it.
|
|
38
43
|
const hasBuild = function (build) {
|
|
39
|
-
return
|
|
40
|
-
.flat()
|
|
41
|
-
.some((cmd) => typeof cmd === "string" && cmd.trim() !== "");
|
|
44
|
+
return buildCommand(build) !== "";
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
// [function]
|
|
@@ -120,6 +123,16 @@ const zDeployDir = function (root, { build }) {
|
|
|
120
123
|
ISSUE.PATH_INVALID,
|
|
121
124
|
),
|
|
122
125
|
abort: true,
|
|
126
|
+
})
|
|
127
|
+
.refine((file) => lacksFolderCheck(root, file, RESERVED_FOLDER), {
|
|
128
|
+
...message(
|
|
129
|
+
field,
|
|
130
|
+
[
|
|
131
|
+
`Must not have an ${RESERVED_FOLDER} folder at its root, in any letter case. It's reserved for ${cfgproduct.title}'s own files.`,
|
|
132
|
+
],
|
|
133
|
+
ISSUE.PATH_INVALID,
|
|
134
|
+
),
|
|
135
|
+
abort: true,
|
|
123
136
|
});
|
|
124
137
|
};
|
|
125
138
|
|
package/src/util/argv.js
CHANGED
|
@@ -19,6 +19,11 @@ const parse = helpers.Parser;
|
|
|
19
19
|
|
|
20
20
|
// [declare]
|
|
21
21
|
|
|
22
|
+
// the --browser option of arc open and arc play.
|
|
23
|
+
const BROWSER = {
|
|
24
|
+
describe: "Open in a web browser",
|
|
25
|
+
type: "boolean",
|
|
26
|
+
};
|
|
22
27
|
// the -C, --cwd option of every project command.
|
|
23
28
|
const CWD = {
|
|
24
29
|
alias: "C",
|
|
@@ -26,6 +31,18 @@ const CWD = {
|
|
|
26
31
|
describe: "Set the working directory",
|
|
27
32
|
type: "string",
|
|
28
33
|
};
|
|
34
|
+
// the -j, --json option, which prints one JSON document (OUTPUT.md).
|
|
35
|
+
const JSON_OUTPUT = {
|
|
36
|
+
alias: "j",
|
|
37
|
+
describe: "Format output as JSON",
|
|
38
|
+
type: "boolean",
|
|
39
|
+
};
|
|
40
|
+
// the -q, --quiet option, which prints only errors.
|
|
41
|
+
const QUIET = {
|
|
42
|
+
alias: "q",
|
|
43
|
+
describe: "Output only errors",
|
|
44
|
+
type: "boolean",
|
|
45
|
+
};
|
|
29
46
|
|
|
30
47
|
// [function]
|
|
31
48
|
|
|
@@ -87,4 +104,13 @@ const fail = function (argv) {
|
|
|
87
104
|
|
|
88
105
|
// [export]
|
|
89
106
|
|
|
90
|
-
module.exports = {
|
|
107
|
+
module.exports = {
|
|
108
|
+
BROWSER,
|
|
109
|
+
CWD,
|
|
110
|
+
JSON_OUTPUT,
|
|
111
|
+
QUIET,
|
|
112
|
+
cwd,
|
|
113
|
+
fail,
|
|
114
|
+
json,
|
|
115
|
+
normalize,
|
|
116
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// [function]
|
|
4
|
+
|
|
5
|
+
// workflow.build as the shell runs it: each command trimmed, blank ones
|
|
6
|
+
// dropped, and a list joined with `&&`. Blank when there's nothing to run.
|
|
7
|
+
const buildCommand = function (build) {
|
|
8
|
+
return [build]
|
|
9
|
+
.flat()
|
|
10
|
+
.filter((cmd) => typeof cmd === "string")
|
|
11
|
+
.map((cmd) => cmd.trim())
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.join(" && ");
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// [export]
|
|
17
|
+
|
|
18
|
+
module.exports = { buildCommand };
|
package/src/util/delay.js
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
// [import]
|
|
4
|
-
|
|
5
|
-
const phrase = require("../phrase");
|
|
6
|
-
const time = require("./time");
|
|
7
|
-
|
|
8
|
-
// [declare]
|
|
9
|
-
|
|
10
|
-
const POLL = {
|
|
11
|
-
delay: time.s(1),
|
|
12
|
-
factor: 1,
|
|
13
|
-
interval: time.m(1),
|
|
14
|
-
maxDelay: time.s(1),
|
|
15
|
-
timeout: Infinity,
|
|
16
|
-
timeoutError: phrase.timedOut(),
|
|
17
|
-
};
|
|
18
|
-
|
|
19
3
|
// [function]
|
|
20
4
|
|
|
21
5
|
const backoff = function (elapsed, delay, factor, interval, maxDelay) {
|
|
@@ -39,10 +23,13 @@ const wait = function (delay, next) {
|
|
|
39
23
|
|
|
40
24
|
// [function]
|
|
41
25
|
|
|
26
|
+
// calls fn(value) until it resolves to something other than null, backing
|
|
27
|
+
// off by `factor` every `interval`, up to `maxDelay`. After `timeout`, it
|
|
28
|
+
// throws timeoutError(), the caller's own error, with its code.
|
|
42
29
|
const poll = function (
|
|
43
30
|
fn,
|
|
44
31
|
value,
|
|
45
|
-
{ delay, factor, interval, maxDelay, timeout, timeoutError }
|
|
32
|
+
{ delay, factor, interval, maxDelay, timeout, timeoutError },
|
|
46
33
|
) {
|
|
47
34
|
const started = Date.now();
|
|
48
35
|
const next = function () {
|
|
@@ -52,10 +39,7 @@ const poll = function (
|
|
|
52
39
|
}
|
|
53
40
|
const elapsed = Date.now() - started;
|
|
54
41
|
if (elapsed >= timeout) {
|
|
55
|
-
|
|
56
|
-
throw typeof timeoutError === "function"
|
|
57
|
-
? timeoutError()
|
|
58
|
-
: new Error(timeoutError);
|
|
42
|
+
throw timeoutError();
|
|
59
43
|
}
|
|
60
44
|
return wait(backoff(elapsed, delay, factor, interval, maxDelay), next);
|
|
61
45
|
});
|
package/src/util/doc.js
CHANGED
|
@@ -6,7 +6,6 @@ const jsdom = require("jsdom");
|
|
|
6
6
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
|
-
const cfgdoc = require("../config/doc");
|
|
10
9
|
const phrase = require("../phrase");
|
|
11
10
|
|
|
12
11
|
// [use]
|
|
@@ -59,23 +58,15 @@ const checkNode = function (node, opts, issues) {
|
|
|
59
58
|
|
|
60
59
|
// [function]
|
|
61
60
|
|
|
62
|
-
// checks HTML as written, before anything sanitizes it:
|
|
63
|
-
// allowed, with only its allowed attributes, each
|
|
64
|
-
// problem is reported once.
|
|
65
|
-
const
|
|
61
|
+
// checks the description's HTML as written, before anything sanitizes it:
|
|
62
|
+
// every element must be allowed, with only its allowed attributes, each
|
|
63
|
+
// passing its hook. Each problem is reported once.
|
|
64
|
+
const check = function (str, { allowed, hooks = {} }) {
|
|
66
65
|
const issues = new Set();
|
|
67
66
|
checkNode(JSDOM.fragment(str), { allowed, hooks }, issues);
|
|
68
67
|
return [...issues];
|
|
69
68
|
};
|
|
70
69
|
|
|
71
|
-
// [function]
|
|
72
|
-
|
|
73
|
-
const check = function (str, { type, ...opts }) {
|
|
74
|
-
const checks = { [cfgdoc[".html"]]: checkHtml };
|
|
75
|
-
const checkDoc = checks[type];
|
|
76
|
-
return checkDoc ? checkDoc(str, opts) : [phrase.docUnsupported()];
|
|
77
|
-
};
|
|
78
|
-
|
|
79
70
|
// [export]
|
|
80
71
|
|
|
81
72
|
module.exports = { check };
|
package/src/util/links.js
CHANGED
|
@@ -41,13 +41,26 @@ const storePage = function (game) {
|
|
|
41
41
|
|
|
42
42
|
// [function]
|
|
43
43
|
|
|
44
|
+
// a game's store page on the web.
|
|
45
|
+
const storeUrl = function (game) {
|
|
46
|
+
return `${cfguri.HOST_HTTP_WWW}${storePage(game)}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// [function]
|
|
50
|
+
|
|
51
|
+
// a game's page in Studio, on one of its tabs, such as `builds`.
|
|
52
|
+
const studioUrl = function (game, tab) {
|
|
53
|
+
return `${cfguri.HOST_HTTP_STUDIO}/games/${game}/${tab}`;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// [function]
|
|
57
|
+
|
|
44
58
|
// where a deployed version will be, once it's published: its channel, that
|
|
45
59
|
// channel's play link, and for production, its store page.
|
|
46
60
|
const published = function ({ handle, id, version }) {
|
|
47
61
|
const game = handle ?? id;
|
|
48
62
|
const release = channel(version);
|
|
49
|
-
const store =
|
|
50
|
-
release === PRODUCTION ? `${cfguri.HOST_HTTP_WWW}${storePage(game)}` : null;
|
|
63
|
+
const store = release === PRODUCTION ? storeUrl(game) : null;
|
|
51
64
|
return { channel: release, store, url: playUrl(game, release) };
|
|
52
65
|
};
|
|
53
66
|
|
|
@@ -60,4 +73,6 @@ module.exports = {
|
|
|
60
73
|
playUrl,
|
|
61
74
|
published,
|
|
62
75
|
storePage,
|
|
76
|
+
storeUrl,
|
|
77
|
+
studioUrl,
|
|
63
78
|
};
|
package/src/util/media.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// [import]
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const cfglimit = require("../config/limit");
|
|
6
6
|
|
|
7
7
|
// [declare]
|
|
8
8
|
|
|
9
9
|
// a file too large to pack isn't read.
|
|
10
|
-
const MAX_READ =
|
|
10
|
+
const MAX_READ = cfglimit.FILE_SIZE;
|
|
11
11
|
|
|
12
12
|
// [function]
|
|
13
13
|
|
package/src/util/objs.js
CHANGED
|
@@ -29,10 +29,17 @@ const deepCompact = function (obj) {
|
|
|
29
29
|
|
|
30
30
|
// [function]
|
|
31
31
|
|
|
32
|
+
// a TOML table: an object, not an array.
|
|
33
|
+
const isTable = function (value) {
|
|
34
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// [function]
|
|
38
|
+
|
|
32
39
|
const deepSort = function (obj) {
|
|
33
40
|
return JSON.parse(stringify(obj));
|
|
34
41
|
};
|
|
35
42
|
|
|
36
43
|
// [export]
|
|
37
44
|
|
|
38
|
-
module.exports = { deepCompact, deepSort };
|
|
45
|
+
module.exports = { deepCompact, deepSort, isTable };
|
package/src/util/output.js
CHANGED
|
@@ -41,7 +41,7 @@ const printToml = function (data, key, nl = false) {
|
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
43
|
write(TOML.stringify(deepSort(data)), nl);
|
|
44
|
-
} catch
|
|
44
|
+
} catch {
|
|
45
45
|
write(TOML.stringify(deepSort({ [field]: data })), nl);
|
|
46
46
|
}
|
|
47
47
|
};
|
|
@@ -107,6 +107,20 @@ const abort = function (
|
|
|
107
107
|
|
|
108
108
|
// [function]
|
|
109
109
|
|
|
110
|
+
// where arc open or arc play opened the page, with its URL, or that it
|
|
111
|
+
// couldn't, with the URL to open by hand.
|
|
112
|
+
const launched = function (where, url) {
|
|
113
|
+
if (where) {
|
|
114
|
+
log.result(phrase.opened(where), [url]);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
log.result(phrase.unableToOpen(), [url, phrase.openToContinue()], {
|
|
118
|
+
color: "yellow",
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// [function]
|
|
123
|
+
|
|
110
124
|
// arc validate's warnings, such as an unknown field, on stderr in yellow,
|
|
111
125
|
// before a command that validates goes on. Left out with `--json` and
|
|
112
126
|
// `--quiet`; arc validate --json lists them.
|
|
@@ -134,4 +148,12 @@ const warning = function (code, message, path = null) {
|
|
|
134
148
|
|
|
135
149
|
// [export]
|
|
136
150
|
|
|
137
|
-
module.exports = {
|
|
151
|
+
module.exports = {
|
|
152
|
+
abort,
|
|
153
|
+
launched,
|
|
154
|
+
print,
|
|
155
|
+
printJson,
|
|
156
|
+
printToml,
|
|
157
|
+
warn,
|
|
158
|
+
warning,
|
|
159
|
+
};
|
package/src/util/rc.js
CHANGED
|
@@ -81,7 +81,7 @@ const read = function (file) {
|
|
|
81
81
|
let str = null;
|
|
82
82
|
try {
|
|
83
83
|
str = readFileSync(file, "utf8");
|
|
84
|
-
} catch
|
|
84
|
+
} catch {
|
|
85
85
|
return {};
|
|
86
86
|
}
|
|
87
87
|
if (!/^\s*\{/u.test(str)) {
|
|
@@ -111,7 +111,7 @@ const findRc = function (cmd, subcmd, argv) {
|
|
|
111
111
|
{},
|
|
112
112
|
);
|
|
113
113
|
} catch (ex) {
|
|
114
|
-
return abort(
|
|
114
|
+
return abort(phrase.aborted(subcmd), ex, {
|
|
115
115
|
json: args.json(argv),
|
|
116
116
|
});
|
|
117
117
|
}
|
package/src/util/request.js
CHANGED
package/src/util/s3.js
CHANGED
package/src/util/schema.js
CHANGED
|
@@ -24,7 +24,7 @@ const NUMBERS = new Set(["bigint", "int", "number"]);
|
|
|
24
24
|
// a zod issue's code (config/code.js, ISSUE). Our own checks name theirs in
|
|
25
25
|
// params; zod's built-in ones, which drop params, are named from what zod
|
|
26
26
|
// reports. Anything else is `invalid`, so every issue has a code.
|
|
27
|
-
const
|
|
27
|
+
const issueCodeOf = function (issue) {
|
|
28
28
|
switch (issue.code) {
|
|
29
29
|
case "custom":
|
|
30
30
|
return issue.params?.code ?? ISSUE.INVALID;
|
|
@@ -71,7 +71,7 @@ const codeOf = function (issue) {
|
|
|
71
71
|
const toIssue = function (name, issue) {
|
|
72
72
|
const { details, message } = schemaMessage.parse(issue.message);
|
|
73
73
|
return {
|
|
74
|
-
code:
|
|
74
|
+
code: issueCodeOf(issue),
|
|
75
75
|
details,
|
|
76
76
|
link: issue.path.length
|
|
77
77
|
? schemaMessage.link(name, String(issue.path[0]))
|
|
@@ -128,4 +128,10 @@ const validator = function (name, schema) {
|
|
|
128
128
|
|
|
129
129
|
// [export]
|
|
130
130
|
|
|
131
|
-
module.exports = {
|
|
131
|
+
module.exports = {
|
|
132
|
+
compare,
|
|
133
|
+
dereference,
|
|
134
|
+
issueCodeOf,
|
|
135
|
+
print,
|
|
136
|
+
validator,
|
|
137
|
+
};
|
package/src/util/uris.js
CHANGED
package/src/util/zip.js
CHANGED