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

Functions for routes #11141

Open
AlexRMU opened this issue Nov 29, 2023 · 4 comments
Open

Functions for routes #11141

AlexRMU opened this issue Nov 29, 2023 · 4 comments

Comments

@AlexRMU
Copy link

AlexRMU commented Nov 29, 2023

Describe the problem

.

Describe the proposed solution

I think it is necessary to add such functions :

Alternatives considered

No response

Importance

nice to have

Additional Information

It is necessary to take into account:

@dimfeld
Copy link
Contributor

dimfeld commented Dec 1, 2023

https://kit.svelte.dev/docs/modules#sveltejs-kit-resolvepath is a step towards the first item on your list.

It's not a complete solution (e.g. no type checking that the route ID actually exists in the current app), but once some of the other issues you linked are done, it should work nicely. I agree that better support for type-safe route url creation would be great.

@AlexRMU
Copy link
Author

AlexRMU commented Dec 2, 2023

I see the solution to this issue like this (excluding #647):

show
/*
/src/types.d.ts
*/
declare global {
    /** absolute path with the base */
    export type Path = string;
    export type PathURL = Path | URL;

    /**
    params generic

    missing parameters cause a type error and are equal to undefined

    if undefined, the argument can be either undefined or missing
    */
    export type ParamsT = Record<string, string | undefined> | undefined;

    /**
    generated-
    */
    export type IDtoParams = {
        "/(main)/user": undefined;
        "/(main)/user/[uuid]": { uuid: string };
    };
    export type DynamicIDtoID = {
        "profile page": "/(main)/user/[uuid]";
    };
    /**
    -generated
    */
    export type ID_Union = keyof IDtoParams;
    export type DynamicID_Union = keyof DynamicIDtoID;
    export type IDtoSymbol = {
        [ID in ID_Union]: PageSymbol<ID>;
    };
    export type DynamicIDtoSymbol = {
        [DynamicID in DynamicID_Union]: DynamicPageSymbol<DynamicIDtoID[DynamicID], DynamicID>;
    };

    /** or is it better to call it a page rune :) ? */
    export type PageSymbol<ID extends ID_Union> = {
        match: (path: PathURL) => boolean;
        stringify: (params: IDtoParams[ID]) => Path;
        parse: (path: PathURL) => Partial<IDtoParams[ID]> | undefined;
        id: ID;
    };
    export type DynamicPageSymbol<
        ID extends ID_Union,
        Description extends string | undefined = undefined,
    > = PageSymbol<ID> & {
        description: Description;
    };
}
declare module "$app/navigation" {
    export const parse_path: parse_path;
    interface parse_path {
        <ID extends ID_Union>(path: PathURL): Parsed<ID> | undefined;
        (path: PathURL): Parsed<ID_Union> | undefined;
    }
    interface Parsed<ID extends ID_Union> {
        id: ID;
        params: Partial<IDtoParams[ID]> | undefined;
    }

    export const id_to_path: id_to_path;
    interface id_to_path {
        <ID extends ID_Union>(id: ID, params: IDtoParams[ID]): Path;
        <Params extends ParamsT>(id: ID_Union, params: Params): Path;
    }

    export const id_from_path: id_from_path;
    interface id_from_path {
        <ID extends ID_Union>(path: PathURL): ID | undefined;
        (path: PathURL): ID_Union | undefined;
    }

    /**
    the symbol map
    it is creating and changing dynamically
    */
    export const id_symbol_map: IDtoSymbol;

    export const create_page_symbol: create_page_symbol;
    interface create_page_symbol {
        <DynamicID extends DynamicID_Union>(description: DynamicID): DynamicIDtoSymbol[DynamicID];
        <NewID extends string>(
            description: NewID,
        ): {
            error: "wait until the types are generated";
        };
    }
}
declare module "$app/stores" {
    /**
    also in the load function
    */
    export const page1: import("svelte/store").Readable<
        import("@sveltejs/kit").Page & {
            /**
            current PageSymbol from the page context
            or undefined from outside the kit
            */
            page_symbol: PageSymbol<any> | undefined;
        }
    >;
}
export {};
/*
/src/lib/index.ts
*/
import { create_page_symbol, parse_path, id_to_path, id_from_path, id_symbol_map } from "$app/navigation";

const all_path_ids = Object.keys(id_symbol_map);
const all_symbols = Object.values(id_symbol_map);

const parsed1 = parse_path("/user/undefined");
parsed1!.id; // "/(main)/user" | "/(main)/user/[uuid]"
parsed1!.params == undefined;
const parsed2 = parse_path<"/(main)/user/[uuid]">("/user/undefined");
parsed2!.id == "/(main)/user/[uuid]";
parsed2!.params!.uuid! == "1234";
const parsed3 = parse_path("");
parsed3 == undefined;

id_to_path("/(main)/user/[uuid]") == "/user/undefined"; // type error
id_to_path("/(main)/user/[uuid]", {}) == "/user/undefined";
id_to_path("/(main)/user/[uuid]", { qwe: "asd" }) == "/user/undefined";
id_to_path("/(main)/user/[uuid]", { uuid: "1234" }) == "/user/1234";

id_from_path("") == undefined;
id_from_path("/user/undefined") == "/(main)/user/[uuid]";
id_from_path("/user/1234") == "/(main)/user/[uuid]";

export const profile_page = create_page_symbol("profile page");

const literal = "profile page";
const profile_page1 = create_page_symbol(literal); // using the literal

const new_symbol = create_page_symbol("new page"); // new symbol, without types

profile_page.description == "profile page";

profile_page.id == "/(main)/user/[uuid]"; // dynamically changing - when you move the +page file, it will become a false

profile_page.match("/user/1234") == true;
profile_page.match("/user/undefined") == true;
profile_page.match("/user") == false;

profile_page.stringify() == "/user/undefined"; // type error
profile_page.stringify({}) == "/user/undefined"; // type error
profile_page.stringify({ uuid: "1234" }) == "/user/1234";

const parsed_params1 = profile_page.parse("");
parsed_params1 == undefined;
const parsed_params2 = profile_page.parse("/user/undefined");
parsed_params2!.uuid == undefined;
const parsed_params3 = profile_page.parse("/user/1234");
parsed_params2!.uuid == "1234";
/*
/src/routes/(main)/user/[uuid]/+page.ts
*/
import { profile_page } from "$lib";
export const symbol = profile_page;
// if the symbol is not used anywhere or has been used several times - a type error and an error will appear during the build
<!-- /src/routes/(main)/user/[uuid]/+page.svelte -->
<script lang="ts">
    import { page1 } from "$app/stores";
    import { profile_page } from "$lib";

    const current_page_symbol1 = $page1.page_symbol;
    profile_page == current_page_symbol1!;
    // or
    if (current_page_symbol1 && current_page_symbol1.id == "/(main)/user/[uuid]") {
        profile_page == current_page_symbol2;
    }
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants