nanos-lint 3.2.0 → 3.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/README.md +25 -5
- package/action.yml +1 -1
- package/dist/{cli-CeNxOiST.js → cli-CsIAHyRZ.js} +145 -85
- package/dist/cli-CsIAHyRZ.js.map +1 -0
- package/dist/cli-dxsaVVVq.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/dist/cli-CeNxOiST.js.map +0 -1
package/README.md
CHANGED
|
@@ -134,7 +134,8 @@ nanos-lint [command] [options] [paths...]
|
|
|
134
134
|
|
|
135
135
|
COMMANDS:
|
|
136
136
|
check [paths...] Check workspace files or directories (default)
|
|
137
|
-
init [path] Scaffold a .luarc.json configuration in the workspace (
|
|
137
|
+
init [path] Scaffold a .luarc.json configuration in the workspace (supports --vendor, --force)
|
|
138
|
+
copy-annotations [dest] Copy cached annotations.lua definitions into a target file or directory (alias: export-annotations; targets not ending in .lua are treated as directories)
|
|
138
139
|
warmup, download Pre-fetch and cache both LuaLS binary and annotations for offline execution
|
|
139
140
|
cache status, cache info Show cache status, installed versions, and disk usage (supports --json)
|
|
140
141
|
cache clean Clear the nanos-lint cache directory
|
|
@@ -153,14 +154,15 @@ OPTIONS:
|
|
|
153
154
|
debug adds diagnostic tracing
|
|
154
155
|
--checklevel=<level> Minimum diagnostic level: Error, Warning, Information, Hint (default: Warning)
|
|
155
156
|
--config=<path> Path to custom .luarc.json configuration file
|
|
156
|
-
--annotations=<path> Path to custom annotations.lua file (applies to
|
|
157
|
+
--annotations=<path> Path to custom annotations.lua file (applies to check, init --vendor, and copy-annotations)
|
|
157
158
|
--format=<format> Output format: pretty, json, github (default: pretty)
|
|
158
159
|
--github Output in GitHub Actions format (shortcut for --format=github)
|
|
159
160
|
--luals-version=<ver> Version of LuaLS to use (default: latest, falling back to 3.19.1 when offline)
|
|
160
161
|
--no-fail Do not exit with code 1 if diagnostics are found
|
|
161
162
|
--realm <realm> Execution realm to check: all, client, server, shared (default: all)
|
|
162
163
|
--no-progress Disable the interactive download, extraction and realm derivation progress display
|
|
163
|
-
|
|
164
|
+
--vendor (init command only) Vendor annotations.lua into .nanos-lint/ inside workspace
|
|
165
|
+
-f, --force (init and copy-annotations only) Overwrite existing files
|
|
164
166
|
```
|
|
165
167
|
|
|
166
168
|
### Progress Display
|
|
@@ -223,7 +225,7 @@ If your project already has a `.luarc.json`, `nanos-lint` automatically merges i
|
|
|
223
225
|
}
|
|
224
226
|
```
|
|
225
227
|
|
|
226
|
-
To scaffold a
|
|
228
|
+
To scaffold a `.luarc.json` configuration in your project:
|
|
227
229
|
|
|
228
230
|
```bash
|
|
229
231
|
npx nanos-lint init
|
|
@@ -231,6 +233,24 @@ npx nanos-lint init
|
|
|
231
233
|
npx nanos-lint init --force
|
|
232
234
|
```
|
|
233
235
|
|
|
236
|
+
By default `init` writes no annotations reference at all: `workspace.library` stays empty and
|
|
237
|
+
`nanos-lint check` injects the managed cache path into its own temporary merged configuration at
|
|
238
|
+
runtime, so a later cache update is picked up without touching repository files. Editors that read
|
|
239
|
+
`.luarc.json` directly need a pinned copy, which is always an explicit opt-in:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Initialize with annotations vendored into .nanos-lint/ and pinned in workspace.library
|
|
243
|
+
npx nanos-lint init --vendor
|
|
244
|
+
|
|
245
|
+
# Or copy the cached annotations to a custom file, or to any target that does not end in
|
|
246
|
+
# ".lua" (treated as a directory). Copying alone does not pin anything: add the resulting
|
|
247
|
+
# path to workspace.library yourself.
|
|
248
|
+
npx nanos-lint copy-annotations
|
|
249
|
+
npx nanos-lint copy-annotations ./types
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`copy-annotations` refuses to overwrite an existing file unless `--force` is passed.
|
|
253
|
+
|
|
234
254
|
### Realm Mapping (`nanos.realms`)
|
|
235
255
|
|
|
236
256
|
nanos world runs two isolated Lua VMs: the server executes `Server/**` + `Shared/**`, the client executes `Client/**` + `Shared/**`. `nanos-lint` mirrors that split and lets you describe a non-standard layout in `.luarc.json`:
|
|
@@ -369,7 +389,7 @@ npm run check:all
|
|
|
369
389
|
npm run format:check # Prettier code formatting (auto-fix via npm run format:fix)
|
|
370
390
|
npm run lint # ESLint
|
|
371
391
|
npm run lint:deps # Dependency architecture & license checks (dependency-cruiser)
|
|
372
|
-
npm run lint:comments # Comment density limit (<=
|
|
392
|
+
npm run lint:comments # Comment density limit (<= 10%)
|
|
373
393
|
npm run lint:docstrings # Docstring coverage (>= 90% top-level/exported function coverage per file in src/)
|
|
374
394
|
npm run typecheck # TypeScript typecheck
|
|
375
395
|
npm run build # Build distribution bundle
|
package/action.yml
CHANGED
|
@@ -1464,20 +1464,23 @@ function resolveRealmMappings(userConfig) {
|
|
|
1464
1464
|
function initWorkspace(workspacePath, options) {
|
|
1465
1465
|
const targetFile = path.join(workspacePath, ".luarc.json");
|
|
1466
1466
|
if (fs.existsSync(targetFile) && !options?.force) throw new ConfigError(`.luarc.json already exists at ${targetFile}. Use --force to overwrite.`, "ERR_CONFIG_EXISTS", "Pass --force to overwrite the existing .luarc.json file.");
|
|
1467
|
+
if (options?.annotationsPath && !options.vendor) throw new ConfigError("--annotations requires --vendor: nanos-lint init does not pin or vendor annotations.lua by default.", "ERR_ANNOTATIONS_WITHOUT_VENDOR", "Run 'nanos-lint init --vendor --annotations <path>' (or pass vendor: true), or omit the custom path to use the managed annotations cache.");
|
|
1467
1468
|
const template = loadConfigFile(getDefaultTemplatePath());
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1469
|
+
if (options?.vendor) {
|
|
1470
|
+
const sourceAnnotations = options.annotationsPath || getDefaultAnnotationsPath();
|
|
1471
|
+
if (!fs.existsSync(sourceAnnotations)) throw new ConfigError(`Definitions file not found at ${sourceAnnotations}. Make sure annotations have been downloaded or pass a valid file with --annotations.`, "ERR_ANNOTATIONS_NOT_FOUND", "Run 'nanos-lint warmup' to download annotations or provide --annotations <path>.");
|
|
1472
|
+
const targetNanosDir = path.join(workspacePath, ".nanos-lint");
|
|
1473
|
+
fs.mkdirSync(targetNanosDir, { recursive: true });
|
|
1474
|
+
const targetAnnotations = path.join(targetNanosDir, "annotations.lua");
|
|
1475
|
+
fs.copyFileSync(sourceAnnotations, targetAnnotations);
|
|
1476
|
+
template.workspace = template.workspace ?? {};
|
|
1477
|
+
template.workspace.library = [".nanos-lint/annotations.lua"];
|
|
1478
|
+
const existingIgnore = template.workspace.ignoreDir ?? [];
|
|
1479
|
+
if (!existingIgnore.includes(".nanos-lint")) template.workspace.ignoreDir = [".nanos-lint", ...existingIgnore];
|
|
1480
|
+
template.files = template.files ?? {};
|
|
1481
|
+
const existingExclude = template.files.exclude ?? [];
|
|
1482
|
+
if (!existingExclude.includes(".nanos-lint/**")) template.files.exclude = [".nanos-lint/**", ...existingExclude];
|
|
1483
|
+
}
|
|
1481
1484
|
fs.writeFileSync(targetFile, JSON.stringify(template, null, 2), "utf-8");
|
|
1482
1485
|
return targetFile;
|
|
1483
1486
|
}
|
|
@@ -6368,6 +6371,13 @@ async function validateArchiveMembers(archivePath) {
|
|
|
6368
6371
|
* user-supplied `LUALS_BIN` may legitimately be a small wrapper script.
|
|
6369
6372
|
*/
|
|
6370
6373
|
const MIN_DOWNLOADED_BINARY_SIZE_BYTES = 1e5;
|
|
6374
|
+
/** Propagates blocked LuaLS execution or cache access without triggering repair. */
|
|
6375
|
+
function rethrowLuaLSPermissionError(err, targetPath, operation = "access") {
|
|
6376
|
+
if (err instanceof LuaLSError && (err.code === "ERR_LUALS_EXECUTION_DENIED" || err.code === "ERR_LUALS_CACHE_PERMISSION")) throw err;
|
|
6377
|
+
const code = err?.code;
|
|
6378
|
+
if (code !== "EPERM" && code !== "EACCES") return;
|
|
6379
|
+
throw new LuaLSError(`Cannot ${operation} LuaLS ${operation === "execute" ? "binary" : "cache path"} '${targetPath}': ${code}: ${err instanceof Error ? err.message : String(err)}`, operation === "execute" ? "ERR_LUALS_EXECUTION_DENIED" : "ERR_LUALS_CACHE_PERMISSION", operation === "execute" ? "Run nanos-lint in an environment that permits LuaLS execution and check the binary's execute permissions and sandbox policy. The existing cache has been preserved." : "Allow access to the LuaLS cache directory or use a writable cache directory.", { cause: err });
|
|
6380
|
+
}
|
|
6371
6381
|
/**
|
|
6372
6382
|
* Runs `binaryPath --version` and checks that it reports a LuaLS version.
|
|
6373
6383
|
* Shared by every binary validation path; the size heuristic stays separate
|
|
@@ -6382,6 +6392,7 @@ function reportsLuaLSVersion(binaryPath) {
|
|
|
6382
6392
|
});
|
|
6383
6393
|
return /^\d+\.\d+\.\d+/.test(output.trim());
|
|
6384
6394
|
} catch (err) {
|
|
6395
|
+
rethrowLuaLSPermissionError(err, binaryPath, "execute");
|
|
6385
6396
|
logger.debug(`[luals] Binary validation check failed for ${binaryPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6386
6397
|
return false;
|
|
6387
6398
|
}
|
|
@@ -6397,6 +6408,7 @@ function isBinaryValid(binaryPath) {
|
|
|
6397
6408
|
if (!stats.isFile() || stats.size < 1e5) return false;
|
|
6398
6409
|
return reportsLuaLSVersion(binaryPath);
|
|
6399
6410
|
} catch (err) {
|
|
6411
|
+
rethrowLuaLSPermissionError(err, binaryPath);
|
|
6400
6412
|
logger.debug(`[luals] Binary validation check failed for ${binaryPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6401
6413
|
return false;
|
|
6402
6414
|
}
|
|
@@ -6410,6 +6422,7 @@ function isBinaryRunnable(binaryPath) {
|
|
|
6410
6422
|
try {
|
|
6411
6423
|
if (!fs.statSync(binaryPath).isFile()) return false;
|
|
6412
6424
|
} catch (err) {
|
|
6425
|
+
rethrowLuaLSPermissionError(err, binaryPath);
|
|
6413
6426
|
logger.debug(`[luals] Binary validation check failed for ${binaryPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6414
6427
|
return false;
|
|
6415
6428
|
}
|
|
@@ -6434,6 +6447,7 @@ function assertValidLuaLSBinary(binaryPath, source) {
|
|
|
6434
6447
|
try {
|
|
6435
6448
|
stats = fs.statSync(binaryPath);
|
|
6436
6449
|
} catch (err) {
|
|
6450
|
+
rethrowLuaLSPermissionError(err, binaryPath);
|
|
6437
6451
|
throw new LuaLSError(`${source} points to '${binaryPath}', which does not exist or cannot be read: ${err instanceof Error ? err.message : String(err)}`, "ERR_LUALS_BIN_INVALID", `Set ${source} to the full path of a lua-language-server executable, or leave it unset so nanos-lint resolves LuaLS automatically.`, { cause: err });
|
|
6438
6452
|
}
|
|
6439
6453
|
if (!stats.isFile()) throw new LuaLSError(`${source} points to '${binaryPath}', which is not a regular file (a directory or special file was found).`, "ERR_LUALS_BIN_INVALID", `Point ${source} at the lua-language-server executable itself, or leave it unset so nanos-lint resolves LuaLS automatically.`);
|
|
@@ -6550,11 +6564,13 @@ function listCachedLuaLSVersions(baseCacheDir = getBaseLuaLSCacheDir()) {
|
|
|
6550
6564
|
if (fs.existsSync(marker) && fs.existsSync(bin)) try {
|
|
6551
6565
|
if (fs.readFileSync(marker, "utf-8").trim() === version && isBinaryValid(bin)) versions.push(version);
|
|
6552
6566
|
} catch (err) {
|
|
6567
|
+
rethrowLuaLSPermissionError(err, bin);
|
|
6553
6568
|
logger.debug(`[luals] Error validating cached version ${version}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6554
6569
|
}
|
|
6555
6570
|
}
|
|
6556
6571
|
return versions;
|
|
6557
6572
|
} catch (err) {
|
|
6573
|
+
rethrowLuaLSPermissionError(err, baseCacheDir);
|
|
6558
6574
|
logger.debug(`[luals] Failed to list cached LuaLS versions: ${err instanceof Error ? err.message : String(err)}`);
|
|
6559
6575
|
return [];
|
|
6560
6576
|
}
|
|
@@ -6604,6 +6620,7 @@ function findExistingLuaLSDir(version, baseCacheDir = getBaseLuaLSCacheDir()) {
|
|
|
6604
6620
|
if (fs.existsSync(primaryMarker)) try {
|
|
6605
6621
|
if (fs.readFileSync(primaryMarker, "utf-8").trim() === version && isBinaryValid(primaryBin)) return primaryCache;
|
|
6606
6622
|
} catch (err) {
|
|
6623
|
+
rethrowLuaLSPermissionError(err, primaryMarker);
|
|
6607
6624
|
logger.debug(`[luals] Error checking primary LuaLS cache marker at ${primaryMarker}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6608
6625
|
}
|
|
6609
6626
|
const pkgRoot = getPackageRoot();
|
|
@@ -6664,6 +6681,7 @@ function isCompleteLuaLSInstall(binaryPath, completeMarker, version) {
|
|
|
6664
6681
|
try {
|
|
6665
6682
|
return fs.readFileSync(completeMarker, "utf-8").trim() === version && isBinaryValid(binaryPath);
|
|
6666
6683
|
} catch (err) {
|
|
6684
|
+
rethrowLuaLSPermissionError(err, completeMarker);
|
|
6667
6685
|
logger.debug(`[luals] Failed to read complete marker at ${completeMarker}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6668
6686
|
return false;
|
|
6669
6687
|
}
|
|
@@ -6694,6 +6712,7 @@ async function downloadAndPromoteLuaLS(resolvedVersion, info, destDir, binaryPat
|
|
|
6694
6712
|
if (options?.reuseExisting !== false && fs.existsSync(binaryPath) && fs.existsSync(completeMarker)) try {
|
|
6695
6713
|
if (fs.readFileSync(completeMarker, "utf-8").trim() === resolvedVersion && isBinaryValid(binaryPath)) return binaryPath;
|
|
6696
6714
|
} catch (err) {
|
|
6715
|
+
rethrowLuaLSPermissionError(err, completeMarker);
|
|
6697
6716
|
logger.debug(`[luals] Failed to read complete marker at ${completeMarker}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6698
6717
|
}
|
|
6699
6718
|
try {
|
|
@@ -6702,6 +6721,7 @@ async function downloadAndPromoteLuaLS(resolvedVersion, info, destDir, binaryPat
|
|
|
6702
6721
|
force: true
|
|
6703
6722
|
});
|
|
6704
6723
|
} catch (err) {
|
|
6724
|
+
rethrowLuaLSPermissionError(err, destDir);
|
|
6705
6725
|
logger.warn(`[luals] Failed to remove stale or invalid cache dir ${destDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
6706
6726
|
}
|
|
6707
6727
|
}
|
|
@@ -7310,6 +7330,7 @@ async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
|
|
|
7310
7330
|
if (options?.reuseExisting !== false) return cachedPath;
|
|
7311
7331
|
}
|
|
7312
7332
|
} catch (err) {
|
|
7333
|
+
rethrowLuaLSPermissionError(err, completeMarker);
|
|
7313
7334
|
logger.debug(`[luals] Failed to read complete marker at ${completeMarker}: ${err instanceof Error ? err.message : String(err)}`);
|
|
7314
7335
|
}
|
|
7315
7336
|
if (!isValid) {
|
|
@@ -7322,6 +7343,7 @@ async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
|
|
|
7322
7343
|
force: true
|
|
7323
7344
|
});
|
|
7324
7345
|
} catch (err) {
|
|
7346
|
+
rethrowLuaLSPermissionError(err, cachedDir);
|
|
7325
7347
|
logger.warn(`[luals] Failed to remove corrupted cache directory ${cachedDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
7326
7348
|
}
|
|
7327
7349
|
}
|
|
@@ -7331,11 +7353,13 @@ async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
|
|
|
7331
7353
|
const found = stdout.trim().split(/\r?\n/)[0];
|
|
7332
7354
|
if (found && fs.existsSync(found) && isBinaryValid(found)) return found;
|
|
7333
7355
|
} catch (err) {
|
|
7356
|
+
rethrowLuaLSPermissionError(err, "lua-language-server", "execute");
|
|
7334
7357
|
logger.debug(`[luals] LuaLS binary not found in PATH: ${err instanceof Error ? err.message : String(err)}`);
|
|
7335
7358
|
}
|
|
7336
7359
|
try {
|
|
7337
7360
|
return await downloadAndExtractLuaLS(resolvedVersion, getCacheDir(resolvedVersion, baseCacheDir), options);
|
|
7338
7361
|
} catch (err) {
|
|
7362
|
+
rethrowLuaLSPermissionError(err, cachedDir);
|
|
7339
7363
|
if (wasCorrupted) {
|
|
7340
7364
|
const isOffline = isOfflineError(err);
|
|
7341
7365
|
const reason = isOffline ? "while offline" : err instanceof Error ? err.message : String(err);
|
|
@@ -7397,12 +7421,14 @@ async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
|
|
|
7397
7421
|
const found = stdout.trim().split(/\r?\n/)[0];
|
|
7398
7422
|
if (found && fs.existsSync(found) && isBinaryValid(found)) return found;
|
|
7399
7423
|
} catch (err) {
|
|
7424
|
+
rethrowLuaLSPermissionError(err, "lua-language-server", "execute");
|
|
7400
7425
|
logger.debug(`[luals] LuaLS binary not found in PATH: ${err instanceof Error ? err.message : String(err)}`);
|
|
7401
7426
|
}
|
|
7402
7427
|
let downloadedBinary;
|
|
7403
7428
|
try {
|
|
7404
7429
|
downloadedBinary = await downloadAndExtractLuaLS(targetVersion, targetCacheDir, options);
|
|
7405
7430
|
} catch (err) {
|
|
7431
|
+
rethrowLuaLSPermissionError(err, targetCacheDir);
|
|
7406
7432
|
if (wasCorrupted) {
|
|
7407
7433
|
const isOffline = isOfflineError(err);
|
|
7408
7434
|
const reason = isOffline ? "while offline" : err instanceof Error ? err.message : String(err);
|
|
@@ -11338,6 +11364,22 @@ async function resolveAnnotations(options = {}) {
|
|
|
11338
11364
|
throw new AnnotationsError(`Failed to resolve nanos world API annotations. Please check your network connection or pass a custom file with --annotations. (${err instanceof Error ? err.message : String(err)})`, "ERR_ANNOTATIONS_NETWORK", "Check your network connection, run 'nanos-lint warmup' when online, or specify --annotations <path>.", { cause: err });
|
|
11339
11365
|
}
|
|
11340
11366
|
}
|
|
11367
|
+
const DEFAULT_COPY_TARGET = `.nanos-lint/${ANNOTATIONS_FILENAME}`;
|
|
11368
|
+
/**
|
|
11369
|
+
* Copies nanos world annotations.lua definitions into a target file or directory.
|
|
11370
|
+
* A target counts as a directory when it ends with a separator, already is a directory,
|
|
11371
|
+
* or does not end in `.lua` (case-insensitively).
|
|
11372
|
+
*/
|
|
11373
|
+
async function copyAnnotations(targetPath = DEFAULT_COPY_TARGET, options = {}) {
|
|
11374
|
+
let resolvedTarget = path.resolve(targetPath);
|
|
11375
|
+
if (targetPath.endsWith("/") || targetPath.endsWith("\\") || fs.existsSync(resolvedTarget) && fs.statSync(resolvedTarget).isDirectory() || path.extname(resolvedTarget).toLowerCase() !== ".lua") resolvedTarget = path.join(resolvedTarget, ANNOTATIONS_FILENAME);
|
|
11376
|
+
if (fs.existsSync(resolvedTarget) && !options.force) throw new AnnotationsError(`Target annotations file already exists: ${resolvedTarget}. Use --force to overwrite.`, "ERR_ANNOTATIONS_EXISTS", "Pass --force to overwrite the existing annotations file.");
|
|
11377
|
+
const sourcePath = options.annotationsPath ? validateCustomAnnotationsPath(options.annotationsPath, "custom") : await resolveAnnotations({ cacheDir: options.cacheDir });
|
|
11378
|
+
const targetDir = path.dirname(resolvedTarget);
|
|
11379
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
11380
|
+
fs.copyFileSync(sourcePath, resolvedTarget);
|
|
11381
|
+
return resolvedTarget;
|
|
11382
|
+
}
|
|
11341
11383
|
//#endregion
|
|
11342
11384
|
//#region src/cache-status.ts
|
|
11343
11385
|
/** Collects detailed status and disk usage information for LuaLS and annotations caches. */
|
|
@@ -11432,6 +11474,80 @@ function formatCacheStatusPretty(report) {
|
|
|
11432
11474
|
return lines.join("\n");
|
|
11433
11475
|
}
|
|
11434
11476
|
//#endregion
|
|
11477
|
+
//#region src/output.ts
|
|
11478
|
+
/** Writes command results to stdout unless the log level is `silent`. */
|
|
11479
|
+
function writeOutput(message) {
|
|
11480
|
+
if (logger.isOutputEnabled()) console.log(message);
|
|
11481
|
+
}
|
|
11482
|
+
//#endregion
|
|
11483
|
+
//#region src/cli-check.ts
|
|
11484
|
+
/** Executes the check command on target paths with specified options. */
|
|
11485
|
+
async function executeCheckCommand(targetPaths = ["."], opts, setExitCode) {
|
|
11486
|
+
if (opts.logLevel && isValidLogLevel(opts.logLevel)) logger.setLevel(opts.logLevel);
|
|
11487
|
+
const { rootPath, targetPaths: canonicalTargets } = resolveCheckTargets(targetPaths && targetPaths.length > 0 ? targetPaths : ["."]);
|
|
11488
|
+
const format = opts.github ? "github" : opts.format || (process.env.GITHUB_ACTIONS ? "github" : "pretty");
|
|
11489
|
+
if (format === "json") {
|
|
11490
|
+
setProgressMode("off");
|
|
11491
|
+
logger.setDiagnosticStream("stderr");
|
|
11492
|
+
}
|
|
11493
|
+
const checkOptions = {
|
|
11494
|
+
path: rootPath,
|
|
11495
|
+
paths: canonicalTargets,
|
|
11496
|
+
configpath: opts.config,
|
|
11497
|
+
checklevel: opts.checklevel,
|
|
11498
|
+
format,
|
|
11499
|
+
lualsVersion: opts.lualsVersion,
|
|
11500
|
+
failOnError: opts.fail !== false,
|
|
11501
|
+
ignore: opts.ignore,
|
|
11502
|
+
deps: opts.dep
|
|
11503
|
+
};
|
|
11504
|
+
if (opts.config) {
|
|
11505
|
+
const resolvedConfig = path.resolve(opts.config);
|
|
11506
|
+
if (!fs.existsSync(resolvedConfig)) throw new ConfigError(`Configuration file not found: ${resolvedConfig}`, "ERR_CONFIG_NOT_FOUND", "Verify the path passed to --config exists and is readable.");
|
|
11507
|
+
}
|
|
11508
|
+
const annotationsPath = await resolveAnnotations({ customPath: opts.annotations });
|
|
11509
|
+
const userConfig = loadUserConfig(rootPath, checkOptions.configpath);
|
|
11510
|
+
const realmPlan = planRealmCheck({
|
|
11511
|
+
targetPath: rootPath,
|
|
11512
|
+
userConfig,
|
|
11513
|
+
selection: opts.realm ?? "all",
|
|
11514
|
+
annotationsPath,
|
|
11515
|
+
customConfigPath: checkOptions.configpath,
|
|
11516
|
+
ignore: checkOptions.ignore,
|
|
11517
|
+
targetPaths: canonicalTargets,
|
|
11518
|
+
cliDeps: checkOptions.deps
|
|
11519
|
+
});
|
|
11520
|
+
let result;
|
|
11521
|
+
if (realmPlan) try {
|
|
11522
|
+
result = await runRealmAwareCheck(realmPlan, rootPath, checkOptions);
|
|
11523
|
+
} finally {
|
|
11524
|
+
realmPlan.cleanup();
|
|
11525
|
+
}
|
|
11526
|
+
else {
|
|
11527
|
+
const resolvedDeps = resolvePackageDependencies(rootPath, userConfig, checkOptions.deps);
|
|
11528
|
+
const unrequestedExclusions = computeUnrequestedExclusions(rootPath, canonicalTargets);
|
|
11529
|
+
const resolved = resolveWorkspaceConfig(rootPath, checkOptions.configpath, {
|
|
11530
|
+
ignore: checkOptions.ignore,
|
|
11531
|
+
annotationsPath,
|
|
11532
|
+
dependencyLibraries: resolvedDeps.all,
|
|
11533
|
+
unrequestedExclusions
|
|
11534
|
+
});
|
|
11535
|
+
try {
|
|
11536
|
+
result = await runLuaLSCheck(rootPath, resolved.configPath, checkOptions);
|
|
11537
|
+
} finally {
|
|
11538
|
+
if (resolved.isTemp && fs.existsSync(resolved.configPath)) try {
|
|
11539
|
+
fs.unlinkSync(resolved.configPath);
|
|
11540
|
+
} catch (err) {
|
|
11541
|
+
logger.warn(`Failed to clean up temporary config file ${resolved.configPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11542
|
+
}
|
|
11543
|
+
}
|
|
11544
|
+
}
|
|
11545
|
+
const output = formatReport(result, checkOptions.format, process.cwd());
|
|
11546
|
+
if (output) writeOutput(output);
|
|
11547
|
+
if (!result.passed && checkOptions.failOnError) setExitCode(1);
|
|
11548
|
+
else setExitCode(0);
|
|
11549
|
+
}
|
|
11550
|
+
//#endregion
|
|
11435
11551
|
//#region src/cli.ts
|
|
11436
11552
|
/** Retrieves the formatted package name and version string from package.json. */
|
|
11437
11553
|
function getVersionString() {
|
|
@@ -11443,10 +11559,6 @@ function getVersionString() {
|
|
|
11443
11559
|
return "nanos-lint v1.0.0";
|
|
11444
11560
|
}
|
|
11445
11561
|
}
|
|
11446
|
-
/** Writes command results to stdout unless the level is `silent`. */
|
|
11447
|
-
function writeOutput(message) {
|
|
11448
|
-
if (logger.isOutputEnabled()) console.log(message);
|
|
11449
|
-
}
|
|
11450
11562
|
/** Accumulates repeatable --ignore pattern arguments, splitting by comma and newline. */
|
|
11451
11563
|
function collectIgnorePatterns(val, prev) {
|
|
11452
11564
|
const parts = val.split(/[\r\n,]+/).map((s) => s.trim()).filter(Boolean);
|
|
@@ -11492,75 +11604,22 @@ function createProgram(options) {
|
|
|
11492
11604
|
"server",
|
|
11493
11605
|
"shared"
|
|
11494
11606
|
]).default("all")).action(async (targetPaths = ["."], opts) => {
|
|
11495
|
-
|
|
11496
|
-
const { rootPath, targetPaths: canonicalTargets } = resolveCheckTargets(targetPaths && targetPaths.length > 0 ? targetPaths : ["."]);
|
|
11497
|
-
const format = opts.github ? "github" : opts.format || (process.env.GITHUB_ACTIONS ? "github" : "pretty");
|
|
11498
|
-
if (format === "json") {
|
|
11499
|
-
setProgressMode("off");
|
|
11500
|
-
logger.setDiagnosticStream("stderr");
|
|
11501
|
-
}
|
|
11502
|
-
const checkOptions = {
|
|
11503
|
-
path: rootPath,
|
|
11504
|
-
paths: canonicalTargets,
|
|
11505
|
-
configpath: opts.config,
|
|
11506
|
-
checklevel: opts.checklevel,
|
|
11507
|
-
format,
|
|
11508
|
-
lualsVersion: opts.lualsVersion,
|
|
11509
|
-
failOnError: opts.fail !== false,
|
|
11510
|
-
ignore: opts.ignore,
|
|
11511
|
-
deps: opts.dep
|
|
11512
|
-
};
|
|
11513
|
-
if (opts.config) {
|
|
11514
|
-
const resolvedConfig = path.resolve(opts.config);
|
|
11515
|
-
if (!fs.existsSync(resolvedConfig)) throw new ConfigError(`Configuration file not found: ${resolvedConfig}`, "ERR_CONFIG_NOT_FOUND", "Verify the path passed to --config exists and is readable.");
|
|
11516
|
-
}
|
|
11517
|
-
const annotationsPath = await resolveAnnotations({ customPath: opts.annotations });
|
|
11518
|
-
const userConfig = loadUserConfig(rootPath, checkOptions.configpath);
|
|
11519
|
-
const realmPlan = planRealmCheck({
|
|
11520
|
-
targetPath: rootPath,
|
|
11521
|
-
userConfig,
|
|
11522
|
-
selection: opts.realm ?? "all",
|
|
11523
|
-
annotationsPath,
|
|
11524
|
-
customConfigPath: checkOptions.configpath,
|
|
11525
|
-
ignore: checkOptions.ignore,
|
|
11526
|
-
targetPaths: canonicalTargets,
|
|
11527
|
-
cliDeps: checkOptions.deps
|
|
11528
|
-
});
|
|
11529
|
-
let result;
|
|
11530
|
-
if (realmPlan) try {
|
|
11531
|
-
result = await runRealmAwareCheck(realmPlan, rootPath, checkOptions);
|
|
11532
|
-
} finally {
|
|
11533
|
-
realmPlan.cleanup();
|
|
11534
|
-
}
|
|
11535
|
-
else {
|
|
11536
|
-
const resolvedDeps = resolvePackageDependencies(rootPath, userConfig, checkOptions.deps);
|
|
11537
|
-
const unrequestedExclusions = computeUnrequestedExclusions(rootPath, canonicalTargets);
|
|
11538
|
-
const resolved = resolveWorkspaceConfig(rootPath, checkOptions.configpath, {
|
|
11539
|
-
ignore: checkOptions.ignore,
|
|
11540
|
-
annotationsPath,
|
|
11541
|
-
dependencyLibraries: resolvedDeps.all,
|
|
11542
|
-
unrequestedExclusions
|
|
11543
|
-
});
|
|
11544
|
-
try {
|
|
11545
|
-
result = await runLuaLSCheck(rootPath, resolved.configPath, checkOptions);
|
|
11546
|
-
} finally {
|
|
11547
|
-
if (resolved.isTemp && fs.existsSync(resolved.configPath)) try {
|
|
11548
|
-
fs.unlinkSync(resolved.configPath);
|
|
11549
|
-
} catch (err) {
|
|
11550
|
-
logger.warn(`Failed to clean up temporary config file ${resolved.configPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11551
|
-
}
|
|
11552
|
-
}
|
|
11553
|
-
}
|
|
11554
|
-
const output = formatReport(result, checkOptions.format, process.cwd());
|
|
11555
|
-
if (output) writeOutput(output);
|
|
11556
|
-
if (!result.passed && checkOptions.failOnError) setExitCode(1);
|
|
11557
|
-
else setExitCode(0);
|
|
11607
|
+
await executeCheckCommand(targetPaths, opts, setExitCode);
|
|
11558
11608
|
});
|
|
11559
|
-
program.command("init [path]").description("Scaffold a .luarc.json configuration in the workspace").option("-f, --force", "Overwrite existing .luarc.json configuration").option("--annotations <path>", "Path to custom annotations.lua file").action(async (targetPath = ".", opts) => {
|
|
11560
|
-
const
|
|
11609
|
+
program.command("init [path]").description("Scaffold a .luarc.json configuration in the workspace").option("-f, --force", "Overwrite existing .luarc.json configuration").option("--vendor", "Vendor annotations.lua into .nanos-lint/ inside workspace for portable standalone editor setup").option("--annotations <path>", "Path to custom annotations.lua file (requires --vendor)").action(async (targetPath = ".", opts) => {
|
|
11610
|
+
const shouldVendor = Boolean(opts.vendor);
|
|
11611
|
+
const annotationsPath = shouldVendor ? await resolveAnnotations({ customPath: opts.annotations }) : opts.annotations;
|
|
11561
11612
|
writeOutput(`[init] Initialized nanos world LuaLS configuration: ${initWorkspace(path.resolve(targetPath), {
|
|
11562
11613
|
force: opts.force,
|
|
11563
|
-
annotationsPath
|
|
11614
|
+
annotationsPath,
|
|
11615
|
+
vendor: shouldVendor
|
|
11616
|
+
})}`);
|
|
11617
|
+
setExitCode(0);
|
|
11618
|
+
});
|
|
11619
|
+
program.command("copy-annotations [destination]").alias("export-annotations").description("Copy cached nanos world annotations.lua definitions into a target file or directory (targets not ending in .lua are treated as directories)").option("-f, --force", "Overwrite existing annotations file").option("--annotations <path>", "Path to custom annotations.lua source file").action(async (destination, opts) => {
|
|
11620
|
+
writeOutput(`[copy-annotations] Copied nanos world annotations to: ${await copyAnnotations(destination, {
|
|
11621
|
+
force: opts.force,
|
|
11622
|
+
annotationsPath: opts.annotations
|
|
11564
11623
|
})}`);
|
|
11565
11624
|
setExitCode(0);
|
|
11566
11625
|
});
|
|
@@ -11626,6 +11685,7 @@ Examples:
|
|
|
11626
11685
|
$ npx nanos-lint check . --realm server
|
|
11627
11686
|
$ npx nanos-lint check Shared/ Server/ --realm server
|
|
11628
11687
|
$ npx nanos-lint init
|
|
11688
|
+
$ npx nanos-lint copy-annotations
|
|
11629
11689
|
$ npx nanos-lint clean-cache
|
|
11630
11690
|
`);
|
|
11631
11691
|
return program;
|
|
@@ -11706,6 +11766,6 @@ if (isDirectExecution()) runCLI().then((code) => {
|
|
|
11706
11766
|
process.exit(1);
|
|
11707
11767
|
});
|
|
11708
11768
|
//#endregion
|
|
11709
|
-
export {
|
|
11769
|
+
export { resolveCheckTargets as $, VALID_LUALS_DIAGNOSTIC_CODES as $t, formatPretty as A, logger as An, validateArchiveMembers as At, collectDeps as B, deriveRealmAnnotationFiles as Bt, getAnnotationsMetadataFilePath as C, systemPaths as Cn, inspectZipMembers as Ct, readAnnotationsMetadata as D, LOG_LEVEL_PRIORITY as Dn, isZipArchive as Dt, isAnnotationsValid as E, LOG_LEVELS as En, isGzipArchive as Et, pluralize as F, resolveLatestLuaLSVersion as Ft, listCheckedFiles as G, createProgressBar as Gt, resolveLuaLSBinary as H, PROGRESS_MILESTONES as Ht, shouldEnableColor as I, resolveLuaLSVersion as It, findCommonAncestorDirectory as J, getProgressMode as Jt, computeUnrequestedExclusions as K, createSpinner as Kt, collectRealmFiles as L, sanitizeLuaLSVersion as Lt, formatReport as M, DEFAULT_LUALS_VERSION as Mt, formatSeverityBadge as N, FALLBACK_LUALS_VERSION as Nt, updateLastCheckedDate as O, Logger as On, parseTarTvSize as Ot, getColors as P, fetchLatestLuaLSVersionFromGitHub as Pt, matchesTargetPaths as Q, DEFAULT_REALM_MAPPINGS as Qt, planRealmCheck as R, ALLOWED_DOWNLOAD_DOMAINS as Rt, getAnnotationsCacheDir as S, getDirectorySize as Sn, getTarBinary as St, getTodayDateString as T, DEFAULT_LOG_LEVEL as Tn, isBinaryValid as Tt, runLuaLSCheck as U, PROGRESS_THROTTLE_MS as Ut, resolvePackageDependencies as V, splitAnnotationsByRealm as Vt, countCheckedFiles as W, SPINNER_FRAMES as Wt, getCanonicalPath as X, restoreTerminal as Xt, findProjectRoot as Y, isProgressInteractive as Yt, isFilesystemRoot as Z, setProgressMode as Zt, ANNOTATIONS_FILENAME as _, ConfigError as _n, MAX_ARCHIVE_MEMBER_COUNT as _t, formatCacheStatusPretty as a, initWorkspace as an, trackDownloadProgress as at, METADATA_FILENAME as b, cleanCache as bn, assertValidLuaLSBinary as bt, resolveAnnotations as c, mergeConfigs as cn, findExistingLuaLSDir as ct, GITHUB_COMMITS_API as d, resolveWorkspaceConfig as dn, getIsoWeek as dt, buildWorkspaceConfig as en, DOWNLOAD_TIMEOUT_MS as et, RAW_ANNOTATIONS_URL as f, stripJsonComments as fn, getLuaLSMetadataPath as ft, getRawAnnotationsUrl as g, CacheError as gn, writeLuaLSMetadata as gt, fetchRawAnnotationsContent as h, AnnotationsError as hn, readLuaLSMetadata as ht, runCLI as i, getPackageRoot as in, limitDownloadStream as it, formatProblemSummary as j, parseLogLevel as jn, getPlatformInfo as jt, formatGitHubAnnotations as k, isValidLogLevel as kn, rethrowLuaLSPermissionError as kt, DOCGEN_BRANCH as l, parseJsonc as ln, getBaseLuaLSCacheDir as lt, fetchLatestCommitId as m, writeTempConfig as mn, listCachedLuaLSVersions as mt, createProgram as n, getDefaultTemplatePath as nn, computeFileSha256 as nt, getCacheStatus as o, loadConfigFile as on, LUALS_METADATA_FILENAME as ot, downloadAndCacheAnnotations as p, stripTrailingSlashes as pn, listCachedLuaLSVersionDirs as pt, filterReportByTargetPaths as q, formatTransferSummary as qt, isDirectExecution as r, getDefinitionsDir as rn, downloadAndExtractLuaLS as rt, copyAnnotations as s, loadUserConfig as sn, cleanupOldCachedLuaLSVersions as st, collectIgnorePatterns as t, getDefaultAnnotationsPath as tn, MAX_ARCHIVE_SIZE_BYTES as tt, DOCGEN_REPO as u, resolveRealmMappings as un, getCacheDir as ut, MAX_ANNOTATIONS_SIZE_BYTES as v, LuaLSError as vn, MAX_DECOMPRESSED_SIZE_BYTES as vt, getCachedAnnotationsFilePath as w, fileUriToPath as wn, isBinaryRunnable as wt, MIN_ANNOTATIONS_SIZE_BYTES as x, formatBytes as xn, escapePowerShellSingleQuote as xt, MAX_COMMIT_JSON_SIZE_BYTES as y, NanosLintError as yn, MIN_DOWNLOADED_BINARY_SIZE_BYTES as yt, runRealmAwareCheck as z, isAllowedDownloadUrl as zt };
|
|
11710
11770
|
|
|
11711
|
-
//# sourceMappingURL=cli-
|
|
11771
|
+
//# sourceMappingURL=cli-CsIAHyRZ.js.map
|