UNPKG

@fireenjin/cli

Version:

A set of tools for speeding up production of full-stack Firebase projects.

216 lines (199 loc) 6.9 kB
import connectDatabase from "../firebase/connectDatabase"; const fs = require("fs"); const prettier = require("prettier"); const readline = require("readline"); const yargs = require("yargs").argv; export default async (config: any) => { const db = connectDatabase(); const collectionName = yargs._[1] ? yargs._[1].toLowerCase() : null; const documentId = yargs.id ? yargs.id : yargs._[2] ? yargs._[2] : null; let seedsClonedCount = 0; const overwrite = yargs.o || yargs.overwrite || false; const seedDir = yargs?.dir || `${process.cwd()}/src/seeds`; if (!collectionName && seedDir === `${process.cwd()}/src/seeds`) { console.log("Collection name is required to clone a seed!"); return false; } async function writeData(filename, data) { return new Promise(async (resolve, reject) => { const filenameParts: string[] = filename.split("/"); filenameParts.pop(); const folderPath = filenameParts.join("/"); if (!fs.existsSync(folderPath)) { fs.mkdirSync(folderPath); } fs.writeFile(filename, data, { flag: "wx" }, function (err: any) { if (err) { if (err.code === "EEXIST") { if (documentId && !overwrite) { console.error("File " + filename + " already exists!"); const rl = readline.createInterface( process.stdin, process.stdout ); rl.question("Overwrite? [yes]/no: ", function (answer) { if (answer === "no") { console.log("Not overwritting " + filename); rl.close(); reject({ message: "Not overwritting" }); } else { console.log("Overwriting " + filename); fs.writeFile(filename, data); rl.close(); resolve({ filename }); } }); } else { fs.writeFileSync(filename, data); resolve({ filename }); } } else { reject(err); } } else { resolve({ filename }); } }); }); } async function getDocument() { const documentRef = db.collection(collectionName).doc(documentId); const document = await documentRef.get(); if (!document.exists) { console.log( `No document matching this path: ${collectionName}/${documentId}` ); return false; } return document.data(); } async function checkForReferences(object: any) { const data = object; for (const key of Object.keys(object)) { const value = object[key]; if (value && value.constructor && value.constructor.name === "Object") { await checkForReferences(value); } else if ( value && value.constructor && value.constructor.name === "DocumentReference" ) { data[ key ] = `<@db.collection('${data[key]._path.segments[0]}').doc('${data[key]._path.segments[1]}')@> as any`; } else if ( value && value.constructor && value.constructor.name === "Timestamp" ) { data[ key ] = `<@admin.firestore.Timestamp.fromDate(new Date('${value.toDate()}'))@> as any`; } else if ( value && value.constructor && value.constructor.name === "Array" ) { const cleanArray: any[] = []; for (const item of data[key]) { cleanArray.push(await checkForReferences(item)); } data[key] = cleanArray; } } return data; } async function renderSeed(location, seedContent) { return new Promise(async (resolve, reject) => { fs.readFile( `${process.cwd()}/templates/seed.hbs`, "utf8", async (customErr, customData) => { if (customErr) { fs.readFile( `${__dirname}/../../templates/seed.hbs`, "utf8", async (err, data) => { if (err) { console.log(err); reject(err); } try { await writeData( location, await prettier.format( data .replace( /{{modelName}}/g, collectionName.charAt(0).toUpperCase() + collectionName.substring( 1, collectionName.length - 1 ) ) .replace(/{{data}}/g, seedContent) ) ); seedsClonedCount++; resolve(data); } catch (err) { reject(err); } } ); } else { try { await writeData( location, await prettier.format( customData .replace( /{{modelName}}/g, collectionName.charAt(0).toUpperCase() + collectionName.substring(1, collectionName.length - 1) ) .replace(/{{data}}/g, seedContent) ) ); seedsClonedCount++; resolve(customData); } catch (err) { reject(err); } } } ); }); } async function getCollection() { const collectionRef = await db.collection(collectionName).get(); if (!collectionRef.docs) { console.log( `No document matching this path: ${collectionName}/${documentId}` ); return false; } return collectionRef.docs; } async function createSeedWithDocumentData(documentData: any, id?: string) { const cleanData = await checkForReferences(documentData); const seedContent = JSON.stringify(cleanData, null, 2) .replace(/"<@/g, "") .replace(/@> as any"/g, "") .replace(/@>"/g, ""); return await renderSeed( `${seedDir}/${collectionName}/${id ? id : documentId}.ts`, seedContent ); } if (documentId) { const documentData = await getDocument(); await createSeedWithDocumentData(documentData); } else { const collectionData = await getCollection(); for (const document of collectionData || []) { await createSeedWithDocumentData(document.data(), document.id); } } console.log(`${seedsClonedCount} seeds cloned successfully!`); };