@tilua/compiler 9.0.0 → 9.0.1

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/README.md CHANGED
@@ -18,9 +18,11 @@ tilua [<entry>] [--out <file>] [--output single|chunks|files] [--config <tilua.c
18
18
  tilua init
19
19
  ```
20
20
 
21
- `--watch` builds again whenever a `.tilua` file, the config or a Rojo project
22
- changes, and keeps going. `tilua init` writes a `tilua.config.json` for the
23
- Rojo project in the folder — see `@tilua-types/roblox`.
21
+ `--watch` builds again whenever a file it reads changes — a `.tilua`, the
22
+ config, a Rojo project, and with an `outDir` of its own anything under
23
+ `rootDir` — and keeps going. `tilua init` sets up the Rojo project in the
24
+ folder: `src` compiled to `out`, and the project pointed at `out` — see
25
+ `@tilua-types/roblox`.
24
26
 
25
27
  Every module the entry imports is bundled in. Problems are reported as
26
28
  `file:line:column message`. Type errors are checked against the config's
@@ -486,7 +488,12 @@ tilua # the config above this folder says the rest
486
488
  `rootDir` is the config's folder unless set, and `outDir` is `rootDir`, so
487
489
  each `.luau` lands beside its `.tilua`. Every file it writes ends with a line
488
490
  saying tilua wrote it: the CLI never replaces a `.luau` without that line —
489
- one written by hand — and removes one with it whose `.tilua` is gone. `--out` names the folder in place of
491
+ one written by hand — and removes one with it whose `.tilua` is gone.
492
+
493
+ With an `outDir` of its own, the CLI makes it a mirror of `rootDir`: every
494
+ `.tilua` compiled, every other file copied as it is, every folder there, and
495
+ nothing else. `outDir` is the build's alone, so it may not hold `rootDir` or
496
+ the project, nor sit under `rootDir`. `--out` names the folder in place of
490
497
  `outDir`. From the API, `bundle({ output: "files", root })` without an
491
498
  `entry`; `result.files` holds every file, its path from `outDir`.
492
499
 
@@ -539,12 +546,12 @@ a script that requires any of them knows what it got.
539
546
  <!-- compatibility:start -->
540
547
  ## Compatibility
541
548
 
542
- `@tilua/compiler@9.0.0` works with these tilua packages. *Released with* is the
549
+ `@tilua/compiler@9.0.1` works with these tilua packages. *Released with* is the
543
550
  version it was built and tested against.
544
551
 
545
552
  | Package | Range | Released with | |
546
553
  | --- | --- | --- | --- |
547
- | `@tilua/parser` | `^9.0.0` | 9.0.0 | dependency |
554
+ | `@tilua/parser` | `^9.0.1` | 9.0.1 | dependency |
548
555
  <!-- compatibility:end -->
549
556
 
550
557
  ## Development
@@ -2805,6 +2805,9 @@ import {
2805
2805
  resolveModulePath,
2806
2806
  resolveTypeLibraries,
2807
2807
  importExpressions,
2808
+ sourceMapOf,
2809
+ sourceMapTypes,
2810
+ outputPathOf,
2808
2811
  directivesOf,
2809
2812
  applyDirectives,
2810
2813
  UNUSED_EXPECT_ERROR,
@@ -4095,6 +4098,35 @@ function importedSpecifiers(program2) {
4095
4098
  return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
4096
4099
  }
4097
4100
  var libraryCache = /* @__PURE__ */ new Map();
4101
+ var treeCache;
4102
+ function instanceTree(config, libs, noLib) {
4103
+ const tree = sourceMapOf(config);
4104
+ if (!tree) return void 0;
4105
+ if ("problem" in tree) return tree.named ? { problem: { file: config.path, message: tree.problem } } : void 0;
4106
+ const declares = (name) => libs.some((lib) => lib.body.statements.some((s) => s.type === "DeclareStatement" && s.name === name));
4107
+ if (!tree.named && !declares("game")) return void 0;
4108
+ if (treeCache && treeCache.text === tree.text && treeCache.libs.length === libs.length && treeCache.libs.every((lib, i) => lib === libs[i])) {
4109
+ return { types: treeCache.types };
4110
+ }
4111
+ const empty = parse("");
4112
+ const aliases = analyzeTypes(empty, analyzeScopes(empty, { noLib }), { libs, noLib, diagnostics: false }).aliases;
4113
+ const membersOf = (className) => {
4114
+ const type = aliases.get(className);
4115
+ return new Set(type?.kind === "object" ? type.properties.keys() : ["Name", "ClassName", "Parent", "Archivable"]);
4116
+ };
4117
+ const { types, problem } = sourceMapTypes(tree.text, tree.path, { classes: new Set(aliases.keys()), membersOf });
4118
+ if (!types) return tree.named && problem ? { problem: { file: tree.path, message: problem } } : void 0;
4119
+ const scripts = /* @__PURE__ */ new Map();
4120
+ const cached = {
4121
+ program: types.program,
4122
+ scriptFor: (file) => {
4123
+ if (!scripts.has(file)) scripts.set(file, types.scriptFor(file));
4124
+ return scripts.get(file);
4125
+ }
4126
+ };
4127
+ treeCache = { text: tree.text, libs: [...libs], types: cached, scripts };
4128
+ return { types: cached };
4129
+ }
4098
4130
  function parsedLibrary(file) {
4099
4131
  let stamp;
4100
4132
  try {
@@ -4118,6 +4150,10 @@ function analyzeModules(modules, config) {
4118
4150
  const libs = libraries.files.map(parsedLibrary);
4119
4151
  const noLib = config?.noLib ?? false;
4120
4152
  const checked = libs.length > 0 || !noLib;
4153
+ const tree = config ? instanceTree(config, libs, noLib) : void 0;
4154
+ if (tree?.problem) out.push({ file: tree.problem.file, message: tree.problem.message, line: 1, column: 1, category: "config" });
4155
+ if (tree?.types) libs.push(tree.types.program);
4156
+ const scriptOf = (file) => tree?.types && config ? tree.types.scriptFor(outputPathOf(config, file)) : void 0;
4121
4157
  const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
4122
4158
  const byFile = new Map(modules.map((m) => [m.file, m]));
4123
4159
  const exportsCache = /* @__PURE__ */ new Map();
@@ -4130,7 +4166,9 @@ function analyzeModules(modules, config) {
4130
4166
  const done = analyzed.get(file);
4131
4167
  if (done) return done;
4132
4168
  const remembered = moduleAnalyses.get(file);
4133
- if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4169
+ const script = scriptOf(file);
4170
+ const ownLibs = script ? [...libs, script] : libs;
4171
+ if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4134
4172
  analyzed.set(file, remembered.result);
4135
4173
  readWhile.set(file, remembered.read);
4136
4174
  return remembered.result;
@@ -4143,7 +4181,7 @@ function analyzeModules(modules, config) {
4143
4181
  }
4144
4182
  const before = partials;
4145
4183
  const types = analyzeTypes(program2, scopes, {
4146
- libs,
4184
+ libs: ownLibs,
4147
4185
  resolveModule: resolverFor(file),
4148
4186
  noLib,
4149
4187
  reportUnknownTypes: checked
@@ -4160,7 +4198,7 @@ function analyzeModules(modules, config) {
4160
4198
  if (own !== void 0) read3.set(file, own);
4161
4199
  readWhile.set(file, read3);
4162
4200
  if ([...read3.values()].every((stamp) => stamp !== void 0)) {
4163
- moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read: read3, result: result2 });
4201
+ moduleAnalyses.set(file, { setting: settingFor, libs: [...ownLibs], program: program2, read: read3, result: result2 });
4164
4202
  }
4165
4203
  }
4166
4204
  return result2;
package/dist/cli.cjs CHANGED
@@ -4091,6 +4091,35 @@ function importedSpecifiers(program2) {
4091
4091
  return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
4092
4092
  }
4093
4093
  var libraryCache = /* @__PURE__ */ new Map();
4094
+ var treeCache;
4095
+ function instanceTree(config2, libs, noLib) {
4096
+ const tree = (0, import_parser7.sourceMapOf)(config2);
4097
+ if (!tree) return void 0;
4098
+ if ("problem" in tree) return tree.named ? { problem: { file: config2.path, message: tree.problem } } : void 0;
4099
+ const declares = (name) => libs.some((lib) => lib.body.statements.some((s) => s.type === "DeclareStatement" && s.name === name));
4100
+ if (!tree.named && !declares("game")) return void 0;
4101
+ if (treeCache && treeCache.text === tree.text && treeCache.libs.length === libs.length && treeCache.libs.every((lib, i) => lib === libs[i])) {
4102
+ return { types: treeCache.types };
4103
+ }
4104
+ const empty = (0, import_parser7.parse)("");
4105
+ const aliases = (0, import_parser7.analyzeTypes)(empty, (0, import_parser7.analyzeScopes)(empty, { noLib }), { libs, noLib, diagnostics: false }).aliases;
4106
+ const membersOf = (className) => {
4107
+ const type = aliases.get(className);
4108
+ return new Set(type?.kind === "object" ? type.properties.keys() : ["Name", "ClassName", "Parent", "Archivable"]);
4109
+ };
4110
+ const { types, problem } = (0, import_parser7.sourceMapTypes)(tree.text, tree.path, { classes: new Set(aliases.keys()), membersOf });
4111
+ if (!types) return tree.named && problem ? { problem: { file: tree.path, message: problem } } : void 0;
4112
+ const scripts = /* @__PURE__ */ new Map();
4113
+ const cached = {
4114
+ program: types.program,
4115
+ scriptFor: (file) => {
4116
+ if (!scripts.has(file)) scripts.set(file, types.scriptFor(file));
4117
+ return scripts.get(file);
4118
+ }
4119
+ };
4120
+ treeCache = { text: tree.text, libs: [...libs], types: cached, scripts };
4121
+ return { types: cached };
4122
+ }
4094
4123
  function parsedLibrary(file) {
4095
4124
  let stamp;
4096
4125
  try {
@@ -4114,6 +4143,10 @@ function analyzeModules(modules, config2) {
4114
4143
  const libs = libraries.files.map(parsedLibrary);
4115
4144
  const noLib = config2?.noLib ?? false;
4116
4145
  const checked = libs.length > 0 || !noLib;
4146
+ const tree = config2 ? instanceTree(config2, libs, noLib) : void 0;
4147
+ if (tree?.problem) out2.push({ file: tree.problem.file, message: tree.problem.message, line: 1, column: 1, category: "config" });
4148
+ if (tree?.types) libs.push(tree.types.program);
4149
+ const scriptOf = (file) => tree?.types && config2 ? tree.types.scriptFor((0, import_parser7.outputPathOf)(config2, file)) : void 0;
4117
4150
  const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
4118
4151
  const byFile = new Map(modules.map((m) => [m.file, m]));
4119
4152
  const exportsCache = /* @__PURE__ */ new Map();
@@ -4126,7 +4159,9 @@ function analyzeModules(modules, config2) {
4126
4159
  const done = analyzed.get(file);
4127
4160
  if (done) return done;
4128
4161
  const remembered = moduleAnalyses.get(file);
4129
- if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4162
+ const script = scriptOf(file);
4163
+ const ownLibs = script ? [...libs, script] : libs;
4164
+ if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4130
4165
  analyzed.set(file, remembered.result);
4131
4166
  readWhile.set(file, remembered.read);
4132
4167
  return remembered.result;
@@ -4139,7 +4174,7 @@ function analyzeModules(modules, config2) {
4139
4174
  }
4140
4175
  const before = partials;
4141
4176
  const types = (0, import_parser7.analyzeTypes)(program2, scopes, {
4142
- libs,
4177
+ libs: ownLibs,
4143
4178
  resolveModule: resolverFor(file),
4144
4179
  noLib,
4145
4180
  reportUnknownTypes: checked
@@ -4156,7 +4191,7 @@ function analyzeModules(modules, config2) {
4156
4191
  if (own !== void 0) read3.set(file, own);
4157
4192
  readWhile.set(file, read3);
4158
4193
  if ([...read3.values()].every((stamp) => stamp !== void 0)) {
4159
- moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read: read3, result: result2 });
4194
+ moduleAnalyses.set(file, { setting: settingFor, libs: [...ownLibs], program: program2, read: read3, result: result2 });
4160
4195
  }
4161
4196
  }
4162
4197
  return result2;
@@ -4234,6 +4269,7 @@ function allStatements(statements) {
4234
4269
  }
4235
4270
 
4236
4271
  // src/cli.ts
4272
+ var import_parser8 = require("@tilua/parser");
4237
4273
  var usage = "usage: tilua [<entry>] [--out <file>] [--output single|chunks|files] [--config <tilua.config.json>] [--noCheck] [--noLineMap] [--minify] [--watch]\n tilua init";
4238
4274
  var args = process.argv.slice(2);
4239
4275
  var entry;
@@ -4272,46 +4308,97 @@ for (let i = 0; i < args.length; i++) {
4272
4308
  } else entry = arg;
4273
4309
  }
4274
4310
  var shown = (path) => (0, import_node_path3.relative)(process.cwd(), path) || ".";
4311
+ var OUT = "out";
4275
4312
  function init() {
4276
4313
  const folder = process.cwd();
4314
+ let existing;
4277
4315
  for (const name of ["tilua.config.json", "tilua.config.jsonc"]) {
4278
- if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(folder, name))) {
4316
+ const path = (0, import_node_path3.join)(folder, name);
4317
+ if (!(0, import_node_fs4.existsSync)(path)) continue;
4318
+ let options2 = {};
4319
+ try {
4320
+ options2 = JSON.parse((0, import_parser8.stripJsonComments)((0, import_node_fs4.readFileSync)(path, "utf8")));
4321
+ } catch (error) {
4322
+ console.error(`${name}: ${error.message}`);
4323
+ process.exit(1);
4324
+ }
4325
+ if (options2.output !== "files" || options2.outDir !== void 0 && options2.outDir !== options2.rootDir) {
4279
4326
  console.error(`${name} is already here`);
4280
4327
  process.exit(1);
4281
4328
  }
4329
+ existing = { path, options: options2 };
4282
4330
  }
4283
- let rootDir = "src";
4284
4331
  const project = (0, import_node_path3.join)(folder, "default.project.json");
4285
- if ((0, import_node_fs4.existsSync)(project)) {
4286
- const paths = [];
4287
- const walk2 = (node) => {
4288
- if (!node || typeof node !== "object") return;
4289
- const path = node.$path;
4290
- const named = typeof path === "string" ? path : path?.optional;
4291
- if (typeof named === "string" && !/\.\w+$/.test(named)) paths.push(named);
4292
- for (const [key, child] of Object.entries(node)) if (!key.startsWith("$")) walk2(child);
4293
- };
4294
- try {
4295
- walk2(JSON.parse((0, import_node_fs4.readFileSync)(project, "utf8")).tree);
4296
- } catch (error) {
4297
- console.error(`default.project.json: ${error.message}`);
4298
- process.exit(1);
4299
- }
4300
- const split = paths.map((path) => path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "").split("/"));
4301
- const shared = [];
4302
- for (let i = 0; split.length && split.every((parts) => parts.length > i && parts[i] === split[0][i]); i++) shared.push(split[0][i]);
4303
- if (split.length) rootDir = shared.join("/") || ".";
4304
- } else {
4305
- console.error('No default.project.json here: rootDir is "src". Change it if the project reads its files from elsewhere.');
4332
+ if (!(0, import_node_fs4.existsSync)(project)) {
4333
+ console.error("No default.project.json here: run `tilua init` in the folder of a Rojo project (`rojo init` makes one)");
4334
+ process.exit(1);
4335
+ }
4336
+ const text = (0, import_node_fs4.readFileSync)(project, "utf8");
4337
+ const paths = [];
4338
+ const walk2 = (node) => {
4339
+ if (!node || typeof node !== "object") return;
4340
+ const path = node.$path;
4341
+ const named = typeof path === "string" ? path : path?.optional;
4342
+ if (typeof named === "string") paths.push(named);
4343
+ for (const [key, child] of Object.entries(node)) if (!key.startsWith("$")) walk2(child);
4344
+ };
4345
+ try {
4346
+ walk2(JSON.parse(text).tree);
4347
+ } catch (error) {
4348
+ console.error(`default.project.json: ${error.message}`);
4349
+ process.exit(1);
4350
+ }
4351
+ const split = paths.map((path) => path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "").split("/"));
4352
+ const shared = [];
4353
+ for (let i = 0; split.length && split.every((parts) => parts.length > i && parts[i] === split[0][i]); i++) shared.push(split[0][i]);
4354
+ if (split.length === 1 && /\.\w+$/.test(shared.at(-1) ?? "")) shared.pop();
4355
+ const rootDir = shared.join("/");
4356
+ if (!rootDir) {
4357
+ console.error("The project's $paths share no folder to compile from: put the code under one (src), as `rojo init` does");
4358
+ process.exit(1);
4359
+ }
4360
+ if (rootDir === OUT || rootDir.startsWith(`${OUT}/`)) {
4361
+ console.error(`The project already reads from ${OUT}: set tilua.config.json up by hand`);
4362
+ process.exit(1);
4363
+ }
4364
+ const out2 = (0, import_node_path3.join)(folder, OUT);
4365
+ if ((0, import_node_fs4.existsSync)(out2) && (0, import_node_fs4.readdirSync)(out2).length) {
4366
+ console.error(`${OUT} is already here and not empty: the build would replace what is in it`);
4367
+ process.exit(1);
4368
+ }
4369
+ const options = existing ? { ...existing.options, rootDir: existing.options.rootDir ?? rootDir, outDir: OUT } : { types: ["roblox"], output: "files", rootDir, outDir: OUT };
4370
+ (0, import_node_fs4.writeFileSync)(existing?.path ?? (0, import_node_path3.join)(folder, "tilua.config.json"), JSON.stringify(options, null, 4) + "\n");
4371
+ console.log(`${(0, import_node_path3.basename)(existing?.path ?? "tilua.config.json")}: ${String(options.rootDir)} compiled to ${OUT}`);
4372
+ const escaped = rootDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4373
+ let changed = 0;
4374
+ const pointed = text.replace(new RegExp(`("\\$path"\\s*:\\s*")(\\./)?${escaped}(?=/|")`, "g"), (_, head) => {
4375
+ changed++;
4376
+ return `${head}${OUT}`;
4377
+ });
4378
+ (0, import_node_fs4.writeFileSync)(project, pointed);
4379
+ console.log(`default.project.json: ${changed} $path${changed === 1 ? "" : "s"} now read from ${OUT}`);
4380
+ const ignore = (0, import_node_path3.join)(folder, ".gitignore");
4381
+ const ignored = (0, import_node_fs4.existsSync)(ignore) ? (0, import_node_fs4.readFileSync)(ignore, "utf8") : "";
4382
+ if (!ignored.split(/\r?\n/).some((line) => [OUT, `/${OUT}`, `${OUT}/`, `/${OUT}/`].includes(line.trim()))) {
4383
+ (0, import_node_fs4.writeFileSync)(ignore, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}
4384
+ # What tilua builds from ${rootDir}
4385
+ /${OUT}
4386
+ `);
4387
+ console.log(`.gitignore: /${OUT}`);
4306
4388
  }
