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

First class TypeScript support #655

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/index.es.js

Large diffs are not rendered by default.

1,233 changes: 1,232 additions & 1 deletion dist/index.js

Large diffs are not rendered by default.

1,188 changes: 1,187 additions & 1 deletion dist/index.m.js

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions dist/types/Route.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { NormalizedRouteParams, RouteConfig, RouteDefinition, RouteMatchResult, RouteName } from ".";
/**
* A Laravel route. This class represents one route and its configuration and metadata.
*/
export default class Route<Name extends RouteName> {
readonly name: Name;
readonly definition: RouteDefinition;
readonly config: RouteConfig;
readonly bindings: Record<string, string>;
readonly wheres: any;
/**
* @param name - Route name.
* @param definition - Route definition.
* @param config - Ziggy configuration.
*/
constructor(name: Name, definition: RouteDefinition, config: RouteConfig);
/**
* Get a 'template' of the complete URL for this route.
*
* @example
* https://{team}.ziggy.dev/user/{user}
*
* @return Route template.
*/
get template(): string;
/**
* Get a template of the origin for this route.
*
* @example
* https://{team}.ziggy.dev/
*
* @return Route origin template.
*/
get origin(): string;
/**
* Get an array of objects representing the parameters that this route accepts.
*
* @example
* [{ name: 'team', required: true }, { name: 'user', required: false }]
*
* @return {Array} Parameter segments.
*/
get parameterSegments(): {
name: string;
required: boolean;
}[];
/**
* Get whether this route's template matches the given URL.
*
* @param url - URL to check.
* @return If this route matches, returns the matched parameters.
*/
matchesUrl(url: string): RouteMatchResult | false;
/**
* Hydrate and return a complete URL for this route with the given parameters.
*/
compile(params: NormalizedRouteParams<Name>): string;
}
133 changes: 133 additions & 0 deletions dist/types/Router.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/// <reference types="qs" />
import { Config, NormalizedRouteParams, ParameterValue, RouteDefinition, RouteMatchResult, RouteName, RouteParams, RouteParamsObject } from '.';
import Route from './Route';
declare type _Unresolve = RouteMatchResult & {
name: string;
route: RouteDefinition;
};
declare global {
var Ziggy: Config;
}
/**
* A collection of Laravel routes. This class constitutes Ziggy's main API.
*/
export default class Router<Name extends RouteName> extends String {
private readonly _config;
private readonly _params;
private readonly _route;
/**
* @param name Route name.
* @param params Route parameters.
* @param absolute Whether to include the URL origin.
* @param config Ziggy configuration.
*/
constructor(name?: Name, params?: RouteParams<Name>, absolute?: boolean, config?: Config);
/**
* Get the compiled URL string for the current route and parameters.
*
* @example
* // with 'posts.show' route 'posts/{post}'
* (new Router('posts.show', 1)).toString(); // 'https://ziggy.dev/posts/1'
*
* @return {String}
*/
toString(): string;
/**
* Get the parameters, values, and metadata from the given URL.
*
* @param {String} [url] - The URL to inspect, defaults to the current window URL.
* @return {{ name: string, params: Object, query: Object, route: Route }}
*/
_unresolve(url?: string): _Unresolve;
_currentUrl(): string;
/**
* Get the name of the route matching the current window URL, or, given a route name
* and parameters, check if the current window URL and parameters match that route.
*
* @example
* // at URL https://ziggy.dev/posts/4 with 'posts.show' route 'posts/{post}'
* route().current(); // 'posts.show'
* route().current('posts.index'); // false
* route().current('posts.show'); // true
* route().current('posts.show', { post: 1 }); // false
* route().current('posts.show', { post: 4 }); // true
*
* @param name Route name to check.
* @param params Route parameters.
*/
current<CurrentName extends RouteName = Name>(name?: CurrentName, params?: RouteParams<CurrentName> | null): boolean | string | void;
/**
* Get an object representing the current location (by default this will be
* the JavaScript `window` global if it's available).
*
* @return {Object}
*/
_location(): {
host: string;
pathname: string;
search: string;
};
/**
* Get all parameter values from the current window URL.
*
* @example
* // at URL https://tighten.ziggy.dev/posts/4?lang=en with 'posts.show' route 'posts/{post}' and domain '{team}.ziggy.dev'
* route().params; // { team: 'tighten', post: 4, lang: 'en' }
*
* @return {Object}
*/
get params(): {
[x: string]: string[] | ParameterValue | import("qs").ParsedQs | import("qs").ParsedQs[];
_query?: Record<string, any>;
};
/**
* Check whether the given route exists.
*
* @param {String} name
* @return {Boolean}
*/
has(name: any): boolean;
/**
* Parse Laravel-style route parameters of any type into a normalized object.
*
* @example
* // with route parameter names 'event' and 'venue'
* _parse(1); // { event: 1 }
* _parse({ event: 2, venue: 3 }); // { event: 2, venue: 3 }
* _parse(['Taylor', 'Matt']); // { event: 'Taylor', venue: 'Matt' }
* _parse([4, { uuid: 56789, name: 'Grand Canyon' }]); // { event: 4, venue: 56789 }
*
* @param {(String|Number|Array|Object)} params - Route parameters.
* @param {CurrentName} route - Route instance.
* @return {Object} Normalized complete route parameters.
*/
_parse<CurrentName extends RouteName = Name>(params: ParameterValue | RouteParams<CurrentName>, route: Route<CurrentName>): NormalizedRouteParams<CurrentName>;
/**
* Populate default parameters for the given route.
*
* @example
* // with default parameters { locale: 'en', country: 'US' } and 'posts.show' route '{locale}/posts/{post}'
* defaults(...); // { locale: 'en' }
*
* @param {Name} route
* @return {Object} Default route parameters.
*/
_defaults(route: any): any;
/**
* Substitute Laravel route model bindings in the given parameters.
*
* @example
* _substituteBindings({ post: { id: 4, slug: 'hello-world', title: 'Hello, world!' } }, { bindings: { post: 'slug' } }); // { post: 'hello-world' }
*
* @param params Route parameters.
* @param route Route definition.
* @return Normalized route parameters.
*/
_substituteBindings<CurrentName extends RouteName = Name>(params: RouteParamsObject<CurrentName>, { bindings, parameterSegments }: Route<CurrentName>): NormalizedRouteParams<CurrentName>;
valueOf(): string;
/**
* @deprecated since v1.0, use `has()` instead.
*/
check(name: any): boolean;
}
export {};
7 changes: 7 additions & 0 deletions dist/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Router from "./Router";
import { Config, RouteName, RouteParams } from "./types";
export * from "./types";
export default function route(): Router<never>;
export default function route<T extends RouteName>(name: T, params?: RouteParams<T> | null, absolute?: boolean, config?: Config): string;
export default function route(name: undefined, params: undefined, absolute: boolean): Router<never>;
export default function route(name: undefined, params: undefined, absolute?: boolean, config?: Config): Router<never>;
78 changes: 78 additions & 0 deletions dist/types/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { ParsedQs } from "qs";
/**
* Offers the route lookup to be merged with declarations emitted from ts generator
*/
export interface RouteLookup {
}
declare type _ParameterBindingDefinition = {
name: string;
binding: string;
} | {
name: string;
};
declare type _BindingOrValue<T extends _ParameterBindingDefinition> = T extends {
binding: string;
} ? ParameterBinding<T['binding']> : ParameterValue;
/** Type of the values a parameter can be passed as. */
export declare type ParameterValue = string | number;
/** A parameter as object or primitive */
export declare type ParameterBinding<Name extends string> = {
[K in Name]: ParameterValue;
} | ParameterValue;
/** Ordered array containing the paramters required to hydrate a route */
export declare type RouteParamsArray<Name extends RouteName> = Name extends keyof RouteLookup ? _RouteParamsArray<RouteLookup[Name]> : GenericRouteParamsArray;
declare type _RouteParamsArray<T extends readonly _ParameterBindingDefinition[]> = {
[K in keyof T]: _BindingOrValue<T[K]> | null;
};
/** Object containing the paramters required to hydrate a route. */
export declare type RouteParamsObject<Name extends RouteName> = Name extends keyof RouteLookup ? _RouteParamsObject<RouteLookup[Name]> & QueryObject : GenericRouteParamsObject & QueryObject;
declare type _RouteParamsObject<T extends readonly _ParameterBindingDefinition[]> = {
[Item in T[number] as Item['name']]?: _BindingOrValue<Item> | null;
};
/** Object containing the normalized paramters required to hydrate a route. */
export declare type NormalizedRouteParams<Route extends RouteName> = Route extends keyof RouteLookup ? Record<keyof RouteParamsObject<Route>, ParameterValue> & _NormalizedRouteParams : _NormalizedRouteParams;
export declare type _NormalizedRouteParams = Record<keyof any, ParameterValue> & QueryObject;
export declare type GenericRouteParamsArray = _BindingOrValue<_ParameterBindingDefinition>[];
export declare type GenericRouteParamsObject = QueryObject & Record<keyof any, any>;
export declare type GenericRouteParams = GenericRouteParamsArray | GenericRouteParamsObject | ParameterValue;
export declare type QueryObject = {
_query?: Record<string, any>;
};
/**
* Holds any known route name or an arbitrary string.
*/
export declare type RouteName = keyof RouteLookup | (string & {});
Copy link
Collaborator

