@tilua/compiler 8.1.0 → 9.0.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/dist/cli.js CHANGED
@@ -1,33 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ WRITTEN_BY_TILUA,
3
4
  bundle,
4
5
  resolveConfig
5
- } from "./chunk-WOBHMGGC.js";
6
+ } from "./chunk-VUIF62OE.js";
6
7
 
7
8
  // src/cli.ts
8
- import { mkdirSync, writeFileSync } from "fs";
9
- import { basename, dirname, join, relative, resolve } from "path";
10
- var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>] [--noCheck] [--noLineMap]";
9
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, watch, writeFileSync } from "fs";
10
+ import { basename, dirname, join, relative, resolve, sep } from "path";
11
+ var usage = "usage: tilua [<entry>] [--out <file>] [--output single|chunks|files] [--config <tilua.config.json>] [--noCheck] [--noLineMap] [--minify] [--watch]\n tilua init";
11
12
  var args = process.argv.slice(2);
12
13
  var entry;
13
14
  var out;
14
15
  var config;
15
16
  var typeCheck = true;
16
17
  var lineMap;
18
+ var minify;
17
19
  var output;
20
+ var watching = false;
18
21
  for (let i = 0; i < args.length; i++) {
19
22
  const arg = args[i];
20
23
  if (arg === "--out") out = args[++i];
21
24
  else if (arg === "--config") config = args[++i];
22
25
  else if (arg === "--noCheck") typeCheck = false;
23
26
  else if (arg === "--noLineMap") lineMap = false;
27
+ else if (arg === "--minify") minify = true;
28
+ else if (arg === "--watch" || arg === "-w") watching = true;
24
29
  else if (arg === "--target") {
25
30
  console.error(`--target is gone: the output runs on Lua 5.1 to 5.4, LuaJIT and Luau, and a library says what more its Lua has \u2014 add "luau" to the config's 'types'`);
26
31
  process.exit(2);
27
32
  } else if (arg === "--output") {
28
33
  const value = args[++i];
29
- if (value !== "single" && value !== "chunks" && value !== "modules") {
30
- console.error(`--output must be 'single', 'chunks' or 'modules', not '${value}'`);
34
+ if (value === "modules") {
35
+ console.error("--output modules is gone: --output files writes one file per module, each of which returns its exports");
36
+ process.exit(2);
37
+ }
38
+ if (value !== "single" && value !== "chunks" && value !== "files") {
39
+ console.error(`--output must be 'single', 'chunks' or 'files', not '${value}'`);
31
40
  process.exit(2);
32
41
  }
33
42
  output = value;
@@ -36,39 +45,162 @@ for (let i = 0; i < args.length; i++) {
36
45
  process.exit(0);
37
46
  } else entry = arg;
38
47
  }
39
- if (!entry) {
40
- console.error(usage);
41
- process.exit(2);
48
+ var shown = (path) => relative(process.cwd(), path) || ".";
49
+ function init() {
50
+ const folder = process.cwd();
51
+ for (const name of ["tilua.config.json", "tilua.config.jsonc"]) {
52
+ if (existsSync(join(folder, name))) {
53
+ console.error(`${name} is already here`);
54
+ process.exit(1);
55
+ }
56
+ }
57
+ let rootDir = "src";
58
+ const project = join(folder, "default.project.json");
59
+ if (existsSync(project)) {
60
+ const paths = [];
61
+ const walk = (node) => {
62
+ if (!node || typeof node !== "object") return;
63
+ const path = node.$path;
64
+ const named = typeof path === "string" ? path : path?.optional;
65
+ if (typeof named === "string" && !/\.\w+$/.test(named)) paths.push(named);
66
+ for (const [key, child] of Object.entries(node)) if (!key.startsWith("$")) walk(child);
67
+ };
68
+ try {
69
+ walk(JSON.parse(readFileSync(project, "utf8")).tree);
70
+ } catch (error) {
71
+ console.error(`default.project.json: ${error.message}`);
72
+ process.exit(1);
73
+ }
74
+ const split = paths.map((path) => path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "").split("/"));
75
+ const shared = [];
76
+ for (let i = 0; split.length && split.every((parts) => parts.length > i && parts[i] === split[0][i]); i++) shared.push(split[0][i]);
77
+ if (split.length) rootDir = shared.join("/") || ".";
78
+ } else {
79
+ console.error('No default.project.json here: rootDir is "src". Change it if the project reads its files from elsewhere.');
80
+ }
81
+ const written = { types: ["roblox"], output: "files", rootDir };
82
+ writeFileSync(join(folder, "tilua.config.json"), JSON.stringify(written, null, 4) + "\n");
83
+ console.log("tilua.config.json: a .luau beside each .tilua under " + rootDir);
84
+ console.log("Next: npm i -D @tilua/compiler @tilua-types/roblox, then run `npx tilua --watch` beside `rojo serve`.");
85
+ process.exit(0);
86
+ }
87
+ function writtenByTilua(folder) {
88
+ const found = [];
89
+ const walk = (at) => {
90
+ let items;
91
+ try {
92
+ items = readdirSync(at, { withFileTypes: true });
93
+ } catch {
94
+ return;
95
+ }
96
+ for (const item of items) {
97
+ if (item.name.startsWith(".") || item.name === "node_modules") continue;
98
+ const path = join(at, item.name);
99
+ if (item.isDirectory()) walk(path);
100
+ else if (/\.luau?$/.test(item.name) && isTilua(path)) found.push(path);
101
+ }
102
+ };
103
+ walk(folder);
104
+ return found;
105
+ }
106
+ function isTilua(path) {
107
+ try {
108
+ const text = readFileSync(path, "utf8").trimEnd();
109
+ return text.slice(text.lastIndexOf("\n") + 1).startsWith(WRITTEN_BY_TILUA);
110
+ } catch {
111
+ return false;
112
+ }
42
113
  }
43
- async function main(from) {
44
- const found = resolveConfig(config, resolve(from)).config;
114
+ async function build(from) {
115
+ const found = resolveConfig(config, resolve(from ?? "tilua.config.json")).config;
45
116
  const mode = output ?? found?.output ?? "single";
46
- const entryFile = mode === "modules" ? void 0 : out ?? from.replace(/\.tilua$/, "") + ".luau";
47
- const folder = entryFile !== void 0 ? dirname(entryFile) : out ?? found?.directory ?? dirname(from);
117
+ if (mode !== "files" && from === void 0) {
118
+ console.error(usage);
119
+ process.exit(2);
120
+ }
121
+ const perFile = mode === "files";
122
+ const entryFile = perFile || from === void 0 ? void 0 : out ?? from.replace(/\.tilua$/, "") + ".luau";
123
+ const folder = resolve(entryFile !== void 0 ? dirname(entryFile) : out ?? found?.outDir ?? process.cwd());
48
124
  const result = await bundle({
49
- entry: from,
125
+ entry: perFile ? void 0 : from,
50
126
  config,
51
127
  typeCheck,
52
128
  output: mode,
53
129
  lineMap,
130
+ minify,
131
+ outDir: perFile ? out : void 0,
54
132
  outFile: entryFile !== void 0 ? basename(entryFile) : void 0
55
133
  });
56
134
  for (const d of result.diagnostics) {
57
- console.error(`${relative(process.cwd(), d.file)}:${d.line}:${d.column} ${d.severity === "warning" ? "warning: " : ""}${d.message}`);
135
+ console.error(`${shown(d.file)}:${d.line}:${d.column} ${d.severity === "warning" ? "warning: " : ""}${d.message}`);
58
136
  }
59
137
  if (result.code === void 0) {
60
- console.error("no bundle written");
61
- process.exit(1);
138
+ console.error("no output written");
139
+ return false;
140
+ }
141
+ const targets = result.files.map((file) => ({ ...file, target: join(folder, file.path) }));
142
+ if (perFile) {
143
+ const theirs = targets.filter((file) => existsSync(file.target) && !isTilua(file.target));
144
+ for (const file of theirs) {
145
+ console.error(`${shown(file.target)}: this file was not written by tilua, and a .tilua would replace it \u2014 rename or remove one of them`);
146
+ }
147
+ if (theirs.length) return false;
148
+ }
149
+ for (const file of targets) {
150
+ if (existsSync(file.target) && readFileSync(file.target, "utf8") === file.code) continue;
151
+ mkdirSync(dirname(file.target), { recursive: true });
152
+ writeFileSync(file.target, file.code);
153
+ console.log(`${shown(file.target)}: ${file.modules.length} module${file.modules.length === 1 ? "" : "s"}`);
62
154
  }
63
- for (const file of result.files) {
64
- const target = join(folder, file.path);
65
- mkdirSync(dirname(target), { recursive: true });
66
- writeFileSync(target, file.code);
67
- console.log(`${target}: ${file.modules.length} module${file.modules.length === 1 ? "" : "s"}`);
155
+ if (perFile) {
156
+ const kept = new Set(targets.map((file) => resolve(file.target)));
157
+ for (const stale of writtenByTilua(folder)) {
158
+ if (kept.has(resolve(stale))) continue;
159
+ rmSync(stale);
160
+ console.log(`${shown(stale)}: removed, its .tilua is gone`);
161
+ }
68
162
  }
69
- process.exit(result.diagnostics.some((d) => d.severity !== "warning") ? 1 : 0);
163
+ return !result.diagnostics.some((d) => d.severity !== "warning");
164
+ }
165
+ async function watchAndBuild(from) {
166
+ const found = resolveConfig(config, resolve(from ?? "tilua.config.json")).config;
167
+ const folder = found?.directory ?? (from !== void 0 ? dirname(resolve(from)) : process.cwd());
168
+ let running = false;
169
+ let again = false;
170
+ let timer;
171
+ const run = async () => {
172
+ if (running) {
173
+ again = true;
174
+ return;
175
+ }
176
+ running = true;
177
+ const ok = await build(from).catch((error) => {
178
+ console.error(error instanceof Error ? error.message : error);
179
+ return false;
180
+ });
181
+ console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] ${ok ? "built" : "built with errors"}; watching ${shown(folder)}`);
182
+ running = false;
183
+ if (again) {
184
+ again = false;
185
+ await run();
186
+ }
187
+ };
188
+ await run();
189
+ watch(folder, { recursive: true }, (_event, name) => {
190
+ if (!name) return;
191
+ const path = name.toString();
192
+ if (path.split(sep).includes("node_modules")) return;
193
+ if (!/\.tilua$|tilua\.config\.jsonc?$|\.project\.json$/.test(path)) return;
194
+ clearTimeout(timer);
195
+ timer = setTimeout(() => void run(), 100);
196
+ });
197
+ }
198
+ async function main() {
199
+ if (entry === "init") init();
200
+ if (watching) return watchAndBuild(entry);
201
+ process.exit(await build(entry) ? 0 : 1);
70
202
  }
71
- main(entry).catch((error) => {
203
+ main().catch((error) => {
72
204
  console.error(error instanceof Error ? error.message : error);
73
205
  process.exit(1);
74
206
  });