4307
- const written = { types: ["roblox"], output: "files", rootDir };
4308
- (0, import_node_fs4.writeFileSync)((0, import_node_path3.join)(folder, "tilua.config.json"), JSON.stringify(written, null, 4) + "\n");
4309
- console.log("tilua.config.json: a .luau beside each .tilua under " + rootDir);
4310
4389
  console.log("Next: npm i -D @tilua/compiler @tilua-types/roblox, then run `npx tilua --watch` beside `rojo serve`.");
4311
4390
  process.exit(0);
4312
4391
  }
4313
- function writtenByTilua(folder) {
4314
- const found = [];
4392
+ function isInside(folder, path) {
4393
+ const below = (0, import_node_path3.relative)(folder, path);
4394
+ return below === "" || !below.startsWith("..") && !(0, import_node_path3.isAbsolute)(below);
4395
+ }
4396
+ function filesUnder(folder) {
4397
+ return under(folder).files;
4398
+ }
4399
+ function under(folder) {
4400
+ const files = [];
4401
+ const folders = [];
4315
4402
  const walk2 = (at) => {
4316
4403
  let items;
4317
4404
  try {
@@ -4320,14 +4407,27 @@ function writtenByTilua(folder) {
4320
4407
  return;
4321
4408
  }
4322
4409
  for (const item of items) {
4323
- if (item.name.startsWith(".") || item.name === "node_modules") continue;
4410
+ if (item.name === "node_modules" || item.name === ".git") continue;
4324
4411
  const path = (0, import_node_path3.join)(at, item.name);
4325
- if (item.isDirectory()) walk2(path);
4326
- else if (/\.luau?$/.test(item.name) && isTilua(path)) found.push(path);
4412
+ if (item.isDirectory()) {
4413
+ folders.push(path);
4414
+ walk2(path);
4415
+ } else files.push(path);
4327
4416
  }
4328
4417
  };
4329
4418
  walk2(folder);
4330
- return found;
4419
+ return { files, folders };
4420
+ }
4421
+ function removeEmpty(folder, keep) {
4422
+ for (const item of (0, import_node_fs4.readdirSync)(folder, { withFileTypes: true })) {
4423
+ if (!item.isDirectory()) continue;
4424
+ const path = (0, import_node_path3.join)(folder, item.name);
4425
+ removeEmpty(path, keep);
4426
+ if (!(0, import_node_fs4.readdirSync)(path).length && !keep.has((0, import_node_path3.resolve)(path))) (0, import_node_fs4.rmdirSync)(path);
4427
+ }
4428
+ }
4429
+ function writtenByTilua(folder) {
4430
+ return filesUnder(folder).filter((path) => /\.luau?$/.test(path) && isTilua(path));
4331
4431
  }
4332
4432
  function isTilua(path) {
4333
4433
  try {
@@ -4347,6 +4447,12 @@ async function build(from) {
4347
4447
  const perFile = mode === "files";
4348
4448
  const entryFile = perFile || from === void 0 ? void 0 : out ?? from.replace(/\.tilua$/, "") + ".luau";
4349
4449
  const folder = (0, import_node_path3.resolve)(entryFile !== void 0 ? (0, import_node_path3.dirname)(entryFile) : out ?? found?.outDir ?? process.cwd());
4450
+ const rootDir = (0, import_node_path3.resolve)(found?.rootDir ?? process.cwd());
4451
+ const mirror = perFile && (0, import_node_path3.resolve)(folder) !== rootDir;
4452
+ if (mirror && (isInside(folder, rootDir) || isInside(rootDir, folder) || isInside(folder, found?.directory ?? process.cwd()))) {
4453
+ console.error(`outDir (${shown(folder)}) has to be a folder of its own: not ${isInside(rootDir, folder) ? "under" : "around"} rootDir (${shown(rootDir)}), and not around the project`);
4454
+ return false;
4455
+ }
4350
4456
  const result2 = await bundle({
4351
4457
  entry: perFile ? void 0 : from,
4352
4458
  config,
@@ -4365,6 +4471,54 @@ async function build(from) {
4365
4471
  return false;
4366
4472
  }
4367
4473
  const targets = result2.files.map((file) => ({ ...file, target: (0, import_node_path3.join)(folder, file.path) }));
4474
+ if (mirror) {
4475
+ const compiled = new Map(targets.map((file) => [(0, import_node_path3.resolve)(file.target), file]));
4476
+ const copies = [];
4477
+ let clash = false;
4478
+ const leftovers = [];
4479
+ for (const source of filesUnder(rootDir)) {
4480
+ if (source.endsWith(".tilua")) continue;
4481
+ if (/\.luau?$/.test(source) && isTilua(source)) {
4482
+ leftovers.push(source);
4483
+ continue;
4484
+ }
4485
+ const target = (0, import_node_path3.resolve)(folder, (0, import_node_path3.relative)(rootDir, source));
4486
+ if (compiled.has(target)) {
4487
+ console.error(`${shown(source)}: a .tilua compiles to the same file \u2014 rename or remove one of them`);
4488
+ clash = true;
4489
+ continue;
4490
+ }
4491
+ copies.push({ source, target });
4492
+ }
4493
+ if (clash) return false;
4494
+ for (const leftover of leftovers) {
4495
+ (0, import_node_fs4.rmSync)(leftover);
4496
+ console.log(`${shown(leftover)}: removed \u2014 tilua compiled it beside its .tilua, and the output is in ${shown(folder)} now`);
4497
+ }
4498
+ for (const file of targets) {
4499
+ if ((0, import_node_fs4.existsSync)(file.target) && (0, import_node_fs4.readFileSync)(file.target, "utf8") === file.code) continue;
4500
+ (0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(file.target), { recursive: true });
4501
+ (0, import_node_fs4.writeFileSync)(file.target, file.code);
4502
+ console.log(`${shown(file.target)}: ${file.modules.length} module${file.modules.length === 1 ? "" : "s"}`);
4503
+ }
4504
+ for (const { source, target } of copies) {
4505
+ const bytes = (0, import_node_fs4.readFileSync)(source);
4506
+ if ((0, import_node_fs4.existsSync)(target) && (0, import_node_fs4.readFileSync)(target).equals(bytes)) continue;
4507
+ (0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(target), { recursive: true });
4508
+ (0, import_node_fs4.copyFileSync)(source, target);
4509
+ console.log(`${shown(target)}: copied`);
4510
+ }
4511
+ const kept = /* @__PURE__ */ new Set([...compiled.keys(), ...copies.map((copy) => copy.target)]);
4512
+ for (const stale of filesUnder(folder)) {
4513
+ if (kept.has((0, import_node_path3.resolve)(stale))) continue;
4514
+ (0, import_node_fs4.rmSync)(stale);
4515
+ console.log(`${shown(stale)}: removed`);
4516
+ }
4517
+ const folders = /* @__PURE__ */ new Set([folder, ...under(rootDir).folders.map((path) => (0, import_node_path3.resolve)(folder, (0, import_node_path3.relative)(rootDir, path)))]);
4518
+ for (const path of folders) (0, import_node_fs4.mkdirSync)(path, { recursive: true });
4519
+ removeEmpty(folder, folders);
4520
+ return !result2.diagnostics.some((d) => d.severity !== "warning");
4521
+ }
4368
4522
  if (perFile) {
4369
4523
  const theirs = targets.filter((file) => (0, import_node_fs4.existsSync)(file.target) && !isTilua(file.target));
4370
4524
  for (const file of theirs) {
@@ -4391,6 +4545,9 @@ async function build(from) {
4391
4545
  async function watchAndBuild(from) {
4392
4546
  const found = resolveConfig(config, (0, import_node_path3.resolve)(from ?? "tilua.config.json")).config;
4393
4547
  const folder = found?.directory ?? (from !== void 0 ? (0, import_node_path3.dirname)((0, import_node_path3.resolve)(from)) : process.cwd());
4548
+ const rootDir = found?.rootDir;
4549
+ const outDir = (0, import_node_path3.resolve)(out ?? found?.outDir ?? folder);
4550
+ const mirrored = (output ?? found?.output) === "files" && rootDir !== void 0 && outDir !== (0, import_node_path3.resolve)(rootDir);
4394
4551
  let running = false;
4395
4552
  let again = false;
4396
4553
  let timer;
@@ -4414,9 +4571,10 @@ async function watchAndBuild(from) {
4414
4571
  await run();
4415
4572
  (0, import_node_fs4.watch)(folder, { recursive: true }, (_event, name) => {
4416
4573
  if (!name) return;
4417
- const path = name.toString();
4418
- if (path.split(import_node_path3.sep).includes("node_modules")) return;
4419
- if (!/\.tilua$|tilua\.config\.jsonc?$|\.project\.json$/.test(path)) return;
4574
+ const path = (0, import_node_path3.resolve)(folder, name.toString());
4575
+ if ((0, import_node_path3.relative)(folder, path).split(/[\\/]/).includes("node_modules") || isInside(outDir, path) && mirrored) return;
4576
+ const read3 = /\.tilua$|tilua\.config\.jsonc?$|\.project\.json$/.test(path) || mirrored && isInside(rootDir, path);
4577
+ if (!read3) return;
4420
4578
  clearTimeout(timer);
4421
4579
  timer = setTimeout(() => void run(), 100);
4422
4580
  });
package/dist/cli.js CHANGED
@@ -3,11 +3,12 @@ import {
3
3
  WRITTEN_BY_TILUA,
4
4
  bundle,
5
5
  resolveConfig
6
- } from "./chunk-VUIF62OE.js";
6
+ } from "./chunk-3RJVN4KC.js";
7
7
 
8
8
  // src/cli.ts
9
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, watch, writeFileSync } from "fs";
10
- import { basename, dirname, join, relative, resolve, sep } from "path";
9
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync, rmSync, watch, writeFileSync } from "fs";
10
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "path";
11
+ import { stripJsonComments } from "@tilua/parser";
11
12
  var usage = "usage: tilua [<entry>] [--out <file>] [--output single|chunks|files] [--config <tilua.config.json>] [--noCheck] [--noLineMap] [--minify] [--watch]\n tilua init";
12
13
  var args = process.argv.slice(2);
13
14
  var entry;
@@ -46,46 +47,97 @@ for (let i = 0; i < args.length; i++) {
46
47
  } else entry = arg;
47
48
  }
48
49
  var shown = (path) => relative(process.cwd(), path) || ".";
50
+ var OUT = "out";
49
51
  function init() {
50
52
  const folder = process.cwd();
53
+ let existing;
51
54
  for (const name of ["tilua.config.json", "tilua.config.jsonc"]) {
52
- if (existsSync(join(folder, name))) {
55
+ const path = join(folder, name);
56
+ if (!existsSync(path)) continue;
57
+ let options2 = {};
58
+ try {
59
+ options2 = JSON.parse(stripJsonComments(readFileSync(path, "utf8")));
60
+ } catch (error) {
61
+ console.error(`${name}: ${error.message}`);
62
+ process.exit(1);
63
+ }
64
+ if (options2.output !== "files" || options2.outDir !== void 0 && options2.outDir !== options2.rootDir) {
53
65
  console.error(`${name} is already here`);
54
66
  process.exit(1);
55
67
  }
68
+ existing = { path, options: options2 };
56
69
  }
57
- let rootDir = "src";
58
70
  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);
71
+ if (!existsSync(project)) {
72
+ console.error("No default.project.json here: run `tilua init` in the folder of a Rojo project (`rojo init` makes one)");
73
+ process.exit(1);
74
+ }
75
+ const text = readFileSync(project, "utf8");
76
+ const paths = [];
77
+ const walk = (node) => {
78
+ if (!node || typeof node !== "object") return;
79
+ const path = node.$path;
80
+ const named = typeof path === "string" ? path : path?.optional;
81
+ if (typeof named === "string") paths.push(named);
82
+ for (const [key, child] of Object.entries(node)) if (!key.startsWith("$")) walk(child);
83
+ };
84
+ try {
85
+ walk(JSON.parse(text).tree);
86
+ } catch (error) {
87
+ console.error(`default.project.json: ${error.message}`);
88
+ process.exit(1);
89
+ }
90
+ const split = paths.map((path) => path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "").split("/"));
91
+ const shared = [];
92
+ for (let i = 0; split.length && split.every((parts) => parts.length > i && parts[i] === split[0][i]); i++) shared.push(split[0][i]);
93
+ if (split.length === 1 && /\.\w+$/.test(shared.at(-1) ?? "")) shared.pop();
94
+ const rootDir = shared.join("/");
95
+ if (!rootDir) {
96
+ console.error("The project's $paths share no folder to compile from: put the code under one (src), as `rojo init` does");
97
+ process.exit(1);
98
+ }
99
+ if (rootDir === OUT || rootDir.startsWith(`${OUT}/`)) {
100
+ console.error(`The project already reads from ${OUT}: set tilua.config.json up by hand`);
101
+ process.exit(1);
102
+ }
103
+ const out2 = join(folder, OUT);
104
+ if (existsSync(out2) && readdirSync(out2).length) {
105
+ console.error(`${OUT} is already here and not empty: the build would replace what is in it`);
106
+ process.exit(1);
107
+ }
108
+ const options = existing ? { ...existing.options, rootDir: existing.options.rootDir ?? rootDir, outDir: OUT } : { types: ["roblox"], output: "files", rootDir, outDir: OUT };
109
+ writeFileSync(existing?.path ?? join(folder, "tilua.config.json"), JSON.stringify(options, null, 4) + "\n");
110
+ console.log(`${basename(existing?.path ?? "tilua.config.json")}: ${String(options.rootDir)} compiled to ${OUT}`);
111
+ const escaped = rootDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
112
+ let changed = 0;
113
+ const pointed = text.replace(new RegExp(`("\\$path"\\s*:\\s*")(\\./)?${escaped}(?=/|")`, "g"), (_, head) => {
114
+ changed++;
115
+ return `${head}${OUT}`;
116
+ });
117
+ writeFileSync(project, pointed);
118
+ console.log(`default.project.json: ${changed} $path${changed === 1 ? "" : "s"} now read from ${OUT}`);
119
+ const ignore = join(folder, ".gitignore");
120
+ const ignored = existsSync(ignore) ? readFileSync(ignore, "utf8") : "";
121
+ if (!ignored.split(/\r?\n/).some((line) => [OUT, `/${OUT}`, `${OUT}/`, `/${OUT}/`].includes(line.trim()))) {
122
+ writeFileSync(ignore, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}
123
+ # What tilua builds from ${rootDir}
124
+ /${OUT}
125
+ `);
126
+ console.log(`.gitignore: /${OUT}`);
127
+ }
84
128
  console.log("Next: npm i -D @tilua/compiler @tilua-types/roblox, then run `npx tilua --watch` beside `rojo serve`.");
85
129
  process.exit(0);
86
130
  }
87
- function writtenByTilua(folder) {
88
- const found = [];
131
+ function isInside(folder, path) {
132
+ const below = relative(folder, path);
133
+ return below === "" || !below.startsWith("..") && !isAbsolute(below);
134
+ }
135
+ function filesUnder(folder) {
136
+ return under(folder).files;
137
+ }
138
+ function under(folder) {
139
+ const files = [];
140
+ const folders = [];
89
141
  const walk = (at) => {
90
142
  let items;
91
143
  try {
@@ -94,14 +146,27 @@ function writtenByTilua(folder) {
94
146
  return;
95
147
  }
96
148
  for (const item of items) {
97
- if (item.name.startsWith(".") || item.name === "node_modules") continue;
149
+ if (item.name === "node_modules" || item.name === ".git") continue;
98
150
  const path = join(at, item.name);
99
- if (item.isDirectory()) walk(path);
100
- else if (/\.luau?$/.test(item.name) && isTilua(path)) found.push(path);
151
+ if (item.isDirectory()) {
152
+ folders.push(path);
153
+ walk(path);
154
+ } else files.push(path);
101
155
  }
102
156
  };
103
157
  walk(folder);
104
- return found;
158
+ return { files, folders };
159
+ }
160
+ function removeEmpty(folder, keep) {
161
+ for (const item of readdirSync(folder, { withFileTypes: true })) {
162
+ if (!item.isDirectory()) continue;
163
+ const path = join(folder, item.name);
164
+ removeEmpty(path, keep);
165
+ if (!readdirSync(path).length && !keep.has(resolve(path))) rmdirSync(path);
166
+ }
167
+ }
168
+ function writtenByTilua(folder) {
169
+ return filesUnder(folder).filter((path) => /\.luau?$/.test(path) && isTilua(path));
105
170
  }
106
171
  function isTilua(path) {
107
172
  try {
@@ -121,6 +186,12 @@ async function build(from) {
121
186
  const perFile = mode === "files";
122
187
  const entryFile = perFile || from === void 0 ? void 0 : out ?? from.replace(/\.tilua$/, "") + ".luau";
123
188
  const folder = resolve(entryFile !== void 0 ? dirname(entryFile) : out ?? found?.outDir ?? process.cwd());
189
+ const rootDir = resolve(found?.rootDir ?? process.cwd());
190
+ const mirror = perFile && resolve(folder) !== rootDir;
191
+ if (mirror && (isInside(folder, rootDir) || isInside(rootDir, folder) || isInside(folder, found?.directory ?? process.cwd()))) {
192
+ console.error(`outDir (${shown(folder)}) has to be a folder of its own: not ${isInside(rootDir, folder) ? "under" : "around"} rootDir (${shown(rootDir)}), and not around the project`);
193
+ return false;
194
+ }
124
195
  const result = await bundle({
125
196
  entry: perFile ? void 0 : from,
126
197
  config,
@@ -139,6 +210,54 @@ async function build(from) {
139
210
  return false;
140
211
  }
141
212
  const targets = result.files.map((file) => ({ ...file, target: join(folder, file.path) }));
213
+ if (mirror) {
214
+ const compiled = new Map(targets.map((file) => [resolve(file.target), file]));
215
+ const copies = [];
216
+ let clash = false;
217
+ const leftovers = [];
218
+ for (const source of filesUnder(rootDir)) {
219
+ if (source.endsWith(".tilua")) continue;
220
+ if (/\.luau?$/.test(source) && isTilua(source)) {
221
+ leftovers.push(source);
222
+ continue;
223
+ }
224
+ const target = resolve(folder, relative(rootDir, source));
225
+ if (compiled.has(target)) {
226
+ console.error(`${shown(source)}: a .tilua compiles to the same file \u2014 rename or remove one of them`);
227
+ clash = true;
228
+ continue;
229
+ }
230
+ copies.push({ source, target });
231
+ }
232
+ if (clash) return false;
233
+ for (const leftover of leftovers) {
234
+ rmSync(leftover);
235
+ console.log(`${shown(leftover)}: removed \u2014 tilua compiled it beside its .tilua, and the output is in ${shown(folder)} now`);
236
+ }
237
+ for (const file of targets) {
238
+ if (existsSync(file.target) && readFileSync(file.target, "utf8") === file.code) continue;
239
+ mkdirSync(dirname(file.target), { recursive: true });
240
+ writeFileSync(file.target, file.code);
241
+ console.log(`${shown(file.target)}: ${file.modules.length} module${file.modules.length === 1 ? "" : "s"}`);
242
+ }
243
+ for (const { source, target } of copies) {
244
+ const bytes = readFileSync(source);
245
+ if (existsSync(target) && readFileSync(target).equals(bytes)) continue;
246
+ mkdirSync(dirname(target), { recursive: true });
247
+ copyFileSync(source, target);
248
+ console.log(`${shown(target)}: copied`);
249
+ }
250
+ const kept = /* @__PURE__ */ new Set([...compiled.keys(), ...copies.map((copy) => copy.target)]);
251
+ for (const stale of filesUnder(folder)) {
252
+ if (kept.has(resolve(stale))) continue;
253
+ rmSync(stale);
254
+ console.log(`${shown(stale)}: removed`);
255
+ }
256
+ const folders = /* @__PURE__ */ new Set([folder, ...under(rootDir).folders.map((path) => resolve(folder, relative(rootDir, path)))]);
257
+ for (const path of folders) mkdirSync(path, { recursive: true });
258
+ removeEmpty(folder, folders);
259
+ return !result.diagnostics.some((d) => d.severity !== "warning");
260
+ }
142
261
  if (perFile) {
143
262
  const theirs = targets.filter((file) => existsSync(file.target) && !isTilua(file.target));
144
263
  for (const file of theirs) {
@@ -165,6 +284,9 @@ async function build(from) {
165
284
  async function watchAndBuild(from) {
166
285
  const found = resolveConfig(config, resolve(from ?? "tilua.config.json")).config;
167
286
  const folder = found?.directory ?? (from !== void 0 ? dirname(resolve(from)) : process.cwd());
287
+ const rootDir = found?.rootDir;
288
+ const outDir = resolve(out ?? found?.outDir ?? folder);
289
+ const mirrored = (output ?? found?.output) === "files" && rootDir !== void 0 && outDir !== resolve(rootDir);
168
290
  let running = false;
169
291
  let again = false;
170
292
  let timer;
@@ -188,9 +310,10 @@ async function watchAndBuild(from) {
188
310
  await run();
189
311
  watch(folder, { recursive: true }, (_event, name) => {
190
312
  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;
313
+ const path = resolve(folder, name.toString());
314
+ if (relative(folder, path).split(/[\\/]/).includes("node_modules") || isInside(outDir, path) && mirrored) return;
315
+ const read = /\.tilua$|tilua\.config\.jsonc?$|\.project\.json$/.test(path) || mirrored && isInside(rootDir, path);
316
+ if (!read) return;
194
317
  clearTimeout(timer);
195
318
  timer = setTimeout(() => void run(), 100);
196
319
  });
package/dist/index.cjs CHANGED
@@ -4115,6 +4115,35 @@ function importedSpecifiers(program2) {
4115
4115
  return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
4116
4116
  }
4117
4117
  var libraryCache = /* @__PURE__ */ new Map();
4118
+ var treeCache;
4119
+ function instanceTree(config, libs, noLib) {
4120
+ const tree = (0, import_parser7.sourceMapOf)(config);
4121
+ if (!tree) return void 0;
4122
+ if ("problem" in tree) return tree.named ? { problem: { file: config.path, message: tree.problem } } : void 0;
4123
+ const declares = (name) => libs.some((lib) => lib.body.statements.some((s) => s.type === "DeclareStatement" && s.name === name));
4124
+ if (!tree.named && !declares("game")) return void 0;
4125
+ if (treeCache && treeCache.text === tree.text && treeCache.libs.length === libs.length && treeCache.libs.every((lib, i) => lib === libs[i])) {
4126
+ return { types: treeCache.types };
4127
+ }
4128
+ const empty = (0, import_parser7.parse)("");
4129
+ const aliases = (0, import_parser7.analyzeTypes)(empty, (0, import_parser7.analyzeScopes)(empty, { noLib }), { libs, noLib, diagnostics: false }).aliases;
4130
+ const membersOf = (className) => {
4131
+ const type = aliases.get(className);
4132
+ return new Set(type?.kind === "object" ? type.properties.keys() : ["Name", "ClassName", "Parent", "Archivable"]);
4133
+ };
4134
+ const { types, problem } = (0, import_parser7.sourceMapTypes)(tree.text, tree.path, { classes: new Set(aliases.keys()), membersOf });
4135
+ if (!types) return tree.named && problem ? { problem: { file: tree.path, message: problem } } : void 0;
4136
+ const scripts = /* @__PURE__ */ new Map();
4137
+ const cached = {
4138
+ program: types.program,
4139
+ scriptFor: (file) => {
4140
+ if (!scripts.has(file)) scripts.set(file, types.scriptFor(file));
4141
+ return scripts.get(file);
4142
+ }
4143
+ };
4144
+ treeCache = { text: tree.text, libs: [...libs], types: cached, scripts };
4145
+ return { types: cached };
4146
+ }
4118
4147
  function parsedLibrary(file) {
4119
4148
  let stamp;
4120
4149
  try {
@@ -4138,6 +4167,10 @@ function analyzeModules(modules, config) {
4138
4167
  const libs = libraries.files.map(parsedLibrary);
4139
4168
  const noLib = config?.noLib ?? false;
4140
4169
  const checked = libs.length > 0 || !noLib;
4170
+ const tree = config ? instanceTree(config, libs, noLib) : void 0;
4171
+ if (tree?.problem) out.push({ file: tree.problem.file, message: tree.problem.message, line: 1, column: 1, category: "config" });
4172
+ if (tree?.types) libs.push(tree.types.program);
4173
+ const scriptOf = (file) => tree?.types && config ? tree.types.scriptFor((0, import_parser7.outputPathOf)(config, file)) : void 0;
4141
4174
  const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
4142
4175
  const byFile = new Map(modules.map((m) => [m.file, m]));
4143
4176
  const exportsCache = /* @__PURE__ */ new Map();
@@ -4150,7 +4183,9 @@ function analyzeModules(modules, config) {
4150
4183
  const done = analyzed.get(file);
4151
4184
  if (done) return done;
4152
4185
  const remembered = moduleAnalyses.get(file);
4153
- if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4186
+ const script = scriptOf(file);
4187
+ const ownLibs = script ? [...libs, script] : libs;
4188
+ if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
4154
4189
  analyzed.set(file, remembered.result);
4155
4190
  readWhile.set(file, remembered.read);
4156
4191
  return remembered.result;
@@ -4163,7 +4198,7 @@ function analyzeModules(modules, config) {
4163
4198
  }
4164
4199
  const before = partials;
4165
4200
  const types = (0, import_parser7.analyzeTypes)(program2, scopes, {
4166
- libs,
4201
+ libs: ownLibs,
4167
4202
  resolveModule: resolverFor(file),
4168
4203
  noLib,
4169
4204
  reportUnknownTypes: checked
@@ -4180,7 +4215,7 @@ function analyzeModules(modules, config) {
4180
4215
  if (own !== void 0) read3.set(file, own);
4181
4216
  readWhile.set(file, read3);
4182
4217
  if ([...read3.values()].every((stamp) => stamp !== void 0)) {
4183
- moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read: read3, result: result2 });
4218
+ moduleAnalyses.set(file, { setting: settingFor, libs: [...ownLibs], program: program2, read: read3, result: result2 });
4184
4219
  }
4185
4220
  }
4186
4221
  return result2;
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  program,
9
9
  resolveConfig,
10
10
  syntaxOf
11
- } from "./chunk-VUIF62OE.js";
11
+ } from "./chunk-3RJVN4KC.js";
12
12
 
13
13
  // src/compile.ts
14
14
  import { readFileSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua/compiler",
3
- "version": "9.0.0",
3
+ "version": "9.0.1",
4
4
  "description": "Compiles tilua to Luau: lowers the @tilua/parser AST to a luau-parser AST and prints it",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -37,7 +37,7 @@
37
37
  "license": "ISC",
38
38
  "type": "module",
39
39
  "dependencies": {
40
- "@tilua/parser": "^9.0.0",
40
+ "@tilua/parser": "^9.0.1",
41
41
  "luau-parser": "^1.1.0"
42
42
  },
43
43
  "devDependencies": {