Naprawa pobierania komponentów - aktualizacja ciasteczek i konfiguracji

This commit is contained in:
NoNamedCobble
2026-01-30 08:57:18 +01:00
commit 37c62f4a50
19 changed files with 12901 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.env
node_modules/
pages/
.DS_Store
*.log

6
.prettierignore Normal file
View File

@@ -0,0 +1,6 @@
node_modules
.env
.env.example
docs
dist
build

25
.prettierrc Normal file
View File

@@ -0,0 +1,25 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"proseWrap": "preserve",
"overrides": [
{
"files": "*.xml",
"options": {
"parser": "babel"
}
},
{
"files": "*.less",
"options": {
"parser": "less"
}
}
]
}

7
.stylelintrc.json Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": "stylelint-config-standard-less",
"rules": {
"no-empty-source": null,
"no-duplicate-selectors": true
}
}

7079
component request.md Normal file

File diff suppressed because it is too large Load Diff

227
components request Normal file

File diff suppressed because one or more lines are too long

5
docs/.env.example Normal file
View File

@@ -0,0 +1,5 @@
# Umieść tutaj swój AUTH_TOKEN i TEMPLATE_ID
AUTH_TOKEN=your_token_here
TEMPLATE_ID=your_template_id_here
API_URL=https://composer.idosell.com/api

112
docs/LINTING.md Normal file
View File

@@ -0,0 +1,112 @@
# Prettier i Stylelint - Formatowanie i Walidacja
Projekt zawiera konfigurację do formatowania i walidacji kodu.
## Zainstalowane narzędzia
- **Prettier** - formatowanie kodu (JS, XML, LESS, JSON)
- **Stylelint** - walidacja LESS
## Komendy
### Formatowanie
```bash
# Sformatuj wszystkie pliki (JS, XML, LESS, JSON)
npm run format
# Sprawdź czy pliki są sformatowane
npm run format:check
```
### Walidacja
```bash
# Sprawdź LESS w pages/
npm run lint:less
```
## Konfiguracje
### `.prettierrc` - Prettier
- Print Width: 100
- Tab Width: 2
- Semicolons: włączone
- Single Quotes: wyłączone (używamy `"`)
- Trailing Commas: `es5`
### `.stylelintrc.json` - Stylelint
Waliduje LESS files:
- Reguły standardowe + Stylelint Less
- Indentacja: 2 spacje
- Sprawdzanie kolorów hex
- Sprawdzanie duplikowanych selektorów
## Obsługa Custom XML
Pliki XML zawierają custom tagi:
- `<iai:variable>`
- `<iaixsl:value-of>`
- `<iaixsl:for-each>`
- itd.
Prettier je prawidłowo formatuje bez błędów.
## Obsługa HTML Entities
Prettier automatycznie konwertuje:
- `<``&lt;`
- `>``&gt;`
- `&``&amp;`
(dla XML i HTML files)
## VS Code Integration
Zainstaluj rozszerzenia:
- **Prettier - Code formatter** (esbenp.prettier-vscode)
- **Stylelint** (stylelint.vscode-plugin)
W VS Code możesz formatować na save:
```json
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
```
## Ignorowanie plików
### `.prettierignore`
```
node_modules
.env
.env.example
docs
dist
build
```
## Przykład: Formatowanie komponenty
Plik przed:
```xml
<xml><iai:variable name="test" select="value" /></xml>
```
Po `npm run format`:
```xml
<xml><iai:variable name="test" select="value" /></xml>
```
## Troubleshooting
### "Parser error" w Prettier
- Upewnij się że `.prettierrc` ma poprawną konfigurację
- Prettier potrzebuje prawidłowego rozszerzenia pliku (`.xml`, `.less`, `.js`)
### Stylelint nie sprawdza LESS
- Zainstaluj `postcss` i `postcss-less`
- Sprawdź że `.stylelintrc.json` ma `postcss-less` w overrides

69
docs/README.md Normal file
View File

