Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preserveKeyOrder option #32

Merged
merged 2 commits into from
Dec 4, 2019
Merged

feat: preserveKeyOrder option #32

merged 2 commits into from
Dec 4, 2019

Conversation

P0lip
Copy link
Contributor

@P0lip P0lip commented Nov 29, 2019

@P0lip P0lip added the enhancement New feature or request label Nov 29, 2019
@P0lip P0lip requested a review from marbemac November 29, 2019 13:10
@P0lip P0lip self-assigned this Nov 29, 2019
@@ -514,4 +514,126 @@ european-cities: &cities
expect(result.diagnostics).toEqual([]);
});
});

describe('keys sorting', () => {
it('does not retain the order of keys by default', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a performance thing? Should we retain order of keys by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we retain order of keys by default?

Not sure, probably not? I believe we want to stay close to JSON.parse, don't we?
Either way, this data won't be preserved anyway when the structured copy is performed, so well, Studio won't benefit too much regardless.

Copy link
Contributor

@marbemac marbemac Dec 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does JSON parse not retain key order? If this does not make a meaningful difference on performance, I suggest we do this by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does JSON parse not retain key order?

It does not.

If this does not make a meaningful difference on performance, I suggest we do this by default.

The parsing performance is not affected too much. It's around 25-35% slower, which isn't terrible.
The "trapped" access is slower by quite some marging in certain circumstances. I made a few Object.keys calls on a few properties from HugeYaml fixture, and they took 15-25 times longer.
Object.getOwnPropertyNames and Reflect.ownKeys aren't particularly slower - only 2-4 times. I didn't test Object.getOwnPropertySymbols, since it didn't make any sense.
That said, I guess we can make it disabled by default.

src/__tests__/parseWithPointers.spec.ts Outdated Show resolved Hide resolved
src/__tests__/parseWithPointers.spec.ts Show resolved Hide resolved
// reduceRight is on purpose here! We need to respect the order - the key cannot be overridden..
return items.reduceRight((merged, item) => Object.assign(merged, item), {});
// reduceRight is on purpose here! We need to respect the order - the key cannot be overridden
const reduced = items.reduceRight(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a sense of how this sortKeys option affects performance?

Copy link
Contributor Author

@P0lip P0lip Dec 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check it.
Frankly speaking, though, I didn't expect to use it anywhere else than Spectral CLI, as in every other case the order does not really matter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... I would expect this to be true - xyz === yaml.stringify(yaml.parse(xyz)). Is this not the case right now?

Copy link
Contributor Author

@P0lip P0lip Dec 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xyz === yaml.stringify(yaml.parse(xyz))

This will be true, but Object.keys(yaml.parse(xyz))[0] === Object.keys(yaml.parse(yaml.stringify(yaml.parse(xyz))))[0] won't if such a YAML document is provided

"foo": true
"0": false
Object.keys(xyz)[0] // equals "foo"
Object.keys(yaml.stringify(yaml.parse(xyz)))[0] // equals "0"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xyz is a string right? So Object.keys(xyz) doesn't apply.

If key ordering is not preserved, I don't understand how xyz === yaml.stringify(yaml.parse(xyz)) could be true?

Copy link
Contributor Author

@P0lip P0lip Dec 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I meant to write Object.keys(yaml.parse(xyz))[0] // equals "foo" 😅

If key ordering is not preserved, I don't understand how xyz === yaml.stringify(yaml.parse(xyz)) could be true?

The key ordering should be preservered during stringification, but it won't be upon the second parsing unless preserveOrderKey is passed again.

I screwed the example there. Here is a correct one.

Object.keys(yaml.parse(xyz, { preserveKeyOrder: true }))[0] === Object.keys(yaml.parse(yaml.stringify(yaml.parse(xyz, { preserveKeyOrder: true }))))[0] // false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also add a test if you'd like to

test('preserves the order of keys', () => {
  const xyz = `foo: true
bar: false
"1": false
"0": true
`;

  expect(safeStringify(parseWithPointers(xyz, { preserveKeyOrder: true }).data)).toEqual(
    safeStringify(parseWithPointers(safeStringify(parseWithPointers(xyz, { preserveKeyOrder: true }).data), {
      preserveKeyOrder: true,
    }).data as any),
  ); // this assertion is met

  expect(safeStringify(parseWithPointers(xyz, { preserveKeyOrder: true }).data)).toEqual(
      safeStringify(parseWithPointers(safeStringify(parseWithPointers(xyz, { preserveKeyOrder: true }).data)).data as any),
  ); // this assertion is not met
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right but wouldn't one expect myString === JSON.stringify(JSON.parse(myString)) to be true?

Take Studio for example - if user opens YAML file, we parse it into memory and then stringify and write it back to disk. What it sounds like is that what is written back to disk will not equal what was originally on disk (key ordering not maintained).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take Studio for example - if user opens YAML file, we parse it into memory and then stringify and write it back to disk. What it sounds like is that what is written back to disk will not equal what was originally on disk (key ordering not maintained).

It depends on the value of preserveKeyOrder and the YAML document itself (if it has no numeric scalar mapping keys, everything will be okay).

@P0lip P0lip changed the title feat: sortKeys option feat: preserveKeyOrder option Dec 2, 2019
@P0lip P0lip merged commit d7797f3 into master Dec 4, 2019
@P0lip P0lip deleted the feat/sort-keys branch December 4, 2019 10:54
@stoplight-bot
Copy link
Collaborator

🎉 This PR is included in version 3.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants