nanos-lint 3.0.0 → 3.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/action.yml +1 -1
- package/dist/{cli-DUsLr0tU.js → cli-B9EpAClV.js} +89 -26
- package/dist/cli-B9EpAClV.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/cli-DUsLr0tU.js.map +0 -1
package/action.yml
CHANGED
|
@@ -4740,9 +4740,11 @@ var Ze = Object.assign(Je, {
|
|
|
4740
4740
|
});
|
|
4741
4741
|
Ze.glob = Ze;
|
|
4742
4742
|
/** A lock file older than this, or owned by a dead process, is treated as abandoned. */
|
|
4743
|
-
const DEFAULT_LOCK_STALE_MS =
|
|
4743
|
+
const DEFAULT_LOCK_STALE_MS = 3e4;
|
|
4744
4744
|
/** Upper bound for the polling interval, so a long wait stays responsive. */
|
|
4745
4745
|
const MAX_LOCK_POLL_INTERVAL_MS = 500;
|
|
4746
|
+
/** Upper bound for the automatic heartbeat interval, keeping it responsive. */
|
|
4747
|
+
const MAX_LOCK_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
4746
4748
|
/** Default rename attempts used to absorb transient Windows file-lock errors. */
|
|
4747
4749
|
const DEFAULT_RENAME_RETRIES = 5;
|
|
4748
4750
|
/** Create failures that mean "the lock is there / being swapped", not "cannot lock". */
|
|
@@ -4788,18 +4790,26 @@ function readLockMetadata(lockPath) {
|
|
|
4788
4790
|
return null;
|
|
4789
4791
|
}
|
|
4790
4792
|
}
|
|
4791
|
-
/** Returns
|
|
4792
|
-
function
|
|
4793
|
-
const
|
|
4794
|
-
|
|
4795
|
-
const createdAt = typeof metadata?.createdAt === "number" ? metadata.createdAt : null;
|
|
4796
|
-
if (createdAt !== null) return Date.now() - createdAt > staleMs;
|
|
4793
|
+
/** Returns the most recent activity timestamp (createdAt or mtime) for a lock file. */
|
|
4794
|
+
function readLockActiveTime(lockPath, metadata) {
|
|
4795
|
+
const meta = metadata !== void 0 ? metadata : readLockMetadata(lockPath);
|
|
4796
|
+
let mtimeMs = null;
|
|
4797
4797
|
try {
|
|
4798
|
-
|
|
4798
|
+
mtimeMs = fs.statSync(lockPath).mtimeMs;
|
|
4799
4799
|
} catch (err) {
|
|
4800
4800
|
logger.debug(`[lock] Could not stat lock file ${lockPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4801
|
-
return false;
|
|
4802
4801
|
}
|
|
4802
|
+
const createdAt = typeof meta?.createdAt === "number" ? meta.createdAt : null;
|
|
4803
|
+
if (createdAt !== null && mtimeMs !== null) return Math.max(createdAt, mtimeMs);
|
|
4804
|
+
return createdAt ?? mtimeMs;
|
|
4805
|
+
}
|
|
4806
|
+
/** Returns true when a lock was left behind by a dead owner or has expired. */
|
|
4807
|
+
function isLockStale(lockPath, staleMs = DEFAULT_LOCK_STALE_MS) {
|
|
4808
|
+
const metadata = readLockMetadata(lockPath);
|
|
4809
|
+
if (typeof metadata?.pid === "number" && !isProcessAlive(metadata.pid)) return true;
|
|
4810
|
+
const activeTime = readLockActiveTime(lockPath, metadata);
|
|
4811
|
+
if (activeTime !== null) return Date.now() - activeTime > staleMs;
|
|
4812
|
+
return false;
|
|
4803
4813
|
}
|
|
4804
4814
|
/**
|
|
4805
4815
|
* Atomically creates the lock file with `O_CREAT | O_EXCL` semantics, so exactly one
|
|
@@ -4831,14 +4841,9 @@ function tryCreateLockFile(lockPath, token) {
|
|
|
4831
4841
|
}
|
|
4832
4842
|
/** Returns the age of a lock file in milliseconds, from its metadata or its mtime. */
|
|
4833
4843
|
function lockAgeMs(lockPath) {
|
|
4834
|
-
const
|
|
4835
|
-
if (
|
|
4836
|
-
|
|
4837
|
-
return Math.max(0, Date.now() - fs.statSync(lockPath).mtimeMs);
|
|
4838
|
-
} catch (err) {
|
|
4839
|
-
logger.debug(`[lock] Could not read the age of ${lockPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4840
|
-
return Number.POSITIVE_INFINITY;
|
|
4841
|
-
}
|
|
4844
|
+
const activeTime = readLockActiveTime(lockPath);
|
|
4845
|
+
if (activeTime !== null) return Math.max(0, Date.now() - activeTime);
|
|
4846
|
+
return Number.POSITIVE_INFINITY;
|
|
4842
4847
|
}
|
|
4843
4848
|
/** Confirms that a lock file still carries the token written by this process. */
|
|
4844
4849
|
function ownsLockFile(lockPath, token) {
|
|
@@ -4878,7 +4883,7 @@ function nextPollDelay(attempt, baseMs) {
|
|
|
4878
4883
|
*/
|
|
4879
4884
|
async function acquireFileLock(lockPath, options) {
|
|
4880
4885
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
4881
|
-
const staleMs = options.staleMs ??
|
|
4886
|
+
const staleMs = options.staleMs ?? 3e4;
|
|
4882
4887
|
const reclaimGraceMs = options.reclaimGraceMs ?? 1e3;
|
|
4883
4888
|
const pollIntervalMs = options.pollIntervalMs ?? 25;
|
|
4884
4889
|
const label = options.label ?? path.basename(lockPath);
|
|
@@ -4910,15 +4915,70 @@ function releaseFileLock(lockPath, token) {
|
|
|
4910
4915
|
}
|
|
4911
4916
|
}
|
|
4912
4917
|
/**
|
|
4918
|
+
* Refreshes the active timestamp of a lock file if the caller still owns it.
|
|
4919
|
+
* Uses `fs.utimesSync` non-destructively so it never overwrites another owner's lock metadata.
|
|
4920
|
+
*/
|
|
4921
|
+
function touchLockFile(lockPath, token) {
|
|
4922
|
+
if (readLockMetadata(lockPath)?.token !== token) {
|
|
4923
|
+
logger.debug(`[lock] Cannot touch lock at ${lockPath}: token mismatch or missing lock.`);
|
|
4924
|
+
return false;
|
|
4925
|
+
}
|
|
4926
|
+
try {
|
|
4927
|
+
const now = /* @__PURE__ */ new Date();
|
|
4928
|
+
fs.utimesSync(lockPath, now, now);
|
|
4929
|
+
return true;
|
|
4930
|
+
} catch (err) {
|
|
4931
|
+
logger.debug(`[lock] Could not touch lock at ${lockPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4932
|
+
return false;
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4935
|
+
/** Calculates the default heartbeat interval for a given staleness threshold. */
|
|
4936
|
+
function defaultHeartbeatInterval(staleMs) {
|
|
4937
|
+
if (staleMs <= 0) return 0;
|
|
4938
|
+
return Math.min(Math.max(1, Math.floor(staleMs / 4)), MAX_LOCK_HEARTBEAT_INTERVAL_MS);
|
|
4939
|
+
}
|
|
4940
|
+
/**
|
|
4913
4941
|
* Runs `task` while holding an exclusive cross-process lock at `lockPath`, releasing it
|
|
4914
4942
|
* in a `finally` block. Concurrent callers queue with jittered exponential backoff, so
|
|
4915
4943
|
* parallel CI jobs and monorepo linters sharing one cache serialize instead of racing.
|
|
4916
4944
|
*/
|
|
4917
4945
|
async function withFileLock(lockPath, task, options = {}) {
|
|
4918
|
-
const
|
|
4946
|
+
const staleMs = options.staleMs ?? 3e4;
|
|
4947
|
+
const label = options.label ?? path.basename(lockPath);
|
|
4948
|
+
const token = await acquireFileLock(lockPath, {
|
|
4949
|
+
...options,
|
|
4950
|
+
staleMs,
|
|
4951
|
+
label
|
|
4952
|
+
});
|
|
4953
|
+
const heartbeatIntervalMs = options.heartbeatIntervalMs ?? defaultHeartbeatInterval(staleMs);
|
|
4954
|
+
let heartbeatTimer;
|
|
4955
|
+
let hasWarnedFailure = false;
|
|
4956
|
+
if (heartbeatIntervalMs > 0) {
|
|
4957
|
+
heartbeatTimer = setInterval(() => {
|
|
4958
|
+
if (readLockMetadata(lockPath)?.token !== token) {
|
|
4959
|
+
if (heartbeatTimer !== void 0) {
|
|
4960
|
+
clearInterval(heartbeatTimer);
|
|
4961
|
+
heartbeatTimer = void 0;
|
|
4962
|
+
}
|
|
4963
|
+
logger.warn(`[lock] Lost ownership of ${label} lock at ${lockPath}; stopping heartbeat.`);
|
|
4964
|
+
return;
|
|
4965
|
+
}
|
|
4966
|
+
if (!touchLockFile(lockPath, token)) {
|
|
4967
|
+
if (!hasWarnedFailure) {
|
|
4968
|
+
hasWarnedFailure = true;
|
|
4969
|
+
logger.warn(`[lock] Failed to touch ${label} lock at ${lockPath}; heartbeat could not update timestamp.`);
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
}, heartbeatIntervalMs);
|
|
4973
|
+
heartbeatTimer.unref();
|
|
4974
|
+
}
|
|
4919
4975
|
try {
|
|
4920
4976
|
return await task();
|
|
4921
4977
|
} finally {
|
|
4978
|
+
if (heartbeatTimer !== void 0) {
|
|
4979
|
+
clearInterval(heartbeatTimer);
|
|
4980
|
+
heartbeatTimer = void 0;
|
|
4981
|
+
}
|
|
4922
4982
|
releaseFileLock(lockPath, token);
|
|
4923
4983
|
}
|
|
4924
4984
|
}
|
|
@@ -6146,24 +6206,27 @@ async function downloadAndPromoteLuaLS(resolvedVersion, info, destDir, binaryPat
|
|
|
6146
6206
|
try {
|
|
6147
6207
|
const res = await fetch(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) });
|
|
6148
6208
|
if (res.url && !isAllowedDownloadUrl(res.url)) {
|
|
6149
|
-
|
|
6209
|
+
if (typeof res.body?.cancel === "function") try {
|
|
6210
|
+
await res.body.cancel();
|
|
6211
|
+
} catch (cancelErr) {}
|
|
6212
|
+
logger.warn(`[luals] Redirect to untrusted URL blocked: ${res.url}`);
|
|
6150
6213
|
throw new LuaLSError(`Redirect to untrusted URL blocked: ${res.url}`, "ERR_LUALS_DOWNLOAD", "Download redirects must stay on allowlisted HTTPS GitHub hosts.");
|
|
6151
6214
|
}
|
|
6152
6215
|
if (res.ok && res.body) {
|
|
6153
6216
|
response = res;
|
|
6154
6217
|
break;
|
|
6155
6218
|
}
|
|
6156
|
-
|
|
6219
|
+
if (typeof res.body?.cancel === "function") try {
|
|
6220
|
+
await res.body.cancel();
|
|
6221
|
+
} catch (cancelErr) {}
|
|
6157
6222
|
lastErr = /* @__PURE__ */ new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
6158
6223
|
} catch (err) {
|
|
6224
|
+
if (err instanceof LuaLSError) throw err;
|
|
6159
6225
|
lastErr = err;
|
|
6160
6226
|
}
|
|
6161
6227
|
if (attempt < 3) await new Promise((resolve) => setTimeout(resolve, attempt * 1e3));
|
|
6162
6228
|
}
|
|
6163
|
-
if (!response || !response.body) {
|
|
6164
|
-
if (lastErr instanceof LuaLSError) throw lastErr;
|
|
6165
|
-
throw new LuaLSError(`Failed to download LuaLS from ${url}${lastErr ? `: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}` : ""}`, "ERR_LUALS_DOWNLOAD", "Check your network connection or specify a custom binary with LUALS_BIN.", { cause: lastErr });
|
|
6166
|
-
}
|
|
6229
|
+
if (!response || !response.body) throw new LuaLSError(`Failed to download LuaLS from ${url}${lastErr ? `: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}` : ""}`, "ERR_LUALS_DOWNLOAD", "Check your network connection or specify a custom binary with LUALS_BIN.", { cause: lastErr });
|
|
6167
6230
|
const contentLengthHeader = response.headers?.get?.("content-length");
|
|
6168
6231
|
if (contentLengthHeader) {
|
|
6169
6232
|
const contentLength = parseInt(contentLengthHeader, 10);
|
|
@@ -10607,4 +10670,4 @@ if (isDirectExecution()) runCLI().then((code) => {
|
|
|
10607
10670
|
//#endregion
|
|
10608
10671
|
export { getBaseLuaLSCacheDir as $, getDirectorySize as $t, formatProblemSummary as A, VALID_LUALS_DIAGNOSTIC_CODES as At, runLuaLSCheck as B, parseJsonc as Bt, getCachedAnnotationsFilePath as C, fetchLatestLuaLSVersionFromGitHub as Ct, updateLastCheckedDate as D, deriveRealmAnnotationFiles as Dt, readAnnotationsMetadata as E, sanitizeLuaLSVersion as Et, shouldEnableColor as F, getPackageRoot as Ft, MAX_ARCHIVE_SIZE_BYTES as G, writeTempConfig as Gt, listCheckedFiles as H, resolveWorkspaceConfig as Ht, collectRealmFiles as I, initWorkspace as It, isAllowedDownloadUrl as J, ConfigError as Jt, computeFileSha256 as K, AnnotationsError as Kt, planRealmCheck as L, loadConfigFile as Lt, formatSeverityBadge as M, getDefaultAnnotationsPath as Mt, getColors as N, getDefaultTemplatePath as Nt, formatGitHubAnnotations as O, splitAnnotationsByRealm as Ot, pluralize as P, getDefinitionsDir as Pt, findExistingLuaLSDir as Q, formatBytes as Qt, runRealmAwareCheck as R, loadUserConfig as Rt, getAnnotationsMetadataFilePath as S, FALLBACK_LUALS_VERSION as St, isAnnotationsValid as T, resolveLuaLSVersion as Tt, ALLOWED_DOWNLOAD_DOMAINS as U, stripJsonComments as Ut, countCheckedFiles as V, resolveRealmMappings as Vt, DOWNLOAD_TIMEOUT_MS as W, stripTrailingSlashes as Wt, LUALS_METADATA_FILENAME as X, NanosLintError as Xt, limitDownloadStream as Y, LuaLSError as Yt, cleanupOldCachedLuaLSVersions as Z, cleanCache as Zt, MAX_ANNOTATIONS_SIZE_BYTES as _, isZipArchive as _t, formatCacheStatusPretty as a, Logger as an, readLuaLSMetadata as at, MIN_ANNOTATIONS_SIZE_BYTES as b, getPlatformInfo as bt, DOCGEN_BRANCH as c, parseLogLevel as cn, MAX_DECOMPRESSED_SIZE_BYTES as ct, RAW_ANNOTATIONS_URL as d, escapePowerShellSingleQuote as dt, systemPaths as en, getCacheDir as et, downloadAndCacheAnnotations as f, getTarBinary as ft, ANNOTATIONS_FILENAME as g, isGzipArchive as gt, getRawAnnotationsUrl as h, isBinaryValid as ht, runCLI as i, LOG_LEVEL_PRIORITY as in, listCachedLuaLSVersions as it, formatReport as j, buildWorkspaceConfig as jt, formatPretty as k, DEFAULT_REALM_MAPPINGS as kt, DOCGEN_REPO as l, MIN_DOWNLOADED_BINARY_SIZE_BYTES as lt, fetchRawAnnotationsContent as m, isBinaryRunnable as mt, createProgram as n, DEFAULT_LOG_LEVEL as nn, getLuaLSMetadataPath as nt, getCacheStatus as o, isValidLogLevel as on, writeLuaLSMetadata as ot, fetchLatestCommitId as p, inspectZipMembers as pt, downloadAndExtractLuaLS as q, CacheError as qt, isDirectExecution as r, LOG_LEVELS as rn, listCachedLuaLSVersionDirs as rt, resolveAnnotations as s, logger as sn, MAX_ARCHIVE_MEMBER_COUNT as st, collectIgnorePatterns as t, fileUriToPath as tn, getIsoWeek as tt, GITHUB_COMMITS_API as u, assertValidLuaLSBinary as ut, MAX_COMMIT_JSON_SIZE_BYTES as v, parseTarTvSize as vt, getTodayDateString as w, resolveLatestLuaLSVersion as wt, getAnnotationsCacheDir as x, DEFAULT_LUALS_VERSION as xt, METADATA_FILENAME as y, validateArchiveMembers as yt, resolveLuaLSBinary as z, mergeConfigs as zt };
|
|
10609
10672
|
|
|
10610
|
-
//# sourceMappingURL=cli-
|
|
10673
|
+
//# sourceMappingURL=cli-B9EpAClV.js.map
|