WIP: bootstrap and partial real Solana watcher implementation

This commit is contained in:
2026-08-16 09:17:45 +00:00
commit dc23412c3f
7232 changed files with 1687637 additions and 0 deletions

View File

@@ -0,0 +1,263 @@
declare module 'os' {
interface CpuInfo {
model: string;
speed: number;
times: {
user: number;
nice: number;
sys: number;
idle: number;
irq: number;
};
}
interface NetworkInterfaceBase {
address: string;
netmask: string;
mac: string;
internal: boolean;
cidr: string | null;
}
interface NetworkInterfaceInfoIPv4 extends NetworkInterfaceBase {
family: "IPv4";
}
interface NetworkInterfaceInfoIPv6 extends NetworkInterfaceBase {
family: "IPv6";
scopeid: number;
}
interface UserInfo<T> {
username: T;
uid: number;
gid: number;
shell: T;
homedir: T;
}
type NetworkInterfaceInfo = NetworkInterfaceInfoIPv4 | NetworkInterfaceInfoIPv6;
function hostname(): string;
function loadavg(): number[];
function uptime(): number;
function freemem(): number;
function totalmem(): number;
function cpus(): CpuInfo[];
function type(): string;
function release(): string;
function networkInterfaces(): { [index: string]: NetworkInterfaceInfo[] };
function homedir(): string;
function userInfo(options: { encoding: 'buffer' }): UserInfo<Buffer>;
function userInfo(options?: { encoding: string }): UserInfo<string>;
const constants: {
UV_UDP_REUSEADDR: number;
// signals: { [key in NodeJS.Signals]: number; }; @todo: change after migration to typescript 2.1
signals: {
SIGHUP: number;
SIGINT: number;
SIGQUIT: number;
SIGILL: number;
SIGTRAP: number;
SIGABRT: number;
SIGIOT: number;
SIGBUS: number;
SIGFPE: number;
SIGKILL: number;
SIGUSR1: number;
SIGSEGV: number;
SIGUSR2: number;
SIGPIPE: number;
SIGALRM: number;
SIGTERM: number;
SIGCHLD: number;
SIGSTKFLT: number;
SIGCONT: number;
SIGSTOP: number;
SIGTSTP: number;
SIGBREAK: number;
SIGTTIN: number;
SIGTTOU: number;
SIGURG: number;
SIGXCPU: number;
SIGXFSZ: number;
SIGVTALRM: number;
SIGPROF: number;
SIGWINCH: number;
SIGIO: number;
SIGPOLL: number;
SIGLOST: number;
SIGPWR: number;
SIGINFO: number;
SIGSYS: number;
SIGUNUSED: number;
};
errno: {
E2BIG: number;
EACCES: number;
EADDRINUSE: number;
EADDRNOTAVAIL: number;
EAFNOSUPPORT: number;
EAGAIN: number;
EALREADY: number;
EBADF: number;
EBADMSG: number;
EBUSY: number;
ECANCELED: number;
ECHILD: number;
ECONNABORTED: number;
ECONNREFUSED: number;
ECONNRESET: number;
EDEADLK: number;
EDESTADDRREQ: number;
EDOM: number;
EDQUOT: number;
EEXIST: number;
EFAULT: number;
EFBIG: number;
EHOSTUNREACH: number;
EIDRM: number;
EILSEQ: number;
EINPROGRESS: number;
EINTR: number;
EINVAL: number;
EIO: number;
EISCONN: number;
EISDIR: number;
ELOOP: number;
EMFILE: number;
EMLINK: number;
EMSGSIZE: number;
EMULTIHOP: number;
ENAMETOOLONG: number;
ENETDOWN: number;
ENETRESET: number;
ENETUNREACH: number;
ENFILE: number;
ENOBUFS: number;
ENODATA: number;
ENODEV: number;
ENOENT: number;
ENOEXEC: number;
ENOLCK: number;
ENOLINK: number;
ENOMEM: number;
ENOMSG: number;
ENOPROTOOPT: number;
ENOSPC: number;
ENOSR: number;
ENOSTR: number;
ENOSYS: number;
ENOTCONN: number;
ENOTDIR: number;
ENOTEMPTY: number;
ENOTSOCK: number;
ENOTSUP: number;
ENOTTY: number;
ENXIO: number;
EOPNOTSUPP: number;
EOVERFLOW: number;
EPERM: number;
EPIPE: number;
EPROTO: number;
EPROTONOSUPPORT: number;
EPROTOTYPE: number;
ERANGE: number;
EROFS: number;
ESPIPE: number;
ESRCH: number;
ESTALE: number;
ETIME: number;
ETIMEDOUT: number;
ETXTBSY: number;
EWOULDBLOCK: number;
EXDEV: number;
WSAEINTR: number;
WSAEBADF: number;
WSAEACCES: number;
WSAEFAULT: number;
WSAEINVAL: number;
WSAEMFILE: number;
WSAEWOULDBLOCK: number;
WSAEINPROGRESS: number;
WSAEALREADY: number;
WSAENOTSOCK: number;
WSAEDESTADDRREQ: number;
WSAEMSGSIZE: number;
WSAEPROTOTYPE: number;
WSAENOPROTOOPT: number;
WSAEPROTONOSUPPORT: number;
WSAESOCKTNOSUPPORT: number;
WSAEOPNOTSUPP: number;
WSAEPFNOSUPPORT: number;
WSAEAFNOSUPPORT: number;
WSAEADDRINUSE: number;
WSAEADDRNOTAVAIL: number;
WSAENETDOWN: number;
WSAENETUNREACH: number;
WSAENETRESET: number;
WSAECONNABORTED: number;
WSAECONNRESET: number;
WSAENOBUFS: number;
WSAEISCONN: number;
WSAENOTCONN: number;
WSAESHUTDOWN: number;
WSAETOOMANYREFS: number;
WSAETIMEDOUT: number;
WSAECONNREFUSED: number;
WSAELOOP: number;
WSAENAMETOOLONG: number;
WSAEHOSTDOWN: number;
WSAEHOSTUNREACH: number;
WSAENOTEMPTY: number;
WSAEPROCLIM: number;
WSAEUSERS: number;
WSAEDQUOT: number;
WSAESTALE: number;
WSAEREMOTE: number;
WSASYSNOTREADY: number;
WSAVERNOTSUPPORTED: number;
WSANOTINITIALISED: number;
WSAEDISCON: number;
WSAENOMORE: number;
WSAECANCELLED: number;
WSAEINVALIDPROCTABLE: number;
WSAEINVALIDPROVIDER: number;
WSAEPROVIDERFAILEDINIT: number;
WSASYSCALLFAILURE: number;
WSASERVICE_NOT_FOUND: number;
WSATYPE_NOT_FOUND: number;
WSA_E_NO_MORE: number;
WSA_E_CANCELLED: number;
WSAEREFUSED: number;
};
priority: {
PRIORITY_LOW: number;
PRIORITY_BELOW_NORMAL: number;
PRIORITY_NORMAL: number;
PRIORITY_ABOVE_NORMAL: number;
PRIORITY_HIGH: number;
PRIORITY_HIGHEST: number;
}
};
function arch(): string;
function platform(): NodeJS.Platform;
function tmpdir(): string;
const EOL: string;
function endianness(): "BE" | "LE";
/**
* Gets the priority of a process.
* Defaults to current process.
*/
function getPriority(pid?: number): number;
/**
* Sets the priority of the current process.
* @param priority Must be in range of -20 to 19
*/
function setPriority(priority: number): void;
/**
* Sets the priority of the process specified process.
* @param priority Must be in range of -20 to 19
*/
function setPriority(pid: number, priority: number): void;
}

View File

