From 487ea3a4f19ea8c4d051b47ad253052a3c1d6b54 Mon Sep 17 00:00:00 2001 From: Wilson Gramer <12683684+WilsonGramer@users.noreply.github.com> Date: Fri, 26 Jun 2026 15:18:54 -0400 Subject: [PATCH] Add verification pass for unresolved React components --- src/parser/parser.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/parser/parser.ts b/src/parser/parser.ts index 9dcafb4652..fee6253cd6 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -20,6 +20,14 @@ import { shouldWarnForDefaultSupabaseConfig, } from '../utils/defaultStorageConfig'; +const modules = import.meta.glob( + [ + '../public/**/*.{mjs,js,mts,ts,jsx,tsx}', + '!../public/**/*.spec.{mjs,js,mts,ts,jsx,tsx}', + ], + { eager: false }, // the parser only checks if the path exists +); + const ajv1 = new Ajv({ allowUnionTypes: true }); ajv1.addSchema(globalSchema); const globalValidate = ajv1.getSchema('#/definitions/GlobalConfig')!; @@ -311,6 +319,29 @@ function verifyStudyConfig(studyConfig: StudyConfig, importedLibrariesData: Reco }); }); + // Verify that paths to React components exist under the correct base directory + if (studyConfig.baseComponents != null) { + for (const key of ['baseComponents', 'components'] as const) { + for (const [name, component] of Object.entries(studyConfig[key] ?? {})) { + if ( + 'path' in component + && component.path != null + && component.type === 'react-component' + && !(`../public/${component.path}` in modules) + ) { + errors.push({ + message: 'Unresolved path', + instancePath: `/${key}/${name}/path`, + params: { + action: 'Make sure the React component is in `src/public/`, not `public/`', + }, + category: 'undefined-component', + }); + } + } + } + } + return { errors, warnings }; }