You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
7.3 KiB
254 lines
7.3 KiB
import path from 'path';
|
|
import {BLOCK_NAME, getModulePath, getProjectPath, IS_DEV} from "./env.js";
|
|
import config from 'config';
|
|
import {fileURLToPath} from 'url';
|
|
import memFs from 'mem-fs';
|
|
import editor from 'mem-fs-editor';
|
|
import fsExtra from "fs-extra";
|
|
import archiver from "archiver";
|
|
import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js";
|
|
import {buildHubspotEmail} from "./platforms/hubspot/hubspot-email-adapter.js";
|
|
import {buildHubspotPage} from "./platforms/hubspot/hubspot-page-adapter.js";
|
|
import fs from "fs/promises";
|
|
import fetch from "node-fetch";
|
|
import mime from "mime-types";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
export function getConfigs() {
|
|
return {
|
|
isDev: IS_DEV,
|
|
developmentBlockName: BLOCK_NAME,
|
|
modulesPath: getModulePath(),
|
|
projectPath: getProjectPath(),
|
|
};
|
|
}
|
|
|
|
export async function readJSONFile(jsonFile) {
|
|
let data = {};
|
|
|
|
try {
|
|
data = await fsExtra.readJson(jsonFile);
|
|
} catch (e) {
|
|
return {
|
|
error: true, errorMessage: getErrorHtml("JSON Syntax error. Please make sure the dataFile is valid.", e),
|
|
};
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function getErrorHtml(message = '', errorMessage = '') {
|
|
return `<div style="padding: 10px 15px; font-family: Arial, sans-serif">
|
|
<p>${message}</p>
|
|
<pre style="padding: 10px 15px; background-color: #ffd0d0; border: 1px solid red;">${errorMessage}</pre>
|
|
</div>`;
|
|
}
|
|
|
|
export async function getBlockData(jsonFileName = 'default', {projectPath} = {jsonFileName: 'default'}) {
|
|
let data = await readJSONFile(path.join(projectPath, 'data', `${jsonFileName}.json`));
|
|
if (data.error) {
|
|
return data;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) {
|
|
const updatedConfig = Object.assign(JSON.parse(JSON.stringify(config)), // The entire config object.
|
|
{
|
|
projectDir: args.modulesPath, dataFiles: args.dataFiles.map((name) => {
|
|
return {
|
|
name,
|
|
};
|
|
}), remToPx: config.has('remToPx') ? config.get('remToPx') : 16,
|
|
});
|
|
|
|
// Avoid cache conflict on Global Project css/js files.
|
|
if (updatedConfig.project) {
|
|
updatedConfig.project.css = updatedConfig.project.css ? updatedConfig.project.css + '?cache=' + Date.now() : undefined;
|
|
updatedConfig.project.js = updatedConfig.project.js ? updatedConfig.project.js + '?cache=' + Date.now() : undefined;
|
|
}
|
|
|
|
return updatedConfig;
|
|
}
|
|
|
|
export function getBlockName(name = '') {
|
|
if (name.startsWith('@')) {
|
|
name = name.substring(1);
|
|
}
|
|
|
|
const arr = name.split('/');
|
|
|
|
return {
|
|
project: arr[0],
|
|
name: arr[1],
|
|
};
|
|
}
|
|
|
|
export async function createFiles(data, files = [], {pathDist, generatorsPath}) {
|
|
generatorsPath = generatorsPath ?? path.join(__dirname, 'generators/block/templates');
|
|
|
|
const store = memFs.create();
|
|
const filesystem = editor.create(store);
|
|
for (let file of files) {
|
|
const from = typeof file !== 'string' ? `${generatorsPath}/${file.from}` : `${generatorsPath}/${file}`;
|
|
const to = typeof file !== 'string' ? `${pathDist}/${file.to}` : `${pathDist}/${file}`;
|
|
|
|
await filesystem.copyTplAsync(from, to, data);
|
|
}
|
|
|
|
return filesystem.commit(); // Promise
|
|
}
|
|
|
|
export function capitalize(str) {
|
|
if (typeof str !== 'string') {
|
|
return '';
|
|
}
|
|
|
|
return str
|
|
.toLowerCase()
|
|
.split(/[ -_]/g)
|
|
.filter((word) => !!word)
|
|
.map((word) => {
|
|
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
})
|
|
.join(' ');
|
|
}
|
|
|
|
export async function zipProject(srcDir, outputFileName = 'dist.zip') {
|
|
// create a file to stream archive data to.
|
|
const output = await fsExtra.createWriteStream(outputFileName);
|
|
const archive = archiver('zip', {});
|
|
|
|
// listen for all archive data to be written
|
|
// 'close' event is fired only when a file descriptor is involved
|
|
output.on('close', function () {
|
|
console.log(archive.pointer() + ' total bytes');
|
|
console.log('archiver has been finalized and the output file descriptor has closed.');
|
|
});
|
|
|
|
// This event is fired when the data source is drained no matter what was the data source.
|
|
// It is not part of this library but rather from the NodeJS Stream API.
|
|
// @see: https://nodejs.org/api/stream.html#stream_event_end
|
|
output.on('end', function () {
|
|
console.log('Data has been drained');
|
|
});
|
|
|
|
// good practice to catch warnings (ie stat failures and other non-blocking errors)
|
|
archive.on('warning', function (err) {
|
|
if (err.code === 'ENOENT') {
|
|
// log warning
|
|
} else {
|
|
// throw error
|
|
throw err;
|
|
}
|
|
});
|
|
|
|
// good practice to catch this error explicitly
|
|
archive.on('error', function (err) {
|
|
throw err;
|
|
});
|
|
|
|
// pipe archive data to the file
|
|
archive.pipe(output);
|
|
|
|
// append files from a subdirectory, putting its contents at the root of archive
|
|
archive.directory(srcDir, false);
|
|
|
|
// finalize the archive (ie we are done appending files but streams have to finish yet)
|
|
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
|
|
await archive.finalize();
|
|
}
|
|
|
|
export async function buildExportFiles(blockName, platform) {
|
|
if (platform.name.startsWith('wordpress')) {
|
|
await buildWordPress(blockName, {platform: platform.name});
|
|
} else if (platform.name === 'hubspot-email') {
|
|
await buildHubspotEmail(blockName)
|
|
} else if (platform.name === 'hubspot') {
|
|
await buildHubspotPage(blockName)
|
|
}
|
|
}
|
|
|
|
export function removeCommentsFromCss(content) {
|
|
return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, '');
|
|
}
|
|
|
|
export function removeCommentsFromJs(content) {
|
|
return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, '');
|
|
}
|
|
|
|
export async function uploadFile(filePath, uploadUrl, validator) {
|
|
const options = {};
|
|
|
|
const contentType = mime.lookup(filePath);
|
|
if (['text/css', 'application/javascript'].includes(contentType)) {
|
|
options.encoding = 'utf8';
|
|
}
|
|
|
|
let body = await fs.readFile(filePath, options);
|
|
|
|
if (validator) {
|
|
body = validator(body);
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(uploadUrl, {
|
|
method: 'PUT',
|
|
body: body,
|
|
headers: {'Content-Type': contentType}
|
|
});
|
|
|
|
return response.status !== 200;
|
|
} catch (err) {
|
|
console.log(err)
|
|
const fileName = filePath.split('/').pop();
|
|
throw new Error(`Can't upload "${fileName}" file. Server permission error.`);
|
|
}
|
|
}
|
|
|
|
export async function getImagesList(rootFolder, subFolder = '') {
|
|
const imagesPath = path.join(rootFolder, subFolder);
|
|
const images = await fs.readdir(imagesPath);
|
|
const imagesList = [];
|
|
|
|
for (const image of images) {
|
|
const stats = await fs.stat(path.join(imagesPath, image));
|
|
|
|
if (stats.isDirectory()) {
|
|
const subImages = await getImagesList(rootFolder, image);
|
|
imagesList.push(...subImages);
|
|
} else {
|
|
imagesList.push(path.join(subFolder, image));
|
|
}
|
|
}
|
|
|
|
return imagesList;
|
|
}
|
|
|
|
export async function isFileEmpty(filePath, ignoreComments = false) {
|
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
const lines = fileContent.split('\n');
|
|
|
|
for (const line of lines) {
|
|
if (ignoreComments && line.trim().startsWith('//')) {
|
|
continue;
|
|
}
|
|
|
|
if (line.trim().length > 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
export function replaceNames(content, images, uploadedImages) {
|
|
images.forEach((image, index) => {
|
|
content = content.replace(image, uploadedImages[index].fileName);
|
|
});
|
|
|
|
return content;
|
|
}
|
|
|