shopify-accelerate
Version:
Shopify Theme development with full Typescript Support
996 lines (878 loc) • 35.5 kB
text/typescript
import chalk from "chalk";
import fs from "fs";
import path from "path";
import { PresetSchema, ShopifySectionPreset } from "../../@types/shopify";
import { config, root_dir } from "../../shopify-accelerate";
import { deleteFile, writeCompareFile, writeOnlyNew } from "../utils/fs";
import { isObject } from "../utils/is-object";
import { JSONParse } from "../utils/json";
import { toCamelCase } from "../utils/to-camel-case";
import { toLocaleFriendlySnakeCase, toSnakeCase } from "../utils/to-snake-case";
import { generateBlockFiles } from "./generate-block-files";
import { generateSectionFiles } from "./generate-section-files";
import { generateSectionPresetFiles } from "./generate-section-preset-files";
import { generateSettingsFile } from "./generate-settings-file";
export const generateLiquidFiles = () => {
const {
theme_path,
folders,
sources,
targets,
delete_external_blocks,
delete_external_layouts,
delete_external_sections,
delete_external_snippets,
disabled_theme_blocks,
} = config;
const translations: any = {};
const snippets = sources.snippets;
const giftCards = sources.giftCards;
const layouts = sources.layouts;
const sectionsSchemas = sources.sectionSchemas;
const sectionPresetSchemas = sources.sectionPresetSchemas;
const blockSchemas = sources.blockSchemas;
generateSettingsFile();
for (const key in sectionsSchemas) {
const schema = sectionsSchemas[key];
const sectionName = `${schema.folder}.liquid`;
const sectionPath = path.join(process.cwd(), theme_path, "sections", sectionName);
if (schema.disabled) {
const targetFile = targets.sections.find(
(target) => target.split(/[\\/]/gi).at(-1) === sectionName
);
if (targetFile) {
config.targets.sections = config.targets.sections.filter((target) => target !== targetFile);
deleteFile(path.join(root_dir, targetFile));
}
const snippetTargets = targets.snippets.filter(
(target) => `${target.split(/[\\/]/gi).at(-1).split(".")[0]}.liquid` === sectionName
);
if (snippetTargets.length) {
config.targets.snippets = config.targets.snippets.filter((target) => {
if (snippetTargets.includes(target)) {
deleteFile(path.join(root_dir, target));
return false;
}
return true;
});
}
continue;
}
schema?.blocks?.forEach((block) => {
if (block.disabled) {
const targetFile = targets.snippets.find(
(target) =>
target.split(/[\\/]/gi).at(-1) ===
`${sectionName.replace(".liquid", "")}.${block.type}.liquid`
);
if (targetFile) {
config.targets.snippets = config.targets.snippets.filter(
(target) => target !== targetFile
);
deleteFile(path.join(root_dir, targetFile));
}
}
});
let translationArray = [];
const rawContent = fs.readFileSync(path.join(folders.sections, schema.folder, sectionName), {
encoding: "utf-8",
});
if (rawContent) {
let translatedContent = rawContent.replace(
/<t(\s+[^>]*)*>((.|\r|\n)*?)<\/t>/gi,
(str, group1, group2) => {
const group = toLocaleFriendlySnakeCase(schema.folder);
const content = toLocaleFriendlySnakeCase(
group2?.split(" ")?.slice(0, 2)?.join("_") ?? ""
).trim();
const backupContent = toLocaleFriendlySnakeCase(group2).trim();
const id = toLocaleFriendlySnakeCase(group1?.replace(/id="(.*)"/gi, "$1") ?? "").trim();
if (!(group in translations)) {
translations[group] = {};
}
if (id && !(id in translations[group])) {
translations[group][id] = group2;
return `{{ "${group}.${id}" | t }}`;
}
if (!(content in translations[group])) {
translations[group][content] = group2;
return `{{ "${group}.${content}" | t }}`;
}
if (translations[group][content] !== group2) {
if (!(backupContent in translations[group])) {
translations[group][backupContent] = group2;
return `{{ "${group}.${backupContent}" | t }}`;
}
if (translations[group][backupContent] !== group2) {
translations[group][`${content}_2`] = group2;
return `{{ "${group}.${content}_2" | t }}`;
}
}
if (translations[group][content] === group2) {
return `{{ "${group}.${content}" | t }}`;
}
return group2;
}
);
if (disabled_theme_blocks) {
translatedContent = translatedContent?.replace(
/\n(\s*){%-?\s*content_for\s*['"]blocks["']\s*-?%}/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}{% liquid`];
arr.push(`${match} for block in section.blocks`);
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match} endfor`);
arr.push(`${match}%}`);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*)content_for\s*['"]blocks["']\s*\n/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}`];
arr.push(`${match}for block in section.blocks`);
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match}endfor`);
arr.push(``);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*){%-?\s*content_for\s*['"]block["']\s*-?%}/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}{% liquid`];
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match}%}`);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*)content_for\s*['"]block["']\s*\n/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}`];
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match}if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match}endif`);
}
arr.push(``);
return arr.join("\n");
}
);
}
translationArray.push(translatedContent);
}
const snippetPath = path.join(process.cwd(), theme_path, "snippets", sectionName);
if (config.ignore_snippets?.includes(snippetPath.split(/[/\\]/)?.at(-1))) {
console.log(
`[${chalk.gray(new Date().toLocaleTimeString())}]: ${chalk.greenBright(
`Ignored: ${snippetPath.replace(process.cwd(), "")}`
)}`
);
writeOnlyNew(snippetPath, translationArray.join("\n"));
} else {
writeCompareFile(snippetPath, translationArray.join("\n"));
}
snippets.push(snippetPath);
translationArray = [`{%- render "${schema.folder}" -%}`];
translationArray.push(generateSectionFiles(schema));
if (config.ignore_sections?.includes(sectionPath.split(/[/\\]/)?.at(-1))) {
console.log(
`[${chalk.gray(new Date().toLocaleTimeString())}]: ${chalk.greenBright(
`Ignored: ${sectionPath.replace(process.cwd(), "")}`
)}`
);
writeOnlyNew(sectionPath, translationArray.join("\n"));
} else {
writeCompareFile(sectionPath, translationArray.join("\n"));
}
}
for (const key in sectionPresetSchemas) {
const presets =
sectionPresetSchemas[key]?.presets
?.filter(
(preset) =>
config.all_presets ||
!preset.enabled_on ||
preset.enabled_on?.includes(process.env.SHOPIFY_ACCELERATE_STORE)
)
?.map((preset, index, arr) => {
let currentPreset = {
name:
arr?.length === 1
? sectionPresetSchemas[key]?.name
: preset.enabled_on &&
!preset.enabled_on?.includes(process.env.SHOPIFY_ACCELERATE_STORE)
? `${sectionPresetSchemas[key]?.name} - ${
index + 1
}` /*`${sectionPresetSchemas[key]?.name} - ${preset.enabled_on?.[0]}`*/
: `${sectionPresetSchemas[key]?.name} - ${index + 1}`,
settings: preset?.settings,
blocks: Array.isArray(preset?.blocks)
? preset?.blocks
: Object.values(preset?.blocks ?? {}) ?? [],
} as unknown as ShopifySectionPreset;
if (
preset.enabled_on &&
!preset.enabled_on?.includes(process.env.SHOPIFY_ACCELERATE_STORE)
) {
const matchList = {
content_class: ["richtext-md"],
button_class: [
"button-primary",
"button-tabs",
"button-secondary",
"button-primary-outline",
],
scrollbar_class: ["scrollbar-no-buttons", "scrollbar"],
article_card_class: ["article-card"],
title_class: ["richtext-md"],
product_card_class: ["product-card", "product-card-flat"],
select_class: ["input-select"],
subscription_label_class: ["label-primary"],
legend_class: ["richtext-md"],
savings_highlight_class: ["richtext-md"],
label_class: ["richtext-md"],
price_class: ["richtext-md"],
incomplete_button_class: [
"button-primary",
"button-tabs",
"button-secondary",
"button-primary-outline",
],
collection_card_class: ["collection-card"],
input_class: ["input-text", "input-text-inline"],
accordion_class: ["accordion"],
text_over_image_class: ["richtext-md"],
link_class: ["richtext-md"],
color_scheme: ["color_scheme_1"],
};
let string_content = JSON.stringify(currentPreset, null, 2);
for (const key in matchList) {
const regexp = new RegExp(`("${key}": )"([^"]*)"`, "gi");
string_content = string_content.replace(regexp, (totalMatch, _1, _2) => {
const value = _2;
const isValid = matchList[key].some(
(className) =>
new RegExp(`^${className}$`, "gi").test(value) ||
new RegExp(` ${className}$`, "gi").test(value) ||
new RegExp(`^${className} `, "gi").test(value) ||
new RegExp(` ${className} `, "gi").test(value)
);
if (!isValid) {
return `${_1}"${matchList[key][0]}"`;
}
return `${_1}"${value}"`;
});
}
currentPreset = JSONParse(string_content) || currentPreset;
}
return currentPreset;
}) ?? [];
if (!presets?.length) {
const targetFile = targets.sections.find(
(target) => target.split(/[\\/]/gi).at(-1) === `preset__${toSnakeCase(key)}.liquid`
);
if (targetFile) {
config.targets.sections = config.targets.sections.filter((target) => target !== targetFile);
deleteFile(path.join(root_dir, targetFile));
}
continue;
}
const schema = Object.values(sectionsSchemas)?.find(
(val) => val.folder === sectionPresetSchemas[key]?.type
);
if (!schema) {
continue;
}
const translationArray = [`{%- render "${schema.folder}" -%}`];
translationArray.push(
generateSectionPresetFiles({ schema, preset_name: sectionPresetSchemas[key].name, presets })
);
const sectionName = `preset__${toSnakeCase(key)}.liquid`;
const sectionPath = path.join(process.cwd(), theme_path, "sections", sectionName);
writeCompareFile(sectionPath, translationArray.join("\n"));
}
for (const key in blockSchemas) {
const schema = blockSchemas[key];
const sectionName = `${schema.folder}.liquid`;
const blockPath = disabled_theme_blocks
? path.join(process.cwd(), theme_path, "snippets", sectionName)
: path.join(process.cwd(), theme_path, "blocks", sectionName);
if (schema.disabled) {
const targetFile = targets.blocks.find(
(target) => target.split(/[\\/]/gi).at(-1) === sectionName
);
if (targetFile) {
config.targets.blocks = config.targets.blocks.filter((target) => target !== targetFile);
deleteFile(path.join(root_dir, targetFile));
}
const snippetTargets = targets.snippets.filter((target) => {
return (
target
.split(/[\\/]/gi)
.at(-1)
.replace(/_blocks\./gi, "") === sectionName
);
});
if (snippetTargets.length) {
config.targets.snippets = config.targets.snippets.filter((target) => {
if (snippetTargets.includes(target)) {
deleteFile(path.join(root_dir, target));
return false;
}
return true;
});
}
continue;
}
const translationArray = [];
const rawContent = fs.readFileSync(path.join(folders.blocks, schema.folder, sectionName), {
encoding: "utf-8",
});
if (rawContent) {
const translatedContent = rawContent.replace(
/<t(\s+[^>]*)*>((.|\r|\n)*?)<\/t>/gi,
(str, group1, group2) => {
const group = toLocaleFriendlySnakeCase(schema.folder);
const content = toLocaleFriendlySnakeCase(
group2?.split(" ")?.slice(0, 2)?.join("_") ?? ""
).trim();
const backupContent = toLocaleFriendlySnakeCase(group2).trim();
const id = toLocaleFriendlySnakeCase(group1?.replace(/id="(.*)"/gi, "$1") ?? "").trim();
if (!(group in translations)) {
translations[group] = {};
}
if (id && !(id in translations[group])) {
translations[group][id] = group2;
return `{{ "${group}.${id}" | t }}`;
}
if (!(content in translations[group])) {
translations[group][content] = group2;
return `{{ "${group}.${content}" | t }}`;
}
if (translations[group][content] !== group2) {
if (!(backupContent in translations[group])) {
translations[group][backupContent] = group2;
return `{{ "${group}.${backupContent}" | t }}`;
}
if (translations[group][backupContent] !== group2) {
translations[group][`${content}_2`] = group2;
return `{{ "${group}.${content}_2" | t }}`;
}
}
if (translations[group][content] === group2) {
return `{{ "${group}.${content}" | t }}`;
}
return group2;
}
);
translationArray.push(translatedContent);
}
translationArray.push(generateBlockFiles(schema));
if (disabled_theme_blocks) continue;
if (config.ignore_blocks?.includes(blockPath.split(/[/\\]/)?.at(-1))) {
console.log(
`[${chalk.gray(new Date().toLocaleTimeString())}]: ${chalk.greenBright(
`Ignored: ${blockPath.replace(process.cwd(), "")}`
)}`
);
writeOnlyNew(blockPath, translationArray.join("\n"));
} else {
writeCompareFile(blockPath, translationArray.join("\n"));
}
}
for (let i = 0; i < snippets.length; i++) {
const snippet = snippets[i];
const snippetName = snippet.split(/[\\/]/gi).at(-1);
const section = Object.values(sectionsSchemas).find((section) =>
section.path.includes(snippet.replace(snippetName, ""))
);
const blockSchema = section?.blocks?.find((block) =>
new RegExp(`\\.${block.type}\\.`, "gi").test(snippetName)
);
if (section && (section.disabled || blockSchema?.disabled)) {
continue;
}
const block = Object.values(blockSchemas).find((section) =>
section.path.includes(snippet.replace(snippetName, ""))
);
if (block && block.disabled) {
continue;
}
const snippetPath =
disabled_theme_blocks && snippet?.includes(folders.blocks)
? path.join(process.cwd(), theme_path, "snippets", `_blocks.${snippetName}`)
: path.join(process.cwd(), theme_path, "snippets", snippetName);
const returnArr = [];
const rawContent = fs.readFileSync(snippet, {
encoding: "utf-8",
});
if (rawContent) {
let translatedContent = rawContent.replace(
/<t(\s+[^>]*)*>((.|\r|\n)*?)<\/t>/gi,
(_, group1, group2) => {
const group = toLocaleFriendlySnakeCase(
snippet.split(/[\\/]/gi).at(-1).split(".").at(0)
).trim();
const content = toLocaleFriendlySnakeCase(
group2?.split(" ")?.slice(0, 2)?.join("_") ?? ""
).trim();
const backupContent = toLocaleFriendlySnakeCase(group2).trim();
const id = toLocaleFriendlySnakeCase(group1?.replace(/id="(.*)"/gi, "$1") ?? "").trim();
if (!(group in translations)) {
translations[group] = {};
}
if (id && !(id in translations[group])) {
translations[group][id] = group2;
return `{{ "${group}.${id}" | t }}`;
}
if (!(content in translations[group])) {
translations[group][content] = group2;
return `{{ "${group}.${content}" | t }}`;
}
if (translations[group][content] !== group2) {
if (!(backupContent in translations[group])) {
translations[group][backupContent] = group2;
return `{{ "${group}.${backupContent}" | t }}`;
}
if (translations[group][backupContent] !== group2) {
translations[group][`${content}_2`] = group2;
return `{{ "${group}.${content}_2" | t }}`;
}
}
if (translations[group][content] === group2) {
return `{{ "${group}.${content}" | t }}`;
}
return group2;
}
);
if (disabled_theme_blocks) {
translatedContent = translatedContent?.replace(
/\n(\s*){%-?\s*content_for\s*['"]blocks["']\s*-?%}/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}{% liquid`];
arr.push(`${match} for block in section.blocks`);
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match} endfor`);
arr.push(`${match}%}`);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*)content_for\s*['"]blocks["']\s*\n/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}`];
arr.push(`${match}for block in section.blocks`);
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match}endfor`);
arr.push(``);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*){%-?\s*content_for\s*['"]block["']\s*-?%}/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}{% liquid`];
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match} if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match} endif`);
}
arr.push(`${match}%}`);
return arr.join("\n");
}
);
translatedContent = translatedContent?.replace(
/\n(\s*)content_for\s*['"]block["']\s*\n/gi,
(str, match) => {
match = match.replace(/\n/gi, "");
const arr = [`\n${match}`];
for (const key in blockSchemas) {
const schema = blockSchemas[key];
if (schema.disabled) continue;
arr.push(`${match}if block.type == "${schema.folder}"`);
arr.push(
`${match} render "_blocks.${schema.folder}", block: block, forloop: forloop, section_type: section_type, form: form`
);
arr.push(`${match}endif`);
}
arr.push(``);
return arr.join("\n");
}
);
}
returnArr.push(translatedContent);
}
if (config.ignore_snippets?.includes(snippetPath.split(/[/\\]/)?.at(-1))) {
console.log(
`[${chalk.gray(new Date().toLocaleTimeString())}]: ${chalk.greenBright(
`Ignored: ${snippetPath.replace(process.cwd(), "")}`
)}`
);
writeOnlyNew(snippetPath, returnArr.join("\n"));
} else {
writeCompareFile(snippetPath, returnArr.join("\n"));
}
}
for (let i = 0; i < giftCards.length; i++) {
const giftCard = giftCards[i];
const giftCardName = giftCard.split(/[\\/]/gi).at(-1);
const giftCardPath = path.join(process.cwd(), theme_path, "templates", giftCardName);
const returnArr = [];
const rawContent = fs.readFileSync(giftCard, {
encoding: "utf-8",
});
if (rawContent) {
const translatedContent = rawContent.replace(
/<t(\s+[^>]*)*>((.|\r|\n)*?)<\/t>/gi,
(_, group1, group2) => {
const group = toLocaleFriendlySnakeCase(
giftCard.split(/[\\/]/gi).at(-1).split(".").at(0)
).trim();
const content = toLocaleFriendlySnakeCase(
group2?.split(" ")?.slice(0, 2)?.join("_") ?? ""
).trim();
const backupContent = toLocaleFriendlySnakeCase(group2).trim();
const id = toLocaleFriendlySnakeCase(group1?.replace(/id="(.*)"/gi, "$1") ?? "").trim();
if (!(group in translations)) {
translations[group] = {};
}
if (id && !(id in translations[group])) {
translations[group][id] = group2;
return `{{ "${group}.${id}" | t }}`;
}
if (!(content in translations[group])) {
translations[group][content] = group2;
return `{{ "${group}.${content}" | t }}`;
}
if (translations[group][content] !== group2) {
if (!(backupContent in translations[group])) {
translations[group][backupContent] = group2;
return `{{ "${group}.${backupContent}" | t }}`;
}
if (translations[group][backupContent] !== group2) {
translations[group][`${content}_2`] = group2;
return `{{ "${group}.${content}_2" | t }}`;
}
}
if (translations[group][content] === group2) {
return `{{ "${group}.${content}" | t }}`;
}
return group2;
}
);
returnArr.push(translatedContent);
}
writeCompareFile(giftCardPath, returnArr.join("\n"));
}
for (let i = 0; i < layouts.length; i++) {
const layout = layouts[i];
const layoutName = layout.split(/[\\/]/gi).at(-1);
const layoutPath = path.join(process.cwd(), theme_path, "layout", layoutName);
const returnArr = [];
const rawContent = fs.readFileSync(layout, {
encoding: "utf-8",
});
if (rawContent) {
const translatedContent = rawContent.replace(
/<t(\s+[^>]*)*>((.|\r|\n)*?)<\/t>/gi,
(_, group1, group2) => {
const group = toLocaleFriendlySnakeCase(
layout.split(/[\\/]/gi).at(-1).split(".").at(0)
).trim();
const content = toLocaleFriendlySnakeCase(
group2?.split(" ")?.slice(0, 2)?.join("_") ?? ""
).trim();
const backupContent = toLocaleFriendlySnakeCase(group2).trim();
const id = toLocaleFriendlySnakeCase(group1?.replace(/id="(.*)"/gi, "$1") ?? "").trim();
if (!(group in translations)) {
translations[group] = {};
}
if (id && !(id in translations[group])) {
translations[group][id] = group2;
return `{{ "${group}.${id}" | t }}`;
}
if (!(content in translations[group])) {
translations[group][content] = group2;
return `{{ "${group}.${content}" | t }}`;
}
if (translations[group][content] !== group2) {
if (!(backupContent in translations[group])) {
translations[group][backupContent] = group2;
return `{{ "${group}.${backupContent}" | t }}`;
}
if (translations[group][backupContent] !== group2) {
translations[group][`${content}_2`] = group2;
return `{{ "${group}.${content}_2" | t }}`;
}
}
if (translations[group][content] === group2) {
return `{{ "${group}.${content}" | t }}`;
}
return group2;
}
);
returnArr.push(translatedContent);
}
if (config.ignore_layouts?.includes(layoutPath.split(/[/\\]/)?.at(-1))) {
console.log(
`[${chalk.gray(new Date().toLocaleTimeString())}]: ${chalk.greenBright(
`Ignored: ${layoutPath.replace(process.cwd(), "")}`
)}`
);
if (layoutPath.split(/[/\\]/)?.at(-1) === "theme.liquid") {
writeCompareFile(
layoutPath.replace("theme.liquid", "theme.dev.liquid"),
returnArr.join("\n")
);
}
writeOnlyNew(layoutPath, returnArr.join("\n"));
} else {
writeCompareFile(layoutPath, returnArr.join("\n"));
}
}
const transformTranslations = (input, prevKey = "") => {
if (isObject(input)) {
return Object.entries(input).reduce<any>((acc, [key, val]) => {
acc[key] = transformTranslations(val, `${prevKey ? `${prevKey}.` : ""}${key}`);
return acc;
}, {});
}
if (typeof input === "string") {
return `{{ '${prevKey}' | t }}`;
}
};
const translationsJs = `<script data-no-block>
window.translations = ${JSON.stringify(transformTranslations(translations), undefined, 2)};
</script>
`;
const translationTypes = `export type Translations = ${JSON.stringify(translations, undefined, 2)
.replace(/(\s+)([^\n:]*):([^\n{]*?),?\n/gi, "$1/* $3 */\n$1$2: string;\n")
.replace(/"/gi, "")
.replace(/,/gi, ";")
.replace(/}\n/gi, "};\n")
.replace(/\n\n/gi, "\n")};
declare global {
interface Window {
translations?: Translations;
}
}
`;
writeCompareFile(
path.join(process.cwd(), theme_path, "locales", "en.default.json"),
JSON.stringify(translations, undefined, 2)
);
writeCompareFile(
path.join(process.cwd(), theme_path, "snippets", "_layout.translations.liquid"),
translationsJs
);
writeCompareFile(path.join(folders.types, "translations.ts"), translationTypes);
const dynamicJsImports = [];
sources.sectionsJs.forEach((name) => {
const filename = name.split(/[\\/]/gi).at(-1);
const section = Object.values(sectionsSchemas).find((section) =>
section.path.includes(name.replace(filename, ""))
);
const targetName = `__section--${filename.replace(/\.(ts)x?$/gi, ".js")}`;
const targetFile = targets.dynamicJs.find((file) => file.includes(targetName));
if (section && !section.disabled) {
dynamicJsImports.push(
`<link rel="preload" as="script" href="{{ '${targetName}' | asset_url }}">`
);
dynamicJsImports.push(
`<script type="module" src="{{ '${targetName}' | asset_url }}" defer></script>`
);
} else if (targetFile) {
deleteFile(path.join(root_dir, targetFile));
config.targets.dynamicJs = config.targets.dynamicJs.filter((target) => target !== targetFile);
}
});
sources.blocksJs.forEach((name) => {
const filename = name.split(/[\\/]/gi).at(-1);
const block = Object.values(blockSchemas).find((section) =>
section.path.includes(name.replace(filename, ""))
);
const targetName = `__block--${filename.replace(/\.(ts)x?$/gi, ".js")}`;
const targetFile = targets.dynamicJs.find((file) => file.includes(targetName));
if (block && !block.disabled) {
dynamicJsImports.push(
`<link rel="preload" as="script" href="{{ '${targetName}' | asset_url }}">`
);
dynamicJsImports.push(
`<script type="module" src="{{ '${targetName}' | asset_url }}" defer></script>`
);
} else if (targetFile) {
deleteFile(path.join(root_dir, targetFile));
config.targets.dynamicJs = config.targets.dynamicJs.filter((target) => target !== targetFile);
}
});
targets.dynamicJs.forEach((name) => {
const targetName = name.split(/[\\/]/gi).at(-1).replace(/\.js$/gi, "");
const sectionFile = sources.sectionsJs.find(
(section) =>
section.includes(`\\${targetName.replace(/__section--/gi, "")}.ts`) ||
section.includes(`/${targetName.replace(/__section--/gi, "")}.ts`)
);
if (sectionFile) {
const filename = sectionFile?.split(/[\\/]/gi)?.at(-1);
const section = Object.values(sectionsSchemas).find((section) =>
section.path.includes(sectionFile.replace(filename, ""))
);
if (!section || section.disabled) {
deleteFile(path.join(root_dir, name));
config.targets.dynamicJs = config.targets.dynamicJs.filter((target) => target !== name);
}
return;
}
const blockFile = sources.blocksJs.find((section) =>
section.includes(targetName.replace(/__block--/gi, ""))
);
if (blockFile) {
const filename = blockFile?.split(/[\\/]/gi)?.at(-1);
const block = Object.values(blockSchemas).find((section) =>
section.path.includes(blockFile.replace(filename, ""))
);
if (!block || block.disabled) {
deleteFile(path.join(root_dir, name));
config.targets.dynamicJs = config.targets.dynamicJs.filter((target) => target !== name);
}
return;
}
deleteFile(path.join(root_dir, name));
config.targets.dynamicJs = config.targets.dynamicJs.filter((target) => target !== name);
});
writeCompareFile(
path.join(process.cwd(), theme_path, "snippets", "_layout.dynamic-imports.liquid"),
dynamicJsImports.join("\n")
);
if (delete_external_snippets) {
targets.snippets.forEach((file) => {
const fileName = file.split(/[\\/]/gi).at(-1);
const targetFile = snippets.find((sourcePath) =>
disabled_theme_blocks && sourcePath?.includes(folders.blocks)
? `_blocks.${sourcePath.split(/[\\/]/gi).at(-1)}` === fileName
: sourcePath.split(/[\\/]/gi).at(-1) === fileName
);
if (
fileName.includes("_layout.translations.liquid") ||
fileName.includes("_layout.dynamic-imports.liquid") ||
/^replo/gi.test(fileName) ||
/^pandectes/gi.test(fileName) ||
/^locksmith/gi.test(fileName) ||
/^shogun/gi.test(fileName)
) {
return;
}
if (!targetFile) {
deleteFile(path.join(process.cwd(), file));
}
});
}
if (delete_external_sections) {
targets.sections.forEach((file) => {
const fileName = file.split(/[\\/]/gi).at(-1);
const targetFile =
sources.sectionsLiquid.find(
(sourcePath) => sourcePath.split(/[\\/]/gi).at(-1) === fileName
) ||
Object.entries(sources.sectionPresetSchemas).find(
([key, val]) =>
val.presets?.filter(
(preset) =>
config.all_presets ||
!preset.enabled_on ||
preset.enabled_on?.includes(process.env.SHOPIFY_ACCELERATE_STORE)
)?.length && fileName === `preset__${toSnakeCase(key)}.liquid`
);
if (
/^replo/gi.test(fileName) ||
/^pandectes/gi.test(fileName) ||
/^locksmith/gi.test(fileName) ||
/^shogun/gi.test(fileName)
) {
return;
}
if (!targetFile) {
deleteFile(path.join(process.cwd(), file));
}
});
}
if (delete_external_layouts) {
targets.layout.forEach((file) => {
const fileName = file.split(/[\\/]/gi).at(-1);
const targetFile = sources.layouts.find(
(sourcePath) => sourcePath.split(/[\\/]/gi).at(-1) === fileName
);
if (!targetFile) {
deleteFile(path.join(process.cwd(), file));
}
});
}
if (delete_external_blocks) {
targets.blocks.forEach((file) => {
const fileName = file.split(/[\\/]/gi).at(-1);
const targetFile = sources.blocksLiquid.find(
(sourcePath) => sourcePath.split(/[\\/]/gi).at(-1) === fileName
);
if (!targetFile) {
deleteFile(path.join(process.cwd(), file));
}
});
}
};