@@ -0,0 +1,10 @@
export type Options = [
{
allowOptionalChaining?: boolean;
}
];
export type MessageIds = 'errorComputedMemberAccess' | 'errorMemberExpression' | 'errorThisMemberExpression' | 'unsafeComputedMemberAccess' | 'unsafeMemberExpression' | 'unsafeThisMemberExpression';
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1,181 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4";
const stringSet = z.set(z.string());
type stringSet = z.infer<typeof stringSet>;
const minTwo = z.set(z.string()).min(2);
const maxTwo = z.set(z.string()).max(2);
const justTwo = z.set(z.string()).size(2);
const nonEmpty = z.set(z.string()).nonempty();
const nonEmptyMax = z.set(z.string()).nonempty().max(2);
test("type inference", () => {
expectTypeOf<stringSet>().toEqualTypeOf<Set<string>>();
});
test("valid parse", () => {
const result = stringSet.safeParse(new Set(["first", "second"]));
expect(result.success).toEqual(true);
expect(result.data!.has("first")).toEqual(true);
expect(result.data!.has("second")).toEqual(true);
expect(result.data!.has("third")).toEqual(false);
expect(() => {
minTwo.parse(new Set(["a", "b"]));
minTwo.parse(new Set(["a", "b", "c"]));
maxTwo.parse(new Set(["a", "b"]));
maxTwo.parse(new Set(["a"]));
justTwo.parse(new Set(["a", "b"]));
nonEmpty.parse(new Set(["a"]));
nonEmptyMax.parse(new Set(["a"]));
}).not.toThrow();
});
test("valid parse async", async () => {
const result = await stringSet.spa(new Set(["first", "second"]));
expect(result.success).toEqual(true);
expect(result.data!.has("first")).toEqual(true);
expect(result.data!.has("second")).toEqual(true);
expect(result.data!.has("third")).toEqual(false);
const asyncResult = stringSet.safeParse(new Set(["first", "second"]));
expect(asyncResult.success).toEqual(true);
expect(asyncResult.data!.has("first")).toEqual(true);
expect(asyncResult.data!.has("second")).toEqual(true);
expect(asyncResult.data!.has("third")).toEqual(false);
});
test("valid parse: size-related methods", () => {
expect(() => {
minTwo.parse(new Set(["a", "b"]));
minTwo.parse(new Set(["a", "b", "c"]));
maxTwo.parse(new Set(["a", "b"]));
maxTwo.parse(new Set(["a"]));
justTwo.parse(new Set(["a", "b"]));
nonEmpty.parse(new Set(["a"]));
nonEmptyMax.parse(new Set(["a"]));
}).not.toThrow();
const sizeZeroResult = stringSet.parse(new Set());
expect(sizeZeroResult.size).toBe(0);
const sizeTwoResult = minTwo.parse(new Set(["a", "b"]));
expect(sizeTwoResult.size).toBe(2);
});
test("failing when parsing empty set in nonempty ", () => {
const result = nonEmpty.safeParse(new Set());
expect(result.success).toEqual(false);
expect(result.error!.issues.length).toEqual(1);
expect(result.error!.issues[0].code).toEqual("too_small");
});
test("failing when set is smaller than min() ", () => {
const result = minTwo.safeParse(new Set(["just_one"]));
expect(result.success).toEqual(false);
expect(result.error!.issues.length).toEqual(1);
expect(result.error!.issues[0].code).toEqual("too_small");
});
test("failing when set is bigger than max() ", () => {
const result = maxTwo.safeParse(new Set(["one", "two", "three"]));
expect(result.success).toEqual(false);
expect(result.error!.issues.length).toEqual(1);
expect(result.error!.issues[0].code).toEqual("too_big");
});
test("doesnt throw when an empty set is given", () => {
const result = stringSet.safeParse(new Set([]));
expect(result.success).toEqual(true);
});
test("throws when a Map is given", () => {
const result = stringSet.safeParse(new Map([]));
expect(result.success).toEqual(false);
expect(result.error).toMatchInlineSnapshot(`
[ZodError: [
{
"expected": "set",
"code": "invalid_type",
"path": [],
"message": "Invalid input: expected set, received Map"
}
]]
`);
});
test("throws when the given set has invalid input", () => {
const result = stringSet.safeParse(new Set([Symbol()]));
expect(result.success).toEqual(false);
expect(result.error!.issues.length).toEqual(1);
expect(result.error).toMatchInlineSnapshot(`
[ZodError: [
{
"expected": "string",
"code": "invalid_type",
"path": [],
"message": "Invalid input: expected string, received symbol"
}
]]
`);
});
test("throws when the given set has multiple invalid entries", () => {
const result = stringSet.safeParse(new Set([1, 2] as any[]));
expect(result.success).toEqual(false);
expect(result.error!.issues.length).toEqual(2);
expect(result.error).toMatchInlineSnapshot(`
[ZodError: [
{
"expected": "string",
"code": "invalid_type",
"path": [],
"message": "Invalid input: expected string, received number"
},
{
"expected": "string",
"code": "invalid_type",
"path": [],
"message": "Invalid input: expected string, received number"
}
]]
`);
});
test("min/max", async () => {
const schema = z.set(z.string()).min(4).max(5);
const r1 = schema.safeParse(new Set(["a", "b", "c", "d"]));
expect(r1.success).toEqual(true);
const r2 = schema.safeParse(new Set(["a", "b", "c"]));
expect(r2.success).toEqual(false);
expect(r2.error!.issues).toMatchInlineSnapshot(`
[
{
"code": "too_small",
"inclusive": true,
"message": "Too small: expected set to have >=4 items",
"minimum": 4,
"origin": "set",
"path": [],
},
]
`);
const r3 = schema.safeParse(new Set(["a", "b", "c", "d", "e", "f"]));
expect(r3.success).toEqual(false);
expect(r3.error!.issues).toMatchInlineSnapshot(`
[
{
"code": "too_big",
"inclusive": true,
"maximum": 5,
"message": "Too big: expected set to have <=5 items",
"origin": "set",
"path": [],
},
]
`);
});

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env node
var which = require("../")
if (process.argv.length < 3)
usage()
function usage () {
console.error('usage: which [-as] program ...')
process.exit(1)
}
var all = false
var silent = false
var dashdash = false
var args = process.argv.slice(2).filter(function (arg) {
if (dashdash || !/^-/.test(arg))
return true
if (arg === '--') {
dashdash = true
return false
}
var flags = arg.substr(1).split('')
for (var f = 0; f < flags.length; f++) {
var flag = flags[f]
switch (flag) {
case 's':
silent = true
break
case 'a':
all = true
break
default:
console.error('which: illegal option -- ' + flag)
usage()
}
}
return false
})
process.exit(args.reduce(function (pv, current) {
try {
var f = which.sync(current, { all: all })
if (all)
f = f.join('\n')
if (!silent)
console.log(f)
return pv;
} catch (e) {
return 1;
}
}, 0))

View File

