@toddledev/ssr
Advanced tools
Comparing version 0.0.3-alpha.6 to 0.0.3-alpha.7
@@ -1,2 +0,2 @@ | ||
import type { PageComponent } from '@toddledev/core/dist/component/component.types'; | ||
import type { PageComponent, PageRoute } from '@toddledev/core/dist/component/component.types'; | ||
import { FormulaContext, ToddleServerEnv } from '@toddledev/core/dist/formula/formula'; | ||
@@ -17,2 +17,9 @@ import { ProjectFiles } from '../ssr.types'; | ||
}; | ||
export declare const getServerToddleObject: (files: ProjectFiles) => FormulaContext["toddle"]; | ||
export declare const getDataUrlParameters: ({ route, req, }: { | ||
route: Pick<PageRoute, "path" | "query">; | ||
req: Request; | ||
}) => { | ||
[x: string]: string | null; | ||
}; | ||
export declare const serverEnv: ({ branchName, req, logErrors, }: { | ||
@@ -19,0 +26,0 @@ branchName: string; |
@@ -36,3 +36,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.serverEnv = exports.getPageFormulaContext = void 0; | ||
exports.serverEnv = exports.getDataUrlParameters = exports.getServerToddleObject = exports.getPageFormulaContext = void 0; | ||
const formula_1 = require("@toddledev/core/dist/formula/formula"); | ||
@@ -52,7 +52,3 @@ const formulaTypes_1 = require("@toddledev/core/dist/formula/formulaTypes"); | ||
const env = (0, exports.serverEnv)({ req, branchName, logErrors }); | ||
const { searchParamsWithDefaults, hash, combinedParams, url } = getParameters({ component, req }); | ||
const coreFormulas = Object.fromEntries(Object.entries(libFormulas).map(([name, module]) => [ | ||
'@toddle/' + name, | ||
module.default, | ||
])); | ||
const { searchParamsWithDefaults, hash, combinedParams, url } = getParameters({ route: component.route, req }); | ||
const formulaContext = { | ||
@@ -71,6 +67,3 @@ data: { | ||
// in case of naming collisions | ||
'URL parameters': { | ||
...searchParamsWithDefaults, | ||
...combinedParams, | ||
}, | ||
'URL parameters': (0, exports.getDataUrlParameters)({ route: component.route, req }), | ||
Apis: {}, | ||
@@ -82,18 +75,3 @@ }, | ||
env, | ||
toddle: { | ||
getFormula: (name) => coreFormulas[name], | ||
getCustomFormula: (name, packageName) => { | ||
let formula; | ||
if ((0, util_1.isDefined)(packageName)) { | ||
formula = files.packages?.[packageName]?.formulas?.[name]; | ||
} | ||
else { | ||
formula = files.formulas?.[name]; | ||
} | ||
if (formula && (0, formulaTypes_1.isToddleFormula)(formula)) { | ||
return formula; | ||
} | ||
}, | ||
errors: [], | ||
}, | ||
toddle: (0, exports.getServerToddleObject)(files), | ||
}; | ||
@@ -106,3 +84,37 @@ formulaContext.data.Variables = (0, collections_1.mapValues)(component.variables, ({ initialValue }) => { | ||
exports.getPageFormulaContext = getPageFormulaContext; | ||
const getParameters = ({ component, req, }) => { | ||
const getServerToddleObject = (files) => { | ||
const coreFormulas = Object.fromEntries(Object.entries(libFormulas).map(([name, module]) => [ | ||
'@toddle/' + name, | ||
module.default, | ||
])); | ||
return { | ||
getFormula: (name) => coreFormulas[name], | ||
getCustomFormula: (name, packageName) => { | ||
let formula; | ||
if ((0, util_1.isDefined)(packageName)) { | ||
formula = files.packages?.[packageName]?.formulas?.[name]; | ||
} | ||
else { | ||
formula = files.formulas?.[name]; | ||
} | ||
if (formula && (0, formulaTypes_1.isToddleFormula)(formula)) { | ||
return formula; | ||
} | ||
}, | ||
errors: [], | ||
}; | ||
}; | ||
exports.getServerToddleObject = getServerToddleObject; | ||
const getDataUrlParameters = ({ route, req, }) => { | ||
const { searchParamsWithDefaults, combinedParams } = getParameters({ | ||
route, | ||
req, | ||
}); | ||
return { | ||
...searchParamsWithDefaults, | ||
...combinedParams, | ||
}; | ||
}; | ||
exports.getDataUrlParameters = getDataUrlParameters; | ||
const getParameters = ({ route, req, }) => { | ||
const url = new URL(req.url); | ||
@@ -117,3 +129,3 @@ const searchParams = [ | ||
const pathSegments = (0, routing_1.getPathSegments)(url); | ||
component.route?.path.forEach((p, i) => { | ||
route?.path.forEach((p, i) => { | ||
if (p.type === 'param') { | ||
@@ -132,3 +144,3 @@ if ((0, util_1.isDefined)(pathSegments[i]) && typeof pathSegments[i] === 'string') { | ||
// to avoid undefined values in the runtime | ||
const defaultQueryParams = Object.keys(component.route?.query ?? {}).reduce((params, key) => ({ ...params, [key]: null }), {}); | ||
const defaultQueryParams = Object.keys(route?.query ?? {}).reduce((params, key) => ({ ...params, [key]: null }), {}); | ||
return { | ||
@@ -135,0 +147,0 @@ combinedParams: params, |
@@ -1,3 +0,3 @@ | ||
import { PageComponent } from '@toddledev/core/dist/component/component.types'; | ||
import { ProjectFiles } from '../ssr.types'; | ||
import { PageComponent, PageRoute } from '@toddledev/core/dist/component/component.types'; | ||
import { ProjectFiles, Route } from '../ssr.types'; | ||
export declare const matchPageForUrl: ({ url, components, }: { | ||
@@ -7,3 +7,17 @@ url: URL; | ||
}) => PageComponent | undefined; | ||
export declare const matchRouteForUrl: ({ url, routes, }: { | ||
url: URL; | ||
routes: ProjectFiles["routes"]; | ||
}) => Route | undefined; | ||
export declare const matchRoutes: <T>({ url, entries, getRoute, }: { | ||
url: URL; | ||
entries: T[]; | ||
getRoute: (entry: T) => Pick<PageRoute, "path" | "query">; | ||
}) => T | undefined; | ||
export declare const getRouteDestination: ({ files, req, route, }: { | ||
files: ProjectFiles; | ||
req: Request; | ||
route: Route; | ||
}) => false | URL; | ||
export declare const get404Page: (components: ProjectFiles["components"]) => PageComponent | undefined; | ||
export declare const getPathSegments: (url: URL) => string[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getPathSegments = exports.get404Page = exports.matchPageForUrl = void 0; | ||
exports.getPathSegments = exports.get404Page = exports.getRouteDestination = exports.matchRoutes = exports.matchRouteForUrl = exports.matchPageForUrl = void 0; | ||
const formula_1 = require("@toddledev/core/dist/formula/formula"); | ||
const url_1 = require("@toddledev/core/dist/utils/url"); | ||
const util_1 = require("@toddledev/core/dist/utils/util"); | ||
const matchPageForUrl = ({ url, components, }) => { | ||
const formulaContext_1 = require("../rendering/formulaContext"); | ||
const matchPageForUrl = ({ url, components, }) => (0, exports.matchRoutes)({ | ||
url, | ||
entries: getPages(components), | ||
getRoute: (route) => route.route, | ||
}); | ||
exports.matchPageForUrl = matchPageForUrl; | ||
const matchRouteForUrl = ({ url, routes, }) => (0, exports.matchRoutes)({ | ||
url, | ||
entries: Object.values(routes ?? {}), | ||
getRoute: (route) => route.source, | ||
}); | ||
exports.matchRouteForUrl = matchRouteForUrl; | ||
const matchRoutes = ({ url, entries, getRoute, }) => { | ||
const pathSegments = (0, exports.getPathSegments)(url); | ||
const matches = getPages(components) | ||
.filter((page) => pathSegments.length <= page.route.path.length && | ||
page.route.path.every((segment, index) => segment.type === 'param' || | ||
segment.optional === true || | ||
segment.name === pathSegments[index])) | ||
const matches = Object.values(entries) | ||
.filter((entry) => { | ||
const route = getRoute(entry); | ||
return (pathSegments.length <= route.path.length && | ||
route.path.every((segment, index) => segment.type === 'param' || | ||
segment.optional === true || | ||
segment.name === pathSegments[index])); | ||
}) | ||
.sort((a, b) => { | ||
const routeA = getRoute(a); | ||
const routeB = getRoute(b); | ||
// Prefer shorter routes | ||
const diff = a.route.path.length - b.route.path.length; | ||
const diff = routeA.path.length - routeB.path.length; | ||
if (diff !== 0) { | ||
@@ -21,4 +41,4 @@ return diff; | ||
// We don't need to check if the name matches, since we did that in the filter above | ||
const aScore = a.route.path[i].type === 'static' ? 1 : 0; | ||
const bScore = b.route.path[i].type === 'static' ? 1 : 0; | ||
const aScore = routeA.path[i].type === 'static' ? 1 : 0; | ||
const bScore = routeB.path[i].type === 'static' ? 1 : 0; | ||
if (aScore !== bScore) { | ||
@@ -33,3 +53,18 @@ return bScore - aScore; | ||
}; | ||
exports.matchPageForUrl = matchPageForUrl; | ||
exports.matchRoutes = matchRoutes; | ||
const getRouteDestination = ({ files, req, route, }) => { | ||
return (0, url_1.validateUrl)((0, formula_1.applyFormula)(route.destination.formula, | ||
// destination formulas should only have access to URL parameters from | ||
// the route's source definition. Not from anything else atm. | ||
{ | ||
data: { | ||
'URL parameters': (0, formulaContext_1.getDataUrlParameters)({ | ||
route: route.source, | ||
req, | ||
}), | ||
}, | ||
toddle: (0, formulaContext_1.getServerToddleObject)(files), | ||
})); | ||
}; | ||
exports.getRouteDestination = getRouteDestination; | ||
const get404Page = (components) => getPages(components).find((page) => page.name === '404'); | ||
@@ -36,0 +71,0 @@ exports.get404Page = get404Page; |
@@ -1,2 +0,2 @@ | ||
import type { Component } from '@toddledev/core/dist/component/component.types'; | ||
import type { Component, RouteDeclaration } from '@toddledev/core/dist/component/component.types'; | ||
import type { Formula } from '@toddledev/core/dist/formula/formula'; | ||
@@ -21,2 +21,3 @@ import type { PluginFormula } from '@toddledev/core/dist/formula/formulaTypes'; | ||
formulas?: Record<string, PluginFormula<string>>; | ||
routes?: Record<string, Route>; | ||
config?: { | ||
@@ -50,3 +51,3 @@ theme: OldTheme; | ||
}; | ||
export type PluginAction = { | ||
export interface PluginAction { | ||
name: string; | ||
@@ -62,2 +63,8 @@ description?: string; | ||
exported?: boolean; | ||
}; | ||
} | ||
export interface Route { | ||
source: RouteDeclaration; | ||
destination: { | ||
formula: Formula; | ||
}; | ||
} |
@@ -15,7 +15,7 @@ { | ||
"dependencies": { | ||
"@toddledev/core": "0.0.3-alpha.6", | ||
"@toddledev/core": "0.0.3-alpha.7", | ||
"cookie": "1.0.2", | ||
"xss": "1.0.15" | ||
}, | ||
"version": "0.0.3-alpha.6" | ||
"version": "0.0.3-alpha.7" | ||
} |
@@ -1,2 +0,5 @@ | ||
import type { PageComponent } from '@toddledev/core/dist/component/component.types' | ||
import type { | ||
PageComponent, | ||
PageRoute, | ||
} from '@toddledev/core/dist/component/component.types' | ||
import { | ||
@@ -38,10 +41,4 @@ applyFormula, | ||
const { searchParamsWithDefaults, hash, combinedParams, url } = getParameters( | ||
{ component, req }, | ||
{ route: component.route, req }, | ||
) | ||
const coreFormulas = Object.fromEntries( | ||
Object.entries(libFormulas).map(([name, module]) => [ | ||
'@toddle/' + name, | ||
module.default as any, | ||
]), | ||
) | ||
const formulaContext: FormulaContext & { env: ToddleServerEnv } = { | ||
@@ -60,6 +57,3 @@ data: { | ||
// in case of naming collisions | ||
'URL parameters': { | ||
...searchParamsWithDefaults, | ||
...combinedParams, | ||
} as Record<string, string>, | ||
'URL parameters': getDataUrlParameters({ route: component.route, req }), | ||
Apis: {} as Record<string, any>, | ||
@@ -71,19 +65,3 @@ }, | ||
env, | ||
toddle: { | ||
getFormula: (name: string) => coreFormulas[name], | ||
getCustomFormula: (name: string, packageName: string | undefined) => { | ||
let formula: PluginFormula<string> | undefined | ||
if (isDefined(packageName)) { | ||
formula = files.packages?.[packageName]?.formulas?.[name] | ||
} else { | ||
formula = files.formulas?.[name] | ||
} | ||
if (formula && isToddleFormula(formula)) { | ||
return formula | ||
} | ||
}, | ||
errors: [], | ||
}, | ||
toddle: getServerToddleObject(files), | ||
} | ||
@@ -99,7 +77,52 @@ formulaContext.data.Variables = mapValues( | ||
export const getServerToddleObject = ( | ||
files: ProjectFiles, | ||
): FormulaContext['toddle'] => { | ||
const coreFormulas = Object.fromEntries( | ||
Object.entries(libFormulas).map(([name, module]) => [ | ||
'@toddle/' + name, | ||
module.default as any, | ||
]), | ||
) | ||
return { | ||
getFormula: (name: string) => coreFormulas[name], | ||
getCustomFormula: (name: string, packageName: string | undefined) => { | ||
let formula: PluginFormula<string> | undefined | ||
if (isDefined(packageName)) { | ||
formula = files.packages?.[packageName]?.formulas?.[name] | ||
} else { | ||
formula = files.formulas?.[name] | ||
} | ||
if (formula && isToddleFormula(formula)) { | ||
return formula | ||
} | ||
}, | ||
errors: [], | ||
} | ||
} | ||
export const getDataUrlParameters = ({ | ||
route, | ||
req, | ||
}: { | ||
route: Pick<PageRoute, 'path' | 'query'> | ||
req: Request | ||
}) => { | ||
const { searchParamsWithDefaults, combinedParams } = getParameters({ | ||
route, | ||
req, | ||
}) | ||
return { | ||
...searchParamsWithDefaults, | ||
...combinedParams, | ||
} | ||
} | ||
const getParameters = ({ | ||
component, | ||
route, | ||
req, | ||
}: { | ||
component: PageComponent | ||
route?: Pick<PageRoute, 'path' | 'query'> | ||
req: Request | ||
@@ -122,3 +145,3 @@ }) => { | ||
const pathSegments = getPathSegments(url) | ||
component.route?.path.forEach((p, i) => { | ||
route?.path.forEach((p, i) => { | ||
if (p.type === 'param') { | ||
@@ -137,3 +160,3 @@ if (isDefined(pathSegments[i]) && typeof pathSegments[i] === 'string') { | ||
// to avoid undefined values in the runtime | ||
const defaultQueryParams = Object.keys(component.route?.query ?? {}).reduce< | ||
const defaultQueryParams = Object.keys(route?.query ?? {}).reduce< | ||
Record<string, null> | ||
@@ -140,0 +163,0 @@ >((params, key) => ({ ...params, [key]: null }), {}) |
@@ -1,4 +0,13 @@ | ||
import { PageComponent } from '@toddledev/core/dist/component/component.types' | ||
import { | ||
PageComponent, | ||
PageRoute, | ||
} from '@toddledev/core/dist/component/component.types' | ||
import { applyFormula } from '@toddledev/core/dist/formula/formula' | ||
import { validateUrl } from '@toddledev/core/dist/utils/url' | ||
import { isDefined } from '@toddledev/core/dist/utils/util' | ||
import { ProjectFiles } from '../ssr.types' | ||
import { | ||
getDataUrlParameters, | ||
getServerToddleObject, | ||
} from '../rendering/formulaContext' | ||
import { ProjectFiles, Route } from '../ssr.types' | ||
@@ -11,9 +20,38 @@ export const matchPageForUrl = ({ | ||
components: ProjectFiles['components'] | ||
}): PageComponent | undefined => { | ||
}) => | ||
matchRoutes({ | ||
url, | ||
entries: getPages(components), | ||
getRoute: (route) => route.route, | ||
}) | ||
export const matchRouteForUrl = ({ | ||
url, | ||
routes, | ||
}: { | ||
url: URL | ||
routes: ProjectFiles['routes'] | ||
}) => | ||
matchRoutes({ | ||
url, | ||
entries: Object.values(routes ?? {}), | ||
getRoute: (route) => route.source, | ||
}) | ||
export const matchRoutes = <T>({ | ||
url, | ||
entries, | ||
getRoute, | ||
}: { | ||
url: URL | ||
entries: T[] | ||
getRoute: (entry: T) => Pick<PageRoute, 'path' | 'query'> | ||
}): T | undefined => { | ||
const pathSegments = getPathSegments(url) | ||
const matches = getPages(components) | ||
.filter( | ||
(page) => | ||
pathSegments.length <= page.route.path.length && | ||
page.route.path.every( | ||
const matches = Object.values(entries) | ||
.filter((entry) => { | ||
const route = getRoute(entry) | ||
return ( | ||
pathSegments.length <= route.path.length && | ||
route.path.every( | ||
(segment, index) => | ||
@@ -23,7 +61,10 @@ segment.type === 'param' || | ||
segment.name === pathSegments[index], | ||
), | ||
) | ||
) | ||
) | ||
}) | ||
.sort((a, b) => { | ||
const routeA = getRoute(a) | ||
const routeB = getRoute(b) | ||
// Prefer shorter routes | ||
const diff = a.route.path.length - b.route.path.length | ||
const diff = routeA.path.length - routeB.path.length | ||
if (diff !== 0) { | ||
@@ -35,4 +76,4 @@ return diff | ||
// We don't need to check if the name matches, since we did that in the filter above | ||
const aScore = a.route.path[i].type === 'static' ? 1 : 0 | ||
const bScore = b.route.path[i].type === 'static' ? 1 : 0 | ||
const aScore = routeA.path[i].type === 'static' ? 1 : 0 | ||
const bScore = routeB.path[i].type === 'static' ? 1 : 0 | ||
if (aScore !== bScore) { | ||
@@ -48,2 +89,29 @@ return bScore - aScore | ||
export const getRouteDestination = ({ | ||
files, | ||
req, | ||
route, | ||
}: { | ||
files: ProjectFiles | ||
req: Request | ||
route: Route | ||
}) => { | ||
return validateUrl( | ||
applyFormula( | ||
route.destination.formula, | ||
// destination formulas should only have access to URL parameters from | ||
// the route's source definition. Not from anything else atm. | ||
{ | ||
data: { | ||
'URL parameters': getDataUrlParameters({ | ||
route: route.source, | ||
req, | ||
}), | ||
}, | ||
toddle: getServerToddleObject(files), | ||
} as any, | ||
), | ||
) | ||
} | ||
export const get404Page = (components: ProjectFiles['components']) => | ||
@@ -50,0 +118,0 @@ getPages(components).find((page) => page.name === '404') |
@@ -1,2 +0,5 @@ | ||
import type { Component } from '@toddledev/core/dist/component/component.types' | ||
import type { | ||
Component, | ||
RouteDeclaration, | ||
} from '@toddledev/core/dist/component/component.types' | ||
import type { Formula } from '@toddledev/core/dist/formula/formula' | ||
@@ -22,2 +25,3 @@ import type { PluginFormula } from '@toddledev/core/dist/formula/formulaTypes' | ||
formulas?: Record<string, PluginFormula<string>> | ||
routes?: Record<string, Route> | ||
config?: { | ||
@@ -48,3 +52,3 @@ theme: OldTheme | ||
export type PluginAction = { | ||
export interface PluginAction { | ||
name: string | ||
@@ -62,1 +66,8 @@ description?: string | ||
} | ||
export interface Route { | ||
source: RouteDeclaration | ||
destination: { | ||
formula: Formula | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
183788
3790
+ Added@toddledev/core@0.0.3-alpha.7(transitive)
- Removed@toddledev/core@0.0.3-alpha.6(transitive)