arcadible 0.1.23 → 0.1.25

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-init.js CHANGED
@@ -16,12 +16,12 @@ const yargs = require("yargs/yargs");
16
16
 
17
17
  const cfgpackage = require("../src/config/package");
18
18
  const cfgproduct = require("../src/config/product");
19
+ const cfgtemplate = require("../src/config/template");
19
20
  const init = require("../src/cli/init");
20
21
  const log = require("../src/util/log");
21
22
  const output = require("../src/util/output");
22
23
  const rc = require("../src/util/rc");
23
24
  const spinner = require("../src/util/spinner");
24
- const template = require("../src/prompt/template");
25
25
 
26
26
  // [use]
27
27
 
@@ -126,11 +126,11 @@ const prompt = async function ({ yes, ...argv }) {
126
126
  const opts = { ...argv };
127
127
  opts.patch = await patch(opts.cwd, opts.project);
128
128
  if (opts.patch || yes) {
129
- opts.template ??= template.select.default;
129
+ opts.template ??= cfgtemplate.default;
130
130
  return opts;
131
131
  }
132
132
  if (!opts.template) {
133
- opts.template = await select(template.select);
133
+ opts.template = await select(cfgtemplate);
134
134
  }
135
135
  return opts;
136
136
  };
@@ -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.25"
65
65
  }
@@ -107,8 +107,8 @@ const createTag = function (root, version, cb) {
107
107
  `${PREFIX}${version}`,
108
108
  "-m",
109
109
  prereleaseSemver(version) === null
110
- ? `Release v${version}`
111
- : `Prerelease v${version}`,
110
+ ? phrase.versionRelease(version)
111
+ : phrase.versionPrerelease(version),
112
112
  ],
