arcadible 0.1.23 → 0.1.24
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-validate.js +13 -2
- package/package.json +1 -1
- package/src/schema/game.js +70 -22
- package/src/schema/workflow.js +3 -3
- package/src/util/bytes.js +20 -0
- package/src/util/image.js +10 -8
- package/src/util/progress.js +5 -15
- package/src/util/schema.js +26 -2
- package/src/util/video.js +14 -9
package/bin/arc-validate.js
CHANGED
|
@@ -17,10 +17,12 @@ const cfgproduct = require("../src/config/product");
|
|
|
17
17
|
const log = require("../src/util/log");
|
|
18
18
|
const output = require("../src/util/output");
|
|
19
19
|
const rc = require("../src/util/rc");
|
|
20
|
+
const schema = require("../src/util/schema");
|
|
20
21
|
const validate = require("../src/cli/validate");
|
|
21
22
|
|
|
22
23
|
// [use]
|
|
23
24
|
|
|
25
|
+
const dereference = schema.dereference;
|
|
24
26
|
const findRc = rc.findRc;
|
|
25
27
|
const print = output.print;
|
|
26
28
|
const resolve = path.resolve;
|
|
@@ -49,8 +51,17 @@ const start = function (argv) {
|
|
|
49
51
|
if (json) {
|
|
50
52
|
print({ issues });
|
|
51
53
|
} else if (count) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
const [probs, refs] = dereference(issues);
|
|
55
|
+
const probcount = probs.length;
|
|
56
|
+
if (probcount) {
|
|
57
|
+
log.hd(`${probcount} ${probcount === 1 ? "issue" : "issues"}:`);
|
|
58
|
+
log.p(probs.map((prob) => `✗ ${prob}`));
|
|
59
|
+
}
|
|
60
|
+
const refcount = refs.length;
|
|
61
|
+
if (refcount) {
|
|
62
|
+
log.h(`${refcount} ${refcount === 1 ? "reference" : "references"}:`);
|
|
63
|
+
log.p(refs);
|
|
64
|
+
}
|
|
54
65
|
} else if (!argv.quiet) {
|
|
55
66
|
log.hs("No issues found.");
|
|
56
67
|
}
|
package/package.json
CHANGED
package/src/schema/game.js
CHANGED
|
@@ -96,33 +96,48 @@ const zMedia = function (field, root) {
|
|
|
96
96
|
// [function]
|
|
97
97
|
|
|
98
98
|
const zPng = function (field, root, opts) {
|
|
99
|
-
return zMedia(field, root).
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
return zMedia(field, root).superRefine((file, ctx) => {
|
|
100
|
+
const issues = imageCheck(root, file, { ...opts, type: cfgimage[".png"] });
|
|
101
|
+
if (issues.length) {
|
|
102
|
+
ctx.addIssue({
|
|
103
|
+
code: "custom",
|
|
104
|
+
...message(field, ["Invalid PNG.", ...issues]),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
103
108
|
};
|
|
104
109
|
|
|
105
110
|
// [function]
|
|
106
111
|
|
|
107
112
|
const zSvg = function (field, root, opts) {
|
|
108
|
-
return zMedia(field, root).
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
return zMedia(field, root).superRefine((file, ctx) => {
|
|
114
|
+
const issues = imageCheck(root, file, { ...opts, type: cfgimage[".svg"] });
|
|
115
|
+
if (issues.length) {
|
|
116
|
+
ctx.addIssue({
|
|
117
|
+
code: "custom",
|
|
118
|
+
...message(field, ["Invalid SVG.", ...issues]),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
112
122
|
};
|
|
113
123
|
|
|
114
124
|
// [function]
|
|
115
125
|
|
|
116
126
|
const zMp4 = function (field, root, opts) {
|
|
117
|
-
return zMedia(field, root).
|
|
118
|
-
(file
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
return zMedia(field, root).superRefine((file, ctx) => {
|
|
128
|
+
const issues = videoCheck(root, file, {
|
|
129
|
+
maxDuration: 30,
|
|
130
|
+
minDuration: 3,
|
|
131
|
+
...opts,
|
|
132
|
+
type: cfgvideo[".mp4"],
|
|
133
|
+
});
|
|
134
|
+
if (issues.length) {
|
|
135
|
+
ctx.addIssue({
|
|
136
|
+
code: "custom",
|
|
137
|
+
...message(field, ["Invalid MP4.", ...issues]),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
126
141
|
};
|
|
127
142
|
|
|
128
143
|
// [function]
|
|
@@ -243,11 +258,44 @@ const zGallery = function (root) {
|
|
|
243
258
|
return z.optional(
|
|
244
259
|
z
|
|
245
260
|
.array(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
zMedia(field, root).superRefine((file, ctx) => {
|
|
262
|
+
if (file.endsWith(".png")) {
|
|
263
|
+
const issues = imageCheck(root, file, {
|
|
264
|
+
maxSize: size.mb(2),
|
|
265
|
+
type: cfgimage[".png"],
|
|
266
|
+
});
|
|
267
|
+
if (issues.length) {
|
|
268
|
+
ctx.addIssue({
|
|
269
|
+
code: "custom",
|
|
270
|
+
...message(field, [`Invalid PNG: ${file}`, ...issues]),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
} else if (file.endsWith(".svg")) {
|
|
274
|
+
const issues = imageCheck(root, file, {
|
|
275
|
+
maxSize: size.mb(1),
|
|
276
|
+
type: cfgimage[".svg"],
|
|
277
|
+
});
|
|
278
|
+
if (issues.length) {
|
|
279
|
+
ctx.addIssue({
|
|
280
|
+
code: "custom",
|
|
281
|
+
...message(field, [`Invalid SVG: ${file}`, ...issues]),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
} else if (file.endsWith(".mp4")) {
|
|
285
|
+
const issues = videoCheck(root, file, {
|
|
286
|
+
maxDuration: 30,
|
|
287
|
+
maxSize: size.mb(15),
|
|
288
|
+
minDuration: 3,
|
|
289
|
+
type: cfgvideo[".mp4"],
|
|
290
|
+
});
|
|
291
|
+
if (issues.length) {
|
|
292
|
+
ctx.addIssue({
|
|
293
|
+
code: "custom",
|
|
294
|
+
...message(field, [`Invalid MP4: ${file}`, ...issues]),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}),
|
|
251
299
|
)
|
|
252
300
|
.min(1)
|
|
253
301
|
.max(12),
|
package/src/schema/workflow.js
CHANGED
|
@@ -29,7 +29,7 @@ const MEDIA = `.${HANDLE}`;
|
|
|
29
29
|
// [function]
|
|
30
30
|
|
|
31
31
|
const reference = function (field) {
|
|
32
|
-
return chalk.cyan.underline(`${cfgurl.MANIFEST}#
|
|
32
|
+
return chalk.cyan.underline(`${cfgurl.MANIFEST}#game.${field}`);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// [function]
|
|
@@ -64,11 +64,11 @@ const zDeployDir = function (root, { build }) {
|
|
|
64
64
|
)
|
|
65
65
|
.refine(
|
|
66
66
|
(file) => isOutCheck(root, file),
|
|
67
|
-
message(field, ["Must be within the project
|
|
67
|
+
message(field, ["Must be within the project."]),
|
|
68
68
|
)
|
|
69
69
|
.refine(
|
|
70
70
|
(file) => isReservedCheck(root, file, MEDIA),
|
|
71
|
-
message(field, [`Must not contain ${MEDIA}.`]),
|
|
71
|
+
message(field, [`Must not contain ${MEDIA} in path.`]),
|
|
72
72
|
)
|
|
73
73
|
.refine(
|
|
74
74
|
(file) => build || existsCheck(root, file),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// [function]
|
|
4
|
+
|
|
5
|
+
const formatBytes = function (bytes) {
|
|
6
|
+
switch (true) {
|
|
7
|
+
case bytes < 1024:
|
|
8
|
+
return `${bytes} B`;
|
|
9
|
+
case bytes < 1024 ** 2:
|
|
10
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
11
|
+
case bytes < 1024 ** 3:
|
|
12
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
13
|
+
default:
|
|
14
|
+
return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// [export]
|
|
19
|
+
|
|
20
|
+
module.exports = { formatBytes };
|
package/src/util/image.js
CHANGED
|
@@ -11,11 +11,13 @@ const imageSize = require("image-size").imageSize;
|
|
|
11
11
|
|
|
12
12
|
// [import]
|
|
13
13
|
|
|
14
|
+
const bytes = require("./bytes");
|
|
14
15
|
const cfgimage = require("../config/image");
|
|
15
16
|
|
|
16
17
|
// [use]
|
|
17
18
|
|
|
18
19
|
const extname = path.extname;
|
|
20
|
+
const formatBytes = bytes.formatBytes;
|
|
19
21
|
const readFileSync = fs.readFileSync; // eslint-disable-line no-sync
|
|
20
22
|
const statSync = fs.statSync; // eslint-disable-line no-sync
|
|
21
23
|
|
|
@@ -50,29 +52,29 @@ const checkSize = function (file, maxSize) {
|
|
|
50
52
|
|
|
51
53
|
const checkPng = function (file, { aspect, maxSize, minHeight, minWidth }) {
|
|
52
54
|
if (!checkSize(file, maxSize)) {
|
|
53
|
-
return
|
|
55
|
+
return [`Image size must not exceed: ${formatBytes(maxSize)}`];
|
|
54
56
|
}
|
|
55
57
|
const buffer = readFileSync(file);
|
|
56
58
|
const { height, width } = imageSize(buffer);
|
|
57
59
|
if (minWidth && width < minWidth) {
|
|
58
|
-
return
|
|
60
|
+
return [`Image width must be at least: ${minWidth}px`];
|
|
59
61
|
}
|
|
60
62
|
if (minHeight && height < minHeight) {
|
|
61
|
-
return
|
|
63
|
+
return [`Image height must be at least: ${minHeight}px`];
|
|
62
64
|
}
|
|
63
65
|
if (!checkAspect(width, height, aspect)) {
|
|
64
|
-
return
|
|
66
|
+
return [`Image aspect ratio must be: ${aspect}`];
|
|
65
67
|
}
|
|
66
|
-
return
|
|
68
|
+
return [];
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
// [function]
|
|
70
72
|
|
|
71
73
|
const checkSvg = function (file, { maxSize }) {
|
|
72
74
|
if (!checkSize(file, maxSize)) {
|
|
73
|
-
return
|
|
75
|
+
return [`Image size must not exceed: ${formatBytes(maxSize)}`];
|
|
74
76
|
}
|
|
75
|
-
return
|
|
77
|
+
return [];
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
// [function]
|
|
@@ -85,7 +87,7 @@ const check = function (file, { type, ...opts }) {
|
|
|
85
87
|
const checkImage = checks[type];
|
|
86
88
|
return checkImage && cfgimage[extname(file)] === type
|
|
87
89
|
? checkImage(file, opts)
|
|
88
|
-
:
|
|
90
|
+
: ["Image has an unsupported file type."];
|
|
89
91
|
};
|
|
90
92
|
|
|
91
93
|
// [export]
|
package/src/util/progress.js
CHANGED
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
const cliProgress = require("cli-progress");
|
|
6
6
|
|
|
7
|
+
// [import]
|
|
8
|
+
|
|
9
|
+
const bytes = require("./bytes");
|
|
10
|
+
|
|
7
11
|
// [use]
|
|
8
12
|
|
|
13
|
+
const formatBytes = bytes.formatBytes;
|
|
9
14
|
const Presets = cliProgress.Presets;
|
|
10
15
|
const SingleBar = cliProgress.SingleBar;
|
|
11
16
|
|
|
@@ -15,21 +20,6 @@ const FORMAT = "[{bar}] {percentage}% | {value}/{total}";
|
|
|
15
20
|
|
|
16
21
|
// [function]
|
|
17
22
|
|
|
18
|
-
const formatBytes = function (bytes) {
|
|
19
|
-
switch (true) {
|
|
20
|
-
case bytes < 1000:
|
|
21
|
-
return `${bytes} B`;
|
|
22
|
-
case bytes < 1000 * 1000:
|
|
23
|
-
return `${(bytes / 1000).toFixed(1)} KB`;
|
|
24
|
-
case bytes < 1000 * 1000 * 1000:
|
|
25
|
-
return `${(bytes / 1000 / 1000).toFixed(1)} MB`;
|
|
26
|
-
default:
|
|
27
|
-
return `${(bytes / 1000 / 1000 / 1000).toFixed(1)} GB`;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// [function]
|
|
32
|
-
|
|
33
23
|
const formatValue = function (value, opts, type) {
|
|
34
24
|
if (type === "percentage") {
|
|
35
25
|
return value;
|
package/src/util/schema.js
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
// [import]
|
|
4
|
+
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
|
|
7
|
+
// [function]
|
|
8
|
+
|
|
9
|
+
const dereference = function (issues) {
|
|
10
|
+
const references = new Set();
|
|
11
|
+
const output = issues.map((issue) =>
|
|
12
|
+
issue
|
|
13
|
+
.split("\n")
|
|
14
|
+
.filter((line) => {
|
|
15
|
+
if (/https?:\/\//u.test(line)) {
|
|
16
|
+
references.add(line.trim());
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
})
|
|
21
|
+
.join("\n"),
|
|
22
|
+
);
|
|
23
|
+
return [output, [...references]];
|
|
24
|
+
};
|
|
25
|
+
|
|
3
26
|
// [function]
|
|
4
27
|
|
|
5
28
|
const format = function (name, { issues }) {
|
|
6
29
|
return issues.map(
|
|
7
|
-
({ message, path }) =>
|
|
30
|
+
({ message, path }) =>
|
|
31
|
+
`${chalk.cyan(`${name}.${path.join(".") || "value"}`)}: ${message}`,
|
|
8
32
|
);
|
|
9
33
|
};
|
|
10
34
|
|
|
@@ -22,4 +46,4 @@ const validator = function (name, schema) {
|
|
|
22
46
|
|
|
23
47
|
// [export]
|
|
24
48
|
|
|
25
|
-
module.exports = { validator };
|
|
49
|
+
module.exports = { dereference, validator };
|
package/src/util/video.js
CHANGED
|
@@ -11,12 +11,14 @@ const fs = require("fs-extra");
|
|
|
11
11
|
|
|
12
12
|
// [import]
|
|
13
13
|
|
|
14
|
+
const bytes = require("./bytes");
|
|
14
15
|
const cfgvideo = require("../config/video");
|
|
15
16
|
const phrase = require("../phrase");
|
|
16
17
|
|
|
17
18
|
// [use]
|
|
18
19
|
|
|
19
20
|
const extname = path.extname;
|
|
21
|
+
const formatBytes = bytes.formatBytes;
|
|
20
22
|
const readFileSync = fs.readFileSync; // eslint-disable-line no-sync
|
|
21
23
|
const statSync = fs.statSync; // eslint-disable-line no-sync
|
|
22
24
|
|
|
@@ -89,31 +91,34 @@ const readMp4 = function (file) {
|
|
|
89
91
|
|
|
90
92
|
const checkMp4 = function (
|
|
91
93
|
file,
|
|
92
|
-
{ aspect, maxDuration, maxSize, minHeight, minWidth },
|
|
94
|
+
{ aspect, maxDuration, maxSize, minDuration, minHeight, minWidth },
|
|
93
95
|
) {
|
|
94
96
|
if (!checkSize(file, maxSize)) {
|
|
95
|
-
return
|
|
97
|
+
return [`Video size must not exceed: ${formatBytes(maxSize)}`];
|
|
96
98
|
}
|
|
97
99
|
let video = null;
|
|
98
100
|
try {
|
|
99
101
|
video = readMp4(file);
|
|
100
102
|
} catch {
|
|
101
|
-
return
|
|
103
|
+
return ["Video is an invalid file."];
|
|
102
104
|
}
|
|
103
105
|
const { duration, height, width } = video;
|
|
104
106
|
if (minWidth && width < minWidth) {
|
|
105
|
-
return
|
|
107
|
+
return [`Video width must be at least: ${minWidth}px`];
|
|
106
108
|
}
|
|
107
109
|
if (minHeight && height < minHeight) {
|
|
108
|
-
return
|
|
110
|
+
return [`Video height must be at least: ${minHeight}px`];
|
|
111
|
+
}
|
|
112
|
+
if (minDuration && duration < minDuration) {
|
|
113
|
+
return [`Video duration must be at least: ${minDuration}s`];
|
|
109
114
|
}
|
|
110
115
|
if (maxDuration && duration > maxDuration) {
|
|
111
|
-
return
|
|
116
|
+
return [`Video duration must not exceed: ${maxDuration}s`];
|
|
112
117
|
}
|
|
113
118
|
if (!checkAspect(width, height, aspect)) {
|
|
114
|
-
return
|
|
119
|
+
return [`Video aspect ratio must be: ${aspect}`];
|
|
115
120
|
}
|
|
116
|
-
return
|
|
121
|
+
return [];
|
|
117
122
|
};
|
|
118
123
|
|
|
119
124
|
// [function]
|
|
@@ -125,7 +130,7 @@ const check = function (file, { type, ...opts }) {
|
|
|
125
130
|
const checkVideo = checks[type];
|
|
126
131
|
return checkVideo && cfgvideo[extname(file)] === type
|
|
127
132
|
? checkVideo(file, opts)
|
|
128
|
-
:
|
|
133
|
+
: ["Video has an unsupported file type."];
|
|
129
134
|
};
|
|
130
135
|
|
|
131
136
|
// [export]
|