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.
@@ -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
- log.hd(`${count} ${count === 1 ? "issue" : "issues"} found.`);
53
- log.p(issues.map((issue) => `✗ ${issue}`));
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
@@ -61,5 +61,5 @@
61
61
  "license": "Apache-2.0",
62
62
  "main": "./src/cli/index.js",
63
63
  "name": "arcadible",
64
- "version": "0.1.23"
64
+ "version": "0.1.24"
65
65
  }
@@ -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).refine(
100
- (file) => imageCheck(root, file, { ...opts, type: cfgimage[".png"] }),
101
- message(field, ["Invalid PNG."]),
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).refine(
109
- (file) => imageCheck(root, file, { ...opts, type: cfgimage[".svg"] }),
110
- message(field, ["Invalid SVG."]),
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).refine(
118
- (file) =>
119
- videoCheck(root, file, {
120
- maxDuration: 30,
121
- ...opts,
122
- type: cfgvideo[".mp4"],
123
- }),
124
- message(field, ["Invalid MP4."]),
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
- z.union([
247
- zPng(field, root, { maxSize: size.mb(2) }),
248
- zSvg(field, root, { maxSize: size.mb(1) }),
249
- zMp4(field, root, { maxSize: size.mb(15) }),
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),
@@ -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}#workflow.${field}`);
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 directory."]),
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 false;
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 false;
60
+ return [`Image width must be at least: ${minWidth}px`];
59
61
  }
60
62
  if (minHeight && height < minHeight) {
61
- return false;
63
+ return [`Image height must be at least: ${minHeight}px`];
62
64
  }
63
65
  if (!checkAspect(width, height, aspect)) {
64
- return false;
66
+ return [`Image aspect ratio must be: ${aspect}`];
65
67
  }
66
- return true;
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 false;
75
+ return [`Image size must not exceed: ${formatBytes(maxSize)}`];
74
76
  }
75
- return true;
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
- : false;
90
+ : ["Image has an unsupported file type."];
89
91
  };
90
92
 
91
93
  // [export]
@@ -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;
@@ -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 }) => `${name}.${path.join(".") || "value"}: ${message}`,
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 false;
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 false;
103
+ return ["Video is an invalid file."];
102
104
  }
103
105
  const { duration, height, width } = video;
104
106
  if (minWidth && width < minWidth) {
105
- return false;
107
+ return [`Video width must be at least: ${minWidth}px`];
106
108
  }
107
109
  if (minHeight && height < minHeight) {
108
- return false;
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 false;
116
+ return [`Video duration must not exceed: ${maxDuration}s`];
112
117
  }
113
118
  if (!checkAspect(width, height, aspect)) {
114
- return false;
119
+ return [`Video aspect ratio must be: ${aspect}`];
115
120
  }
116
- return true;
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
- : false;
133
+ : ["Video has an unsupported file type."];
129
134
  };
130
135
 
131
136
  // [export]