@@ -0,0 +1,69 @@
# 🚀 Composer Builder
Szybko pobiera strony z szablonów iDoSell i tworzy strukturę folderów do edycji.
## ⚡ Szybki Start
### 1. Pierwsza konfiguracja
```bash
npm install
npm run setup
```
Skrypt będzie pytać o dane do API interaktywnie.
### 2. Pobierz strony
```bash
npm run template:pull
```
## 📖 Komendy
| Komenda | Opis |
| -------------------------------- | --------------------------------------- |
| `npm run setup` | Konfiguracja - wprowadzenie tokena i ID |
| `npm run template:pull` | Pobierz WSZYSTKIE komponenty |
| `npm run template:pull --custom` | Pobierz TYLKO komponenty typu custom |
| `npm run template:config` | Wyświetl aktualną konfigurację |
## 🔐 Gdzie znaleźć dane?
### AUTH_TOKEN (monit_token)
1. Zaloguj się do [composer.idosell.com](https://composer.idosell.com)
2. Otwórz DevTools: **F12**
3. Idź na: **Application → Cookies**
4. Szukaj: **monit_token**
5. Skopiuj wartość
### TEMPLATE_ID
- URL szablonu: `https://composer.idosell.com/compositions/xxxxx.12345`
- TEMPLATE_ID = **12345** (część po kropce)
To polecenie:
- Pobierze listę stron z szablonu
- Utworzy folder dla każdej strony
- Wygeneruje plik `config.json` w każdym folderze
### Konfiguracja
```bash
npm run template:config
```
Wyświetli obecną konfigurację.
## Struktura wyjścia
```
pages/
├── opinions-photos/
│ └── config.json
├── homepage/
│ └── config.json
└── ...
```

24
docs/SETUP.md Normal file
View File

@@ -0,0 +1,24 @@
# Composer Builder Configuration
Dodaj tutaj swoje dane do konfiguracji.
## Jak znaleźć AUTH_TOKEN
1. Otwórz DevTools (F12) w przeglądarce
2. Idź do zakładki "Application" → "Cookies"
3. Szukaj cookie'a o nazwie `monit_token`
4. Skopiuj jego wartość
## Jak znaleźć TEMPLATE_ID
1. Otwórz URL szablonu w przeglądarce
2. URL wygląda podobnie do: `https://composer.idosell.com/compositions/69773895f35fc9.84872857`
3. Ostatnia część (po `.`) to TEMPLATE_ID
## Plik .env
```env
AUTH_TOKEN=30fa9d107ac0dbd46280e52d9039f0545364bf5a
TEMPLATE_ID=84872857
API_URL=https://composer.idosell.com/api
```

8
example.env Normal file
View File

@@ -0,0 +1,8 @@
AUTH_TOKEN=
TEMPLATE_ID=
API_URL=https://composer.idosell.com/api
# Cookies (zaktualizuj gdy ciasteczka wygasną)
PHPSESSID=
IAI_SYSTEM_CLIENT=
IAI_DASHBOARD=

1880
najnowszyrequest.txt Normal file

File diff suppressed because it is too large Load Diff

2799
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
package.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "composer-builder",
"version": "1.0.0",
"description": "Template page builder for iDoSell Composer",
"main": "src/index.js",
"type": "module",
"scripts": {
"setup": "node setup.js",
"template:pull": "node src/index.js",
"template:config": "node src/config.js",
"format": "prettier --write \"pages/**/*.{xml,less,js,json}\" \"src/**/*.js\"",
"format:check": "prettier --check \"pages/**/*.{xml,less,js,json}\" \"src/**/*.js\"",
"lint:less": "stylelint \"pages/**/*.less\""
},
"keywords": [
"composer",
"idosell",
"template"
],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.0",
"dotenv": "^16.3.1",
"fs-extra": "^11.1.1"
},
"devDependencies": {
"prettier": "^3.1.0",
"stylelint": "^15.11.0",
"stylelint-config-standard-less": "^1.0.0",
"stylelint-less": "^1.0.5",
"postcss": "^8.4.31",
"postcss-less": "^6.0.0"
}
}

0
page request.md Normal file
View File

71
setup.js Normal file
View File

