WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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("doesn’t 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": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
@@ -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))
|
||||
@@ -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')
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
```
|
||||
|
||||
[](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)
|
||||
@@ -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 _ };
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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());
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export { _ as default } from "../esm/_get.js";
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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"}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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"}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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"}
|
||||
@@ -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,
|
||||
]);
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_iterable_to_array_limit.cjs",
|
||||
"module": "../../esm/_iterable_to_array_limit.js"
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
Reference in New Issue
Block a user