import _locreq from "locreq"; import { exec } from "./utils.js"; const target_locreq = _locreq(process.cwd()); import { promises as fs } from "fs"; import { is, predicates } from "@sealcode/ts-predicates"; import { FormField } from "../forms/fields/field.js"; import { sealiousFieldInfoToFormField } from "../forms/fields/get-field-for-sealious.js"; export type ExtractedFieldInfo = { name: string; type: string; target: string | null; referencing_collection: string | null; referencing_field: string | null; intermediary_field_that_points_there: string | null; is_required: boolean; }; export type ExtractedFieldInfoWithFormField = ExtractedFieldInfo & { form_field: FormField; }; const counter = (function* () { let i = 0; while (true) { yield i++; } })(); const cache = {} as Record< string, Promise | undefined >; export default async function extract_fields_from_collection( collection_name: string ): Promise { if (cache[collection_name]) { return cache[collection_name]; } const extractor_code = `import {default as the_app} from "./app.js"; const c = new the_app({}).collections["${collection_name}"]; const fields = []; for (const field_name in c.fields){ let field = c.fields[field_name]; let type = field.typeName; let target = null; let referencing_collection = null; let referencing_field = null; let intermediary_field_that_points_there = null; let is_required = field.required || false; if(["derived-value", "cached-value", "settable-by", "control-access"].includes(type)){ type = field.virtual_field.typeName; field = field.virtual_field } if(type == "single-reference"){ target = field.target_collection; } if(type == "item-draft"){ target = field.target_collection_name; } if(type == "deep-reverse-single-reference" || type =="reverse-single-reference"){ target = field.target_collection; referencing_collection = field.referencing_collection; referencing_field = field.referencing_field; intermediary_field_that_points_there = field.intermediary_field_that_points_there } fields.push({ name: field_name, type, target, referencing_collection, referencing_field, intermediary_field_that_points_there, is_required }) } console.log(JSON.stringify(fields)); `; const extractor_code_path = target_locreq.resolve( `dist/back/___extract_fields--${counter.next().value || 0}.js` ); await fs.writeFile(extractor_code_path, extractor_code); const result = exec("node", [extractor_code_path]) .then(async ({ stdout }) => { await fs.unlink(extractor_code_path); const ret = JSON.parse(stdout) as unknown; if ( !is( ret, predicates.array( predicates.shape({ name: predicates.string, type: predicates.string, target: predicates.or( predicates.string, predicates.null ), referencing_collection: predicates.or( predicates.string, predicates.null ), referencing_field: predicates.or( predicates.string, predicates.null ), is_required: predicates.boolean, intermediary_field_that_points_there: predicates.or( predicates.string, predicates.null ), }) ) ) ) { throw new Error( "Encountered a problem while extracting the names of fields from collection. Got: " + stdout ); } const result = (await Promise.all( ret.map(async (field_info) => ({ ...field_info, form_field: await sealiousFieldInfoToFormField(field_info), })) )) as ExtractedFieldInfoWithFormField[]; return result; }) .catch((e) => { console.error("ERROR", e); process.exit(1); }); cache[collection_name] = result; return result; }