@@ -0,0 +1,71 @@
import fs from "fs";
import path from "path";
import readline from "readline";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const envPath = path.join(__dirname, ".env");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function question(query) {
return new Promise((resolve) => {
rl.question(query, resolve);
});
}
async function main() {
console.clear();
console.log("*** Setup Composer Builder ***\n");
console.log("Uzupełnij dane do konfiguracji API\n");
console.log("[INFO] Jak znaleźć dane:");
console.log("1. Zaloguj się do https://composer.idosell.com");
console.log("2. Otwórz DevTools (F12)");
console.log("3. Application → Cookies");
console.log("4. Skopiuj wartość cookie'a: monit_token\n");
const authToken = await question("[INPUT] AUTH_TOKEN (monit_token): ");
if (!authToken || authToken.trim().length < 10) {
console.log("\n[ERROR] Token jest zbyt krótki!");
process.exit(1);
}
const templateId = await question(
"[INPUT] TEMPLATE_ID (z URL: compositions/xxx.12345 → 12345): ",
);
if (!templateId || templateId.trim().length < 2) {
console.log("\n[ERROR] Template ID jest wymagany!");
process.exit(1);
}
const apiUrl =
(await question(
"[INPUT] API_URL (domyślnie: https://composer.idosell.com/api): ",
)) || "https://composer.idosell.com/api";
// Generuj .env
const envContent = `# Composer Builder Configuration
# Wygenerowano automatycznie
AUTH_TOKEN=${authToken.trim()}
TEMPLATE_ID=${templateId.trim()}
API_URL=${apiUrl.trim()}
`;
fs.writeFileSync(envPath, envContent);
console.log("\n[OK] Konfiguracja zapisana w .env");
console.log(`[INFO] Plik: ${envPath}\n`);
console.log("[NEXT] Możesz teraz uruchomić:");
console.log(" npm run template:pull\n");
rl.close();
}
main().catch(console.error);

3
src/config-display.js Normal file
View File

@@ -0,0 +1,3 @@
import { displayConfig } from "./config.js";
displayConfig();

85
src/config.js Normal file
View File

@@ -0,0 +1,85 @@
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";
dotenv.config();
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const envPath = path.join(__dirname, "..", ".env");
/**
* Pobierz konfigurację ze zmiennych środowiska
*/
export function getConfig() {
return {
authToken: process.env.AUTH_TOKEN,
templateId: process.env.TEMPLATE_ID,
apiUrl: process.env.API_URL || "https://composer.idosell.com/api",
// Cookies
phpsessid: process.env.PHPSESSID || "",
iaiSystemClient: process.env.IAI_SYSTEM_CLIENT || "",
iaiDashboard: process.env.IAI_DASHBOARD || "",
};
}
/**
* Sprawdź, czy konfiguracja jest kompletna
*/
export function validateConfig() {
const config = getConfig();
if (!config.authToken) {
console.error("[ERROR] Brakuje AUTH_TOKEN w pliku .env");
return false;
}
if (!config.templateId) {
console.error("[ERROR] Brakuje TEMPLATE_ID w pliku .env");
return false;
}
console.log("[OK] Konfiguracja załadowana poprawnie");
return true;
}
/**
* Wyświetl obecną konfigurację
*/
export function displayConfig() {
const config = getConfig();
console.log("\n[CONFIG] Obecna konfiguracja:");
console.log("---".repeat(15));
console.log(`API URL: ${config.apiUrl}`);
console.log(
`Auth Token: ${config.authToken ? config.authToken.substring(0, 10) + "..." : "[ERROR] nie ustawiony"}`
);
console.log(`Template ID: ${config.templateId || "[ERROR] nie ustawiony"}`);
console.log("---".repeat(15));
if (!config.authToken || !config.templateId) {
console.log("\n[INFO] Edytuj plik .env aby ustawić konfigurację:");
console.log(`Plik: ${envPath}`);
}
console.log();
}
/**
* Zbuduj cookie string z konfiguracji
*/
export function buildCookieString(config) {
let cookies = `monit_token=${config.authToken}; lang=pl; currency_uk=eur; currency_pl=pln; type_of_visitor=client`;
if (config.phpsessid) {
cookies += `; PHPSESSID=${config.phpsessid}`;
}
if (config.iaiSystemClient) {
cookies += `; IAI_System_client=${config.iaiSystemClient}`;
}
if (config.iaiDashboard) {
cookies += `; iai_dashboard=${config.iaiDashboard}`;
}
return cookies;
}

461
src/index.js Normal file
View File

