arcadible 0.1.1 → 0.1.2

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.
@@ -35,7 +35,6 @@ const main = function (argv) {
35
35
  .command("inspect", "Inspect project metadata")
36
36
  .command("login", "Log in to Arcadible")
37
37
  .command("logout", "Log out of Arcadible")
38
- .command("pack", "Package for distribution")
39
38
  .command("validate", "Validate workspace")
40
39
  .command("whoami", "Show current account")
41
40
  .help("help")
package/bin/arc-deploy.js CHANGED
@@ -17,6 +17,7 @@ const log = require("../src/util/log");
17
17
  const output = require("../src/util/output");
18
18
  const pkg = require("../package.json");
19
19
  const rc = require("../src/util/rc");
20
+ const validate = require("../src/cli/validate");
20
21
 
21
22
  // [use]
22
23
 
@@ -32,7 +33,6 @@ const SUBCMD = "deploy";
32
33
  // [define]
33
34
 
34
35
  const conf = {
35
- git: false,
36
36
  json: false,
37
37
  production: false,
38
38
  quiet: false,
@@ -41,24 +41,69 @@ const conf = {
41
41
 
42
42
  // [function]
43
43
 
44
+ const handler = function ({ json, quiet }) {
45
+ return {
46
+ onBegin() {
47
+ if (!json && !quiet) {
48
+ log.p("Deploying project...");
49
+ }
50
+ },
51
+ onInfo({ level, message }) {
52
+ if (json || quiet) {
53
+ return;
54
+ }
55
+ switch (level) {
56
+ case "warn":
57
+ log.pw(`⚠ ${message}`);
58
+ return;
59
+ default:
60
+ log.p(`• ${message}`);
61
+ }
62
+ },
63
+ };
64
+ };
65
+
66
+ // [function]
67
+
44
68
  const start = function (argv) {
45
69
  const json = argv.json;
46
- return deploy({
47
- git: argv.git,
48
- pre: !argv.production,
49
- preId: "rc",
50
- quiet: argv.quiet,
51
- root: resolve(process.cwd(), argv.cwd),
52
- }).catch((ex) => {
53
- const message = ex.message;
54
- if (json) {
55
- print({ error: { message } });
56
- } else {
57
- log.hd("Deploy aborted.");
58
- log.p(message);
59
- }
60
- process.exit(1);
61
- });
70
+ const pre = !argv.production;
71
+ const quiet = argv.quiet;
72
+ const root = resolve(process.cwd(), argv.cwd);
73
+ return validate({ root })
74
+ .then((issues) => {
75
+ const valid = !issues.length;
76
+ if (!valid) {
77
+ throw new Error("Validate failed. Run `arc validate` for details.");
78
+ }
79
+ return deploy({
80
+ direct: false,
81
+ handler: handler({ json, quiet }),
82
+ pre,
83
+ preId: "rc",
84
+ root,
85
+ });
86
+ })
87
+ .then((data) => {
88
+ if (json) {
89
+ print({ version: data });
90
+ return;
91
+ }
92
+ if (!quiet) {
93
+ log.p(`✓ ${pre ? "Prerelease" : "Release"} v${data.to} submitted.`);
94
+ log.hs("Deployed.");
95
+ }
96
+ })
97
+ .catch((ex) => {
98
+ const message = ex.message;
99
+ if (json) {
100
+ print({ error: { message } });
101
+ } else {
102
+ log.hd("Deploy aborted.");
103
+ log.p(message);
104
+ }
105
+ process.exit(1);
106
+ });
62
107
  };
63
108
 
64
109
  // [function]
@@ -74,11 +119,6 @@ const main = function (argv) {
74
119
  describe: "Deploy to production.",
75
120
  type: "boolean",
76
121
  })
77
- .option("git", {
78
- default: conf.git,
79
- describe: "Deploy using Git.",
80
- type: "boolean",
81
- })
82
122
  .option("json", {
83
123
  alias: "j",
84
124
  default: conf.json,
package/bin/arc-init.js CHANGED
@@ -20,7 +20,7 @@ const output = require("../src/util/output");
20
20
  const pkg = require("../package.json");
21
21
  const project = require("../src/prompt/project");
22
22
  const rc = require("../src/util/rc");
23
- const template = require("../src/prompt/template");
23
+ const starter = require("../src/prompt/starter");
24
24
 
25
25
  // [use]
26
26
 
@@ -70,7 +70,7 @@ const start = function (argv) {
70
70
  handler: handler({ json, quiet }),
71
71
  project: argv.project,
72
72
  root,
73
- template: argv.template,
73
+ starter: argv.starter,
74
74
  })
75
75
  .then((data) => {
76
76
  const dir = relative(root, data.path);
@@ -110,14 +110,14 @@ const prompt = async function ({ yes, ...argv }) {
110
110
  const opts = { ...argv };
111
111
  if (yes) {
112
112
  opts.project ??= project.input.default;
113
- opts.template ??= template.select.default;
113
+ opts.starter ??= starter.select.default;
114
114
  return opts;
115
115
  }
116
116
  if (!argv.project) {
117
117
  opts.project = await input(project.input);
118
118
  }
119
- if (!argv.template) {
120
- opts.template = await select(template.select);
119
+ if (!argv.starter) {
120
+ opts.starter = await select(starter.select);
121
121
  }
122
122
  return opts;
123
123
  };
@@ -135,9 +135,9 @@ const main = function (argv) {
135
135
  type: "string",
136
136
  }),
137
137
  )
138
- .option("template", {
138
+ .option("starter", {
139
139
  alias: "t",
140
- describe: "Select a project template.",
140
+ describe: "Select a project starter.",
141
141
  type: "string",
142
142
  })
143
143
  .option("yes", {
package/bin/arc-pack.js CHANGED
@@ -49,7 +49,7 @@ const start = function (argv) {
49
49
  .then((issues) => {
50
50
  const valid = !issues.length;
51
51
  if (!valid) {
52
- throw new Error("Validation failed. Run `arc validate` for details.");
52
+ throw new Error("Validate failed. Run `arc validate` for details.");
53
53
  }
54
54
  return pack({ output: argv.output, root });
55
55
  })
@@ -60,7 +60,6 @@ const start = function (argv) {
60
60
  }
61
61
  if (!quiet) {
62
62
  log.hs("Packed.");
63
- print(data, { toml: true });
64
63
  }
65
64
  })
66
65
  .catch((ex) => {
@@ -44,18 +44,19 @@ const start = function (argv) {
44
44
  const quiet = argv.quiet;
45
45
  return validate({ root: resolve(process.cwd(), argv.cwd) })
46
46
  .then((issues) => {
47
- const valid = !issues.length;
47
+ const count = issues.length;
48
+ const term = count === 1 ? "issue" : "issues";
48
49
  if (json) {
49
50
  print({ issues });
50
- } else if (valid) {
51
- if (!quiet) {
52
- log.hs("Passed.");
51
+ } else if (!quiet) {
52
+ if (count) {
53
+ log.hd(`${count} ${term} found.`);
54
+ log.p(issues.map((error) => `✗ ${error}`));
55
+ } else {
56
+ log.hs("Validated.");
53
57
  }
54
- } else {
55
- log.hd("Failed.");
56
- log.p(issues.map((error) => `✖ ${error}`));
57
58
  }
58
- process.exit(valid ? 0 : 1);
59
+ process.exit(count ? 1 : 0);
59
60
  })
60
61
  .catch((ex) => {
61
62
  const message = ex.message;
package/package.json CHANGED
@@ -18,6 +18,7 @@
18
18
  "degit": "^2.8.6",
19
19
  "dompurify": "^3.3.1",
20
20
  "dot-prop": "^6.0.1",
21
+ "fast-json-stable-stringify": "^2.1.0",
21
22
  "fs-extra": "^11.3.2",
22
23
  "image-size": "^2.0.2",
23
24
  "jsdom": "^27.3.0",
@@ -25,6 +26,7 @@
25
26
  "mp4box": "^2.3.0",
26
27
  "open": "^8.4.2",
27
28
  "rc": "^1.2.8",
29
+ "semver": "^7.7.3",
28
30
  "yargs": "^17.7.2",
29
31
  "zod": "^4.1.13"
30
32
  },
@@ -49,5 +51,5 @@
49
51
  "license": "Apache-2.0",
50
52
  "main": "./src/cli/index.js",
51
53
  "name": "arcadible",
52
- "version": "0.1.1"
54
+ "version": "0.1.2"
53
55
  }
@@ -4,20 +4,189 @@
4
4
 
5
5
  const execFile = require("node:child_process").execFile;
6
6
 
7
+ // [import]
8
+
9
+ const semver = require("semver");
10
+
11
+ // [import]
12
+
13
+ const strs = require("../../util/strs");
14
+
15
+ // [use]
16
+
17
+ const compareSemver = semver.compare;
18
+ const trimWhitespace = strs.trimWhitespace;
19
+ const validSemver = semver.valid;
20
+
21
+ // [declare]
22
+
23
+ const PREFIX = "arcadible/release/v";
24
+
25
+ // [function]
26
+
27
+ const git = function (root, args, cb) {
28
+ execFile("git", ["-C", root, ...args], cb);
29
+ };
30
+
31
+ // [function]
32
+
33
+ const ensureRepo = function (root, cb) {
34
+ const message = [
35
+ "Unable to find Git repository.",
36
+ "Run this command from a Git repository.",
37
+ ];
38
+ git(root, ["rev-parse", "--is-inside-work-tree"], (err) => {
39
+ if (err) {
40
+ cb(new Error(message.join("\n"), { cause: err }));
41
+ return;
42
+ }
43
+ cb();
44
+ });
45
+ };
46
+
47
+ // [function]
48
+
49
+ const ensureRemote = function (root, cb) {
50
+ const message = [
51
+ "Unable to access Git remote 'origin'.",
52
+ "Verify the remote exists and you have permission to access it.",
53
+ ];
54
+ git(root, ["ls-remote", "origin"], (err) => {
55
+ if (err) {
56
+ cb(new Error(message.join("\n"), { cause: err }));
57
+ return;
58
+ }
59
+ cb();
60
+ });
61
+ };
62
+
7
63
  // [function]
8
64
 
9
- const isDirty = function (root, cb) {
10
- execFile("git", ["-C", root, "diff", "--quiet"], (err) => {
65
+ const ensureClean = function (root, cb) {
66
+ const message = [
67
+ "Unable to continue with unstaged changes.",
68
+ "Stage, commit, or discard local changes before deploying.",
69
+ ];
70
+ git(root, ["diff", "--quiet"], (err) => {
11
71
  if (err) {
12
- cb(true);
72
+ if (err.code === 1) {
73
+ cb(new Error(message.join("\n"), { cause: err }));
74
+ return;
75
+ }
76
+ cb(err);
13
77
  return;
14
78
  }
15
- execFile("git", ["-C", root, "diff", "--cached", "--quiet"], (err) => {
16
- cb(Boolean(err));
79
+ git(root, ["diff", "--cached", "--quiet"], (err) => {
80
+ if (!err) {
81
+ cb(null, { cached: false });
82
+ return;
83
+ }
84
+ if (err.code === 1) {
85
+ cb(null, { cached: true });
86
+ return;
87
+ }
88
+ cb(err);
17
89
  });
18
90
  });
19
91
  };
20
92
 
93
+ // [function]
94
+
95
+ const fetchTags = function (root, cb) {
96
+ const message = [
97
+ "Unable to synchronize Git release tags.",
98
+ "Run `arc deploy` again to retry with the latest release tags.",
99
+ ];
100
+ git(
101
+ root,
102
+ ["fetch", "origin", `refs/tags/${PREFIX}*:refs/tags/${PREFIX}*`],
103
+ (err) => {
104
+ if (err) {
105
+ cb(new Error(message.join("\n"), { cause: err }));
106
+ return;
107
+ }
108
+ cb();
109
+ },
110
+ );
111
+ };
112
+
113
+ // [function]
114
+
115
+ const listTags = function (root, cb) {
116
+ fetchTags(root, (err) => {
117
+ if (err) {
118
+ cb(err);
119
+ return;
120
+ }
121
+ git(root, ["tag", "--list", `${PREFIX}*`], (err, stdOut) => {
122
+ if (err) {
123
+ cb(err);
124
+ return;
125
+ }
126
+ const versions = trimWhitespace(stdOut)
127
+ .split("\n")
128
+ .map((tag) => tag.slice(PREFIX.length))
129
+ .filter(validSemver)
130
+ .sort(compareSemver);
131
+ cb(null, versions.at(-1) || "0.0.0");
132
+ });
133
+ });
134
+ };
135
+
136
+ // [function]
137
+
138
+ const createTag = function (root, version, pre, cb) {
139
+ const message = [
140
+ "Unable to create Git tag.",
141
+ "Verify the release tag does not already exist locally.",
142
+ ];
143
+ git(
144
+ root,
145
+ [
146
+ "tag",
147
+ "-a",
148
+ `${PREFIX}${version}`,
149
+ "-m",
150
+ pre ? `Prerelease v${version}` : `Release v${version}`,
151
+ ],
152
+ (err) => {
153
+ if (err) {
154
+ cb(new Error(message.join("\n"), { cause: err }));
155
+ return;
156
+ }
157
+ cb();
158
+ },
159
+ );
160
+ };
161
+
162
+ // [function]
163
+
164
+ const pushTag = function (root, version, cb) {
165
+ const message = [
166
+ "Unable to push Git tag.",
167
+ "Run `arc deploy` again to retry with the latest release version.",
168
+ ];
169
+ git(root, ["push", "origin", `${PREFIX}${version}`], (err) => {
170
+ if (err) {
171
+ cb(new Error(message.join("\n"), { cause: err }));
172
+ return;
173
+ }
174
+ cb();
175
+ });
176
+ };
177
+
178
+ // [function]
179
+
180
+ const release = function (root, version, pre, cb) {
181
+ createTag(root, version, pre, (err) => {
182
+ if (err) {
183
+ cb(err);
184
+ return;
185
+ }
186
+ pushTag(root, version, cb);
187
+ });
188
+ };
189
+
21
190
  // [export]
22
191
 
23
- module.exports = { isDirty };
192
+ module.exports = { ensureClean, ensureRemote, ensureRepo, listTags, release };
@@ -1,9 +1,84 @@
1
1
  "use strict";
2
2
 
3
+ // [import]
4
+
5
+ const semver = require("semver");
6
+
7
+ // [import]
8
+
9
+ const git = require("./git");
10
+
11
+ // [use]
12
+
13
+ const ensureClean = git.ensureClean;
14
+ const ensureRemote = git.ensureRemote;
15
+ const ensureRepo = git.ensureRepo;
16
+ const incSemver = semver.inc;
17
+ const listTags = git.listTags;
18
+ const release = git.release;
19
+
20
+ // [function]
21
+
22
+ const deployGit = function ({ pre, preId, root }, handler, cb) {
23
+ listTags(root, (err, from) => {
24
+ if (err) {
25
+ cb(err);
26
+ return;
27
+ }
28
+ const to = incSemver(from, pre ? "prerelease" : "patch", preId);
29
+ release(root, to, pre, (err) => {
30
+ if (err) {
31
+ cb(err);
32
+ return;
33
+ }
34
+ cb(null, { from, to });
35
+ });
36
+ });
37
+ };
38
+
39
+ // [function]
40
+
41
+ const deploy = function ({ pre, preId, root }, { onInfo }, cb) {
42
+ ensureRepo(root, (err) => {
43
+ if (err) {
44
+ cb(err);
45
+ return;
46
+ }
47
+ ensureClean(root, (err, diff) => {
48
+ if (err) {
49
+ cb(err);
50
+ return;
51
+ }
52
+ if (diff.cached) {
53
+ onInfo({
54
+ level: "warn",
55
+ message: "Staged but uncommitted changes will not be deployed.",
56
+ });
57
+ }
58
+ ensureRemote(root, (err) => {
59
+ if (err) {
60
+ cb(err);
61
+ return;
62
+ }
63
+ deployGit({ pre, preId, root }, { onInfo }, cb);
64
+ });
65
+ });
66
+ });
67
+ };
68
+
3
69
  // [function]
4
70
 
5
- const main = function () {
6
- return Promise.reject(new Error("Unimplemented command."));
71
+ const main = function ({ pre, preId, root }, { onBegin, ...handler }) {
72
+ onBegin({ root });
73
+ return new Promise((resolve, reject) => {
74
+ deploy({ pre, preId, root }, handler, (err, data) => {
75
+ if (err) {
76
+ reject(err);
77
+ return;
78
+ }
79
+ resolve(data);
80
+ });
81
+ });
7
82
  };
8
83
 
9
84
  // [export]
@@ -27,14 +27,14 @@ const init = function (src, dest, { onBegin, onInfo }) {
27
27
 
28
28
  // [function]
29
29
 
30
- const main = function ({ force, project, root, template }, handler) {
30
+ const main = function ({ force, project, root, starter }, handler) {
31
31
  const dest = resolve(root, project);
32
32
  return pathExists(dest)
33
33
  .then((exists) => {
34
34
  if (exists && !force) {
35
35
  throw new Error("Directory exists. Run with `--force` to overwrite.");
36
36
  }
37
- return init(template, dest, handler);
37
+ return init(starter, dest, handler);
38
38
  })
39
39
  .then(() => ({ path: dest }));
40
40
  };
package/src/cli/deploy.js CHANGED
@@ -7,9 +7,9 @@ const deployTool = require("../action/deploy/tool");
7
7
 
8
8
  // [function]
9
9
 
10
- const main = function ({ git, ...conf }) {
11
- const tool = git ? deployGitTool : deployTool;
12
- return tool(conf);
10
+ const main = function ({ direct, handler, ...conf }) {
11
+ const tool = direct ? deployTool : deployGitTool;
12
+ return tool(conf, handler);
13
13
  };
14
14
 
15
15
  // [export]
@@ -2,4 +2,9 @@
2
2
 
3
3
  // [export]
4
4
 
5
- module.exports = {};
5
+ module.exports = {
6
+ /* eslint-disable camelcase */
7
+ deploy_dir: ".arcadible-public",
8
+ skip_build: false,
9
+ /* eslint-enable camelcase */
10
+ };
@@ -12,6 +12,7 @@ const TOML = require("@iarna/toml");
12
12
  // [use]
13
13
 
14
14
  const join = path.join;
15
+ const pathExists = fs.pathExists;
15
16
  const readFile = fs.readFile;
16
17
 
17
18
  // [declare]
@@ -33,12 +34,10 @@ const parseToml = function (buf) {
33
34
  // [function]
34
35
 
35
36
  const parse = function (root) {
36
- return new Promise((resolve, reject) => {
37
- readFile(join(root, MANIFEST), "utf8")
38
- .then(parseToml)
39
- .then(resolve)
40
- .catch(reject);
41
- });
37
+ const file = join(root, MANIFEST);
38
+ return pathExists(file)
39
+ .then((exists) => (exists ? readFile(file, "utf8") : null))
40
+ .then((buf) => (buf === null ? {} : parseToml(buf)));
42
41
  };
43
42
 
44
43
  // [export]
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const path = require("node:path");
6
+
7
+ // [import]
8
+
9
+ const fs = require("fs-extra");
10
+
11
+ // [use]
12
+
13
+ const join = path.join;
14
+ const pathExists = fs.pathExists;
15
+ const readFile = fs.readFile;
16
+
17
+ // [declare]
18
+
19
+ const PACKAGE = "package.json";
20
+
21
+ // [function]
22
+
23
+ const parseJson = function (buf) {
24
+ try {
25
+ return JSON.parse(buf);
26
+ } catch (ex) {
27
+ throw new Error(`Unable to parse ${PACKAGE}: ${ex.message}`, {
28
+ cause: ex,
29
+ });
30
+ }
31
+ };
32
+
33
+ // [function]
34
+
35
+ const extract = function (pkg) {
36
+ const game = { version: pkg.version || null };
37
+ return Object.fromEntries(
38
+ Object.entries({ game }).filter(([, value]) =>
39
+ Object.values(value).some(Boolean),
40
+ ),
41
+ );
42
+ };
43
+
44
+ // [function]
45
+
46
+ const parse = function (root) {
47
+ const file = join(root, PACKAGE);
48
+ return pathExists(file)
49
+ .then((exists) => (exists ? readFile(file, "utf8") : null))
50
+ .then((buf) => (buf === null ? {} : parseJson(buf)))
51
+ .then((pkg) => (Object.keys(pkg).length ? extract(pkg) : {}));
52
+ };
53
+
54
+ // [export]
55
+
56
+ module.exports = { parse };
@@ -6,16 +6,18 @@ const cfggame = require("../config/game");
6
6
  const cfgworkflow = require("../config/workflow");
7
7
  const manifest = require("./manifest");
8
8
  const media = require("./media");
9
+ const pkg = require("./pkg");
9
10
  const promise = require("../util/promise");
10
11
  const readme = require("./readme");
11
12
 
12
13
  // [function]
13
14
 
14
- const configGame = function (readmeGame, mediaGame, manifestGame) {
15
+ const configGame = function (readmeGame, mediaGame, pkgGame, manifestGame) {
15
16
  return {
16
17
  ...cfggame,
17
18
  ...(readmeGame || {}),
18
19
  ...(mediaGame || {}),
20
+ ...(pkgGame || {}),
19
21
  ...(manifestGame || {}),
20
22
  };
21
23
  };
@@ -35,14 +37,16 @@ const parse = function (root) {
35
37
  const parsers = [
36
38
  () => manifest.parse(root),
37
39
  () => media.parse(root),
40
+ () => pkg.parse(root),
38
41
  () => readme.parse(root),
39
42
  ];
40
43
  return promise
41
44
  .serial(parsers)
42
- .then(([manifestData, mediaData, readmeData]) => {
45
+ .then(([manifestData, mediaData, pkgData, readmeData]) => {
43
46
  const game = configGame(
44
47
  readmeData.game,
45
48
  mediaData.game,
49
+ pkgData.game,
46
50
  manifestData.game,
47
51
  );
48
52
  const workflow = configWorkflow(manifestData.workflow);
@@ -18,13 +18,14 @@ const strs = require("../util/strs");
18
18
  // [use]
19
19
 
20
20
  const join = path.join;
21
+ const pathExists = fs.pathExists;
21
22
  const pruneEmpty = objs.pruneEmpty;
22
23
  const readFile = fs.readFile;
23
24
  const trimWhitespace = strs.trimWhitespace;
24
25
 
25
26
  // [declare]
26
27
 
27
- const README = "README.md";
28
+ const README = ["arcadible.md", "README.md"];
28
29
 
29
30
  // [function]
30
31
 
@@ -118,25 +119,34 @@ const extract = function (html) {
118
119
 
119
120
  // [function]
120
121
 
121
- const parseReadme = function (buf) {
122
+ const parseReadme = function (buf, file) {
122
123
  try {
123
124
  return extract(MD.parse(buf));
124
125
  } catch (ex) {
125
- throw new Error(`Unable to parse ${README}: ${ex.message}`, { cause: ex });
126
+ throw new Error(`Unable to parse ${file}: ${ex.message}`, {
127
+ cause: ex,
128
+ });
126
129
  }
127
130
  };
128
131
 
129
132
  // [function]
130
133
 
134
+ const findReadme = function (root) {
135
+ return Promise.all(
136
+ README.map((file) =>
137
+ pathExists(join(root, file)).then((exists) => (exists ? file : null)),
138
+ ),
139
+ ).then((files) => files.find(Boolean) || null);
140
+ };
141
+
142
+ // [function]
143
+
131
144
  const parse = function (root) {
132
- return new Promise((resolve, reject) => {
133
- readFile(join(root, README), "utf8")
134
- .then(parseReadme)
135
- .then(pruneEmpty)
136
- .then((game) => ({ game }))
137
- .then(resolve)
138
- .catch(reject);
139
- });
145
+ return findReadme(root)
146
+ .then((file) => (file ? readFile(join(root, file), "utf8") : null))
147
+ .then((buf) => (buf === null ? null : parseReadme(buf)))
148
+ .then(pruneEmpty)
149
+ .then((game) => ({ game: game || null }));
140
150
  };
141
151
 
142
152
  // [export]
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ // [declare]
4
+
5
+ const REPO = "arcadible";
6
+
3
7
  // [export]
4
8
 
5
9
  module.exports = {
@@ -8,30 +12,30 @@ module.exports = {
8
12
  {
9
13
  description: "Blank starter template.",
10
14
  name: "Blank",
11
- value: "arcadible/starter",
15
+ value: `${REPO}/starter`,
12
16
  },
13
17
  {
14
18
  description: "Three.js starter template.",
15
19
  name: "Three.js",
16
- value: "arcadible/starter-threejs",
20
+ value: `${REPO}/starter-threejs`,
17
21
  },
18
22
  {
19
23
  description: "Phaser starter template.",
20
24
  name: "Phaser",
21
- value: "arcadible/starter-phaser",
25
+ value: `${REPO}/starter-phaser`,
22
26
  },
23
27
  {
24
28
  description: "PixiJS starter template.",
25
29
  name: "PixiJS",
26
- value: "arcadible/starter-pixijs",
30
+ value: `${REPO}/starter-pixijs`,
27
31
  },
28
32
  {
29
33
  description: "Babylon.js starter template.",
30
34
  name: "Babylon.js",
31
- value: "arcadible/starter-babylonjs",
35
+ value: `${REPO}/starter-babylonjs`,
32
36
  },
33
37
  ],
34
- default: "arcadible/starter",
35
- message: "Template",
38
+ default: `${REPO}/starter`,
39
+ message: "Starter",
36
40
  },
37
41
  };
@@ -3,6 +3,7 @@
3
3
  // [import]
4
4
 
5
5
  const chalk = require("chalk");
6
+ const semver = require("semver");
6
7
  const z = require("zod");
7
8
 
8
9
  // [import]
@@ -16,6 +17,10 @@ const cfgurl = require("../config/url");
16
17
  const cfgvisibility = require("../config/visibility");
17
18
  const dom = require("../util/dom");
18
19
 
20
+ // [use]
21
+
22
+ const validSemver = semver.valid;
23
+
19
24
  // [function]
20
25
 
21
26
  const reference = function (field) {
@@ -267,6 +272,18 @@ const zTrailer = function () {
267
272
 
268
273
  // [function]
269
274
 
275
+ const zVersion = function () {
276
+ const field = "game.version";
277
+ return z
278
+ .string()
279
+ .refine(
280
+ (value) => validSemver(value) !== null,
281
+ message(field, "Must be a valid semver."),
282
+ );
283
+ };
284
+
285
+ // [function]
286
+
270
287
  const zVisibility = function () {
271
288
  // const field = "game.visibility";
272
289
  return z.optional(z.enum(cfgvisibility));
@@ -312,6 +329,7 @@ const main = function (value, { root }) {
312
329
  tagline: zTagline(),
313
330
  title: zTitle(),
314
331
  trailer: zTrailer(),
332
+ version: zVersion(),
315
333
  visibility: zVisibility(),
316
334
  wordmark: zWordmark(root),
317
335
  wordmark_animated: zWordmarkAnimated(root),
package/src/util/log.js CHANGED
@@ -72,6 +72,30 @@ const pdnl = function (message) {
72
72
 
73
73
  // [function]
74
74
 
75
+ const hw = function (message) {
76
+ log(console.log, message, { bold: true, color: "yellow" });
77
+ };
78
+
79
+ // [function]
80
+
81
+ const hwnl = function (message) {
82
+ log(console.log, message, { bold: true, color: "yellow", nl: true });
83
+ };
84
+
85
+ // [function]
86
+
87
+ const pw = function (message) {
88
+ log(console.log, message, { color: "yellow" });
89
+ };
90
+
91
+ // [function]
92
+
93
+ const pwnl = function (message) {
94
+ log(console.log, message, { color: "yellow", nl: true });
95
+ };
96
+
97
+ // [function]
98
+
75
99
  const hs = function (message) {
76
100
  log(console.log, message, { bold: true, color: "green" });
77
101
  };
@@ -96,4 +120,21 @@ const psnl = function (message) {
96
120
 
97
121
  // [export]
98
122
 
99
- module.exports = { h, hd, hdnl, hnl, hs, hsnl, p, pd, pdnl, pnl, ps, psnl };
123
+ module.exports = {
124
+ h,
125
+ hd,
126
+ hdnl,
127
+ hnl,
128
+ hs,
129
+ hsnl,
130
+ hw,
131
+ hwnl,
132
+ p,
133
+ pd,
134
+ pdnl,
135
+ pnl,
136
+ ps,
137
+ psnl,
138
+ pw,
139
+ pwnl,
140
+ };
package/src/util/objs.js CHANGED
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ // [import]
4
+
5
+ const stringify = require("fast-json-stable-stringify");
6
+
3
7
  // [function]
4
8
 
5
9
  const pruneEmpty = function (value) {
@@ -23,6 +27,12 @@ const pruneEmpty = function (value) {
23
27
  /* eslint-enable no-undefined */
24
28
  };
25
29
 
30
+ // [function]
31
+
32
+ const sort = function (value) {
33
+ return JSON.parse(stringify(value));
34
+ };
35
+
26
36
  // [export]
27
37
 
28
- module.exports = { pruneEmpty };
38
+ module.exports = { pruneEmpty, sort };
@@ -4,6 +4,14 @@
4
4
 
5
5
  const TOML = require("@iarna/toml");
6
6
 
7
+ // [import]
8
+
9
+ const objs = require("./objs");
10
+
11
+ // [use]
12
+
13
+ const sort = objs.sort;
14
+
7
15
  // [function]
8
16
 
9
17
  const write = function (data) {
@@ -13,7 +21,7 @@ const write = function (data) {
13
21
  // [function]
14
22
 
15
23
  const printJson = function (data) {
16
- write(JSON.stringify(data, null, 2));
24
+ write(JSON.stringify(sort(data), null, 2));
17
25
  };
18
26
 
19
27
  // [function]
@@ -25,7 +33,7 @@ const printToml = function (data, key = "value") {
25
33
  return;
26
34
  }
27
35
  try {
28
- write(TOML.stringify(data));
36
+ write(TOML.stringify(sort(data)));
29
37
  } catch (ex) {
30
38
  write(TOML.stringify({ [field]: data }));
31
39
  }
@@ -24,8 +24,8 @@ const parse = function (resp) {
24
24
 
25
25
  const send = function (method, url, body, { token } = {}) {
26
26
  const headers = {
27
- "X-Arc-Id": CLIENT_ID,
28
- "X-Arc-Version": CLIENT_VERSION,
27
+ "X-Arc-Client-Id": CLIENT_ID,
28
+ "X-Arc-Client-Version": CLIENT_VERSION,
29
29
  };
30
30
  if (token) {
31
31
  headers.authorization = `Bearer ${token}`;
@@ -1,74 +0,0 @@
1
- "use strict";
2
-
3
- // [import]
4
-
5
- const execFile = require("node:child_process").execFile;
6
-
7
- // [import]
8
-
9
- const strs = require("../../util/strs");
10
-
11
- // [use]
12
-
13
- const trimWhitespace = strs.trimWhitespace;
14
-
15
- // [declare]
16
-
17
- const RE_TAG_EXISTS = /tag\s+'([^']+)'\s+already\s+exists/iu;
18
-
19
- // [function]
20
-
21
- const knownErr = function (stdErr) {
22
- const tagExists = stdErr.match(RE_TAG_EXISTS);
23
- if (tagExists) {
24
- return [
25
- `Git tag exists: ${tagExists[1]}`,
26
- "The package version has been synchronized.",
27
- "Try again.",
28
- ].join("\n");
29
- }
30
- return stdErr;
31
- };
32
-
33
- // [function]
34
-
35
- const npm = function (root, pre, preId) {
36
- return [
37
- "--prefix",
38
- root,
39
- "version",
40
- pre ? "prerelease" : "patch",
41
- "--preid",
42
- preId,
43
- "-m",
44
- pre ? "Prerelease v%s" : "Release v%s",
45
- ];
46
- };
47
-
48
- // [function]
49
-
50
- const git = function (root) {
51
- return ["-C", root, "push", "--follow-tags"];
52
- };
53
-
54
- // [function]
55
-
56
- const main = function (root, { pre, preId }, cb) {
57
- execFile("npm", npm(root, pre, preId), (err, stdOut, stdErr) => {
58
- if (err) {
59
- cb(new Error(knownErr(stdErr), { cause: err }));
60
- return;
61
- }
62
- execFile("git", git(root), (err) => {
63
- if (err) {
64
- cb(new Error(knownErr(stdErr), { cause: err }));
65
- return;
66
- }
67
- cb(null, trimWhitespace(stdOut));
68
- });
69
- });
70
- };
71
-
72
- // [export]
73
-
74
- module.exports = main;