Reconstructing the complete pathway using object identifiers

Imagine I have a set of website routes represented by the object below:

const routes = {
  HOME: "start",
  ACCOUNT: {
    HOME: "account",
    PROFILE: "profile",
    ADDRESSES: {
      HOME: "addresses",
      DETAIL: ":addressId",
    },
  },
  ESHOP: {
    HOME: "eshop",
    INVOICES: "invoices",
    ORDERS: {
      HOME: "orders",
      DETAIL: ":orderId",
    },
  },
  INVENTORY: {
    HOME: "warehouse",
    CATEGORIES: {
      HOME: "categories",
      CATEGORY: {
        HOME: ":categoryId",
        PRODUCTS: {
          HOME: "products",
          PRODUCT: ":productId",
        },
      },
    },
  },
};

I am looking to create a concise and elegant function that can generate the full path from a given path consisting of known object keys, like so:

buildRoute(routes, "routes.ACCOUNT.ADDRESSES.DETAIL")
// should output: "start/account/addresses/:addressId"

or

buildRoute(routes, "routes.INVENTORY.CATEGORIES")
// should output: "start/warehouse/categories"

or

buildRoute(routes, "routes.INVENTORY.CATEGORIES.CATEGORY.PRODUCTS.PRODUCT")
// should output: "start/warehouse/categories/:categoryId/products/:productId"

In this case, "routes" represents the object containing the routes, "HOME" is the fixed key for each path/subpath, and a slash should be included between all subroutes except the last one. I plan to provide the data as strings rather than values when implementing this solution.

If you have any suggestions on how to achieve this with clean and concise code, particularly in TypeScript with defined types, it would be greatly appreciated!

Answer №1

To extract different segments of the provided string and then navigate through the structure step by step, constructing the final output string gradually:

function createPath(node, path) {
    const keys = path.split(".");
    if (keys[0] != "r") throw "path must start with 'r.'";
    let result = "";
    for (const key of keys.slice(1)) {
        if (!Object.hasOwn(node, key)) throw `unknown key '${key}'`;
        result += node.HOME + "/";
        node = node[key];
    }
    return result + (typeof node === "string" ? node : node.HOME);
}

const r = {HOME: "start",ACCOUNT: {HOME: "account",PROFILE: "profile",ADDRESSES: {HOME: "addresses",DETAIL: ":addressId",},},ESHOP: {HOME: "eshop",INVOICES: "invoices",ORDERS: {HOME: "orders",DETAIL: ":orderId",},},INVENTORY: {HOME: "inventory",CATEGORIES: {HOME: "categories",CATEGORY: {HOME: ":categoryId",PRODUCTS: {HOME: "products",PRODUCT: ":productId",},},},},};

console.log(createPath(r, "r.ACCOUNT.ADDRESSES.DETAIL"));
// expected result: "start/account/addresses/:addressId"
console.log(createPath(r, "r.INVENTORY.CATEGORIES"));
// expected result: "start/warehouse/categories"
console.log(createPath(r, "r.INVENTORY.CATEGORIES.CATEGORY.PRODUCTS.PRODUCT"));
// expected result: "start/warehouse/categories/:categoryId/products/:productId"

Answer №2

For a sleek and efficient solution with autocomplete features, consider utilizing the Proxy style, similar to frameworks like tRPC.

type GenerateProxy<T, S extends string> =
  T extends string ? {
    (): `${S}/${T}`
  } : T extends { HOME: infer H extends string } ? {
    [K in keyof T]: GenerateProxy<T[K], `${S}/${H}`>
  } & {
    (): `${S}/${H}`
  } : never

function createProxy<T extends object>(obj: T, path = ''): GenerateProxy<T, ''> {
  return new Proxy(()=>{}, {
    // property getter logic
    get(func, prop) {
      // convert strings into {HOME: string}
      let newObj = typeof obj[prop] === 'string' ? { HOME: obj[prop] } : obj[prop]
      return createProxy(newObj, `${path}/${obj.HOME}`)
    },
    // return final path on function call
    apply() {
      return `${path}/${obj.HOME}`
    }
  }) as any;
}

let address1 = createProxy(r).ACCOUNT.ADDRESSES.DETAIL()
//  ^?
// let address1: "/start/account/addresses/:addressId"
console.log(address1) // prints "/start/account/addresses/:addressId"

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to establish a header in the login route that allows the browser to remember the user's login status?

I have successfully implemented a user login backend and everything seems to be working fine. However, when I try to access a user detail after logging in, I am faced with an authorization issue preventing me from exploring other routes. How can I store th ...

Place the script tags within the div element

After loading a page dynamically, I found that only the contents of the div id="example" were being executed. However, the script tag inside the div was not being executed. I attempted to use eval to solve this issue, but it was unsuccessful. <div id=" ...