@@ -0,0 +1,6 @@
const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // eslint-disable-line
if (typeof runtimeRequire.addon === 'function') { // if the platform supports native resolving prefer that
module.exports = runtimeRequire.addon.bind(runtimeRequire)
} else { // else use the runtime version here
module.exports = require('./node-gyp-build.js')
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"u16.d.ts","sourceRoot":"","sources":["../../src/u16.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvG,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GAAI,SAAQ,iBAAsB,KAAG,gBAAgB,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAO5F,CAAC;AAEP;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GAAI,SAAQ,iBAAsB,KAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAMnF,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,WAAW,GAAI,SAAQ,iBAAsB,KAAG,cAAc,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CACxC,CAAC"}

View File

@@ -0,0 +1,63 @@
"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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.typescriptVersionIsAtLeast = void 0;
const semver = __importStar(require("semver"));
const ts = __importStar(require("typescript"));
function semverCheck(version) {
return semver.satisfies(ts.version, `>= ${version}.0 || >= ${version}.1-rc || >= ${version}.0-beta`, {
includePrerelease: true,
});
}
const versions = [
'4.7',
'4.8',
'4.9',
'5.0',
'5.1',
'5.2',
'5.3',
'5.4',
'5.5',
'5.6',
'5.7',
'5.8',
'5.9',
'6.0',
];
exports.typescriptVersionIsAtLeast = {};
for (const version of versions) {
exports.typescriptVersionIsAtLeast[version] = semverCheck(version);
}

View File

@@ -0,0 +1,50 @@
import type {Buffer} from 'buffer';
import {PublicKey} from './publickey';
import {Loader} from './loader';
import type {Connection} from './connection';
import type {Signer} from './keypair';
/**
* @deprecated Deprecated since Solana v1.17.20.
*/
export const BPF_LOADER_PROGRAM_ID = new PublicKey(
'BPFLoader2111111111111111111111111111111111',
);
/**
* Factory class for transactions to interact with a program loader
*
* @deprecated Deprecated since Solana v1.17.20.
*/
export class BpfLoader {
/**
* Minimum number of signatures required to load a program not including
* retries
*
* Can be used to calculate transaction fees
*/
static getMinNumSignatures(dataLength: number): number {
return Loader.getMinNumSignatures(dataLength);
}
/**
* Load a SBF program
*
* @param connection The connection to use
* @param payer Account that will pay program loading fees
* @param program Account to load the program into
* @param elf The entire ELF containing the SBF program
* @param loaderProgramId The program id of the BPF loader to use
* @return true if program was loaded successfully, false if program was already loaded
*/
static load(
connection: Connection,
payer: Signer,
program: Signer,
elf: Buffer | Uint8Array | Array<number>,
loaderProgramId: PublicKey,
): Promise<boolean> {
return Loader.load(connection, payer, program, loaderProgramId, elf);
}
}

View File

@@ -0,0 +1,74 @@
# pump
pump is a small node module that pipes streams together and destroys all of them if one of them closes.
```
npm install pump
```
[![build status](http://img.shields.io/travis/mafintosh/pump.svg?style=flat)](http://travis-ci.org/mafintosh/pump)
## What problem does it solve?
When using standard `source.pipe(dest)` source will _not_ be destroyed if dest emits close or an error.
You are also not able to provide a callback to tell when then pipe has finished.
pump does these two things for you
## Usage
Simply pass the streams you want to pipe together to pump and add an optional callback
``` js
var pump = require('pump')
var fs = require('fs')
var source = fs.createReadStream('/dev/random')
var dest = fs.createWriteStream('/dev/null')
pump(source, dest, function(err) {
console.log('pipe finished', err)
})
setTimeout(function() {
dest.destroy() // when dest is closed pump will destroy source
}, 1000)
```
You can use pump to pipe more than two streams together as well
``` js
var transform = someTransformStream()
pump(source, transform, anotherTransform, dest, function(err) {
console.log('pipe finished', err)
})
```
If `source`, `transform`, `anotherTransform` or `dest` closes all of them will be destroyed.
Similarly to `stream.pipe()`, `pump()` returns the last stream passed in, so you can do:
```
return pump(s1, s2) // returns s2
```
Note that `pump` attaches error handlers to the streams to do internal error handling, so if `s2` emits an
error in the above scenario, it will not trigger a `proccess.on('uncaughtException')` if you do not listen for it.
If you want to return a stream that combines *both* s1 and s2 to a single stream use
[pumpify](https://github.com/mafintosh/pumpify) instead.
## License
MIT
## Related
`pump` is part of the [mississippi stream utility collection](https://github.com/maxogden/mississippi) which includes more useful stream modules similar to this one.
## For enterprise
Available as part of the Tidelift Subscription.
The maintainers of pump and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-pump?utm_source=npm-pump&utm_medium=referral&utm_campaign=enterprise)

View File

@@ -0,0 +1,22 @@
import { _ as _unsupported_iterable_to_array } from "./_unsupported_iterable_to_array.js";
function _create_for_of_iterator_helper_loose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
// Fallback for engines without symbol support
if (Array.isArray(o) || (it = _unsupported_iterable_to_array(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function() {
if (i >= o.length) return { done: true };
return { done: false, value: o[i++] };
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
export { _create_for_of_iterator_helper_loose as _ };

View File

@@ -0,0 +1,12 @@
import type { TSESTree } from '@typescript-eslint/types';
import type { Referencer } from './Referencer';
import { Visitor } from './Visitor';
export declare class ImportVisitor extends Visitor {
#private;
constructor(declaration: TSESTree.ImportDeclaration, referencer: Referencer);
static visit(referencer: Referencer, declaration: TSESTree.ImportDeclaration): void;
protected ImportDefaultSpecifier(node: TSESTree.ImportDefaultSpecifier): void;
protected ImportNamespaceSpecifier(node: TSESTree.ImportNamespaceSpecifier): void;
protected ImportSpecifier(node: TSESTree.ImportSpecifier): void;
protected visitImport(id: TSESTree.Identifier, specifier: TSESTree.ImportDefaultSpecifier | TSESTree.ImportNamespaceSpecifier | TSESTree.ImportSpecifier): void;
}

View File

@@ -0,0 +1,895 @@
import { expect, test } from "vitest";
import { fromJSONSchema } from "../from-json-schema.js";
import * as z from "../index.js";
test("basic string schema", () => {
const schema = fromJSONSchema({ type: "string" });
expect(schema.parse("hello")).toBe("hello");
expect(() => schema.parse(123)).toThrow();
});
test("string with constraints", () => {
const schema = fromJSONSchema({
type: "string",
minLength: 3,
maxLength: 10,
pattern: "^[a-z]+$",
});
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse("helloworld")).toBe("helloworld"); // exactly 10 chars - valid
expect(() => schema.parse("hi")).toThrow(); // too short
expect(() => schema.parse("helloworld1")).toThrow(); // too long (11 chars)
expect(() => schema.parse("Hello")).toThrow(); // pattern mismatch
});
test("pattern is not implicitly anchored", () => {
// JSON Schema patterns match anywhere in the string, not just the full string
const schema = fromJSONSchema({
type: "string",
pattern: "foo",
});
expect(schema.parse("foo")).toBe("foo");
expect(schema.parse("foobar")).toBe("foobar"); // matches at start
expect(schema.parse("barfoo")).toBe("barfoo"); // matches at end
expect(schema.parse("barfoobar")).toBe("barfoobar"); // matches in middle
expect(() => schema.parse("bar")).toThrow(); // no match
});
test("number schema", () => {
const schema = fromJSONSchema({ type: "number" });
expect(schema.parse(42)).toBe(42);
expect(() => schema.parse("42")).toThrow();
});
test("number with constraints", () => {
const schema = fromJSONSchema({
type: "number",
minimum: 0,
maximum: 100,
multipleOf: 5,
});
expect(schema.parse(50)).toBe(50);
expect(() => schema.parse(-1)).toThrow();
expect(() => schema.parse(101)).toThrow();
expect(() => schema.parse(47)).toThrow(); // not multiple of 5
});
test("integer schema", () => {
const schema = fromJSONSchema({ type: "integer" });
expect(schema.parse(42)).toBe(42);
expect(() => schema.parse(42.5)).toThrow();
});
test("boolean schema", () => {
const schema = fromJSONSchema({ type: "boolean" });
expect(schema.parse(true)).toBe(true);
expect(schema.parse(false)).toBe(false);
expect(() => schema.parse("true")).toThrow();
});
test("null schema", () => {
const schema = fromJSONSchema({ type: "null" });
expect(schema.parse(null)).toBe(null);
expect(() => schema.parse(undefined)).toThrow();
});
test("object schema", () => {
const schema = fromJSONSchema({
type: "object",
properties: {
name: { type: "string" },
age: { type: "number" },
},
required: ["name"],
});
expect(schema.parse({ name: "John", age: 30 })).toEqual({ name: "John", age: 30 });
expect(schema.parse({ name: "John" })).toEqual({ name: "John" });
expect(() => schema.parse({ age: 30 })).toThrow(); // missing required
});
test("object with additionalProperties false", () => {
const schema = fromJSONSchema({
type: "object",
properties: {
name: { type: "string" },
},
additionalProperties: false,
});
expect(schema.parse({ name: "John" })).toEqual({ name: "John" });
expect(() => schema.parse({ name: "John", extra: "field" })).toThrow();
});
test("array schema", () => {
const schema = fromJSONSchema({
type: "array",
items: { type: "string" },
});
expect(schema.parse(["a", "b", "c"])).toEqual(["a", "b", "c"]);
expect(() => schema.parse([1, 2, 3])).toThrow();
});
test("array with constraints", () => {
const schema = fromJSONSchema({
type: "array",
items: { type: "number" },
minItems: 2,
maxItems: 4,
});
expect(schema.parse([1, 2])).toEqual([1, 2]);
expect(schema.parse([1, 2, 3, 4])).toEqual([1, 2, 3, 4]);
expect(() => schema.parse([1])).toThrow();
expect(() => schema.parse([1, 2, 3, 4, 5])).toThrow();
});
test("tuple with prefixItems (draft-2020-12)", () => {
const schema = fromJSONSchema({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "array",
prefixItems: [{ type: "string" }, { type: "number" }],
});
expect(schema.parse(["hello", 42])).toEqual(["hello", 42]);
expect(() => schema.parse(["hello"])).toThrow();
expect(() => schema.parse(["hello", "world"])).toThrow();
});
test("tuple with items array (draft-7)", () => {
const schema = fromJSONSchema({
$schema: "http://json-schema.org/draft-07/schema#",
type: "array",
items: [{ type: "string" }, { type: "number" }],
additionalItems: false,
});
expect(schema.parse(["hello", 42])).toEqual(["hello", 42]);
expect(() => schema.parse(["hello", 42, "extra"])).toThrow();
});
test("enum schema", () => {
const schema = fromJSONSchema({
enum: ["red", "green", "blue"],
});
expect(schema.parse("red")).toBe("red");
expect(() => schema.parse("yellow")).toThrow();
});
test("const schema", () => {
const schema = fromJSONSchema({
const: "hello",
});
expect(schema.parse("hello")).toBe("hello");
expect(() => schema.parse("world")).toThrow();
});
test("anyOf schema", () => {
const schema = fromJSONSchema({
anyOf: [{ type: "string" }, { type: "number" }],
});
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse(42)).toBe(42);
expect(() => schema.parse(true)).toThrow();
});
test("allOf schema", () => {
const schema = fromJSONSchema({
allOf: [
{ type: "object", properties: { name: { type: "string" } }, required: ["name"] },
{ type: "object", properties: { age: { type: "number" } }, required: ["age"] },
],
});
const result = schema.parse({ name: "John", age: 30 }) as { name: string; age: number };
expect(result.name).toBe("John");
expect(result.age).toBe(30);
});
test("allOf with empty array", () => {
// Empty allOf without explicit type returns any
const schema1 = fromJSONSchema({
allOf: [],
});
expect(schema1.parse("hello")).toBe("hello");
expect(schema1.parse(123)).toBe(123);
expect(schema1.parse({})).toEqual({});
// Empty allOf with explicit type returns base schema
const schema2 = fromJSONSchema({
type: "string",
allOf: [],
});
expect(schema2.parse("hello")).toBe("hello");
expect(() => schema2.parse(123)).toThrow();
});
test("oneOf schema (exclusive union)", () => {
const schema = fromJSONSchema({
oneOf: [{ type: "string" }, { type: "number" }],
});
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse(42)).toBe(42);
expect(() => schema.parse(true)).toThrow();
});
test("type with anyOf creates intersection", () => {
// type: string AND (type:string,minLength:5 OR type:string,pattern:^a)
const schema = fromJSONSchema({
type: "string",
anyOf: [
{ type: "string", minLength: 5 },
{ type: "string", pattern: "^a" },
],
});
// Should pass: string AND (minLength:5 OR pattern:^a) - matches minLength
expect(schema.parse("hello")).toBe("hello");
// Should pass: string AND (minLength:5 OR pattern:^a) - matches pattern
expect(schema.parse("abc")).toBe("abc");
// Should fail: string but neither minLength nor pattern match
expect(() => schema.parse("hi")).toThrow();
// Should fail: not a string
expect(() => schema.parse(123)).toThrow();
});
test("type with oneOf creates intersection", () => {
// type: string AND (exactly one of: type:string,minLength:5 OR type:string,pattern:^a)
const schema = fromJSONSchema({
type: "string",
oneOf: [
{ type: "string", minLength: 5 },
{ type: "string", pattern: "^a" },
],
});
// Should pass: string AND minLength:5 (exactly one match - "hello" length 5 >= 5, doesn't start with 'a')
expect(schema.parse("hello")).toBe("hello");
// Should pass: string AND pattern:^a (exactly one match - "abc" starts with 'a', length 3 < 5)
expect(schema.parse("abc")).toBe("abc");
// Should fail: string but neither match
expect(() => schema.parse("hi")).toThrow();
// Should fail: not a string
expect(() => schema.parse(123)).toThrow();
// Should fail: matches both (length >= 5 AND starts with 'a') - exclusive union fails
expect(() => schema.parse("apple")).toThrow();
});
test("unevaluatedItems throws error", () => {
expect(() => {
fromJSONSchema({
type: "array",
unevaluatedItems: false,
});
}).toThrow("unevaluatedItems is not supported");
});
test("unevaluatedProperties throws error", () => {
expect(() => {
fromJSONSchema({
type: "object",
unevaluatedProperties: false,
});
}).toThrow("unevaluatedProperties is not supported");
});
test("if/then/else throws error", () => {
expect(() => {
fromJSONSchema({
if: { type: "string" },
then: { type: "number" },
});
}).toThrow("Conditional schemas");
});
test("external $ref throws error", () => {
expect(() => {
fromJSONSchema({
$ref: "https://example.com/schema#/definitions/User",
});
}).toThrow("External $ref is not supported");
});
test("local $ref resolution", () => {
const schema = fromJSONSchema({
$defs: {
User: {
type: "object",
properties: {
name: { type: "string" },
},
required: ["name"],
},
},
$ref: "#/$defs/User",
});
expect(schema.parse({ name: "John" })).toEqual({ name: "John" });
expect(() => schema.parse({})).toThrow();
});
test("circular $ref with lazy", () => {
const schema = fromJSONSchema({
$defs: {
Node: {
type: "object",
properties: {
value: { type: "string" },
children: {
type: "array",
items: { $ref: "#/$defs/Node" },
},
},
},
},
$ref: "#/$defs/Node",
});
type Node = { value: string; children: Node[] };
const result = schema.parse({
value: "root",
children: [{ value: "child", children: [] }],
}) as Node;
expect(result.value).toBe("root");
expect(result.children[0]?.value).toBe("child");
});
test("patternProperties", () => {
const schema = fromJSONSchema({
type: "object",
patternProperties: {
"^S_": { type: "string" },
},
});
const result = schema.parse({ S_name: "John", S_age: "30" }) as Record<string, string>;
expect(result.S_name).toBe("John");
expect(result.S_age).toBe("30");
});
test("patternProperties with regular properties", () => {
// Note: When patternProperties is combined with properties, the intersection
// validates all keys against the pattern. This test uses a pattern that
// matches the regular property name as well.
const schema = fromJSONSchema({
type: "object",
properties: {
S_name: { type: "string" },
},
patternProperties: {
"^S_": { type: "string" },
},
required: ["S_name"],
});
const result = schema.parse({ S_name: "John", S_extra: "value" }) as Record<string, string>;
expect(result.S_name).toBe("John");
expect(result.S_extra).toBe("value");
});
test("multiple patternProperties", () => {
const schema = fromJSONSchema({
type: "object",
patternProperties: {
"^S_": { type: "string" },
"^N_": { type: "number" },
},
});
const result = schema.parse({ S_name: "John", N_count: 123 }) as Record<string, string | number>;
expect(result.S_name).toBe("John");
expect(result.N_count).toBe(123);
// Keys not matching any pattern should pass through
const result2 = schema.parse({ S_name: "John", N_count: 123, other: "value" }) as Record<string, string | number>;
expect(result2.other).toBe("value");
});
test("multiple overlapping patternProperties", () => {
// If a key matches multiple patterns, value must satisfy all schemas
const schema = fromJSONSchema({
type: "object",
patternProperties: {
"^S_": { type: "string" },
"^S_N": { type: "string", minLength: 3 },
},
});
// S_name matches ^S_ but not ^S_N
expect(schema.parse({ S_name: "John" })).toEqual({ S_name: "John" });
// S_N matches both patterns - must satisfy both (string with minLength 3)
expect(schema.parse({ S_N: "abc" })).toEqual({ S_N: "abc" });
expect(() => schema.parse({ S_N: "ab" })).toThrow(); // too short for ^S_N pattern
});
test("default value", () => {
const schema = fromJSONSchema({
type: "string",
default: "hello",
});
// Default is applied during parsing if value is missing/undefined
// This depends on Zod's default behavior
expect(schema.parse("world")).toBe("world");
});
test("description metadata", () => {
const schema = fromJSONSchema({
type: "string",
description: "A string value",
});
expect(schema.parse("hello")).toBe("hello");
});
test("version detection - draft-2020-12", () => {
const schema = fromJSONSchema({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "array",
prefixItems: [{ type: "string" }],
});
expect(schema.parse(["hello"])).toEqual(["hello"]);
});
test("version detection - draft-7", () => {
const schema = fromJSONSchema({
$schema: "http://json-schema.org/draft-07/schema#",
type: "array",
items: [{ type: "string" }],
});
expect(schema.parse(["hello"])).toEqual(["hello"]);
});
test("version detection - draft-4", () => {
const schema = fromJSONSchema({
$schema: "http://json-schema.org/draft-04/schema#",
type: "array",
items: [{ type: "string" }],
});
expect(schema.parse(["hello"])).toEqual(["hello"]);
});
test("default version (draft-2020-12)", () => {
const schema = fromJSONSchema({
type: "array",
prefixItems: [{ type: "string" }],
});
expect(schema.parse(["hello"])).toEqual(["hello"]);
});
test("string format - email", () => {
const schema = fromJSONSchema({
type: "string",
format: "email",
});
expect(schema.parse("test@example.com")).toBe("test@example.com");
});
test("string format - uuid", () => {
const schema = fromJSONSchema({
type: "string",
format: "uuid",
});
const uuid = "550e8400-e29b-41d4-a716-446655440000";
expect(schema.parse(uuid)).toBe(uuid);
});
test("exclusiveMinimum and exclusiveMaximum", () => {
const schema = fromJSONSchema({
type: "number",
exclusiveMinimum: 0,
exclusiveMaximum: 100,
});
expect(schema.parse(50)).toBe(50);
expect(() => schema.parse(0)).toThrow();
expect(() => schema.parse(100)).toThrow();
});
test("boolean schema (true/false)", () => {
const trueSchema = fromJSONSchema(true);
expect(trueSchema.parse("anything")).toBe("anything");
const falseSchema = fromJSONSchema(false);
expect(() => falseSchema.parse("anything")).toThrow();
});
test("empty object schema", () => {
const schema = fromJSONSchema({
type: "object",
});
expect(schema.parse({})).toEqual({});
expect(schema.parse({ extra: "field" })).toEqual({ extra: "field" });
});
test("array without items", () => {
const schema = fromJSONSchema({
type: "array",
});
expect(schema.parse([1, "string", true])).toEqual([1, "string", true]);
});
test("mixed enum types", () => {
const schema = fromJSONSchema({
enum: ["string", 42, true, null],
});
expect(schema.parse("string")).toBe("string");
expect(schema.parse(42)).toBe(42);
expect(schema.parse(true)).toBe(true);
expect(schema.parse(null)).toBe(null);
});
test("nullable in OpenAPI 3.0", () => {
// General nullable case (not just enum: [null])
const stringSchema = fromJSONSchema(
{
type: "string",
nullable: true,
},
{ defaultTarget: "openapi-3.0" }
);
expect(stringSchema.parse("hello")).toBe("hello");
expect(stringSchema.parse(null)).toBe(null);
expect(() => stringSchema.parse(123)).toThrow();
const numberSchema = fromJSONSchema(
{
type: "number",
nullable: true,
},
{ defaultTarget: "openapi-3.0" }
);
expect(numberSchema.parse(42)).toBe(42);
expect(numberSchema.parse(null)).toBe(null);
expect(() => numberSchema.parse("string")).toThrow();
const objectSchema = fromJSONSchema(
{
type: "object",
properties: { name: { type: "string" } },
nullable: true,
},
{ defaultTarget: "openapi-3.0" }
);
expect(objectSchema.parse({ name: "John" })).toEqual({ name: "John" });
expect(objectSchema.parse(null)).toBe(null);
});
// Metadata extraction tests
test("unrecognized keys stored in globalRegistry by default", () => {
const schema = fromJSONSchema({
type: "string",
title: "My String",
deprecated: true,
examples: ["hello", "world"],
"x-custom": "custom value",
});
const meta = z.globalRegistry.get(schema);
expect(meta).toBeDefined();
expect(meta?.title).toBe("My String");
expect(meta?.deprecated).toBe(true);
expect(meta?.examples).toEqual(["hello", "world"]);
expect((meta as any)?.["x-custom"]).toBe("custom value");
// Clean up
z.globalRegistry.remove(schema);
});
test("unrecognized keys stored in custom registry", () => {
const customRegistry = z.registry<{ title?: string; deprecated?: boolean }>();
const schema = fromJSONSchema(
{
type: "number",
title: "Age",
deprecated: true,
},
{ registry: customRegistry }
);
// Should be in custom registry
const meta = customRegistry.get(schema);
expect(meta).toBeDefined();
expect(meta?.title).toBe("Age");
expect(meta?.deprecated).toBe(true);
// Should NOT be in globalRegistry
expect(z.globalRegistry.get(schema)).toBeUndefined();
});
test("$id and id are captured as metadata", () => {
const customRegistry = z.registry<{ $id?: string; id?: string }>();
const schema1 = fromJSONSchema(
{
$id: "https://example.com/schemas/user",
type: "object",
},
{ registry: customRegistry }
);
expect(customRegistry.get(schema1)?.$id).toBe("https://example.com/schemas/user");
const schema2 = fromJSONSchema(
{
id: "legacy-id",
type: "string",
},
{ registry: customRegistry }
);
expect(customRegistry.get(schema2)?.id).toBe("legacy-id");
});
test("x-* extension keys are captured as metadata", () => {
const customRegistry = z.registry<Record<string, unknown>>();
const schema = fromJSONSchema(
{
type: "string",
"x-openapi-example": "example value",
"x-internal": true,
"x-tags": ["api", "public"],
},
{ registry: customRegistry }
);
const meta = customRegistry.get(schema);
expect(meta?.["x-openapi-example"]).toBe("example value");
expect(meta?.["x-internal"]).toBe(true);
expect(meta?.["x-tags"]).toEqual(["api", "public"]);
});
test("metadata on nested schemas", () => {
const customRegistry = z.registry<Record<string, unknown>>();
const parentSchema = fromJSONSchema(
{
type: "object",
title: "User",
properties: {
name: {
type: "string",
title: "Name",
"x-field-order": 1,
},
age: {
type: "number",
title: "Age",
deprecated: true,
},
},
},
{ registry: customRegistry }
);
// Verify parent schema has its metadata
expect(customRegistry.get(parentSchema)?.title).toBe("User");
// We can't easily access nested schemas directly, but we can verify
// the registry is being used correctly by checking a separate schema
const simpleSchema = fromJSONSchema(
{
type: "string",
title: "Simple",
},
{ registry: customRegistry }
);
expect(customRegistry.get(simpleSchema)?.title).toBe("Simple");
});
test("no metadata added when no unrecognized keys", () => {
const customRegistry = z.registry<Record<string, unknown>>();
const schema = fromJSONSchema(
{
type: "string",
minLength: 1,
maxLength: 100,
description: "A regular string",
},
{ registry: customRegistry }
);
// description is handled via .describe(), so it shouldn't be in metadata
// All other keys are recognized, so no metadata should be added
expect(customRegistry.get(schema)).toBeUndefined();
});
test("writeOnly and examples are captured as metadata", () => {
const customRegistry = z.registry<{ writeOnly?: boolean; examples?: unknown[] }>();
const schema = fromJSONSchema(
{
type: "string",
writeOnly: true,
examples: ["password123", "secret"],
},
{ registry: customRegistry }
);
const meta = customRegistry.get(schema);
expect(meta?.writeOnly).toBe(true);
expect(meta?.examples).toEqual(["password123", "secret"]);
});
test("$comment and $anchor are captured as metadata", () => {
const customRegistry = z.registry<{ $comment?: string; $anchor?: string }>();
const schema = fromJSONSchema(
{
type: "string",
$comment: "This is a developer note",
$anchor: "my-anchor",
},
{ registry: customRegistry }
);
const meta = customRegistry.get(schema);
expect(meta?.$comment).toBe("This is a developer note");
expect(meta?.$anchor).toBe("my-anchor");
});
test("contentEncoding and contentMediaType are stored as metadata", () => {
const customRegistry = z.registry<{ contentEncoding?: string; contentMediaType?: string }>();
const schema = fromJSONSchema(
{
type: "string",
contentEncoding: "base64",
contentMediaType: "image/png",
},
{ registry: customRegistry }
);
// Should just be a string schema
expect(schema.parse("aGVsbG8gd29ybGQ=")).toBe("aGVsbG8gd29ybGQ=");
// Content keywords should be in metadata
const meta = customRegistry.get(schema);
expect(meta?.contentEncoding).toBe("base64");
expect(meta?.contentMediaType).toBe("image/png");
});
test("description on enum schema is applied", () => {
const schema = fromJSONSchema({
enum: ["red", "green", "blue"],
description: "A color value",
});
expect(schema.description).toBe("A color value");
expect(schema.parse("red")).toBe("red");
});
test("description on const schema is applied", () => {
const schema = fromJSONSchema({
const: "hello",
description: "A greeting",
});
expect(schema.description).toBe("A greeting");
expect(schema.parse("hello")).toBe("hello");
});
test("description on not: {} (never) schema is applied", () => {
const schema = fromJSONSchema({
not: {},
description: "A never schema",
});
expect(schema.description).toBe("A never schema");
expect(() => schema.parse("anything")).toThrow();
});
test("default on enum schema is applied", () => {
const schema = fromJSONSchema({
enum: ["red", "green", "blue"],
default: "red",
});
expect(schema.parse(undefined)).toBe("red");
});
test("default on const schema is applied", () => {
const schema = fromJSONSchema({
const: "hello",
default: "hello",
});
expect(schema.parse(undefined)).toBe("hello");
});
test("description and default on enum schema are both applied", () => {
const schema = fromJSONSchema({
enum: ["red", "green", "blue"],
description: "A color value",
default: "red",
});
expect(schema.description).toBe("A color value");
expect(schema.parse(undefined)).toBe("red");
expect(schema.parse("green")).toBe("green");
});
test("description on type-array schema is applied", () => {
const schema = fromJSONSchema({
type: ["string", "number"],
description: "A string or number",
} as any);
expect(schema.description).toBe("A string or number");
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse(42)).toBe(42);
});
test("default on type-array schema is applied", () => {
const schema = fromJSONSchema({
type: ["string", "number"],
default: "fallback",
} as any);
expect(schema.parse(undefined)).toBe("fallback");
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse(42)).toBe(42);
});
test("description on schema with anyOf is applied to the outer schema", () => {
const schema = fromJSONSchema({
description: "Either a string or a number",
anyOf: [{ type: "string" }, { type: "number" }],
});
expect(schema.description).toBe("Either a string or a number");
expect(schema.parse("hello")).toBe("hello");
expect(schema.parse(42)).toBe(42);
});
test("default on schema with anyOf is applied to the outer schema", () => {
const schema = fromJSONSchema({
default: "fallback",
anyOf: [{ type: "string" }, { type: "number" }],
});
expect(schema.parse(undefined)).toBe("fallback");
expect(schema.parse(42)).toBe(42);
});
test("description and unrecognized metadata coexist on the same schema", () => {
const customRegistry = z.registry<{ "x-custom"?: string; description?: string }>();
const schema = fromJSONSchema(
{
type: "string",
description: "A custom string",
"x-custom": "value",
},
{ registry: customRegistry }
);
expect(schema.description).toBe("A custom string");
expect(customRegistry.get(schema)?.["x-custom"]).toBe("value");
});
test("circular input throws a clear error", () => {
const person: any = {
type: "object",
properties: { name: { type: "string" } },
required: ["name"],
};
person.properties.bestFriend = person;
expect(() => fromJSONSchema(person)).toThrow(/not valid JSON/);
});
test("getter-based input that synthesizes a cycle throws", () => {
const root: any = { type: "object", properties: { name: { type: "string" } } };
Object.defineProperty(root.properties, "self", {
enumerable: true,
get() {
return root;
},
});
expect(() => fromJSONSchema(root)).toThrow(/not valid JSON/);
});
test("BigInt in input throws", () => {
const input: any = { type: "integer", minimum: 1n };
expect(() => fromJSONSchema(input)).toThrow(/not valid JSON/);
});
test("class-instance input is normalized to a plain object", () => {
class StringSchema {
type = "string" as const;
minLength = 2;
}
const schema = fromJSONSchema(new StringSchema() as any);
expect(schema.parse("hi")).toBe("hi");
expect(() => schema.parse("h")).toThrow();
});
test("getter-based properties are materialized", () => {
const input: any = { type: "object", properties: {}, required: [] };
Object.defineProperty(input.properties, "name", {
enumerable: true,
get() {
return { type: "string" };
},
});
const schema = fromJSONSchema(input);
expect(schema.parse({ name: "Alice" })).toEqual({ name: "Alice" });
});
test("Date default is coerced to its JSON string form", () => {
const date = new Date("2026-01-02T03:04:05.000Z");
const schema = fromJSONSchema({ type: "string", default: date as any });
expect(schema.parse(undefined)).toBe(date.toISOString());
});

View File

@@ -0,0 +1,3 @@
import type * as ts from 'typescript';
export declare function getTypeOfPropertyOfName(checker: ts.TypeChecker, type: ts.Type, name: string, escapedName?: ts.__String): ts.Type | undefined;
export declare function getTypeOfPropertyOfType(checker: ts.TypeChecker, type: ts.Type, property: ts.Symbol): ts.Type | undefined;

View File

@@ -0,0 +1,618 @@
'use strict'
let AtRule = require('./at-rule')
let Comment = require('./comment')
let Declaration = require('./declaration')
let Root = require('./root')
let Rule = require('./rule')
let tokenizer = require('./tokenize')
const SAFE_COMMENT_NEIGHBOR = {
empty: true,
space: true
}
function findLastWithPosition(tokens) {
for (let i = tokens.length - 1; i >= 0; i--) {
let token = tokens[i]
let pos = token[3] || token[2]
if (pos) return pos
}
}
function tokensToString(tokens, from, to) {
let result = ''
for (let i = from; i < to; i++) result += tokens[i][1]
return result
}
class Parser {
constructor(input) {
this.input = input
this.root = new Root()
this.current = this.root
this.spaces = ''
this.semicolon = false
this.createTokenizer()
this.root.source = { input, start: { column: 1, line: 1, offset: 0 } }
}
atrule(token) {
let node = new AtRule()
node.name = token[1].slice(1)
if (node.name === '') {
this.unnamedAtrule(node, token)
}
this.init(node, token[2])
let type
let prev
let shift
let last = false
let open = false
let params = []
let brackets = []
while (!this.tokenizer.endOfFile()) {
token = this.tokenizer.nextToken()
type = token[0]
if (type === '(' || type === '[') {
brackets.push(type === '(' ? ')' : ']')
} else if (type === '{' && brackets.length > 0) {
brackets.push('}')
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
}
if (brackets.length === 0) {
if (type === ';') {
node.source.end = this.getPosition(token[2])
node.source.end.offset++
this.semicolon = true
break
} else if (type === '{') {
open = true
break
} else if (type === '}') {
if (params.length > 0) {
shift = params.length - 1
prev = params[shift]
while (prev && prev[0] === 'space') {
prev = params[--shift]
}
if (prev) {
node.source.end = this.getPosition(prev[3] || prev[2])
node.source.end.offset++
}
}
this.end(token)
break
} else {
params.push(token)
}
} else {
params.push(token)
}
if (this.tokenizer.endOfFile()) {
last = true
break
}
}
node.raws.between = this.spacesAndCommentsFromEnd(params)
if (params.length) {
node.raws.afterName = this.spacesAndCommentsFromStart(params)
this.raw(node, 'params', params)
if (last) {
token = params[params.length - 1]
node.source.end = this.getPosition(token[3] || token[2])
node.source.end.offset++
this.spaces = node.raws.between
node.raws.between = ''
}
} else {
node.raws.afterName = ''
node.params = ''
}
if (open) {
node.nodes = []
this.current = node
}
}
checkMissedSemicolon(tokens) {
let colon = this.colon(tokens)
if (colon === false) return
let founded = 0
let token
for (let j = colon - 1; j >= 0; j--) {
token = tokens[j]
if (token[0] !== 'space') {
founded += 1
if (founded === 2) break
}
}
// If the token is a word, e.g. `!important`, `red` or any other valid
// property's value. Then we need to return the colon after that word
// token. [3] is the "end" colon of that word. And because we need it
// after that one we do +1 to get the next one.
throw this.input.error(
'Missed semicolon',
token[0] === 'word' ? token[3] + 1 : token[2]
)
}
colon(tokens) {
let brackets = 0
let prev, token, type
for (let [i, element] of tokens.entries()) {
token = element
type = token[0]
if (type === '(') {
brackets += 1
}
if (type === ')') {
brackets -= 1
}
if (brackets === 0 && type === ':') {
if (!prev) {
this.doubleColon(token)
} else if (prev[0] === 'word' && prev[1] === 'progid') {
continue
} else {
return i
}
}
prev = token
}
return false
}
comment(token) {
let node = new Comment()
this.init(node, token[2])
node.source.end = this.getPosition(token[3] || token[2])
node.source.end.offset++
let text = token[1].slice(2, -2)
if (!text.trim()) {
node.text = ''
node.raws.left = text
node.raws.right = ''
} else {
let match = text.match(/^(\s*)([^]*\S)(\s*)$/)
node.text = match[2]
node.raws.left = match[1]
node.raws.right = match[3]
}
}
createTokenizer() {
this.tokenizer = tokenizer(this.input)
}
decl(tokens, customProperty) {
let node = new Declaration()
this.init(node, tokens[0][2])
let last = tokens[tokens.length - 1]
if (last[0] === ';') {
this.semicolon = true
tokens.pop()
}
node.source.end = this.getPosition(
last[3] || last[2] || findLastWithPosition(tokens)
)
node.source.end.offset++
let start = 0
while (tokens[start][0] !== 'word') {
if (start === tokens.length - 1) this.unknownWord([tokens[start]])
start++
}
node.raws.before += tokensToString(tokens, 0, start)
node.source.start = this.getPosition(tokens[start][2])
let propStart = start
while (start < tokens.length) {
let type = tokens[start][0]
if (type === ':' || type === 'space' || type === 'comment') {
break
}
start++
}
node.prop = tokensToString(tokens, propStart, start)
let betweenStart = start
let token
while (start < tokens.length) {
token = tokens[start]
start++
if (token[0] === ':') break
if (token[0] === 'word' && /\w/.test(token[1])) {
this.unknownWord([token])
}
}
node.raws.between = tokensToString(tokens, betweenStart, start)
if (node.prop[0] === '_' || node.prop[0] === '*') {
node.raws.before += node.prop[0]
node.prop = node.prop.slice(1)
}
let firstSpacesStart = start
while (start < tokens.length) {
let next = tokens[start][0]
if (next !== 'space' && next !== 'comment') break
start++
}
let firstSpaces = tokens.slice(firstSpacesStart, start)
tokens = tokens.slice(start)
this.precheckMissedSemicolon(tokens)
for (let i = tokens.length - 1; i >= 0; i--) {
token = tokens[i]
if (token[1].toLowerCase() === '!important') {
node.important = true
let string = this.stringFrom(tokens, i)
string = this.spacesFromEnd(tokens) + string
if (string !== ' !important') node.raws.important = string
break
} else if (token[1].toLowerCase() === 'important') {
let cache = tokens.slice(0)
let str = ''
for (let j = i; j > 0; j--) {
let type = cache[j][0]
if (str.trim().startsWith('!') && type !== 'space') {
break
}
str = cache.pop()[1] + str
}
if (str.trim().startsWith('!')) {
node.important = true
node.raws.important = str
tokens = cache
}
}
if (token[0] !== 'space' && token[0] !== 'comment') {
break
}
}
let hasWord = tokens.some(i => i[0] !== 'space' && i[0] !== 'comment')
if (hasWord) {
node.raws.between += firstSpaces.map(i => i[1]).join('')
firstSpaces = []
}
this.raw(node, 'value', firstSpaces.concat(tokens), customProperty)
if (node.value.includes(':') && !customProperty) {
this.checkMissedSemicolon(tokens)
}
}
doubleColon(token) {
throw this.input.error(
'Double colon',
{ offset: token[2] },
{ offset: token[2] + token[1].length }
)
}
emptyRule(token) {
let node = new Rule()
this.init(node, token[2])
node.selector = ''
node.raws.between = ''
this.current = node
}
end(token) {
if (this.current.nodes && this.current.nodes.length) {
this.current.raws.semicolon = this.semicolon
}
this.semicolon = false
this.current.raws.after = (this.current.raws.after || '') + this.spaces
this.spaces = ''
if (this.current.parent) {
this.current.source.end = this.getPosition(token[2])
this.current.source.end.offset++
this.current = this.current.parent
} else {
this.unexpectedClose(token)
}
}
endFile() {
if (this.current.parent) this.unclosedBlock()
if (this.current.nodes && this.current.nodes.length) {
this.current.raws.semicolon = this.semicolon
}
this.current.raws.after = (this.current.raws.after || '') + this.spaces
this.root.source.end = this.getPosition(this.tokenizer.position())
}
freeSemicolon(token) {
this.spaces += token[1]
if (this.current.nodes) {
let prev = this.current.nodes[this.current.nodes.length - 1]
if (prev && prev.type === 'rule' && !prev.raws.ownSemicolon) {
prev.raws.ownSemicolon = this.spaces
this.spaces = ''
prev.source.end = this.getPosition(token[2])
prev.source.end.offset += prev.raws.ownSemicolon.length
}
}
}
// Helpers
getPosition(offset) {
let pos = this.input.fromOffset(offset)
return {
column: pos.col,
line: pos.line,
offset
}
}
init(node, offset) {
this.current.push(node)
node.source = {
input: this.input,
start: this.getPosition(offset)
}
node.raws.before = this.spaces
this.spaces = ''
if (node.type !== 'comment') this.semicolon = false
}
other(start) {
let end = false
let type = null
let colon = false
let bracket = null
let brackets = []
let customProperty = start[1].startsWith('--')
let tokens = []
let token = start
while (token) {
type = token[0]
tokens.push(token)
if (type === '(' || type === '[') {
if (!bracket) bracket = token
brackets.push(type === '(' ? ')' : ']')
} else if (customProperty && colon && type === '{') {
if (!bracket) bracket = token
brackets.push('}')
} else if (brackets.length === 0) {
if (type === ';') {
if (colon) {
this.decl(tokens, customProperty)
return
} else {
break
}
} else if (type === '{') {
this.rule(tokens)
return
} else if (type === '}') {
this.tokenizer.back(tokens.pop())
end = true
break
} else if (type === ':') {
colon = true
}
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
if (brackets.length === 0) bracket = null
}
token = this.tokenizer.nextToken()
}
if (this.tokenizer.endOfFile()) end = true
if (brackets.length > 0) this.unclosedBracket(bracket)
if (end && colon) {
if (!customProperty) {
while (tokens.length) {
token = tokens[tokens.length - 1][0]
if (token !== 'space' && token !== 'comment') break
this.tokenizer.back(tokens.pop())
}
}
this.decl(tokens, customProperty)
} else {
this.unknownWord(tokens)
}
}
parse() {
let token
while (!this.tokenizer.endOfFile()) {
token = this.tokenizer.nextToken()
switch (token[0]) {
case 'space':
this.spaces += token[1]
break
case ';':
this.freeSemicolon(token)
break
case '}':
this.end(token)
break
case 'comment':
this.comment(token)
break
case 'at-word':
this.atrule(token)
break
case '{':
this.emptyRule(token)
break
default:
this.other(token)
break
}
}
this.endFile()
}
precheckMissedSemicolon(/* tokens */) {
// Hook for Safe Parser
}
raw(node, prop, tokens, customProperty) {
let token, type
let length = tokens.length
let value = ''
let clean = true
let next, prev
for (let i = 0; i < length; i += 1) {
token = tokens[i]
type = token[0]
if (type === 'space' && i === length - 1 && !customProperty) {
clean = false
} else if (type === 'comment') {
prev = tokens[i - 1] ? tokens[i - 1][0] : 'empty'
next = tokens[i + 1] ? tokens[i + 1][0] : 'empty'
if (!SAFE_COMMENT_NEIGHBOR[prev] && !SAFE_COMMENT_NEIGHBOR[next]) {
if (value.slice(-1) === ',') {
clean = false
} else {
value += token[1]
}
} else {
clean = false
}
} else {
value += token[1]
}
}
if (!clean) {
let raw = tokens.reduce((all, i) => all + i[1], '')
node.raws[prop] = { raw, value }
}
node[prop] = value
}
rule(tokens) {
tokens.pop()
let node = new Rule()
this.init(node, tokens[0][2])
node.raws.between = this.spacesAndCommentsFromEnd(tokens)
this.raw(node, 'selector', tokens)
this.current = node
}
spacesAndCommentsFromEnd(tokens) {
let lastTokenType
let spaces = ''
while (tokens.length) {
lastTokenType = tokens[tokens.length - 1][0]
if (lastTokenType !== 'space' && lastTokenType !== 'comment') break
spaces = tokens.pop()[1] + spaces
}
return spaces
}
// Errors
spacesAndCommentsFromStart(tokens) {
let next
let spaces = ''
while (tokens.length) {
next = tokens[0][0]
if (next !== 'space' && next !== 'comment') break
spaces += tokens.shift()[1]
}
return spaces
}
spacesFromEnd(tokens) {
let lastTokenType
let spaces = ''
while (tokens.length) {
lastTokenType = tokens[tokens.length - 1][0]
if (lastTokenType !== 'space') break
spaces = tokens.pop()[1] + spaces
}
return spaces
}
stringFrom(tokens, from) {
let result = ''
for (let i = from; i < tokens.length; i++) {
result += tokens[i][1]
}
tokens.splice(from, tokens.length - from)
return result
}
unclosedBlock() {
let pos = this.current.source.start
throw this.input.error('Unclosed block', pos.line, pos.column)
}
unclosedBracket(bracket) {
throw this.input.error(
'Unclosed bracket',
{ offset: bracket[2] },
{ offset: bracket[2] + 1 }
)
}
unexpectedClose(token) {
throw this.input.error(
'Unexpected }',
{ offset: token[2] },
{ offset: token[2] + 1 }
)
}
unknownWord(tokens) {
throw this.input.error(
'Unknown word ' + tokens[0][1],
{ offset: tokens[0][2] },
{ offset: tokens[0][2] + tokens[0][1].length }
)
}
unnamedAtrule(node, token) {
throw this.input.error(
'At-rule without name',
{ offset: token[2] },
{ offset: token[2] + token[1].length }
)
}
}
module.exports = Parser

View File

@@ -0,0 +1,147 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/// <reference no-default-lib="true"/>
interface Map<K, V> {
clear(): void;
/**
* @returns true if an element in the Map existed and has been removed, or false if the element does not exist.
*/
delete(key: K): boolean;
/**
* Executes a provided function once per each key/value pair in the Map, in insertion order.
*/
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
/**
* Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
*/
get(key: K): V | undefined;
/**
* @returns boolean indicating whether an element with the specified key exists or not.
*/
has(key: K): boolean;
/**
* Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
*/
set(key: K, value: V): this;
/**
* @returns the number of elements in the Map.
*/
readonly size: number;
}
interface MapConstructor {
new (): Map<any, any>;
new <K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>;
readonly prototype: Map<any, any>;
}
declare var Map: MapConstructor;
interface ReadonlyMap<K, V> {
forEach(callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void, thisArg?: any): void;
get(key: K): V | undefined;
has(key: K): boolean;
readonly size: number;
}
interface WeakMap<K extends WeakKey, V> {
/**
* Removes the specified element from the WeakMap.
* @returns true if the element was successfully removed, or false if it was not present.
*/
delete(key: K): boolean;
/**
* @returns a specified element.
*/
get(key: K): V | undefined;
/**
* @returns a boolean indicating whether an element with the specified key exists or not.
*/
has(key: K): boolean;
/**
* Adds a new element with a specified key and value.
* @param key Must be an object or symbol.
*/
set(key: K, value: V): this;
}
interface WeakMapConstructor {
new <K extends WeakKey = WeakKey, V = any>(entries?: readonly (readonly [K, V])[] | null): WeakMap<K, V>;
readonly prototype: WeakMap<WeakKey, any>;
}
declare var WeakMap: WeakMapConstructor;
interface Set<T> {
/**
* Appends a new element with a specified value to the end of the Set.
*/
add(value: T): this;
clear(): void;
/**
* Removes a specified value from the Set.
* @returns Returns true if an element in the Set existed and has been removed, or false if the element does not exist.
*/
delete(value: T): boolean;
/**
* Executes a provided function once per each value in the Set object, in insertion order.
*/
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void;
/**
* @returns a boolean indicating whether an element with the specified value exists in the Set or not.
*/
has(value: T): boolean;
/**
* @returns the number of (unique) elements in Set.
*/
readonly size: number;
}
interface SetConstructor {
new <T = any>(values?: readonly T[] | null): Set<T>;
readonly prototype: Set<any>;
}
declare var Set: SetConstructor;
interface ReadonlySet<T> {
forEach(callbackfn: (value: T, value2: T, set: ReadonlySet<T>) => void, thisArg?: any): void;
has(value: T): boolean;
readonly size: number;
}
interface WeakSet<T extends WeakKey> {
/**
* Appends a new value to the end of the WeakSet.
*/
add(value: T): this;
/**
* Removes the specified element from the WeakSet.
* @returns Returns true if the element existed and has been removed, or false if the element does not exist.
*/
delete(value: T): boolean;
/**
* @returns a boolean indicating whether a value exists in the WeakSet or not.
*/
has(value: T): boolean;
}
interface WeakSetConstructor {
new <T extends WeakKey = WeakKey>(values?: readonly T[] | null): WeakSet<T>;
readonly prototype: WeakSet<WeakKey>;
}
declare var WeakSet: WeakSetConstructor;

View File

@@ -0,0 +1,9 @@
import validate from './validate.js';
function parse(uuid) {
if (!validate(uuid)) {
throw TypeError('Invalid UUID');
}
let v;
return Uint8Array.of((v = parseInt(uuid.slice(0, 8), 16)) >>> 24, (v >>> 16) & 0xff, (v >>> 8) & 0xff, v & 0xff, (v = parseInt(uuid.slice(9, 13), 16)) >>> 8, v & 0xff, (v = parseInt(uuid.slice(14, 18), 16)) >>> 8, v & 0xff, (v = parseInt(uuid.slice(19, 23), 16)) >>> 8, v & 0xff, ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff, (v / 0x100000000) & 0xff, (v >>> 24) & 0xff, (v >>> 16) & 0xff, (v >>> 8) & 0xff, v & 0xff);
}
export default parse;

View File

@@ -0,0 +1 @@
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["src/crypto.ts"],"names":[],"mappings":";;;AAOa,QAAA,MAAM,GACjB,OAAO,UAAU,KAAK,QAAQ,IAAI,QAAQ,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC"}

View File

@@ -0,0 +1,67 @@
/**
* Tokenizes the given code.
* @param {string} code The code to tokenize.
* @param {Options} [options] Options defining how to tokenize.
* @returns {EspreeTokens} An array of tokens.
* @throws {EnhancedSyntaxError} If the input code is invalid.
* @private
*/
export function tokenize(code: string, options?: Options): EspreeTokens;
/**
* Parses the given code.
* @param {string} code The code to tokenize.
* @param {Options} [options] Options defining how to tokenize.
* @returns {acorn.Program} The "Program" AST node.
* @throws {EnhancedSyntaxError} If the input code is invalid.
*/
export function parse(code: string, options?: Options): acorn.Program;
/** @type {string} */
export const version: string;
export const name: "espree";
export const Syntax: Record<string, string>;
export const latestEcmaVersion: 17;
export const supportedEcmaVersions: [3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
export { KEYS as VisitorKeys } from "eslint-visitor-keys";
export type EcmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | "latest";
export type EspreeToken = {
type: string;
value: any;
start?: number;
end?: number;
loc?: acorn.SourceLocation;
range?: [number, number];
regex?: {
flags: string;
pattern: string;
};
};
export type EspreeComment = {
type: "Block" | "Hashbang" | "Line";
value: string;
range?: [number, number];
start?: number;
end?: number;
loc?: {
start: acorn.Position | undefined;
end: acorn.Position | undefined;
};
};
export type EspreeTokens = {
comments?: EspreeComment[];
} & EspreeToken[];
export type Options = {
allowReserved?: boolean;
ecmaVersion?: EcmaVersion;
sourceType?: "script" | "module" | "commonjs";
ecmaFeatures?: {
jsx?: boolean;
globalReturn?: boolean;
impliedStrict?: boolean;
};
range?: boolean;
loc?: boolean;
tokens?: boolean;
comment?: boolean;
};
import * as acorn from "acorn";
//# sourceMappingURL=espree.d.ts.map

View File

@@ -0,0 +1,17 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
/**
* Gets the location of the head of the given for statement variant for reporting.
*
* - `for (const foo in bar) expressionOrBlock`
* ^^^^^^^^^^^^^^^^^^^^^^
*
* - `for (const foo of bar) expressionOrBlock`
* ^^^^^^^^^^^^^^^^^^^^^^
*
* - `for await (const foo of bar) expressionOrBlock`
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* - `for (let i = 0; i < 10; i++) expressionOrBlock`
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
export declare function getForStatementHeadLoc(sourceCode: TSESLint.SourceCode, node: TSESTree.ForInStatement | TSESTree.ForOfStatement | TSESTree.ForStatement): TSESTree.SourceLocation;

View File

@@ -0,0 +1,13 @@
type Modifier = 'private' | 'private readonly' | 'protected' | 'protected readonly' | 'public' | 'public readonly' | 'readonly';
type Prefer = 'class-property' | 'parameter-property';
export type Options = [
{
allow?: Modifier[];
prefer?: Prefer;
}
];
export type MessageIds = 'preferClassProperty' | 'preferParameterProperty';
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1 @@
{"version":3,"file":"modifierFlags.enum.d.ts","sourceRoot":"","sources":["../../src/enums/modifierFlags.enum.ts"],"names":[],"mappings":"AAEA,oBAAY,aAAa;IACrB,IAAI,IAAI;IACR,MAAM,IAAS;IACf,OAAO,IAAS;IAChB,SAAS,IAAS;IAClB,QAAQ,IAAS;IACjB,QAAQ,KAAS;IACjB,MAAM,KAAS;IACf,QAAQ,KAAS;IACjB,OAAO,MAAS;IAChB,MAAM,MAAS;IACf,QAAQ,MAAS;IACjB,KAAK,OAAU;IACf,OAAO,OAAU;IACjB,KAAK,OAAU;IACf,EAAE,OAAU;IACZ,GAAG,QAAU;IACb,SAAS,QAAU;IACnB,UAAU,QAAU;IACpB,WAAW,UAAU;IACrB,YAAY,WAAU;IACtB,cAAc,WAAU;IACxB,aAAa,WAAU;IACvB,aAAa,YAAU;IACvB,yBAAyB,YAAU;IACnC,gBAAgB,YAAU;IAC1B,yBAAyB,KAAqD;IAC9E,sBAAsB,QAAmG;IACzH,kBAAkB,QAAqD;IACvE,uBAAuB,YAA8E;IACrG,kBAAkB,QAAa;IAC/B,qBAAqB,SAA0E;IAC/F,qBAAqB,IAA+B;IACpD,yBAAyB,KAA8C;IACvE,8BAA8B,IAAsB;IACpD,kBAAkB,QAA6F;IAC/G,aAAa,OAAmB;IAChC,GAAG,SAAqK;IACxK,QAAQ,QAAmB;IAC3B,UAAU,OAA+C;CAC5D"}

View File

@@ -0,0 +1,84 @@
'use strict'
const { test } = require('node:test')
const { rimraf } = require('rimraf')
const fs = require('node:fs')
const { join } = require('node:path')
const buildSafeSonicBoom = require('./build-safe-sonic-boom')
const file = () => {
const dest = join(__dirname, `${process.pid}-${process.hrtime().toString()}`)
const fd = fs.openSync(dest, 'w')
return { dest, fd }
}
test('should not write when error emitted and code is "EPIPE"', t => {
t.plan(1)
const { fd, dest } = file()
const stream = buildSafeSonicBoom({ sync: true, fd, mkdir: true })
t.after(() => rimraf(dest))
stream.emit('error', { code: 'EPIPE' })
stream.write('will not work')
const dataFile = fs.readFileSync(dest)
t.assert.strictEqual(dataFile.length, 0)
})
test('should stream.write works when error code is not "EPIPE"', t => {
t.plan(3)
const { fd, dest } = file()
const stream = buildSafeSonicBoom({ sync: true, fd, mkdir: true })
t.after(() => rimraf(dest))
stream.on('error', () => t.assert.ok('error emitted'))
stream.emit('error', 'fake error description')
t.assert.ok(stream.write('will work'))
const dataFile = fs.readFileSync(dest)
t.assert.strictEqual(dataFile.toString(), 'will work')
})
test('cover setupOnExit', async t => {
t.plan(3)
const { fd, dest } = file()
const stream = buildSafeSonicBoom({ sync: false, fd, mkdir: true })
t.after(() => rimraf(dest))
stream.on('error', () => t.assert.ok('error emitted'))
stream.emit('error', 'fake error description')
t.assert.ok(stream.write('will work'))
await watchFileCreated(dest)
const dataFile = fs.readFileSync(dest)
t.assert.strictEqual(dataFile.toString(), 'will work')
})
function watchFileCreated (filename) {
return new Promise((resolve, reject) => {
const TIMEOUT = 2000
const INTERVAL = 100
const threshold = TIMEOUT / INTERVAL
let counter = 0
const interval = setInterval(() => {
// On some CI runs file is created but not filled
if (fs.existsSync(filename) && fs.statSync(filename).size !== 0) {
clearInterval(interval)
resolve()
} else if (counter <= threshold) {
counter++
} else {
clearInterval(interval)
reject(new Error(`${filename} was not created.`))
}
}, INTERVAL)
})
}

View File

@@ -0,0 +1,11 @@
import type { TSESLint } from '@typescript-eslint/utils';
type MessageId = 'noStrictNullCheck' | 'preferOptionalSyntax' | 'uselessDefaultAssignment' | 'uselessUndefined';
type Options = [
{
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
}
];
declare const _default: TSESLint.RuleModule<MessageId, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1 @@
{"version":3,"file":"_shortw_utils.d.ts","sourceRoot":"","sources":["src/_shortw_utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,sEAAsE;AACtE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAe,MAAM,2BAA2B,CAAC;AACtF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAEpD;AACD,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AACzD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAA;CAAE,CAAC;AAE/E,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,GAAG,iBAAiB,CAGjF"}

View File

@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isLoop = exports.isImportKeyword = exports.isTypeKeyword = exports.isAwaitKeyword = exports.isAwaitExpression = exports.isIdentifier = exports.isConstructor = exports.isClassOrTypeElement = exports.isTSConstructorType = exports.isTSFunctionType = exports.isFunctionOrFunctionType = exports.isFunctionType = exports.isFunction = exports.isVariableDeclarator = exports.isTypeAssertion = exports.isLogicalOrOperator = exports.isOptionalCallExpression = exports.isNotNonNullAssertionPunctuator = exports.isNonNullAssertionPunctuator = exports.isNotOptionalChainPunctuator = exports.isOptionalChainPunctuator = void 0;
exports.isSetter = isSetter;
const ts_estree_1 = require("../ts-estree");
const helpers_1 = require("./helpers");
exports.isOptionalChainPunctuator = (0, helpers_1.isTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Punctuator, { value: '?.' });
exports.isNotOptionalChainPunctuator = (0, helpers_1.isNotTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Punctuator, { value: '?.' });
exports.isNonNullAssertionPunctuator = (0, helpers_1.isTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Punctuator, { value: '!' });
exports.isNotNonNullAssertionPunctuator = (0, helpers_1.isNotTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Punctuator, { value: '!' });
/**
* Returns true if and only if the node represents: foo?.() or foo.bar?.()
*/
exports.isOptionalCallExpression = (0, helpers_1.isNodeOfTypeWithConditions)(ts_estree_1.AST_NODE_TYPES.CallExpression,
// this flag means the call expression itself is option
// i.e. it is foo.bar?.() and not foo?.bar()
{ optional: true });
/**
* Returns true if and only if the node represents logical OR
*/
exports.isLogicalOrOperator = (0, helpers_1.isNodeOfTypeWithConditions)(ts_estree_1.AST_NODE_TYPES.LogicalExpression, { operator: '||' });
/**
* Checks if a node is a type assertion:
* ```
* x as foo
* <foo>x
* ```
*/
exports.isTypeAssertion = (0, helpers_1.isNodeOfTypes)([
ts_estree_1.AST_NODE_TYPES.TSAsExpression,
ts_estree_1.AST_NODE_TYPES.TSTypeAssertion,
]);
exports.isVariableDeclarator = (0, helpers_1.isNodeOfType)(ts_estree_1.AST_NODE_TYPES.VariableDeclarator);
const functionTypes = [
ts_estree_1.AST_NODE_TYPES.ArrowFunctionExpression,
ts_estree_1.AST_NODE_TYPES.FunctionDeclaration,
ts_estree_1.AST_NODE_TYPES.FunctionExpression,
];
exports.isFunction = (0, helpers_1.isNodeOfTypes)(functionTypes);
const functionTypeTypes = [
ts_estree_1.AST_NODE_TYPES.TSCallSignatureDeclaration,
ts_estree_1.AST_NODE_TYPES.TSConstructorType,
ts_estree_1.AST_NODE_TYPES.TSConstructSignatureDeclaration,
ts_estree_1.AST_NODE_TYPES.TSDeclareFunction,
ts_estree_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
ts_estree_1.AST_NODE_TYPES.TSFunctionType,
ts_estree_1.AST_NODE_TYPES.TSMethodSignature,
];
exports.isFunctionType = (0, helpers_1.isNodeOfTypes)(functionTypeTypes);
exports.isFunctionOrFunctionType = (0, helpers_1.isNodeOfTypes)([
...functionTypes,
...functionTypeTypes,
]);
exports.isTSFunctionType = (0, helpers_1.isNodeOfType)(ts_estree_1.AST_NODE_TYPES.TSFunctionType);
exports.isTSConstructorType = (0, helpers_1.isNodeOfType)(ts_estree_1.AST_NODE_TYPES.TSConstructorType);
exports.isClassOrTypeElement = (0, helpers_1.isNodeOfTypes)([
// ClassElement
ts_estree_1.AST_NODE_TYPES.PropertyDefinition,
ts_estree_1.AST_NODE_TYPES.FunctionExpression,
ts_estree_1.AST_NODE_TYPES.MethodDefinition,
ts_estree_1.AST_NODE_TYPES.TSAbstractPropertyDefinition,
ts_estree_1.AST_NODE_TYPES.TSAbstractMethodDefinition,
ts_estree_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
ts_estree_1.AST_NODE_TYPES.TSIndexSignature,
// TypeElement
ts_estree_1.AST_NODE_TYPES.TSCallSignatureDeclaration,
ts_estree_1.AST_NODE_TYPES.TSConstructSignatureDeclaration,
// AST_NODE_TYPES.TSIndexSignature,
ts_estree_1.AST_NODE_TYPES.TSMethodSignature,
ts_estree_1.AST_NODE_TYPES.TSPropertySignature,
]);
/**
* Checks if a node is a constructor method.
*/
exports.isConstructor = (0, helpers_1.isNodeOfTypeWithConditions)(ts_estree_1.AST_NODE_TYPES.MethodDefinition, { kind: 'constructor' });
/**
* Checks if a node is a setter method.
*/
function isSetter(node) {
return (!!node &&
(node.type === ts_estree_1.AST_NODE_TYPES.MethodDefinition ||
node.type === ts_estree_1.AST_NODE_TYPES.Property) &&
node.kind === 'set');
}
exports.isIdentifier = (0, helpers_1.isNodeOfType)(ts_estree_1.AST_NODE_TYPES.Identifier);
/**
* Checks if a node represents an `await …` expression.
*/
exports.isAwaitExpression = (0, helpers_1.isNodeOfType)(ts_estree_1.AST_NODE_TYPES.AwaitExpression);
/**
* Checks if a possible token is the `await` keyword.
*/
exports.isAwaitKeyword = (0, helpers_1.isTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Identifier, { value: 'await' });
/**
* Checks if a possible token is the `type` keyword.
*/
exports.isTypeKeyword = (0, helpers_1.isTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Identifier, { value: 'type' });
/**
* Checks if a possible token is the `import` keyword.
*/
exports.isImportKeyword = (0, helpers_1.isTokenOfTypeWithConditions)(ts_estree_1.AST_TOKEN_TYPES.Keyword, { value: 'import' });
exports.isLoop = (0, helpers_1.isNodeOfTypes)([
ts_estree_1.AST_NODE_TYPES.DoWhileStatement,
ts_estree_1.AST_NODE_TYPES.ForStatement,
ts_estree_1.AST_NODE_TYPES.ForInStatement,
ts_estree_1.AST_NODE_TYPES.ForOfStatement,
ts_estree_1.AST_NODE_TYPES.WhileStatement,
]);

View File

@@ -0,0 +1,116 @@
// @ts-check
/** @import { DevRuntime } from './runtime-extra-dev-common.js' */
/** @type {typeof DevRuntime} */
// @ts-expect-error -- there's no way to declare a variable by JSDoc
var BaseDevRuntime = DevRuntime;
class ModuleHotContext {
/**
* @type {{ deps: [string], fn: (moduleExports: Record<string, any>[]) => void }[]}
*/
acceptCallbacks = [];
/**
* @param {string} moduleId
* @param {InstanceType<BaseDevRuntime>} devRuntime
*/
constructor(moduleId, devRuntime) {
this.moduleId = moduleId;
this.devRuntime = devRuntime;
}
/**
* @overload
* @param {(mod: Record<string, any>) => void} cb
* @returns {void}
*/
/**
* @param {...any} args
* @returns {void}
*/
accept(...args) {
if (args.length === 1) {
const [cb] = /** @type {[(mod: Record<string, any>) => void]} */ (args);
const acceptingPath = this.moduleId;
this.acceptCallbacks.push({
deps: [acceptingPath],
fn: cb,
});
} else if (args.length === 0) {}
else {
throw new Error('Invalid arguments for `import.meta.hot.accept`');
}
}
invalidate() {
socket.send(JSON.stringify({
type: 'hmr:invalidate',
moduleId: this.moduleId,
}));
}
}
class DefaultDevRuntime extends BaseDevRuntime {
/**
* @type {Map<string, ModuleHotContext>}
*/
moduleHotContexts = new Map();
/**
* @override
* @param {string} moduleId
*/
createModuleHotContext(moduleId) {
const hotContext = new ModuleHotContext(moduleId, this);
this.moduleHotContexts.set(moduleId, hotContext);
return hotContext;
}
}
/** @param {string} url */
function loadScript(url) {
var script = document.createElement('script');
script.src = url;
script.type = 'module';
script.onerror = function() {
console.error('Failed to load script: ' + url);
};
document.body.appendChild(script);
}
console.debug('HMR runtime loaded', '$ADDR');
// Generate client ID immediately at runtime initialization
// This ensures the client ID is available before any lazy imports
const clientId = crypto.randomUUID();
const addr = new URL('ws://$ADDR');
addr.searchParams.set('clientId', clientId);
const socket = new WebSocket(addr);
(/** @type {any} */ (globalThis)).__rolldown_runtime__ ??=
new DefaultDevRuntime(clientId);
/** @param {MessageEvent} event */
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
console.debug('Received message:', data);
if (data.type === 'connected') {
// Server acknowledged the connection
console.debug('[hmr]: Connection established with server');
} else if (data.type === 'hmr:update') {
if (typeof process === 'object') {
import(data.path);
console.debug(`[hmr]: Importing HMR patch: ${data.path}`);
} else {
console.debug(`[hmr]: Loading HMR patch: ${data.path}`);
loadScript(data.url);
}
} else if (data.type === 'hmr:reload') {
console.log('[hmr]: Full reload required, reloading page');
if (typeof location !== 'undefined') {
location.reload();
} else {
console.log('[hmr]: location is undefined, cannot reload page');
}
}
};

View File

@@ -0,0 +1,4 @@
{
"main": "../../cjs/_iterable_to_array_limit.cjs",
"module": "../../esm/_iterable_to_array_limit.js"
}

View File

@@ -0,0 +1,31 @@
'use strict'
const { test } = require('node:test')
const getPropertyValue = require('./get-property-value')
test('getPropertyValue returns the value of the property', t => {
const result = getPropertyValue({
foo: 'bar'
}, 'foo')
t.assert.strictEqual(result, 'bar')
})
test('getPropertyValue returns the value of the nested property', t => {
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, 'extra.foo.value')
t.assert.strictEqual(result, 'bar')
})
test('getPropertyValue returns the value of the nested property using the array of nested property keys', t => {
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, ['extra', 'foo', 'value'])
t.assert.strictEqual(result, 'bar')
})
test('getPropertyValue returns undefined for non-existing properties', t => {
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, 'extra.foo.value-2')
t.assert.strictEqual(result, undefined)
})
test('getPropertyValue returns undefined for non-existing properties using the array of nested property keys', t => {
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, ['extra', 'foo', 'value-2'])
t.assert.strictEqual(result, undefined)
})