@jspicl/cli 4.0.0-alpha.0
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/LICENSE.md +9 -0
- package/README.md +94 -0
- package/dist/cli.js +530 -0
- package/dist/cli.js.map +7 -0
- package/dist/types.d.ts +25 -0
- package/package.json +73 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Agron Kabashi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @jspicl/cli
|
|
2
|
+
|
|
3
|
+
A command-line tool that simplifies PICO-8 game development in JavaScript.
|
|
4
|
+
|
|
5
|
+
**Features:**
|
|
6
|
+
|
|
7
|
+
- Built-in build pipeline powered by esbuild
|
|
8
|
+
- JavaScript to PICO-8 Lua transpilation via [@jspicl/core](../core)
|
|
9
|
+
- Tree-shaking to minimize token count
|
|
10
|
+
- PNG spritesheet support - use your favorite image editor
|
|
11
|
+
- Live reloading with watch mode
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -D @jspicl/cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
jspicl <input> <output> --config <config-file> [--watch]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Example:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
jspicl src/game.js build/game.p8 --config jspicl.config.ts --watch
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Config File
|
|
32
|
+
|
|
33
|
+
Create a config file (JavaScript or TypeScript):
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// jspicl.config.ts
|
|
37
|
+
import type {Config} from "@jspicl/cli/types";
|
|
38
|
+
|
|
39
|
+
const config: Config = {
|
|
40
|
+
spritesheetImagePath: "assets/sprites.png",
|
|
41
|
+
jsOutput: "build/game.js",
|
|
42
|
+
picoPath: "/Applications/PICO-8.app/Contents/MacOS/pico8",
|
|
43
|
+
reloadOnSave: true,
|
|
44
|
+
showStats: true
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default config;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Config Options
|
|
51
|
+
|
|
52
|
+
| Name | Type | Required | Description |
|
|
53
|
+
| ---------------------- | -------- | -------- | -------------------------------------------------- |
|
|
54
|
+
| `spritesheetImagePath` | string | Yes | Path to PNG spritesheet |
|
|
55
|
+
| `jsOutput` | string | Yes | Path to output bundled JavaScript (for debugging) |
|
|
56
|
+
| `picoPath` | string | No | Custom path to PICO-8 executable |
|
|
57
|
+
| `includeBanner` | boolean | No | Include jspicl info comment in output |
|
|
58
|
+
| `luaOutput` | string | No | Path to output transpiled Lua (for debugging) |
|
|
59
|
+
| `pipeOutputToConsole` | boolean | No | Pipe console.log to terminal |
|
|
60
|
+
| `reloadOnSave` | boolean | No | Reload PICO-8 when cartridge is updated |
|
|
61
|
+
| `showStats` | boolean | No | Display build statistics |
|
|
62
|
+
| `jspicl` | object | No | Options passed to @jspicl/core (prettify, etc.) |
|
|
63
|
+
|
|
64
|
+
## CLI Options
|
|
65
|
+
|
|
66
|
+
| Name | Description |
|
|
67
|
+
| ----------------- | ---------------------------------------- |
|
|
68
|
+
| `--config`, `-c` | Path to config file (required) |
|
|
69
|
+
| `--watch`, `-w` | Watch for changes and rebuild |
|
|
70
|
+
|
|
71
|
+
## Watch Mode
|
|
72
|
+
|
|
73
|
+
With `--watch`, the CLI rebuilds automatically when source files change:
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
This applies for the spritesheet as well. Simply save your image and your changes will be reloaded in PICO-8.
|
|
78
|
+
|
|
79
|
+

|
|
80
|
+
|
|
81
|
+
**Note:** Automatic PICO-8 reload is currently only supported on macOS.
|
|
82
|
+
|
|
83
|
+
## Requirements
|
|
84
|
+
|
|
85
|
+
- Node.js 22+
|
|
86
|
+
|
|
87
|
+
## Related
|
|
88
|
+
|
|
89
|
+
- [@jspicl/core](../core) - The transpiler library
|
|
90
|
+
- [Games made with jspicl](https://github.com/topics/jspicl-sample)
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import { hideBin } from "yargs/helpers";
|
|
6
|
+
import path5 from "node:path";
|
|
7
|
+
import process2 from "process";
|
|
8
|
+
import esbuild from "esbuild";
|
|
9
|
+
|
|
10
|
+
// src/arguments.ts
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
var cliArguments = {
|
|
13
|
+
watch: {
|
|
14
|
+
description: "Reload cartridge on rebuilds",
|
|
15
|
+
type: "boolean",
|
|
16
|
+
default: false,
|
|
17
|
+
alias: "w"
|
|
18
|
+
},
|
|
19
|
+
config: {
|
|
20
|
+
description: "Path to a config file",
|
|
21
|
+
type: "string",
|
|
22
|
+
alias: "c",
|
|
23
|
+
requiresArg: true,
|
|
24
|
+
default: {
|
|
25
|
+
jsOutput: "build/jsOutput.js"
|
|
26
|
+
},
|
|
27
|
+
coerce: async (p) => {
|
|
28
|
+
const configModule = await import(path.resolve(p));
|
|
29
|
+
return configModule.default;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/logging.ts
|
|
35
|
+
import fs from "node:fs";
|
|
36
|
+
import path2 from "node:path";
|
|
37
|
+
import { mkdirp } from "mkdirp";
|
|
38
|
+
|
|
39
|
+
// src/tokenCounter.ts
|
|
40
|
+
var tokens = [
|
|
41
|
+
/\"[^\"]*\"/,
|
|
42
|
+
// Strings
|
|
43
|
+
/\d+\.\d+/,
|
|
44
|
+
// floating numbers
|
|
45
|
+
/\w+/,
|
|
46
|
+
// words
|
|
47
|
+
/\d+/,
|
|
48
|
+
// numbers
|
|
49
|
+
/!=/,
|
|
50
|
+
// inequality
|
|
51
|
+
/==/,
|
|
52
|
+
// comparison
|
|
53
|
+
/\+=/,
|
|
54
|
+
// incrementing assignment
|
|
55
|
+
/-=/,
|
|
56
|
+
// decrementing assignment
|
|
57
|
+
/<=/,
|
|
58
|
+
// equal or less than
|
|
59
|
+
/>=/,
|
|
60
|
+
// equal or greater than
|
|
61
|
+
/\.\./,
|
|
62
|
+
// string concatenation
|
|
63
|
+
/</,
|
|
64
|
+
// less than
|
|
65
|
+
/>/,
|
|
66
|
+
// greater than
|
|
67
|
+
/\+/,
|
|
68
|
+
// addition
|
|
69
|
+
/-/,
|
|
70
|
+
// subtraction
|
|
71
|
+
/\//,
|
|
72
|
+
// division
|
|
73
|
+
/\*/,
|
|
74
|
+
// multiplication
|
|
75
|
+
/=/,
|
|
76
|
+
// equals
|
|
77
|
+
/\%/,
|
|
78
|
+
// percentage
|
|
79
|
+
/\(/,
|
|
80
|
+
// paranthesis
|
|
81
|
+
/\[/,
|
|
82
|
+
// left bracket
|
|
83
|
+
/\{/
|
|
84
|
+
// left curly brace
|
|
85
|
+
].map((r) => r.source).join("|");
|
|
86
|
+
function getTokenCount(luaCode) {
|
|
87
|
+
const regex = new RegExp(`(${tokens})`, "gi");
|
|
88
|
+
return (luaCode.match(regex) || []).filter(
|
|
89
|
+
(token) => token !== "local" && token !== "end"
|
|
90
|
+
).length;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/logging.ts
|
|
94
|
+
function logToFile(content, filePath) {
|
|
95
|
+
mkdirp.sync(path2.dirname(filePath));
|
|
96
|
+
fs.writeFileSync(path2.resolve(filePath), content);
|
|
97
|
+
}
|
|
98
|
+
function logInfo(content) {
|
|
99
|
+
logToConsole(content, "\x1B[34m\u2139" /* info */);
|
|
100
|
+
}
|
|
101
|
+
function logSuccess(content) {
|
|
102
|
+
logToConsole(content, "\x1B[32m\u2714" /* success */);
|
|
103
|
+
}
|
|
104
|
+
function logWarning(content) {
|
|
105
|
+
logToConsole(content, "\x1B[33m\u26A0" /* warning */);
|
|
106
|
+
}
|
|
107
|
+
function logError(content) {
|
|
108
|
+
logToConsole(content, "\x1B[31m\u2716" /* error */);
|
|
109
|
+
}
|
|
110
|
+
function logToConsole(content, icon) {
|
|
111
|
+
console.log(`${icon} ${content}\x1B[0m`);
|
|
112
|
+
}
|
|
113
|
+
function logStats(lua, polyfillOutput, code) {
|
|
114
|
+
const tokens2 = getTokenCount(lua);
|
|
115
|
+
const polyfillTokens = getTokenCount(polyfillOutput);
|
|
116
|
+
logInfo("Cartridge Statistics");
|
|
117
|
+
console.log("".padEnd(41, "\u2014"));
|
|
118
|
+
const stats = [
|
|
119
|
+
{
|
|
120
|
+
label: "Characters",
|
|
121
|
+
value: lua.length,
|
|
122
|
+
percent: `${~~(lua.length * 100 / 65535)}%`
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
label: "Tokens",
|
|
126
|
+
value: `~${tokens2}`,
|
|
127
|
+
percent: `${~~(tokens2 * 100 / 8192)}%`
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
label: " - Polyfills",
|
|
131
|
+
value: `~${polyfillTokens}`
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
label: "Filesize",
|
|
135
|
+
value: `${Math.ceil(code.length / 1024)} KB`
|
|
136
|
+
}
|
|
137
|
+
];
|
|
138
|
+
stats.forEach((stats2) => {
|
|
139
|
+
const label = `${stats2.label}:`.padEnd(20, " ");
|
|
140
|
+
const value = `${stats2.value}`.padStart(15, " ");
|
|
141
|
+
const percent = stats2.percent ? `\x1B[33m${stats2.percent}`.padStart(10, " ") : "";
|
|
142
|
+
console.log(`${label}${value}${percent}\x1B[0m`);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/createPico8Launcher.ts
|
|
147
|
+
import path3 from "path";
|
|
148
|
+
import { spawn, exec } from "child_process";
|
|
149
|
+
import { fileURLToPath } from "url";
|
|
150
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
151
|
+
var osMatrix = {
|
|
152
|
+
win32: {
|
|
153
|
+
execPath: `"C:\\Program Files (x86)\\PICO-8\\pico8.exe"`
|
|
154
|
+
},
|
|
155
|
+
darwin: {
|
|
156
|
+
execPath: "/Applications/PICO-8.app/Contents/MacOS/pico8",
|
|
157
|
+
reloadCommand: path3.resolve(__dirname, "../scripts/reload-pico8-bin")
|
|
158
|
+
},
|
|
159
|
+
linux: {
|
|
160
|
+
execPath: "~/pico-8/pico8"
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
function createPico8Launcher(watch, customPicoPath, reloadOnSave, pipeOutputToConsole) {
|
|
164
|
+
let picoProcess;
|
|
165
|
+
const { execPath, reloadCommand } = osMatrix[process.platform];
|
|
166
|
+
return (cartridgePath) => {
|
|
167
|
+
if (!watch || !cartridgePath) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (picoProcess) {
|
|
171
|
+
if (!reloadOnSave) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (reloadCommand) {
|
|
175
|
+
logSuccess("Reloading cartridge in PICO-8");
|
|
176
|
+
exec(reloadCommand);
|
|
177
|
+
} else {
|
|
178
|
+
logWarning(
|
|
179
|
+
"Autoreloading is currently not supported on your OS. Please press Ctrl+R in PICO-8 to see new changes."
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
logSuccess("Running cartridge in PICO-8");
|
|
184
|
+
picoProcess = launchPico8(
|
|
185
|
+
customPicoPath || execPath,
|
|
186
|
+
cartridgePath,
|
|
187
|
+
pipeOutputToConsole
|
|
188
|
+
);
|
|
189
|
+
picoProcess.on("close", (errorCode) => {
|
|
190
|
+
if (errorCode !== 0) {
|
|
191
|
+
logWarning(`PICO-8 process exited with code ${errorCode}`);
|
|
192
|
+
}
|
|
193
|
+
picoProcess = null;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function launchPico8(picoPath, cartridgePath, pipeOutputToConsole) {
|
|
199
|
+
return spawn(picoPath, ["-run", `"${path3.resolve(cartridgePath)}"`], {
|
|
200
|
+
shell: true,
|
|
201
|
+
stdio: pipeOutputToConsole ? "inherit" : "pipe"
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/watchPlugin.ts
|
|
206
|
+
import fs4 from "node:fs";
|
|
207
|
+
|
|
208
|
+
// src/cartridge.ts
|
|
209
|
+
import fs2 from "fs";
|
|
210
|
+
import path4 from "path";
|
|
211
|
+
function generateCartridgeContent({
|
|
212
|
+
lua = "",
|
|
213
|
+
gff = "",
|
|
214
|
+
gfx = "",
|
|
215
|
+
music = "",
|
|
216
|
+
map = "",
|
|
217
|
+
sfx = ""
|
|
218
|
+
} = {}) {
|
|
219
|
+
return [
|
|
220
|
+
"pico-8 cartridge // http://www.pico-8.com",
|
|
221
|
+
"version 42",
|
|
222
|
+
"__lua__",
|
|
223
|
+
lua,
|
|
224
|
+
gfx && `__gfx__
|
|
225
|
+
${gfx}`,
|
|
226
|
+
gff && `__gff__
|
|
227
|
+
${gff}`,
|
|
228
|
+
map && `__map__
|
|
229
|
+
${map}`,
|
|
230
|
+
sfx && `__sfx__
|
|
231
|
+
${sfx}`,
|
|
232
|
+
music && `__music__
|
|
233
|
+
${music}`,
|
|
234
|
+
"\n"
|
|
235
|
+
].filter(Boolean).join("\n");
|
|
236
|
+
}
|
|
237
|
+
function getPicoSectionsFromCartridge(cartridgePath) {
|
|
238
|
+
try {
|
|
239
|
+
const resolvedCartridgePath = path4.resolve(cartridgePath);
|
|
240
|
+
const content = fs2.existsSync(resolvedCartridgePath) ? fs2.readFileSync(resolvedCartridgePath, "utf8") : "";
|
|
241
|
+
return parsePico8Cartridge(content);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
`Failed to read cartridge at ${cartridgePath}: ${error.message}`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function parsePico8Cartridge(content) {
|
|
249
|
+
const cartridgeSections = {
|
|
250
|
+
lua: "",
|
|
251
|
+
gff: "",
|
|
252
|
+
gfx: "",
|
|
253
|
+
music: "",
|
|
254
|
+
map: "",
|
|
255
|
+
sfx: ""
|
|
256
|
+
};
|
|
257
|
+
const regex = /__(\w+)__\n([\s\S]*?)(?=\n__\w+__\n|\n(\n|$))/g;
|
|
258
|
+
let result;
|
|
259
|
+
while ((result = regex.exec(content)) !== null) {
|
|
260
|
+
const [, section, content2] = result;
|
|
261
|
+
cartridgeSections[section] = content2;
|
|
262
|
+
}
|
|
263
|
+
return cartridgeSections;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/spritesheet.ts
|
|
267
|
+
import fs3 from "fs";
|
|
268
|
+
import pngjs from "pngjs";
|
|
269
|
+
|
|
270
|
+
// src/constants.ts
|
|
271
|
+
var JSPICL_BANNER = `--[[
|
|
272
|
+
generated with jspicl,
|
|
273
|
+
a javascript to pico-8 lua
|
|
274
|
+
transpiler.
|
|
275
|
+
|
|
276
|
+
please report any bugs at:
|
|
277
|
+
https://github.com/jspicl/jspicl/issues
|
|
278
|
+
]]--
|
|
279
|
+
`;
|
|
280
|
+
var PICO8_PALETTE = [
|
|
281
|
+
{
|
|
282
|
+
r: 0,
|
|
283
|
+
g: 0,
|
|
284
|
+
b: 0
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
r: 29,
|
|
288
|
+
g: 43,
|
|
289
|
+
b: 83
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
r: 126,
|
|
293
|
+
g: 37,
|
|
294
|
+
b: 83
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
r: 0,
|
|
298
|
+
g: 135,
|
|
299
|
+
b: 81
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
r: 171,
|
|
303
|
+
g: 82,
|
|
304
|
+
b: 54
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
r: 95,
|
|
308
|
+
g: 87,
|
|
309
|
+
b: 79
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
r: 194,
|
|
313
|
+
g: 195,
|
|
314
|
+
b: 199
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
r: 255,
|
|
318
|
+
g: 241,
|
|
319
|
+
b: 232
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
r: 255,
|
|
323
|
+
g: 0,
|
|
324
|
+
b: 77
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
r: 255,
|
|
328
|
+
g: 163,
|
|
329
|
+
b: 0
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
r: 255,
|
|
333
|
+
g: 236,
|
|
334
|
+
b: 39
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
r: 0,
|
|
338
|
+
g: 228,
|
|
339
|
+
b: 54
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
r: 41,
|
|
343
|
+
g: 173,
|
|
344
|
+
b: 255
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
r: 131,
|
|
348
|
+
g: 118,
|
|
349
|
+
b: 156
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
r: 255,
|
|
353
|
+
g: 119,
|
|
354
|
+
b: 168
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
r: 255,
|
|
358
|
+
g: 204,
|
|
359
|
+
b: 170
|
|
360
|
+
}
|
|
361
|
+
];
|
|
362
|
+
|
|
363
|
+
// src/spritesheet.ts
|
|
364
|
+
var spritesheetWidth = 128;
|
|
365
|
+
var spritesheetHeight = 128;
|
|
366
|
+
var hexBase = 16;
|
|
367
|
+
var pixelDataSize = 4;
|
|
368
|
+
var toClosestColor = (pixels) => (_, offset) => {
|
|
369
|
+
const pixelOffset = offset * pixelDataSize;
|
|
370
|
+
const pixel = {
|
|
371
|
+
r: pixels[pixelOffset],
|
|
372
|
+
g: pixels[pixelOffset + 1],
|
|
373
|
+
b: pixels[pixelOffset + 2]
|
|
374
|
+
};
|
|
375
|
+
let minDistance = Number.MAX_VALUE;
|
|
376
|
+
let closestPaletteColor = 0;
|
|
377
|
+
PICO8_PALETTE.forEach(
|
|
378
|
+
(color, i) => {
|
|
379
|
+
const diff = (color.r - pixel.r) ** 2 + (color.g - pixel.g) ** 2 + (color.b - pixel.b) ** 2;
|
|
380
|
+
if (diff < minDistance) {
|
|
381
|
+
minDistance = diff;
|
|
382
|
+
closestPaletteColor = i;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
return closestPaletteColor.toString(hexBase);
|
|
387
|
+
};
|
|
388
|
+
function getSpritesheetFromImage(imagePath) {
|
|
389
|
+
if (!imagePath) {
|
|
390
|
+
throw new Error("Image path is missing");
|
|
391
|
+
}
|
|
392
|
+
const stream = fs3.createReadStream(imagePath).pipe(new pngjs.PNG());
|
|
393
|
+
return new Promise(
|
|
394
|
+
(resolve) => stream.on("parsed", () => {
|
|
395
|
+
if (stream.width !== spritesheetWidth || stream.height !== spritesheetHeight) {
|
|
396
|
+
throw new Error("The spritesheet must be a 128x128 png image");
|
|
397
|
+
}
|
|
398
|
+
const pixels = new Array(stream.width * stream.height).fill(0).map(toClosestColor(stream.data));
|
|
399
|
+
const pixelsAsString = new Array(stream.height).fill(0).map(
|
|
400
|
+
(_, offset) => (
|
|
401
|
+
// cut the strings so we get stacks of 128 characters
|
|
402
|
+
pixels.slice(
|
|
403
|
+
offset * spritesheetWidth,
|
|
404
|
+
offset * spritesheetWidth + spritesheetWidth
|
|
405
|
+
).join("")
|
|
406
|
+
)
|
|
407
|
+
).join("\n");
|
|
408
|
+
resolve(pixelsAsString);
|
|
409
|
+
})
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/transpile.ts
|
|
414
|
+
import { jspicl } from "@jspicl/core";
|
|
415
|
+
function transpile(javascriptCode, config) {
|
|
416
|
+
const { includeBanner, polyfillTransform, jspicl: jspiclOptions = {} } = config;
|
|
417
|
+
const jspiclBanner = includeBanner && `${JSPICL_BANNER}` || "";
|
|
418
|
+
const { code, polyfills } = jspicl(javascriptCode, jspiclOptions);
|
|
419
|
+
const polyfillOutput = polyfillTransform ? polyfillTransform(polyfills) : Object.values(polyfills).join("\n");
|
|
420
|
+
const lua = `${jspiclBanner}${polyfillOutput}${code}`;
|
|
421
|
+
return {
|
|
422
|
+
lua,
|
|
423
|
+
polyfillOutput
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/watchPlugin.ts
|
|
428
|
+
var watchPlugin = (options) => ({
|
|
429
|
+
name: "watcher",
|
|
430
|
+
setup(build) {
|
|
431
|
+
build.onEnd(async (result) => {
|
|
432
|
+
const { onBuildEnd, onBuildError, config, output } = options;
|
|
433
|
+
const { jsOutput, spritesheetImagePath } = config;
|
|
434
|
+
if (result.errors.length) {
|
|
435
|
+
const errors = result.errors.map((error) => error.text).join("\n");
|
|
436
|
+
onBuildError?.(errors);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
console.clear();
|
|
440
|
+
const jsContent = fs4.readFileSync(jsOutput, "utf-8");
|
|
441
|
+
const transpiledSource = transpile(jsContent, config);
|
|
442
|
+
const cartridgeSections = getPicoSectionsFromCartridge(output);
|
|
443
|
+
const gfxSection = await getSpritesheetFromImage(spritesheetImagePath);
|
|
444
|
+
const cartridgeContent = generateCartridgeContent({
|
|
445
|
+
...cartridgeSections,
|
|
446
|
+
lua: transpiledSource.lua,
|
|
447
|
+
gfx: gfxSection
|
|
448
|
+
});
|
|
449
|
+
onBuildEnd?.(cartridgeContent, transpiledSource);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// src/index.ts
|
|
455
|
+
async function getCommandlineArguments() {
|
|
456
|
+
const argv = await yargs(hideBin(process2.argv)).options(cliArguments).usage("jspicl-cli input output [<args>]").demandCommand(2, "Please specify an input and output file").help(false).strict().wrap(null).parseAsync();
|
|
457
|
+
const {
|
|
458
|
+
_: [input, output],
|
|
459
|
+
...restArguments
|
|
460
|
+
} = argv;
|
|
461
|
+
return {
|
|
462
|
+
input: path5.resolve(input.toString()),
|
|
463
|
+
output: path5.resolve(output.toString()),
|
|
464
|
+
options: restArguments
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
async function startBuildService(input, output, cliOptions) {
|
|
468
|
+
const { watch, config } = cliOptions;
|
|
469
|
+
const runPico = createPico8Launcher(
|
|
470
|
+
watch,
|
|
471
|
+
config.picoPath,
|
|
472
|
+
config.reloadOnSave,
|
|
473
|
+
config.pipeOutputToConsole
|
|
474
|
+
);
|
|
475
|
+
const jsOutput = path5.resolve(config.jsOutput || "build/jsOutput.js");
|
|
476
|
+
const buildConfig = {
|
|
477
|
+
entryPoints: [input],
|
|
478
|
+
bundle: true,
|
|
479
|
+
platform: "neutral",
|
|
480
|
+
treeShaking: false,
|
|
481
|
+
minify: false,
|
|
482
|
+
format: "esm",
|
|
483
|
+
outfile: jsOutput,
|
|
484
|
+
plugins: [
|
|
485
|
+
watchPlugin({
|
|
486
|
+
config,
|
|
487
|
+
output,
|
|
488
|
+
onBuildError: (errors) => {
|
|
489
|
+
logError(`Build failed with errors:
|
|
490
|
+
${errors}`);
|
|
491
|
+
},
|
|
492
|
+
onBuildEnd: (cartridgeContent, transpiledSource) => {
|
|
493
|
+
config.luaOutput && logToFile(transpiledSource.lua, config.luaOutput);
|
|
494
|
+
logToFile(cartridgeContent, output);
|
|
495
|
+
logSuccess("Build completed");
|
|
496
|
+
runPico(output);
|
|
497
|
+
config.showStats && logStats(
|
|
498
|
+
transpiledSource.lua,
|
|
499
|
+
transpiledSource.polyfillOutput,
|
|
500
|
+
cartridgeContent
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
]
|
|
505
|
+
};
|
|
506
|
+
if (watch) {
|
|
507
|
+
const context = await esbuild.context(buildConfig);
|
|
508
|
+
await context.watch();
|
|
509
|
+
} else {
|
|
510
|
+
await esbuild.build(buildConfig);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
async function runCLI() {
|
|
514
|
+
const { input, output, options } = await getCommandlineArguments();
|
|
515
|
+
process2.on("SIGINT", () => {
|
|
516
|
+
logInfo("Shutting down...");
|
|
517
|
+
process2.exit(0);
|
|
518
|
+
});
|
|
519
|
+
try {
|
|
520
|
+
await startBuildService(input, output, options);
|
|
521
|
+
} catch (error) {
|
|
522
|
+
logError(String(error));
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
runCLI();
|
|
527
|
+
export {
|
|
528
|
+
startBuildService
|
|
529
|
+
};
|
|
530
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../src/arguments.ts", "../src/logging.ts", "../src/tokenCounter.ts", "../src/createPico8Launcher.ts", "../src/watchPlugin.ts", "../src/cartridge.ts", "../src/spritesheet.ts", "../src/constants.ts", "../src/transpile.ts"],
|
|
4
|
+
"sourcesContent": ["import yargs from \"yargs\";\nimport {hideBin} from \"yargs/helpers\";\n\nimport path from \"node:path\";\n\nimport process from \"process\";\n\nimport esbuild, {type BuildOptions} from \"esbuild\";\nimport {cliArguments} from \"./arguments.js\";\nimport {logError, logInfo, logStats, logSuccess, logToFile} from \"./logging.js\";\nimport type {CommandLineOptions} from \"./types.js\";\nimport {createPico8Launcher} from \"./createPico8Launcher.js\";\nimport {watchPlugin} from \"./watchPlugin.js\";\n\nasync function getCommandlineArguments(): Promise<{\n input: string;\n output: string;\n options: CommandLineOptions;\n}> {\n const argv = await yargs(hideBin(process.argv))\n .options(cliArguments)\n .usage(\"jspicl-cli input output [<args>]\")\n .demandCommand(2, \"Please specify an input and output file\")\n .help(false)\n .strict()\n .wrap(null)\n .parseAsync();\n\n const {\n _: [input, output],\n ...restArguments\n } = argv;\n\n return {\n input: path.resolve(input.toString()),\n output: path.resolve(output.toString()),\n options: restArguments as CommandLineOptions\n };\n}\n\nexport async function startBuildService(\n input: string,\n output: string,\n cliOptions: CommandLineOptions\n) {\n const {watch, config} = cliOptions;\n const runPico = createPico8Launcher(\n watch,\n config.picoPath,\n config.reloadOnSave,\n config.pipeOutputToConsole\n );\n\n const jsOutput = path.resolve(config.jsOutput || \"build/jsOutput.js\");\n\n const buildConfig: BuildOptions = {\n entryPoints: [input],\n bundle: true,\n platform: \"neutral\",\n treeShaking: false,\n minify: false,\n format: \"esm\",\n outfile: jsOutput,\n plugins: [\n watchPlugin({\n config,\n output,\n\n onBuildError: (errors) => {\n logError(`Build failed with errors:\\n${errors}`);\n },\n\n onBuildEnd: (cartridgeContent, transpiledSource) => {\n config.luaOutput && logToFile(transpiledSource.lua, config.luaOutput);\n logToFile(cartridgeContent, output);\n\n logSuccess(\"Build completed\");\n runPico(output);\n\n // Statistics\n config.showStats &&\n logStats(\n transpiledSource.lua,\n transpiledSource.polyfillOutput,\n cartridgeContent\n );\n }\n })\n ]\n };\n\n if (watch) {\n const context = await esbuild.context(buildConfig);\n await context.watch();\n } else {\n await esbuild.build(buildConfig);\n }\n}\n\nasync function runCLI() {\n const {input, output, options} = await getCommandlineArguments();\n\n process.on(\"SIGINT\", () => {\n logInfo(\"Shutting down...\");\n process.exit(0);\n });\n\n try {\n await startBuildService(input, output, options);\n } catch (error) {\n logError(String(error));\n throw error;\n }\n}\n\nrunCLI();\n", "import path from \"node:path\";\nimport type {Options} from \"yargs\";\nimport type {CommandLineOptions, Config} from \"./types.js\";\n\nexport const cliArguments: Record<keyof CommandLineOptions, Options> = {\n watch: {\n description: \"Reload cartridge on rebuilds\",\n type: \"boolean\",\n default: false,\n alias: \"w\"\n },\n config: {\n description: \"Path to a config file\",\n type: \"string\",\n alias: \"c\",\n requiresArg: true,\n default: {\n jsOutput: \"build/jsOutput.js\"\n } as Config,\n coerce: async (p: string) => {\n const configModule = await import(path.resolve(p));\n return configModule.default;\n }\n }\n};\n", "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport {mkdirp} from \"mkdirp\";\nimport {getTokenCount} from \"./tokenCounter.js\";\n\nenum ICONS {\n info = \"\\x1b[34m\u2139\",\n success = \"\\x1b[32m\u2714\",\n warning = \"\\x1b[33m\u26A0\",\n error = \"\\x1b[31m\u2716\"\n}\n\nexport function logToFile(content: string, filePath: string) {\n mkdirp.sync(path.dirname(filePath));\n fs.writeFileSync(path.resolve(filePath), content);\n}\n\nexport function logInfo(content: string) {\n logToConsole(content, ICONS.info);\n}\n\nexport function logSuccess(content: string) {\n logToConsole(content, ICONS.success);\n}\n\nexport function logWarning(content: string) {\n logToConsole(content, ICONS.warning);\n}\n\nexport function logError(content: string) {\n logToConsole(content, ICONS.error);\n}\n\nfunction logToConsole(content: string, icon: string) {\n console.log(`${icon} ${content}\\x1b[0m`);\n}\n\nexport function logStats(lua: string, polyfillOutput: string, code: string) {\n const tokens = getTokenCount(lua);\n const polyfillTokens = getTokenCount(polyfillOutput);\n\n logInfo(\"Cartridge Statistics\");\n console.log(\"\".padEnd(41, \"\u2014\"));\n\n const stats = [\n {\n label: \"Characters\",\n value: lua.length,\n percent: `${~~((lua.length * 100) / 65535)}%`\n },\n {\n label: \"Tokens\",\n value: `~${tokens}`,\n percent: `${~~((tokens * 100) / 8192)}%`\n },\n {\n label: \" - Polyfills\",\n value: `~${polyfillTokens}`\n },\n {\n label: \"Filesize\",\n value: `${Math.ceil(code.length / 1024)} KB`\n }\n ];\n\n stats.forEach((stats) => {\n const label = `${stats.label}:`.padEnd(20, \" \");\n const value = `${stats.value}`.padStart(15, \" \");\n const percent = stats.percent\n ? `\\x1b[33m${stats.percent}`.padStart(10, \" \")\n : \"\";\n\n console.log(`${label}${value}${percent}\\x1b[0m`);\n });\n}\n", "// Each token is a word (e.g. variable name) or operator.\n// Pairs of brackets, and strings count as 1 token.\n// Commas, periods, LOCALs, semi-colons, ENDs, and comments are not counted.\nconst tokens = [\n /\\\"[^\\\"]*\\\"/, // Strings\n /\\d+\\.\\d+/, // floating numbers\n /\\w+/, // words\n /\\d+/, // numbers\n\n /!=/, // inequality\n /==/, // comparison\n /\\+=/, // incrementing assignment\n /-=/, // decrementing assignment\n /<=/, // equal or less than\n />=/, // equal or greater than\n /\\.\\./, // string concatenation\n\n /</, // less than\n />/, // greater than\n /\\+/, // addition\n /-/, // subtraction\n /\\//, // division\n /\\*/, // multiplication\n /=/, // equals\n /\\%/, // percentage\n /\\(/, // paranthesis\n /\\[/, // left bracket\n /\\{/ // left curly brace\n]\n .map((r) => r.source)\n .join(\"|\");\n\n/** Calculates the token count for the passed in Lua code*/\nexport function getTokenCount(luaCode: string) {\n const regex = new RegExp(`(${tokens})`, \"gi\");\n\n return (luaCode.match(regex) || []).filter(\n (token) => token !== \"local\" && token !== \"end\"\n ).length;\n}\n", "import path from \"path\";\nimport {spawn, exec, ChildProcess} from \"child_process\";\nimport {fileURLToPath} from \"url\";\nimport {logSuccess, logWarning} from \"./logging.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst osMatrix: Record<string, {execPath: string; reloadCommand?: string}> = {\n win32: {\n execPath: `\"C:\\\\Program Files (x86)\\\\PICO-8\\\\pico8.exe\"`\n },\n darwin: {\n execPath: \"/Applications/PICO-8.app/Contents/MacOS/pico8\",\n reloadCommand: path.resolve(__dirname, \"../scripts/reload-pico8-bin\")\n },\n linux: {\n execPath: \"~/pico-8/pico8\"\n }\n};\n\nexport function createPico8Launcher(\n watch: boolean,\n customPicoPath?: string,\n reloadOnSave?: boolean,\n pipeOutputToConsole?: boolean\n) {\n let picoProcess: ChildProcess | null;\n const {execPath, reloadCommand} = osMatrix[process.platform];\n\n return (cartridgePath: string) => {\n if (!watch || !cartridgePath) {\n return;\n }\n\n if (picoProcess) {\n if (!reloadOnSave) {\n return;\n }\n\n if (reloadCommand) {\n logSuccess(\"Reloading cartridge in PICO-8\");\n exec(reloadCommand);\n } else {\n logWarning(\n \"Autoreloading is currently not supported on your OS. Please press Ctrl+R in PICO-8 to see new changes.\"\n );\n }\n } else {\n logSuccess(\"Running cartridge in PICO-8\");\n // Use customized path if available, otherwise fallback to the default one for the current OS\n picoProcess = launchPico8(\n customPicoPath || execPath,\n cartridgePath,\n pipeOutputToConsole\n );\n\n picoProcess.on(\"close\", (errorCode) => {\n if (errorCode !== 0) {\n logWarning(`PICO-8 process exited with code ${errorCode}`);\n }\n picoProcess = null;\n });\n }\n };\n}\n\nfunction launchPico8(\n picoPath: string,\n cartridgePath: string,\n pipeOutputToConsole?: boolean\n) {\n return spawn(picoPath, [\"-run\", `\"${path.resolve(cartridgePath)}\"`], {\n shell: true,\n stdio: pipeOutputToConsole ? \"inherit\" : \"pipe\"\n });\n}\n", "import type {BuildResult, Plugin} from \"esbuild\";\nimport fs from \"node:fs\";\nimport {\n generateCartridgeContent,\n getPicoSectionsFromCartridge\n} from \"./cartridge.js\";\nimport {getSpritesheetFromImage} from \"./spritesheet.js\";\nimport {transpile} from \"./transpile.js\";\nimport type {Config} from \"./types.js\";\n\ntype WatchPluginOptions = {\n config: Config;\n output: string;\n onBuildEnd?: (\n cartridgeContent: string,\n transpiledSource: {lua: string; polyfillOutput: string}\n ) => void;\n onBuildError?: (errors: string) => void;\n};\n\nexport const watchPlugin = (options: WatchPluginOptions): Plugin => ({\n name: \"watcher\",\n setup(build) {\n build.onEnd(async (result: BuildResult) => {\n const {onBuildEnd, onBuildError, config, output} = options;\n\n const {jsOutput, spritesheetImagePath} = config;\n\n if (result.errors.length) {\n const errors = result.errors.map((error) => error.text).join(\"\\n\");\n onBuildError?.(errors);\n\n return;\n }\n\n console.clear();\n\n const jsContent = fs.readFileSync(jsOutput, \"utf-8\");\n const transpiledSource = transpile(jsContent, config);\n const cartridgeSections = getPicoSectionsFromCartridge(output);\n const gfxSection = await getSpritesheetFromImage(spritesheetImagePath);\n\n const cartridgeContent = generateCartridgeContent({\n ...cartridgeSections,\n lua: transpiledSource.lua,\n gfx: gfxSection\n });\n\n onBuildEnd?.(cartridgeContent, transpiledSource);\n });\n }\n});\n", "import fs from \"fs\";\nimport path from \"path\";\nimport type {PicoSections} from \"./types.js\";\n\nexport function generateCartridgeContent({\n lua = \"\",\n gff = \"\",\n gfx = \"\",\n music = \"\",\n map = \"\",\n sfx = \"\"\n}: Partial<PicoSections> = {}) {\n return [\n \"pico-8 cartridge // http://www.pico-8.com\",\n \"version 42\",\n \"__lua__\",\n lua,\n gfx && `__gfx__\\n${gfx}`,\n gff && `__gff__\\n${gff}`,\n map && `__map__\\n${map}`,\n sfx && `__sfx__\\n${sfx}`,\n music && `__music__\\n${music}`,\n \"\\n\"\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport function getPicoSectionsFromCartridge(\n cartridgePath: string\n): PicoSections {\n try {\n const resolvedCartridgePath = path.resolve(cartridgePath);\n const content = fs.existsSync(resolvedCartridgePath)\n ? fs.readFileSync(resolvedCartridgePath, \"utf8\")\n : \"\";\n return parsePico8Cartridge(content);\n } catch (error) {\n throw new Error(\n `Failed to read cartridge at ${cartridgePath}: ${(error as Error).message}`\n );\n }\n}\n\nfunction parsePico8Cartridge(content: string): PicoSections {\n const cartridgeSections: PicoSections = {\n lua: \"\",\n gff: \"\",\n gfx: \"\",\n music: \"\",\n map: \"\",\n sfx: \"\"\n };\n\n // Extract the contents of each section\n const regex = /__(\\w+)__\\n([\\s\\S]*?)(?=\\n__\\w+__\\n|\\n(\\n|$))/g;\n // /__(\\w+)__\\r?\\n([\\s\\S]*?)(?=__\\w+__|\\s*$)/g;\n\n let result;\n while ((result = regex.exec(content)) !== null) {\n const [, section, content] = result;\n cartridgeSections[section as keyof PicoSections] = content;\n }\n\n return cartridgeSections;\n}\n", "import fs from \"fs\";\nimport pngjs from \"pngjs\";\nimport {PICO8_PALETTE} from \"./constants.js\";\n\nconst spritesheetWidth = 128;\nconst spritesheetHeight = 128;\nconst hexBase = 16;\nconst pixelDataSize = 4; // red + green + blue + alpha\n\nconst toClosestColor = (pixels: Buffer) => (_: any, offset: number) => {\n const pixelOffset = offset * pixelDataSize;\n const pixel = {\n r: pixels[pixelOffset],\n g: pixels[pixelOffset + 1],\n b: pixels[pixelOffset + 2]\n };\n\n let minDistance = Number.MAX_VALUE;\n let closestPaletteColor = 0;\n PICO8_PALETTE.forEach(\n (color: {r: number; g: number; b: number}, i: number) => {\n const diff =\n (color.r - pixel.r) ** 2 +\n (color.g - pixel.g) ** 2 +\n (color.b - pixel.b) ** 2;\n\n if (diff < minDistance) {\n minDistance = diff;\n closestPaletteColor = i;\n }\n }\n );\n\n return closestPaletteColor.toString(hexBase);\n};\n\nexport function getSpritesheetFromImage(imagePath: string): Promise<string> {\n if (!imagePath) {\n throw new Error(\"Image path is missing\");\n }\n\n const stream = fs.createReadStream(imagePath).pipe(new pngjs.PNG());\n\n return new Promise((resolve) =>\n stream.on(\"parsed\", () => {\n if (\n stream.width !== spritesheetWidth ||\n stream.height !== spritesheetHeight\n ) {\n throw new Error(\"The spritesheet must be a 128x128 png image\");\n }\n\n const pixels = new Array(stream.width * stream.height)\n .fill(0)\n .map(toClosestColor(stream.data));\n\n const pixelsAsString = new Array(stream.height)\n .fill(0)\n .map((_: any, offset) =>\n // cut the strings so we get stacks of 128 characters\n pixels\n .slice(\n offset * spritesheetWidth,\n offset * spritesheetWidth + spritesheetWidth\n )\n .join(\"\")\n )\n .join(\"\\n\");\n\n resolve(pixelsAsString);\n })\n );\n}\n", "export const JSPICL_BANNER = `--[[\ngenerated with jspicl,\na javascript to pico-8 lua\ntranspiler.\n\nplease report any bugs at:\nhttps://github.com/jspicl/jspicl/issues\n]]--\n`;\n\nexport const PICO8_PALETTE = [\n {\n r: 0,\n g: 0,\n b: 0\n },\n {\n r: 29,\n g: 43,\n b: 83\n },\n {\n r: 126,\n g: 37,\n b: 83\n },\n {\n r: 0,\n g: 135,\n b: 81\n },\n {\n r: 171,\n g: 82,\n b: 54\n },\n {\n r: 95,\n g: 87,\n b: 79\n },\n {\n r: 194,\n g: 195,\n b: 199\n },\n {\n r: 255,\n g: 241,\n b: 232\n },\n {\n r: 255,\n g: 0,\n b: 77\n },\n {\n r: 255,\n g: 163,\n b: 0\n },\n {\n r: 255,\n g: 236,\n b: 39\n },\n {\n r: 0,\n g: 228,\n b: 54\n },\n {\n r: 41,\n g: 173,\n b: 255\n },\n {\n r: 131,\n g: 118,\n b: 156\n },\n {\n r: 255,\n g: 119,\n b: 168\n },\n {\n r: 255,\n g: 204,\n b: 170\n }\n];\n", "import {jspicl} from \"@jspicl/core\";\nimport {JSPICL_BANNER} from \"./constants.js\";\nimport type {Config} from \"./types.js\";\n\nexport function transpile(javascriptCode: string, config: Config) {\n const {includeBanner, polyfillTransform, jspicl: jspiclOptions = {}} = config;\n\n const jspiclBanner = (includeBanner && `${JSPICL_BANNER}`) || \"\";\n\n const {code, polyfills} = jspicl(javascriptCode, jspiclOptions);\n const polyfillOutput = polyfillTransform\n ? polyfillTransform(polyfills)\n : Object.values(polyfills).join(\"\\n\");\n\n const lua = `${jspiclBanner}${polyfillOutput}${code}`;\n\n return {\n lua,\n polyfillOutput\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "process", "path", "path", "tokens", "stats", "path", "path", "fs", "fs", "path", "content", "fs", "fs", "fs", "process", "path"]
|
|
7
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Options as JspiclOptions } from "@jspicl/core/types";
|
|
2
|
+
export interface PicoSections extends Record<string, string> {
|
|
3
|
+
lua: string;
|
|
4
|
+
gff: string;
|
|
5
|
+
gfx: string;
|
|
6
|
+
music: string;
|
|
7
|
+
map: string;
|
|
8
|
+
sfx: string;
|
|
9
|
+
}
|
|
10
|
+
export interface Config {
|
|
11
|
+
spritesheetImagePath: string;
|
|
12
|
+
jsOutput: string;
|
|
13
|
+
picoPath?: string;
|
|
14
|
+
includeBanner?: boolean;
|
|
15
|
+
luaOutput?: string;
|
|
16
|
+
pipeOutputToConsole?: boolean;
|
|
17
|
+
polyfillTransform?: (polyfills: Record<string, string>) => string;
|
|
18
|
+
reloadOnSave?: boolean;
|
|
19
|
+
showStats?: boolean;
|
|
20
|
+
jspicl?: JspiclOptions;
|
|
21
|
+
}
|
|
22
|
+
export interface CommandLineOptions {
|
|
23
|
+
watch: boolean;
|
|
24
|
+
config: Config;
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jspicl/cli",
|
|
3
|
+
"version": "4.0.0-alpha.0",
|
|
4
|
+
"description": "CLI for simplifying PICO-8 game development in JavaScript",
|
|
5
|
+
"author": "Agron Kabashi",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"jspicl": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
"./types": {
|
|
13
|
+
"types": "./dist/types.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"build": "tsc --noEmit && tsc -p tsconfig.types.json && esbuild src/index.ts --bundle --platform=node --format=esm --packages=external --banner:js='#!/usr/bin/env node' --outfile=dist/cli.js --sourcemap",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
26
|
+
"test": "echo \"No tests yet\"",
|
|
27
|
+
"prepublishOnly": "yarn clean && yarn test && yarn build"
|
|
28
|
+
},
|
|
29
|
+
"prettier": {
|
|
30
|
+
"arrowParens": "always",
|
|
31
|
+
"bracketSpacing": false,
|
|
32
|
+
"endOfLine": "lf",
|
|
33
|
+
"printWidth": 80,
|
|
34
|
+
"semi": true,
|
|
35
|
+
"singleQuote": false,
|
|
36
|
+
"tabWidth": 2,
|
|
37
|
+
"trailingComma": "none",
|
|
38
|
+
"useTabs": false
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/jspicl/jspicl"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"jspicl",
|
|
46
|
+
"pico-8",
|
|
47
|
+
"cli",
|
|
48
|
+
"build-tool",
|
|
49
|
+
"javascript",
|
|
50
|
+
"lua",
|
|
51
|
+
"transpiler",
|
|
52
|
+
"game-development"
|
|
53
|
+
],
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/lodash.debounce": "^4.0.9",
|
|
56
|
+
"@types/node": "^22.0.0",
|
|
57
|
+
"@types/pngjs": "^6.0.5",
|
|
58
|
+
"@types/yargs": "^17.0.33",
|
|
59
|
+
"esbuild": "^0.25.0",
|
|
60
|
+
"typescript": "^5.7.0"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@jspicl/core": "workspace:^",
|
|
64
|
+
"chokidar": "^5.0.0",
|
|
65
|
+
"lodash.debounce": "^4.0.8",
|
|
66
|
+
"mkdirp": "^3.0.1",
|
|
67
|
+
"pngjs": "^7.0.0",
|
|
68
|
+
"yargs": "^18.0.0"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=22"
|
|
72
|
+
}
|
|
73
|
+
}
|