@vercel/routing-utils
Advanced tools
Comparing version 1.8.3-canary.1 to 1.8.3-canary.2
@@ -6,2 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const url_1 = require("url"); | ||
__export(require("./schemas")); | ||
@@ -39,26 +40,18 @@ const superstatic_1 = require("./superstatic"); | ||
const errors = []; | ||
// We don't want to treat the input routes as references | ||
inputRoutes.forEach(r => routes.push(Object.assign({}, r))); | ||
for (const route of routes) { | ||
inputRoutes.forEach((r, i) => { | ||
const route = { ...r }; | ||
routes.push(route); | ||
const keys = Object.keys(route); | ||
if (isHandler(route)) { | ||
if (Object.keys(route).length !== 1) { | ||
errors.push({ | ||
message: `Cannot have any other keys when handle is used (handle: ${route.handle})`, | ||
handle: route.handle, | ||
}); | ||
} | ||
const { handle } = route; | ||
if (!isValidHandleValue(handle)) { | ||
errors.push({ | ||
message: `This is not a valid handler (handle: ${handle})`, | ||
handle: handle, | ||
}); | ||
continue; | ||
if (keys.length !== 1) { | ||
const unknownProp = keys.find(prop => prop !== 'handle'); | ||
errors.push(`Route at index ${i} has unknown property \`${unknownProp}\`.`); | ||
} | ||
if (handling.includes(handle)) { | ||
errors.push({ | ||
message: `You can only handle something once (handle: ${handle})`, | ||
handle: handle, | ||
}); | ||
else if (!isValidHandleValue(handle)) { | ||
errors.push(`Route at index ${i} has unknown handle value \`handle: ${handle}\`.`); | ||
} | ||
else if (handling.includes(handle)) { | ||
errors.push(`Route at index ${i} is a duplicate. Please use one \`handle: ${handle}\` at most.`); | ||
} | ||
else { | ||
@@ -79,3 +72,3 @@ handling.push(handle); | ||
route.src = route.src.replace(/\\\//g, '/'); | ||
const regError = checkRegexSyntax(route.src); | ||
const regError = checkRegexSyntax('Route', i, route.src); | ||
if (regError) { | ||
@@ -88,18 +81,9 @@ errors.push(regError); | ||
if (route.dest) { | ||
errors.push({ | ||
message: `You cannot assign "dest" after "handle: hit"`, | ||
src: route.src, | ||
}); | ||
errors.push(`Route at index ${i} cannot define \`dest\` after \`handle: hit\`.`); | ||
} | ||
if (route.status) { | ||
errors.push({ | ||
message: `You cannot assign "status" after "handle: hit"`, | ||
src: route.src, | ||
}); | ||
errors.push(`Route at index ${i} cannot define \`status\` after \`handle: hit\`.`); | ||
} | ||
if (!route.continue) { | ||
errors.push({ | ||
message: `You must assign "continue: true" after "handle: hit"`, | ||
src: route.src, | ||
}); | ||
errors.push(`Route at index ${i} must define \`continue: true\` after \`handle: hit\`.`); | ||
} | ||
@@ -109,12 +93,6 @@ } | ||
if (route.dest && !route.check) { | ||
errors.push({ | ||
message: `You must assign "check: true" after "handle: miss"`, | ||
src: route.src, | ||
}); | ||
errors.push(`Route at index ${i} must define \`check: true\` after \`handle: miss\`.`); | ||
} | ||
else if (!route.dest && !route.continue) { | ||
errors.push({ | ||
message: `You must assign "continue: true" after "handle: miss"`, | ||
src: route.src, | ||
}); | ||
errors.push(`Route at index ${i} must define \`continue: true\` after \`handle: miss\`.`); | ||
} | ||
@@ -124,27 +102,24 @@ } | ||
else { | ||
errors.push({ | ||
message: 'A route must set either handle or src', | ||
}); | ||
errors.push(`Route at index ${i} must define either \`handle\` or \`src\` property.`); | ||
} | ||
} | ||
const error = createNowError('invalid_routes', 'One or more invalid routes were found', errors); | ||
}); | ||
const error = errors.length > 0 | ||
? createError('invalid_route', errors, 'https://vercel.link/routes-json', 'Learn More') | ||
: null; | ||
return { routes, error }; | ||
} | ||
exports.normalizeRoutes = normalizeRoutes; | ||
function checkRegexSyntax(src) { | ||
function checkRegexSyntax(type, index, src) { | ||
try { | ||
// This feels a bit dangerous if there would be a vulnerability in RegExp. | ||
new RegExp(src); | ||
} | ||
catch (err) { | ||
return { | ||
message: `Invalid regular expression: "${src}"`, | ||
src, | ||
}; | ||
const prop = type === 'Route' ? 'src' : 'source'; | ||
return `${type} at index ${index} has invalid \`${prop}\` regular expression "${src}".`; | ||
} | ||
return null; | ||
} | ||
function checkPatternSyntax({ source, destination, }) { | ||
function checkPatternSyntax(type, index, { source, destination, }) { | ||
let sourceSegments = new Set(); | ||
let destinationSegments = new Set(); | ||
const destinationSegments = new Set(); | ||
try { | ||
@@ -155,15 +130,15 @@ sourceSegments = new Set(superstatic_1.sourceToRegex(source).segments); | ||
return { | ||
message: `Invalid source pattern: "${source}"`, | ||
src: source, | ||
message: `${type} at index ${index} has invalid \`source\` pattern "${source}".`, | ||
link: 'https://vercel.link/invalid-route-source-pattern', | ||
}; | ||
} | ||
if (destination) { | ||
if (destination.startsWith('http://')) { | ||
destination = destination.slice(7); | ||
} | ||
if (destination.startsWith('https://')) { | ||
destination = destination.slice(8); | ||
} | ||
try { | ||
destinationSegments = new Set(superstatic_1.sourceToRegex(destination).segments); | ||
const { hostname, pathname, query } = url_1.parse(destination, true); | ||
superstatic_1.sourceToRegex(hostname || '').segments.forEach(name => destinationSegments.add(name)); | ||
superstatic_1.sourceToRegex(pathname || '').segments.forEach(name => destinationSegments.add(name)); | ||
for (const strOrArray of Object.values(query)) { | ||
const value = Array.isArray(strOrArray) ? strOrArray[0] : strOrArray; | ||
superstatic_1.sourceToRegex(value || '').segments.forEach(name => destinationSegments.add(name)); | ||
} | ||
} | ||
@@ -178,4 +153,4 @@ catch (err) { | ||
return { | ||
message: `Found segment ":${segment}" in "destination" pattern but not in "source" pattern.`, | ||
src: segment, | ||
message: `${type} at index ${index} has segment ":${segment}" in \`destination\` property but not in \`source\` property.`, | ||
link: 'https://vercel.link/invalid-route-destination-segment', | ||
}; | ||
@@ -187,22 +162,25 @@ } | ||
} | ||
function checkRedirect(r) { | ||
function checkRedirect(r, index) { | ||
if (typeof r.permanent !== 'undefined' && | ||
typeof r.statusCode !== 'undefined') { | ||
return { | ||
message: `Redirect "${r.source}" cannot define both "permanent" and "statusCode".`, | ||
src: r.source, | ||
}; | ||
return `Redirect at index ${index} cannot define both \`permanent\` and \`statusCode\` properties.`; | ||
} | ||
return null; | ||
} | ||
function createNowError(code, msg, errors) { | ||
const error = errors.length > 0 | ||
? { | ||
code, | ||
message: `${msg}:\n${errors | ||
.map(item => `- ${item.message}`) | ||
.join('\n')}`, | ||
errors, | ||
} | ||
: null; | ||
function createError(code, errors, link, action) { | ||
let message; | ||
let otherErrors = []; | ||
if (Array.isArray(errors)) { | ||
[message, ...otherErrors] = errors; | ||
} | ||
else { | ||
message = errors; | ||
} | ||
const error = { | ||
code, | ||
message, | ||
link, | ||
action, | ||
otherErrors, | ||
}; | ||
return error; | ||
@@ -216,31 +194,10 @@ } | ||
let { routes = null } = nowConfig; | ||
const errors = []; | ||
if (routes) { | ||
if (typeof cleanUrls !== 'undefined') { | ||
errors.push({ | ||
message: 'Cannot define both `routes` and `cleanUrls`', | ||
}); | ||
} | ||
if (typeof trailingSlash !== 'undefined') { | ||
errors.push({ | ||
message: 'Cannot define both `routes` and `trailingSlash`', | ||
}); | ||
} | ||
if (typeof redirects !== 'undefined') { | ||
errors.push({ | ||
message: 'Cannot define both `routes` and `redirects`', | ||
}); | ||
} | ||
if (typeof headers !== 'undefined') { | ||
errors.push({ | ||
message: 'Cannot define both `routes` and `headers`', | ||
}); | ||
} | ||
if (typeof rewrites !== 'undefined') { | ||
errors.push({ | ||
message: 'Cannot define both `routes` and `rewrites`', | ||
}); | ||
} | ||
if (errors.length > 0) { | ||
const error = createNowError('invalid_keys', 'Cannot mix legacy routes with new keys', errors); | ||
const hasNewProperties = typeof cleanUrls !== 'undefined' || | ||
typeof trailingSlash !== 'undefined' || | ||
typeof redirects !== 'undefined' || | ||
typeof headers !== 'undefined' || | ||
typeof rewrites !== 'undefined'; | ||
if (hasNewProperties) { | ||
const error = createError('invalid_mixed_routes', 'If `rewrites`, `redirects`, `headers`, `cleanUrls` or `trailingSlash` are used, then `routes` cannot be present.', 'https://vercel.link/mix-routing-props', 'Learn More'); | ||
return { routes, error }; | ||
@@ -269,26 +226,26 @@ } | ||
if (typeof redirects !== 'undefined') { | ||
const code = 'invalid_redirects'; | ||
const errorsRegex = redirects | ||
.map(r => checkRegexSyntax(r.source)) | ||
.filter(notEmpty); | ||
if (errorsRegex.length > 0) { | ||
const code = 'invalid_redirect'; | ||
const regexErrorMessage = redirects | ||
.map((r, i) => checkRegexSyntax('Redirect', i, r.source)) | ||
.find(notEmpty); | ||
if (regexErrorMessage) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Redirect `source` contains invalid regex. Read more: https://err.sh/now/invalid-route-source', errorsRegex), | ||
error: createError('invalid_redirect', regexErrorMessage, 'https://vercel.link/invalid-route-source-pattern', 'Learn More'), | ||
}; | ||
} | ||
const errorsPattern = redirects | ||
.map(r => checkPatternSyntax(r)) | ||
.filter(notEmpty); | ||
if (errorsPattern.length > 0) { | ||
const patternError = redirects | ||
.map((r, i) => checkPatternSyntax('Redirect', i, r)) | ||
.find(notEmpty); | ||
if (patternError) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Redirect `source` contains invalid pattern. Read more: https://err.sh/now/invalid-route-source', errorsPattern), | ||
error: createError(code, patternError.message, patternError.link, 'Learn More'), | ||
}; | ||
} | ||
const errorProps = redirects.map(r => checkRedirect(r)).filter(notEmpty); | ||
if (errorProps.length > 0) { | ||
const redirectErrorMessage = redirects.map(checkRedirect).find(notEmpty); | ||
if (redirectErrorMessage) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Invalid redirects', errorProps), | ||
error: createError(code, redirectErrorMessage, 'https://vercel.link/redirects-json', 'Learn More'), | ||
}; | ||
@@ -305,19 +262,19 @@ } | ||
if (typeof headers !== 'undefined') { | ||
const code = 'invalid_headers'; | ||
const errorsRegex = headers | ||
.map(r => checkRegexSyntax(r.source)) | ||
.filter(notEmpty); | ||
if (errorsRegex.length > 0) { | ||
const code = 'invalid_header'; | ||
const regexErrorMessage = headers | ||
.map((r, i) => checkRegexSyntax('Header', i, r.source)) | ||
.find(notEmpty); | ||
if (regexErrorMessage) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Headers `source` contains invalid regex. Read more: https://err.sh/now/invalid-route-source', errorsRegex), | ||
error: createError(code, regexErrorMessage, 'https://vercel.link/invalid-route-source-pattern', 'Learn More'), | ||
}; | ||
} | ||
const errorsPattern = headers | ||
.map(r => checkPatternSyntax(r)) | ||
.filter(notEmpty); | ||
if (errorsPattern.length > 0) { | ||
const patternError = headers | ||
.map((r, i) => checkPatternSyntax('Header', i, r)) | ||
.find(notEmpty); | ||
if (patternError) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Headers `source` contains invalid pattern. Read more: https://err.sh/now/invalid-route-source', errorsPattern), | ||
error: createError(code, patternError.message, patternError.link, 'Learn More'), | ||
}; | ||
@@ -327,3 +284,3 @@ } | ||
if (normalized.error) { | ||
normalized.error.code = 'invalid_headers'; | ||
normalized.error.code = code; | ||
return { routes, error: normalized.error }; | ||
@@ -335,19 +292,19 @@ } | ||
if (typeof rewrites !== 'undefined') { | ||
const code = 'invalid_rewrites'; | ||
const errorsRegex = rewrites | ||
.map(r => checkRegexSyntax(r.source)) | ||
.filter(notEmpty); | ||
if (errorsRegex.length > 0) { | ||
const code = 'invalid_rewrite'; | ||
const regexErrorMessage = rewrites | ||
.map((r, i) => checkRegexSyntax('Rewrite', i, r.source)) | ||
.find(notEmpty); | ||
if (regexErrorMessage) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Rewrites `source` contains invalid regex. Read more: https://err.sh/now/invalid-route-source', errorsRegex), | ||
error: createError(code, regexErrorMessage, 'https://vercel.link/invalid-route-source-pattern', 'Learn More'), | ||
}; | ||
} | ||
const errorsPattern = rewrites | ||
.map(r => checkPatternSyntax(r)) | ||
.filter(notEmpty); | ||
if (errorsPattern.length > 0) { | ||
const patternError = rewrites | ||
.map((r, i) => checkPatternSyntax('Rewrite', i, r)) | ||
.find(notEmpty); | ||
if (patternError) { | ||
return { | ||
routes, | ||
error: createNowError(code, 'Rewrites `source` contains invalid pattern. Read more: https://err.sh/now/invalid-route-source', errorsPattern), | ||
error: createError(code, patternError.message, patternError.link, 'Learn More'), | ||
}; | ||
@@ -354,0 +311,0 @@ } |
import { HandleValue } from './index'; | ||
export declare type NowError = { | ||
export declare type RouteApiError = { | ||
code: string; | ||
message: string; | ||
errors: NowErrorNested[]; | ||
sha?: string; | ||
link?: string; | ||
action?: string; | ||
otherErrors?: string[]; | ||
}; | ||
export declare type NowErrorNested = { | ||
message: string; | ||
src?: string; | ||
handle?: string; | ||
}; | ||
export declare type Source = { | ||
@@ -33,3 +29,3 @@ src: string; | ||
routes: Route[] | null; | ||
error: NowError | null; | ||
error: RouteApiError | null; | ||
}; | ||
@@ -36,0 +32,0 @@ export interface GetRoutesProps { |
{ | ||
"name": "@vercel/routing-utils", | ||
"version": "1.8.3-canary.1", | ||
"version": "1.8.3-canary.2", | ||
"description": "Vercel routing utilities", | ||
@@ -33,3 +33,3 @@ "main": "./dist/index.js", | ||
}, | ||
"gitHead": "081b3fd3db01ad2252036fb3a2503e14868103fe" | ||
"gitHead": "b16f94098af561ab9ea12597fd019a1ac423cc38" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45670
1062