From 01ba1a7473d4a9722ec1150756928448f3ea9ccc Mon Sep 17 00:00:00 2001 From: John Peel Date: Sat, 23 Nov 2019 14:27:22 -0500 Subject: [PATCH 1/2] Allow multiple slugs in server route filename Regex for getting parts from a file segement was made non-greedy. Added regex sanitizing to non-dynamic parts of segment. Added a test for the new ability for multiple slugs. --- src/core/create_manifest_data.ts | 13 ++++++------ .../samples/multiple-slugs/[file].[ext].js | 0 test/unit/create_manifest_data/test.ts | 21 +++++++++++++++---- 3 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 test/unit/create_manifest_data/samples/multiple-slugs/[file].[ext].js diff --git a/src/core/create_manifest_data.ts b/src/core/create_manifest_data.ts index 4fce9b2f0..b4c2f9309 100644 --- a/src/core/create_manifest_data.ts +++ b/src/core/create_manifest_data.ts @@ -84,16 +84,16 @@ export default function create_manifest_data(cwd: string, extensions: string = ' ? basename : basename.slice(0, -ext.length); + if (/\]\[/.test(segment)) { + throw new Error(`Invalid route ${file} — parameters must be separated`); + } + const parts = get_parts(segment); const is_index = is_dir ? false : basename.startsWith('index.'); const is_page = component_extensions.indexOf(ext) !== -1; const route_suffix = basename.slice(basename.indexOf('.'), -ext.length); parts.forEach(part => { - if (/\]\[/.test(part.content)) { - throw new Error(`Invalid route ${file} — parameters must be separated`); - } - if (part.qualifier && /[\(\)\?\:]/.test(part.qualifier.slice(1, -1))) { throw new Error(`Invalid route ${file} — cannot use (, ), ? or : in route qualifiers`); } @@ -298,7 +298,7 @@ function comparator( } function get_parts(part: string): Part[] { - return part.split(/\[(.+)\]/) + return part.split(/\[(.+\(.+\)|.+?)\]/) .map((str, i) => { if (!str) return null; const dynamic = i % 2 === 1; @@ -340,7 +340,8 @@ function get_pattern(segments: Part[][], add_trailing_slash: boolean) { .replace(/\?/g, '%3F') .replace(/#/g, '%23') .replace(/%5B/g, '[') - .replace(/%5D/g, ']'); + .replace(/%5D/g, ']') + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }).join(''); }).join('\\/'); diff --git a/test/unit/create_manifest_data/samples/multiple-slugs/[file].[ext].js b/test/unit/create_manifest_data/samples/multiple-slugs/[file].[ext].js new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit/create_manifest_data/test.ts b/test/unit/create_manifest_data/test.ts index 6c3a98dc6..3046bdf02 100644 --- a/test/unit/create_manifest_data/test.ts +++ b/test/unit/create_manifest_data/test.ts @@ -59,14 +59,14 @@ describe('manifest_data', () => { { name: 'route_blog_json', - pattern: /^\/blog.json$/, + pattern: /^\/blog\.json$/, file: 'blog/index.json.js', params: [] }, { name: 'route_blog_$slug_json', - pattern: /^\/blog\/([^\/]+?).json$/, + pattern: /^\/blog\/([^\/]+?)\.json$/, file: 'blog/[slug].json.js', params: ['slug'] } @@ -143,6 +143,19 @@ describe('manifest_data', () => { ]); }); + it('allows mutliple slugs', () => { + const { server_routes } = create_manifest_data(path.join(__dirname, 'samples/multiple-slugs')); + + assert.deepEqual(server_routes, [ + { + name: "route_$file$93_$91ext", + pattern: /^\/([^\/]+?)\.([^\/]+?)$/, + file: "[file].[ext].js", + params: ["file", "ext"] + } + ]); + }); + it('fails on clashes', () => { assert.throws(() => { const { pages } = create_manifest_data(path.join(__dirname, 'samples/clash-pages')); @@ -226,13 +239,13 @@ describe('manifest_data', () => { assert.deepEqual(server_routes, [ { name: 'route_blog_json', - pattern: /^\/blog.json$/, + pattern: /^\/blog\.json$/, file: 'blog/index.json.js', params: [] }, { name: 'route_blog_$slug_json', - pattern: /^\/blog\/([^\/]+?).json$/, + pattern: /^\/blog\/([^\/]+?)\.json$/, file: 'blog/[slug].json.js', params: ['slug'] } From 6f024c3073c1e5b4c5acdd98b3fe2d9038bdbaf9 Mon Sep 17 00:00:00 2001 From: John Peel Date: Sat, 23 Nov 2019 17:00:43 -0500 Subject: [PATCH 2/2] Fixed issue with multiple slugs with nested brackets --- src/core/create_manifest_data.ts | 2 +- .../[file([a-z]+)].[ext([a-z]+)].js | 0 test/unit/create_manifest_data/test.ts | 13 +++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/unit/create_manifest_data/samples/nested-square-brackets/[file([a-z]+)].[ext([a-z]+)].js diff --git a/src/core/create_manifest_data.ts b/src/core/create_manifest_data.ts index b4c2f9309..b33e7a40c 100644 --- a/src/core/create_manifest_data.ts +++ b/src/core/create_manifest_data.ts @@ -298,7 +298,7 @@ function comparator( } function get_parts(part: string): Part[] { - return part.split(/\[(.+\(.+\)|.+?)\]/) + return part.split(/\[(.+?\(.+?\)|.+?)\]/) .map((str, i) => { if (!str) return null; const dynamic = i % 2 === 1; diff --git a/test/unit/create_manifest_data/samples/nested-square-brackets/[file([a-z]+)].[ext([a-z]+)].js b/test/unit/create_manifest_data/samples/nested-square-brackets/[file([a-z]+)].[ext([a-z]+)].js new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit/create_manifest_data/test.ts b/test/unit/create_manifest_data/test.ts index 3046bdf02..804a61be1 100644 --- a/test/unit/create_manifest_data/test.ts +++ b/test/unit/create_manifest_data/test.ts @@ -156,6 +156,19 @@ describe('manifest_data', () => { ]); }); + it('allows mutliple slugs with nested square brackets', () => { + const { server_routes } = create_manifest_data(path.join(__dirname, 'samples/nested-square-brackets')); + + assert.deepEqual(server_routes, [ + { + name: "route_$file_$91ext$40$91a$45z$93$43$41$93", + pattern: /^\/([a-z]+)\.([a-z]+)$/, + file: "[file([a-z]+)].[ext([a-z]+)].js", + params: ["file", "ext"] + } + ]); + }); + it('fails on clashes', () => { assert.throws(() => { const { pages } = create_manifest_data(path.join(__dirname, 'samples/clash-pages'));