@@ -0,0 +1,461 @@
import axios from "axios";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
import { getConfig, validateConfig, displayConfig, buildCookieString } from "./config.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pagesDir = path.join(__dirname, "..", "pages");
/**
* Sprawdź czy użytkownik jest zalogowany
*/
async function checkLogin(config) {
try {
console.log("[AUTH] Sprawdzanie zalogowania...");
const cookies = buildCookieString(config);
const response = await axios.get(`${config.apiUrl}/auth/get-logged-user/`, {
headers: {
Cookie: cookies,
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
Accept: "*/*",
"Accept-Language": "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Referer:
`https://composer.idosell.com/compositions/${config.templateId}`,
},
});
if (response.data.response && response.data.response.id) {
console.log(`[OK] Zalogowany jako: ${response.data.response.name}`);
return true;
}
return false;
} catch (error) {
console.error("[ERROR] Błąd przy sprawdzaniu zalogowania:");
console.error(error.response?.data || error.message);
return false;
}
}
/**
* Pobierz szczegóły strony (komponenty)
*/
async function fetchPageDetails(config, pageName) {
try {
const cookies = buildCookieString(config);
// TEMPLATE_ID jest w formacie: compositionId.version
const compositionId = config.templateId;
const url = `${config.apiUrl}/compositions/get-page/compositionId/${compositionId}/compositionVersion/1/page/${pageName}`;
console.log(` [URL] Pobieranie: ${url}`);
const response = await axios.get(url, {
headers: {
Cookie: cookies,
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
Accept: "*/*",
"Accept-Language": "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Referer:
`https://composer.idosell.com/compositions/${compositionId}`,
},
});
if (response.data.response && response.data.response.page) {
return response.data.response.page;
}
return [];
} catch (error) {
console.error(
` ⚠️ Błąd przy pobieraniu szczegółów ${pageName}:`,
error.response?.status,
error.message,
);
return [];
}
}
/**
* Pobierz strony z API
*/
async function fetchPages() {
const config = getConfig();
try {
console.log("[LOAD] Pobieranie listy stron...");
const cookies = buildCookieString(config);
const response = await axios.get(`${config.apiUrl}/pages/get`, {
headers: {
Cookie: cookies,
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
Accept: "*/*",
"Accept-Language": "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Referer:
"https://composer.idosell.com/compositions/69773895f35fc9.84872857",
},
});
if (response.data.response && response.data.response.pages) {
console.log(`[OK] Pobrano ${response.data.response.pages.length} stron`);
return response.data.response.pages;
} else {
console.error("[ERROR] Nieoczekiwany format odpowiedzi API");
console.error("Odpowiedź:", JSON.stringify(response.data, null, 2));
return [];
}
} catch (error) {
console.error("[ERROR] Błąd przy pobieraniu stron:");
console.error(error.response?.data || error.message);
process.exit(1);
}
}
/**
* Pobierz szczegóły komponentu ze najnowszą wersją
*/
async function fetchComponentDetails(config, componentId, componentVersion) {
try {
const cookies = buildCookieString(config);
// Użyj wersji komponenty z API, jeśli dostępna, w przeciwnym razie 1
const version = componentVersion || 1;
const url = `${config.apiUrl}/modules/get/id/${componentId}/version/${version}`;
const response = await axios.get(url, {
headers: {
Cookie: cookies,
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
Accept: "*/*",
"Accept-Language": "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Referer:
`https://composer.idosell.com/modules/${componentId}/version/${version}`,
},
});
if (response.data && response.data.response) return response.data.response;
return null;
} catch (error) {
console.error(
` [WARN] Błąd pobierania komponentu ${componentId} v${componentVersion}:`,
error.response?.status,
error.message,
);
return null;
}
}
async function createPageFolders(pages, config, onlyCustom = false) {
try {
// Wyczyść stary katalog jeśli istnieje
if (fs.existsSync(pagesDir)) {
console.log("[CLEAN] Czyszczenie starego katalogu pages/");
fs.removeSync(pagesDir);
}
// Stwórz nowy katalog
fs.ensureDirSync(pagesDir);
console.log(`[OK] Utworzono katalog: pages/\n`);
// Stwórz folder dla każdej strony
for (const page of pages) {
const pagePath = path.join(pagesDir, page.name);
fs.ensureDirSync(pagePath);
// Stwórz config.json dla każdej strony
const configFile = path.join(pagePath, "config.json");
const configContent = {
id: page.id,
name: page.name,
description: page.description,
createdAt: new Date().toISOString(),
};
fs.writeFileSync(configFile, JSON.stringify(configContent, null, 2));
// Pobierz szczegóły strony (komponenty)
const pageDetails = await fetchPageDetails(config, page.name);
// Helper: utwórz folder komponentu (async, bo pobiera dane komponentu)
async function createComponentFolder(baseDir, component) {
const folderName = (component.group || component.name || "component")
.toString()
.toLowerCase()
.replace(/\s+/g, "_")
.replace(/[^a-z0-9_]/g, "");
const componentDir = path.join(baseDir, folderName);
fs.ensureDirSync(componentDir);
const componentFile = path.join(componentDir, "component.json");
fs.writeFileSync(componentFile, JSON.stringify(component, null, 2));
// Pobierz pełne dane komponentu i zapisz pliki ze sources
// Użyj wersji z API (component.version) zamiast zawsze 1
const version = component.version || component.version === 0 ? component.version : 1;
const details = await fetchComponentDetails(config, component.id, version);
if (details && details.sources) {
console.log(` [SOURCES] ${component.name} (v${version})`);
await writeSourceFiles(details.sources, componentDir);
}
}
// Helper: zapisz pliki ze sources
async function writeSourceFiles(sources, componentDir) {
// Mapowanie klucz -> rozszerzenie
const sourceExtensions = {
javascript: "js",
jsLocal: "js",
css: "less",
xml: "xml",
xmlBefore: "xml",
xmlAfter: "xml",
attributes: "json",
translations: "json",
};
// Helper do zapisu pliku (tworzy plik nawet jeśli pusty)
function writeFile(content, key) {
if (typeof content === "undefined" || content === null) return;
const ext = sourceExtensions[key] || "txt";
const filename = `${key}.${ext}`;
const filePath = path.join(componentDir, filename);
let contentToWrite = content;
if (typeof content === "object") {
contentToWrite = JSON.stringify(content, null, 2);
} else if (typeof content !== "string") {
contentToWrite = String(content);
}
fs.writeFileSync(filePath, contentToWrite, "utf8");
}
// Zmapuj wszystkie klucze sources na pliki
Object.keys(sources).forEach((key) => {
if (key === "attributes" || key === "translations") {
// te już obsługujemy osobno
return;
}
writeFile(sources[key], key);
});
// Osobnie attributes i translations jeśli są i są obiektami
if (sources.attributes && typeof sources.attributes === "object") {
writeFile(sources.attributes, "attributes");
}
if (sources.translations && typeof sources.translations === "object") {
writeFile(sources.translations, "translations");
}
}
// Rekursywnie szukaj componentów z type: custom i twórz foldery
async function processItems(items, baseDir, onlyCustom = false) {
if (!items) return;
if (!Array.isArray(items)) return;
for (const item of items) {
// Jeśli onlyCustom = false, tworzymy folder dla każdego komponentu
// Jeśli onlyCustom = true, tworzymy tylko dla type: custom
if (!onlyCustom || item.type === "custom") {
await createComponentFolder(baseDir, item);
}
// jeśli element ma wewnętrzne components, rekurencyjnie je przetwórz
if (item.components && Array.isArray(item.components)) {
await processItems(item.components, baseDir, onlyCustom);
}
}
}
if (pageDetails) {
// Jeśli API zwróciło obiekt z kluczem components -> traktuj jako wrapper
if (
!Array.isArray(pageDetails) &&
pageDetails.components &&
Array.isArray(pageDetails.components)
) {
// użyj group lub name jako nazwy wrappera (sanitizowane)
const rawWrapperName = (
pageDetails.group ||
pageDetails.name ||
"wrapper"
).toString();
const wrapperName = rawWrapperName
.toLowerCase()
.replace(/\s+/g, "_")
.replace(/[^a-z0-9_]/g, "");
const wrapperDir = path.join(pagePath, wrapperName);
fs.ensureDirSync(wrapperDir);
// Zapisz component.json dla wrappera
const wrapperComponentFile = path.join(wrapperDir, "component.json");
fs.writeFileSync(
wrapperComponentFile,
JSON.stringify(pageDetails, null, 2),
);
// Zapisz pliki ze sources dla wrappera
if (pageDetails.sources) {
await writeSourceFiles(pageDetails.sources, wrapperDir);
}
await processItems(pageDetails.components, wrapperDir, onlyCustom);
} else if (Array.isArray(pageDetails)) {
// Jeśli otrzymaliśmy tablicę, najpierw znajdź wrappery (model === 'wrapper')
// znajdź potencjalne wrappery (mają model 'wrapper' lub components[])
const possibleWrappers = pageDetails.filter(
(it) =>
it &&
(it.model === "wrapper" ||
(it.components && Array.isArray(it.components))),
);
// helper: sprawdź rekursywnie czy w items jest jakikolwiek custom
function hasCustom(items) {
if (!items) return false;
if (!Array.isArray(items)) return false;
for (const it of items) {
if (!it) continue;
if (it.type === "custom") return true;
if (it.components && Array.isArray(it.components)) {
if (hasCustom(it.components)) return true;
}
}
return false;
}
const processedWrapperIds = new Set();
for (const wrapper of possibleWrappers) {
// tylko twórz wrapper jeśli wewnątrz są custom komponenty
if (!hasCustom(wrapper.components)) {
continue;
}
const rawWrapperName = (
wrapper.group ||
wrapper.name ||
"wrapper"
).toString();
const wrapperName = rawWrapperName
.toLowerCase()
.replace(/\s+/g, "_")
.replace(/[^a-z0-9_]/g, "");
const wrapperDir = path.join(pagePath, wrapperName);
fs.ensureDirSync(wrapperDir);
// Zapisz component.json dla wrappera
const wrapperComponentFile = path.join(
wrapperDir,
"component.json",
);
fs.writeFileSync(
wrapperComponentFile,
JSON.stringify(wrapper, null, 2),
);
// Zapisz pliki ze sources dla wrappera
if (wrapper.sources) {
await writeSourceFiles(wrapper.sources, wrapperDir);
}
if (Array.isArray(wrapper.components)) {
await processItems(wrapper.components, wrapperDir, onlyCustom);
}
if (wrapper.id) processedWrapperIds.add(wrapper.id);
}
// Przetwórz pozostałe elementy (pomijając wrappery)
const remaining = pageDetails.filter(
(it) => !processedWrapperIds.has(it.id),
);
await processItems(remaining, pagePath, onlyCustom);
}
}
// Policz rzeczywiste komponenty w folderze strony
const componentDirs = fs.readdirSync(pagePath).filter((f) => {
const fullPath = path.join(pagePath, f);
return fs.statSync(fullPath).isDirectory();
});
const customText =
componentDirs.length > 0 ? ` (${componentDirs.length})` : "";
console.log(` [OK] ${page.name}${customText}`);
}
console.log(`\n[DONE] Ukończono! Przetworzono ${pages.length} stron`);
} catch (error) {
console.error("[ERROR] Błąd przy tworzeniu folderów:");
console.error(error.message);
process.exit(1);
}
}
/**
* Główna funkcja
*/
async function main() {
console.clear();
console.log("*** Composer Builder - Template Puller ***\n");
// Czytaj flagi z argumentów
const args = process.argv.slice(2);
const onlyCustom = args.includes("--custom");
// Wyświetl tryb
if (onlyCustom) {
console.log("[MODE] Pobieranie TYLKO komponentów custom\n");
} else {
console.log("[MODE] Pobieranie WSZYSTKICH komponentów\n");
}
// Wyświetl konfigurację
displayConfig();
// Walidacja konfiguracji
if (!validateConfig()) {
process.exit(1);
}
const config = getConfig();
// Sprawdź zalogowanie
const isLogged = await checkLogin(config);
if (!isLogged) {
console.log("\n[ERROR] Nie jesteś zalogowany. Token może być wygaszony.");
console.log("[INFO] Zaktualizuj AUTH_TOKEN w pliku .env");
process.exit(1);
}
// Pobierz strony
const pages = await fetchPages();
if (pages.length === 0) {
console.log("[WARN] Brak stron do pobrania");
return;
}
// Stwórz foldery
await createPageFolders(pages, config, onlyCustom);
}
main().catch(console.error);