nanos-lint 2.2.1 → 2.3.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-Dx-1zSOk.js → cli-DnmSA08r.js} +137 -39
- package/dist/cli-DnmSA08r.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/templates/.luarc.json +6 -0
- package/dist/cli-Dx-1zSOk.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { fileURLToPath } from "node:url";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import os from "node:os";
|
|
5
|
-
import childProcess, { execFile } from "node:child_process";
|
|
5
|
+
import childProcess, { execFile, execFileSync } from "node:child_process";
|
|
6
6
|
import { promisify, stripVTControlCharacters } from "node:util";
|
|
7
7
|
import { EventEmitter } from "node:events";
|
|
8
8
|
import process$1 from "node:process";
|
|
@@ -161,6 +161,7 @@ function mergeConfigs(base, override = {}, definitionsDir = getDefinitionsDir(),
|
|
|
161
161
|
const defaultIgnore = [
|
|
162
162
|
".git",
|
|
163
163
|
".vscode",
|
|
164
|
+
".nanos-lint",
|
|
164
165
|
"node_modules",
|
|
165
166
|
"dist",
|
|
166
167
|
"bin",
|
|
@@ -290,12 +291,18 @@ function initWorkspace(workspacePath, options) {
|
|
|
290
291
|
const template = loadConfigFile(getDefaultTemplatePath());
|
|
291
292
|
const definitionsDir = getDefinitionsDir();
|
|
292
293
|
const sourceAnnotations = path.join(definitionsDir, "annotations.lua");
|
|
294
|
+
if (!fs.existsSync(sourceAnnotations)) throw new Error(`Definitions file not found at ${sourceAnnotations}. Make sure submodules are initialized.`);
|
|
293
295
|
const targetNanosDir = path.join(workspacePath, ".nanos-lint");
|
|
294
296
|
fs.mkdirSync(targetNanosDir, { recursive: true });
|
|
295
297
|
const targetAnnotations = path.join(targetNanosDir, "annotations.lua");
|
|
296
|
-
|
|
298
|
+
fs.copyFileSync(sourceAnnotations, targetAnnotations);
|
|
297
299
|
template.workspace = template.workspace ?? {};
|
|
298
300
|
template.workspace.library = [".nanos-lint/annotations.lua"];
|
|
301
|
+
const existingIgnore = template.workspace.ignoreDir ?? [];
|
|
302
|
+
if (!existingIgnore.includes(".nanos-lint")) template.workspace.ignoreDir = [".nanos-lint", ...existingIgnore];
|
|
303
|
+
template.files = template.files ?? {};
|
|
304
|
+
const existingExclude = template.files.exclude ?? [];
|
|
305
|
+
if (!existingExclude.includes(".nanos-lint/**")) template.files.exclude = [".nanos-lint/**", ...existingExclude];
|
|
299
306
|
fs.writeFileSync(targetFile, JSON.stringify(template, null, 2), "utf-8");
|
|
300
307
|
return targetFile;
|
|
301
308
|
}
|
|
@@ -374,15 +381,50 @@ function getCacheDir(version = FALLBACK_LUALS_VERSION) {
|
|
|
374
381
|
const base = process.platform === "win32" ? process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local") : process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache");
|
|
375
382
|
return path.join(base, "nanos-lint", "luals", version);
|
|
376
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Verifies that a LuaLS binary exists, has non-trivial size, and is executable.
|
|
386
|
+
*/
|
|
387
|
+
function isBinaryValid(binaryPath) {
|
|
388
|
+
if (!fs.existsSync(binaryPath)) return false;
|
|
389
|
+
try {
|
|
390
|
+
const stats = fs.statSync(binaryPath);
|
|
391
|
+
if (!stats.isFile() || stats.size < 1e5) return false;
|
|
392
|
+
const output = execFileSync(binaryPath, ["--version"], {
|
|
393
|
+
timeout: 5e3,
|
|
394
|
+
stdio: "pipe",
|
|
395
|
+
encoding: "utf-8"
|
|
396
|
+
});
|
|
397
|
+
return /^\d+\.\d+\.\d+/.test(output.trim());
|
|
398
|
+
} catch {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
377
402
|
async function downloadAndExtractLuaLS(version = DEFAULT_LUALS_VERSION, targetDir, options) {
|
|
378
403
|
const resolvedVersion = await resolveLuaLSVersion(version);
|
|
379
404
|
const info = getPlatformInfo(resolvedVersion);
|
|
380
405
|
const destDir = targetDir || getCacheDir(resolvedVersion);
|
|
381
406
|
const binaryPath = path.join(destDir, info.binaryRelativePath);
|
|
382
|
-
|
|
383
|
-
fs.
|
|
407
|
+
const completeMarker = path.join(destDir, ".complete");
|
|
408
|
+
if (fs.existsSync(destDir)) {
|
|
409
|
+
if (fs.existsSync(binaryPath) && isBinaryValid(binaryPath)) {
|
|
410
|
+
if (!fs.existsSync(completeMarker)) try {
|
|
411
|
+
fs.writeFileSync(completeMarker, resolvedVersion, "utf-8");
|
|
412
|
+
} catch {}
|
|
413
|
+
return binaryPath;
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
fs.rmSync(destDir, {
|
|
417
|
+
recursive: true,
|
|
418
|
+
force: true
|
|
419
|
+
});
|
|
420
|
+
} catch {}
|
|
421
|
+
}
|
|
422
|
+
const parentDir = path.dirname(destDir);
|
|
423
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
424
|
+
const tempDir = path.join(parentDir, `.${path.basename(destDir)}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
425
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
384
426
|
const url = `https://github.com/LuaLS/lua-language-server/releases/download/${resolvedVersion}/${info.assetName}`;
|
|
385
|
-
const archivePath = path.join(
|
|
427
|
+
const archivePath = path.join(tempDir, info.assetName);
|
|
386
428
|
if (!options?.quiet) console.log(`[luals] Downloading LuaLS ${resolvedVersion} from ${url}...`);
|
|
387
429
|
let response = null;
|
|
388
430
|
let lastErr = null;
|
|
@@ -393,54 +435,108 @@ async function downloadAndExtractLuaLS(version = DEFAULT_LUALS_VERSION, targetDi
|
|
|
393
435
|
response = res;
|
|
394
436
|
break;
|
|
395
437
|
}
|
|
438
|
+
await res.body?.cancel();
|
|
396
439
|
lastErr = /* @__PURE__ */ new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
397
440
|
} catch (err) {
|
|
398
441
|
lastErr = err;
|
|
399
442
|
}
|
|
400
443
|
if (attempt < 3) await new Promise((resolve) => setTimeout(resolve, attempt * 1e3));
|
|
401
444
|
}
|
|
402
|
-
if (!response || !response.body)
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"-C",
|
|
411
|
-
destDir
|
|
412
|
-
]);
|
|
413
|
-
} catch (tarErr) {
|
|
414
|
-
if (process.platform === "win32" && info.assetName.endsWith(".zip")) await execFileAsync("powershell.exe", [
|
|
415
|
-
"-NoProfile",
|
|
416
|
-
"-Command",
|
|
417
|
-
`Expand-Archive -Path '${escapePowerShellSingleQuote(archivePath)}' -DestinationPath '${escapePowerShellSingleQuote(destDir)}' -Force`
|
|
418
|
-
]);
|
|
419
|
-
else throw tarErr;
|
|
445
|
+
if (!response || !response.body) {
|
|
446
|
+
try {
|
|
447
|
+
fs.rmSync(tempDir, {
|
|
448
|
+
recursive: true,
|
|
449
|
+
force: true
|
|
450
|
+
});
|
|
451
|
+
} catch {}
|
|
452
|
+
throw lastErr || /* @__PURE__ */ new Error(`Failed to download ${url}`);
|
|
420
453
|
}
|
|
421
454
|
try {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
455
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
456
|
+
fs.writeFileSync(archivePath, Buffer.from(arrayBuffer));
|
|
457
|
+
if (!options?.quiet) console.log(`[luals] Extracting to ${destDir}...`);
|
|
458
|
+
try {
|
|
459
|
+
await execFileAsync("tar", [
|
|
460
|
+
"-xf",
|
|
461
|
+
archivePath,
|
|
462
|
+
"-C",
|
|
463
|
+
tempDir
|
|
464
|
+
]);
|
|
465
|
+
} catch (tarErr) {
|
|
466
|
+
if (process.platform === "win32" && info.assetName.endsWith(".zip")) await execFileAsync("powershell.exe", [
|
|
467
|
+
"-NoProfile",
|
|
468
|
+
"-Command",
|
|
469
|
+
`Expand-Archive -Path '${escapePowerShellSingleQuote(archivePath)}' -DestinationPath '${escapePowerShellSingleQuote(tempDir)}' -Force`
|
|
470
|
+
]);
|
|
471
|
+
else throw tarErr;
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
fs.unlinkSync(archivePath);
|
|
475
|
+
} catch {}
|
|
476
|
+
const tempBinaryPath = path.join(tempDir, info.binaryRelativePath);
|
|
477
|
+
if (process.platform !== "win32") try {
|
|
478
|
+
fs.chmodSync(tempBinaryPath, 493);
|
|
479
|
+
} catch {}
|
|
480
|
+
if (!fs.existsSync(tempBinaryPath) || fs.statSync(tempBinaryPath).size < 1e5) throw new Error(`Failed to extract valid LuaLS binary to expected path: ${tempBinaryPath}`);
|
|
481
|
+
fs.writeFileSync(path.join(tempDir, ".complete"), resolvedVersion, "utf-8");
|
|
482
|
+
for (let attempt = 0; attempt < 5; attempt++) try {
|
|
483
|
+
fs.renameSync(tempDir, destDir);
|
|
484
|
+
break;
|
|
485
|
+
} catch (renameErr) {
|
|
486
|
+
if (fs.existsSync(binaryPath) && isBinaryValid(binaryPath)) {
|
|
487
|
+
try {
|
|
488
|
+
fs.rmSync(tempDir, {
|
|
489
|
+
recursive: true,
|
|
490
|
+
force: true
|
|
491
|
+
});
|
|
492
|
+
} catch {}
|
|
493
|
+
if (!options?.quiet) console.log(`[luals] Ready: ${binaryPath}`);
|
|
494
|
+
return binaryPath;
|
|
495
|
+
}
|
|
496
|
+
if (attempt < 4) await new Promise((resolve) => setTimeout(resolve, 100 * (attempt + 1)));
|
|
497
|
+
else throw renameErr;
|
|
498
|
+
}
|
|
499
|
+
if (!isBinaryValid(binaryPath)) throw new Error(`Extracted LuaLS binary at ${binaryPath} is invalid or non-functional.`);
|
|
500
|
+
if (!options?.quiet) console.log(`[luals] Ready: ${binaryPath}`);
|
|
501
|
+
return binaryPath;
|
|
502
|
+
} finally {
|
|
503
|
+
if (fs.existsSync(tempDir)) try {
|
|
504
|
+
fs.rmSync(tempDir, {
|
|
505
|
+
recursive: true,
|
|
506
|
+
force: true
|
|
507
|
+
});
|
|
508
|
+
} catch {}
|
|
509
|
+
}
|
|
430
510
|
}
|
|
431
511
|
async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
|
|
432
512
|
if (process.env.LUALS_BIN && fs.existsSync(process.env.LUALS_BIN)) return process.env.LUALS_BIN;
|
|
433
513
|
const resolvedVersion = await resolveLuaLSVersion(version);
|
|
434
514
|
const info = getPlatformInfo(resolvedVersion);
|
|
435
515
|
const bundledPath = path.join(getPackageRoot(), info.binaryRelativePath);
|
|
436
|
-
if (fs.existsSync(bundledPath)) return bundledPath;
|
|
437
|
-
const
|
|
438
|
-
|
|
516
|
+
if (fs.existsSync(bundledPath) && isBinaryValid(bundledPath)) return bundledPath;
|
|
517
|
+
const cachedDir = getCacheDir(resolvedVersion);
|
|
518
|
+
const cachedPath = path.join(cachedDir, info.binaryRelativePath);
|
|
519
|
+
const completeMarker = path.join(cachedDir, ".complete");
|
|
520
|
+
if (fs.existsSync(cachedPath)) {
|
|
521
|
+
if (isBinaryValid(cachedPath)) {
|
|
522
|
+
if (!fs.existsSync(completeMarker)) try {
|
|
523
|
+
fs.writeFileSync(completeMarker, resolvedVersion, "utf-8");
|
|
524
|
+
} catch {}
|
|
525
|
+
return cachedPath;
|
|
526
|
+
}
|
|
527
|
+
if (!options?.quiet) console.warn(`[luals] Cached LuaLS binary at ${cachedPath} is corrupted or incomplete. Repairing...`);
|
|
528
|
+
try {
|
|
529
|
+
fs.rmSync(cachedDir, {
|
|
530
|
+
recursive: true,
|
|
531
|
+
force: true
|
|
532
|
+
});
|
|
533
|
+
} catch {}
|
|
534
|
+
}
|
|
439
535
|
try {
|
|
440
536
|
const cmd = process.platform === "win32" ? "where.exe" : "which";
|
|
441
537
|
const { stdout } = await execFileAsync(cmd, ["lua-language-server"]);
|
|
442
538
|
const found = stdout.trim().split(/\r?\n/)[0];
|
|
443
|
-
if (found && fs.existsSync(found)) return found;
|
|
539
|
+
if (found && fs.existsSync(found) && isBinaryValid(found)) return found;
|
|
444
540
|
} catch {}
|
|
445
541
|
return await downloadAndExtractLuaLS(resolvedVersion, void 0, options);
|
|
446
542
|
}
|
|
@@ -485,8 +581,9 @@ async function runLuaLSCheck(targetPath, configPath, options) {
|
|
|
485
581
|
} catch {}
|
|
486
582
|
}
|
|
487
583
|
if (!parseSucceeded) {
|
|
488
|
-
|
|
489
|
-
throw new Error(`LuaLS check failed to produce diagnostic output
|
|
584
|
+
const cacheHint = `(Cache location: ${getCacheDir()})`;
|
|
585
|
+
if (execError) throw new Error(`LuaLS check failed to execute or produce diagnostic output: ${execError instanceof Error ? execError.message : String(execError)}. ${cacheHint}`);
|
|
586
|
+
throw new Error(`LuaLS check failed to produce diagnostic output at: ${checkOutPath}. ${cacheHint}`);
|
|
490
587
|
}
|
|
491
588
|
if (targetFileOnly) {
|
|
492
589
|
const filtered = {};
|
|
@@ -529,6 +626,7 @@ function countCheckedFiles(targetPath, configPath) {
|
|
|
529
626
|
let ignoreDirs = [
|
|
530
627
|
".git",
|
|
531
628
|
".vscode",
|
|
629
|
+
".nanos-lint",
|
|
532
630
|
"node_modules"
|
|
533
631
|
];
|
|
534
632
|
let excludePatterns = [];
|
|
@@ -3832,6 +3930,6 @@ if (isDirectExecution()) runCLI().then((code) => {
|
|
|
3832
3930
|
process.exit(1);
|
|
3833
3931
|
});
|
|
3834
3932
|
//#endregion
|
|
3835
|
-
export {
|
|
3933
|
+
export { mergeConfigs as A, resolveLuaLSVersion as C, getPackageRoot as D, getDefinitionsDir as E, resolveWorkspaceConfig as M, stripJsonComments as N, initWorkspace as O, fileUriToPath as P, resolveLuaLSBinary as S, getDefaultTemplatePath as T, escapePowerShellSingleQuote as _, formatGitHubAnnotations as a, isBinaryValid as b, formatReport as c, pluralize as d, shouldEnableColor as f, downloadAndExtractLuaLS as g, countCheckedFiles as h, runCLI as i, parseJsonc as j, loadConfigFile as k, formatSeverityBadge as l, FALLBACK_LUALS_VERSION as m, createProgram as n, formatPretty as o, DEFAULT_LUALS_VERSION as p, isDirectExecution as r, formatProblemSummary as s, collectIgnorePatterns as t, getColors as u, getCacheDir as v, runLuaLSCheck as w, resolveLatestLuaLSVersion as x, getPlatformInfo as y };
|
|
3836
3934
|
|
|
3837
|
-
//# sourceMappingURL=cli-
|
|
3935
|
+
//# sourceMappingURL=cli-DnmSA08r.js.map
|