diff --git a/src/__tests__/trapAccess.spec.ts b/src/__tests__/trapAccess.spec.ts new file mode 100644 index 0000000..b97bcb5 --- /dev/null +++ b/src/__tests__/trapAccess.spec.ts @@ -0,0 +1,13 @@ +import { KEYS, trapAccess } from '../trapAccess'; + +describe('trapAccess', () => { + test('given no KEYS, should use own keys in ownKeys trap', () => { + const obj = trapAccess({ '404': null, '200': null }); + expect(Reflect.ownKeys(obj)).toEqual(['200', '404']); + }); + + test('given KEYS, should use KEYS in ownKeys trap', () => { + const obj = trapAccess({ '404': null, '200': null, [KEYS]: ['404', '200'] }); + expect(Reflect.ownKeys(obj)).toEqual(['404', '200']); + }); +}); diff --git a/src/index.ts b/src/index.ts index 97dbd30..06e6677 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,3 +7,4 @@ export * from './parse'; export * from './parseWithPointers'; export * from './safeStringify'; export * from './types'; +export * from './trapAccess'; diff --git a/src/parseWithPointers.ts b/src/parseWithPointers.ts index 95975ce..cc7eb18 100644 --- a/src/parseWithPointers.ts +++ b/src/parseWithPointers.ts @@ -11,6 +11,7 @@ import { buildJsonPath } from './buildJsonPath'; import { SpecialMappingKeys } from './consts'; import { dereferenceAnchor } from './dereferenceAnchor'; import { lineForPosition } from './lineForPosition'; +import { KEYS, trapAccess } from './trapAccess'; import { IParseOptions, Kind, ScalarType, YAMLMapping, YAMLNode, YamlParserResult, YAMLScalar } from './types'; import { isObject } from './utils'; @@ -48,8 +49,6 @@ export const parseWithPointers = (value: string, options?: IParseOptions): Ya return parsed; }; -const KEYS = Symbol('object_keys'); - export const walkAST = ( node: YAMLNode | null, options: Optional, @@ -221,15 +220,9 @@ const reduceMergeKeys = (items: unknown, preserveKeyOrder: boolean): object | nu return typeof items !== 'object' || items === null ? null : Object(items); }; -const traps = { - ownKeys(target: object) { - return target[KEYS]; - }, -}; - function createMapContainer(preserveKeyOrder: boolean): { [key in PropertyKey]: unknown } { if (preserveKeyOrder) { - const container = new Proxy({}, traps); + const container = trapAccess({}); Reflect.defineProperty(container, KEYS, { value: [], }); diff --git a/src/trapAccess.ts b/src/trapAccess.ts new file mode 100644 index 0000000..5c76a74 --- /dev/null +++ b/src/trapAccess.ts @@ -0,0 +1,9 @@ +export const KEYS = Symbol('object_keys'); + +const traps = { + ownKeys(target: object) { + return KEYS in target ? target[KEYS] : Reflect.ownKeys(target); + }, +}; + +export const trapAccess = (target: T): T => new Proxy(target, traps);