WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
var _typeof = require("./typeof.js")["default"];
|
||||
function applyDecs2203Factory() {
|
||||
function createAddInitializerMethod(e, t) {
|
||||
return function (r) {
|
||||
!function (e) {
|
||||
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
|
||||
}(t), assertCallable(r, "An initializer"), e.push(r);
|
||||
};
|
||||
}
|
||||
function memberDec(e, t, r, a, n, i, s, o) {
|
||||
var c;
|
||||
switch (n) {
|
||||
case 1:
|
||||
c = "accessor";
|
||||
break;
|
||||
case 2:
|
||||
c = "method";
|
||||
break;
|
||||
case 3:
|
||||
c = "getter";
|
||||
break;
|
||||
case 4:
|
||||
c = "setter";
|
||||
break;
|
||||
default:
|
||||
c = "field";
|
||||
}
|
||||
var l,
|
||||
u,
|
||||
f = {
|
||||
kind: c,
|
||||
name: s ? "#" + t : t,
|
||||
"static": i,
|
||||
"private": s
|
||||
},
|
||||
p = {
|
||||
v: !1
|
||||
};
|
||||
0 !== n && (f.addInitializer = createAddInitializerMethod(a, p)), 0 === n ? s ? (l = r.get, u = r.set) : (l = function l() {
|
||||
return this[t];
|
||||
}, u = function u(e) {
|
||||
this[t] = e;
|
||||
}) : 2 === n ? l = function l() {
|
||||
return r.value;
|
||||
} : (1 !== n && 3 !== n || (l = function l() {
|
||||
return r.get.call(this);
|
||||
}), 1 !== n && 4 !== n || (u = function u(e) {
|
||||
r.set.call(this, e);
|
||||
})), f.access = l && u ? {
|
||||
get: l,
|
||||
set: u
|
||||
} : l ? {
|
||||
get: l
|
||||
} : {
|
||||
set: u
|
||||
};
|
||||
try {
|
||||
return e(o, f);
|
||||
} finally {
|
||||
p.v = !0;
|
||||
}
|
||||
}
|
||||
function assertCallable(e, t) {
|
||||
if ("function" != typeof e) throw new TypeError(t + " must be a function");
|
||||
}
|
||||
function assertValidReturnValue(e, t) {
|
||||
var r = _typeof(t);
|
||||
if (1 === e) {
|
||||
if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
||||
void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
|
||||
} else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
|
||||
}
|
||||
function applyMemberDec(e, t, r, a, n, i, s, o) {
|
||||
var c,
|
||||
l,
|
||||
u,
|
||||
f,
|
||||
p,
|
||||
d,
|
||||
h = r[0];
|
||||
if (s ? c = 0 === n || 1 === n ? {
|
||||
get: r[3],
|
||||
set: r[4]
|
||||
} : 3 === n ? {
|
||||
get: r[3]
|
||||
} : 4 === n ? {
|
||||
set: r[3]
|
||||
} : {
|
||||
value: r[3]
|
||||
} : 0 !== n && (c = Object.getOwnPropertyDescriptor(t, a)), 1 === n ? u = {
|
||||
get: c.get,
|
||||
set: c.set
|
||||
} : 2 === n ? u = c.value : 3 === n ? u = c.get : 4 === n && (u = c.set), "function" == typeof h) void 0 !== (f = memberDec(h, a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? l = f : 1 === n ? (l = f.init, p = f.get || u.get, d = f.set || u.set, u = {
|
||||
get: p,
|
||||
set: d
|
||||
}) : u = f);else for (var v = h.length - 1; v >= 0; v--) {
|
||||
var g;
|
||||
void 0 !== (f = memberDec(h[v], a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? g = f : 1 === n ? (g = f.init, p = f.get || u.get, d = f.set || u.set, u = {
|
||||
get: p,
|
||||
set: d
|
||||
}) : u = f, void 0 !== g && (void 0 === l ? l = g : "function" == typeof l ? l = [l, g] : l.push(g)));
|
||||
}
|
||||
if (0 === n || 1 === n) {
|
||||
if (void 0 === l) l = function l(e, t) {
|
||||
return t;
|
||||
};else if ("function" != typeof l) {
|
||||
var y = l;
|
||||
l = function l(e, t) {
|
||||
for (var r = t, a = 0; a < y.length; a++) r = y[a].call(e, r);
|
||||
return r;
|
||||
};
|
||||
} else {
|
||||
var m = l;
|
||||
l = function l(e, t) {
|
||||
return m.call(e, t);
|
||||
};
|
||||
}
|
||||
e.push(l);
|
||||
}
|
||||
0 !== n && (1 === n ? (c.get = u.get, c.set = u.set) : 2 === n ? c.value = u : 3 === n ? c.get = u : 4 === n && (c.set = u), s ? 1 === n ? (e.push(function (e, t) {
|
||||
return u.get.call(e, t);
|
||||
}), e.push(function (e, t) {
|
||||
return u.set.call(e, t);
|
||||
})) : 2 === n ? e.push(u) : e.push(function (e, t) {
|
||||
return u.call(e, t);
|
||||
}) : Object.defineProperty(t, a, c));
|
||||
}
|
||||
function pushInitializers(e, t) {
|
||||
t && e.push(function (e) {
|
||||
for (var r = 0; r < t.length; r++) t[r].call(e);
|
||||
return e;
|
||||
});
|
||||
}
|
||||
return function (e, t, r) {
|
||||
var a = [];
|
||||
return function (e, t, r) {
|
||||
for (var a, n, i = new Map(), s = new Map(), o = 0; o < r.length; o++) {
|
||||
var c = r[o];
|
||||
if (Array.isArray(c)) {
|
||||
var l,
|
||||
u,
|
||||
f = c[1],
|
||||
p = c[2],
|
||||
d = c.length > 3,
|
||||
h = f >= 5;
|
||||
if (h ? (l = t, 0 != (f -= 5) && (u = n = n || [])) : (l = t.prototype, 0 !== f && (u = a = a || [])), 0 !== f && !d) {
|
||||
var v = h ? s : i,
|
||||
g = v.get(p) || 0;
|
||||
if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
|
||||
!g && f > 2 ? v.set(p, f) : v.set(p, !0);
|
||||
}
|
||||
applyMemberDec(e, l, c, p, f, h, d, u);
|
||||
}
|
||||
}
|
||||
pushInitializers(e, a), pushInitializers(e, n);
|
||||
}(a, e, t), function (e, t, r) {
|
||||
if (r.length > 0) {
|
||||
for (var a = [], n = t, i = t.name, s = r.length - 1; s >= 0; s--) {
|
||||
var o = {
|
||||
v: !1
|
||||
};
|
||||
try {
|
||||
var c = r[s](n, {
|
||||
kind: "class",
|
||||
name: i,
|
||||
addInitializer: createAddInitializerMethod(a, o)
|
||||
});
|
||||
} finally {
|
||||
o.v = !0;
|
||||
}
|
||||
void 0 !== c && (assertValidReturnValue(10, c), n = c);
|
||||
}
|
||||
e.push(n, function () {
|
||||
for (var e = 0; e < a.length; e++) a[e].call(n);
|
||||
});
|
||||
}
|
||||
}(a, e, r), a;
|
||||
};
|
||||
}
|
||||
var applyDecs2203Impl;
|
||||
function applyDecs2203(e, t, r) {
|
||||
return (applyDecs2203Impl = applyDecs2203Impl || applyDecs2203Factory())(e, t, r);
|
||||
}
|
||||
module.exports = applyDecs2203, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,155 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AbstractMessageBuffer = void 0;
|
||||
const CR = 13;
|
||||
const LF = 10;
|
||||
const CRLF = '\r\n';
|
||||
class AbstractMessageBuffer {
|
||||
_encoding;
|
||||
_chunks;
|
||||
_totalLength;
|
||||
constructor(encoding = 'utf-8') {
|
||||
this._encoding = encoding;
|
||||
this._chunks = [];
|
||||
this._totalLength = 0;
|
||||
}
|
||||
get encoding() {
|
||||
return this._encoding;
|
||||
}
|
||||
append(chunk) {
|
||||
const toAppend = typeof chunk === 'string' ? this.fromString(chunk, this._encoding) : chunk;
|
||||
this._chunks.push(toAppend);
|
||||
this._totalLength += toAppend.byteLength;
|
||||
}
|
||||
tryReadHeaders(lowerCaseKeys = false) {
|
||||
if (this._chunks.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
let state = 0;
|
||||
let chunkIndex = 0;
|
||||
let offset = 0;
|
||||
let chunkBytesRead = 0;
|
||||
row: while (chunkIndex < this._chunks.length) {
|
||||
const chunk = this._chunks[chunkIndex];
|
||||
offset = 0;
|
||||
while (offset < chunk.length) {
|
||||
const value = chunk[offset];
|
||||
switch (value) {
|
||||
case CR:
|
||||
switch (state) {
|
||||
case 0:
|
||||
state = 1;
|
||||
break;
|
||||
case 2:
|
||||
state = 3;
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case LF:
|
||||
switch (state) {
|
||||
case 1:
|
||||
state = 2;
|
||||
break;
|
||||
case 3:
|
||||
state = 4;
|
||||
offset++;
|
||||
break row;
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
chunkBytesRead += chunk.byteLength;
|
||||
chunkIndex++;
|
||||
}
|
||||
if (state !== 4) {
|
||||
return undefined;
|
||||
}
|
||||
// The buffer contains the two CRLF at the end. So we will
|
||||
// have two empty lines after the split at the end as well.
|
||||
const buffer = this._read(chunkBytesRead + offset);
|
||||
const result = new Map();
|
||||
const headers = this.toString(buffer, 'ascii').split(CRLF);
|
||||
if (headers.length < 2) {
|
||||
return result;
|
||||
}
|
||||
for (let i = 0; i < headers.length - 2; i++) {
|
||||
const header = headers[i];
|
||||
const index = header.indexOf(':');
|
||||
if (index === -1) {
|
||||
throw new Error(`Message header must separate key and value using ':'\n${header}`);
|
||||
}
|
||||
const key = header.substr(0, index);
|
||||
const value = header.substr(index + 1).trim();
|
||||
result.set(lowerCaseKeys ? key.toLowerCase() : key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
tryReadBody(length) {
|
||||
if (this._totalLength < length) {
|
||||
return undefined;
|
||||
}
|
||||
return this._read(length);
|
||||
}
|
||||
get numberOfBytes() {
|
||||
return this._totalLength;
|
||||
}
|
||||
_read(byteCount) {
|
||||
if (byteCount === 0) {
|
||||
return this.emptyBuffer();
|
||||
}
|
||||
if (byteCount > this._totalLength) {
|
||||
throw new Error(`Cannot read so many bytes!`);
|
||||
}
|
||||
if (this._chunks[0].byteLength === byteCount) {
|
||||
// super fast path, precisely first chunk must be returned
|
||||
const chunk = this._chunks[0];
|
||||
this._chunks.shift();
|
||||
this._totalLength -= byteCount;
|
||||
return this.asNative(chunk);
|
||||
}
|
||||
if (this._chunks[0].byteLength > byteCount) {
|
||||
// fast path, the reading is entirely within the first chunk
|
||||
const chunk = this._chunks[0];
|
||||
const result = this.asNative(chunk, byteCount);
|
||||
this._chunks[0] = chunk.slice(byteCount);
|
||||
this._totalLength -= byteCount;
|
||||
return result;
|
||||
}
|
||||
const result = this.allocNative(byteCount);
|
||||
let resultOffset = 0;
|
||||
const chunkIndex = 0;
|
||||
while (byteCount > 0) {
|
||||
const chunk = this._chunks[chunkIndex];
|
||||
if (chunk.byteLength > byteCount) {
|
||||
// this chunk will survive
|
||||
const chunkPart = chunk.slice(0, byteCount);
|
||||
result.set(chunkPart, resultOffset);
|
||||
resultOffset += byteCount;
|
||||
this._chunks[chunkIndex] = chunk.slice(byteCount);
|
||||
this._totalLength -= byteCount;
|
||||
byteCount -= byteCount;
|
||||
}
|
||||
else {
|
||||
// this chunk will be entirely read
|
||||
result.set(chunk, resultOffset);
|
||||
resultOffset += chunk.byteLength;
|
||||
this._chunks.shift();
|
||||
this._totalLength -= chunk.byteLength;
|
||||
byteCount -= chunk.byteLength;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
exports.AbstractMessageBuffer = AbstractMessageBuffer;
|
||||
@@ -0,0 +1,91 @@
|
||||
# std-env
|
||||
|
||||
[](http://npmjs.com/package/std-env)
|
||||
[](http://npmjs.com/package/std-env)
|
||||
[](https://bundlephobia.com/result?p=std-env)
|
||||
|
||||
Runtime-agnostic JS utils for detecting environments, runtimes, CI providers, and AI coding agents.
|
||||
|
||||
## Runtime Detection
|
||||
|
||||
Detects the current JavaScript runtime based on global variables, following the [WinterCG Runtime Keys proposal](https://runtime-keys.proposal.wintercg.org/).
|
||||
|
||||
```ts
|
||||
import { runtime, runtimeInfo } from "std-env";
|
||||
|
||||
console.log(runtime); // "" | "node" | "deno" | "bun" | "workerd" ...
|
||||
console.log(runtimeInfo); // { name: "node" }
|
||||
```
|
||||
|
||||
Individual named exports: `isNode`, `isBun`, `isDeno`, `isNetlify`, `isEdgeLight`, `isWorkerd`, `isFastly`
|
||||
|
||||
> [!NOTE]
|
||||
> `isNode` is also `true` in Bun/Deno with Node.js compatibility mode. Use `runtime === "node"` for strict checks.
|
||||
|
||||
See [./src/runtimes.ts](./src/runtimes.ts) for the full list.
|
||||
|
||||
## Provider Detection
|
||||
|
||||
Detects the current CI/CD provider based on environment variables.
|
||||
|
||||
```ts
|
||||
import { isCI, provider, providerInfo } from "std-env";
|
||||
|
||||
console.log({ isCI, provider, providerInfo });
|
||||
// { isCI: true, provider: "github_actions", providerInfo: { name: "github_actions", ci: true } }
|
||||
```
|
||||
|
||||
Use `detectProvider()` to re-run detection. See [./src/providers.ts](./src/providers.ts) for the full list.
|
||||
|
||||
## Agent Detection
|
||||
|
||||
Detects if the environment is running inside an AI coding agent.
|
||||
|
||||
```ts
|
||||
import { isAgent, agent, agentInfo } from "std-env";
|
||||
|
||||
console.log({ isAgent, agent, agentInfo });
|
||||
// { isAgent: true, agent: "claude", agentInfo: { name: "claude" } }
|
||||
```
|
||||
|
||||
Set the `AI_AGENT` env var to explicitly specify the agent name. Use `detectAgent()` to re-run detection.
|
||||
|
||||
Supported agents: `cursor`, `claude`, `devin`, `replit`, `gemini`, `codex`, `auggie`, `opencode`, `kiro`, `goose`, `pi`, `junie`
|
||||
|
||||
## Flags
|
||||
|
||||
```js
|
||||
import { env, isDevelopment, isProduction } from "std-env";
|
||||
```
|
||||
|
||||
| Export | Description |
|
||||
| ------------------ | ------------------------------------------------------------ |
|
||||
| `hasTTY` | stdout TTY is available |
|
||||
| `hasWindow` | Global `window` is available |
|
||||
| `isCI` | Running in CI |
|
||||
| `isColorSupported` | Terminal color output supported |
|
||||
| `isDebug` | `DEBUG` env var is set |
|
||||
| `isDevelopment` | `NODE_ENV` is `dev`/`development` or `MODE` is `development` |
|
||||
| `isLinux` | Linux platform |
|
||||
| `isMacOS` | macOS (darwin) platform |
|
||||
| `isMinimal` | `MINIMAL` env is set, CI, test, or no TTY |
|
||||
| `isProduction` | `NODE_ENV` or `MODE` is `production` |
|
||||
| `isTest` | `NODE_ENV` is `test` or `TEST` env is set |
|
||||
| `isWindows` | Windows platform |
|
||||
| `platform` | Value of `process.platform` |
|
||||
| `nodeVersion` | Node.js version string (e.g. `"22.0.0"`) |
|
||||
| `nodeMajorVersion` | Node.js major version number (e.g. `22`) |
|
||||
|
||||
See [./src/flags.ts](./src/flags.ts) for details.
|
||||
|
||||
## Environment
|
||||
|
||||
| Export | Description |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| `env` | Universal `process.env` (works across all runtimes) |
|
||||
| `process` | Universal `process` shim (works across all runtimes) |
|
||||
| `nodeENV` | Current `NODE_ENV` value (undefined if unset) |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1 @@
|
||||
export * from './dist/utils.js'
|
||||
@@ -0,0 +1 @@
|
||||
export { _ as default } from "../esm/_initializer_define_property.js";
|
||||
@@ -0,0 +1,24 @@
|
||||
- testing: chrome @ Windows 2008: 26
|
||||
- testing: opera @ Windows 2003: 11 12
|
||||
- queuing: <chrome 26 on Windows 2008>
|
||||
- starting: <chrome 26 on Windows 2008>
|
||||
<chrome 26 on Windows 2008> console
|
||||
Finished benchmarking: nickyout/fast-stable-stringify x 6,025 ops/sec ±6.76% (50 runs sampled) (cumulative string length: 94425969)
|
||||
Finished benchmarking: substack/json-stable-stringify x 4,114 ops/sec ±1.05% (50 runs sampled) (cumulative string length: 61301724)
|
||||
- passed: <chrome 26 on Windows 2008>
|
||||
- queuing: <opera 11 on Windows 2003>
|
||||
- starting: <opera 11 on Windows 2003>
|
||||
<opera 11 on Windows 2003> Benchmark :: fastest
|
||||
Error: Benchmark.js was unable to find a working timer.
|
||||
clock([arguments not available]) __zuul/test-bundle.js:4066
|
||||
cycle([arguments not available]) __zuul/test-bundle.js:4301
|
||||
run([arguments not available]) __zuul/test-bundle.js:4409
|
||||
execute([arguments not available]) __zuul/test-bundle.js:3088
|
||||
invoke([arguments not available]) __zuul/test-bundle.js:3202
|
||||
compute([arguments not available]) __zuul/test-bundle.js:4259
|
||||
run([arguments not available]) __zuul/test-bundle.js:4414
|
||||
execute([arguments not available]) __zuul/test-bundle.js:3088
|
||||
invoke([arguments not available]) __zuul/test-bundle.js:3202
|
||||
runSuite([arguments not available]) __zuul/test-bundle.js:3451
|
||||
|
||||
- passed: <opera 11 on Windows 2003>
|
||||
@@ -0,0 +1,717 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
test("type inference", () => {
|
||||
const booleanRecord = z.record(z.string(), z.boolean());
|
||||
type booleanRecord = typeof booleanRecord._output;
|
||||
|
||||
const recordWithEnumKeys = z.record(z.enum(["Tuna", "Salmon"]), z.string());
|
||||
type recordWithEnumKeys = z.infer<typeof recordWithEnumKeys>;
|
||||
|
||||
const recordWithLiteralKey = z.record(z.literal(["Tuna", "Salmon", 21]), z.string());
|
||||
type recordWithLiteralKey = z.infer<typeof recordWithLiteralKey>;
|
||||
|
||||
const recordWithLiteralUnionKeys = z.record(
|
||||
z.union([z.literal("Tuna"), z.literal("Salmon"), z.literal(21)]),
|
||||
z.string()
|
||||
);
|
||||
type recordWithLiteralUnionKeys = z.infer<typeof recordWithLiteralUnionKeys>;
|
||||
|
||||
enum Enum {
|
||||
Tuna = 0,
|
||||
Salmon = "Shark",
|
||||
}
|
||||
|
||||
const recordWithTypescriptEnum = z.record(z.enum(Enum), z.string());
|
||||
type recordWithTypescriptEnum = z.infer<typeof recordWithTypescriptEnum>;
|
||||
|
||||
expectTypeOf<booleanRecord>().toEqualTypeOf<Record<string, boolean>>();
|
||||
expectTypeOf<recordWithEnumKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
|
||||
expectTypeOf<recordWithLiteralKey>().toEqualTypeOf<Record<"Tuna" | "Salmon" | 21, string>>();
|
||||
expectTypeOf<recordWithLiteralUnionKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon" | 21, string>>();
|
||||
expectTypeOf<recordWithTypescriptEnum>().toEqualTypeOf<Record<Enum, string>>();
|
||||
});
|
||||
|
||||
test("enum exhaustiveness", () => {
|
||||
const schema = z.record(z.enum(["Tuna", "Salmon"]), z.string());
|
||||
expect(
|
||||
schema.parse({
|
||||
Tuna: "asdf",
|
||||
Salmon: "asdf",
|
||||
})
|
||||
).toEqual({
|
||||
Tuna: "asdf",
|
||||
Salmon: "asdf",
|
||||
});
|
||||
|
||||
expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "unrecognized_keys",
|
||||
"keys": [
|
||||
"Trout"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Unrecognized key: \\"Trout\\""
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"Salmon"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("typescript enum exhaustiveness", () => {
|
||||
enum BigFish {
|
||||
Tuna = 0,
|
||||
Salmon = "Shark",
|
||||
}
|
||||
|
||||
const schema = z.record(z.enum(BigFish), z.string());
|
||||
const value = {
|
||||
[BigFish.Tuna]: "asdf",
|
||||
[BigFish.Salmon]: "asdf",
|
||||
};
|
||||
|
||||
expect(schema.parse(value)).toEqual(value);
|
||||
|
||||
expect(schema.safeParse({ [BigFish.Tuna]: "asdf", [BigFish.Salmon]: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "unrecognized_keys",
|
||||
"keys": [
|
||||
"Trout"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Unrecognized key: \\"Trout\\""
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ [BigFish.Tuna]: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"Shark"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ [BigFish.Salmon]: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
0
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("literal exhaustiveness", () => {
|
||||
const schema = z.record(z.literal(["Tuna", "Salmon", 21]), z.string());
|
||||
schema.parse({
|
||||
Tuna: "asdf",
|
||||
Salmon: "asdf",
|
||||
21: "asdf",
|
||||
});
|
||||
|
||||
expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "unrecognized_keys",
|
||||
"keys": [
|
||||
"Trout"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Unrecognized key: \\"Trout\\""
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"Salmon"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
21
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("pipe exhaustiveness", () => {
|
||||
const schema = z.record(z.enum(["Tuna", "Salmon"]).pipe(z.any()), z.string());
|
||||
expect(schema.parse({ Tuna: "asdf", Salmon: "asdf" })).toEqual({
|
||||
Tuna: "asdf",
|
||||
Salmon: "asdf",
|
||||
});
|
||||
|
||||
expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "unrecognized_keys",
|
||||
"keys": [
|
||||
"Trout"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Unrecognized key: \\"Trout\\""
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"Salmon"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("union exhaustiveness", () => {
|
||||
const schema = z.record(z.union([z.literal("Tuna"), z.literal("Salmon"), z.literal(21)]), z.string());
|
||||
expect(schema.parse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf" })).toEqual({
|
||||
Tuna: "asdf",
|
||||
Salmon: "asdf",
|
||||
21: "asdf",
|
||||
});
|
||||
|
||||
expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "unrecognized_keys",
|
||||
"keys": [
|
||||
"Trout"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Unrecognized key: \\"Trout\\""
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"Salmon"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
21
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("applies transforms on the key schema (#5296)", () => {
|
||||
const single = z.record(
|
||||
z.literal("a").transform(() => "b" as const),
|
||||
z.string()
|
||||
);
|
||||
expect(single.parse({ a: "John" })).toEqual({ b: "John" });
|
||||
|
||||
const multi = z.record(
|
||||
z.literal(["a", "b"]).transform((k) => k.toUpperCase()),
|
||||
z.number()
|
||||
);
|
||||
expect(multi.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
||||
|
||||
// required-key semantics still hold when the keyType has a known value set
|
||||
expect(multi.safeParse({ a: 1 }).success).toBe(false);
|
||||
|
||||
const en = z.record(
|
||||
z.enum(["a", "b"]).transform((k) => k.toUpperCase()),
|
||||
z.number()
|
||||
);
|
||||
expect(en.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
||||
|
||||
// matches partialRecord, which already applied transforms
|
||||
const part = z.partialRecord(
|
||||
z.literal("a").transform(() => "b" as const),
|
||||
z.string()
|
||||
);
|
||||
expect(part.parse({ a: "John" })).toEqual({ b: "John" });
|
||||
});
|
||||
|
||||
test("surfaces key schema refinement failures as invalid_key", () => {
|
||||
// refine rejects "b" but it's still in the literal's value set
|
||||
const schema = z.record(
|
||||
z.literal(["a", "b"]).refine((k) => k === "a", { message: "only 'a' is allowed" }),
|
||||
z.string()
|
||||
);
|
||||
|
||||
expect(schema.safeParse({ a: "ok", b: "nope" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "invalid_key",
|
||||
"origin": "record",
|
||||
"issues": [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "only 'a' is allowed"
|
||||
}
|
||||
],
|
||||
"path": [
|
||||
"b"
|
||||
],
|
||||
"message": "Invalid key in record"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("string record parse - pass", () => {
|
||||
const schema = z.record(z.string(), z.boolean());
|
||||
schema.parse({
|
||||
k1: true,
|
||||
k2: false,
|
||||
1234: false,
|
||||
});
|
||||
|
||||
expect(schema.safeParse({ asdf: 1234 }).success).toEqual(false);
|
||||
expect(schema.safeParse("asdf")).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "record",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "Invalid input: expected record, received string"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("key and value getters", () => {
|
||||
const rec = z.record(z.string(), z.number());
|
||||
|
||||
rec.keyType.parse("asdf");
|
||||
rec.valueType.parse(1234);
|
||||
});
|
||||
|
||||
test("is not vulnerable to prototype pollution", async () => {
|
||||
const rec = z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
a: z.string(),
|
||||
})
|
||||
);
|
||||
|
||||
const data = JSON.parse(`
|
||||
{
|
||||
"__proto__": {
|
||||
"a": "evil"
|
||||
},
|
||||
"b": {
|
||||
"a": "good"
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const obj1 = rec.parse(data);
|
||||
expect(obj1.a).toBeUndefined();
|
||||
|
||||
const obj2 = rec.safeParse(data);
|
||||
expect(obj2.success).toBe(true);
|
||||
if (obj2.success) {
|
||||
expect(obj2.data.a).toBeUndefined();
|
||||
}
|
||||
|
||||
const obj3 = await rec.parseAsync(data);
|
||||
expect(obj3.a).toBeUndefined();
|
||||
|
||||
const obj4 = await rec.safeParseAsync(data);
|
||||
expect(obj4.success).toBe(true);
|
||||
if (obj4.success) {
|
||||
expect(obj4.data.a).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
test("dont remove undefined values", () => {
|
||||
const result1 = z.record(z.string(), z.any()).parse({ foo: undefined });
|
||||
|
||||
expect(result1).toEqual({
|
||||
foo: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
test("allow undefined values", () => {
|
||||
const schema = z.record(z.string(), z.undefined());
|
||||
|
||||
expect(
|
||||
Object.keys(
|
||||
schema.parse({
|
||||
_test: undefined,
|
||||
})
|
||||
)
|
||||
).toEqual(["_test"]);
|
||||
});
|
||||
|
||||
test("async parsing", async () => {
|
||||
const schema = z
|
||||
.record(
|
||||
z.string(),
|
||||
z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(async () => true)
|
||||
)
|
||||
.refine(async () => true);
|
||||
|
||||
const data = {
|
||||
foo: "bar",
|
||||
baz: "qux",
|
||||
};
|
||||
const result = await schema.safeParseAsync(data);
|
||||
expect(result.data).toEqual(data);
|
||||
});
|
||||
|
||||
test("async parsing", async () => {
|
||||
const schema = z
|
||||
.record(
|
||||
z.string(),
|
||||
z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(async () => false)
|
||||
)
|
||||
.refine(async () => false);
|
||||
|
||||
const data = {
|
||||
foo: "bar",
|
||||
baz: "qux",
|
||||
};
|
||||
const result = await schema.safeParseAsync(data);
|
||||
expect(result.success).toEqual(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [
|
||||
"foo"
|
||||
],
|
||||
"message": "Invalid input"
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [
|
||||
"baz"
|
||||
],
|
||||
"message": "Invalid input"
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "Invalid input"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("partial record", () => {
|
||||
const schema = z.partialRecord(z.string(), z.string());
|
||||
type schema = z.infer<typeof schema>;
|
||||
expectTypeOf<schema>().toEqualTypeOf<Partial<Record<string, string>>>();
|
||||
|
||||
const Keys = z.enum(["id", "name", "email"]); //.or(z.never());
|
||||
const Person = z.partialRecord(Keys, z.string());
|
||||
expectTypeOf<z.infer<typeof Person>>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
|
||||
|
||||
Person.parse({
|
||||
id: "123",
|
||||
// name: "John",
|
||||
// email: "john@example.com",
|
||||
});
|
||||
|
||||
Person.parse({
|
||||
// id: "123",
|
||||
// name: "John",
|
||||
email: "john@example.com",
|
||||
});
|
||||
|
||||
expect(Person.def.keyType._zod.def.type).toEqual("enum");
|
||||
});
|
||||
|
||||
test("partialRecord with z.literal([key, ...])", () => {
|
||||
const Keys = z.literal(["id", "name", "email"]);
|
||||
const schema = z.partialRecord(Keys, z.string());
|
||||
type Schema = z.infer<typeof schema>;
|
||||
expectTypeOf<Schema>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
|
||||
|
||||
// Should parse valid partials
|
||||
expect(schema.parse({})).toEqual({});
|
||||
expect(schema.parse({ id: "1" })).toEqual({ id: "1" });
|
||||
expect(schema.parse({ name: "n", email: "e@example.com" })).toEqual({ name: "n", email: "e@example.com" });
|
||||
|
||||
// Should fail with unrecognized key, error checked via inline snapshot
|
||||
expect(schema.safeParse({ foo: "bar" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "invalid_key",
|
||||
"origin": "record",
|
||||
"issues": [
|
||||
{
|
||||
"code": "invalid_value",
|
||||
"values": [
|
||||
"id",
|
||||
"name",
|
||||
"email"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Invalid option: expected one of \\"id\\"|\\"name\\"|\\"email\\""
|
||||
}
|
||||
],
|
||||
"path": [
|
||||
"foo"
|
||||
],
|
||||
"message": "Invalid key in record"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("partialRecord with numeric literal keys", () => {
|
||||
const Keys = z.literal([1, 2, 3]);
|
||||
const schema = z.partialRecord(Keys, z.string());
|
||||
type Schema = z.infer<typeof schema>;
|
||||
expectTypeOf<Schema>().toEqualTypeOf<Partial<Record<1 | 2 | 3, string>>>();
|
||||
|
||||
// Should parse valid partials with numeric keys (as strings in JS objects)
|
||||
expect(schema.parse({})).toEqual({});
|
||||
expect(schema.parse({ 1: "one" })).toEqual({ 1: "one" });
|
||||
expect(schema.parse({ 2: "two", 3: "three" })).toEqual({ 2: "two", 3: "three" });
|
||||
|
||||
// Should fail with unrecognized key
|
||||
expect(schema.safeParse({ 4: "four" }).success).toBe(false);
|
||||
});
|
||||
|
||||
test("partialRecord with union of string and numeric literal keys", () => {
|
||||
const StringKeys = z.literal(["a", "b", "c"]);
|
||||
const NumericKeys = z.literal([1, 2, 3]);
|
||||
const schema = z.partialRecord(z.union([StringKeys, NumericKeys]), z.string());
|
||||
type Schema = z.infer<typeof schema>;
|
||||
expectTypeOf<Schema>().toEqualTypeOf<Partial<Record<"a" | "b" | "c" | 1 | 2 | 3, string>>>();
|
||||
|
||||
// Should parse valid partials with mixed keys
|
||||
expect(schema.parse({})).toEqual({});
|
||||
expect(schema.parse({ a: "1", 2: "4" })).toEqual({ a: "1", 2: "4" });
|
||||
expect(schema.parse({ a: "a", b: "b", 1: "1", 2: "2" })).toEqual({ a: "a", b: "b", 1: "1", 2: "2" });
|
||||
|
||||
// Should fail with unrecognized key
|
||||
expect(schema.safeParse({ d: "d" }).success).toBe(false);
|
||||
expect(schema.safeParse({ 4: "4" }).success).toBe(false);
|
||||
});
|
||||
|
||||
test("looseRecord passes through non-matching keys", () => {
|
||||
const schema = z.looseRecord(z.string().regex(/^S_/), z.string());
|
||||
|
||||
// Keys matching pattern are validated
|
||||
expect(schema.parse({ S_name: "John" })).toEqual({ S_name: "John" });
|
||||
expect(() => schema.parse({ S_name: 123 })).toThrow(); // wrong value type
|
||||
|
||||
// Keys not matching pattern pass through unchanged
|
||||
expect(schema.parse({ S_name: "John", other: "value" })).toEqual({ S_name: "John", other: "value" });
|
||||
expect(schema.parse({ S_name: "John", count: 123 })).toEqual({ S_name: "John", count: 123 });
|
||||
expect(schema.parse({ other: "value" })).toEqual({ other: "value" });
|
||||
});
|
||||
|
||||
test("intersection of loose records", () => {
|
||||
const schema = z.intersection(
|
||||
z.object({ name: z.string() }).passthrough(),
|
||||
z.intersection(
|
||||
z.looseRecord(z.string().regex(/^S_/), z.string()),
|
||||
z.looseRecord(z.string().regex(/^N_/), z.number())
|
||||
)
|
||||
);
|
||||
|
||||
// Each pattern validates its matching keys
|
||||
const result = schema.parse({ name: "John", S_foo: "bar", N_count: 123 });
|
||||
expect(result.name).toBe("John");
|
||||
expect(result.S_foo).toBe("bar");
|
||||
expect(result.N_count).toBe(123);
|
||||
|
||||
// Keys not matching any pattern pass through
|
||||
const result2 = schema.parse({ name: "John", S_foo: "bar", N_count: 123, other: "value" });
|
||||
expect(result2.other).toBe("value");
|
||||
|
||||
// Validation errors still occur for matching keys
|
||||
expect(() => schema.parse({ name: "John", S_foo: 123 })).toThrow(); // S_foo should be string
|
||||
expect(() => schema.parse({ name: "John", N_count: "abc" })).toThrow(); // N_count should be number
|
||||
});
|
||||
|
||||
test("object with looseRecord index signature", () => {
|
||||
// Simulates TypeScript index signature: { label: string; [key: `label:${string}`]: string }
|
||||
const schema = z.object({ label: z.string() }).and(z.looseRecord(z.string().regex(/^label:[a-z]{2}$/), z.string()));
|
||||
|
||||
type Schema = z.infer<typeof schema>;
|
||||
expectTypeOf<Schema>().toEqualTypeOf<{ label: string } & Record<string, string>>();
|
||||
|
||||
// Valid: has required property and matching pattern keys
|
||||
expect(schema.parse({ label: "Purple", "label:en": "Purple", "label:ru": "Пурпурный" })).toEqual({
|
||||
label: "Purple",
|
||||
"label:en": "Purple",
|
||||
"label:ru": "Пурпурный",
|
||||
});
|
||||
|
||||
// Valid: just required property
|
||||
expect(schema.parse({ label: "Purple" })).toEqual({ label: "Purple" });
|
||||
|
||||
// Invalid: missing required property
|
||||
expect(schema.safeParse({ "label:en": "Purple" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"label"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
|
||||
// Invalid: pattern key with wrong value type
|
||||
expect(schema.safeParse({ label: "Purple", "label:en": 123 })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"label:en"
|
||||
],
|
||||
"message": "Invalid input: expected string, received number"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("numeric string keys", () => {
|
||||
const schema = z.record(z.number(), z.number());
|
||||
|
||||
// Numeric string keys work
|
||||
expect(schema.parse({ 1: 100, 2: 200 })).toEqual({ 1: 100, 2: 200 });
|
||||
expect(schema.parse({ "1.5": 100, "-3": 200 })).toEqual({ "1.5": 100, "-3": 200 });
|
||||
|
||||
// Non-numeric keys fail
|
||||
expect(schema.safeParse({ abc: 100 }).success).toBe(false);
|
||||
|
||||
// Integer constraint is respected
|
||||
const intSchema = z.record(z.number().int(), z.number());
|
||||
expect(intSchema.parse({ 1: 100 })).toEqual({ 1: 100 });
|
||||
expect(intSchema.safeParse({ "1.5": 100 }).success).toBe(false);
|
||||
|
||||
// Transforms on numeric keys work
|
||||
const transformedSchema = z.record(
|
||||
z.number().overwrite((n) => n * 2),
|
||||
z.string()
|
||||
);
|
||||
expect(transformedSchema.parse({ 5: "five", 10: "ten" })).toEqual({ 10: "five", 20: "ten" });
|
||||
});
|
||||
|
||||
test("v3-compat single-arg form: z.record(valueType)", () => {
|
||||
// single arg should default keyType to z.string() and use the arg as valueType
|
||||
const schema = (z.record as any)(z.number());
|
||||
expect(schema.keyType._zod.def.type).toEqual("string");
|
||||
expect(schema.valueType._zod.def.type).toEqual("number");
|
||||
|
||||
expect(schema.parse({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
||||
expect(schema.safeParse({ a: "x" }).success).toBe(false);
|
||||
|
||||
// params still flow through in the single-arg form
|
||||
const withMessage = (z.record as any)(z.number(), "must be a number record");
|
||||
expect(withMessage.keyType._zod.def.type).toEqual("string");
|
||||
expect(withMessage.valueType._zod.def.type).toEqual("number");
|
||||
|
||||
// toJSONSchema should produce a well-formed schema (regression: previously produced
|
||||
// additionalProperties from undefined valueType, crashing process())
|
||||
const json = z.toJSONSchema(schema);
|
||||
expect(json).toMatchObject({
|
||||
type: "object",
|
||||
propertyNames: { type: "string" },
|
||||
additionalProperties: { type: "number" },
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
function _write_only_error(name) {
|
||||
throw new TypeError("\"" + name + "\" is write-only");
|
||||
}
|
||||
export { _write_only_error as _ };
|
||||
@@ -0,0 +1,12 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: npm
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag use of parseInt without a radix argument
|
||||
* @author James Allardice
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("eslint-scope").Variable} Variable */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const validRadixValues = new Set(
|
||||
Array.from({ length: 37 - 2 }, (_, index) => index + 2),
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks whether a given variable is shadowed or not.
|
||||
* @param {Variable} variable A variable to check.
|
||||
* @returns {boolean} `true` if the variable is shadowed.
|
||||
*/
|
||||
function isShadowed(variable) {
|
||||
return variable.defs.length >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given node is a valid value of radix or not.
|
||||
*
|
||||
* The following values are invalid.
|
||||
*
|
||||
* - A literal except integers between 2 and 36.
|
||||
* - undefined.
|
||||
* @param {ASTNode} radix A node of radix to check.
|
||||
* @param {SourceCode} sourceCode The source code object.
|
||||
* @returns {boolean} `true` if the node is valid.
|
||||
*/
|
||||
function isValidRadix(radix, sourceCode) {
|
||||
if (
|
||||
radix.type === "UnaryExpression" &&
|
||||
(radix.operator === "-" || radix.operator === "+") &&
|
||||
radix.argument.type === "Literal" &&
|
||||
typeof radix.argument.value === "number"
|
||||
) {
|
||||
const value =
|
||||
radix.operator === "-"
|
||||
? -radix.argument.value
|
||||
: radix.argument.value;
|
||||
|
||||
return validRadixValues.has(value);
|
||||
}
|
||||
|
||||
return !(
|
||||
(radix.type === "Literal" && !validRadixValues.has(radix.value)) ||
|
||||
(radix.type === "Identifier" &&
|
||||
radix.name === "undefined" &&
|
||||
sourceCode.isGlobalReference(radix))
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce the use of the radix argument when using `parseInt()`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/radix",
|
||||
},
|
||||
|
||||
hasSuggestions: true,
|
||||
|
||||
schema: [
|
||||
// deprecated
|
||||
{
|
||||
enum: ["always", "as-needed"],
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingParameters: "Missing parameters.",
|
||||
missingRadix: "Missing radix parameter.",
|
||||
invalidRadix:
|
||||
"Invalid radix parameter, must be an integer between 2 and 36.",
|
||||
addRadixParameter10:
|
||||
"Add radix parameter `10` for parsing decimal numbers.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Checks the arguments of a given CallExpression node and reports it if it
|
||||
* offends this rule.
|
||||
* @param {ASTNode} node A CallExpression node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkArguments(node) {
|
||||
const args = node.arguments;
|
||||
const spreadIndex = args.findIndex(
|
||||
arg => arg.type === "SpreadElement",
|
||||
);
|
||||
|
||||
if (spreadIndex !== -1 && spreadIndex < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "missingParameters",
|
||||
});
|
||||
} else if (args.length === 1) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "missingRadix",
|
||||
suggest: [
|
||||
{
|
||||
messageId: "addRadixParameter10",
|
||||
fix(fixer) {
|
||||
const lastToken = sourceCode.getLastToken(node);
|
||||
const prevToken =
|
||||
sourceCode.getTokenBefore(lastToken);
|
||||
|
||||
const hasTrailingComma =
|
||||
astUtils.isCommaToken(prevToken);
|
||||
|
||||
return fixer.insertTextBefore(
|
||||
lastToken,
|
||||
hasTrailingComma ? " 10," : ", 10",
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
} else if (!isValidRadix(args[1], sourceCode)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "invalidRadix",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"Program:exit"(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
let variable;
|
||||
|
||||
// Check `parseInt()`
|
||||
variable = astUtils.getVariableByName(scope, "parseInt");
|
||||
if (variable && !isShadowed(variable)) {
|
||||
variable.references.forEach(reference => {
|
||||
const idNode = reference.identifier;
|
||||
|
||||
if (astUtils.isCallee(idNode)) {
|
||||
checkArguments(idNode.parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check `Number.parseInt()`
|
||||
variable = astUtils.getVariableByName(scope, "Number");
|
||||
if (variable && !isShadowed(variable)) {
|
||||
variable.references.forEach(reference => {
|
||||
const parentNode = reference.identifier.parent;
|
||||
const maybeCallee =
|
||||
parentNode.parent.type === "ChainExpression"
|
||||
? parentNode.parent
|
||||
: parentNode;
|
||||
|
||||
if (
|
||||
astUtils.isSpecificMemberAccess(
|
||||
parentNode,
|
||||
"Number",
|
||||
"parseInt",
|
||||
) &&
|
||||
astUtils.isCallee(maybeCallee)
|
||||
) {
|
||||
checkArguments(maybeCallee.parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,178 @@
|
||||
// Generated by LiveScript 1.6.0
|
||||
var Func, List, Obj, Str, Num, id, isType, replicate, prelude, toString$ = {}.toString;
|
||||
Func = require('./Func.js');
|
||||
List = require('./List.js');
|
||||
Obj = require('./Obj.js');
|
||||
Str = require('./Str.js');
|
||||
Num = require('./Num.js');
|
||||
id = function(x){
|
||||
return x;
|
||||
};
|
||||
isType = curry$(function(type, x){
|
||||
return toString$.call(x).slice(8, -1) === type;
|
||||
});
|
||||
replicate = curry$(function(n, x){
|
||||
var i$, results$ = [];
|
||||
for (i$ = 0; i$ < n; ++i$) {
|
||||
results$.push(x);
|
||||
}
|
||||
return results$;
|
||||
});
|
||||
Str.empty = List.empty;
|
||||
Str.slice = List.slice;
|
||||
Str.take = List.take;
|
||||
Str.drop = List.drop;
|
||||
Str.splitAt = List.splitAt;
|
||||
Str.takeWhile = List.takeWhile;
|
||||
Str.dropWhile = List.dropWhile;
|
||||
Str.span = List.span;
|
||||
Str.breakStr = List.breakList;
|
||||
prelude = {
|
||||
Func: Func,
|
||||
List: List,
|
||||
Obj: Obj,
|
||||
Str: Str,
|
||||
Num: Num,
|
||||
id: id,
|
||||
isType: isType,
|
||||
replicate: replicate
|
||||
};
|
||||
prelude.each = List.each;
|
||||
prelude.map = List.map;
|
||||
prelude.filter = List.filter;
|
||||
prelude.compact = List.compact;
|
||||
prelude.reject = List.reject;
|
||||
prelude.partition = List.partition;
|
||||
prelude.find = List.find;
|
||||
prelude.head = List.head;
|
||||
prelude.first = List.first;
|
||||
prelude.tail = List.tail;
|
||||
prelude.last = List.last;
|
||||
prelude.initial = List.initial;
|
||||
prelude.empty = List.empty;
|
||||
prelude.reverse = List.reverse;
|
||||
prelude.difference = List.difference;
|
||||
prelude.intersection = List.intersection;
|
||||
prelude.union = List.union;
|
||||
prelude.countBy = List.countBy;
|
||||
prelude.groupBy = List.groupBy;
|
||||
prelude.fold = List.fold;
|
||||
prelude.foldl = List.foldl;
|
||||
prelude.fold1 = List.fold1;
|
||||
prelude.foldl1 = List.foldl1;
|
||||
prelude.foldr = List.foldr;
|
||||
prelude.foldr1 = List.foldr1;
|
||||
prelude.unfoldr = List.unfoldr;
|
||||
prelude.andList = List.andList;
|
||||
prelude.orList = List.orList;
|
||||
prelude.any = List.any;
|
||||
prelude.all = List.all;
|
||||
prelude.unique = List.unique;
|
||||
prelude.uniqueBy = List.uniqueBy;
|
||||
prelude.sort = List.sort;
|
||||
prelude.sortWith = List.sortWith;
|
||||
prelude.sortBy = List.sortBy;
|
||||
prelude.sum = List.sum;
|
||||
prelude.product = List.product;
|
||||
prelude.mean = List.mean;
|
||||
prelude.average = List.average;
|
||||
prelude.concat = List.concat;
|
||||
prelude.concatMap = List.concatMap;
|
||||
prelude.flatten = List.flatten;
|
||||
prelude.maximum = List.maximum;
|
||||
prelude.minimum = List.minimum;
|
||||
prelude.maximumBy = List.maximumBy;
|
||||
prelude.minimumBy = List.minimumBy;
|
||||
prelude.scan = List.scan;
|
||||
prelude.scanl = List.scanl;
|
||||
prelude.scan1 = List.scan1;
|
||||
prelude.scanl1 = List.scanl1;
|
||||
prelude.scanr = List.scanr;
|
||||
prelude.scanr1 = List.scanr1;
|
||||
prelude.slice = List.slice;
|
||||
prelude.take = List.take;
|
||||
prelude.drop = List.drop;
|
||||
prelude.splitAt = List.splitAt;
|
||||
prelude.takeWhile = List.takeWhile;
|
||||
prelude.dropWhile = List.dropWhile;
|
||||
prelude.span = List.span;
|
||||
prelude.breakList = List.breakList;
|
||||
prelude.zip = List.zip;
|
||||
prelude.zipWith = List.zipWith;
|
||||
prelude.zipAll = List.zipAll;
|
||||
prelude.zipAllWith = List.zipAllWith;
|
||||
prelude.at = List.at;
|
||||
prelude.elemIndex = List.elemIndex;
|
||||
prelude.elemIndices = List.elemIndices;
|
||||
prelude.findIndex = List.findIndex;
|
||||
prelude.findIndices = List.findIndices;
|
||||
prelude.apply = Func.apply;
|
||||
prelude.curry = Func.curry;
|
||||
prelude.flip = Func.flip;
|
||||
prelude.fix = Func.fix;
|
||||
prelude.over = Func.over;
|
||||
prelude.split = Str.split;
|
||||
prelude.join = Str.join;
|
||||
prelude.lines = Str.lines;
|
||||
prelude.unlines = Str.unlines;
|
||||
prelude.words = Str.words;
|
||||
prelude.unwords = Str.unwords;
|
||||
prelude.chars = Str.chars;
|
||||
prelude.unchars = Str.unchars;
|
||||
prelude.repeat = Str.repeat;
|
||||
prelude.capitalize = Str.capitalize;
|
||||
prelude.camelize = Str.camelize;
|
||||
prelude.dasherize = Str.dasherize;
|
||||
prelude.values = Obj.values;
|
||||
prelude.keys = Obj.keys;
|
||||
prelude.pairsToObj = Obj.pairsToObj;
|
||||
prelude.objToPairs = Obj.objToPairs;
|
||||
prelude.listsToObj = Obj.listsToObj;
|
||||
prelude.objToLists = Obj.objToLists;
|
||||
prelude.max = Num.max;
|
||||
prelude.min = Num.min;
|
||||
prelude.negate = Num.negate;
|
||||
prelude.abs = Num.abs;
|
||||
prelude.signum = Num.signum;
|
||||
prelude.quot = Num.quot;
|
||||
prelude.rem = Num.rem;
|
||||
prelude.div = Num.div;
|
||||
prelude.mod = Num.mod;
|
||||
prelude.recip = Num.recip;
|
||||
prelude.pi = Num.pi;
|
||||
prelude.tau = Num.tau;
|
||||
prelude.exp = Num.exp;
|
||||
prelude.sqrt = Num.sqrt;
|
||||
prelude.ln = Num.ln;
|
||||
prelude.pow = Num.pow;
|
||||
prelude.sin = Num.sin;
|
||||
prelude.tan = Num.tan;
|
||||
prelude.cos = Num.cos;
|
||||
prelude.acos = Num.acos;
|
||||
prelude.asin = Num.asin;
|
||||
prelude.atan = Num.atan;
|
||||
prelude.atan2 = Num.atan2;
|
||||
prelude.truncate = Num.truncate;
|
||||
prelude.round = Num.round;
|
||||
prelude.ceiling = Num.ceiling;
|
||||
prelude.floor = Num.floor;
|
||||
prelude.isItNaN = Num.isItNaN;
|
||||
prelude.even = Num.even;
|
||||
prelude.odd = Num.odd;
|
||||
prelude.gcd = Num.gcd;
|
||||
prelude.lcm = Num.lcm;
|
||||
prelude.VERSION = '1.2.1';
|
||||
module.exports = prelude;
|
||||
function curry$(f, bound){
|
||||
var context,
|
||||
_curry = function(args) {
|
||||
return f.length > 1 ? function(){
|
||||
var params = args ? args.concat() : [];
|
||||
context = bound ? context || this : this;
|
||||
return params.push.apply(params, arguments) <
|
||||
f.length && arguments.length ?
|
||||
_curry.call(context, params) : f.apply(context, params);
|
||||
} : f;
|
||||
};
|
||||
return _curry();
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.NoticeMessage = exports.DataRowMessage = exports.CommandCompleteMessage = exports.ReadyForQueryMessage = exports.NotificationResponseMessage = exports.BackendKeyDataMessage = exports.AuthenticationMD5Password = exports.ParameterStatusMessage = exports.ParameterDescriptionMessage = exports.RowDescriptionMessage = exports.Field = exports.CopyResponse = exports.CopyDataMessage = exports.DatabaseError = exports.copyDone = exports.emptyQuery = exports.replicationStart = exports.portalSuspended = exports.noData = exports.closeComplete = exports.bindComplete = exports.parseComplete = void 0;
|
||||
exports.parseComplete = {
|
||||
name: 'parseComplete',
|
||||
length: 5,
|
||||
};
|
||||
exports.bindComplete = {
|
||||
name: 'bindComplete',
|
||||
length: 5,
|
||||
};
|
||||
exports.closeComplete = {
|
||||
name: 'closeComplete',
|
||||
length: 5,
|
||||
};
|
||||
exports.noData = {
|
||||
name: 'noData',
|
||||
length: 5,
|
||||
};
|
||||
exports.portalSuspended = {
|
||||
name: 'portalSuspended',
|
||||
length: 5,
|
||||
};
|
||||
exports.replicationStart = {
|
||||
name: 'replicationStart',
|
||||
length: 4,
|
||||
};
|
||||
exports.emptyQuery = {
|
||||
name: 'emptyQuery',
|
||||
length: 4,
|
||||
};
|
||||
exports.copyDone = {
|
||||
name: 'copyDone',
|
||||
length: 4,
|
||||
};
|
||||
class DatabaseError extends Error {
|
||||
constructor(message, length, name) {
|
||||
super(message);
|
||||
this.length = length;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
exports.DatabaseError = DatabaseError;
|
||||
class CopyDataMessage {
|
||||
constructor(length, chunk) {
|
||||
this.length = length;
|
||||
this.chunk = chunk;
|
||||
this.name = 'copyData';
|
||||
}
|
||||
}
|
||||
exports.CopyDataMessage = CopyDataMessage;
|
||||
class CopyResponse {
|
||||
constructor(length, name, binary, columnCount) {
|
||||
this.length = length;
|
||||
this.name = name;
|
||||
this.binary = binary;
|
||||
this.columnTypes = new Array(columnCount);
|
||||
}
|
||||
}
|
||||
exports.CopyResponse = CopyResponse;
|
||||
class Field {
|
||||
constructor(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, format) {
|
||||
this.name = name;
|
||||
this.tableID = tableID;
|
||||
this.columnID = columnID;
|
||||
this.dataTypeID = dataTypeID;
|
||||
this.dataTypeSize = dataTypeSize;
|
||||
this.dataTypeModifier = dataTypeModifier;
|
||||
this.format = format;
|
||||
}
|
||||
}
|
||||
exports.Field = Field;
|
||||
class RowDescriptionMessage {
|
||||
constructor(length, fieldCount) {
|
||||
this.length = length;
|
||||
this.fieldCount = fieldCount;
|
||||
this.name = 'rowDescription';
|
||||
this.fields = new Array(this.fieldCount);
|
||||
}
|
||||
}
|
||||
exports.RowDescriptionMessage = RowDescriptionMessage;
|
||||
class ParameterDescriptionMessage {
|
||||
constructor(length, parameterCount) {
|
||||
this.length = length;
|
||||
this.parameterCount = parameterCount;
|
||||
this.name = 'parameterDescription';
|
||||
this.dataTypeIDs = new Array(this.parameterCount);
|
||||
}
|
||||
}
|
||||
exports.ParameterDescriptionMessage = ParameterDescriptionMessage;
|
||||
class ParameterStatusMessage {
|
||||
constructor(length, parameterName, parameterValue) {
|
||||
this.length = length;
|
||||
this.parameterName = parameterName;
|
||||
this.parameterValue = parameterValue;
|
||||
this.name = 'parameterStatus';
|
||||
}
|
||||
}
|
||||
exports.ParameterStatusMessage = ParameterStatusMessage;
|
||||
class AuthenticationMD5Password {
|
||||
constructor(length, salt) {
|
||||
this.length = length;
|
||||
this.salt = salt;
|
||||
this.name = 'authenticationMD5Password';
|
||||
}
|
||||
}
|
||||
exports.AuthenticationMD5Password = AuthenticationMD5Password;
|
||||
class BackendKeyDataMessage {
|
||||
constructor(length, processID, secretKey) {
|
||||
this.length = length;
|
||||
this.processID = processID;
|
||||
this.secretKey = secretKey;
|
||||
this.name = 'backendKeyData';
|
||||
}
|
||||
}
|
||||
exports.BackendKeyDataMessage = BackendKeyDataMessage;
|
||||
class NotificationResponseMessage {
|
||||
constructor(length, processId, channel, payload) {
|
||||
this.length = length;
|
||||
this.processId = processId;
|
||||
this.channel = channel;
|
||||
this.payload = payload;
|
||||
this.name = 'notification';
|
||||
}
|
||||
}
|
||||
exports.NotificationResponseMessage = NotificationResponseMessage;
|
||||
class ReadyForQueryMessage {
|
||||
constructor(length, status) {
|
||||
this.length = length;
|
||||
this.status = status;
|
||||
this.name = 'readyForQuery';
|
||||
}
|
||||
}
|
||||
exports.ReadyForQueryMessage = ReadyForQueryMessage;
|
||||
class CommandCompleteMessage {
|
||||
constructor(length, text) {
|
||||
this.length = length;
|
||||
this.text = text;
|
||||
this.name = 'commandComplete';
|
||||
}
|
||||
}
|
||||
exports.CommandCompleteMessage = CommandCompleteMessage;
|
||||
class DataRowMessage {
|
||||
constructor(length, fields) {
|
||||
this.length = length;
|
||||
this.fields = fields;
|
||||
this.name = 'dataRow';
|
||||
this.fieldCount = fields.length;
|
||||
}
|
||||
}
|
||||
exports.DataRowMessage = DataRowMessage;
|
||||
class NoticeMessage {
|
||||
constructor(length, message) {
|
||||
this.length = length;
|
||||
this.message = message;
|
||||
this.name = 'notice';
|
||||
}
|
||||
}
|
||||
exports.NoticeMessage = NoticeMessage;
|
||||
//# sourceMappingURL=messages.js.map
|
||||
@@ -0,0 +1,10 @@
|
||||
import isNativeReflectConstruct from "./isNativeReflectConstruct.js";
|
||||
import setPrototypeOf from "./setPrototypeOf.js";
|
||||
function _construct(t, e, r) {
|
||||
if (isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
|
||||
var o = [null];
|
||||
o.push.apply(o, e);
|
||||
var p = new (t.bind.apply(t, o))();
|
||||
return r && setPrototypeOf(p, r.prototype), p;
|
||||
}
|
||||
export { _construct as default };
|
||||
@@ -0,0 +1,21 @@
|
||||
export function objectOrFunction(x) {
|
||||
let type = typeof x;
|
||||
return x !== null && (type === 'object' || type === 'function');
|
||||
}
|
||||
|
||||
export function isFunction(x) {
|
||||
return typeof x === 'function';
|
||||
}
|
||||
|
||||
export function isMaybeThenable(x) {
|
||||
return x !== null && typeof x === 'object';
|
||||
}
|
||||
|
||||
let _isArray;
|
||||
if (Array.isArray) {
|
||||
_isArray = Array.isArray;
|
||||
} else {
|
||||
_isArray = x => Object.prototype.toString.call(x) === '[object Array]';
|
||||
}
|
||||
|
||||
export const isArray = _isArray;
|
||||
@@ -0,0 +1,558 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Referencer = void 0;
|
||||
const types_1 = require("@typescript-eslint/types");
|
||||
const assert_1 = require("../assert");
|
||||
const definition_1 = require("../definition");
|
||||
const lib_1 = require("../lib");
|
||||
const ClassVisitor_1 = require("./ClassVisitor");
|
||||
const ExportVisitor_1 = require("./ExportVisitor");
|
||||
const ImportVisitor_1 = require("./ImportVisitor");
|
||||
const PatternVisitor_1 = require("./PatternVisitor");
|
||||
const Reference_1 = require("./Reference");
|
||||
const TypeVisitor_1 = require("./TypeVisitor");
|
||||
const Visitor_1 = require("./Visitor");
|
||||
// Referencing variables and creating bindings.
|
||||
class Referencer extends Visitor_1.Visitor {
|
||||
#hasReferencedJsxFactory = false;
|
||||
#hasReferencedJsxFragmentFactory = false;
|
||||
#jsxFragmentName;
|
||||
#jsxPragma;
|
||||
#lib;
|
||||
scopeManager;
|
||||
constructor(options, scopeManager) {
|
||||
super(options);
|
||||
this.scopeManager = scopeManager;
|
||||
this.#jsxPragma = options.jsxPragma;
|
||||
this.#jsxFragmentName = options.jsxFragmentName;
|
||||
this.#lib = options.lib;
|
||||
}
|
||||
populateGlobalsFromLib(globalScope) {
|
||||
const libs = this.resolveLibDefinitions();
|
||||
for (const lib of libs) {
|
||||
for (const [name, variable] of lib.variables) {
|
||||
globalScope.defineImplicitVariable(name, variable);
|
||||
}
|
||||
}
|
||||
// Special implicit global for const assertions (`{} as const`, `<const>{}`)
|
||||
globalScope.defineImplicitVariable('const', {
|
||||
eslintImplicitGlobalSetting: 'readonly',
|
||||
isTypeVariable: true,
|
||||
isValueVariable: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Resolves lib names into a deduplicated set of LibDefinitions,
|
||||
* including all transitive dependencies.
|
||||
*/
|
||||
resolveLibDefinitions() {
|
||||
const resolvedLibs = new Set();
|
||||
// Resolve the top-level lib names into LibDefinition objects
|
||||
for (const lib of this.#lib) {
|
||||
const definition = lib_1.lib.get(lib);
|
||||
if (!definition) {
|
||||
throw new Error(`Invalid value for lib provided: ${lib}`);
|
||||
}
|
||||
resolvedLibs.add(definition);
|
||||
}
|
||||
// Expand transitive lib dependencies.
|
||||
// New entries added to the Set during iteration will be visited exactly once.
|
||||
for (const lib of resolvedLibs) {
|
||||
for (const dependency of lib.libs) {
|
||||
resolvedLibs.add(dependency);
|
||||
}
|
||||
}
|
||||
return resolvedLibs;
|
||||
}
|
||||
close(node) {
|
||||
while (this.currentScope(true) && node === this.currentScope().block) {
|
||||
this.scopeManager.currentScope = this.currentScope().close(this.scopeManager);
|
||||
}
|
||||
}
|
||||
currentScope(dontThrowOnNull) {
|
||||
if (!dontThrowOnNull) {
|
||||
(0, assert_1.assert)(this.scopeManager.currentScope, 'Expected currentScope to exist. This usually happens when analyze() is called with an incomplete AST node instead of a complete Program node.');
|
||||
}
|
||||
return this.scopeManager.currentScope;
|
||||
}
|
||||
referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) {
|
||||
assignments.forEach(assignment => {
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.Write, assignment.right, maybeImplicitGlobal, init);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Searches for a variable named "name" in the upper scopes and adds a pseudo-reference from itself to itself
|
||||
*/
|
||||
referenceInSomeUpperScope(name) {
|
||||
let scope = this.scopeManager.currentScope;
|
||||
while (scope) {
|
||||
const variable = scope.set.get(name);
|
||||
if (!variable) {
|
||||
scope = scope.upper;
|
||||
continue;
|
||||
}
|
||||
scope.referenceValue(variable.identifiers[0]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
referenceJsxFragment() {
|
||||
if (this.#jsxFragmentName == null ||
|
||||
this.#hasReferencedJsxFragmentFactory) {
|
||||
return;
|
||||
}
|
||||
this.#hasReferencedJsxFragmentFactory = this.referenceInSomeUpperScope(this.#jsxFragmentName);
|
||||
}
|
||||
referenceJsxPragma() {
|
||||
if (this.#jsxPragma == null || this.#hasReferencedJsxFactory) {
|
||||
return;
|
||||
}
|
||||
this.#hasReferencedJsxFactory = this.referenceInSomeUpperScope(this.#jsxPragma);
|
||||
}
|
||||
///////////////////
|
||||
// Visit helpers //
|
||||
///////////////////
|
||||
visitClass(node) {
|
||||
ClassVisitor_1.ClassVisitor.visit(this, node);
|
||||
}
|
||||
visitForIn(node) {
|
||||
if (node.left.type === types_1.AST_NODE_TYPES.VariableDeclaration &&
|
||||
node.left.kind !== 'var') {
|
||||
this.scopeManager.nestForScope(node);
|
||||
}
|
||||
if (node.left.type === types_1.AST_NODE_TYPES.VariableDeclaration) {
|
||||
this.visit(node.left);
|
||||
this.visitPattern(node.left.declarations[0].id, pattern => {
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.Write, node.right, null, true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.visitPattern(node.left, (pattern, info) => {
|
||||
const maybeImplicitGlobal = !this.currentScope().isStrict
|
||||
? {
|
||||
node,
|
||||
pattern,
|
||||
}
|
||||
: null;
|
||||
this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.Write, node.right, maybeImplicitGlobal, false);
|
||||
}, { processRightHandNodes: true });
|
||||
}
|
||||
this.visit(node.right);
|
||||
this.visit(node.body);
|
||||
this.close(node);
|
||||
}
|
||||
visitFunction(node) {
|
||||
// FunctionDeclaration name is defined in upper scope
|
||||
// NOTE: Not referring variableScope. It is intended.
|
||||
// Since
|
||||
// in ES5, FunctionDeclaration should be in FunctionBody.
|
||||
// in ES6, FunctionDeclaration should be block scoped.
|
||||
if (node.type === types_1.AST_NODE_TYPES.FunctionExpression) {
|
||||
if (node.id) {
|
||||
// FunctionExpression with name creates its special scope;
|
||||
// FunctionExpressionNameScope.
|
||||
this.scopeManager.nestFunctionExpressionNameScope(node);
|
||||
}
|
||||
}
|
||||
else if (node.id) {
|
||||
// id is defined in upper scope
|
||||
this.currentScope().defineIdentifier(node.id, new definition_1.FunctionNameDefinition(node.id, node));
|
||||
}
|
||||
// Consider this function is in the MethodDefinition.
|
||||
this.scopeManager.nestFunctionScope(node, false);
|
||||
// Process parameter declarations.
|
||||
for (const param of node.params) {
|
||||
this.visitPattern(param, (pattern, info) => {
|
||||
this.currentScope().defineIdentifier(pattern, new definition_1.ParameterDefinition(pattern, node, info.rest));
|
||||
this.referencingDefaultValue(pattern, info.assignments, null, true);
|
||||
}, { processRightHandNodes: true });
|
||||
this.visitFunctionParameterTypeAnnotation(param);
|
||||
param.decorators.forEach(d => this.visit(d));
|
||||
}
|
||||
this.visitType(node.returnType);
|
||||
this.visitType(node.typeParameters);
|
||||
// In TypeScript there are a number of function-like constructs which have no body,
|
||||
// so check it exists before traversing
|
||||
if (node.body) {
|
||||
// Skip BlockStatement to prevent creating BlockStatement scope.
|
||||
if (node.body.type === types_1.AST_NODE_TYPES.BlockStatement) {
|
||||
this.visitChildren(node.body);
|
||||
}
|
||||
else {
|
||||
this.visit(node.body);
|
||||
}
|
||||
}
|
||||
this.close(node);
|
||||
}
|
||||
visitFunctionParameterTypeAnnotation(node) {
|
||||
switch (node.type) {
|
||||
case types_1.AST_NODE_TYPES.AssignmentPattern:
|
||||
this.visitType(node.left.typeAnnotation);
|
||||
break;
|
||||
case types_1.AST_NODE_TYPES.TSParameterProperty:
|
||||
this.visitFunctionParameterTypeAnnotation(node.parameter);
|
||||
break;
|
||||
default:
|
||||
this.visitType(node.typeAnnotation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
visitJSXElement(node) {
|
||||
if (node.name.type === types_1.AST_NODE_TYPES.JSXIdentifier) {
|
||||
if (node.name.name[0].toUpperCase() === node.name.name[0] ||
|
||||
node.name.name === 'this') {
|
||||
// lower cased component names are always treated as "intrinsic" names, and are converted to a string,
|
||||
// not a variable by JSX transforms:
|
||||
// <div /> => React.createElement("div", null)
|
||||
// the only case we want to visit a lower-cased component has its name as "this",
|
||||
this.visit(node.name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.visit(node.name);
|
||||
}
|
||||
}
|
||||
visitProperty(node) {
|
||||
if (node.computed) {
|
||||
this.visit(node.key);
|
||||
}
|
||||
this.visit(node.value);
|
||||
}
|
||||
visitType(node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
TypeVisitor_1.TypeVisitor.visit(this, node);
|
||||
}
|
||||
visitTypeAssertion(node) {
|
||||
this.visit(node.expression);
|
||||
this.visitType(node.typeAnnotation);
|
||||
}
|
||||
/////////////////////
|
||||
// Visit selectors //
|
||||
/////////////////////
|
||||
ArrowFunctionExpression(node) {
|
||||
this.visitFunction(node);
|
||||
}
|
||||
AssignmentExpression(node) {
|
||||
const left = this.visitExpressionTarget(node.left);
|
||||
if (PatternVisitor_1.PatternVisitor.isPattern(left)) {
|
||||
if (node.operator === '=') {
|
||||
this.visitPattern(left, (pattern, info) => {
|
||||
const maybeImplicitGlobal = !this.currentScope().isStrict
|
||||
? {
|
||||
node,
|
||||
pattern,
|
||||
}
|
||||
: null;
|
||||
this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.Write, node.right, maybeImplicitGlobal, false);
|
||||
}, { processRightHandNodes: true });
|
||||
}
|
||||
else if (left.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
this.currentScope().referenceValue(left, Reference_1.ReferenceFlag.ReadWrite, node.right);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.visit(left);
|
||||
}
|
||||
this.visit(node.right);
|
||||
}
|
||||
BlockStatement(node) {
|
||||
this.scopeManager.nestBlockScope(node);
|
||||
this.visitChildren(node);
|
||||
this.close(node);
|
||||
}
|
||||
BreakStatement() {
|
||||
// don't reference the break statement's label
|
||||
}
|
||||
CallExpression(node) {
|
||||
this.visitChildren(node, ['typeArguments']);
|
||||
this.visitType(node.typeArguments);
|
||||
}
|
||||
CatchClause(node) {
|
||||
this.scopeManager.nestCatchScope(node);
|
||||
if (node.param) {
|
||||
this.visitPattern(node.param, (pattern, info) => {
|
||||
this.currentScope().defineIdentifier(pattern, new definition_1.CatchClauseDefinition(pattern, node));
|
||||
this.referencingDefaultValue(pattern, info.assignments, null, true);
|
||||
}, { processRightHandNodes: true });
|
||||
}
|
||||
this.visit(node.body);
|
||||
this.close(node);
|
||||
}
|
||||
ClassDeclaration(node) {
|
||||
this.visitClass(node);
|
||||
}
|
||||
ClassExpression(node) {
|
||||
this.visitClass(node);
|
||||
}
|
||||
ContinueStatement() {
|
||||
// don't reference the continue statement's label
|
||||
}
|
||||
ExportAllDeclaration() {
|
||||
// this defines no local variables
|
||||
}
|
||||
ExportDefaultDeclaration(node) {
|
||||
if (node.declaration.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
ExportVisitor_1.ExportVisitor.visit(this, node);
|
||||
}
|
||||
else {
|
||||
this.visit(node.declaration);
|
||||
}
|
||||
}
|
||||
ExportNamedDeclaration(node) {
|
||||
if (node.declaration) {
|
||||
this.visit(node.declaration);
|
||||
}
|
||||
else {
|
||||
ExportVisitor_1.ExportVisitor.visit(this, node);
|
||||
}
|
||||
}
|
||||
ForInStatement(node) {
|
||||
this.visitForIn(node);
|
||||
}
|
||||
ForOfStatement(node) {
|
||||
this.visitForIn(node);
|
||||
}
|
||||
ForStatement(node) {
|
||||
// Create ForStatement declaration.
|
||||
// NOTE: In ES6, ForStatement dynamically generates per iteration environment. However, this is
|
||||
// a static analyzer, we only generate one scope for ForStatement.
|
||||
if (node.init?.type === types_1.AST_NODE_TYPES.VariableDeclaration &&
|
||||
node.init.kind !== 'var') {
|
||||
this.scopeManager.nestForScope(node);
|
||||
}
|
||||
this.visitChildren(node);
|
||||
this.close(node);
|
||||
}
|
||||
FunctionDeclaration(node) {
|
||||
this.visitFunction(node);
|
||||
}
|
||||
FunctionExpression(node) {
|
||||
this.visitFunction(node);
|
||||
}
|
||||
Identifier(node) {
|
||||
this.currentScope().referenceValue(node);
|
||||
this.visitType(node.typeAnnotation);
|
||||
}
|
||||
ImportAttribute() {
|
||||
// import assertions are module metadata and thus have no variables to reference
|
||||
}
|
||||
ImportDeclaration(node) {
|
||||
(0, assert_1.assert)(this.scopeManager.isModule(), 'ImportDeclaration should appear when the mode is ES6 and in the module context.');
|
||||
ImportVisitor_1.ImportVisitor.visit(this, node);
|
||||
}
|
||||
JSXAttribute(node) {
|
||||
this.visit(node.value);
|
||||
}
|
||||
JSXClosingElement(node) {
|
||||
this.visitJSXElement(node);
|
||||
}
|
||||
JSXFragment(node) {
|
||||
this.referenceJsxPragma();
|
||||
this.referenceJsxFragment();
|
||||
this.visitChildren(node);
|
||||
}
|
||||
JSXIdentifier(node) {
|
||||
this.currentScope().referenceValue(node);
|
||||
}
|
||||
JSXMemberExpression(node) {
|
||||
if (node.object.type !== types_1.AST_NODE_TYPES.JSXIdentifier ||
|
||||
node.object.name !== 'this') {
|
||||
this.visit(node.object);
|
||||
}
|
||||
// we don't ever reference the property as it's always going to be a property on the thing
|
||||
}
|
||||
JSXOpeningElement(node) {
|
||||
this.referenceJsxPragma();
|
||||
this.visitJSXElement(node);
|
||||
this.visitType(node.typeArguments);
|
||||
for (const attr of node.attributes) {
|
||||
this.visit(attr);
|
||||
}
|
||||
}
|
||||
LabeledStatement(node) {
|
||||
this.visit(node.body);
|
||||
}
|
||||
MemberExpression(node) {
|
||||
this.visit(node.object);
|
||||
if (node.computed) {
|
||||
this.visit(node.property);
|
||||
}
|
||||
}
|
||||
MetaProperty() {
|
||||
// meta properties all builtin globals
|
||||
}
|
||||
NewExpression(node) {
|
||||
this.visitChildren(node, ['typeArguments']);
|
||||
this.visitType(node.typeArguments);
|
||||
}
|
||||
PrivateIdentifier() {
|
||||
// private identifiers are members on classes and thus have no variables to reference
|
||||
}
|
||||
Program(node) {
|
||||
const globalScope = this.scopeManager.nestGlobalScope(node);
|
||||
this.populateGlobalsFromLib(globalScope);
|
||||
if (this.scopeManager.isGlobalReturn()) {
|
||||
// Force strictness of GlobalScope to false when using node.js scope.
|
||||
this.currentScope().isStrict = false;
|
||||
this.scopeManager.nestFunctionScope(node, false);
|
||||
}
|
||||
if (this.scopeManager.isModule()) {
|
||||
this.scopeManager.nestModuleScope(node);
|
||||
}
|
||||
if (this.scopeManager.isImpliedStrict()) {
|
||||
this.currentScope().isStrict = true;
|
||||
}
|
||||
this.visitChildren(node);
|
||||
this.close(node);
|
||||
}
|
||||
Property(node) {
|
||||
this.visitProperty(node);
|
||||
}
|
||||
SwitchStatement(node) {
|
||||
this.visit(node.discriminant);
|
||||
this.scopeManager.nestSwitchScope(node);
|
||||
for (const switchCase of node.cases) {
|
||||
this.visit(switchCase);
|
||||
}
|
||||
this.close(node);
|
||||
}
|
||||
TaggedTemplateExpression(node) {
|
||||
this.visit(node.tag);
|
||||
this.visit(node.quasi);
|
||||
this.visitType(node.typeArguments);
|
||||
}
|
||||
TSAsExpression(node) {
|
||||
this.visitTypeAssertion(node);
|
||||
}
|
||||
TSDeclareFunction(node) {
|
||||
this.visitFunction(node);
|
||||
}
|
||||
TSEmptyBodyFunctionExpression(node) {
|
||||
this.visitFunction(node);
|
||||
}
|
||||
TSEnumDeclaration(node) {
|
||||
this.currentScope().defineIdentifier(node.id, new definition_1.TSEnumNameDefinition(node.id, node));
|
||||
// enum members can be referenced within the enum body
|
||||
this.scopeManager.nestTSEnumScope(node);
|
||||
for (const member of node.body.members) {
|
||||
// TS resolves literal named members to be actual names
|
||||
// enum Foo {
|
||||
// 'a' = 1,
|
||||
// b = a, // this references the 'a' member
|
||||
// }
|
||||
if (member.id.type === types_1.AST_NODE_TYPES.Literal &&
|
||||
typeof member.id.value === 'string') {
|
||||
const name = member.id;
|
||||
this.currentScope().defineLiteralIdentifier(name, new definition_1.TSEnumMemberDefinition(name, member));
|
||||
}
|
||||
else if (member.id.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
this.currentScope().defineIdentifier(member.id, new definition_1.TSEnumMemberDefinition(member.id, member));
|
||||
}
|
||||
this.visit(member.initializer);
|
||||
}
|
||||
this.close(node);
|
||||
}
|
||||
TSExportAssignment(node) {
|
||||
if (node.expression.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
// this is a special case - you can `export = T` where `T` is a type OR a
|
||||
// value however `T[U]` is illegal when `T` is a type and `T.U` is illegal
|
||||
// when `T.U` is a type
|
||||
// i.e. if the expression is JUST an Identifier - it could be either ref
|
||||
// kind; otherwise the standard rules apply
|
||||
this.currentScope().referenceDualValueType(node.expression);
|
||||
}
|
||||
else {
|
||||
this.visit(node.expression);
|
||||
}
|
||||
}
|
||||
TSImportEqualsDeclaration(node) {
|
||||
this.currentScope().defineIdentifier(node.id, new definition_1.ImportBindingDefinition(node.id, node, node));
|
||||
if (node.moduleReference.type === types_1.AST_NODE_TYPES.TSQualifiedName) {
|
||||
let moduleIdentifier = node.moduleReference.left;
|
||||
while (moduleIdentifier.type === types_1.AST_NODE_TYPES.TSQualifiedName) {
|
||||
moduleIdentifier = moduleIdentifier.left;
|
||||
}
|
||||
this.visit(moduleIdentifier);
|
||||
}
|
||||
else {
|
||||
this.visit(node.moduleReference);
|
||||
}
|
||||
}
|
||||
TSInstantiationExpression(node) {
|
||||
this.visitChildren(node, ['typeArguments']);
|
||||
this.visitType(node.typeArguments);
|
||||
}
|
||||
TSInterfaceDeclaration(node) {
|
||||
this.visitType(node);
|
||||
}
|
||||
TSModuleDeclaration(node) {
|
||||
if (node.id.type === types_1.AST_NODE_TYPES.Identifier && node.kind !== 'global') {
|
||||
this.currentScope().defineIdentifier(node.id, new definition_1.TSModuleNameDefinition(node.id, node));
|
||||
}
|
||||
this.scopeManager.nestTSModuleScope(node);
|
||||
this.visit(node.body);
|
||||
this.close(node);
|
||||
}
|
||||
TSSatisfiesExpression(node) {
|
||||
this.visitTypeAssertion(node);
|
||||
}
|
||||
TSTypeAliasDeclaration(node) {
|
||||
this.visitType(node);
|
||||
}
|
||||
TSTypeAssertion(node) {
|
||||
this.visitTypeAssertion(node);
|
||||
}
|
||||
UpdateExpression(node) {
|
||||
const argument = this.visitExpressionTarget(node.argument);
|
||||
if (PatternVisitor_1.PatternVisitor.isPattern(argument)) {
|
||||
this.visitPattern(argument, pattern => {
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.ReadWrite, null);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.visitChildren(node);
|
||||
}
|
||||
}
|
||||
VariableDeclaration(node) {
|
||||
const variableTargetScope = node.kind === 'var'
|
||||
? this.currentScope().variableScope
|
||||
: this.currentScope();
|
||||
for (const decl of node.declarations) {
|
||||
const init = decl.init;
|
||||
this.visitPattern(decl.id, (pattern, info) => {
|
||||
variableTargetScope.defineIdentifier(pattern, new definition_1.VariableDefinition(pattern, decl, node));
|
||||
this.referencingDefaultValue(pattern, info.assignments, null, true);
|
||||
if (init) {
|
||||
this.currentScope().referenceValue(pattern, Reference_1.ReferenceFlag.Write, init, null, true);
|
||||
}
|
||||
}, { processRightHandNodes: true });
|
||||
this.visit(decl.init);
|
||||
this.visitType(decl.id.typeAnnotation);
|
||||
}
|
||||
}
|
||||
WithStatement(node) {
|
||||
this.visit(node.object);
|
||||
// Then nest scope for WithStatement.
|
||||
this.scopeManager.nestWithScope(node);
|
||||
this.visit(node.body);
|
||||
this.close(node);
|
||||
}
|
||||
visitExpressionTarget(left) {
|
||||
switch (left.type) {
|
||||
case types_1.AST_NODE_TYPES.TSAsExpression:
|
||||
case types_1.AST_NODE_TYPES.TSTypeAssertion:
|
||||
// explicitly visit the type annotation
|
||||
this.visitType(left.typeAnnotation);
|
||||
// intentional fallthrough
|
||||
case types_1.AST_NODE_TYPES.TSNonNullExpression:
|
||||
// unwrap the expression
|
||||
left = left.expression;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
}
|
||||
exports.Referencer = Referencer;
|
||||
@@ -0,0 +1,32 @@
|
||||
import { h as BindingReplacePluginConfig } from "./shared/binding-CVtkJvyl.mjs";
|
||||
import { I as BuiltinPlugin } from "./shared/define-config-Dsp5YQR4.mjs";
|
||||
import { t as esmExternalRequirePlugin } from "./shared/constructors-CGzna3vk.mjs";
|
||||
//#region src/builtin-plugin/replace-plugin.d.ts
|
||||
/**
|
||||
* Replaces targeted strings in files while bundling.
|
||||
*
|
||||
* @example
|
||||
* **Basic usage**
|
||||
* ```js
|
||||
* replacePlugin({
|
||||
* 'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
* __buildVersion: 15
|
||||
* })
|
||||
* ```
|
||||
* @example
|
||||
* **With options**
|
||||
* ```js
|
||||
* replacePlugin({
|
||||
* 'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
* __buildVersion: 15
|
||||
* }, {
|
||||
* preventAssignment: false,
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @see https://rolldown.rs/builtin-plugins/replace
|
||||
* @category Builtin Plugins
|
||||
*/
|
||||
declare function replacePlugin(values?: BindingReplacePluginConfig["values"], options?: Omit<BindingReplacePluginConfig, "values">): BuiltinPlugin;
|
||||
//#endregion
|
||||
export { esmExternalRequirePlugin, replacePlugin };
|
||||
@@ -0,0 +1,3 @@
|
||||
import type { TSESTree } from '@typescript-eslint/utils';
|
||||
import type { SourceCode } from '@typescript-eslint/utils/ts-eslint';
|
||||
export declare function getTextWithParentheses(sourceCode: Readonly<SourceCode>, node: TSESTree.Node): string;
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
Copyright (c) 2009-2011, Mozilla Foundation and contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the Mozilla Foundation nor the names of project
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../util");
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'default-param-last',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Enforce default parameters to be last',
|
||||
extendsBaseRule: true,
|
||||
frozen: true,
|
||||
},
|
||||
messages: {
|
||||
shouldBeLast: 'Default parameters should be last.',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
/**
|
||||
* checks if node is optional parameter
|
||||
* @param node the node to be evaluated
|
||||
* @private
|
||||
*/
|
||||
function isOptionalParam(node) {
|
||||
return ((node.type === utils_1.AST_NODE_TYPES.ArrayPattern ||
|
||||
node.type === utils_1.AST_NODE_TYPES.AssignmentPattern ||
|
||||
node.type === utils_1.AST_NODE_TYPES.Identifier ||
|
||||
node.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
||||
node.type === utils_1.AST_NODE_TYPES.RestElement) &&
|
||||
node.optional);
|
||||
}
|
||||
/**
|
||||
* checks if node is plain parameter
|
||||
* @param node the node to be evaluated
|
||||
* @private
|
||||
*/
|
||||
function isPlainParam(node) {
|
||||
return !(node.type === utils_1.AST_NODE_TYPES.AssignmentPattern ||
|
||||
node.type === utils_1.AST_NODE_TYPES.RestElement ||
|
||||
isOptionalParam(node));
|
||||
}
|
||||
function checkDefaultParamLast(node) {
|
||||
let hasSeenPlainParam = false;
|
||||
for (let i = node.params.length - 1; i >= 0; i--) {
|
||||
const current = node.params[i];
|
||||
const param = current.type === utils_1.AST_NODE_TYPES.TSParameterProperty
|
||||
? current.parameter
|
||||
: current;
|
||||
if (isPlainParam(param)) {
|
||||
hasSeenPlainParam = true;
|
||||
continue;
|
||||
}
|
||||
if (hasSeenPlainParam &&
|
||||
(isOptionalParam(param) ||
|
||||
param.type === utils_1.AST_NODE_TYPES.AssignmentPattern)) {
|
||||
context.report({ node: current, messageId: 'shouldBeLast' });
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
ArrowFunctionExpression: checkDefaultParamLast,
|
||||
FunctionDeclaration: checkDefaultParamLast,
|
||||
FunctionExpression: checkDefaultParamLast,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './estree-to-ts-node-types';
|
||||
export * from './ts-nodes';
|
||||
export { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree, } from '@typescript-eslint/types';
|
||||
@@ -0,0 +1,5 @@
|
||||
export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.DC7d2Pf8.js';
|
||||
import 'node:url';
|
||||
import 'node:console';
|
||||
|
||||
console.warn("Importing from \"vitest/environments\" is deprecated since Vitest 4.1. Please use \"vitest/runtime\" instead.");
|
||||
@@ -0,0 +1,6 @@
|
||||
import temporalUndefined from "./temporalUndefined.js";
|
||||
import tdz from "./tdz.js";
|
||||
function _temporalRef(r, e) {
|
||||
return r === temporalUndefined ? tdz(e) : r;
|
||||
}
|
||||
export { _temporalRef as default };
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @fileoverview Rule to disallow assignments where both sides are exactly the same
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const SPACES = /\s+/gu;
|
||||
|
||||
/**
|
||||
* Traverses 2 Pattern nodes in parallel, then reports self-assignments.
|
||||
* @param {ASTNode|null} left A left node to traverse. This is a Pattern or
|
||||
* a Property.
|
||||
* @param {ASTNode|null} right A right node to traverse. This is a Pattern or
|
||||
* a Property.
|
||||
* @param {boolean} props The flag to check member expressions as well.
|
||||
* @param {Function} report A callback function to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function eachSelfAssignment(left, right, props, report) {
|
||||
if (!left || !right) {
|
||||
// do nothing
|
||||
} else if (
|
||||
left.type === "Identifier" &&
|
||||
right.type === "Identifier" &&
|
||||
left.name === right.name
|
||||
) {
|
||||
report(right);
|
||||
} else if (
|
||||
left.type === "ArrayPattern" &&
|
||||
right.type === "ArrayExpression"
|
||||
) {
|
||||
const end = Math.min(left.elements.length, right.elements.length);
|
||||
|
||||
for (let i = 0; i < end; ++i) {
|
||||
const leftElement = left.elements[i];
|
||||
const rightElement = right.elements[i];
|
||||
|
||||
// Avoid cases such as [...a] = [...a, 1]
|
||||
if (
|
||||
leftElement &&
|
||||
leftElement.type === "RestElement" &&
|
||||
i < right.elements.length - 1
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
eachSelfAssignment(leftElement, rightElement, props, report);
|
||||
|
||||
// After a spread element, those indices are unknown.
|
||||
if (rightElement && rightElement.type === "SpreadElement") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (left.type === "RestElement" && right.type === "SpreadElement") {
|
||||
eachSelfAssignment(left.argument, right.argument, props, report);
|
||||
} else if (
|
||||
left.type === "ObjectPattern" &&
|
||||
right.type === "ObjectExpression" &&
|
||||
right.properties.length >= 1
|
||||
) {
|
||||
/*
|
||||
* Gets the index of the last spread property.
|
||||
* It's possible to overwrite properties followed by it.
|
||||
*/
|
||||
let startJ = 0;
|
||||
|
||||
for (let i = right.properties.length - 1; i >= 0; --i) {
|
||||
const propType = right.properties[i].type;
|
||||
|
||||
if (
|
||||
propType === "SpreadElement" ||
|
||||
propType === "ExperimentalSpreadProperty"
|
||||
) {
|
||||
startJ = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < left.properties.length; ++i) {
|
||||
for (let j = startJ; j < right.properties.length; ++j) {
|
||||
eachSelfAssignment(
|
||||
left.properties[i],
|
||||
right.properties[j],
|
||||
props,
|
||||
report,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
left.type === "Property" &&
|
||||
right.type === "Property" &&
|
||||
right.kind === "init" &&
|
||||
!right.method
|
||||
) {
|
||||
const leftName = astUtils.getStaticPropertyName(left);
|
||||
|
||||
if (
|
||||
leftName !== null &&
|
||||
leftName === astUtils.getStaticPropertyName(right)
|
||||
) {
|
||||
eachSelfAssignment(left.value, right.value, props, report);
|
||||
}
|
||||
} else if (
|
||||
props &&
|
||||
astUtils.skipChainExpression(left).type === "MemberExpression" &&
|
||||
astUtils.skipChainExpression(right).type === "MemberExpression" &&
|
||||
astUtils.isSameReference(left, right)
|
||||
) {
|
||||
report(right);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
defaultOptions: [{ props: true }],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow assignments where both sides are exactly the same",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-self-assign",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
props: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
selfAssignment: "'{{name}}' is assigned to itself.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const [{ props }] = context.options;
|
||||
|
||||
/**
|
||||
* Reports a given node as self assignments.
|
||||
* @param {ASTNode} node A node to report. This is an Identifier node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "selfAssignment",
|
||||
data: {
|
||||
name: sourceCode.getText(node).replace(SPACES, ""),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
AssignmentExpression(node) {
|
||||
if (["=", "&&=", "||=", "??="].includes(node.operator)) {
|
||||
eachSelfAssignment(node.left, node.right, props, report);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"sha1.js","sourceRoot":"","sources":["../src/sha1.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,aAAa,CAAC;AAC3D,+DAA+D;AAC/D,MAAM,CAAC,MAAM,IAAI,GAAiB,KAAK,CAAC;AACxC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,IAAI,GAAiB,KAAK,CAAC"}
|
||||
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseOptions = parseOptions;
|
||||
const util_1 = require("../../util");
|
||||
const enums_1 = require("./enums");
|
||||
const shared_1 = require("./shared");
|
||||
const validator_1 = require("./validator");
|
||||
function normalizeOption(option) {
|
||||
let weight = 0;
|
||||
option.modifiers?.forEach(mod => {
|
||||
weight |= enums_1.Modifiers[mod];
|
||||
});
|
||||
option.types?.forEach(mod => {
|
||||
weight |= enums_1.TypeModifiers[mod];
|
||||
});
|
||||
// give selectors with a filter the _highest_ priority
|
||||
if (option.filter) {
|
||||
weight |= 1 << 30;
|
||||
}
|
||||
const normalizedOption = {
|
||||
// format options
|
||||
custom: option.custom
|
||||
? {
|
||||
match: option.custom.match,
|
||||
regex: new RegExp(option.custom.regex, 'u'),
|
||||
}
|
||||
: null,
|
||||
filter: option.filter != null
|
||||
? typeof option.filter === 'string'
|
||||
? {
|
||||
match: true,
|
||||
regex: new RegExp(option.filter, 'u'),
|
||||
}
|
||||
: {
|
||||
match: option.filter.match,
|
||||
regex: new RegExp(option.filter.regex, 'u'),
|
||||
}
|
||||
: null,
|
||||
format: option.format ? option.format.map(f => enums_1.PredefinedFormats[f]) : null,
|
||||
leadingUnderscore: option.leadingUnderscore != null
|
||||
? enums_1.UnderscoreOptions[option.leadingUnderscore]
|
||||
: null,
|
||||
modifiers: option.modifiers?.map(m => enums_1.Modifiers[m]) ?? null,
|
||||
prefix: option.prefix && option.prefix.length > 0 ? option.prefix : null,
|
||||
suffix: option.suffix && option.suffix.length > 0 ? option.suffix : null,
|
||||
trailingUnderscore: option.trailingUnderscore != null
|
||||
? enums_1.UnderscoreOptions[option.trailingUnderscore]
|
||||
: null,
|
||||
types: option.types?.map(m => enums_1.TypeModifiers[m]) ?? null,
|
||||
// calculated ordering weight based on modifiers
|
||||
modifierWeight: weight,
|
||||
};
|
||||
const selectors = Array.isArray(option.selector)
|
||||
? option.selector
|
||||
: [option.selector];
|
||||
return selectors.map(selector => ({
|
||||
selector: (0, shared_1.isMetaSelector)(selector)
|
||||
? enums_1.MetaSelectors[selector]
|
||||
: enums_1.Selectors[selector],
|
||||
...normalizedOption,
|
||||
}));
|
||||
}
|
||||
function parseOptions(context) {
|
||||
const normalizedOptions = context.options.flatMap(normalizeOption);
|
||||
return Object.fromEntries((0, util_1.getEnumNames)(enums_1.Selectors).map(k => [
|
||||
k,
|
||||
(0, validator_1.createValidator)(k, context, normalizedOptions),
|
||||
]));
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.z = void 0;
|
||||
const z = __importStar(require("./external.cjs"));
|
||||
exports.z = z;
|
||||
__exportStar(require("./external.cjs"), exports);
|
||||
exports.default = z;
|
||||
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const { register, unregister } = require('..')
|
||||
|
||||
process.on('warning', () => {
|
||||
t.fail('warning emitted')
|
||||
})
|
||||
|
||||
const objs = []
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const obj = { i }
|
||||
objs.push(obj)
|
||||
register(obj, shutdown)
|
||||
}
|
||||
|
||||
for (const obj of objs) {
|
||||
unregister(obj)
|
||||
}
|
||||
|
||||
t.pass('completed')
|
||||
|
||||
function shutdown () {}
|
||||
@@ -0,0 +1,7 @@
|
||||
import classApplyDescriptorGet from "./classApplyDescriptorGet.js";
|
||||
import assertClassBrand from "./assertClassBrand.js";
|
||||
import classCheckPrivateStaticFieldDescriptor from "./classCheckPrivateStaticFieldDescriptor.js";
|
||||
function _classStaticPrivateFieldSpecGet(t, s, r) {
|
||||
return assertClassBrand(s, t), classCheckPrivateStaticFieldDescriptor(r, "get"), classApplyDescriptorGet(t, r);
|
||||
}
|
||||
export { _classStaticPrivateFieldSpecGet as default };
|
||||
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.assertValidPattern = void 0;
|
||||
const MAX_PATTERN_LENGTH = 1024 * 64;
|
||||
const assertValidPattern = (pattern) => {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('invalid pattern');
|
||||
}
|
||||
if (pattern.length > MAX_PATTERN_LENGTH) {
|
||||
throw new TypeError('pattern is too long');
|
||||
}
|
||||
};
|
||||
exports.assertValidPattern = assertValidPattern;
|
||||
//# sourceMappingURL=assert-valid-pattern.js.map
|
||||
@@ -0,0 +1,98 @@
|
||||
'use strict'
|
||||
|
||||
const bench = require('fastbench')
|
||||
const bunyan = require('bunyan')
|
||||
const pino = require('../')
|
||||
const fs = require('node:fs')
|
||||
const dest = fs.createWriteStream('/dev/null')
|
||||
|
||||
const tenStreams = [
|
||||
{ stream: dest },
|
||||
{ stream: dest },
|
||||
{ stream: dest },
|
||||
{ stream: dest },
|
||||
{ stream: dest },
|
||||
{ level: 'debug', stream: dest },
|
||||
{ level: 'debug', stream: dest },
|
||||
{ level: 'trace', stream: dest },
|
||||
{ level: 'warn', stream: dest },
|
||||
{ level: 'fatal', stream: dest }
|
||||
]
|
||||
const pinomsTen = pino({ level: 'debug' }, pino.multistream(tenStreams))
|
||||
|
||||
const fourStreams = [
|
||||
{ stream: dest },
|
||||
{ stream: dest },
|
||||
{ level: 'debug', stream: dest },
|
||||
{ level: 'trace', stream: dest }
|
||||
]
|
||||
const pinomsFour = pino({ level: 'debug' }, pino.multistream(fourStreams))
|
||||
|
||||
const pinomsOne = pino({ level: 'info' }, pino.multistream(dest))
|
||||
const blogOne = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: [{ stream: dest }]
|
||||
})
|
||||
|
||||
const blogTen = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: tenStreams
|
||||
})
|
||||
const blogFour = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: fourStreams
|
||||
})
|
||||
|
||||
const max = 10
|
||||
const run = bench([
|
||||
function benchBunyanTen (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
blogTen.info('hello world')
|
||||
blogTen.debug('hello world')
|
||||
blogTen.trace('hello world')
|
||||
blogTen.warn('hello world')
|
||||
blogTen.fatal('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPinoMSTen (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
pinomsTen.info('hello world')
|
||||
pinomsTen.debug('hello world')
|
||||
pinomsTen.trace('hello world')
|
||||
pinomsTen.warn('hello world')
|
||||
pinomsTen.fatal('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchBunyanFour (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
blogFour.info('hello world')
|
||||
blogFour.debug('hello world')
|
||||
blogFour.trace('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPinoMSFour (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
pinomsFour.info('hello world')
|
||||
pinomsFour.debug('hello world')
|
||||
pinomsFour.trace('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchBunyanOne (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
blogOne.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPinoMSOne (cb) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
pinomsOne.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
}
|
||||
], 10000)
|
||||
|
||||
run()
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
declare const _default: TSESLint.RuleModule<"interfaceOverType" | "typeOverInterface", [string], import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,19 @@
|
||||
export type Options = [
|
||||
{
|
||||
allowAny?: boolean;
|
||||
allowNullableBoolean?: boolean;
|
||||
allowNullableEnum?: boolean;
|
||||
allowNullableNumber?: boolean;
|
||||
allowNullableObject?: boolean;
|
||||
allowNullableString?: boolean;
|
||||
allowNumber?: boolean;
|
||||
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
|
||||
allowString?: boolean;
|
||||
}
|
||||
];
|
||||
type ConditionErrorMessageId = 'conditionErrorAny' | 'conditionErrorNullableBoolean' | 'conditionErrorNullableEnum' | 'conditionErrorNullableNumber' | 'conditionErrorNullableObject' | 'conditionErrorNullableString' | 'conditionErrorNullish' | 'conditionErrorNumber' | 'conditionErrorObject' | 'conditionErrorOther' | 'conditionErrorString';
|
||||
export type MessageId = 'conditionFixCastBoolean' | 'conditionFixCompareArrayLengthNonzero' | 'conditionFixCompareArrayLengthZero' | 'conditionFixCompareEmptyString' | 'conditionFixCompareFalse' | 'conditionFixCompareNaN' | 'conditionFixCompareNullish' | 'conditionFixCompareStringLength' | 'conditionFixCompareTrue' | 'conditionFixCompareZero' | 'conditionFixDefaultEmptyString' | 'conditionFixDefaultFalse' | 'conditionFixDefaultZero' | 'explicitBooleanReturnType' | 'noStrictNullCheck' | 'predicateCannotBeAsync' | ConditionErrorMessageId;
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageId, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* @fileoverview Utility for caching lint results.
|
||||
* @author Kevin Partington
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const fs = require("node:fs");
|
||||
const fileEntryCache = require("file-entry-cache");
|
||||
const stringify = require("json-stable-stringify-without-jsonify");
|
||||
const pkg = require("../../package.json");
|
||||
const assert = require("../shared/assert");
|
||||
const hash = require("./hash");
|
||||
|
||||
const debug = require("debug")("eslint:lint-result-cache");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").Linter.Config} Config */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const configHashCache = new WeakMap();
|
||||
const nodeVersion = process && process.version;
|
||||
|
||||
const validCacheStrategies = ["metadata", "content"];
|
||||
const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${validCacheStrategies
|
||||
.map(strategy => `"${strategy}"`)
|
||||
.join(", ")}`;
|
||||
|
||||
/**
|
||||
* Tests whether a provided cacheStrategy is valid
|
||||
* @param {string} cacheStrategy The cache strategy to use
|
||||
* @returns {boolean} true if `cacheStrategy` is one of `validCacheStrategies`; false otherwise
|
||||
*/
|
||||
function isValidCacheStrategy(cacheStrategy) {
|
||||
return validCacheStrategies.includes(cacheStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash of the config
|
||||
* @param {Config} config The config.
|
||||
* @returns {string} The hash of the config
|
||||
*/
|
||||
function hashOfConfigFor(config) {
|
||||
if (!configHashCache.has(config)) {
|
||||
configHashCache.set(
|
||||
config,
|
||||
hash(`${pkg.version}_${nodeVersion}_${stringify(config)}`),
|
||||
);
|
||||
}
|
||||
|
||||
return configHashCache.get(config);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Lint result cache. This wraps around the file-entry-cache module,
|
||||
* transparently removing properties that are difficult or expensive to
|
||||
* serialize and adding them back in on retrieval.
|
||||
*/
|
||||
class LintResultCache {
|
||||
/**
|
||||
* Creates a new LintResultCache instance.
|
||||
* @param {string} cacheFileLocation The cache file location.
|
||||
* @param {"metadata" | "content"} cacheStrategy The cache strategy to use.
|
||||
*/
|
||||
constructor(cacheFileLocation, cacheStrategy) {
|
||||
assert(cacheFileLocation, "Cache file location is required");
|
||||
assert(cacheStrategy, "Cache strategy is required");
|
||||
assert(
|
||||
isValidCacheStrategy(cacheStrategy),
|
||||
invalidCacheStrategyErrorMessage,
|
||||
);
|
||||
|
||||
debug(`Caching results to ${cacheFileLocation}`);
|
||||
|
||||
const useChecksum = cacheStrategy === "content";
|
||||
|
||||
debug(`Using "${cacheStrategy}" strategy to detect changes`);
|
||||
|
||||
this.fileEntryCache = fileEntryCache.create(
|
||||
cacheFileLocation,
|
||||
void 0,
|
||||
useChecksum,
|
||||
);
|
||||
this.cacheFileLocation = cacheFileLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cached lint results for a given file path, if present in the
|
||||
* cache. If the file is present and has not been changed, rebuild any
|
||||
* missing result information.
|
||||
* @param {string} filePath The file for which to retrieve lint results.
|
||||
* @param {Config} config The config of the file.
|
||||
* @returns {Object|null} The rebuilt lint results, or null if the file is
|
||||
* changed or not in the filesystem.
|
||||
*/
|
||||
getCachedLintResults(filePath, config) {
|
||||
const cachedResults = this.getValidCachedLintResults(filePath, config);
|
||||
|
||||
if (!cachedResults) {
|
||||
return cachedResults;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shallow clone the object to ensure that any properties added or modified afterwards
|
||||
* will not be accidentally stored in the cache file when `reconcile()` is called.
|
||||
* https://github.com/eslint/eslint/issues/13507
|
||||
* All intentional changes to the cache file must be done through `setCachedLintResults()`.
|
||||
*/
|
||||
const results = { ...cachedResults };
|
||||
|
||||
// If source is present but null, need to reread the file from the filesystem.
|
||||
if (results.source === null) {
|
||||
debug(
|
||||
`Rereading cached result source from filesystem: ${filePath}`,
|
||||
);
|
||||
results.source = fs.readFileSync(filePath, "utf-8");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cached lint results for a given file path, if present in the
|
||||
* cache and still valid.
|
||||
* @param {string} filePath The file for which to retrieve lint results.
|
||||
* @param {Config} config The config of the file.
|
||||
* @returns {Object|null} The cached lint results if present in the cache
|
||||
* and still valid; null otherwise.
|
||||
*/
|
||||
getValidCachedLintResults(filePath, config) {
|
||||
/*
|
||||
* Cached lint results are valid if and only if:
|
||||
* 1. The file is present in the filesystem
|
||||
* 2. The file has not changed since the time it was previously linted
|
||||
* 3. The ESLint configuration has not changed since the time the file
|
||||
* was previously linted
|
||||
* If any of these are not true, we will not reuse the lint results.
|
||||
*/
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
|
||||
if (fileDescriptor.notFound) {
|
||||
debug(`File not found on the file system: ${filePath}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const hashOfConfig = hashOfConfigFor(config);
|
||||
const changed =
|
||||
fileDescriptor.changed ||
|
||||
fileDescriptor.meta.hashOfConfig !== hashOfConfig;
|
||||
|
||||
if (changed) {
|
||||
debug(`Cache entry not found or no longer valid: ${filePath}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileDescriptor.meta.results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cached lint results for a given file path, after removing any
|
||||
* information that will be both unnecessary and difficult to serialize.
|
||||
* Avoids caching results with an "output" property (meaning fixes were
|
||||
* applied), to prevent potentially incorrect results if fixes are not
|
||||
* written to disk.
|
||||
* @param {string} filePath The file for which to set lint results.
|
||||
* @param {Config} config The config of the file.
|
||||
* @param {Object} result The lint result to be set for the file.
|
||||
* @returns {void}
|
||||
*/
|
||||
setCachedLintResults(filePath, config, result) {
|
||||
if (result && Object.hasOwn(result, "output")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
|
||||
if (fileDescriptor && !fileDescriptor.notFound) {
|
||||
debug(`Updating cached result: ${filePath}`);
|
||||
|
||||
// Serialize the result, except that we want to remove the file source if present.
|
||||
const resultToSerialize = Object.assign({}, result);
|
||||
|
||||
/*
|
||||
* Set result.source to null.
|
||||
* In `getCachedLintResults`, if source is explicitly null, we will
|
||||
* read the file from the filesystem to set the value again.
|
||||
*/
|
||||
if (Object.hasOwn(resultToSerialize, "source")) {
|
||||
resultToSerialize.source = null;
|
||||
}
|
||||
|
||||
fileDescriptor.meta.results = resultToSerialize;
|
||||
fileDescriptor.meta.hashOfConfig = hashOfConfigFor(config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the in-memory cache to disk.
|
||||
* @returns {void}
|
||||
*/
|
||||
reconcile() {
|
||||
debug(`Persisting cached results: ${this.cacheFileLocation}`);
|
||||
this.fileEntryCache.reconcile();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LintResultCache;
|
||||
@@ -0,0 +1,32 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
{{
|
||||
var $currentBaseId = $it.baseId
|
||||
, $allSchemasEmpty = true;
|
||||
}}
|
||||
|
||||
{{~ $schema:$sch:$i }}
|
||||
{{? {{# def.nonEmptySchema:$sch }} }}
|
||||
{{
|
||||
$allSchemasEmpty = false;
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
||||
}}
|
||||
|
||||
{{# def.insertSubschemaCode }}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
{{~}}
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{? $allSchemasEmpty }}
|
||||
if (true) {
|
||||
{{??}}
|
||||
{{= $closingBraces.slice(0,-1) }}
|
||||
{{?}}
|
||||
{{?}}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user