From 8c7939fcd305eb1aee07e0f7debc593524c10e21 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 19 Sep 2022 11:10:02 -0700 Subject: [PATCH] feat: @W-11752332 add shared and shared-dom packages (#393) --- .eslintrc | 2 +- examples/package.json | 2 +- jest.config.js | 10 +- package.json | 2 + packages/near-membrane-base/package.json | 7 +- .../src/__tests__/connector.spec.ts | 2 +- .../src/__tests__/intrinsics.spec.ts | 2 +- .../src/__tests__/virtualenvironment.spec.ts | 2 +- packages/near-membrane-base/src/connector.ts | 3 +- .../near-membrane-base/src/environment.ts | 61 +- packages/near-membrane-base/src/index.ts | 1 - packages/near-membrane-base/src/intrinsics.ts | 10 +- packages/near-membrane-base/src/membrane.ts | 35 +- packages/near-membrane-base/src/types.ts | 31 +- packages/near-membrane-dom/package.json | 8 +- .../near-membrane-dom/src/browser-realm.ts | 63 +- packages/near-membrane-dom/src/index.ts | 1 - packages/near-membrane-dom/src/window.ts | 23 +- packages/near-membrane-node/.eslintrc.cjs | 2 +- packages/near-membrane-node/.rolluprc.cjs | 4 +- packages/near-membrane-node/package.json | 7 +- packages/near-membrane-node/src/index.ts | 1 - packages/near-membrane-node/src/node-realm.ts | 20 +- .../near-membrane-shared-dom/.eslintrc.cjs | 18 + .../near-membrane-shared-dom/.rolluprc.cjs | 5 + packages/near-membrane-shared-dom/LICENSE.txt | 21 + packages/near-membrane-shared-dom/README.md | 3 + .../near-membrane-shared-dom/package.json | 31 + .../near-membrane-shared-dom/src/Document.ts | 13 + .../near-membrane-shared-dom/src/Element.ts | 2 + .../src/HTMLElement.ts | 3 + .../src/HTMLIFrameElement.ts | 6 + packages/near-membrane-shared-dom/src/Node.ts | 7 + .../src/__tests__/Document.spec.js | 23 + .../src/__tests__/Element.spec.js | 10 + .../src/__tests__/HTMLElement.spec.js | 9 + .../src/__tests__/HTMLIFrameElement.spec.js | 9 + .../src/__tests__/Node.spec.js | 12 + .../near-membrane-shared-dom/src/index.ts | 6 + .../near-membrane-shared-dom/src/types.ts | 1 + .../near-membrane-shared-dom/tsconfig.json | 6 + .../tsconfig.types.json | 10 + packages/near-membrane-shared/.eslintrc.cjs | 18 + packages/near-membrane-shared/.rolluprc.cjs | 5 + packages/near-membrane-shared/LICENSE.txt | 21 + packages/near-membrane-shared/README.md | 3 + packages/near-membrane-shared/package.json | 28 + .../src/Array.ts} | 53 +- packages/near-membrane-shared/src/Error.ts | 2 + packages/near-membrane-shared/src/Function.ts | 3 + packages/near-membrane-shared/src/Object.ts | 37 ++ packages/near-membrane-shared/src/Reflect.ts | 7 + packages/near-membrane-shared/src/Symbol.ts | 5 + packages/near-membrane-shared/src/WeakMap.ts | 25 + .../src/__tests__/Array.spec.js | 96 +++ .../src/__tests__/Error.spec.js | 10 + .../src/__tests__/Function.spec.js | 11 + .../src/__tests__/Object.spec.js | 60 ++ .../src/__tests__/Reflect.spec.js | 25 + .../src/__tests__/Symbol.spec.js | 13 + .../src/__tests__/WeakMap.spec.js | 30 + packages/near-membrane-shared/src/index.ts | 8 + packages/near-membrane-shared/src/types.ts | 15 + packages/near-membrane-shared/tsconfig.json | 6 + .../near-membrane-shared/tsconfig.types.json | 10 + scripts/locker-trash.mjs | 70 +++ scripts/package.json | 5 +- scripts/rollup/configs/base.cjs | 15 +- test/membrane/arrays.spec.js | 35 ++ test/membrane/errors.spec.js | 585 ++++++++++++++++++ test/membrane/object-graph.spec.js | 67 ++ yarn.lock | 295 ++++++++- 72 files changed, 1856 insertions(+), 201 deletions(-) create mode 100644 packages/near-membrane-shared-dom/.eslintrc.cjs create mode 100644 packages/near-membrane-shared-dom/.rolluprc.cjs create mode 100644 packages/near-membrane-shared-dom/LICENSE.txt create mode 100644 packages/near-membrane-shared-dom/README.md create mode 100644 packages/near-membrane-shared-dom/package.json create mode 100644 packages/near-membrane-shared-dom/src/Document.ts create mode 100644 packages/near-membrane-shared-dom/src/Element.ts create mode 100644 packages/near-membrane-shared-dom/src/HTMLElement.ts create mode 100644 packages/near-membrane-shared-dom/src/HTMLIFrameElement.ts create mode 100644 packages/near-membrane-shared-dom/src/Node.ts create mode 100644 packages/near-membrane-shared-dom/src/__tests__/Document.spec.js create mode 100644 packages/near-membrane-shared-dom/src/__tests__/Element.spec.js create mode 100644 packages/near-membrane-shared-dom/src/__tests__/HTMLElement.spec.js create mode 100644 packages/near-membrane-shared-dom/src/__tests__/HTMLIFrameElement.spec.js create mode 100644 packages/near-membrane-shared-dom/src/__tests__/Node.spec.js create mode 100644 packages/near-membrane-shared-dom/src/index.ts create mode 100644 packages/near-membrane-shared-dom/src/types.ts create mode 100644 packages/near-membrane-shared-dom/tsconfig.json create mode 100644 packages/near-membrane-shared-dom/tsconfig.types.json create mode 100644 packages/near-membrane-shared/.eslintrc.cjs create mode 100644 packages/near-membrane-shared/.rolluprc.cjs create mode 100644 packages/near-membrane-shared/LICENSE.txt create mode 100644 packages/near-membrane-shared/README.md create mode 100644 packages/near-membrane-shared/package.json rename packages/{near-membrane-base/src/utils.ts => near-membrane-shared/src/Array.ts} (68%) create mode 100644 packages/near-membrane-shared/src/Error.ts create mode 100644 packages/near-membrane-shared/src/Function.ts create mode 100644 packages/near-membrane-shared/src/Object.ts create mode 100644 packages/near-membrane-shared/src/Reflect.ts create mode 100644 packages/near-membrane-shared/src/Symbol.ts create mode 100644 packages/near-membrane-shared/src/WeakMap.ts create mode 100644 packages/near-membrane-shared/src/__tests__/Array.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/Error.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/Function.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/Object.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/Reflect.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/Symbol.spec.js create mode 100644 packages/near-membrane-shared/src/__tests__/WeakMap.spec.js create mode 100644 packages/near-membrane-shared/src/index.ts create mode 100644 packages/near-membrane-shared/src/types.ts create mode 100644 packages/near-membrane-shared/tsconfig.json create mode 100644 packages/near-membrane-shared/tsconfig.types.json create mode 100755 scripts/locker-trash.mjs create mode 100644 test/membrane/arrays.spec.js create mode 100644 test/membrane/errors.spec.js create mode 100644 test/membrane/object-graph.spec.js diff --git a/.eslintrc b/.eslintrc index db01f21b..bb270798 100644 --- a/.eslintrc +++ b/.eslintrc @@ -24,7 +24,7 @@ ], "rules": { "prettier/prettier": "error", - // Overriden + // Overridden "no-eval": "off", "camelcase": ["error", { "properties": "never", "allow": [ "W[0-9]+_"] }], "import/extensions": "off", diff --git a/examples/package.json b/examples/package.json index 586ed6ba..5b0f814b 100644 --- a/examples/package.json +++ b/examples/package.json @@ -3,7 +3,7 @@ "version": "0.11.4", "private": true, "scripts": { - "clean": "rimraf */bundle.js", + "clean": "locker-trash */bundle.js", "build": "rollup --config .rolluprc.cjs" }, "dependencies": { diff --git a/jest.config.js b/jest.config.js index 25b3323a..1882a6c9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,10 +5,14 @@ module.exports = { coverageDirectory: 'jest-coverage/json/', coverageReporters: ['json'], moduleNameMapper: { - '^@locker/near-membrane-base$': '/packages/near-membrane-base/src', - '^@locker/near-membrane-node$': '/packages/near-membrane-node/src', + '^@locker/(near-membrane-\\w+)$': '/packages/$1/src', }, - roots: ['/packages/near-membrane-base', '/packages/near-membrane-node'], + roots: [ + '/packages/near-membrane-base', + '/packages/near-membrane-node', + '/packages/near-membrane-shared', + '/packages/near-membrane-shared-dom', + ], testEnvironment: 'jsdom', testEnvironmentOptions: { url: 'http://localhost/', diff --git a/package.json b/package.json index aebca69a..03f66ec5 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "karma-safari-launcher": "1.0.0", "lerna": "5.5.0", "lint-staged": "13.0.3", + "meow": "10.1.3", "merge-options": "3.0.4", "nyc": "15.1.0", "prettier": "2.7.1", @@ -87,6 +88,7 @@ "rimraf": "3.0.2", "rollup": "2.79.0", "rollup-plugin-istanbul": "3.0.0", + "trash": "7.2.0", "tslib": "2.4.0", "typescript": "4.8.2" }, diff --git a/packages/near-membrane-base/package.json b/packages/near-membrane-base/package.json index 8796ea44..5c9d5fdd 100644 --- a/packages/near-membrane-base/package.json +++ b/packages/near-membrane-base/package.json @@ -8,13 +8,13 @@ }, "license": "MIT", "author": "Caridy Patiño ", - "description": "JavaScript Near Membrane Library to create a sandboxed environment", + "description": "Base membrane library to create sandboxed environments", "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, "typings": "types/index.d.ts", "scripts": { - "clean": "rimraf dist types", + "clean": "locker-trash dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", "build:dev": "cross-env NODE_ENV=development yarn build" }, @@ -24,5 +24,8 @@ ], "publishConfig": { "access": "public" + }, + "dependencies": { + "@locker/near-membrane-shared": "0.11.4" } } diff --git a/packages/near-membrane-base/src/__tests__/connector.spec.ts b/packages/near-membrane-base/src/__tests__/connector.spec.ts index bb5dff9b..caeb41ca 100644 --- a/packages/near-membrane-base/src/__tests__/connector.spec.ts +++ b/packages/near-membrane-base/src/__tests__/connector.spec.ts @@ -1,4 +1,4 @@ -import { createBlueConnector, createRedConnector } from '../index'; +import { createBlueConnector, createRedConnector } from '../../dist/index'; describe('createBlueConnector()', () => { it('throws when globalObject is not provided', () => { diff --git a/packages/near-membrane-base/src/__tests__/intrinsics.spec.ts b/packages/near-membrane-base/src/__tests__/intrinsics.spec.ts index 099974fe..349fe5b8 100644 --- a/packages/near-membrane-base/src/__tests__/intrinsics.spec.ts +++ b/packages/near-membrane-base/src/__tests__/intrinsics.spec.ts @@ -5,7 +5,7 @@ import { getFilteredGlobalOwnKeys, linkIntrinsics, VirtualEnvironment, -} from '../index'; +} from '../../dist/index'; const ESGlobalKeys = [ // *** 19.1 Value Properties of the Global Object diff --git a/packages/near-membrane-base/src/__tests__/virtualenvironment.spec.ts b/packages/near-membrane-base/src/__tests__/virtualenvironment.spec.ts index 377948d8..b8642b84 100644 --- a/packages/near-membrane-base/src/__tests__/virtualenvironment.spec.ts +++ b/packages/near-membrane-base/src/__tests__/virtualenvironment.spec.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { createBlueConnector, createRedConnector, VirtualEnvironment } from '../index'; +import { createBlueConnector, createRedConnector, VirtualEnvironment } from '../../dist/index'; const { toString: ObjectProtoToString } = Object.prototype; diff --git a/packages/near-membrane-base/src/connector.ts b/packages/near-membrane-base/src/connector.ts index fde908fc..9ed9a265 100644 --- a/packages/near-membrane-base/src/connector.ts +++ b/packages/near-membrane-base/src/connector.ts @@ -1,8 +1,7 @@ +import { TypeErrorCtor } from '@locker/near-membrane-shared'; import { createMembraneMarshall } from './membrane'; import type { Connector } from './types'; -const TypeErrorCtor = TypeError; - const createMembraneMarshallSourceInStrictMode = ` 'use strict'; (${createMembraneMarshall})`; diff --git a/packages/near-membrane-base/src/environment.ts b/packages/near-membrane-base/src/environment.ts index 16e8febd..4fb533a7 100644 --- a/packages/near-membrane-base/src/environment.ts +++ b/packages/near-membrane-base/src/environment.ts @@ -1,3 +1,13 @@ +import { + ArrayCtor, + ArrayProtoPush, + ErrorCtor, + noop, + ObjectAssign, + ReflectApply, + ReflectOwnKeys, +} from '@locker/near-membrane-shared'; +import type { ProxyTarget } from '@locker/near-membrane-shared/types'; import type { CallableDefineProperties, CallableEvaluate, @@ -9,20 +19,12 @@ import type { GetTransferableValue, HooksCallback, Pointer, - ProxyTarget, - PropertyKeys, VirtualEnvironmentOptions, } from './types'; const LOCKER_NEAR_MEMBRANE_UNDEFINED_VALUE_SYMBOL = Symbol.for( '@@lockerNearMembraneUndefinedValue' ); -const ArrayCtor = Array; -const ErrorCtor = Error; -const ObjectCtor = Object; -const { push: ArrayProtoPush } = ArrayCtor.prototype; -const { assign: ObjectAssign } = ObjectCtor; -const { apply: ReflectApply, ownKeys: ReflectOwnKeys } = Reflect; export class VirtualEnvironment { private readonly blueCallableGetPropertyValuePointer: CallableGetPropertyValuePointer; @@ -155,12 +157,12 @@ export class VirtualEnvironment { 35: redCallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor, } = redHooks!; blueConnect( - undefined, // redGlobalThisPointer, - undefined, // redGetSelectedTarget, - undefined, // redGetTransferableValue, - undefined, // redCallableGetPropertyValuePointer, - undefined, // redCallableEvaluate, - undefined, // redCallableLinkPointers, + noop, // redGlobalThisPointer, + noop, // redGetSelectedTarget, + noop as GetTransferableValue, // redGetTransferableValue, + noop as unknown as CallableGetPropertyValuePointer, // redCallableGetPropertyValuePointer, + noop as CallableEvaluate, // redCallableEvaluate, + noop, // redCallableLinkPointers, redCallablePushErrorTarget, redCallablePushTarget, redCallableApply, @@ -177,13 +179,13 @@ export class VirtualEnvironment { redCallableSet, redCallableSetPrototypeOf, redCallableDebugInfo, - undefined, // redCallableDefineProperties, + noop, // redCallableDefineProperties, redCallableGetLazyPropertyDescriptorStateByTarget, redCallableGetTargetIntegrityTraits, redCallableGetToStringTagOfTarget, redCallableGetTypedArrayIndexedValue, redCallableInstallErrorPrepareStackTrace, - undefined, // redCallableInstallLazyPropertyDescriptors, + noop, // redCallableInstallLazyPropertyDescriptors, redCallableIsTargetLive, redCallableIsTargetRevoked, redCallableSerializeTarget, @@ -193,12 +195,12 @@ export class VirtualEnvironment { redCallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor ); redConnect( - undefined, // blueGlobalThisPointer, - undefined, // blueGetSelectedTarget, - undefined, // blueGetTransferableValue, - undefined, // blueCallableGetPropertyValuePointer, - undefined, // blueCallableEvaluate, - undefined, // blueCallableLinkPointers, + noop, // blueGlobalThisPointer, + noop, // blueGetSelectedTarget, + noop as GetTransferableValue, // blueGetTransferableValue, + noop as unknown as CallableGetPropertyValuePointer, // blueCallableGetPropertyValuePointer, + noop as CallableEvaluate, // blueCallableEvaluate, + noop, // blueCallableLinkPointers, blueCallablePushErrorTarget, blueCallablePushTarget, blueCallableApply, @@ -215,13 +217,13 @@ export class VirtualEnvironment { blueCallableSet, blueCallableSetPrototypeOf, blueCallableDebugInfo, - undefined, // blueCallableDefineProperties, + noop, // blueCallableDefineProperties, blueCallableGetLazyPropertyDescriptorStateByTarget, blueCallableGetTargetIntegrityTraits, blueCallableGetToStringTagOfTarget, blueCallableGetTypedArrayIndexedValue, blueCallableInstallErrorPrepareStackTrace, - undefined, // blueCallableInstallLazyPropertyDescriptors, + noop, // blueCallableInstallLazyPropertyDescriptors, blueCallableIsTargetLive, blueCallableIsTargetRevoked, blueCallableSerializeTarget, @@ -260,12 +262,13 @@ export class VirtualEnvironment { lazyRemapProperties( target: ProxyTarget, - ownKeys: PropertyKeys, - unforgeableGlobalThisKeys?: PropertyKeys + ownKeys: PropertyKey[], + unforgeableGlobalThisKeys?: PropertyKey[] ) { if ((typeof target === 'object' && target !== null) || typeof target === 'function') { - const targetPointer = this.blueGetTransferableValue(target) as Pointer; - const args: Parameters = [targetPointer]; + const args: Parameters = [ + this.blueGetTransferableValue(target) as Pointer, + ]; ReflectApply(ArrayProtoPush, args, ownKeys); if (unforgeableGlobalThisKeys?.length) { // Use `LOCKER_NEAR_MEMBRANE_UNDEFINED_VALUE_SYMBOL` to delimit @@ -277,7 +280,7 @@ export class VirtualEnvironment { } } - link(...keys: PropertyKeys) { + link(...keys: PropertyKey[]) { let bluePointer = this.blueGlobalThisPointer; let redPointer = this.redGlobalThisPointer; for (let i = 0, { length } = keys; i < length; i += 1) { diff --git a/packages/near-membrane-base/src/index.ts b/packages/near-membrane-base/src/index.ts index 0d494542..8c09a2a5 100644 --- a/packages/near-membrane-base/src/index.ts +++ b/packages/near-membrane-base/src/index.ts @@ -3,4 +3,3 @@ export * from './environment'; export * from './intrinsics'; export * from './membrane'; export * from './types'; -export * from './utils'; diff --git a/packages/near-membrane-base/src/intrinsics.ts b/packages/near-membrane-base/src/intrinsics.ts index 5cb4c99a..b0af002e 100644 --- a/packages/near-membrane-base/src/intrinsics.ts +++ b/packages/near-membrane-base/src/intrinsics.ts @@ -1,9 +1,5 @@ -import { toSafeArray } from './utils'; +import { ObjectAssign, ReflectOwnKeys, toSafeArray } from '@locker/near-membrane-shared'; import { VirtualEnvironment } from './environment'; -import type { PropertyKeys } from './types'; - -const { assign: ObjectAssign } = Object; -const { ownKeys: ReflectOwnKeys } = Reflect; /** * This list must be in sync with ecma-262, anything new added to the global object @@ -147,8 +143,8 @@ export function assignFilteredGlobalDescriptorsFromPropertyDescriptorMap< return descMap; } -export function getFilteredGlobalOwnKeys(source: object): PropertyKeys { - const result: PropertyKeys = []; +export function getFilteredGlobalOwnKeys(source: object): PropertyKey[] { + const result: PropertyKey[] = []; let resultOffset = 0; const ownKeys = ReflectOwnKeys(source); for (let i = 0, { length } = ownKeys; i < length; i += 1) { diff --git a/packages/near-membrane-base/src/membrane.ts b/packages/near-membrane-base/src/membrane.ts index f21e9eea..764cab25 100644 --- a/packages/near-membrane-base/src/membrane.ts +++ b/packages/near-membrane-base/src/membrane.ts @@ -22,7 +22,8 @@ * argument of the foreign callable for proxies, and the other side can use * it via `selectedTarget!`. */ -import { toSafeWeakMap } from './utils'; +import { toSafeWeakMap, WeakMapCtor } from '@locker/near-membrane-shared'; +import type { Getter, ProxyTarget, Setter } from '@locker/near-membrane-shared/types'; import type { Activity, CallableApply, @@ -61,22 +62,17 @@ import type { CallableSetPrototypeOf, ForeignPropertyDescriptor, GetSelectedTarget, - Getter, GlobalThisGetter, HooksCallback, HooksOptions, Pointer, PointerOrPrimitive, - PropertyKey, - PropertyKeys, - ProxyTarget, SerializedValue, - Setter, ShadowTarget, } from './types'; const proxyTargetToLazyPropertyDescriptorStateMap: WeakMap = toSafeWeakMap( - new WeakMap() + new WeakMapCtor() ); // istanbul ignore next @@ -95,6 +91,7 @@ export function createMembraneMarshall( const StringCtor = String; const SymbolCtor = Symbol; const TypeErrorCtor = TypeError; + // eslint-disable-next-line @typescript-eslint/no-shadow, no-shadow const WeakMapCtor = WeakMap; const { for: SymbolFor, toStringTag: SymbolToStringTag } = SymbolCtor; const { @@ -180,7 +177,7 @@ export function createMembraneMarshall( let MINIFICATION_SAFE_SERIALIZED_VALUE_PROPERTY_NAME: PropertyKey | undefined; // Minification safe references to the private `BoundaryProxyHandler` // 'apply' and 'construct' trap variant's property names. - let MINIFICATION_SAFE_TRAP_PROPERTY_NAMES: PropertyKeys | undefined; + let MINIFICATION_SAFE_TRAP_PROPERTY_NAMES: PropertyKey[] | undefined; const SUPPORTS_BIG_INT = typeof BigInt === 'function'; const { isArray: isArrayOrThrowForRevoked } = ArrayCtor; const { @@ -1650,7 +1647,7 @@ export function createMembraneMarshall( } const installPropertyDescriptorMethodWrappers = IS_IN_SHADOW_REALM - ? (unforgeableGlobalThisKeys?: PropertyKeys) => { + ? (unforgeableGlobalThisKeys?: PropertyKey[]) => { if (installedPropertyDescriptorMethodWrappersFlag) { return; } @@ -3354,7 +3351,11 @@ export function createMembraneMarshall( } else { this.makeProxyStatic(); } - return this.defineProperty!(shadowTarget, key, unsafePartialDesc); + return this.defineProperty!( + shadowTarget, + key as string | symbol, + unsafePartialDesc + ); } : (alwaysFalse as typeof Reflect.defineProperty); @@ -3376,7 +3377,7 @@ export function createMembraneMarshall( } else { this.makeProxyStatic(); } - return this.deleteProperty!(shadowTarget, key); + return this.deleteProperty!(shadowTarget, key as string | symbol); } : (alwaysFalse as typeof Reflect.deleteProperty); @@ -3443,7 +3444,7 @@ export function createMembraneMarshall( } else { this.makeProxyStatic(); } - return this.set!(shadowTarget, key, value, receiver); + return this.set!(shadowTarget, key as string | symbol, value, receiver); } : (alwaysFalse as typeof Reflect.set); @@ -4199,15 +4200,15 @@ export function createMembraneMarshall( IS_IN_SHADOW_REALM ? ( targetPointer: Pointer, - ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKeys + ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKey[] ) => { const sliceIndex: number = ReflectApply( ArrayProtoIndexOf, ownKeysAndUnforgeableGlobalThisKeys, [LOCKER_NEAR_MEMBRANE_UNDEFINED_VALUE_SYMBOL] ); - let ownKeys: PropertyKeys; - let unforgeableGlobalThisKeys: PropertyKeys | undefined; + let ownKeys: PropertyKey[]; + let unforgeableGlobalThisKeys: PropertyKey[] | undefined; if (sliceIndex === -1) { ownKeys = ownKeysAndUnforgeableGlobalThisKeys; } else { @@ -4215,12 +4216,12 @@ export function createMembraneMarshall( ArrayProtoSlice, ownKeysAndUnforgeableGlobalThisKeys, [0, sliceIndex] - ) as PropertyKeys; + ) as PropertyKey[]; unforgeableGlobalThisKeys = ReflectApply( ArrayProtoSlice, ownKeysAndUnforgeableGlobalThisKeys, [sliceIndex + 1] - ) as PropertyKeys; + ) as PropertyKey[]; } targetPointer(); const target = selectedTarget!; diff --git a/packages/near-membrane-base/src/types.ts b/packages/near-membrane-base/src/types.ts index 95f2c380..afc64e60 100644 --- a/packages/near-membrane-base/src/types.ts +++ b/packages/near-membrane-base/src/types.ts @@ -1,3 +1,9 @@ +import type { + Getter, + NearMembraneSerializedValue as SerializedValue, + ProxyTarget, +} from '@locker/near-membrane-shared/types'; + export interface Activity { stop(data?: DataType): void; error(data?: DataType): void; @@ -81,7 +87,7 @@ export type CallableHas = (targetPointer: Pointer, key: PropertyKey) => boolean; export type CallableInstallErrorPrepareStackTrace = () => void; export type CallableInstallLazyPropertyDescriptors = ( targetPointer: Pointer, - ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKeys + ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKey[] ) => void; export type CallableIsExtensible = (targetPointer: Pointer) => boolean; export type CallableIsTargetLive = (targetPointer: Pointer, targetTraits: number) => boolean; @@ -127,16 +133,15 @@ export interface ForeignPropertyDescriptor extends PropertyDescriptor { foreign?: boolean; } export type GetSelectedTarget = Getter; -export type Getter = () => any; export type GetTransferableValue = (value: any) => PointerOrPrimitive; export type GlobalThisGetter = () => typeof globalThis; export type HooksCallback = ( - globalThisPointer: Pointer | undefined, - getSelectedTarget: GetSelectedTarget | undefined, - getTransferableValue: GetTransferableValue | undefined, - callableGetPropertyValuePointer: CallableGetPropertyValuePointer | undefined, - callableEvaluate: CallableEvaluate | undefined, - callableLinkPointers: CallableLinkPointers | undefined, + globalThisPointer: Pointer, + getSelectedTarget: GetSelectedTarget, + getTransferableValue: GetTransferableValue, + callableGetPropertyValuePointer: CallableGetPropertyValuePointer, + callableEvaluate: CallableEvaluate, + callableLinkPointers: CallableLinkPointers, callablePushErrorTarget: CallablePushErrorTarget, callablePushTarget: CallablePushTarget, callableApply: CallableApply, @@ -153,13 +158,13 @@ export type HooksCallback = ( callableSet: CallableSet, callableSetPrototypeOf: CallableSetPrototypeOf, callableDebugInfo: CallableDebugInfo, - callableDefineProperties: CallableDefineProperties | undefined, + callableDefineProperties: CallableDefineProperties, callableGetLazyPropertyDescriptorStateByTarget: CallableGetLazyPropertyDescriptorStateByTarget, callableGetTargetIntegrityTraits: CallableGetTargetIntegrityTraits, callableGetToStringTagOfTarget: CallableGetToStringTagOfTarget, callableGetTypedArrayIndexedValue: CallableGetTypedArrayIndexedValue, callableInstallErrorPrepareStackTrace: CallableInstallErrorPrepareStackTrace, - callableInstallLazyPropertyDescriptors: CallableInstallLazyPropertyDescriptors | undefined, + callableInstallLazyPropertyDescriptors: CallableInstallLazyPropertyDescriptors, callableIsTargetLive: CallableIsTargetLive, callableIsTargetRevoked: CallableIsTargetRevoked, callableSerializeTarget: CallableSerializeTarget, @@ -182,11 +187,7 @@ export type LiveTargetCallback = (target: ProxyTarget, targetTraits: number) => export type Pointer = CallableFunction; export type PointerOrPrimitive = Pointer | Primitive; export type Primitive = bigint | boolean | null | number | string | symbol | undefined; -export type PropertyKey = string | symbol; -export type PropertyKeys = PropertyKey[]; -export type ProxyTarget = CallableFunction | any[] | object; -export type SerializedValue = bigint | boolean | number | string | symbol; -export type Setter = (value: any) => void; +export type { SerializedValue }; export type ShadowTarget = ProxyTarget; export interface VirtualEnvironmentOptions { blueConnector: Connector; diff --git a/packages/near-membrane-dom/package.json b/packages/near-membrane-dom/package.json index 54527e6c..4eaaded3 100644 --- a/packages/near-membrane-dom/package.json +++ b/packages/near-membrane-dom/package.json @@ -8,13 +8,13 @@ }, "license": "MIT", "author": "Caridy Patiño ", - "description": "JavaScript DOM Membrane Library to create a sandboxed environment in the browser", + "description": "DOM membrane library to create sandboxed environments in the browser", "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, "typings": "types/index.d.ts", "scripts": { - "clean": "rimraf dist types", + "clean": "locker-trash dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", "build:dev": "cross-env NODE_ENV=development yarn build" }, @@ -26,6 +26,8 @@ "access": "public" }, "dependencies": { - "@locker/near-membrane-base": "0.11.4" + "@locker/near-membrane-base": "0.11.4", + "@locker/near-membrane-shared": "0.11.4", + "@locker/near-membrane-shared-dom": "0.11.4" } } diff --git a/packages/near-membrane-dom/src/browser-realm.ts b/packages/near-membrane-dom/src/browser-realm.ts index 9eba2aab..e62f52d0 100644 --- a/packages/near-membrane-dom/src/browser-realm.ts +++ b/packages/near-membrane-dom/src/browser-realm.ts @@ -4,11 +4,29 @@ import { createRedConnector, getFilteredGlobalOwnKeys, linkIntrinsics, - toSafeWeakMap, VirtualEnvironment, } from '@locker/near-membrane-base'; -import type { Connector, Getter, PropertyKeys } from '@locker/near-membrane-base/types'; - +import { + ObjectAssign, + ReflectApply, + toSafeWeakMap, + TypeErrorCtor, + WeakMapCtor, +} from '@locker/near-membrane-shared'; +import { + DocumentProtoBodyGetter, + DocumentProtoClose, + DocumentProtoCreateElement, + DocumentProtoOpen, + ElementProtoRemove, + ElementProtoSetAttribute, + HTMLElementProtoStyleGetter, + HTMLIFrameElementProtoContentWindowGetter, + NodeProtoAppendChild, + NodeProtoLastChildGetter, +} from '@locker/near-membrane-shared-dom'; +import type { GlobalObject } from '@locker/near-membrane-shared-dom/types'; +import type { Connector } from '@locker/near-membrane-base/types'; import type { BrowserEnvironmentOptions } from './types'; import { getCachedGlobalObjectReferences, @@ -19,44 +37,11 @@ import { const IFRAME_SANDBOX_ATTRIBUTE_VALUE = 'allow-same-origin allow-scripts'; -const ObjectCtor = Object; -const TypeErrorCtor = TypeError; -const WeakMapCtor = WeakMap; -const { prototype: DocumentProto } = Document; -const { prototype: NodeProto } = Node; -const { remove: ElementProtoRemove, setAttribute: ElementProtoSetAttribute } = Element.prototype; -const { appendChild: NodeProtoAppendChild } = NodeProto; -const { assign: ObjectAssign } = ObjectCtor; -// eslint-disable-next-line @typescript-eslint/naming-convention -const { __lookupGetter__: ObjectProtoLookupGetter } = ObjectCtor.prototype as any; -const { apply: ReflectApply } = Reflect; -const { - close: DocumentProtoClose, - createElement: DocumentProtoCreateElement, - open: DocumentProtoOpen, -} = DocumentProto; -const DocumentProtoBodyGetter: Getter = ReflectApply(ObjectProtoLookupGetter, DocumentProto, [ - 'body', -])!; -const HTMLElementProtoStyleGetter: Getter = ReflectApply( - ObjectProtoLookupGetter, - HTMLElement.prototype, - ['style'] -)!; -const HTMLIFrameElementProtoContentWindowGetter: Getter = ReflectApply( - ObjectProtoLookupGetter, - HTMLIFrameElement.prototype, - ['contentWindow'] -)!; -const NodeProtoLastChildGetter: Getter = ReflectApply(ObjectProtoLookupGetter, NodeProto, [ - 'lastChild', -])!; - const blueDocumentToBlueCreateHooksCallbackMap = toSafeWeakMap( new WeakMapCtor() ); -let defaultGlobalOwnKeys: PropertyKeys | null = null; +let defaultGlobalOwnKeys: PropertyKey[] | null = null; function createDetachableIframe(doc: Document): HTMLIFrameElement { const iframe: HTMLIFrameElement = ReflectApply(DocumentProtoCreateElement, doc, ['iframe']); @@ -93,7 +78,7 @@ function createIframeVirtualEnvironment( // eslint-disable-next-line prefer-object-spread } = ObjectAssign({ __proto__: null }, options); const iframe = createDetachableIframe(blueRefs.document); - const redWindow: Window & typeof globalThis = ReflectApply( + const redWindow: GlobalObject = ReflectApply( HTMLIFrameElementProtoContentWindowGetter, iframe, [] @@ -137,7 +122,7 @@ function createIframeVirtualEnvironment( env.lazyRemapProperties( blueRefs.window, shouldUseDefaultGlobalOwnKeys - ? (defaultGlobalOwnKeys as PropertyKeys) + ? (defaultGlobalOwnKeys as PropertyKey[]) : filterWindowKeys(getFilteredGlobalOwnKeys(globalObjectShape)), // Chromium based browsers have a bug that nulls the result of `window` // getters in detached iframes when the property descriptor of `window.window` diff --git a/packages/near-membrane-dom/src/index.ts b/packages/near-membrane-dom/src/index.ts index 68383c4a..fd3ad12e 100644 --- a/packages/near-membrane-dom/src/index.ts +++ b/packages/near-membrane-dom/src/index.ts @@ -6,5 +6,4 @@ export type { DistortionCallback, Instrumentation, LiveTargetCallback, - ProxyTarget, } from '@locker/near-membrane-base/types'; diff --git a/packages/near-membrane-dom/src/window.ts b/packages/near-membrane-dom/src/window.ts index 95d68fd9..4610fe56 100644 --- a/packages/near-membrane-dom/src/window.ts +++ b/packages/near-membrane-dom/src/window.ts @@ -1,11 +1,10 @@ -import { toSafeWeakMap } from '@locker/near-membrane-base'; -import { PropertyKeys } from '@locker/near-membrane-base/types'; - -const { - deleteProperty: ReflectDeleteProperty, - getPrototypeOf: ReflectGetPrototypeOf, - ownKeys: ReflectOwnKeys, -} = Reflect; +import { + ArrayIsArray, + ReflectDeleteProperty, + ReflectGetPrototypeOf, + ReflectOwnKeys, + toSafeWeakMap, +} from '@locker/near-membrane-shared'; interface CachedBlueReferencesRecord extends Object { document: Document; @@ -14,7 +13,7 @@ interface CachedBlueReferencesRecord extends Object { WindowProto: object; WindowPropertiesProto: object; EventTargetProto: object; - EventTargetProtoOwnKeys: PropertyKeys; + EventTargetProtoOwnKeys: PropertyKey[]; } const blueDocumentToRecordMap: WeakMap = toSafeWeakMap( @@ -38,7 +37,7 @@ export const unforgeablePoisonedWindowKeys = (() => { if ( // While experimental, `navigator.userAgentData.brands` may be defined // as an empty array in headless Chromium based browsers. - Array.isArray(brands) && brands.length + ArrayIsArray(brands) && brands.length ? // Use user-agent client hints API if available to avoid // deprecation warnings. // https://developer.mozilla.org/en-US/docs/Web/API/User-Agent_Client_Hints_API @@ -88,8 +87,8 @@ export function getCachedGlobalObjectReferences( return record; } -export function filterWindowKeys(keys: PropertyKeys): PropertyKeys { - const result: PropertyKeys = []; +export function filterWindowKeys(keys: PropertyKey[]): PropertyKey[] { + const result: PropertyKey[] = []; let resultOffset = 0; for (let i = 0, { length } = keys; i < length; i += 1) { const key = keys[i]; diff --git a/packages/near-membrane-node/.eslintrc.cjs b/packages/near-membrane-node/.eslintrc.cjs index 53bcd256..1be09955 100644 --- a/packages/near-membrane-node/.eslintrc.cjs +++ b/packages/near-membrane-node/.eslintrc.cjs @@ -5,7 +5,7 @@ const path = require('node:path'); module.exports = { overrides: [ { - files: ['**/*.{js,ts}'], + files: ['**/*.{ts}'], rules: { 'import/no-extraneous-dependencies': [ 'error', diff --git a/packages/near-membrane-node/.rolluprc.cjs b/packages/near-membrane-node/.rolluprc.cjs index b82d557b..974817c8 100644 --- a/packages/near-membrane-node/.rolluprc.cjs +++ b/packages/near-membrane-node/.rolluprc.cjs @@ -2,6 +2,4 @@ const { rollupConfig } = require('@locker/scripts/rollup/configs/base.cjs'); -module.exports = rollupConfig({ - external: ['@locker/near-membrane-base', 'vm'], -}); +module.exports = rollupConfig(); diff --git a/packages/near-membrane-node/package.json b/packages/near-membrane-node/package.json index 75845c86..0b51eb9a 100644 --- a/packages/near-membrane-node/package.json +++ b/packages/near-membrane-node/package.json @@ -8,13 +8,13 @@ }, "license": "MIT", "author": "Caridy Patiño ", - "description": "JavaScript Node Membrane Library to create a sandboxed environment in Node", + "description": "Node membrane library to create sandboxed environments in Node", "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, "typings": "types/index.d.ts", "scripts": { - "clean": "rimraf dist types", + "clean": "locker-trash dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", "build:dev": "cross-env NODE_ENV=development yarn build" }, @@ -26,6 +26,7 @@ "access": "public" }, "dependencies": { - "@locker/near-membrane-base": "0.11.4" + "@locker/near-membrane-base": "0.11.4", + "@locker/near-membrane-shared": "0.11.4" } } diff --git a/packages/near-membrane-node/src/index.ts b/packages/near-membrane-node/src/index.ts index bf1b6401..43033898 100644 --- a/packages/near-membrane-node/src/index.ts +++ b/packages/near-membrane-node/src/index.ts @@ -6,5 +6,4 @@ export type { DistortionCallback, Instrumentation, LiveTargetCallback, - ProxyTarget, } from '@locker/near-membrane-base/types'; diff --git a/packages/near-membrane-node/src/node-realm.ts b/packages/near-membrane-node/src/node-realm.ts index 76598d1e..fce2006e 100644 --- a/packages/near-membrane-node/src/node-realm.ts +++ b/packages/near-membrane-node/src/node-realm.ts @@ -4,23 +4,23 @@ import { createRedConnector, getFilteredGlobalOwnKeys, linkIntrinsics, - toSafeWeakMap, VirtualEnvironment, } from '@locker/near-membrane-base'; -import type { Connector, PropertyKeys } from '@locker/near-membrane-base/types'; -import { runInNewContext } from 'vm'; +import { + ObjectAssign, + toSafeWeakMap, + TypeErrorCtor, + WeakMapCtor, +} from '@locker/near-membrane-shared'; +import type { Connector } from '@locker/near-membrane-base/types'; +import { runInNewContext } from 'node:vm'; import type { NodeEnvironmentOptions } from './types'; -const ObjectCtor = Object; -const { assign: ObjectAssign } = ObjectCtor; -const TypeErrorCtor = TypeError; -const WeakMapCtor = WeakMap; - const globalObjectToBlueCreateHooksCallbackMap = toSafeWeakMap( new WeakMapCtor() ); -let defaultGlobalOwnKeys: PropertyKeys | null = null; +let defaultGlobalOwnKeys: PropertyKey[] | null = null; export default function createVirtualEnvironment( globalObject: typeof globalThis, @@ -62,7 +62,7 @@ export default function createVirtualEnvironment( env.lazyRemapProperties( globalObject, shouldUseDefaultGlobalOwnKeys - ? (defaultGlobalOwnKeys as PropertyKeys) + ? (defaultGlobalOwnKeys as PropertyKey[]) : getFilteredGlobalOwnKeys(globalObjectShape) ); diff --git a/packages/near-membrane-shared-dom/.eslintrc.cjs b/packages/near-membrane-shared-dom/.eslintrc.cjs new file mode 100644 index 00000000..1be09955 --- /dev/null +++ b/packages/near-membrane-shared-dom/.eslintrc.cjs @@ -0,0 +1,18 @@ +'use strict'; + +const path = require('node:path'); + +module.exports = { + overrides: [ + { + files: ['**/*.{ts}'], + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + // Use package.json from both this package folder and root. + { packageDir: [__dirname, path.join(__dirname, '../..')] }, + ], + }, + }, + ], +}; diff --git a/packages/near-membrane-shared-dom/.rolluprc.cjs b/packages/near-membrane-shared-dom/.rolluprc.cjs new file mode 100644 index 00000000..974817c8 --- /dev/null +++ b/packages/near-membrane-shared-dom/.rolluprc.cjs @@ -0,0 +1,5 @@ +'use strict'; + +const { rollupConfig } = require('@locker/scripts/rollup/configs/base.cjs'); + +module.exports = rollupConfig(); diff --git a/packages/near-membrane-shared-dom/LICENSE.txt b/packages/near-membrane-shared-dom/LICENSE.txt new file mode 100644 index 00000000..1a7d0ea1 --- /dev/null +++ b/packages/near-membrane-shared-dom/LICENSE.txt @@ -0,0 +1,21 @@ +Terms of Use + +Copyright 2022 Salesforce, Inc. All rights reserved. + +These Terms of Use govern the download, installation, and/or use of this software provided by Salesforce, Inc. (“Salesforce”) (the “Software”), were last updated on April 15, 2022, ** and constitute a legally binding agreement between you and Salesforce. If you do not agree to these Terms of Use, do not install or use the Software. + +Salesforce grants you a worldwide, non-exclusive, no-charge, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the Software and derivative works subject to these Terms. These Terms shall be included in all copies or substantial portions of the Software. + +Subject to the limited rights expressly granted hereunder, Salesforce reserves all rights, title, and interest in and to all intellectual property subsisting in the Software. No rights are granted to you hereunder other than as expressly set forth herein. Users residing in countries on the United States Office of Foreign Assets Control sanction list, or which are otherwise subject to a US export embargo, may not use the Software. + +Implementation of the Software may require development work, for which you are responsible. The Software may contain bugs, errors and incompatibilities and is made available on an AS IS basis without support, updates, or service level commitments. + +Salesforce reserves the right at any time to modify, suspend, or discontinue, the Software (or any part thereof) with or without notice. You agree that Salesforce shall not be liable to you or to any third party for any modification, suspension, or discontinuance. + +You agree to defend Salesforce against any claim, demand, suit or proceeding made or brought against Salesforce by a third party arising out of or accruing from (a) your use of the Software, and (b) any application you develop with the Software that infringes any copyright, trademark, trade secret, trade dress, patent, or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy (each a “Claim Against Salesforce”), and will indemnify Salesforce from any damages, attorney fees, and costs finally awarded against Salesforce as a result of, or for any amounts paid by Salesforce under a settlement approved by you in writing of, a Claim Against Salesforce, provided Salesforce (x) promptly gives you written notice of the Claim Against Salesforce, (y) gives you sole control of the defense and settlement of the Claim Against Salesforce (except that you may not settle any Claim Against Salesforce unless it unconditionally releases Salesforce of all liability), and (z) gives you all reasonable assistance, at your expense. + +WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE SOFTWARE IS NOT SUPPORTED AND IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL SALESFORCE HAVE ANY LIABILITY FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES, OR DAMAGES BASED ON LOST PROFITS, DATA, OR USE, IN CONNECTION WITH THE SOFTWARE, HOWEVER CAUSED AND WHETHER IN CONTRACT, TORT, OR UNDER ANY OTHER THEORY OF LIABILITY, WHETHER OR NOT YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +These Terms of Use shall be governed exclusively by the internal laws of the State of California, without regard to its conflicts of laws rules. Each party hereby consents to the exclusive jurisdiction of the state and federal courts located in San Francisco County, California to adjudicate any dispute arising out of or relating to these Terms of Use and the download, installation, and/or use of the Software. Except as expressly stated herein, these Terms of Use constitute the entire agreement between the parties, and supersede all prior and contemporaneous agreements, proposals, or representations, written or oral, concerning their subject matter. No modification, amendment, or waiver of any provision of these Terms of Use shall be effective unless it is by an update to these Terms of Use that Salesforce makes available, or is in writing and signed by the party against whom the modification, amendment, or waiver is to be asserted. + +Data Privacy: Salesforce may collect, process, and store device, system, and other information related to your use of the Software. This information includes, but is not limited to, IP address, user metrics, and other data (“Usage Data”). Salesforce may use Usage Data for analytics, product development, and marketing purposes. You acknowledge that files generated in conjunction with the Software may contain sensitive or confidential data, and you are solely responsible for anonymizing and protecting such data. diff --git a/packages/near-membrane-shared-dom/README.md b/packages/near-membrane-shared-dom/README.md new file mode 100644 index 00000000..7012f426 --- /dev/null +++ b/packages/near-membrane-shared-dom/README.md @@ -0,0 +1,3 @@ +# @locker/near-membrane-shared-dom + +> Near-membrane shared DOM utilities diff --git a/packages/near-membrane-shared-dom/package.json b/packages/near-membrane-shared-dom/package.json new file mode 100644 index 00000000..c07c5a11 --- /dev/null +++ b/packages/near-membrane-shared-dom/package.json @@ -0,0 +1,31 @@ +{ + "name": "@locker/near-membrane-shared-dom", + "version": "0.11.4", + "repository": { + "type": "git", + "url": "https://github.com/salesforce/near-membrane.git", + "directory": "packages/near-membrane-shared-dom" + }, + "license": "MIT", + "author": "Caridy Patiño ", + "description": "Near-membrane shared DOM utilities", + "main": "dist/index.cjs.js", + "module": "dist/index.js", + "sideEffects": false, + "typings": "types/index.d.ts", + "scripts": { + "clean": "locker-trash dist types", + "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", + "build:dev": "cross-env NODE_ENV=development yarn build" + }, + "files": [ + "dist/", + "types/" + ], + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@locker/near-membrane-shared": "0.11.4" + } +} diff --git a/packages/near-membrane-shared-dom/src/Document.ts b/packages/near-membrane-shared-dom/src/Document.ts new file mode 100644 index 00000000..bd67b558 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/Document.ts @@ -0,0 +1,13 @@ +import { ObjectLookupOwnGetter } from '@locker/near-membrane-shared'; + +export const topDocument = document; + +const { prototype: DocumentProto } = Document; + +export const { + close: DocumentProtoClose, + createElement: DocumentProtoCreateElement, + open: DocumentProtoOpen, +} = DocumentProto; + +export const DocumentProtoBodyGetter = ObjectLookupOwnGetter(DocumentProto, 'body')!; diff --git a/packages/near-membrane-shared-dom/src/Element.ts b/packages/near-membrane-shared-dom/src/Element.ts new file mode 100644 index 00000000..8a2cace7 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/Element.ts @@ -0,0 +1,2 @@ +export const { remove: ElementProtoRemove, setAttribute: ElementProtoSetAttribute } = + Element.prototype; diff --git a/packages/near-membrane-shared-dom/src/HTMLElement.ts b/packages/near-membrane-shared-dom/src/HTMLElement.ts new file mode 100644 index 00000000..f509d75d --- /dev/null +++ b/packages/near-membrane-shared-dom/src/HTMLElement.ts @@ -0,0 +1,3 @@ +import { ObjectLookupOwnGetter } from '@locker/near-membrane-shared'; + +export const HTMLElementProtoStyleGetter = ObjectLookupOwnGetter(HTMLElement.prototype, 'style')!; diff --git a/packages/near-membrane-shared-dom/src/HTMLIFrameElement.ts b/packages/near-membrane-shared-dom/src/HTMLIFrameElement.ts new file mode 100644 index 00000000..5d83d231 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/HTMLIFrameElement.ts @@ -0,0 +1,6 @@ +import { ObjectLookupOwnGetter } from '@locker/near-membrane-shared'; + +export const HTMLIFrameElementProtoContentWindowGetter = ObjectLookupOwnGetter( + HTMLIFrameElement.prototype, + 'contentWindow' +)!; diff --git a/packages/near-membrane-shared-dom/src/Node.ts b/packages/near-membrane-shared-dom/src/Node.ts new file mode 100644 index 00000000..4c143326 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/Node.ts @@ -0,0 +1,7 @@ +import { ObjectLookupOwnGetter } from '@locker/near-membrane-shared'; + +const { prototype: NodeProto } = Node; + +export const { appendChild: NodeProtoAppendChild } = NodeProto; + +export const NodeProtoLastChildGetter = ObjectLookupOwnGetter(NodeProto, 'lastChild')!; diff --git a/packages/near-membrane-shared-dom/src/__tests__/Document.spec.js b/packages/near-membrane-shared-dom/src/__tests__/Document.spec.js new file mode 100644 index 00000000..a95cb6f2 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/__tests__/Document.spec.js @@ -0,0 +1,23 @@ +import { + DocumentProtoBodyGetter, + DocumentProtoClose, + DocumentProtoCreateElement, + DocumentProtoOpen, +} from '../../dist/index'; + +describe('Document', () => { + it('DocumentProtoClose', () => { + expect(DocumentProtoClose).toBe(Document.prototype.close); + }); + it('DocumentProtoBodyGetter', () => { + expect(DocumentProtoBodyGetter).toBe( + Reflect.getOwnPropertyDescriptor(Document.prototype, 'body').get + ); + }); + it('DocumentProtoCreateElement', () => { + expect(DocumentProtoCreateElement).toBe(Document.prototype.createElement); + }); + it('DocumentProtoOpen', () => { + expect(DocumentProtoOpen).toBe(Document.prototype.open); + }); +}); diff --git a/packages/near-membrane-shared-dom/src/__tests__/Element.spec.js b/packages/near-membrane-shared-dom/src/__tests__/Element.spec.js new file mode 100644 index 00000000..afab13d0 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/__tests__/Element.spec.js @@ -0,0 +1,10 @@ +import { ElementProtoRemove, ElementProtoSetAttribute } from '../../dist/index'; + +describe('Element', () => { + it('ElementProtoRemove', () => { + expect(ElementProtoRemove).toBe(Element.prototype.remove); + }); + it('ElementProtoSetAttribute', () => { + expect(ElementProtoSetAttribute).toBe(Element.prototype.setAttribute); + }); +}); diff --git a/packages/near-membrane-shared-dom/src/__tests__/HTMLElement.spec.js b/packages/near-membrane-shared-dom/src/__tests__/HTMLElement.spec.js new file mode 100644 index 00000000..62b3c7df --- /dev/null +++ b/packages/near-membrane-shared-dom/src/__tests__/HTMLElement.spec.js @@ -0,0 +1,9 @@ +import { HTMLElementProtoStyleGetter } from '../../dist/index'; + +describe('HTMLElement', () => { + it('HTMLElementProtoStyleGetter', () => { + expect(HTMLElementProtoStyleGetter).toBe( + Reflect.getOwnPropertyDescriptor(HTMLElement.prototype, 'style').get + ); + }); +}); diff --git a/packages/near-membrane-shared-dom/src/__tests__/HTMLIFrameElement.spec.js b/packages/near-membrane-shared-dom/src/__tests__/HTMLIFrameElement.spec.js new file mode 100644 index 00000000..fb9e030d --- /dev/null +++ b/packages/near-membrane-shared-dom/src/__tests__/HTMLIFrameElement.spec.js @@ -0,0 +1,9 @@ +import { HTMLIFrameElementProtoContentWindowGetter } from '../../dist/index'; + +describe('HTMLIFrameElement', () => { + it('HTMLIFrameElementProtoContentWindowGetter', () => { + expect(HTMLIFrameElementProtoContentWindowGetter).toBe( + Reflect.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'contentWindow').get + ); + }); +}); diff --git a/packages/near-membrane-shared-dom/src/__tests__/Node.spec.js b/packages/near-membrane-shared-dom/src/__tests__/Node.spec.js new file mode 100644 index 00000000..6ace78b7 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/__tests__/Node.spec.js @@ -0,0 +1,12 @@ +import { NodeProtoAppendChild, NodeProtoLastChildGetter } from '../../dist/index'; + +describe('Node', () => { + it('NodeAppendChild', () => { + expect(NodeProtoAppendChild).toBe(Node.prototype.appendChild); + }); + it('NodeProtoLastChildGetter', () => { + expect(NodeProtoLastChildGetter).toBe( + Reflect.getOwnPropertyDescriptor(Node.prototype, 'lastChild').get + ); + }); +}); diff --git a/packages/near-membrane-shared-dom/src/index.ts b/packages/near-membrane-shared-dom/src/index.ts new file mode 100644 index 00000000..1cd242d0 --- /dev/null +++ b/packages/near-membrane-shared-dom/src/index.ts @@ -0,0 +1,6 @@ +export * from './Document'; +export * from './Element'; +export * from './HTMLElement'; +export * from './HTMLIFrameElement'; +export * from './Node'; +export * from './types'; diff --git a/packages/near-membrane-shared-dom/src/types.ts b/packages/near-membrane-shared-dom/src/types.ts new file mode 100644 index 00000000..d61c674e --- /dev/null +++ b/packages/near-membrane-shared-dom/src/types.ts @@ -0,0 +1 @@ +export type GlobalObject = Window & typeof globalThis; diff --git a/packages/near-membrane-shared-dom/tsconfig.json b/packages/near-membrane-shared-dom/tsconfig.json new file mode 100644 index 00000000..18cf266d --- /dev/null +++ b/packages/near-membrane-shared-dom/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "exclude": [ + "**/__tests__" + ] +} diff --git a/packages/near-membrane-shared-dom/tsconfig.types.json b/packages/near-membrane-shared-dom/tsconfig.types.json new file mode 100644 index 00000000..d3d38068 --- /dev/null +++ b/packages/near-membrane-shared-dom/tsconfig.types.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.types.json", + "compilerOptions": { + "declarationDir": "types", + }, + "include": ["src/"], + "exclude": [ + "**/__tests__" + ] +} diff --git a/packages/near-membrane-shared/.eslintrc.cjs b/packages/near-membrane-shared/.eslintrc.cjs new file mode 100644 index 00000000..1be09955 --- /dev/null +++ b/packages/near-membrane-shared/.eslintrc.cjs @@ -0,0 +1,18 @@ +'use strict'; + +const path = require('node:path'); + +module.exports = { + overrides: [ + { + files: ['**/*.{ts}'], + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + // Use package.json from both this package folder and root. + { packageDir: [__dirname, path.join(__dirname, '../..')] }, + ], + }, + }, + ], +}; diff --git a/packages/near-membrane-shared/.rolluprc.cjs b/packages/near-membrane-shared/.rolluprc.cjs new file mode 100644 index 00000000..974817c8 --- /dev/null +++ b/packages/near-membrane-shared/.rolluprc.cjs @@ -0,0 +1,5 @@ +'use strict'; + +const { rollupConfig } = require('@locker/scripts/rollup/configs/base.cjs'); + +module.exports = rollupConfig(); diff --git a/packages/near-membrane-shared/LICENSE.txt b/packages/near-membrane-shared/LICENSE.txt new file mode 100644 index 00000000..1a7d0ea1 --- /dev/null +++ b/packages/near-membrane-shared/LICENSE.txt @@ -0,0 +1,21 @@ +Terms of Use + +Copyright 2022 Salesforce, Inc. All rights reserved. + +These Terms of Use govern the download, installation, and/or use of this software provided by Salesforce, Inc. (“Salesforce”) (the “Software”), were last updated on April 15, 2022, ** and constitute a legally binding agreement between you and Salesforce. If you do not agree to these Terms of Use, do not install or use the Software. + +Salesforce grants you a worldwide, non-exclusive, no-charge, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the Software and derivative works subject to these Terms. These Terms shall be included in all copies or substantial portions of the Software. + +Subject to the limited rights expressly granted hereunder, Salesforce reserves all rights, title, and interest in and to all intellectual property subsisting in the Software. No rights are granted to you hereunder other than as expressly set forth herein. Users residing in countries on the United States Office of Foreign Assets Control sanction list, or which are otherwise subject to a US export embargo, may not use the Software. + +Implementation of the Software may require development work, for which you are responsible. The Software may contain bugs, errors and incompatibilities and is made available on an AS IS basis without support, updates, or service level commitments. + +Salesforce reserves the right at any time to modify, suspend, or discontinue, the Software (or any part thereof) with or without notice. You agree that Salesforce shall not be liable to you or to any third party for any modification, suspension, or discontinuance. + +You agree to defend Salesforce against any claim, demand, suit or proceeding made or brought against Salesforce by a third party arising out of or accruing from (a) your use of the Software, and (b) any application you develop with the Software that infringes any copyright, trademark, trade secret, trade dress, patent, or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy (each a “Claim Against Salesforce”), and will indemnify Salesforce from any damages, attorney fees, and costs finally awarded against Salesforce as a result of, or for any amounts paid by Salesforce under a settlement approved by you in writing of, a Claim Against Salesforce, provided Salesforce (x) promptly gives you written notice of the Claim Against Salesforce, (y) gives you sole control of the defense and settlement of the Claim Against Salesforce (except that you may not settle any Claim Against Salesforce unless it unconditionally releases Salesforce of all liability), and (z) gives you all reasonable assistance, at your expense. + +WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE SOFTWARE IS NOT SUPPORTED AND IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL SALESFORCE HAVE ANY LIABILITY FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES, OR DAMAGES BASED ON LOST PROFITS, DATA, OR USE, IN CONNECTION WITH THE SOFTWARE, HOWEVER CAUSED AND WHETHER IN CONTRACT, TORT, OR UNDER ANY OTHER THEORY OF LIABILITY, WHETHER OR NOT YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +These Terms of Use shall be governed exclusively by the internal laws of the State of California, without regard to its conflicts of laws rules. Each party hereby consents to the exclusive jurisdiction of the state and federal courts located in San Francisco County, California to adjudicate any dispute arising out of or relating to these Terms of Use and the download, installation, and/or use of the Software. Except as expressly stated herein, these Terms of Use constitute the entire agreement between the parties, and supersede all prior and contemporaneous agreements, proposals, or representations, written or oral, concerning their subject matter. No modification, amendment, or waiver of any provision of these Terms of Use shall be effective unless it is by an update to these Terms of Use that Salesforce makes available, or is in writing and signed by the party against whom the modification, amendment, or waiver is to be asserted. + +Data Privacy: Salesforce may collect, process, and store device, system, and other information related to your use of the Software. This information includes, but is not limited to, IP address, user metrics, and other data (“Usage Data”). Salesforce may use Usage Data for analytics, product development, and marketing purposes. You acknowledge that files generated in conjunction with the Software may contain sensitive or confidential data, and you are solely responsible for anonymizing and protecting such data. diff --git a/packages/near-membrane-shared/README.md b/packages/near-membrane-shared/README.md new file mode 100644 index 00000000..58629523 --- /dev/null +++ b/packages/near-membrane-shared/README.md @@ -0,0 +1,3 @@ +# @locker/near-membrane-shared + +> Near-membrane shared language utilities diff --git a/packages/near-membrane-shared/package.json b/packages/near-membrane-shared/package.json new file mode 100644 index 00000000..6f8429cf --- /dev/null +++ b/packages/near-membrane-shared/package.json @@ -0,0 +1,28 @@ +{ + "name": "@locker/near-membrane-shared", + "version": "0.11.4", + "repository": { + "type": "git", + "url": "https://github.com/salesforce/near-membrane.git", + "directory": "packages/near-membrane-shared" + }, + "license": "MIT", + "author": "Caridy Patiño ", + "description": "Near-membrane shared language utilities", + "main": "dist/index.cjs.js", + "module": "dist/index.js", + "sideEffects": false, + "typings": "types/index.d.ts", + "scripts": { + "clean": "locker-trash dist types", + "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", + "build:dev": "cross-env NODE_ENV=development yarn build" + }, + "files": [ + "dist/", + "types/" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/packages/near-membrane-base/src/utils.ts b/packages/near-membrane-shared/src/Array.ts similarity index 68% rename from packages/near-membrane-base/src/utils.ts rename to packages/near-membrane-shared/src/Array.ts index 1917f143..c1dd4e91 100644 --- a/packages/near-membrane-base/src/utils.ts +++ b/packages/near-membrane-shared/src/Array.ts @@ -1,13 +1,8 @@ -const ArrayCtor = Array; -const WeakMapCtor = WeakMap; +import { ObjectAssign, ObjectFreeze } from './Object'; +import { ReflectSetPrototypeOf } from './Reflect'; +import { SymbolIterator, SymbolUnscopables } from './Symbol'; -const { setPrototypeOf: ReflectSetPrototypeOf } = Reflect; - -const { - iterator: SymbolIterator, - toStringTag: SymbolToStringTag, - unscopables: SymbolUnscopables, -} = Symbol; +export const ArrayCtor = Array; const { prototype: ArrayProto } = ArrayCtor; @@ -31,7 +26,6 @@ const { lastIndexOf: ArrayProtoLastIndexOf, map: ArrayProtoMap, pop: ArrayProtoPop, - push: ArrayProtoPush, reduce: ArrayProtoReduce, reduceRight: ArrayProtoReduceRight, reverse: ArrayProtoReverse, @@ -44,22 +38,16 @@ const { toString: ArrayProtoToString, unshift: ArrayProtoUnshift, values: ArrayProtoValues, - [SymbolIterator]: ArrayProtoSymbolIterator, -} = ArrayProto as any; + [SymbolIterator as any]: ArrayProtoSymbolIterator, +} = ArrayProto; -const ArrayUnscopables = Object.freeze( - Object.assign({ __proto__: null }, (ArrayProto as any)[SymbolUnscopables]) +const ArrayUnscopables = ObjectFreeze( + ObjectAssign({ __proto__: null }, ArrayProto[SymbolUnscopables as any]) ); -const { prototype: WeakMapProto } = WeakMapCtor; +export const { push: ArrayProtoPush } = ArrayProto; -const { - delete: WeakMapProtoDelete, - get: WeakMapProtoGet, - has: WeakMapProtoHas, - set: WeakMapProtoSet, - [SymbolToStringTag]: WeakMapProtoSymbolToStringTag, -} = WeakMapProto as any; +export const { isArray: ArrayIsArray } = ArrayCtor; export function toSafeArray(array: T): T { ReflectSetPrototypeOf(array, null); @@ -75,10 +63,10 @@ export function toSafeArray(array: T): T { // if the prototype of the array is change or nulled beforehand. Further, // the de-opt persists after a page refresh. It is not until navigating to // a different page that the performance of `Array#splice` is restored. - array.copyWithin = ArrayProtoCopyWithin; + array.copyWithin = ArrayProtoCopyWithin as any; array.entries = ArrayProtoEntries; array.every = ArrayProtoEvery; - array.fill = ArrayProtoFill; + array.fill = ArrayProtoFill as any; array.filter = ArrayProtoFilter; array.find = ArrayProtoFind; array.findIndex = ArrayProtoFindIndex; @@ -99,25 +87,14 @@ export function toSafeArray(array: T): T { array.shift = ArrayProtoShift; array.slice = ArrayProtoSlice; array.some = ArrayProtoSome; - array.sort = ArrayProtoSort; + array.sort = ArrayProtoSort as any; array.splice = ArrayProtoSplice; array.toLocaleString = ArrayProtoToLocaleString; array.toString = ArrayProtoToString; array.unshift = ArrayProtoUnshift; array.values = ArrayProtoValues; - (array as any)[SymbolIterator] = ArrayProtoSymbolIterator; - (array as any)[SymbolUnscopables] = ArrayUnscopables; + array[SymbolIterator as any] = ArrayProtoSymbolIterator; + array[SymbolUnscopables as any] = ArrayUnscopables; ReflectSetPrototypeOf(array, ArrayProto); return array; } - -export function toSafeWeakMap>(weakMap: T): T { - ReflectSetPrototypeOf(weakMap, null); - weakMap.delete = WeakMapProtoDelete; - weakMap.get = WeakMapProtoGet; - weakMap.has = WeakMapProtoHas; - weakMap.set = WeakMapProtoSet; - (weakMap as any)[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; - ReflectSetPrototypeOf(weakMap, WeakMapProto); - return weakMap; -} diff --git a/packages/near-membrane-shared/src/Error.ts b/packages/near-membrane-shared/src/Error.ts new file mode 100644 index 00000000..47410c74 --- /dev/null +++ b/packages/near-membrane-shared/src/Error.ts @@ -0,0 +1,2 @@ +export const ErrorCtor = Error; +export const TypeErrorCtor = TypeError; diff --git a/packages/near-membrane-shared/src/Function.ts b/packages/near-membrane-shared/src/Function.ts new file mode 100644 index 00000000..6f841f96 --- /dev/null +++ b/packages/near-membrane-shared/src/Function.ts @@ -0,0 +1,3 @@ +export function noop() { + // No operation performed. +} diff --git a/packages/near-membrane-shared/src/Object.ts b/packages/near-membrane-shared/src/Object.ts new file mode 100644 index 00000000..6e424eeb --- /dev/null +++ b/packages/near-membrane-shared/src/Object.ts @@ -0,0 +1,37 @@ +import { ReflectApply } from './Reflect'; +import type { Getter, Setter } from './types'; + +const ObjectCtor = Object; +const { prototype: ObjectProto } = ObjectCtor; + +export const { assign: ObjectAssign, freeze: ObjectFreeze } = ObjectCtor; + +const { hasOwn: OriginalObjectHasOwn } = ObjectCtor as any; + +const { + __lookupGetter__: ObjectProtoLookupGetter, + __lookupSetter__: ObjectProtoLookupSetter, + hasOwnProperty: ObjectProtoHasOwnProperty, +} = ObjectProto as any; + +const ObjectHasOwn: (object: any, key: PropertyKey) => boolean = + typeof OriginalObjectHasOwn === 'function' + ? OriginalObjectHasOwn + : /* istanbul ignore next: currently unreachable via tests */ function ObjectHasOwn( + object: any, + key: PropertyKey + ): boolean { + return ReflectApply(ObjectProtoHasOwnProperty, object, [key]); + }; + +export function ObjectLookupOwnGetter(object: any, key: PropertyKey): Getter | undefined { + return object === null || object === undefined || !ObjectHasOwn(object, key) + ? undefined + : ReflectApply(ObjectProtoLookupGetter, object, [key]); +} + +export function ObjectLookupOwnSetter(object: any, key: PropertyKey): Setter | undefined { + return object === null || object === undefined || !ObjectHasOwn(object, key) + ? undefined + : ReflectApply(ObjectProtoLookupSetter, object, [key]); +} diff --git a/packages/near-membrane-shared/src/Reflect.ts b/packages/near-membrane-shared/src/Reflect.ts new file mode 100644 index 00000000..9a97d773 --- /dev/null +++ b/packages/near-membrane-shared/src/Reflect.ts @@ -0,0 +1,7 @@ +export const { + apply: ReflectApply, + deleteProperty: ReflectDeleteProperty, + getPrototypeOf: ReflectGetPrototypeOf, + ownKeys: ReflectOwnKeys, + setPrototypeOf: ReflectSetPrototypeOf, +} = Reflect; diff --git a/packages/near-membrane-shared/src/Symbol.ts b/packages/near-membrane-shared/src/Symbol.ts new file mode 100644 index 00000000..76b331c4 --- /dev/null +++ b/packages/near-membrane-shared/src/Symbol.ts @@ -0,0 +1,5 @@ +export const { + iterator: SymbolIterator, + toStringTag: SymbolToStringTag, + unscopables: SymbolUnscopables, +} = Symbol; diff --git a/packages/near-membrane-shared/src/WeakMap.ts b/packages/near-membrane-shared/src/WeakMap.ts new file mode 100644 index 00000000..2707222f --- /dev/null +++ b/packages/near-membrane-shared/src/WeakMap.ts @@ -0,0 +1,25 @@ +import { ReflectSetPrototypeOf } from './Reflect'; +import { SymbolToStringTag } from './Symbol'; + +export const WeakMapCtor = WeakMap; + +const { prototype: WeakMapProto } = WeakMapCtor; + +const { + delete: WeakMapProtoDelete, + get: WeakMapProtoGet, + has: WeakMapProtoHas, + set: WeakMapProtoSet, + [SymbolToStringTag]: WeakMapProtoSymbolToStringTag, +} = WeakMapProto as any; + +export function toSafeWeakMap>(weakMap: T): T { + ReflectSetPrototypeOf(weakMap, null); + weakMap.delete = WeakMapProtoDelete; + weakMap.get = WeakMapProtoGet; + weakMap.has = WeakMapProtoHas; + weakMap.set = WeakMapProtoSet; + (weakMap as any)[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; + ReflectSetPrototypeOf(weakMap, WeakMapProto); + return weakMap; +} diff --git a/packages/near-membrane-shared/src/__tests__/Array.spec.js b/packages/near-membrane-shared/src/__tests__/Array.spec.js new file mode 100644 index 00000000..124716fb --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Array.spec.js @@ -0,0 +1,96 @@ +import { ArrayCtor, ArrayIsArray, ArrayProtoPush, toSafeArray } from '../../dist/index'; + +describe('Array', () => { + it('ArrayCtor', () => { + expect(ArrayCtor).toBe(Array); + }); + it('ArrayIsArray', () => { + expect(ArrayIsArray).toBe(Array.isArray); + }); + it('ArrayProtoPush', () => { + expect(ArrayProtoPush).toBe(Array.prototype.push); + }); + it('toSafeArray', () => { + const array = []; + expect(Reflect.ownKeys(array)).toEqual(['length']); + expect(toSafeArray(array)).toBe(array); + expect(Reflect.ownKeys(array)).toEqual([ + 'length', + 'at', + 'concat', + 'copyWithin', + 'entries', + 'every', + 'fill', + 'filter', + 'find', + 'findIndex', + 'flat', + 'flatMap', + 'forEach', + 'includes', + 'indexOf', + 'join', + 'keys', + 'lastIndexOf', + 'map', + 'pop', + 'push', + 'reduce', + 'reduceRight', + 'reverse', + 'shift', + 'slice', + 'some', + 'sort', + 'splice', + 'toLocaleString', + 'toString', + 'unshift', + 'values', + Symbol.iterator, + Symbol.unscopables, + ]); + expect(array.at).toBe(Array.prototype.at); + expect(array.concat).toBe(Array.prototype.concat); + expect(array.constructor).toBe(Array.prototype.constructor); + expect(array.copyWithin).toBe(Array.prototype.copyWithin); + expect(array.entries).toBe(Array.prototype.entries); + expect(array.every).toBe(Array.prototype.every); + expect(array.fill).toBe(Array.prototype.fill); + expect(array.find).toBe(Array.prototype.find); + expect(array.findIndex).toBe(Array.prototype.findIndex); + expect(array.flat).toBe(Array.prototype.flat); + expect(array.flatMap).toBe(Array.prototype.flatMap); + expect(array.forEach).toBe(Array.prototype.forEach); + expect(array.includes).toBe(Array.prototype.includes); + expect(array.indexOf).toBe(Array.prototype.indexOf); + expect(array.join).toBe(Array.prototype.join); + expect(array.keys).toBe(Array.prototype.keys); + expect(array.lastIndexOf).toBe(Array.prototype.lastIndexOf); + expect(array.map).toBe(Array.prototype.map); + expect(array.pop).toBe(Array.prototype.pop); + expect(array.push).toBe(Array.prototype.push); + expect(array.reduce).toBe(Array.prototype.reduce); + expect(array.reduceRight).toBe(Array.prototype.reduceRight); + expect(array.reverse).toBe(Array.prototype.reverse); + expect(array.shift).toBe(Array.prototype.shift); + expect(array.slice).toBe(Array.prototype.slice); + expect(array.some).toBe(Array.prototype.some); + expect(array.sort).toBe(Array.prototype.sort); + expect(array.toLocalString).toBe(Array.prototype.toLocalString); + expect(array.toString).toBe(Array.prototype.toString); + expect(array.unshift).toBe(Array.prototype.unshift); + expect(array.values).toBe(Array.prototype.values); + expect(array[Symbol.iterator]).toBe(Array.prototype[Symbol.iterator]); + expect(array[Symbol.unscopables]).toEqual(Array.prototype[Symbol.unscopables]); + expect(array[Symbol.unscopables]).not.toBe(Array.prototype[Symbol.unscopables]); + expect(Object.isFrozen(array[Symbol.unscopables])).toBe(true); + expect(Reflect.getOwnPropertyDescriptor(array, Symbol.unscopables)).toEqual({ + enumerable: true, + configurable: true, + value: Array.prototype[Symbol.unscopables], + writable: true, + }); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/Error.spec.js b/packages/near-membrane-shared/src/__tests__/Error.spec.js new file mode 100644 index 00000000..babed764 --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Error.spec.js @@ -0,0 +1,10 @@ +import { ErrorCtor, TypeErrorCtor } from '../../dist/index'; + +describe('Error', () => { + it('ErrorCtor', () => { + expect(ErrorCtor).toBe(Error); + }); + it('TypeErrorCtor', () => { + expect(TypeErrorCtor).toBe(TypeError); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/Function.spec.js b/packages/near-membrane-shared/src/__tests__/Function.spec.js new file mode 100644 index 00000000..c81fc7ae --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Function.spec.js @@ -0,0 +1,11 @@ +import { noop } from '../../dist/index'; + +describe('Function', () => { + it('noop', () => { + expect(noop()).toBe(undefined); + expect(noop(null)).toBe(undefined); + expect(noop(true)).toBe(undefined); + expect(noop(1)).toBe(undefined); + expect(noop({})).toBe(undefined); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/Object.spec.js b/packages/near-membrane-shared/src/__tests__/Object.spec.js new file mode 100644 index 00000000..254b4309 --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Object.spec.js @@ -0,0 +1,60 @@ +import { + ObjectAssign, + ObjectFreeze, + ObjectLookupOwnGetter, + ObjectLookupOwnSetter, +} from '../../dist/index'; + +describe('Object', () => { + it('ObjectAssign', () => { + expect(ObjectAssign).toBe(Object.assign); + }); + it('ObjectFreeze', () => { + expect(ObjectFreeze).toBe(Object.freeze); + }); + it('ObjectLookupOwnGetter', () => { + expect(ObjectLookupOwnGetter(undefined, undefined)).toBe(undefined); + expect(ObjectLookupOwnGetter(null, null)).toBe(undefined); + expect(ObjectLookupOwnGetter(null, 'x')).toBe(undefined); + expect(ObjectLookupOwnGetter(undefined, 'x')).toBe(undefined); + expect(ObjectLookupOwnGetter({}, 'x')).toBe(undefined); + expect( + ObjectLookupOwnGetter( + { + get x() { + return 1; + }, + }, + 'x' + )() + ).toBe(1); + const o = {}; + Reflect.defineProperty(o, 'x', { + get() { + return 1; + }, + }); + expect(ObjectLookupOwnGetter(o, 'x')()).toBe(1); + // eslint-disable-next-line no-restricted-properties, no-underscore-dangle + o.__defineGetter__('y', () => 1); + expect(ObjectLookupOwnGetter(o, 'y')()).toBe(1); + expect(ObjectLookupOwnGetter(Object.create(o), 'x')).toBe(undefined); + }); + it('ObjectLookupOwnSetter', () => { + expect(ObjectLookupOwnSetter(null, 'x')).toBe(undefined); + expect(ObjectLookupOwnSetter(undefined, 'x')).toBe(undefined); + expect(ObjectLookupOwnSetter({}, 'x')).toBe(undefined); + // eslint-disable-next-line no-empty-function + const o = { set x(_v) {} }; + const { set: xSetter } = Reflect.getOwnPropertyDescriptor(o, 'x'); + expect(ObjectLookupOwnSetter(o, 'x')).toBe(xSetter); + delete o.x; + // eslint-disable-next-line no-restricted-properties, no-underscore-dangle + o.__defineSetter__('x', xSetter); + delete o.x; + Reflect.defineProperty(o, 'x', { set: xSetter }); + expect(ObjectLookupOwnSetter(o, 'x')).toBe(xSetter); + expect(ObjectLookupOwnSetter(o, 'x')).toBe(xSetter); + expect(ObjectLookupOwnSetter(Object.create(o), 'x')).toBe(undefined); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/Reflect.spec.js b/packages/near-membrane-shared/src/__tests__/Reflect.spec.js new file mode 100644 index 00000000..bc20ee3e --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Reflect.spec.js @@ -0,0 +1,25 @@ +import { + ReflectApply, + ReflectDeleteProperty, + ReflectGetPrototypeOf, + ReflectOwnKeys, + ReflectSetPrototypeOf, +} from '../../dist/index'; + +describe('Reflect', () => { + it('ReflectApply', () => { + expect(ReflectApply).toBe(Reflect.apply); + }); + it('ReflectDeleteProperty', () => { + expect(ReflectDeleteProperty).toBe(Reflect.deleteProperty); + }); + it('ReflectGetPrototypeOf', () => { + expect(ReflectGetPrototypeOf).toBe(Reflect.getPrototypeOf); + }); + it('ReflectOwnKeys', () => { + expect(ReflectOwnKeys).toBe(Reflect.ownKeys); + }); + it('ReflectSetPrototypeOf', () => { + expect(ReflectSetPrototypeOf).toBe(Reflect.setPrototypeOf); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/Symbol.spec.js b/packages/near-membrane-shared/src/__tests__/Symbol.spec.js new file mode 100644 index 00000000..69f224ae --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/Symbol.spec.js @@ -0,0 +1,13 @@ +import { SymbolIterator, SymbolToStringTag, SymbolUnscopables } from '../../dist/index'; + +describe('Symbol', () => { + it('SymbolIterator', () => { + expect(SymbolIterator).toBe(Symbol.iterator); + }); + it('SymbolToStringTag', () => { + expect(SymbolToStringTag).toBe(Symbol.toStringTag); + }); + it('SymbolUnscopables', () => { + expect(SymbolUnscopables).toBe(Symbol.unscopables); + }); +}); diff --git a/packages/near-membrane-shared/src/__tests__/WeakMap.spec.js b/packages/near-membrane-shared/src/__tests__/WeakMap.spec.js new file mode 100644 index 00000000..13d45c8a --- /dev/null +++ b/packages/near-membrane-shared/src/__tests__/WeakMap.spec.js @@ -0,0 +1,30 @@ +import { toSafeWeakMap, WeakMapCtor } from '../../dist/index'; + +describe('WeakMap', () => { + it('toSafeWeakMap', () => { + const weakMap = new WeakMap(); + expect(Reflect.ownKeys(weakMap)).toEqual([]); + expect(toSafeWeakMap(weakMap)).toBe(weakMap); + expect(Reflect.ownKeys(weakMap)).toEqual([ + 'delete', + 'get', + 'has', + 'set', + Symbol.toStringTag, + ]); + expect(weakMap.constructor).toBe(WeakMap); + expect(weakMap.delete).toBe(WeakMap.prototype.delete); + expect(weakMap.get).toBe(WeakMap.prototype.get); + expect(weakMap.has).toBe(WeakMap.prototype.has); + expect(weakMap.set).toBe(WeakMap.prototype.set); + expect(Reflect.getOwnPropertyDescriptor(weakMap, Symbol.toStringTag)).toEqual({ + configurable: true, + enumerable: true, + value: WeakMap.prototype[Symbol.toStringTag], + writable: true, + }); + }); + it('WeakMapCtor', () => { + expect(WeakMapCtor).toBe(WeakMap); + }); +}); diff --git a/packages/near-membrane-shared/src/index.ts b/packages/near-membrane-shared/src/index.ts new file mode 100644 index 00000000..1d1cf26d --- /dev/null +++ b/packages/near-membrane-shared/src/index.ts @@ -0,0 +1,8 @@ +export * from './Array'; +export * from './Error'; +export * from './Function'; +export * from './Object'; +export * from './Reflect'; +export * from './Symbol'; +export * from './types'; +export * from './WeakMap'; diff --git a/packages/near-membrane-shared/src/types.ts b/packages/near-membrane-shared/src/types.ts new file mode 100644 index 00000000..09eacdd3 --- /dev/null +++ b/packages/near-membrane-shared/src/types.ts @@ -0,0 +1,15 @@ +export type Getter = () => any; +export type NearMembraneSerializedValue = bigint | boolean | number | string | symbol; +export type ProxyTarget = CallableFunction | any[] | object; +export type Setter = (value: any) => void; +// eslint-disable-next-line no-shadow +export const enum TargetTraits { + None, + IsArray = 1 << 0, + IsArrayBufferView = 1 << 1, + IsFunction = 1 << 2, + IsArrowFunction = 1 << 3, + IsObject = 1 << 4, + IsTypedArray = 1 << 5, + Revoked = 1 << 6, +} diff --git a/packages/near-membrane-shared/tsconfig.json b/packages/near-membrane-shared/tsconfig.json new file mode 100644 index 00000000..18cf266d --- /dev/null +++ b/packages/near-membrane-shared/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "exclude": [ + "**/__tests__" + ] +} diff --git a/packages/near-membrane-shared/tsconfig.types.json b/packages/near-membrane-shared/tsconfig.types.json new file mode 100644 index 00000000..d3d38068 --- /dev/null +++ b/packages/near-membrane-shared/tsconfig.types.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.types.json", + "compilerOptions": { + "declarationDir": "types", + }, + "include": ["src/"], + "exclude": [ + "**/__tests__" + ] +} diff --git a/scripts/locker-trash.mjs b/scripts/locker-trash.mjs new file mode 100755 index 00000000..5a4fc629 --- /dev/null +++ b/scripts/locker-trash.mjs @@ -0,0 +1,70 @@ +#!/usr/bin/env node + +import fs from 'node:fs'; +import globby from 'globby'; +import meow from 'meow'; +import trash from 'trash'; + +const cli = meow( + ` + Usage + $ locker-trash [...] + + Options + --test, -t Test and display the paths to be trashed, but don't do it + + Examples + $ locker-trash dist types + $ locker-trash **/dist/** **/types/** + $ locker-trash '*.png' '!keep.png' + `, + { + flags: { + test: { + type: 'boolean', + alias: 't', + }, + }, + importMeta: import.meta, + } +); + +async function lockerTrash(args, flags) { + const argPaths = []; + const argGlobs = []; + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (fs.existsSync(arg)) { + // Path exists, capture as-is. + argPaths.push(arg); + } else { + // Path does not exist, assume it may be a glob pattern. + argGlobs.push(arg); + } + } + // Resolve all potential glob patterns. + const globPaths = await globby(argGlobs, { + nodir: false, + }); + + // This is the full list of paths to trash. + const trashPaths = argPaths.concat(globPaths); + if (flags.test) { + // eslint-disable-next-line no-console + console.log({ trashPaths }); + } else { + await Promise.all( + trashPaths.map(async (thePath) => { + try { + await trash(thePath, { glob: false }); + } catch (e) { + if (e?.code === 'EACCES') { + process.exitCode = e.code; + } + } + }) + ); + } +} + +lockerTrash(cli.input, cli.flags); diff --git a/scripts/package.json b/scripts/package.json index 382b2d1c..c3e231d2 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -2,5 +2,8 @@ "private": true, "name": "@locker/scripts", "version": "0.11.4", - "description": "Locker scripts" + "description": "Locker scripts", + "bin": { + "locker-trash": "./locker-trash.mjs" + } } diff --git a/scripts/rollup/configs/base.cjs b/scripts/rollup/configs/base.cjs index 8ce72d5d..0575e5c8 100644 --- a/scripts/rollup/configs/base.cjs +++ b/scripts/rollup/configs/base.cjs @@ -1,6 +1,7 @@ 'use strict'; const mergeOptions = require('merge-options'); +const fs = require('fs-extra'); const typescriptPlugin = require('@rollup/plugin-typescript'); const { getBabelOutputPlugin } = require('../plugins/babel-output.cjs'); @@ -16,12 +17,16 @@ function createConfig({ ...rollupOverrides } = {}) { const isCJS = format === 'cjs'; + const packageJSONPath = 'package.json'; - return mergeOptions.call( + const packageJSON = fs.readJSONSync(packageJSONPath); + const { dependencies } = packageJSON; + + const mergedRollupOptions = mergeOptions.call( mergeOptionsConfig, { input, - external: [], + external: undefined, output: { exports: 'auto', file: `dist/index${isCJS ? '.cjs' : ''}.js`, @@ -38,6 +43,12 @@ function createConfig({ }, rollupOverrides ); + + if (!mergedRollupOptions.external && dependencies) { + mergedRollupOptions.external = Object.keys(dependencies); + } + + return mergedRollupOptions; } module.exports = { diff --git a/test/membrane/arrays.spec.js b/test/membrane/arrays.spec.js new file mode 100644 index 00000000..16fc2e2c --- /dev/null +++ b/test/membrane/arrays.spec.js @@ -0,0 +1,35 @@ +import createVirtualEnvironment from '@locker/near-membrane-dom'; + +const blue = [1, 2, 3]; + +let red; +function saveFoo(arg) { + red = arg; +} + +describe('Arrays', () => { + it('should preserve the length behavior across the membrane', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ blue, expect, saveFoo }), + }); + + env.evaluate(` + saveFoo(['a', 'b', 'c']); + expect(blue.length).toBe(3); + expect(blue[2]).toBe(3); + blue[3] = 4; + expect(blue.length).toBe(4); + expect(blue[3]).toBe(4); + `); + + // Blue mutation from red realm should leak into blue realm. + expect(blue.length).toBe(4); + expect(blue[3]).toBe(4); + // Mutate red from blue realm. + expect(red.length).toBe(3); + expect(red[2]).toBe('c'); + red[3] = 'd'; + expect(red.length).toBe(4); + expect(red[3]).toBe('d'); + }); +}); diff --git a/test/membrane/errors.spec.js b/test/membrane/errors.spec.js new file mode 100644 index 00000000..689bc4fa --- /dev/null +++ b/test/membrane/errors.spec.js @@ -0,0 +1,585 @@ +/* eslint-disable no-throw-literal, no-new, class-methods-use-this */ +import createVirtualEnvironment from '@locker/near-membrane-dom'; + +const onerrorHandler = (function (originalOnError) { + return function onerror(...args) { + const { 0: message } = args; + // Suppress Jasmine's built-in unhandled promise rejection handling. + if (!String(message).startsWith('Unhandled promise rejection:')) { + Reflect.apply(originalOnError, globalThis, args); + } + }; +})(globalThis.onerror); + +it('[red] non-error objects thrown in red functions', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + function foo() { + throw errorObj + } + + try { + foo() + } catch(e) { + expect(e.foo).toBe('bar') + expect(e).toBe(errorObj) + expect(e.message).toBe(undefined) + } + `); +}); + +it('[red] non-error objects thrown in red constructors', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + + class Foo { + constructor() { + throw errorObj + } + } + + try { + new Foo() + } catch(e) { + expect(e.foo).toBe('bar') + expect(e).toBe(errorObj) + expect(e.message).toBe(undefined) + } + `); +}); + +it('[red] non-error objects thrown in Promise', (done) => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ done, expect }), + }); + + env.evaluate(` + const error = { foo: 'bar' } + const p = new Promise(() => { + throw error + }) + p.catch((e) => { + expect(e.foo).toBe('bar') + expect(e).toBe(error) + expect(e.message).toBe(undefined) + done() + }) + `); +}); + +it('[red] unhandled promise rejections with non-error objects and red listener', (done) => { + globalThis.onerror = onerrorHandler; + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ done, expect }), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + + function handler(event) { + window.removeEventListener('unhandledrejection', handler) + event.preventDefault() + expect(event.reason).toBe(errorObj) + expect(event.reason.foo).toBe('bar') + expect(event.reason.message).toBe(undefined) + done() + } + + window.addEventListener('unhandledrejection', handler) + + new Promise((resolve, reject) => { + throw errorObj + }) + `); +}); + +it('[red] Promise.reject non-error objects', (done) => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ done, expect }), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + + new Promise((resolve, reject) => { + reject(errorObj) + }).catch(e => { + expect(e.message).toBe(undefined) + expect(e.foo).toBe('bar') + done() + }) + `); +}); + +it('[red] unhandled promise rejections and Promise.reject with non-error objects and red listener', (done) => { + globalThis.onerror = onerrorHandler; + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ done, expect }), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + + function handler(event) { + window.removeEventListener('unhandledrejection', handler) + event.preventDefault() + expect(event.reason).toBe(errorObj) + expect(event.reason.foo).toBe('bar') + expect(event.reason.message).toBe(undefined) + done() + } + + window.addEventListener('unhandledrejection', handler) + new Promise((resolve, reject) => { + reject(errorObj) + }) + `); +}); + +it('[red] non-error objects thrown in blue functions', () => { + function foo() { + throw { foo: 'bar' }; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, foo }), + }); + + env.evaluate(` + try { + foo() + } catch (e) { + expect(e.message).toBe(undefined) + expect(e.foo).toBe('bar') + } + `); +}); + +it('[red] non-error objects thrown in blue constructors', () => { + class Foo { + constructor() { + throw { foo: 'bar' }; + } + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, Foo }), + }); + + env.evaluate(` + try { + new Foo() + } catch (e) { + expect(e.message).toBe(undefined) + expect(e.foo).toBe('bar') + } + `); +}); + +it('[red] blue extended error objects', () => { + class CustomError extends Error { + constructor(message) { + super(message); + this.bar = 'baz'; + } + + get foo() { + return 'bar'; + } + } + + class Foo { + constructor() { + throw new CustomError('foo'); + } + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, Foo }), + }); + + env.evaluate(` + try { + new Foo() + } catch (e) { + expect(e.foo).toBe('bar') + expect(e.bar).toBe('baz') + expect(e.message).toBe('foo') + } + `); +}); + +it('[red] .catch on blue promise', (done) => { + const promise = new Promise(() => { + throw { foo: 'bar' }; + }); + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, done, expect, promise }), + }); + + env.evaluate(` + promise.catch(e => { + expect(e.foo).toBe('bar') + expect(e.message).toBe(undefined) + done() + }) + `); +}); + +it('[red] non-error object with null proto', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + const errorObj = Object.create(null, {foo: {value: 'bar'}}) + try { + throw errorObj + } catch(e) { + expect(errorObj).toBe(errorObj) + expect(Reflect.getPrototypeOf(errorObj)).toBe(null) + expect(errorObj.message).toBe(undefined) + expect(errorObj.foo).toBe('bar') + } + `); +}); + +it('[red] non-error object with null proto from blue', () => { + function foo() { + throw Object.create(null, { foo: { value: 'bar' } }); + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, foo }), + }); + + env.evaluate(` + try { + foo() + } catch(e) { + expect(Reflect.getPrototypeOf(e)).toBe(null) + expect(e.message).toBe(undefined) + expect(e.foo).toBe('bar') + } + `); +}); + +it('[red] instanceof Error', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + try { + throw new Error('foo') + } catch(e) { + expect(e instanceof Error).toBe(true) + expect(e.message).toBe('foo') + } + `); +}); + +it('[red] instanceof extended Error objects', () => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + class CustomError extends Error {} + try { + throw new CustomError('foo') + } catch(e) { + expect(e instanceof CustomError).toBe(true) + expect(e.message).toBe('foo') + } + `); +}); + +it('[red] .catch instanceof Error', (done) => { + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, done }), + }); + + env.evaluate(` + new Promise((resolve, reject) => { + reject(new Error('foo')) + }).catch(e => { + expect(e instanceof Error).toBe(true) + expect(e.message).toBe('foo') + done() + }) + `); +}); + +it('[red] instanceof blue Error objects', () => { + function foo() { + throw new Error('foo'); + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect, foo }), + }); + + env.evaluate(` + try { + foo() + } catch(e) { + expect(e instanceof Error).toBe(true) + expect(e.message).toBe('foo') + } + `); +}); + +it('[red] .catch instanceof blue Error objects', (done) => { + const promise = new Promise((resolve, reject) => { + reject(new Error('foo')); + }); + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ done, expect, promise }), + }); + + env.evaluate(` + promise.catch(e => { + expect(e instanceof Error).toBe(true) + expect(e.message).toBe('foo') + done() + }) + `); +}); + +it('[blue] .catch on red promise', (done) => { + let promise; + + function save(arg) { + promise = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + const error = { foo: 'bar' } + const p = new Promise(() => { + throw error + }) + + save(p) + `); + + promise.catch((e) => { + expect(e.foo).toBe('bar'); + expect(e.message).toBe(undefined); + done(); + }); +}); + +it('[blue] unhandled promise rejections listener with red non-error objects', (done) => { + globalThis.onerror = onerrorHandler; + + function handler(event) { + window.removeEventListener('unhandledrejection', handler); + event.preventDefault(); + expect(event.reason.foo).toBe('bar'); + expect(event.reason.message).toBe(undefined); + done(); + } + + window.addEventListener('unhandledrejection', handler); + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors(window), + }); + + env.evaluate(` + const errorObj = { foo: 'bar' } + new Promise((resolve, reject) => { + throw errorObj + }) + `); +}); + +it('[blue] non-error objects thrown in red functions', () => { + let fn; + function save(arg) { + fn = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + function foo() { + throw { foo: 'bar' } + } + save(foo) + `); + + try { + fn(); + } catch (e) { + expect(e.message).toBe(undefined); + expect(e.foo).toBe('bar'); + } +}); + +it('[blue] non-error objects thrown in red consturctors', () => { + let ctor; + function save(arg) { + ctor = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + class Foo { + constructor() { + throw { foo: 'bar' } + } + } + save(Foo) + `); + + try { + // eslint-disable-next-line no-new + new ctor(); + } catch (e) { + expect(e.message).toBe(undefined); + expect(e.foo).toBe('bar'); + } +}); + +it('[blue] red extended error objects', () => { + let ctor; + function save(arg) { + ctor = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + class CustomError extends Error { + constructor(message) { + super(message) + this.bar = 'baz' + } + + get foo() { + return 'bar' + } + } + + class Foo { + constructor() { + throw new CustomError('foo') + } + } + + save(Foo) + `); + + try { + // eslint-disable-next-line no-new + new ctor(); + } catch (e) { + expect(e.message).toBe('foo'); + expect(e.bar).toBe('baz'); + expect(e.foo).toBe('bar'); + } +}); + +it('[blue] non-error objects with null proto from red', () => { + let fn; + function save(arg) { + fn = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + function foo() { + const errorObj = Object.create(null, {foo: {value: 'bar'}}) + throw errorObj + } + + save(foo) + `); + + try { + fn(); + } catch (e) { + expect(Reflect.getPrototypeOf(e)).toBe(null); + expect(e.message).toBe(undefined); + expect(e.foo).toBe('bar'); + } +}); + +it('[blue] instanceof red error', () => { + let fn; + function save(arg) { + fn = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + function foo() { + throw new Error('foo') + } + + save(foo) + `); + + try { + fn(); + } catch (e) { + expect(e instanceof Error).toBe(true); + expect(e.message).toBe('foo'); + } +}); + +it('[blue] .catch instanceof red error', (done) => { + let promise; + function save(arg) { + promise = arg; + } + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ ...window, save }), + }); + + env.evaluate(` + const promise = new Promise((resolve, reject) => { + reject(new Error('foo')) + }) + + save(promise) + `); + + promise.catch((e) => { + expect(e instanceof Error).toBe(true); + expect(e.message).toBe('foo'); + done(); + }); +}); diff --git a/test/membrane/object-graph.spec.js b/test/membrane/object-graph.spec.js new file mode 100644 index 00000000..f5a56913 --- /dev/null +++ b/test/membrane/object-graph.spec.js @@ -0,0 +1,67 @@ +import createVirtualEnvironment from '@locker/near-membrane-dom'; + +describe('The object graph', () => { + it('should be shadowed by a sandbox', () => { + expect.assertions(21); + + const env = createVirtualEnvironment(window, { + endowments: Object.getOwnPropertyDescriptors({ expect }), + }); + + env.evaluate(` + 'use strict'; + + const originalProto = HTMLParagraphElement.prototype.__proto__; + const newProto = { + get x() { return 1; }, + y: 2, + z: 3, + }; + // making z non-writable + Object.defineProperty(newProto, 'z', { writable: false }); + + // replacing proto chain + Object.setPrototypeOf(newProto, originalProto); + Object.setPrototypeOf(HTMLParagraphElement.prototype, newProto); + + const elm = document.createElement('p'); + document.body.appendChild(elm); + + expect('x' in elm).toBe(true); + expect(elm.x).toBe(1); + expect(() => { + elm.x = 100; + }).toThrow(); + expect(elm.x).toBe(1); + + expect(elm.y).toBe(2); + expect(() => { + elm.y = 200; + }).not.toThrow(); + expect(elm.y).toBe(200); + + expect(elm.z).toBe(3); + expect(() => { + elm.z = 300; + }).toThrow(); + expect(elm.z).toBe(3); + + expect(elm.w).toBe(undefined); + expect(() => { + elm.w = 400; + }).not.toThrow(); + expect(elm.w).toBe(400); + `); + + // Mutations on the object graph in the sandbox do not leak into the outer realm + const elm = document.querySelector('p'); + expect('w' in elm).toBe(false); + expect(elm.w).toBe(undefined); + expect('x' in elm).toBe(false); + expect(elm.x).toBe(undefined); + expect('y' in elm).toBe(false); + expect(elm.y).toBe(undefined); + expect('z' in elm).toBe(false); + expect(elm.z).toBe(undefined); + }); +}); diff --git a/yarn.lock b/yarn.lock index e9eef681..8f9d78c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3002,6 +3002,18 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.28.tgz#15aa0b416f82c268b1573ab653e4413c965fe794" integrity sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow== +"@sindresorhus/df@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@sindresorhus/df/-/df-1.0.1.tgz#c69b66f52f6fcdd287c807df210305dbaf78500d" + integrity sha512-1Hyp7NQnD/u4DSxR2DGW78TF9k7R0wZ8ev0BpMAIzA6yTQSHqNb5wTuvtcPYf4FWbVse2rW7RgDsyL8ua2vXHw== + +"@sindresorhus/df@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@sindresorhus/df/-/df-3.1.1.tgz#94200f9277e4a7fdd35ce8ab8b6bc5b52b164d31" + integrity sha512-SME/vtXaJcnQ/HpeV6P82Egy+jThn11IKfwW8+/XVoRD0rmPHVTeKMtww1oWdVnMykzVPjmrDN9S8NBndPEHCQ== + dependencies: + execa "^2.0.1" + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -3016,6 +3028,11 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@stroncium/procfs@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@stroncium/procfs/-/procfs-1.2.1.tgz#6b9be6fd20fb0a4c20e99a8695e083c699bb2b45" + integrity sha512-X1Iui3FUNZP18EUvysTHxt+Avu2nlVzyf90YM8OYgP6SGzTzzX/0JgObfO1AQQDzuZtNNz29bVh8h5R97JrjxA== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -3175,6 +3192,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== +"@types/minimist@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + "@types/node@*", "@types/node@>=10.0.0": version "17.0.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" @@ -3589,11 +3611,23 @@ array-includes@^3.1.4: get-intrinsic "^1.1.1" is-string "^1.0.7" +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== + dependencies: + array-uniq "^1.0.1" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + array.prototype.flat@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" @@ -3989,6 +4023,16 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" +camelcase-keys@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252" + integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg== + dependencies: + camelcase "^6.3.0" + map-obj "^4.1.0" + quick-lru "^5.1.1" + type-fest "^1.2.1" + camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" @@ -4004,6 +4048,11 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== +camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30001271, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001370: version "1.0.30001389" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001389.tgz" @@ -4634,6 +4683,11 @@ decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" + integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== + decimal.js@^10.3.1: version "10.4.0" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.0.tgz#97a7448873b01e92e5ff9117d89a7bca8e63e0fe" @@ -4750,6 +4804,13 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dir-glob@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== + dependencies: + path-type "^3.0.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5224,6 +5285,21 @@ eventemitter3@^4.0.0, eventemitter3@^4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +execa@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" + integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^3.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -5640,7 +5716,7 @@ get-port@^5.1.1: resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-stream@^5.1.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== @@ -5758,6 +5834,18 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.2: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^8.0.1: version "8.0.3" resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" @@ -5812,6 +5900,18 @@ globby@^11.0.2: merge2 "^1.3.0" slash "^3.0.0" +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g== + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" @@ -5932,6 +6032,13 @@ hosted-git-info@^4.0.0: dependencies: lru-cache "^6.0.0" +hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + hosted-git-info@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-5.1.0.tgz#9786123f92ef3627f24abc3f15c20d98ec4a6594" @@ -6075,6 +6182,11 @@ ignore-walk@^5.0.1: dependencies: minimatch "^5.0.1" +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + ignore@^5.0.4, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" @@ -6111,6 +6223,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" @@ -6247,7 +6364,7 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" -is-core-module@^2.8.1, is-core-module@^2.9.0: +is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.10.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== @@ -6333,6 +6450,11 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -7586,7 +7708,7 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0, make-dir@^3.0.2: +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -7637,11 +7759,34 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5" integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g== +map-obj@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +meow@10.1.3: + version "10.1.3" + resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.3.tgz#21689959a7d00e8901aff30d208acb2122eb8088" + integrity sha512-0WL7RMCPPdUTE00+GxJjL4d5Dm6eUbmAzxlzywJWiRUKCW093owmZ7/q74tH9VI91vxw9KJJNxAcvdpxb2G4iA== + dependencies: + "@types/minimist" "^1.2.2" + camelcase-keys "^7.0.0" + decamelize "^5.0.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.2" + read-pkg-up "^8.0.0" + redent "^4.0.0" + trim-newlines "^4.0.2" + type-fest "^1.2.2" + yargs-parser "^20.2.9" + meow@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-8.0.0.tgz#1aa10ee61046719e334ffdc038bb5069250ec99a" @@ -7744,12 +7889,12 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== -min-indent@^1.0.0: +min-indent@^1.0.0, min-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.1.2: +"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7891,6 +8036,22 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +mount-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mount-point/-/mount-point-3.0.0.tgz#665cb9edebe80d110e658db56c31d0aef51a8f97" + integrity sha512-jAhfD7ZCG+dbESZjcY1SdFVFqSJkh/yGbdsifHcPkvuLRO5ugK0Ssmd9jdATu29BTd4JiN+vkpMzVvsUgP3SZA== + dependencies: + "@sindresorhus/df" "^1.0.1" + pify "^2.3.0" + pinkie-promise "^2.0.1" + +move-file@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/move-file/-/move-file-2.1.0.tgz#3bec9d34fbe4832df6865f112cda4492b56e8507" + integrity sha512-i9qLW6gqboJ5Ht8bauZi7KlTnQ3QFpBCvMvFfEcHADKgHGeJ9BZMO7SFCTwHPV9Qa0du9DYY1Yx3oqlGt30nXA== + dependencies: + path-exists "^4.0.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -8031,6 +8192,16 @@ normalize-package-data@^3.0.0: semver "^7.3.2" validate-npm-package-license "^3.0.1" +normalize-package-data@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + normalize-package-data@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-4.0.1.tgz#b46b24e0616d06cadf9d5718b29b6d445a82a62c" @@ -8134,6 +8305,13 @@ npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3 npm-package-arg "^9.0.1" proc-log "^2.0.0" +npm-run-path@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -8371,6 +8549,11 @@ ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" @@ -8388,6 +8571,11 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -8716,7 +8904,7 @@ pify@^5.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== -pinkie-promise@^2.0.0: +pinkie-promise@^2.0.0, pinkie-promise@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= @@ -8934,6 +9122,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + range-parser@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -9002,6 +9195,15 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" +read-pkg-up@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670" + integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ== + dependencies: + find-up "^5.0.0" + read-pkg "^6.0.0" + type-fest "^1.0.1" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -9030,6 +9232,16 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +read-pkg@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c" + integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^3.0.2" + parse-json "^5.2.0" + type-fest "^1.0.1" + read@1, read@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -9084,6 +9296,14 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9" + integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag== + dependencies: + indent-string "^5.0.0" + strip-indent "^4.0.0" + regenerate-unicode-properties@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" @@ -9451,6 +9671,11 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -9800,6 +10025,13 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" + integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== + dependencies: + min-indent "^1.0.1" + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -10021,6 +10253,20 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= +trash@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/trash/-/trash-7.2.0.tgz#c5ad0c9b13d7e7cad0b4187b3cfe38cd8b39abe2" + integrity sha512-3bR8Z5aWO8b9qybS6skBoaavH/hX9Onb1RrdIIhJxv9VpH3aBtpbKuAX4rIh/0xpDZ7K4ga36wONk/okbhjTlA== + dependencies: + "@stroncium/procfs" "^1.2.1" + globby "^7.1.1" + is-path-inside "^3.0.2" + make-dir "^3.1.0" + move-file "^2.0.0" + p-map "^4.0.0" + uuid "^8.3.2" + xdg-trashdir "^3.1.0" + treeverse@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" @@ -10031,6 +10277,11 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +trim-newlines@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.0.2.tgz#d6aaaf6a0df1b4b536d183879a6b939489808c7c" + integrity sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew== + ts-node@^10.8.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -10136,6 +10387,11 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== + type-is@~1.6.17: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -10286,6 +10542,13 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + integrity sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ== + dependencies: + os-homedir "^1.0.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -10586,6 +10849,21 @@ ws@~8.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xdg-trashdir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/xdg-trashdir/-/xdg-trashdir-3.1.0.tgz#7294262d5793eb5488c2f529fba883ec32a24ea0" + integrity sha512-N1XQngeqMBoj9wM4ZFadVV2MymImeiFfYD+fJrNlcVcOHsJFFQe7n3b+aBoTPwARuq2HQxukfzVpQmAk1gN4sQ== + dependencies: + "@sindresorhus/df" "^3.1.1" + mount-point "^3.0.0" + user-home "^2.0.0" + xdg-basedir "^4.0.0" + xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" @@ -10662,6 +10940,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== +yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.0.0: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"