transfigure-json

    1.1.0 • Public • Published

    Transfigure-JSON

    NPM

    Transfigure-JSON is a data transformation library that provides JSON compatible data a fluent interface for a chainable, Array-like API.
    Report Bug · Request Feature . Documentation

    Installation

    From NPM

    npm install transfigure-json

    From CDN

    <script src="https://cdn.jsdelivr.net/npm/transfigure-json"></script>

    Usage

    Reddit Comments

    Imagine your project needs to extract the text & scores from reddit comments. Comment pages are arbitrarily nested arrays of objects of arrays of objects which can require dozens of lines of looping & null checking to extract the necessary data.

    Transfigure-JSON does that work with a few chained methods.

    fetch(`${REDDIT_COMMENTS_URL}.json`)
      .then((r) => r.json())
      .then((json) => {
        const rows = new Transfigurator(json)
          .prune(({ key }) => "author score created body".includes(key)) // 1
          .fold((acc, { path, key, value }) => {
            // 2
            const root = path
              .slice(0, -1) // 3
              .join("/"); // 4
            return acc.set(`${root}.${key}`, value); // 5
          }, new Transfigurator({}))
          .toggle() // 6
          .get() // 7
          .map(([key, values]) => values); // 8
    
        console.table(rows);
      })
      .catch(console.error);
    1. Prunes the comment tree for the specified keys. Keep in mind that just like an Array.filter.reduce chain, the pruning for Doc.prune.fold can be done entirely within the fold operation. Separating prune and fold simply makes it easier to swap out operations when changes are required.
    2. Folds the pruned tree into a flattened Object of { ...key: { created, score, body, author } }.
    3. Moves up one from the current path to get the necessary root path (think $ cd ..).
    4. The delimeter is replaced to allow using the whole root path as a single Object key. This prevents the recreation of the original shape by flattening the whole tree (nested.path.to.key becomes nested/path/to.key).
    5. Update and return the accumulator Object {...<path/to/object>: {...<key>: value } }.
    6. Converts the flattened tree into an array of [...[key, { created, score, body, author }]].
    7. Returns the current document.
    8. The current document is easily handled by native array methods.

    Caveats

    Currently, transfigure-json only supports JSON-compatible objects.

    For a refresher, a JSON-compatible object is one of:

    • Booleans
    • Numbers
    • Strings
    • Objects (of valid JSON)
    • Arrays (of valid JSON)
    Documentation
    1. Document Interface
    2. Instantiation
    3. Iterating
    4. JSON Path
    5. Breadth First Stream
    6. Contributing
    7. License
    8. Contact

    Document Interface

    TransfiguratorInterface = {
        clone(Object | Array) => Object | Array,
        schema(Object | Array) => Object | Array
    }
    
    TransfiguratorInstance = Transfigurator(doc: Object | Array, options?: Object)
    InstanceInterface = { get (path?: ValidPath, options?: { useConstructor: false }) => TransfiguratorInstance | Object | Array, set(path: ValidPath, value: any) => TransfiguratorInstance, fold(proc: (accumulator: any, item: StreamItem) => any, accumulator: any) => any, transform(proc: (item: StreamItem) => any) => TransfiguratorInstance, prune(predicate: (item: StreamItem) => boolean) => TransfiguratorInstance, each(proc: (item: StreamItem) => any) => TransfiguratorInstance, select(predicate: (item: StreamItem) => boolean) => StreamItem, smoosh() => TransfiguratorInstance, toggle() => TransfiguratorInstance, toStream() => BFSteamInstance }

    Instantiation

    Options:

    Key ValueType Default Description
    delimeter string "." The delimeter for paths (e.g. 'rootKey.0.aChildKey' or 'rootKey/0/aChildKey').
    useConstructor boolean false Return a Transfigurator instance when retrieving a specifc key instead of the raw value (only for Objects/Arrays).
    /* Commons JS compatible */
    import Transfigurator from "transfigure-json";
    /* Available as Transfigurator when using a script tag */
    
    const test = {
      a: 1,
      b: 2,
      c: 3,
    };
    
    // "new" is optional.
    const docInstance = new Transfigurator(test);
    const docInstance = Transfigurator(test);
    // Use a custom delimeter.
    const docInstance = Transfigurator(test, { delimeter: "***" });

    If passed invalid JSON, JsonData will throw an error. If passed a Number/String/Boolean/null, JsonData will simply return the given argument.

    A document instance wraps the given object. For testing/debugging, consider deep-cloning an object before passing it to the constructor to prevent unwanted mutations.

    • .get
      • Returns the document at the given path. If not path is provided, get returns the full document. If the useConstructor option is set to true, a new TransfiguratorInstance will be returned if the given path points to an Object or Array.
    • .set
      • Mutates the Transfigurator instance at the given path with a value and returns the instance.

    Static methods

    • .clone
      • Performs a deep clone of the given object.
    • .schema
      • Replaces the primitive values of an object with strings denoting the type ("string", "number", "boolean", "null").

    Iterating

    Part of the goal of transfigure-json is to give users an interface comparable to native Array methods, providing a concise, chainable API. Rather than copy Array method names, transfigure-json uses alternates to ensure a user can bounce between transfigure-json and Array methods without confusion.

    Array Transfigure-JSON
    reduce fold
    map transform
    filter prune
    forEach each
    find select

    The callbacks for all iterative instance methods bind the current instance to this.

    • .fold
      • Object keys are assumed to be unordered, which means there is no Array.reduceRight equivalent.
    • .transform
      • Maps a procedure to each value in a doc.
    • .prune
      • "Prunes" a tree returning all values that match the predicate function but maintains the shape of the original document. This may return sparse arrays.
    • .each
      • Applies the given procedure to each value but does not return a result, but instead returns the instance to allow for chaining.
    • .select
      • Returns the first value that matches the predicate or undefined.
    • .smoosh
      • Completely flattens an object to a single of Object of {...string<JFPath>: any }.
    • .toggle
      • Toggles the root object between Object and Array. Toggling Object->Array creates [...[string<key>, any]] and Array->Object creates {...number: any}.
    • .toStream

    JSON Path

    A Path is a convenience wrapper to abstract the swapping of path strings and arrays and path navigation.

    JsonPathInstance = new JsonPath(string | string[], delimeter: string)
    
    ValidPath = JsonPathInstance | string | string[]
    InstanceInterface = { toString() => string toArray() => Array, join(delimiter?: string) => string, clone() => JsonPathInstance, slice(from?: number, to?: number) => JsonPathInstance, append(key: string | number) => JsonPathInstance }
    • .toString
      • Returns the current path array as a string separated by the current delimiter.
    • .toArray
      • Return the current path array.
    • .join
      • With no argument provided, path.join calls path.toString. if a string argument is provided, it will join the current path array by the given string.
    • .clone
      • Creates a clone using the current path array and delimiter.
    • .slice
      • Mimics Array.slice & String.slice. Returns a new path instance based on the selection of from and to.
    • .append
      • Mutates the current instance by appending a key at the end of the current path. Returns the instance.

    Breadth First Stream

    Transfigure-JSON uses a breadth-first stream of primitives under the hood. The algorithm will always emit primitive values instead of their encompassing Objects/Arrays. Array indexes are cast as strings.

    BFStreamInstance = new BFStream(Object | Array, delimeter: string)
    
    StreamItem = ObjectJsonPathInstance, key: string, value: null | boolean | number | string }>
    InstanceInterface = { private setQueue(path: JsonPath, key: string[]) => BFStreamInstance, empty() => boolean, next() => StreamItem }
    • .empty
      • Returns true if the queue is empty.
    • .next
      • Returns the next StreamItem within an object. Returns null when the stream has ended.

    Contributing

    Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

    1. Fork the Project
    2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
    3. Commit your Changes (git commit -m 'Add some AmazingFeature')
    4. Push to the Branch (git push origin feature/AmazingFeature)
    5. Open a Pull Request

    License

    Distributed under the MIT License. See LICENSE for more information.


    Contact

    Project Link: https://github.com/BeAnMo/transfigure-json

    Install

    npm i transfigure-json

    DownloadsWeekly Downloads

    7

    Version

    1.1.0

    License

    ISC

    Unpacked Size

    33.8 kB

    Total Files

    5

    Last publish

    Collaborators

    • bamorin00