diff --git a/package.json b/package.json index 50ddc82..73db2a6 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "test.watch": "yarn test --watch" }, "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.0", "@stoplight/types": "^11.1.1", "@stoplight/yaml-ast-parser": "0.0.45", "lodash": "^4.17.15" diff --git a/src/parseWithPointers.ts b/src/parseWithPointers.ts index cc7eb18..e092c37 100644 --- a/src/parseWithPointers.ts +++ b/src/parseWithPointers.ts @@ -1,4 +1,5 @@ -import { DiagnosticSeverity, IDiagnostic, Optional } from '@stoplight/types'; +import createOrderedObject, { getOrder } from '@stoplight/ordered-object-literal'; +import { DiagnosticSeverity, Dictionary, IDiagnostic, Optional } from '@stoplight/types'; import { determineScalarType, load as loadAST, @@ -11,7 +12,6 @@ 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'; @@ -88,11 +88,6 @@ export const walkAST = ( // https://yaml.org/type/merge.html merge keys, not a part of YAML spec if (handleMergeKeys && key === SpecialMappingKeys.MergeKey) { const reduced = reduceMergeKeys(walkAST(mapping.value, options, lineMap, diagnostics), preserveKeyOrder); - if (preserveKeyOrder && reduced !== null) { - for (const reducedKey of Object.keys(reduced)) { - pushKey(container, reducedKey); - } - } Object.assign(container, reduced); } else { @@ -104,10 +99,6 @@ export const walkAST = ( } } - if (KEYS in container) { - (container as Partial<{ [KEYS]: Array }>)[KEYS]!.push(KEYS); - } - return container; } case Kind.SEQ: @@ -200,20 +191,19 @@ const reduceMergeKeys = (items: unknown, preserveKeyOrder: boolean): object | nu preserveKeyOrder ? (merged, item) => { const keys = Object.keys(item); + + Object.assign(merged, item); + for (let i = keys.length - 1; i >= 0; i--) { unshiftKey(merged, keys[i]); } - return Object.assign(merged, item); + return merged; } : (merged, item) => Object.assign(merged, item), createMapContainer(preserveKeyOrder), ); - if (preserveKeyOrder) { - reduced[KEYS].push(KEYS); - } - return reduced; } @@ -221,33 +211,26 @@ const reduceMergeKeys = (items: unknown, preserveKeyOrder: boolean): object | nu }; function createMapContainer(preserveKeyOrder: boolean): { [key in PropertyKey]: unknown } { - if (preserveKeyOrder) { - const container = trapAccess({}); - Reflect.defineProperty(container, KEYS, { - value: [], - }); - - return container; - } - - return {}; + return preserveKeyOrder ? createOrderedObject({}) : {}; } -function deleteKey(container: object, key: string) { - const index = key in container ? container[KEYS].indexOf(key) : -1; +function deleteKey(container: Dictionary, key: string) { + if (!(key in container)) return; + const order = getOrder(container)!; + const index = order.indexOf(key); if (index !== -1) { - container[KEYS].splice(index, 1); + order.splice(index, 1); } } -function unshiftKey(container: object, key: string) { +function unshiftKey(container: Dictionary, key: string) { deleteKey(container, key); - container[KEYS].unshift(key); + getOrder(container)!.unshift(key); } -function pushKey(container: object, key: string) { +function pushKey(container: Dictionary, key: string) { deleteKey(container, key); - container[KEYS].push(key); + getOrder(container)!.push(key); } function validateMappingKey( diff --git a/src/trapAccess.ts b/src/trapAccess.ts index 5c76a74..8c3b1f7 100644 --- a/src/trapAccess.ts +++ b/src/trapAccess.ts @@ -1,4 +1,6 @@ -export const KEYS = Symbol('object_keys'); +import { ORDER_KEY_ID } from '@stoplight/ordered-object-literal'; + +export const KEYS = Symbol.for(ORDER_KEY_ID); const traps = { ownKeys(target: object) { diff --git a/yarn.lock b/yarn.lock index 6eae2ae..53e1813 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1518,6 +1518,11 @@ lodash "^4.17.4" read-pkg-up "^6.0.0" +"@stoplight/ordered-object-literal@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.0.tgz#c47523924a5ff573d00a46e231e0060060fdbc6d" + integrity sha512-nnyPqCeWUqBY2hmeF9psftty35anYytP5Gz1iI7qL/hiSb+hkFAV6k6FuLYZZShaQdmHAPsanG3f6rvhA8sOzg== + "@stoplight/scripts@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@stoplight/scripts/-/scripts-3.1.0.tgz#212f183ad2fc941be2c8e79d6abc40bfbb6e1500"