113
113
  (err) => {
114
114
  if (err) {
@@ -5,15 +5,15 @@
5
5
  const fs = require("node:fs");
6
6
  const path = require("node:path");
7
7
 
8
+ // [import]
9
+
10
+ const phrase = require("../../phrase");
11
+
8
12
  // [use]
9
13
 
10
14
  const existsSync = fs.existsSync; // eslint-disable-line no-sync
11
15
  const join = path.join;
12
16
 
13
- // [import]
14
-
15
- const phrase = require("../../phrase");
16
-
17
17
  // [function]
18
18
 
19
19
  const ensureLockFile = function (root, cb) {
@@ -3,6 +3,7 @@
3
3
  // [import]
4
4
 
5
5
  const git = require("./git");
6
+ const phrase = require("../../phrase");
6
7
  const pm = require("./pm");
7
8
  const project = require("../../parser/project");
8
9
 
@@ -42,7 +43,7 @@ const deployEnsureGit = function ({ root }, { onLogInfo }, cb) {
42
43
  if (diff.cached && onLogInfo) {
43
44
  onLogInfo({
44
45
  level: "warn",
45
- message: "Staged but uncommitted changes will not be included.",
46
+ message: phrase.gitStagedUnincluded(),
46
47
  });
47
48
  }
48
49
  ensureRemote(root, cb);
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cfgproduct = require("./product");
6
+ const phrase = require("../phrase");
7
+
8
+ // [declare]
9
+
10
+ const HANDLE = cfgproduct.handle;
11
+ const STARTER = `${HANDLE}/starter`;
12
+
13
+ // [export]
14
+
15
+ module.exports = {
16
+ choices: [
17
+ {
18
+ description: phrase.starterBlank(),
19
+ name: "Blank",
20
+ value: STARTER,
21
+ },
22
+ {
23
+ description: phrase.starterThreeJs(),
24
+ name: "Three.js",
25
+ value: `${STARTER}-threejs`,
26
+ },
27
+ {
28
+ description: phrase.starterPhaser(),
29
+ name: "Phaser",
30
+ value: `${STARTER}-phaser`,
31
+ },
32
+ {
33
+ description: phrase.starterPixiJs(),
34
+ name: "PixiJS",
35
+ value: `${STARTER}-pixijs`,
36
+ },
37
+ {
38
+ description: phrase.starterBabylonJs(),
39
+ name: "Babylon.js",
40
+ value: `${STARTER}-babylonjs`,
41
+ },
42
+ ],
43
+ default: STARTER,
44
+ message: "Template",
45
+ };
package/src/phrase.js CHANGED
@@ -2,8 +2,13 @@
2
2
 
3
3
  // [import]
4
4
 
5
+ const bytes = require("./util/bytes");
5
6
  const cfgproduct = require("./config/product");
6
7
 
8
+ // [use]
9
+
10
+ const formatBytes = bytes.formatBytes;
11
+
7
12
  // [declare]
8
13
 
9
14
  const TOOL = cfgproduct.tool;
@@ -73,6 +78,12 @@ const gitRepoMissing = function () {
73
78
 
74
79
  // [function]
75
80
 
81
+ const gitStagedUnincluded = function () {
82
+ return ["Staged but uncommitted changes will not be included."].join("\n");
83
+ };
84
+
85
+ // [function]
86
+
76
87
  const gitTagCreateFailed = function () {
77
88
  return [
78
89
  "Unable to create Git tag.",
@@ -100,6 +111,42 @@ const gitVersionExists = function () {
100
111
 
101
112
  // [function]
102
113
 
114
+ const httpError = function (name, status) {
115
+ return `HttpError: ${name} (${status})`;
116
+ };
117
+
118
+ // [function]
119
+
120
+ const imageAspect = function (aspect) {
121
+ return `Image aspect ratio must be: ${aspect}`;
122
+ };
123
+
124
+ // [function]
125
+
126
+ const imageHeightMin = function (height) {
127
+ return `Image height must be at least: ${height}px`;
128
+ };
129
+
130
+ // [function]
131
+
132
+ const imageSizeMax = function (size) {
133
+ return `Image size must not exceed: ${formatBytes(size)}`;
134
+ };
135
+
136
+ // [function]
137
+
138
+ const imageUnsupported = function () {
139
+ return "Image has an unsupported file type.";
140
+ };
141
+
142
+ // [function]
143
+
144
+ const imageWidthMin = function (width) {
145
+ return `Image width must be at least: ${width}px`;
146
+ };
147
+
148
+ // [function]
149
+
103
150
  const issuesFound = function (count) {
104
151
  return `${count} ${count === 1 ? "issue" : "issues"} found. Run ${cmdValidate()} for details.`;
105
152
  };
@@ -172,6 +219,60 @@ const packageTooLarge = function (size, assets) {
172
219
 
173
220
  // [function]
174
221
 
222
+ const sizeB = function (size) {
223
+ return `${size} B`;
224
+ };
225
+
226
+ // [function]
227
+
228
+ const sizeGb = function (size) {
229
+ return `${size} GB`;
230
+ };
231
+
232
+ // [function]
233
+
234
+ const sizeKb = function (size) {
235
+ return `${size} KB`;
236
+ };
237
+
238
+ // [function]
239
+
240
+ const sizeMb = function (size) {
241
+ return `${size} MB`;
242
+ };
243
+
244
+ // [function]
245
+
246
+ const starterBabylonJs = function () {
247
+ return "Babylon.js starter.";
248
+ };
249
+
250
+ // [function]
251
+
252
+ const starterBlank = function () {
253
+ return "Blank JavaScript starter.";
254
+ };
255
+
256
+ // [function]
257
+
258
+ const starterPhaser = function () {
259
+ return "Phaser starter.";
260
+ };
261
+
262
+ // [function]
263
+
264
+ const starterPixiJs = function () {
265
+ return "PixiJS starter.";
266
+ };
267
+
268
+ // [function]
269
+
270
+ const starterThreeJs = function () {
271
+ return "Three.js starter.";
272
+ };
273
+
274
+ // [function]
275
+
175
276
  const timedOut = function () {
176
277
  return "Timed out.";
177
278
  };
@@ -194,6 +295,66 @@ const uploadFailed = function (status) {
194
295
  return `Upload failed with status ${status}.`;
195
296
  };
196
297
 
298
+ // [function]
299
+
300
+ const versionPrerelease = function (version) {
301
+ return `Prerelease v${version}`;
302
+ };
303
+
304
+ // [function]
305
+
306
+ const versionRelease = function (version) {
307
+ return `Release v${version}`;
308
+ };
309
+
310
+ // [function]
311
+
312
+ const videoAspect = function (aspect) {
313
+ return `Video aspect ratio must be: ${aspect}`;
314
+ };
315
+
316
+ // [function]
317
+
318
+ const videoDurationMax = function (maxDuration) {
319
+ return `Video duration must not exceed: ${maxDuration}s`;
320
+ };
321
+
322
+ // [function]
323
+
324
+ const videoDurationMin = function (duration) {
325
+ return `Video duration must be at least: ${duration}s`;
326
+ };
327
+
328
+ // [function]
329
+
330
+ const videoHeightMin = function (height) {
331
+ return `Video height must be at least: ${height}px`;
332
+ };
333
+
334
+ // [function]
335
+
336
+ const videoInvalid = function () {
337
+ return "Video is an invalid file.";
338
+ };
339
+
340
+ // [function]
341
+
342
+ const videoSizeMax = function (size) {
343
+ return `Video size must not exceed: ${formatBytes(size)}`;
344
+ };
345
+
346
+ // [function]
347
+
348
+ const videoUnsupported = function () {
349
+ return "Video has an unsupported file type.";
350
+ };
351
+
352
+ // [function]
353
+
354
+ const videoWidthMin = function (width) {
355
+ return `Video width must be at least: ${width}px`;
356
+ };
357
+
197
358
  // [export]
198
359
 
199
360
  module.exports = {
@@ -206,9 +367,16 @@ module.exports = {
206
367
  gitChangesPresent,
207
368
  gitRemoteMissing,
208
369
  gitRepoMissing,
370
+ gitStagedUnincluded,
209
371
  gitTagCreateFailed,
210
372
  gitTagPushFailed,
211
373
  gitVersionExists,
374
+ httpError,
375
+ imageAspect,
376
+ imageHeightMin,
377
+ imageSizeMax,
378
+ imageUnsupported,
379
+ imageWidthMin,
212
380
  issuesFound,
213
381
  loginExpired,
214
382
  loginFailed,
@@ -221,8 +389,27 @@ module.exports = {
221
389
  overwriteWithForce,
222
390
  packageFileMissing,
223
391
  packageTooLarge,
392
+ sizeB,
393
+ sizeGb,
394
+ sizeKb,
395
+ sizeMb,
396
+ starterBabylonJs,
397
+ starterBlank,
398
+ starterPhaser,
399
+ starterPixiJs,
400
+ starterThreeJs,
224
401
  timedOut,
225
402
  unableToFind,
226
403
  unableToParse,
227
404
  uploadFailed,
405
+ versionPrerelease,
406
+ versionRelease,
407
+ videoAspect,
408
+ videoDurationMax,
409
+ videoDurationMin,
410
+ videoHeightMin,
411
+ videoInvalid,
412
+ videoSizeMax,
413
+ videoUnsupported,
414
+ videoWidthMin,
228
415
  };
@@ -64,8 +64,8 @@ const message = function (field, lines) {
64
64
  const zText = function (field, { max, min }) {
65
65
  return z
66
66
  .string()
67
- .min(min)
68
- .max(max)
67
+ .min(min, message(field, [`Must be at least: ${min} character`]))
68
+ .max(max, message(field, [`Must not exceed: ${max} characters`]))
69
69
  .regex(
70
70
  /^[\p{L}0-9 .,!?'"():;-]+$/u,
71
71
  message(field, ["Contains invalid characters."]),
@@ -77,7 +77,7 @@ const zText = function (field, { max, min }) {
77
77
  const zMedia = function (field, root) {
78
78
  return z
79
79
  .string()
80
- .min(1)
80
+ .min(1, message(field, ["Must be defined."]))
81
81
  .refine(
82
82
  (file) => isRelativeCheck(root, file),
83
83
  message(field, ["Must be a relative path."]),
@@ -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]
@@ -184,7 +199,7 @@ const zBannerVideo = function (root) {
184
199
 
185
200
  const zBio = function () {
186
201
  const field = "bio";
187
- return z.optional(zText(field, { max: 192, min: 1 }));
202
+ return z.optional(zText(field, { max: 30 * 5, min: 1 }));
188
203
  };
189
204
 
190
205
  // [function]
@@ -222,8 +237,8 @@ const zDescription = function () {
222
237
  return z.optional(
223
238
  z
224
239
  .string()
225
- .min(1)
226
- .max(4000)
240
+ .min(1, message(field, ["Must be at least: 1 character"]))
241
+ .max(3000, message(field, ["Must not exceed: 3000 characters"]))
227
242
  .refine(
228
243
  (str) =>
229
244
  str ===
@@ -243,22 +258,58 @@ 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
- .min(1)
253
- .max(12),
300
+ .max(12, message(field, ["Must not exceed: 12 elements"])),
254
301
  );
255
302
  };
256
303
 
257
304
  // [function]
258
305
 
259
306
  const zGenres = function () {
260
- // const field = "genres";
261
- return z.optional(z.array(z.enum(cfggenre)).max(3));
307
+ const field = "genres";
308
+ return z.optional(
309
+ z
310
+ .array(z.enum(cfggenre))
311
+ .max(3, message(field, ["Must not exceed: 3 elements"])),
312
+ );
262
313
  };
263
314
 
264
315
  // [function]
@@ -324,8 +375,12 @@ const zId = function () {
324
375
  // [function]
325
376
 
326
377
  const zInputs = function () {
327
- // const field = "inputs";
328
- return z.optional(z.array(z.enum(cfginput)).max(3));
378
+ const field = "inputs";
379
+ return z.optional(
380
+ z
381
+ .array(z.enum(cfginput))
382
+ .max(3, message(field, ["Must not exceed: 3 elements"])),
383
+ );
329
384
  };
330
385
 
331
386
  // [function]
@@ -366,29 +421,34 @@ const zPosterVideo = function (root) {
366
421
  // [function]
367
422
 
368
423
  const zPrice = function () {
369
- // const field = "price";
370
- return z.optional(z.int().min(0).max(25));
424
+ const field = "price";
425
+ return z.optional(
426
+ z
427
+ .int()
428
+ .min(0, message(field, ["Must not be below: 0"]))
429
+ .max(25, message(field, ["Must not be above: 25"])),
430
+ );
371
431
  };
372
432
 
373
433
  // [function]
374
434
 
375
435
  const zShortTitle = function () {
376
436
  const field = "short_title";
377
- return z.optional(zText(field, { max: 16, min: 1 }));
437
+ return z.optional(zText(field, { max: 30 / 2, min: 1 }));
378
438
  };
379
439
 
380
440
  // [function]
381
441
 
382
442
  const zTagline = function () {
383
443
  const field = "tagline";
384
- return z.optional(zText(field, { max: 96, min: 1 }));
444
+ return z.optional(zText(field, { max: 30 * 1, min: 1 }));
385
445
  };
386
446
 
387
447
  // [function]
388
448
 
389
449
  const zTitle = function () {
390
450
  const field = "title";
391
- return z.optional(zText(field, { max: 64, min: 1 }));
451
+ return z.optional(zText(field, { max: 30 * 1, min: 1 }));
392
452
  };
393
453
 
394
454
  // [function]
@@ -397,7 +457,7 @@ const zTrailer = function () {
397
457
  const field = "trailer";
398
458
  return z
399
459
  .string()
400
- .max(255)
460
+ .max(255, message(field, ["Must not exceed: 255 characters"]))
401
461
  .refine(
402
462
  (url) =>
403
463
  zVimeo().safeParse(url).success || zYouTube().safeParse(url).success,
@@ -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,24 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const phrase = require("../phrase");
6
+
7
+ // [function]
8
+
9
+ const formatBytes = function (bytes) {
10
+ switch (true) {
11
+ case bytes < 1024:
12
+ return phrase.sizeB(bytes);
13
+ case bytes < 1024 ** 2:
14
+ return phrase.sizeKb((bytes / 1024).toFixed(1));
15
+ case bytes < 1024 ** 3:
16
+ return phrase.sizeMb((bytes / 1024 / 1024).toFixed(1));
17
+ default:
18
+ return phrase.sizeGb((bytes / 1024 / 1024 / 1024).toFixed(1));
19
+ }
20
+ };
21
+
22
+ // [export]
23
+
24
+ module.exports = { formatBytes };
package/src/util/http.js CHANGED
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ // [import]
4
+
5
+ const phrase = require("../phrase");
6
+
3
7
  // [class]
4
8
 
5
9
  const HttpError = class extends Error {
@@ -10,7 +14,7 @@ const HttpError = class extends Error {
10
14
  super(message);
11
15
  this.status = status;
12
16
  this.name = title;
13
- this.message = `HttpError: ${this.name} (${this.status})`;
17
+ this.message = phrase.httpError(this.name, this.status);
14
18
  }
15
19
  };
16
20
 
package/src/util/image.js CHANGED
@@ -12,6 +12,7 @@ const imageSize = require("image-size").imageSize;
12
12
  // [import]
13
13
 
14
14
  const cfgimage = require("../config/image");
15
+ const phrase = require("../phrase");
15
16
 
16
17
  // [use]
17
18
 
@@ -50,29 +51,29 @@ const checkSize = function (file, maxSize) {
50
51
 
51
52
  const checkPng = function (file, { aspect, maxSize, minHeight, minWidth }) {
52
53
  if (!checkSize(file, maxSize)) {
53
- return false;
54
+ return [phrase.imageSizeMax(maxSize)];
54
55
  }
55
56
  const buffer = readFileSync(file);
56
57
  const { height, width } = imageSize(buffer);
57
58
  if (minWidth && width < minWidth) {
58
- return false;
59
+ return [phrase.imageWidthMin(minWidth)];
59
60
  }
60
61
  if (minHeight && height < minHeight) {
61
- return false;
62
+ return [phrase.imageHeightMin(minHeight)];
62
63
  }
63
64
  if (!checkAspect(width, height, aspect)) {
64
- return false;
65
+ return [phrase.imageAspect(aspect)];
65
66
  }
66
- return true;
67
+ return [];
67
68
  };
68
69
 
69
70
  // [function]
70
71
 
71
72
  const checkSvg = function (file, { maxSize }) {
72
73
  if (!checkSize(file, maxSize)) {
73
- return false;
74
+ return [phrase.imageSizeMax(maxSize)];
74
75
  }
75
- return true;
76
+ return [];
76
77
  };
77
78
 
78
79
  // [function]
@@ -85,7 +86,7 @@ const check = function (file, { type, ...opts }) {
85
86
  const checkImage = checks[type];
86
87
  return checkImage && cfgimage[extname(file)] === type
87
88
  ? checkImage(file, opts)
88
- : false;
89
+ : [phrase.imageUnsupported()];
89
90
  };
90
91
 
91
92
  // [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
@@ -89,31 +89,34 @@ const readMp4 = function (file) {
89
89
 
90
90
  const checkMp4 = function (
91
91
  file,
92
- { aspect, maxDuration, maxSize, minHeight, minWidth },
92
+ { aspect, maxDuration, maxSize, minDuration, minHeight, minWidth },
93
93
  ) {
94
94
  if (!checkSize(file, maxSize)) {
95
- return false;
95
+ return [phrase.videoSizeMax(maxSize)];
96
96
  }
97
97
  let video = null;
98
98
  try {
99
99
  video = readMp4(file);
100
100
  } catch {
101
- return false;
101
+ return [phrase.videoInvalid()];
102
102
  }
103
103
  const { duration, height, width } = video;
104
104
  if (minWidth && width < minWidth) {
105
- return false;
105
+ return [phrase.videoWidthMin(minWidth)];
106
106
  }
107
107
  if (minHeight && height < minHeight) {
108
- return false;
108
+ return [phrase.videoHeightMin(minHeight)];
109
+ }
110
+ if (minDuration && duration < minDuration) {
111
+ return [phrase.videoDurationMin(minDuration)];
109
112
  }
110
113
  if (maxDuration && duration > maxDuration) {
111
- return false;
114
+ return [phrase.videoDurationMax(maxDuration)];
112
115
  }
113
116
  if (!checkAspect(width, height, aspect)) {
114
- return false;
117
+ return [phrase.videoAspect(aspect)];
115
118
  }
116
- return true;
119
+ return [];
117
120
  };
118
121
 
119
122
  // [function]
@@ -125,7 +128,7 @@ const check = function (file, { type, ...opts }) {
125
128
  const checkVideo = checks[type];
126
129
  return checkVideo && cfgvideo[extname(file)] === type
127
130
  ? checkVideo(file, opts)
128
- : false;
131
+ : [phrase.videoUnsupported()];
129
132
  };
130
133
 
131
134
  // [export]
@@ -1,46 +0,0 @@
1
- "use strict";
2
-
3
- // [import]
4
-
5
- const cfgproduct = require("../config/product");
6
-
7
- // [declare]
8
-
9
- const HANDLE = cfgproduct.handle;
10
- const STARTER = `${HANDLE}/starter`;
11
-
12
- // [export]
13
-
14
- module.exports = {
15
- select: {
16
- choices: [
17
- {
18
- description: "Blank JavaScript starter.",
19
- name: "Blank",
20
- value: STARTER,
21
- },
22
- {
23
- description: "Three.js starter.",
24
- name: "Three.js",
25
- value: `${STARTER}-threejs`,
26
- },
27
- {
28
- description: "Phaser starter.",
29
- name: "Phaser",
30
- value: `${STARTER}-phaser`,
31
- },
32
- {
33
- description: "PixiJS starter.",
34
- name: "PixiJS",
35
- value: `${STARTER}-pixijs`,
36
- },
37
- {
38
- description: "Babylon.js starter.",
39
- name: "Babylon.js",
40
- value: `${STARTER}-babylonjs`,
41
- },
42
- ],
43
- default: STARTER,
44
- message: "Template",
45
- },
46
- };