This commit is contained in:
Benoti 2023-09-01 12:32:35 +01:00
parent 5dc871d8db
commit 59d73239d8
7 changed files with 577 additions and 421 deletions

8
.gitignore vendored
View File

@ -1,5 +1,5 @@
# Ignore npm modules and src folder # Ignore npm modules and src folder
node_modules node_modules
# src # src
# tsconfig.json # tsconfig.json
test test

228
README.md
View File

@ -1,114 +1,114 @@
# Less watch for .less files # Less watch for .less files
This is a super-light npm package that watches .less files and actively compiles them into .css files This is a super-light npm package that watches .less files and actively compiles them into .css files
--- ---
## Prerequisites ## Prerequisites
You need `less` npm package insalled. you can add it your project by running: You need `less` npm package insalled. you can add it your project by running:
```bash ```bash
npm install less npm install less
``` ```
## Installation ## Installation
To install this package simply run: To install this package simply run:
```bash ```bash
npm install lessc-watcher npm install lessc-watcher
``` ```
## How to use ## How to use
There are few different ways to run your less compiler There are few different ways to run your less compiler
### Basic usage ### Basic usage
```bash ```bash
npx lessc-watcher --src ./folder --dst ./dist/less.css npx lessc-watcher --src ./folder --dst ./dist/less.css
``` ```
This traverses the `--src` folder and searches for a `main.less` file. This file serves as the source for your bundled `.css` file. If you want to target a specific file, use: This traverses the `--src` folder and searches for a `main.less` file. This file serves as the source for your bundled `.css` file. If you want to target a specific file, use:
```bash ```bash
npx lessc-watcher --src ./folder/src.less --dst ./dist/less.css npx lessc-watcher --src ./folder/src.less --dst ./dist/less.css
``` ```
Or you can just watch an entire folder. In this case less-watch will searc for an entry file named `main.less`. Without this entry file, your compiler wouldn't work. Or you can just watch an entire folder. In this case less-watch will searc for an entry file named `main.less`. Without this entry file, your compiler wouldn't work.
```bash ```bash
npx lessc-watcher --src ./folder --dst ./dist/less.css npx lessc-watcher --src ./folder --dst ./dist/less.css
``` ```
**_NOTE:_** If you only provide a destination path, without specifying the exact file name in `.css`, your files will be compiled to a css file named `_main.css`. This is done to prevent conflicts with another possible `main.css` file. **_NOTE:_** If you only provide a destination path, without specifying the exact file name in `.css`, your files will be compiled to a css file named `_main.css`. This is done to prevent conflicts with another possible `main.css` file.
### Adding more source folders ### Adding more source folders
You can add more source folders by using a comma(`,`) separator. Example: You can add more source folders by using a comma(`,`) separator. Example:
```bash ```bash
npx lessc-watcher --src ./folder-1,./folder-2 --dst ./dist/folder-1.css,./dist/folder-2.css npx lessc-watcher --src ./folder-1,./folder-2 --dst ./dist/folder-1.css,./dist/folder-2.css
``` ```
**_NOTE:_** Your `--dst` input must match the number of comma-separated folders in your `src` input. **_NOTE:_** Your `--dst` input must match the number of comma-separated folders in your `src` input.
## Advanced Features ## Advanced Features
lessc-watcher has more advanced features to better fine-tune your files lessc-watcher has more advanced features to better fine-tune your files
### Ignore files ### Ignore files
Ignore files/folders by enlosing the names in braces. Eg `(general).less` Ignore files/folders by enlosing the names in braces. Eg `(general).less`
### Compile specific files ### Compile specific files
If you're watching an entire folder, you can compile specific files in that folder to a stanalone file. Example if you create a file named `[test].less` in your watch directory, in your distribution directory there will be an extra file named `test.css`. If you're watching an entire folder, you can compile specific files in that folder to a stanalone file. Example if you create a file named `[test].less` in your watch directory, in your distribution directory there will be an extra file named `test.css`.
## Using a `lesscw.config.json` file ## Using a `lesscw.config.json` file
You can use a `lesscw.config.json` file to add your files instead of using the CLI interface. For this to work your `lesscw.config.json` file must be located in the root directory of your project, and it must contain at least one `src` and one `dst` entry You can use a `lesscw.config.json` file to add your files instead of using the CLI interface. For this to work your `lesscw.config.json` file must be located in the root directory of your project, and it must contain at least one `src` and one `dst` entry
### Basic Config JSON ### Basic Config JSON
```json ```json
{ {
"src": "./folder", "src": "./folder",
"dst": "./dist/less.css" "dst": "./dist/less.css"
} }
``` ```
This works the same as running `npx lessc-watcher --src ./folder --dst ./dist/less.css` in your terminal. Instead you only need to run: This works the same as running `npx lessc-watcher --src ./folder --dst ./dist/less.css` in your terminal. Instead you only need to run:
```bash ```bash
npx lessc-watcher npx lessc-watcher
``` ```
### Using multiple sources and destinations ### Using multiple sources and destinations
```json ```json
{ {
"src": ["./folder", "./folder-2", "./folder/sub-folder/admin.less"], "src": ["./folder", "./folder-2", "./folder/sub-folder/admin.less"],
"dst": ["./dist/less.css", "./dist/folder-2/less.css", "./dist/sub-folder.css"] "dst": ["./dist/less.css", "./dist/folder-2/less.css", "./dist/sub-folder.css"]
} }
``` ```
Like the CLI paradigm, the number of paths in the `src` array must match the `dst array`. And note that you can use multiple different folders with multiple different destinations. Like the CLI paradigm, the number of paths in the `src` array must match the `dst array`. And note that you can use multiple different folders with multiple different destinations.
### Using a `srcDst` cofiguration ### Using a `srcDst` cofiguration
ALternative to the `src` and `dst` paths, you can provide a `srcDst` key instead, this will contain an array of key-value pairs as follows ALternative to the `src` and `dst` paths, you can provide a `srcDst` key instead, this will contain an array of key-value pairs as follows
```json ```json
{ {
"srcDst": [ "srcDst": [
{ {
"src": "./folder", "src": "./folder",
"dst": "./folder-2" "dst": "./folder-2"
} }
] ]
} }
``` ```
**_NOTE:_** If you provide a config file and still add `--src` and `--dst` arguments in your terminal, the terminal source and distributuion arguments will be ignored. **_NOTE:_** If you provide a config file and still add `--src` and `--dst` arguments in your terminal, the terminal source and distributuion arguments will be ignored.