Choose a reason for hiding this comment

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

@lmeysel what does & {} do here? If we want to be permissive and allow strings we don't recognize as route names, why not just keyof RouteLookup | string?

Copy link
Author

@lmeysel lmeysel Sep 19, 2023

Choose a reason for hiding this comment

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

Hmm, not sure if this question is answered in the other PR already: You will need string & {} to make (at least VSCode) to allow strings as well as "specific" strings (i.e. literals). If you just do | string, vscode will make no suggestions, and thus you will not get a list of available routes in intellisense.

Essentially one could say: string swallows literals, but string & {} does not

/**
* The parameters type to hydrate a route.
*/
export declare type RouteParams<Name extends RouteName = RouteName> = RouteParamsArray<Name> | RouteParamsObject<Name> | ParameterValue;
/**
* Normalized route parameters
*/
export interface Config {
routes: {
[key: string]: RouteDefinition;
};
url: string;
port: number | null;
location?: Location;
defaults: {
[key: string]: ParameterValue;
};
}
export declare type RouteMethods = "GET" | "HEAD" | "POST" | "PATCH" | "PUT" | "OPTIONS" | "DELETE";
export interface RouteConfig extends Config {
absolute?: boolean;
}
export interface RouteDefinition {
wheres?: any;
bindings?: Record<string, string>;
uri: string;
domain?: string;
methods: RouteMethods[];
}
export interface RouteMatchResult {
params: NormalizedRouteParams<string>;
query: ParsedQs;
}
export {};
18 changes: 18 additions & 0 deletions dist/types/vite-plugin.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Plugin } from 'vite';
export interface ZiggyPluginConfig {
/**
* Issue the command using laravel sail. Use 'auto' to automatically determine if sails is available and running.
*/
sail?: boolean | 'auto';
/**
* Whether to output TS declarations. Use 'only' to emit only declartion and no routes file.
*/
declarations?: boolean | 'only';
/**
* Destination path where ziggy output files should be placed.
*/
destination?: string;
log?: boolean;
delay?: number;
}
export default function ZiggyPlugin(config: ZiggyPluginConfig): Plugin;
3 changes: 3 additions & 0 deletions dist/types/vue.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export declare const ZiggyVue: {
install: (v: any, options: any) => void;
};
Loading
Loading