diff --git a/.changeset/fair-houses-kneel.md b/.changeset/fair-houses-kneel.md new file mode 100644 index 00000000000..4fe7353d149 --- /dev/null +++ b/.changeset/fair-houses-kneel.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed files with names including things like `[...rest]` created using `ui.getAdditionalFiles` being deleted after being written in dev. diff --git a/package.json b/package.json index 418dcd9b877..5d73027a1f3 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "@types/babel__core": "^7.1.16", "@types/jest": "^27.0.2", "@types/node-fetch": "^2.5.12", - "@types/normalize-path": "3.0.0", "@typescript-eslint/eslint-plugin": "^5.2.0", "@typescript-eslint/parser": "^5.2.0", "chalk-cli": "^5.0.0", diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 0e09818416c..690f92d2be4 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -48,6 +48,7 @@ "@keystone-ui/segmented-control": "^5.0.1", "@keystone-ui/toast": "^4.0.4", "@keystone-ui/tooltip": "^4.0.3", + "@nodelib/fs.walk": "^1.2.8", "@preconstruct/next": "^3.0.1", "@prisma/client": "3.3.0", "@prisma/migrate": "3.3.0", @@ -106,7 +107,6 @@ "micro": "^9.3.4", "next": "^12.0.2", "node-fetch": "^2.6.5", - "normalize-path": "^3.0.0", "object-hash": "^2.2.0", "p-limit": "^2.3.0", "pirates": "^4.0.1", diff --git a/packages/keystone/src/admin-ui/system/generateAdminUI.ts b/packages/keystone/src/admin-ui/system/generateAdminUI.ts index a896a8aedff..8ab38076c70 100644 --- a/packages/keystone/src/admin-ui/system/generateAdminUI.ts +++ b/packages/keystone/src/admin-ui/system/generateAdminUI.ts @@ -1,14 +1,16 @@ import Path from 'path'; +import { promisify } from 'util'; import fs from 'fs-extra'; - import fastGlob from 'fast-glob'; import resolve from 'resolve'; import { GraphQLSchema } from 'graphql'; -import normalizePath from 'normalize-path'; +import { walk as _walk } from '@nodelib/fs.walk'; import type { KeystoneConfig, AdminMetaRootVal, AdminFileToWrite } from '../../types'; import { writeAdminFiles } from '../templates'; import { serializePathForImport } from '../utils/serializePathForImport'; +const walk = promisify(_walk); + function getDoesAdminConfigExist() { try { const configPath = Path.join(process.cwd(), 'admin', 'config'); @@ -151,21 +153,21 @@ export const generateAdminUI = async ( // - they won't create pages in Admin UI which is really what this deleting is about avoiding // - we'll remove them when the user restarts the process if (isLiveReload) { - // fast-glob expects unix style paths/globs in ignore so we need to normalize to that - const ignore = adminFiles.map(x => normalizePath(x.outputPath)); - ignore.push('.next'); - ignore.push('next-env.d.ts'); - ignore.push('public'); - ignore.push('pages/api/__keystone_api_build.js'); - for (const filename of uniqueFiles) { - ignore.push(normalizePath(filename)); - } - const filesToDelete = await fastGlob(['**/*'], { - cwd: projectAdminPath, - ignore, - followSymbolicLinks: false, - absolute: true, + const ignoredDirs = new Set(['.next', 'public'].map(x => Path.resolve(projectAdminPath, x))); + const ignoredFiles = new Set( + [ + ...adminFiles.map(x => x.outputPath), + ...uniqueFiles, + 'next-env.d.ts', + 'pages/api/__keystone_api_build.js', + ].map(x => Path.resolve(projectAdminPath, x)) + ); + + const entries = await walk(projectAdminPath, { + deepFilter: entry => !ignoredDirs.has(entry.path), + entryFilter: entry => entry.dirent.isFile() && !ignoredFiles.has(entry.path), }); - await Promise.all(filesToDelete.map(filepath => fs.remove(filepath))); + + await Promise.all(entries.map(entry => fs.remove(entry.path))); } }; diff --git a/tests/admin-ui-tests/live-reloading.test.ts b/tests/admin-ui-tests/live-reloading.test.ts index 16dd335d54f..a76f213fd89 100644 --- a/tests/admin-ui-tests/live-reloading.test.ts +++ b/tests/admin-ui-tests/live-reloading.test.ts @@ -3,6 +3,7 @@ import fs from 'fs/promises'; import { Browser, Page, chromium } from 'playwright'; import { parse, print } from 'graphql'; import { ExecaChildProcess } from 'execa'; +import fetch from 'node-fetch'; import { generalStartKeystone, loadIndex, makeGqlRequest, promiseSignal } from './utils'; const gql = ([content]: TemplateStringsArray) => content; @@ -56,6 +57,12 @@ test('Creating an item with the GraphQL API and navigating to the item page for expect(value).toBe('blah'); }); +test('api routes written with getAdditionalFiles containing [...rest] work', async () => { + expect( + await fetch('http://localhost:3000/api/blah/asdasdas/das/da/sdad').then(x => x.text()) + ).toEqual('something'); +}); + test('changing the label of a field updates in the Admin UI', async () => { await replaceSchema('second'); diff --git a/tests/test-projects/live-reloading/keystone.ts b/tests/test-projects/live-reloading/keystone.ts index 8e86f606688..fc5248eeea7 100644 --- a/tests/test-projects/live-reloading/keystone.ts +++ b/tests/test-projects/live-reloading/keystone.ts @@ -8,4 +8,15 @@ export default config({ }, lists, extendGraphqlSchema, + ui: { + getAdditionalFiles: [ + () => [ + { + mode: 'write', + src: "export default function(req,res) {res.send('something')}", + outputPath: 'pages/api/blah/[...rest].js', + }, + ], + ], + }, }); diff --git a/yarn.lock b/yarn.lock index cdb4ddf85c2..400343b251a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1993,7 +1993,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2952,11 +2952,6 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== -"@types/normalize-path@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/normalize-path/-/normalize-path-3.0.0.tgz#bb5c46cab77b93350b4cf8d7ff1153f47189ae31" - integrity sha512-Nd8y/5t/7CRakPYiyPzr/IAfYusy1FkcZYFEAcoMZkwpJv2n4Wm+olW+e7xBdHEXhOnWdG9ddbar0gqZWS4x5Q== - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"