mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import { createHash } from 'node:crypto';
|
|
import * as fs from 'node:fs';
|
|
import * as path from 'path';
|
|
|
|
import type { Scenario, ScenarioManifest } from '@/types/scenario';
|
|
|
|
export class ScenarioLoader {
|
|
/**
|
|
* Loads all scenarios from the given path
|
|
*/
|
|
loadAll(pathToScenarios: string, filter?: string): Scenario[] {
|
|
pathToScenarios = path.resolve(pathToScenarios);
|
|
const scenarioFolders = fs
|
|
.readdirSync(pathToScenarios, { withFileTypes: true })
|
|
.filter((dirent) => dirent.isDirectory())
|
|
.map((dirent) => dirent.name);
|
|
|
|
const scenarios: Scenario[] = [];
|
|
|
|
for (const folder of scenarioFolders) {
|
|
if (filter && !folder.toLowerCase().includes(filter.toLowerCase())) {
|
|
continue;
|
|
}
|
|
const scenarioPath = path.join(pathToScenarios, folder);
|
|
const manifestFileName = `${folder}.manifest.json`;
|
|
const scenarioManifestPath = path.join(pathToScenarios, folder, manifestFileName);
|
|
if (!fs.existsSync(scenarioManifestPath)) {
|
|
console.warn(`Scenario at ${scenarioPath} is missing the ${manifestFileName} file`);
|
|
continue;
|
|
}
|
|
|
|
// Load the scenario manifest file
|
|
const [scenario, validationErrors] =
|
|
this.loadAndValidateScenarioManifest(scenarioManifestPath);
|
|
if (validationErrors) {
|
|
console.warn(
|
|
`Scenario at ${scenarioPath} has the following validation errors: ${validationErrors.join(', ')}`,
|
|
);
|
|
continue;
|
|
}
|
|
|
|
scenarios.push({
|
|
...scenario,
|
|
id: this.formScenarioId(scenarioPath),
|
|
scenarioDirPath: scenarioPath,
|
|
});
|
|
}
|
|
|
|
return scenarios;
|
|
}
|
|
|
|
private loadAndValidateScenarioManifest(
|
|
scenarioManifestPath: string,
|
|
): [ScenarioManifest, null] | [null, string[]] {
|
|
const [scenario, error] = this.loadScenarioManifest(scenarioManifestPath);
|
|
if (!scenario) {
|
|
return [null, [error]];
|
|
}
|
|
|
|
const validationErrors: string[] = [];
|
|
|
|
if (!scenario.name) {
|
|
validationErrors.push(`Scenario at ${scenarioManifestPath} is missing a name`);
|
|
}
|
|
if (!scenario.description) {
|
|
validationErrors.push(`Scenario at ${scenarioManifestPath} is missing a description`);
|
|
}
|
|
|
|
return validationErrors.length === 0 ? [scenario, null] : [null, validationErrors];
|
|
}
|
|
|
|
private loadScenarioManifest(
|
|
scenarioManifestPath: string,
|
|
): [ScenarioManifest, null] | [null, string] {
|
|
try {
|
|
const scenario = JSON.parse(
|
|
fs.readFileSync(scenarioManifestPath, 'utf8'),
|
|
) as ScenarioManifest;
|
|
|
|
return [scenario, null];
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
return [null, `Failed to parse manifest ${scenarioManifestPath}: ${message}`];
|
|
}
|
|
}
|
|
|
|
private formScenarioId(scenarioPath: string): string {
|
|
return createHash('sha256').update(scenarioPath).digest('hex');
|
|
}
|
|
}
|