diff --git a/packages/gatsby/src/bootstrap/resolve-module-exports.ts b/packages/gatsby/src/bootstrap/resolve-module-exports.ts index e52b795dd4ee2..eaa010d9f056f 100644 --- a/packages/gatsby/src/bootstrap/resolve-module-exports.ts +++ b/packages/gatsby/src/bootstrap/resolve-module-exports.ts @@ -8,6 +8,7 @@ import { testImportError } from "../utils/test-import-error" import { resolveModule, ModuleResolver } from "../utils/module-resolver" import { maybeAddFileProtocol, resolveJSFilepath } from "./resolve-js-file-path" import { preferDefault } from "./prefer-default" +import { match } from "@reach/router" const staticallyAnalyzeExports = ( modulePath: string, @@ -23,7 +24,7 @@ const staticallyAnalyzeExports = ( } const code = fs.readFileSync(absPath, `utf8`) // get file contents - let ast + let ast: t.File try { ast = babelParseToAst(code, absPath) } catch (err) { @@ -58,7 +59,7 @@ const staticallyAnalyzeExports = ( isES6 = true }, - ExportNamedDeclaration: function ExportNamedDeclaration(astPath) { + ExportNamedDeclaration: function ExportNamedDeclaration(astPath: t.NodePath) { const declaration = astPath.node.declaration // get foo from `export const foo = bar` @@ -82,7 +83,7 @@ const staticallyAnalyzeExports = ( // get foo from `export { foo } from 'bar'` // get foo from `export { foo }` - ExportSpecifier: function ExportSpecifier(astPath) { + ExportSpecifier: function ExportSpecifier(astPath: t.NodePath) { isES6 = true const exp = astPath?.node?.exported if (!exp) { @@ -100,7 +101,7 @@ const staticallyAnalyzeExports = ( // export default function() {} // export default function foo() {} // const foo = () => {}; export default foo - ExportDefaultDeclaration: function ExportDefaultDeclaration(astPath) { + ExportDefaultDeclaration: function ExportDefaultDeclaration(astPath: t.NodePath) { const declaration = astPath.node.declaration if ( !t.isIdentifier(declaration) && @@ -122,7 +123,7 @@ const staticallyAnalyzeExports = ( exportNames.push(exportName) }, - AssignmentExpression: function AssignmentExpression(astPath) { + AssignmentExpression: function AssignmentExpression(astPath: t.NodePath) { const nodeLeft = astPath.node.left if (!t.isMemberExpression(nodeLeft)) { @@ -238,3 +239,38 @@ export async function resolveModuleExports( return [] } +import { match } from "@reach/router" + +export function matchPath(rawPath: string, matchPath?: string): PathMatch { + // Normalize paths + const path = rawPath || `/` + + // First try original path + let result = reachMatch(matchPath || path, { path }) + + // If no match and path has encoded characters + if (!result && path.includes('%')) { + try { + // Try matching decoded path + const decodedPath = decodeURIComponent(path) + result = reachMatch(matchPath || decodedPath, { path: decodedPath }) + + // Handle double-encoded paths + if (!result && decodedPath.includes('%')) { + const doubleDecodedPath = decodeURIComponent(decodedPath) + result = reachMatch(matchPath || doubleDecodedPath, { + path: doubleDecodedPath + }) + } + } catch (e) { + // Silently handle decode errors + } + } + + // Always return valid params object + return { + params: result?.params || {}, + uri: result?.uri || path, + path: result?.path || path + } +} diff --git a/packages/gatsby/src/utils/find-page-by-path.ts b/packages/gatsby/src/utils/find-page-by-path.ts index 76a248d1c6daf..64ad676301d91 100644 --- a/packages/gatsby/src/utils/find-page-by-path.ts +++ b/packages/gatsby/src/utils/find-page-by-path.ts @@ -1,5 +1,5 @@ import { IGatsbyPage, IGatsbyState } from "../redux/types" -import { pick } from "@gatsbyjs/reach-router" +import { pick } from "@reach/router" // Ranks and picks the best page to match. Each segment gets the highest // amount of points, then the type of segment gets an additional amount of