diff options
| author | netop://ウィビ <paul@webb.page> | 2026-04-11 14:45:40 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-04-11 14:45:40 -0700 |
| commit | 1aa441fb05917ad75aede548ba3b84fbf36caf64 (patch) | |
| tree | 17b5255575b3858071a8be65cf5930ae434ec68c | |
| -rw-r--r-- | .editorconfig | 21 | ||||
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | README.md | 58 | ||||
| -rw-r--r-- | deno.json | 6 | ||||
| -rw-r--r-- | mod.ts | 52 | ||||
| -rw-r--r-- | test.ts | 44 |
6 files changed, 187 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9976a35 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig configuration for netop://wibby's projects +# http://editorconfig.org + +# Top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file, utf-8 charset +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +# Match diffs, avoid to trim trailing whitespace +[*.{diff,patch}] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e203e2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# OS garbage +.DS_Store +Thumbs.db + +# &c +*.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..5133419 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# @netopwibby/order-object + +Ever get annoyed when your `Object` keys aren't in alphabetical order? No? Just me? + + + +## Installation + +```sh +# deno +deno add jsr:@netopwibby/order-object + +# node +npx jsr add @netopwibby/order-object +``` + + + +## Usage + +```ts +// deno +import { orderObject } from "jsr:@netopwibby/order-object"; + +// node +import { orderObject } from "@netopwibby/order-object"; + +console.log(orderObject({ zebra: "yay", 1: "neo", horse: "neigh" })); +// returns { "1": "neo", horse: "neigh", zebra: "yay" } +``` + + + +### Running Tests + +```sh +# lint all TypeScript files +deno lint + +# type-check file +deno check mod.ts +deno check test.ts + +# run the tests in `test.ts` +deno test +``` + + + +## License + +MIT + + + +## Prior Art + +- [@webb/order-object](https://github.com/NetOpWibby/order-object/tree/node.js): I made this when Node.js was my best friend. Now Deno is my best friend. diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..605e6cd --- /dev/null +++ b/deno.json @@ -0,0 +1,6 @@ +{ + "exports": "./mod.ts", + "license": "MIT", + "name": "@netopwibby/order-object", + "version": "0.1.1" +} @@ -0,0 +1,52 @@ + + + +//// util + +type OrderableValue = string | number | boolean | null | undefined | OrderableObject | OrderableValue[]; + +interface OrderableObject { + [key: string]: OrderableValue; +} + + + +//// export + +/** + * Recursively orders an object's keys and its nested objects alphabetically + * ```ts + * import { orderObject } from "jsr:@netopwibby/order-object"; + * + * console.log(orderObject({ zebra: "yay", 1: "neo", horse: "neigh" })); + * // returns { "1": "neo", horse: "neigh", zebra: "yay" } + * + * @param value - The value to order (object, array, or primitive) + * @returns The ordered value, or the original value if not orderable + */ +export function orderObject<T extends OrderableValue>(value?: T): T | null { + if (value === null || value === undefined) + return null; + + if (Array.isArray(value)) // recursively order array elements + return value.map(item => orderObject(item)) as T; + + if (typeof value !== "object") + return value; + + const sortedKeys = Object.keys(value).sort(); + + // recursively order key values + const orderedObject = sortedKeys.reduce<OrderableObject>((result, key) => { + const currentValue = (value as OrderableObject)[key]; + result[key] = orderObject(currentValue); + + return result; + }, {}); + + // preserve original object's prototype + return Object.setPrototypeOf( + orderedObject, + Object.getPrototypeOf(value) + ) as T; +} @@ -0,0 +1,44 @@ + + + +//// import + +import { assertEquals } from "jsr:@std/assert"; + +//// util + +import { orderObject } from "./mod.ts"; + + + +//// program + +Deno.test("Test orderObject", async(t) => { + await t.step("Returns null when no options are supplied", () => { + assertEquals(orderObject(), null); + }); + + await t.step("Returns empty array when supplied the same", () => { + assertEquals(orderObject([]), []); + }); + + await t.step("Returns empty object when supplied the same", () => { + assertEquals(orderObject({}), {}); + }); + + await t.step("Returns ordered object", () => { + const options = { + zebra: "yay", + 1: "neo", + horse: "neigh" + }; + + const expectedResponse = { + "1": "neo", + horse: "neigh", + zebra: "yay" + }; + + assertEquals(orderObject(options), expectedResponse); + }); +}); |