How can I specify the array's length when using JSON.stringify in AngularJS?

I am looking to store form values in JSON to send via $http.post. One of the values, rooms, should be an array with a length determined by the selected value from md-select. The value of Adult should be included within each room entry. var data = { rooms: ...

Using lambda expressions to sort through an array of objects in React

My goal is to create a delete button that removes items from a list and updates the state variable accordingly. public OnDeleteClick = (): void => { const selectionCount = this._selection.getSelectedCount(); let newArray = this.state.items; for ...

Get back a variety of substitutions

I have a variety of different text strings that I need to swap out on the client side. For example, let's say I need to replace "Red Apple" with "Orange Orange" and "Sad Cat" with "Happy Dog". I've been working on enhancing this particular ques ...

JavaScript - Toggling checkboxes to either be checked or unchecked with a "check all" option

To create a toggle checkboxes functionality, I am attempting the following: HTML Code: <!-- "Check all" box --> <input type="checkbox" name="check" id="cbx_00_00" onclick="selectbox( this.getAttribute( 'id' ));" /> <!-- the other ...

The PHP on server could not be loaded by Ajax

Trying to establish a PHP connection, encountering an error and seeking assistance. The error message displayed is as follows: { "readyState": 0, "status": 0, "statusText": "NetworkError: Failed to execute 'send' on 'XMLHttpReq ...

Blast information to Observable

To view the code sample, visit the following link: stackblitz In my data service, data is fetched asynchronously from a global object (in the actual project, data is emitted via EventEmitter). The structure of the service is as follows: import { Injectab ...

Exploring the capabilities of AngularJS and Spring Boot in web development

I'm encountering a 404 error when trying to load a file in the ng-view route in AngularJS with Spring. As a newcomer to both technologies, I'm struggling to find a solution. app.js app.config(function($routeProvider) { console $route ...

Load a script in a specific div using React

Can anyone assist me with loading a script onto a specific component in my React application? Here is the script that needs to be loaded at the bottom-most div within my component: <div id="rexxxx"></div> <script> new carouselI ...

Problem with Clerk's authentication() functionality

Currently facing an issue with the Clerk auth() helper (auth() documentation) while working with react and next 13 (app router). When trying to access both userId and user from auth(), const { userId, user } = auth();, it seems that userId contains a val ...

The `encodeAddress()` function in Google Geocode is used to ge

Encountering issues with extracting latitude and longitude values from Google's response. Google is providing XML-like data: "location" : { "lat" : 53.55914120, "lng" : 10.00923520 }, I am trying to parse this using var r = results[0].geome ...

Using AngularJS to Retrieve a Specific DOM Element Using its Unique Identifier

Example Please take a look at this Plunkr example. Requirement I am looking for a way to retrieve an element by its id. The provided code should be capable of applying a CSS class to any existing DOM element within the current view. This functionality ...

How to use mousedown event in Three.js to create line drawings

I've tried multiple approaches to achieve this effect. I'm looking to draw a line on mouse down event, and despite researching various resources, I haven't been able to come up with a solution. Currently, I'm utilizing the RayCaster met ...

Unexpected issue with Ustream JSON API and jQuery

Recently, I attempted to execute the following jQuery code: var query = 'http://api.ustream.tv/json/channel/masaiblog/getValueOf/status?jsonp=?'; $.getJSON(query, function(data) { if (data['results'] == 'live') { ...

Uploading a file to a URL using Node.js

Looking for a way to replicate the functionality of wget --post-file=foo.xpi http://localhost:8888/ in nodejs, while ensuring it's compatible across different platforms. In need of assistance to find a simple method for posting a zip file to a specif ...

Tips for implementing absolute paths and baseUrl in TypeScript compiler

When I bundle a package using tsc, I am getting incorrect output. Here is the structure of my project directory: common └── index.ts types ├── action.ts ├── index.ts └── request.ts utils ├── event.ts ├── index.ts ├─ ...

Adjust the color of radio button text with Jquery

Here is a sample of radio buttons: <input type='radio' name='ans' value='0'> Apple <input type='radio' name='ans' value='1'> Banana <input type='radio' name='ans&apo ...

Having trouble locating the module 'monaco-editor/esm/vs/editor/editor.worker' while using create react app

I am currently facing some challenges running react-monaco-editor in my project despite following the documentation and making necessary adjustments to my files. Below is a snippet of my package.json file: { "name": "chatbot_compiler", "version": "0. ...

Transform an array containing strings into an array containing objects within a JSON property

I have received the following JSON data from an endpoint: { "response": { "lines": [ "[{'line':'3007621h7s2','type':'national'},{'line':'3007663f7s9','type':&apo ...