84
dist/index.js vendored
View File

@ -18,18 +18,31 @@ const grabSrcDisStrings = () => {
} }
try { try {
const configObject = JSON.parse(fs_1.default.readFileSync("./lesscw.config.json", "utf-8")); const configObject = JSON.parse(fs_1.default.readFileSync("./lesscw.config.json", "utf-8"));
if ((configObject === null || configObject === void 0 ? void 0 : configObject.src) && (configObject === null || configObject === void 0 ? void 0 : configObject.dst) && typeof configObject.src === "string" && typeof configObject.dst === "string") { if ((configObject === null || configObject === void 0 ? void 0 : configObject.src) &&
(configObject === null || configObject === void 0 ? void 0 : configObject.dst) &&
typeof configObject.src === "string" &&
typeof configObject.dst === "string") {
srcArray = configObject.src.split(","); srcArray = configObject.src.split(",");
dstArray = configObject.dst.split(","); dstArray = configObject.dst.split(",");
} }
else if ((configObject === null || configObject === void 0 ? void 0 : configObject.src) && (configObject === null || configObject === void 0 ? void 0 : configObject.dst) && typeof configObject.src === "object" && typeof configObject.dst === "object" && Array.isArray(configObject.src) && Array.isArray(configObject.dst)) { else if ((configObject === null || configObject === void 0 ? void 0 : configObject.src) &&
(configObject === null || configObject === void 0 ? void 0 : configObject.dst) &&
typeof configObject.src === "object" &&
typeof configObject.dst === "object" &&
Array.isArray(configObject.src) &&
Array.isArray(configObject.dst)) {
srcArray = configObject.src; srcArray = configObject.src;
dstArray = configObject.dst; dstArray = configObject.dst;
} }
else if ((configObject === null || configObject === void 0 ? void 0 : configObject.srcDst) && Array.isArray(configObject.srcDst) && configObject.srcDst.length > 0) { else if ((configObject === null || configObject === void 0 ? void 0 : configObject.srcDst) &&
Array.isArray(configObject.srcDst) &&
configObject.srcDst.length > 0) {
const srcDstArray = configObject.srcDst; const srcDstArray = configObject.srcDst;
srcDstArray.forEach((item) => { srcDstArray.forEach((item) => {
if ((item === null || item === void 0 ? void 0 : item.src) && (item === null || item === void 0 ? void 0 : item.dst) && typeof item.src === "string" && typeof item.dst === "string") { if ((item === null || item === void 0 ? void 0 : item.src) &&
(item === null || item === void 0 ? void 0 : item.dst) &&
typeof item.src === "string" &&
typeof item.dst === "string") {
srcArray.push(item.src); srcArray.push(item.src);
dstArray.push(item.dst); dstArray.push(item.dst);
} }
@ -46,10 +59,13 @@ const grabSrcDisStrings = () => {
} }
} }
else { else {
if (process.argv.indexOf("--src") >= 0 && process.argv.indexOf("--dst") >= 0) { if (process.argv.indexOf("--src") >= 0 &&
process.argv.indexOf("--dst") >= 0) {
try { try {
srcArray = process.argv[process.argv.indexOf("--src") + 1].split(","); srcArray =
dstArray = process.argv[process.argv.indexOf("--dst") + 1].split(","); process.argv[process.argv.indexOf("--src") + 1].split(",");
dstArray =
process.argv[process.argv.indexOf("--dst") + 1].split(",");
} }
catch (error) { } catch (error) { }
} }
@ -73,33 +89,44 @@ if (!sourceFile || !destinationFile) {
process.exit(); process.exit();
} }
function traverseFiles(src, dst) { function traverseFiles(src, dst) {
var _a;
const sourceFiles = src.split(","); const sourceFiles = src.split(",");
const dstFiles = dst.split(","); const dstFiles = dst.split(",");
for (let i = 0; i < sourceFiles.length; i++) { for (let i = 0; i < sourceFiles.length; i++) {
const srcFolder = sourceFiles[i]; const srcFolder = sourceFiles[i];
const dstFile = dstFiles[i]; const dstFile = dstFiles[i];
if ((srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\/[^\/]+\.[^\/]+$/)) && !(srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/))) { if ((srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\/[^\/]+\.[^\/]+$/)) &&
!(srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/))) {
console.log("- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file"); console.log("- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file");
process.exit(); process.exit();
} }
if (!fs_1.default.existsSync(srcFolder)) { if (!fs_1.default.existsSync(srcFolder)) {
if (srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/)) { if (srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/)) {
fs_1.default.mkdirSync(srcFolder.replace(/\/[^\/]+\.less$/, ""), { recursive: true }); fs_1.default.mkdirSync(srcFolder.replace(/\/[^\/]+\.less$/, ""), {
recursive: true,
});
fs_1.default.writeFileSync(srcFolder, "", "utf-8"); fs_1.default.writeFileSync(srcFolder, "", "utf-8");
} }
else { else {
fs_1.default.mkdirSync(srcFolder.replace(/\/[^\/]+\.[^\/]+$/, ""), { recursive: true }); fs_1.default.mkdirSync(srcFolder.replace(/\/[^\/]+\.[^\/]+$/, ""), {
recursive: true,
});
fs_1.default.writeFileSync((srcFolder + "/main.less").replace(/\/\//g, ""), "", "utf-8"); fs_1.default.writeFileSync((srcFolder + "/main.less").replace(/\/\//g, ""), "", "utf-8");
} }
} }
else if (fs_1.default.existsSync(srcFolder) && fs_1.default.existsSync((srcFolder + "/main.less").replace(/\/\//g, ""))) { else if (fs_1.default.existsSync(srcFolder) &&
fs_1.default.existsSync((srcFolder + "/main.less").replace(/\/\//g, ""))) {
} }
if (!fs_1.default.existsSync(dstFile)) { if (!fs_1.default.existsSync(dstFile)) {
if (dstFile === null || dstFile === void 0 ? void 0 : dstFile.match(/\.css$/)) { if (dstFile === null || dstFile === void 0 ? void 0 : dstFile.match(/\.css$/)) {
fs_1.default.mkdirSync(dstFile.replace(/\/[^\/]+\.css$/, ""), { recursive: true }); fs_1.default.mkdirSync(dstFile.replace(/\/[^\/]+\.css$/, ""), {
recursive: true,
});
} }
else { else {
fs_1.default.mkdirSync(dstFile.replace(/\/[^\/]+\.[^\/]+$/, ""), { recursive: true }); fs_1.default.mkdirSync(dstFile.replace(/\/[^\/]+\.[^\/]+$/, ""), {
recursive: true,
});
} }
} }
compile(srcFolder, dstFile, null); compile(srcFolder, dstFile, null);
@ -113,7 +140,9 @@ function traverseFiles(src, dst) {
catch (error) { } catch (error) { }
if (srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/)) { if (srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.less$/)) {
fs_1.default.watchFile(srcFolder, { interval: 500 }, (current, previous) => { fs_1.default.watchFile(srcFolder, { interval: 500 }, (current, previous) => {
const dstFilePathRoot = (dstFile === null || dstFile === void 0 ? void 0 : dstFile.match(/\.css$/)) ? dstFile : dstFile + "/" + "_main.css"; const dstFilePathRoot = (dstFile === null || dstFile === void 0 ? void 0 : dstFile.match(/\.css$/))
? dstFile
: dstFile + "/" + "_main.css";
try { try {
const currentProcessArgsSrc = process.argv[process.argv.indexOf("--src") + 1]; const currentProcessArgsSrc = process.argv[process.argv.indexOf("--src") + 1];
const activeSourceFiles = currentProcessArgsSrc.split(","); const activeSourceFiles = currentProcessArgsSrc.split(",");
@ -130,7 +159,11 @@ function traverseFiles(src, dst) {
}); });
} }
else if (!(srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.[^\/]+$/))) { else if (!(srcFolder === null || srcFolder === void 0 ? void 0 : srcFolder.match(/\.[^\/]+$/))) {
fs_1.default.watch(srcFolder, { recursive: true }, (evtType, fileName) => { fs_1.default.watch(srcFolder, {
recursive: ((_a = process.platform) === null || _a === void 0 ? void 0 : _a.match(/win/i))
? true
: undefined,
}, (evtType, fileName) => {
if (!(evtType === null || evtType === void 0 ? void 0 : evtType.match(/change/i))) { if (!(evtType === null || evtType === void 0 ? void 0 : evtType.match(/change/i))) {
return; return;
} }
@ -143,7 +176,8 @@ function traverseFiles(src, dst) {
if (fileName === null || fileName === void 0 ? void 0 : fileName.match(/^\[/)) { if (fileName === null || fileName === void 0 ? void 0 : fileName.match(/^\[/)) {
compile(srcFolder + "/" + fileName, dstFile, evtType); compile(srcFolder + "/" + fileName, dstFile, evtType);
} }
else if ((fileName === null || fileName === void 0 ? void 0 : fileName.match(/^\(/)) || activeSourceFiles.includes(srcFilePathRoot)) { else if ((fileName === null || fileName === void 0 ? void 0 : fileName.match(/^\(/)) ||
activeSourceFiles.includes(srcFilePathRoot)) {
return; return;
} }
else { else {
@ -163,10 +197,13 @@ function traverseFiles(src, dst) {
} }
traverseFiles(sourceFile, destinationFile); traverseFiles(sourceFile, destinationFile);
function compile(fileName, dst, evtType) { function compile(fileName, dst, evtType) {
if ((fileName === null || fileName === void 0 ? void 0 : fileName.match(/\(/)) || (fileName.match(/\.[\/]$/) && !(fileName === null || fileName === void 0 ? void 0 : fileName.match(/\.less$/i)))) { if ((fileName === null || fileName === void 0 ? void 0 : fileName.match(/\(/)) ||
(fileName.match(/\.[\/]$/) && !(fileName === null || fileName === void 0 ? void 0 : fileName.match(/\.less$/i)))) {
return; return;
} }
let finalSrcPath = (fileName === null || fileName === void 0 ? void 0 : fileName.match(/\.less$/)) ? fileName : `${fileName}/main.less`; let finalSrcPath = (fileName === null || fileName === void 0 ? void 0 : fileName.match(/\.less$/))
? fileName
: `${fileName}/main.less`;
const distFolder = (dst === null || dst === void 0 ? void 0 : dst.match(/\.css$/)) ? null : dst === null || dst === void 0 ? void 0 : dst.replace(/\/+$/, ""); const distFolder = (dst === null || dst === void 0 ? void 0 : dst.match(/\.css$/)) ? null : dst === null || dst === void 0 ? void 0 : dst.replace(/\/+$/, "");
let finalDstPath = distFolder ? `${distFolder}/_main.css` : dst; let finalDstPath = distFolder ? `${distFolder}/_main.css` : dst;
if (distFolder && !fs_1.default.existsSync(distFolder)) { if (distFolder && !fs_1.default.existsSync(distFolder)) {
@ -175,7 +212,9 @@ function compile(fileName, dst, evtType) {
if (fileName === null || fileName === void 0 ? void 0 : fileName.match(/\[/)) { if (fileName === null || fileName === void 0 ? void 0 : fileName.match(/\[/)) {
const paths = fileName.split("/"); const paths = fileName.split("/");
const targetPathFull = paths[paths.length - 1]; const targetPathFull = paths[paths.length - 1];
const targetPath = targetPathFull.replace(/\[|\]/g, "").replace(/\.less/, ""); const targetPath = targetPathFull
.replace(/\[|\]/g, "")
.replace(/\.less/, "");
const destinationFileParentFolder = dst.replace(/\/[^\/]+\.css$/, ""); const destinationFileParentFolder = dst.replace(/\/[^\/]+\.css$/, "");
const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`; const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`;
finalSrcPath = fileName; finalSrcPath = fileName;
@ -185,7 +224,9 @@ function compile(fileName, dst, evtType) {
(0, child_process_1.exec)(executionCmd, (error, stdout, stderr) => { (0, child_process_1.exec)(executionCmd, (error, stdout, stderr) => {
if (error) { if (error) {
console.log("- \x1b[33mWarn:\x1b[0m Compilation didn't run successfully. ERROR =>", error.message); console.log("- \x1b[33mWarn:\x1b[0m Compilation didn't run successfully. ERROR =>", error.message);
if (!(evtType === null || evtType === void 0 ? void 0 : evtType.match(/change/i)) && fileName && fileName.match(/\[/)) { if (!(evtType === null || evtType === void 0 ? void 0 : evtType.match(/change/i)) &&
fileName &&
fileName.match(/\[/)) {
fs_1.default.unlinkSync(finalDstPath); fs_1.default.unlinkSync(finalDstPath);
} }
return; return;
@ -197,7 +238,8 @@ if (fs_1.default.existsSync("./lesscw.config.json")) {
fs_1.default.watchFile("./lesscw.config.json", { interval: 500 }, (evtType, fileName) => { fs_1.default.watchFile("./lesscw.config.json", { interval: 500 }, (evtType, fileName) => {
console.log("- \x1b[34mInfo:\x1b[0m Restarting process..."); console.log("- \x1b[34mInfo:\x1b[0m Restarting process...");
const newSrcDistStrings = grabSrcDisStrings(); const newSrcDistStrings = grabSrcDisStrings();
if (newSrcDistStrings.destinationFile && newSrcDistStrings.sourceFile) { if (newSrcDistStrings.destinationFile &&
newSrcDistStrings.sourceFile) {
process.argv.push("--src", newSrcDistStrings.sourceFile, "--dst", newSrcDistStrings.destinationFile); process.argv.push("--src", newSrcDistStrings.sourceFile, "--dst", newSrcDistStrings.destinationFile);
traverseFiles(newSrcDistStrings.sourceFile, newSrcDistStrings.destinationFile); traverseFiles(newSrcDistStrings.sourceFile, newSrcDistStrings.destinationFile);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "lessc-watcher", "name": "lessc-watcher",
"version": "1.1.9", "version": "1.2.0",
"description": "A minimal package to watch less files and compile them to css", "description": "A minimal package to watch less files and compile them to css",
"main": "dist/index.js", "main": "dist/index.js",
"bin": { "bin": {

16
src/index.d.ts vendored
View File

@ -1,8 +1,8 @@
export type LessCssWatcherConfigObject = { export type LessCssWatcherConfigObject = {
src?: string | string[]; src?: string | string[];
dst?: string | string[]; dst?: string | string[];
srcDst?: { srcDst?: {
src?: string; src?: string;
dst?: string; dst?: string;
}[]; }[];
}; };

View File

@ -1,260 +1,374 @@
#! /usr/bin/env node #! /usr/bin/env node
import fs from "fs"; import fs from "fs";
import { exec } from "child_process"; import { exec } from "child_process";
import { LessCssWatcherConfigObject } from "./index.d"; import { LessCssWatcherConfigObject } from "./index.d";
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
const grabSrcDisStrings = () => { const grabSrcDisStrings = () => {
let srcArray: string[] = []; let srcArray: string[] = [];
let dstArray: string[] = []; let dstArray: string[] = [];
if (fs.existsSync("./lesscw.config.json")) { if (fs.existsSync("./lesscw.config.json")) {
if (process.argv.indexOf("--src")) { if (process.argv.indexOf("--src")) {
try { try {
process.argv.splice(process.argv.indexOf("--src")); process.argv.splice(process.argv.indexOf("--src"));
} catch (error) {} } catch (error) {}
} }
try { try {
const configObject: LessCssWatcherConfigObject = JSON.parse(fs.readFileSync("./lesscw.config.json", "utf-8")); const configObject: LessCssWatcherConfigObject = JSON.parse(
fs.readFileSync("./lesscw.config.json", "utf-8")
if (configObject?.src && configObject?.dst && typeof configObject.src === "string" && typeof configObject.dst === "string") { );
srcArray = configObject.src.split(",");
dstArray = configObject.dst.split(","); if (
} else if (configObject?.src && configObject?.dst && typeof configObject.src === "object" && typeof configObject.dst === "object" && Array.isArray(configObject.src) && Array.isArray(configObject.dst)) { configObject?.src &&
srcArray = configObject.src; configObject?.dst &&
dstArray = configObject.dst; typeof configObject.src === "string" &&
} else if (configObject?.srcDst && Array.isArray(configObject.srcDst) && configObject.srcDst.length > 0) { typeof configObject.dst === "string"
const srcDstArray = configObject.srcDst; ) {
srcArray = configObject.src.split(",");
srcDstArray.forEach((item) => { dstArray = configObject.dst.split(",");
if (item?.src && item?.dst && typeof item.src === "string" && typeof item.dst === "string") { } else if (
srcArray.push(item.src); configObject?.src &&
dstArray.push(item.dst); configObject?.dst &&
} typeof configObject.src === "object" &&
}); typeof configObject.dst === "object" &&
} else { Array.isArray(configObject.src) &&
console.log("- \x1b[31mERROR:\x1b[0m Your config file has some errors. Please check your config file"); Array.isArray(configObject.dst)
process.exit(); ) {
} srcArray = configObject.src;
} catch (error: any) { dstArray = configObject.dst;
console.log("- \x1b[31mERROR:\x1b[0m Your config file has some errors. ERROR =>", error.message); } else if (
process.exit(); configObject?.srcDst &&
} Array.isArray(configObject.srcDst) &&
} else { configObject.srcDst.length > 0
if (process.argv.indexOf("--src") >= 0 && process.argv.indexOf("--dst") >= 0) { ) {
try { const srcDstArray = configObject.srcDst;
srcArray = process.argv[process.argv.indexOf("--src") + 1].split(",");
dstArray = process.argv[process.argv.indexOf("--dst") + 1].split(","); srcDstArray.forEach((item) => {
} catch (error) {} if (
} else { item?.src &&
console.log("- \x1b[31mERROR:\x1b[0m Missing source or destination file"); item?.dst &&
process.exit(); typeof item.src === "string" &&
} typeof item.dst === "string"
} ) {
srcArray.push(item.src);
////////////////////////////////////////////////////////////////////////////// dstArray.push(item.dst);
////////////////////////////////////////////////////////////////////////////// }
////////////////////////////////////////////////////////////////////////////// });
} else {
return { console.log(
sourceFile: srcArray.join(","), "- \x1b[31mERROR:\x1b[0m Your config file has some errors. Please check your config file"
destinationFile: dstArray.join(","), );
}; process.exit();
}; }
} catch (error: any) {
const { sourceFile, destinationFile } = grabSrcDisStrings(); console.log(
"- \x1b[31mERROR:\x1b[0m Your config file has some errors. ERROR =>",
if (sourceFile && destinationFile) { error.message
process.argv.push("--src", sourceFile, "--dst", destinationFile); );
} process.exit();
}
////////////////////////////////////////////////////////////////////////////// } else {
////////////////////////////////////////////////////////////////////////////// if (
////////////////////////////////////////////////////////////////////////////// process.argv.indexOf("--src") >= 0 &&
process.argv.indexOf("--dst") >= 0
console.log("- \x1b[35mStart:\x1b[0m Running Less compiler ..."); ) {
try {
if (!sourceFile || !destinationFile) { srcArray =
console.log("- \x1b[31mERROR:\x1b[0m => Missing source or destination file"); process.argv[process.argv.indexOf("--src") + 1].split(",");
process.exit(); dstArray =
} process.argv[process.argv.indexOf("--dst") + 1].split(",");
} catch (error) {}
////////////////////////////////////////////////////////////////////////////// } else {
////////////////////////////////////////////////////////////////////////////// console.log(
////////////////////////////////////////////////////////////////////////////// "- \x1b[31mERROR:\x1b[0m Missing source or destination file"
);
/** process.exit();
* Loop through source files and destination files and run the compile function }
*/ }
function traverseFiles(src: string, dst: string) {
const sourceFiles = src.split(","); //////////////////////////////////////////////////////////////////////////////
const dstFiles = dst.split(","); //////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
for (let i = 0; i < sourceFiles.length; i++) {
const srcFolder = sourceFiles[i]; return {
const dstFile = dstFiles[i]; sourceFile: srcArray.join(","),
destinationFile: dstArray.join(","),
if (srcFolder?.match(/\/[^\/]+\.[^\/]+$/) && !srcFolder?.match(/\.less$/)) { };
console.log("- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file"); };
process.exit();
} const { sourceFile, destinationFile } = grabSrcDisStrings();
if (!fs.existsSync(srcFolder)) { if (sourceFile && destinationFile) {
if (srcFolder?.match(/\.less$/)) { process.argv.push("--src", sourceFile, "--dst", destinationFile);
fs.mkdirSync(srcFolder.replace(/\/[^\/]+\.less$/, ""), { recursive: true }); }
fs.writeFileSync(srcFolder, "", "utf-8");
} else { //////////////////////////////////////////////////////////////////////////////
fs.mkdirSync(srcFolder.replace(/\/[^\/]+\.[^\/]+$/, ""), { recursive: true }); //////////////////////////////////////////////////////////////////////////////
fs.writeFileSync((srcFolder + "/main.less").replace(/\/\//g, ""), "", "utf-8"); //////////////////////////////////////////////////////////////////////////////
}
} else if (fs.existsSync(srcFolder) && fs.existsSync((srcFolder + "/main.less").replace(/\/\//g, ""))) { console.log("- \x1b[35mStart:\x1b[0m Running Less compiler ...");
}
if (!sourceFile || !destinationFile) {
if (!fs.existsSync(dstFile)) { console.log(
if (dstFile?.match(/\.css$/)) { "- \x1b[31mERROR:\x1b[0m => Missing source or destination file"
fs.mkdirSync(dstFile.replace(/\/[^\/]+\.css$/, ""), { recursive: true }); );
} else { process.exit();
fs.mkdirSync(dstFile.replace(/\/[^\/]+\.[^\/]+$/, ""), { recursive: true }); }
}
} //////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
compile(srcFolder, dstFile, null); //////////////////////////////////////////////////////////////////////////////
try { /**
fs.readdirSync(srcFolder).forEach((file) => { * Loop through source files and destination files and run the compile function
if (file?.match(/^\[.*\.less$/)) { */
compile(srcFolder + "/" + file, dstFile, null); function traverseFiles(src: string, dst: string) {
} const sourceFiles = src.split(",");
}); const dstFiles = dst.split(",");
} catch (error) {}
for (let i = 0; i < sourceFiles.length; i++) {
if (srcFolder?.match(/\.less$/)) { const srcFolder = sourceFiles[i];
fs.watchFile(srcFolder, { interval: 500 }, (current, previous) => { const dstFile = dstFiles[i];
const dstFilePathRoot = dstFile?.match(/\.css$/) ? dstFile : dstFile + "/" + "_main.css";
if (
try { srcFolder?.match(/\/[^\/]+\.[^\/]+$/) &&
const currentProcessArgsSrc = process.argv[process.argv.indexOf("--src") + 1]; !srcFolder?.match(/\.less$/)
const activeSourceFiles = currentProcessArgsSrc.split(","); ) {
console.log(
if (activeSourceFiles.includes(srcFolder)) { "- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file"
compile(srcFolder, dstFilePathRoot, null); );
} else { process.exit();
fs.unwatchFile(srcFolder); }
}
} catch (error: any) { if (!fs.existsSync(srcFolder)) {
console.log("- \x1b[31mERROR:\x1b[0m Please check your config file =>", error.message); if (srcFolder?.match(/\.less$/)) {
} fs.mkdirSync(srcFolder.replace(/\/[^\/]+\.less$/, ""), {
}); recursive: true,
} else if (!srcFolder?.match(/\.[^\/]+$/)) { });
fs.watch(srcFolder, { recursive: true }, (evtType, fileName) => { fs.writeFileSync(srcFolder, "", "utf-8");
if (!evtType?.match(/change/i)) { } else {
return; fs.mkdirSync(srcFolder.replace(/\/[^\/]+\.[^\/]+$/, ""), {
} recursive: true,
});
if (!fileName) return; fs.writeFileSync(
(srcFolder + "/main.less").replace(/\/\//g, ""),
const srcFilePathRoot = srcFolder + "/main.less"; "",
"utf-8"
try { );
const currentProcessArgsSrc = process.argv[process.argv.indexOf("--src") + 1]; }
const activeSourceFiles = currentProcessArgsSrc.split(","); } else if (
fs.existsSync(srcFolder) &&
if (fileName?.match(/^\[/)) { fs.existsSync((srcFolder + "/main.less").replace(/\/\//g, ""))
compile(srcFolder + "/" + fileName, dstFile, evtType); ) {
} else if (fileName?.match(/^\(/) || activeSourceFiles.includes(srcFilePathRoot)) { }
return;
} else { if (!fs.existsSync(dstFile)) {
compile(srcFilePathRoot, dstFile, evtType); if (dstFile?.match(/\.css$/)) {
} fs.mkdirSync(dstFile.replace(/\/[^\/]+\.css$/, ""), {
} catch (error: any) { recursive: true,
console.log("- \x1b[31mERROR:\x1b[0m Please check your config file =>", error.message); });
} } else {
}); fs.mkdirSync(dstFile.replace(/\/[^\/]+\.[^\/]+$/, ""), {
} else { recursive: true,
console.log("- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file"); });
process.exit(); }
} }
}
} compile(srcFolder, dstFile, null);
traverseFiles(sourceFile, destinationFile); try {
fs.readdirSync(srcFolder).forEach((file) => {
////////////////////////////////////////////////////////////////////////////// if (file?.match(/^\[.*\.less$/)) {
////////////////////////////////////////////////////////////////////////////// compile(srcFolder + "/" + file, dstFile, null);
////////////////////////////////////////////////////////////////////////////// }
});
/** } catch (error) {}
* Compile less file to css function
* @param fileName - less file path or folder path if (srcFolder?.match(/\.less$/)) {
* @param dst - destination file path or folder path fs.watchFile(srcFolder, { interval: 500 }, (current, previous) => {
* @param evtType - event type (change, rename, etc.) or null const dstFilePathRoot = dstFile?.match(/\.css$/)
* @returns ? dstFile
*/ : dstFile + "/" + "_main.css";
function compile(fileName: string, dst: string, evtType: string | null) {
if (fileName?.match(/\(/) || (fileName.match(/\.[\/]$/) && !fileName?.match(/\.less$/i))) { try {
return; const currentProcessArgsSrc =
} process.argv[process.argv.indexOf("--src") + 1];
const activeSourceFiles = currentProcessArgsSrc.split(",");
let finalSrcPath = fileName?.match(/\.less$/) ? fileName : `${fileName}/main.less`;
const distFolder = dst?.match(/\.css$/) ? null : dst?.replace(/\/+$/, ""); if (activeSourceFiles.includes(srcFolder)) {
let finalDstPath = distFolder ? `${distFolder}/_main.css` : dst; compile(srcFolder, dstFilePathRoot, null);
} else {
if (distFolder && !fs.existsSync(distFolder)) { fs.unwatchFile(srcFolder);
fs.mkdirSync(distFolder, { recursive: true }); }
} } catch (error: any) {
console.log(
if (fileName?.match(/\[/)) { "- \x1b[31mERROR:\x1b[0m Please check your config file =>",
const paths = fileName.split("/"); error.message
const targetPathFull = paths[paths.length - 1]; );
const targetPath = targetPathFull.replace(/\[|\]/g, "").replace(/\.less/, ""); }
});
const destinationFileParentFolder = dst.replace(/\/[^\/]+\.css$/, ""); } else if (!srcFolder?.match(/\.[^\/]+$/)) {
fs.watch(
const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`; srcFolder,
{
finalSrcPath = fileName; recursive: process.platform?.match(/win/i)
finalDstPath = targetDstFilePath; ? true
} : undefined,
},
const executionCmd = `lessc ${finalSrcPath} ${finalDstPath}`; (evtType, fileName) => {
if (!evtType?.match(/change/i)) {
exec(executionCmd, (error, stdout, stderr) => { return;
/** @type {Error} */ }
if (error) {
console.log("- \x1b[33mWarn:\x1b[0m Compilation didn't run successfully. ERROR =>", error.message); if (!fileName) return;
if (!evtType?.match(/change/i) && fileName && fileName.match(/\[/)) { const srcFilePathRoot = srcFolder + "/main.less";
fs.unlinkSync(finalDstPath);
} try {
const currentProcessArgsSrc =
return; process.argv[process.argv.indexOf("--src") + 1];
} const activeSourceFiles =
currentProcessArgsSrc.split(",");
console.log("- \x1b[32mCompiled:\x1b[0m Less Compilation Successful!");
}); if (fileName?.match(/^\[/)) {
} compile(
srcFolder + "/" + fileName,
////////////////////////////////////////////////////////////////////////////// dstFile,
////////////////////////////////////////////////////////////////////////////// evtType
////////////////////////////////////////////////////////////////////////////// );
} else if (
/** fileName?.match(/^\(/) ||
* watch for changes to the config file activeSourceFiles.includes(srcFilePathRoot)
*/ ) {
if (fs.existsSync("./lesscw.config.json")) { return;
fs.watchFile("./lesscw.config.json", { interval: 500 }, (evtType, fileName) => { } else {
console.log("- \x1b[34mInfo:\x1b[0m Restarting process..."); compile(srcFilePathRoot, dstFile, evtType);
}
const newSrcDistStrings = grabSrcDisStrings(); } catch (error: any) {
console.log(
if (newSrcDistStrings.destinationFile && newSrcDistStrings.sourceFile) { "- \x1b[31mERROR:\x1b[0m Please check your config file =>",
process.argv.push("--src", newSrcDistStrings.sourceFile, "--dst", newSrcDistStrings.destinationFile); error.message
traverseFiles(newSrcDistStrings.sourceFile, newSrcDistStrings.destinationFile); );
} }
}); }
} );
} else {
console.log(
"- \x1b[31mERROR:\x1b[0m Source must be a folder or a .less file"
);
process.exit();
}
}
}
traverseFiles(sourceFile, destinationFile);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* Compile less file to css function
* @param fileName - less file path or folder path
* @param dst - destination file path or folder path
* @param evtType - event type (change, rename, etc.) or null
* @returns
*/
function compile(fileName: string, dst: string, evtType: string | null) {
if (
fileName?.match(/\(/) ||
(fileName.match(/\.[\/]$/) && !fileName?.match(/\.less$/i))
) {
return;
}
let finalSrcPath = fileName?.match(/\.less$/)
? fileName
: `${fileName}/main.less`;
const distFolder = dst?.match(/\.css$/) ? null : dst?.replace(/\/+$/, "");
let finalDstPath = distFolder ? `${distFolder}/_main.css` : dst;
if (distFolder && !fs.existsSync(distFolder)) {
fs.mkdirSync(distFolder, { recursive: true });
}
if (fileName?.match(/\[/)) {
const paths = fileName.split("/");
const targetPathFull = paths[paths.length - 1];
const targetPath = targetPathFull
.replace(/\[|\]/g, "")
.replace(/\.less/, "");
const destinationFileParentFolder = dst.replace(/\/[^\/]+\.css$/, "");
const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`;
finalSrcPath = fileName;
finalDstPath = targetDstFilePath;
}
const executionCmd = `lessc ${finalSrcPath} ${finalDstPath}`;
exec(executionCmd, (error, stdout, stderr) => {
/** @type {Error} */
if (error) {
console.log(
"- \x1b[33mWarn:\x1b[0m Compilation didn't run successfully. ERROR =>",
error.message
);
if (
!evtType?.match(/change/i) &&
fileName &&
fileName.match(/\[/)
) {
fs.unlinkSync(finalDstPath);
}
return;
}
console.log("- \x1b[32mCompiled:\x1b[0m Less Compilation Successful!");
});
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* watch for changes to the config file
*/
if (fs.existsSync("./lesscw.config.json")) {
fs.watchFile(
"./lesscw.config.json",
{ interval: 500 },
(evtType, fileName) => {
console.log("- \x1b[34mInfo:\x1b[0m Restarting process...");
const newSrcDistStrings = grabSrcDisStrings();
if (
newSrcDistStrings.destinationFile &&
newSrcDistStrings.sourceFile
) {
process.argv.push(
"--src",
newSrcDistStrings.sourceFile,
"--dst",
newSrcDistStrings.destinationFile
);
traverseFiles(
newSrcDistStrings.sourceFile,
newSrcDistStrings.destinationFile
);
}
}
);
}

View File

@ -1,13 +1,13 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2016", "target": "es2016",
"module": "commonjs", "module": "commonjs",
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"removeComments": true, "removeComments": true,
"esModuleInterop": true, "esModuleInterop": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,
"skipLibCheck": true "skipLibCheck": true
} }
} }