Socket
Socket
Sign inDemoInstall

flores

Package Overview
Dependencies
461
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.0 to 1.0.0-beta.0

src/get-markdown-output-info.js

23

package.json
{
"name": "flores",
"version": "0.1.0",
"version": "1.0.0-beta.0",
"description": "Minimalist static site generator.",

@@ -23,3 +23,8 @@ "keywords": [

},
"scripts": {},
"scripts": {
"lint": "eslint ./",
"lint-fix": "eslint ./ --fix",
"prepublishOnly": "npm run lint && npm run test",
"test": "jest"
},
"dependencies": {

@@ -47,5 +52,15 @@ "chokidar": "^2.0.4",

"postcss-preset-env": "^6.5.0",
"sitemap": "^2.1.0"
"sitemap": "^2.1.0",
"socket.io": "^2.2.0"
},
"devDependencies": {},
"devDependencies": {
"eslint": "^5.10.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.3.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-prettier": "^3.0.0",
"jest": "^23.6.0",
"jsdom": "^13.1.0",
"prettier": "^1.15.3"
},
"engines": {

@@ -52,0 +67,0 @@ "node": ">=8.0.0"

53

README.md

@@ -1,3 +0,6 @@

# Flores [WIP]
# Flores
[![Build Status](https://badgen.net/travis/risan/flores)](https://travis-ci.org/risan/flores)
[![Test Covarage](https://badgen.net/codecov/c/github/risan/flores)](https://codecov.io/gh/risan/flores)
[![Greenkeeper](https://badges.greenkeeper.io/risan/flores.svg)](https://greenkeeper.io)
[![Latest Version](https://badgen.net/npm/v/flores)](https://www.npmjs.com/package/flores)

@@ -19,3 +22,3 @@

(async () => {
await flores.build("/path/to/source");
await flores.build();
})();

@@ -28,6 +31,6 @@ ```

Build the site for production.
Generate the website.
```js
flores.build([basePath])
flores.build([options])
```

@@ -37,10 +40,10 @@

* `basePath` (`String`): The site source path, default to the current working directory.
* `options` (`Object`): The [configuration options](#configuration-options).
### `flores.serve`
Build the site and start the development server.
Generate the website and start the development server.
```js
flores.serve([basePath])
flores.serve([options])
```

@@ -50,10 +53,10 @@

* `basePath` (`String`): The site source path, default to the current working directory.
* `options` (`Object`): The [configuration options](#configuration-options).
### `flores.watch`
Start the development server and the file watcher.
Start the development server and watch for the file changes. It will automatically refresh the browser on file changes.
```js
flores.watch([basePath])
flores.watch([options])
```

@@ -63,6 +66,34 @@

* `basePath` (`String`): The site source path, default to the current working directory.
* `options` (`Object`): The [configuration options](#configuration-options).
### Configuration Options
Configuration options is an optional `Object` that you can pass to `build`, `serve`, or `watch` methods.
* **`env`** (`String`): The environment name, default to `process.env.NODE_ENV`. If the `NODE_ENV` environment variable is not set, `production` will be set. Note that for `serve` and `watch` methods, the `env` value will always be set to `development`.
* **`url`** (`String`): The website URL, default to `http://localhost:4000`.
* **`basePath`** (`String`): The base path of your website project directory, default to `process.cwd()`.
* **`sourceDir`** (`String`): The directory for the website source relative to the `basePath`, default to `src`.
* **`outputDir`** (`String`): The directory where the generated website will be stored relative to the `basePath`, default to `public`,
* **`templatesDir`** (`String`): The templates directory relative to the `sourceDir`, default to `templates`.
* **`assetsDir`** (`String`): The CSS assets directory relative to the `sourceDir`, default to `assets`.
* **`defaultTemplate`** (`String`): The default template name for the markdown post, default to `post.njk`. You can override the template for individual post by providing the `template` field on the post's front matter.
* **`defaultCollectionTemplate`** (`String`): The default template name for the markdown post collection page, default to `collection.njk`. You can override the template for individual post collection page by providing the `template` field on the page's front matter.
* **`copyFiles`** (`Array`): List of files or file patterns to copy, default to:
```js
["images/**", "robot.txt", "**/*.html"]`
```
* `postcssPresetEnv` (`Object`): [PostCSS Preset Env options](https://github.com/csstools/postcss-preset-env#options), default to:
```js
{
stage: 3,
preserve: false
}
```
## License
[MIT](https://github.com/risan/flores/blob/master/LICENSE) © [Risan Bagja Pradana](https://bagja.net)

@@ -1,3 +0,2 @@

const path = require("path");
/* eslint no-console: "off" */
const fs = require("fs-extra");

@@ -9,3 +8,2 @@

const processCssFiles = require("./process-css-files");
const processCollectionPages = require("./process-collection-pages");
const processMarkdownFiles = require("./process-markdown-files");

@@ -16,13 +14,13 @@ const Renderer = require("./renderer");

* Build the site.
* @param {String} basePath - The project base path.
* @param {Object} options - The site configuration options.
* @return {Object}
*/
const build = async (basePath = process.cwd()) => {
const config = new Config(basePath);
const build = async (options = {}) => {
const config = new Config(options);
console.log(`⏳ Generating website: ${config.outputDir}`);
console.log(`⏳ Generating website to: ${config.outputPath}`);
const renderer = new Renderer(config);
await fs.remove(config.outputDir);
await fs.remove(config.outputPath);

@@ -35,10 +33,10 @@ const assets = await processCssFiles(config);

const pages = await processMarkdownFiles({ config, renderer });
const { posts, collectionPages } = await processMarkdownFiles({
config,
renderer
});
const {
posts, collectionPages
} = await processCollectionPages(pages, { config, renderer });
console.log(`✅ ${posts.length} markdown posts are converted.`);
console.log(`✅ ${collectionPages.length} collection pages are generated.`);
console.log(`✅ ${pages.length} markdown files are converted.`);
const files = await copyStaticFiles(config);

@@ -45,0 +43,0 @@

const path = require("path");
const { URL } = require("url");
const PRODUCTION = "production";
const PROTOCOL = /^http[s]?:\/\//i;
const LEADING_SLASH = /^\//;
const TRAILING_SLASH = /\/$/;
const LEADING_AND_TRAILING_SLASHES = /(^\/|\/$)/g;

@@ -11,14 +13,12 @@

* Create new config instance.
* @param {String} basePath - The site base path.
* @param {Object} options - The site configuration options.
*/
constructor(basePath) {
this.basePath = basePath;
constructor(options = {}) {
this.options = { ...Config.defaultOptions, ...options };
this.data = this.formatData(
this.loadDataFromFile()
);
this.parseOptions(this.options);
return new Proxy(this, {
get(config, prop) {
return prop in config ? config[prop] : config.data[prop];
return prop in config ? config[prop] : config.options[prop];
}

@@ -29,2 +29,35 @@ });

/**
* Parse the config options.
* @param {Object} options - The config options.
* @return {Void}
*/
parseOptions(options) {
this.basePath = path.resolve(options.basePath);
this.sourcePath = path.resolve(this.basePath, options.sourceDir);
this.outputPath = path.resolve(this.basePath, options.outputDir);
this.templatesPath = path.resolve(this.sourcePath, options.templatesDir);
this.assetsPath = path.resolve(this.sourcePath, options.assetsDir);
this.url = PROTOCOL.test(options.url)
? options.url
: `http://${options.url}`;
const urlObj = new URL(this.url);
this.port = urlObj.port ? parseInt(urlObj.port, 10) : 4000;
if (this.isProduction()) {
this.origin = urlObj.origin;
const pathname = urlObj.pathname.replace(
LEADING_AND_TRAILING_SLASHES,
""
);
this.pathname = pathname ? `/${pathname}` : "";
} else {
this.origin = `http://localhost:${this.port}`;
this.pathname = "";
}
}
/**
* Get url for the given path.

@@ -40,4 +73,4 @@ * @param {String} p - The url path to generate.

return cleanRelativeUrl
? `${this.data.url}/${cleanRelativeUrl}`
: this.data.url;
? `${this.origin}/${cleanRelativeUrl}`
: this.origin;
}

@@ -51,7 +84,7 @@

getRelativeUrl(p = "/") {
const baseUrl = this.data.pathPrefix ? `${this.data.pathPrefix}/` : "/";
const pathPrefix = this.pathname ? `${this.pathname}/` : "/";
const cleanPath = p.replace(LEADING_SLASH, "");
return cleanPath ? baseUrl + cleanPath : baseUrl;
return cleanPath ? pathPrefix + cleanPath : pathPrefix;
}

@@ -64,82 +97,15 @@

isProduction() {
return this.data.env.toLowerCase() === "production";
return this.options.env.toLowerCase() === "production";
}
/**
* Format the config data.
* @param {Object} data - The config data.
* @return {Object} The formatted config data.
*/
formatData(data) {
// Directories.
data.sourceDir = this.resolvePath(data.sourceDir);
data.outputDir = this.resolvePath(data.outputDir);
data.templatesDir = path.resolve(data.sourceDir, data.templatesDir);
data.assetsDir = path.resolve(data.sourceDir, data.assetsDir);
if (data.env.toLowerCase() === "production") {
// url.
if (!PROTOCOL.test(data.url)) {
data.url = `http://${data.url}`;
}
data.url = data.url.replace(TRAILING_SLASH, "");
// Path prefix.
data.pathPrefix = data.pathPrefix.replace(
LEADING_AND_TRAILING_SLASHES, ""
);
if (data.pathPrefix) {
data.pathPrefix = `/${data.pathPrefix}`;
}
} else {
data.url = `${Config.defaultData.url}:${Config.defaultData.port}`;
data.pathPrefix = "";
}
return data;
}
/**
* Resolve the given path.
* @param {String} p - The path to resolve.
* @return {String} The resolved path.
*/
resolvePath(p) {
if (path.isAbsolute(p)) {
return p;
}
return path.resolve(this.basePath, p);
}
/**
* Load config data from file.
* @return {Object} The config data.
*/
loadDataFromFile() {
let data = {};
try {
const configFile = path.resolve(this.basePath, "site.config.js");
data = require(configFile);
} catch(error) {
//
}
return { ...Config.defaultData, ...data };
}
/**
* Default config data.
* Get the default config options.
* @return {Object}
*/
static get defaultData() {
static get defaultOptions() {
return {
env: process.env.NODE_ENV ? process.env.NODE_ENV : "production",
url: "http://localhost",
port: 4000,
pathPrefix: "",
env: process.env.NODE_ENV ? process.env.NODE_ENV : PRODUCTION,
watch: false,
url: "http://localhost:4000",
basePath: process.cwd(),
sourceDir: "src",

@@ -149,9 +115,5 @@ outputDir: "public",

assetsDir: "assets",
defaultTemplate: "post.html",
defaultCollectionTemplate: "collection.html",
copyFiles: [
"images/**",
"robot.txt",
"**/*.html"
],
defaultTemplate: "post.njk",
defaultCollectionTemplate: "collection.njk",
copyFiles: ["images/**", "robot.txt", "**/*.html"],
postcssPresetEnv: {

@@ -158,0 +120,0 @@ stage: 3,

@@ -13,9 +13,13 @@ const path = require("path");

const files = await globby(config.copyFiles, {
cwd: config.sourceDir
cwd: config.sourcePath
});
await Promise.all(files.map(file => fs.copy(
path.join(config.sourceDir, file),
path.join(config.outputDir, file)
)));
await Promise.all(
files.map(file =>
fs.copy(
path.join(config.sourcePath, file),
path.join(config.outputPath, file)
)
)
);

@@ -22,0 +26,0 @@ return files;

@@ -19,6 +19,6 @@ const path = require("path");

let obj = {
const obj = {
url: page.url,
...defaultValue,
...get(page, "frontMatter.sitemap", {}),
...get(page, "frontMatter.sitemap", {})
};

@@ -28,3 +28,3 @@

obj.lastmodISO = page.frontMatter.modifiedAt.toISOString();
} else if(has(page, "frontMatter.date")) {
} else if (has(page, "frontMatter.date")) {
obj.lastmodISO = page.frontMatter.date.toISOString();

@@ -45,4 +45,4 @@ }

const postUrls = posts.map(post => formatSiteMapItem(post));
const collectionPageUrls = collectionPages.map(
page => formatSiteMapItem(page, {
const collectionPageUrls = collectionPages.map(page =>
formatSiteMapItem(page, {
changefreq: "daily"

@@ -54,13 +54,10 @@ })

hostname: config.url,
urls: [
...collectionPageUrls.filter(Boolean),
...postUrls.filter(Boolean)
]
urls: [...collectionPageUrls.filter(Boolean), ...postUrls.filter(Boolean)]
});
const outputPath = path.join(config.outputDir, "sitemap.xml");
const sitemapPath = path.join(config.outputPath, "sitemap.xml");
return await fs.outputFile(outputPath, sitemap.toString());
return fs.outputFile(sitemapPath, sitemap.toString());
};
module.exports = generateSitemap;

@@ -7,14 +7,16 @@ const fm = require("front-matter");

md.use(mdAnchor, { permalink: true, permalinkBefore: true })
.use(mdToc, {
containerHeaderHtml: "<h2>Table of Contents</h2>",
includeLevel: [2, 3, 4, 5]
});
const getMarkdownOutputInfo = require("./get-markdown-output-info");
md.use(mdAnchor, { permalink: true, permalinkBefore: true }).use(mdToc, {
containerHeaderHtml: "<h2>Table of Contents</h2>",
includeLevel: [2, 3, 4, 5]
});
/**
* Parse markdown file.
* @param {String} path - The markdown file path to parse.
* @return {Object} Return the frontMatter and the rendered HTML.
* @param {Object} config - The Config instance.
* @return {Object} Return the frontMatter, the rendered HTML, and output info.
*/
const parseMarkdownFile = async path => {
const parseMarkdownFile = async (path, config) => {
const source = await fs.readFile(path, "utf8");

@@ -24,5 +26,8 @@

const outputInfo = getMarkdownOutputInfo(path, config);
return {
frontMatter: attributes,
html: md.render(body)
content: md.render(body),
...outputInfo
};

@@ -29,0 +34,0 @@ };

@@ -19,7 +19,7 @@ const crypto = require("crypto");

const relativePath = path.relative(config.sourceDir, file);
let outputPath = path.join(config.outputDir, relativePath);
const relativePath = path.relative(config.sourcePath, file);
let outputPath = path.join(config.outputPath, relativePath);
const processor = postcss([
atImport,
atImport({ path: [config.assetsPath] }),
presetEnv(config.postcssPresetEnv)

@@ -33,4 +33,3 @@ ]);

const result = await processor.process(css, {
from: path.relative(config.basePath, file),
to: path.relative(config.basePath, outputPath),
from: file,
map: !config.isProduction()

@@ -42,3 +41,3 @@ });

hash.update(css);
hash.update(result.css);

@@ -45,0 +44,0 @@ const outputHash = hash.digest("hex").substring(0, 10);

@@ -15,3 +15,3 @@ const path = require("path");

const sourceFiles = await globby("**/[^_]*.css", {
cwd: config.assetsDir,
cwd: config.assetsPath,
absolute: true

@@ -24,8 +24,8 @@ });

const sourceNames = sourceFiles.map(
file => path.relative(config.assetsDir, file)
const sourceNames = sourceFiles.map(file =>
path.relative(config.assetsPath, file)
);
const outputRelativeUrls = outputFiles.map(
file => config.getRelativeUrl(path.relative(config.outputDir, file))
const outputRelativeUrls = outputFiles.map(file =>
config.getRelativeUrl(path.relative(config.outputPath, file))
);

@@ -32,0 +32,0 @@

@@ -1,20 +0,56 @@

const globby = require("globby");
const processMarkdownFile = require("./process-markdown-file");
const parseMarkdownFiles = require("./parse-markdown-files");
/**
* Write the page.
* @param {Object} page - The page data.
* @param {Config} options.config - The Config instance.
* @param {Renderer} options.renderer - The Renderer instance.
* @param {Object} options.data - All website pages data.
* @return {Promise}
*/
const writePage = async (page, { config, renderer, data }) => {
const defaultTemplate = page.frontMatter.collection
? config.defaultCollectionTemplate
: config.defaultTemplate;
const template = page.frontMatter.template
? page.frontMatter.template
: defaultTemplate;
return renderer.writeHtml(page.outputPath, template, {
...data,
...page,
collection: data.collections[page.collectionName]
});
};
/**
* Process all markdown files.
* @param {Config} options.config - The Config instance.
* @param {Renderer} options.renderer - The Renderer instance.
* @return {Array}
* @return {Object}
*/
const processMarkdownFiles = async ({ config, renderer }) => {
const files = await globby("**/*.(md|markdown)", {
cwd: config.sourceDir,
absolute: true
});
const data = await parseMarkdownFiles(config);
const data = await Promise.all(
files.map(file => processMarkdownFile(file, { config, renderer }))
await Promise.all(
data.posts.map(page =>
writePage(page, {
config,
renderer,
data
})
)
);
await Promise.all(
data.collectionPages.map(page =>
writePage(page, {
config,
renderer,
data
})
)
);
return data;

@@ -21,0 +57,0 @@ };

@@ -13,5 +13,3 @@ const fs = require("fs-extra");

this.config = config;
this.env = nunjucks.configure(config.templatesDir, {
noCache: !config.isProduction()
});
this.env = nunjucks.configure(config.templatesPath);

@@ -36,7 +34,27 @@ this.env.addGlobal("config", this.config);

render(template, data = {}) {
return this.env.render(template, data);
let str = this.env.render(template, data);
if (this.config.isProduction()) {
str = minifier.minify(str, {
collapseWhitespace: true,
removeComments: true
});
}
if (this.config.watch) {
str = str.replace(
/(<\/body[\s]*>)/i,
`
<script src="/socket.io/socket.io.js"></script>
<script src="/flores/socket-client.js"></script>
$1
`
);
}
return str;
}
/**
* Render the template and write to file.
* Render the template and write it to a file.
* @param {String} outputPath - The path to save the file.

@@ -48,11 +66,4 @@ * @param {String} template - The template to render.

async writeHtml(outputPath, template, data = {}) {
let str = this.render(template, data);
const str = this.render(template, data);
if (this.config.isProduction()) {
str = minifier.minify(str, {
collapseWhitespace: true,
removeComments: true
});
}
await fs.outputFile(outputPath, str);

@@ -62,4 +73,14 @@

}
/**
* Clear the compiled template cache.
* @return {Void}
*/
clearCache() {
for (let i = 0; i < this.env.loaders.length; i += 1) {
this.env.loaders[i].cache = {};
}
}
}
module.exports = Renderer;

@@ -0,10 +1,13 @@

/* eslint no-console: "off" */
const express = require("express");
const SocketIo = require("socket.io");
/**
* Run the server.
* @param {String} options.publicDir - The directory to serve.
* @param {Number} options.port - The port to listen to.
* @param {String} options.publicDir - The directory to serve.
* @param {Number} options.port - The port to listen to.
* @param {Boolean} options.watch - Set to true to run watcher.
* @return {Promise}
*/
const runServer = ({ publicDir, port }) => {
const runServer = ({ publicDir, port, watch = false }) => {
const app = express();

@@ -14,7 +17,21 @@

return new Promise(resolve =>
app.listen(port, () => resolve(app, { publicDir, port }))
);
return new Promise(resolve => {
const server = app.listen(port, () => {
console.log(`⚡️ Server is running: http://localhost:${port}`);
if (watch) {
app.get("/flores/socket-client.js", (req, res) =>
res.sendFile(`${__dirname}/socket-client.js`)
);
const socketIo = new SocketIo(server);
resolve({ app, server, socketIo });
} else {
resolve({ app, server });
}
});
});
};
module.exports = runServer;

@@ -6,16 +6,14 @@ const build = require("./build");

* Serve the generated site.
* @param {String} basePath - The project base path.
* @param {Object} options - The configuration data.
* @return {Promise}
*/
const serve = async (basePath = process.cwd()) => {
const { config } = await build(basePath);
const serve = async (options = {}) => {
const { config } = await build({ ...options, env: "development" });
await runServer({
publicDir: config.outputDir,
runServer({
publicDir: config.outputPath,
port: config.port
});
console.log(`⚡️ Server is running: http://localhost:${config.port}`);
};
module.exports = serve;

@@ -0,1 +1,2 @@

/* eslint no-console: "off" */
const path = require("path");

@@ -11,8 +12,5 @@

const processCssFiles = require("./process-css-files");
const processCollectionPages = require("./process-collection-pages");
const processMarkdownFiles = require("./process-markdown-files");
const runServer = require("./run-server");
const EVENTS_TO_CATCH = ["change", "add", "unlink"];
const CSS_FILE = "css";

@@ -25,21 +23,33 @@ const MARKDOWN_FILE = "markdown";

const MARKDOWN_EXTENSIONS = [".md", ".markdown"];
const TEMPLATE_EXTENSIONS = [".html", ".njs"];
const TEMPLATE_EXTENSIONS = [".html", ".njk"];
/**
* Run the file watcher.
* @param {String} basePath - The project base path.
* @param {Object} options - The configuration data.
* @return {Promise}
*/
const watch = async (basePath = process.cwd()) => {
const { config, renderer } = await build(basePath);
const watch = async (options = {}) => {
const { config, renderer } = await build({
...options,
env: "development",
watch: true
});
await runServer({
publicDir: config.outputDir,
port: config.port
const { socketIo } = await runServer({
publicDir: config.outputPath,
port: config.port,
watch: true
});
console.log(`⚡️ Server is running: http://localhost:${config.port}`);
/**
* Reload the browser.
* @return {Void}
*/
const reloadBrowser = () => socketIo.emit("flores.reloadBrowser");
const assetsPath = path.relative(config.sourceDir, config.assetsDir) + "/";
const templatesPath = path.relative(config.sourceDir, config.templatesDir) + "/";
const assetsDir = `${path.relative(config.sourcePath, config.assetsPath)}/`;
const templatesDir = `${path.relative(
config.sourcePath,
config.templatesPath
)}/`;

@@ -56,3 +66,3 @@ /**

if (extension === CSS_EXTENSION && p.startsWith(assetsPath)) {
if (extension === CSS_EXTENSION && p.startsWith(assetsDir)) {
return CSS_FILE;

@@ -65,3 +75,3 @@ }

if (TEMPLATE_EXTENSIONS.includes(extension) && p.startsWith(templatesPath)) {
if (TEMPLATE_EXTENSIONS.includes(extension) && p.startsWith(templatesDir)) {
return TEMPLATE_FILE;

@@ -78,24 +88,32 @@ }

/**
* Get event message for logging.
* @param {String} options.event - The event type.
* @param {String} options.p - The file path.
* @param {String} options.fileType - The file type.
* @return {String}
* Process markdown files.
* @param {Boolean} options.clearCache - Set to true to clear the compiled template caches.
* @return {Promise}
*/
const getEventMessage = ({ event, p, fileType }) => {
switch (event) {
case "change":
return `✏️ ${fileType} file is updated: ${p}`;
case "add":
return `✨ New ${fileType} file: ${p}`;
case "unlink":
return `🔥 ${fileType} is deleted: ${p}`;
};
const processMarkdown = async ({ clearCache = false } = {}) => {
if (clearCache) {
renderer.clearCache();
}
const { posts, collectionPages } = await processMarkdownFiles({
config,
renderer
});
console.log(`✅ ${posts.length} markdown posts are converted.`);
console.log(`✅ ${collectionPages.length} collection pages are generated.`);
await generateSitemap({ config, posts, collectionPages });
console.log("✅ Sitemap is generated.");
reloadBrowser();
};
/**
* Handle css file change.
* Process css files.
* @param {Boolean} options.reprocessMarkdown - Set to true to reprocess the markdown files to.
* @return {Promise}
*/
const handleCssChange = async () => {
const processCss = async ({ reprocessMarkdown = false } = {}) => {
const assets = await processCssFiles(config);

@@ -107,47 +125,31 @@

await handleMarkdownOrTemplateChange();
if (reprocessMarkdown) {
await processMarkdown();
} else {
reloadBrowser();
}
};
/**
* Handle markdown or template change.
* Copy file to output directory.
* @param {String} p - The file path to copy.
* @return {Promise}
*/
const handleMarkdownOrTemplateChange = async () => {
const pages = await processMarkdownFiles({ config, renderer });
const copyFile = async p =>
fs.copy(path.join(config.sourcePath, p), path.join(config.outputPath, p));
const {
posts, collectionPages
} = await processCollectionPages(pages, { config, renderer });
console.log(`✅ ${pages.length} markdown files are converted.`);
await generateSitemap({ config, posts, collectionPages });
console.log("✅ Sitemap is generated.");
};
/**
* Handle static file change.
* @param {String} options.event - The event type.
* @param {String} options.p - The file path.
* Remove file from the output directory.
* @param {String} p - The file path to remove.
* @return {Promise}
*/
const handleStaticFileChange = async ({ event, p }) => {
if (["change", "add"].includes(event)) {
await fs.copy(
path.join(config.sourceDir, p),
path.join(config.outputDir, p)
);
} else if (event === "unlink") {
await fs.remove(path.join(config.outputDir, p));
}
};
const removeFile = async p => fs.remove(path.join(config.outputPath, p));
const handleCssChangeDebounced = debounce(handleCssChange, 1000);
const handleMarkdownOrTemplateChangeDebounced = debounce(handleMarkdownOrTemplateChange, 1000);
const processCssDebounced = debounce(processCss, 500);
const processMarkdownDebounced = debounce(processMarkdown, 500);
const watcher = chokidar.watch(".", {
ignored: /(^|[\/\\])\../,
ignored: /(^|[/\\])\../,
ignoreInitial: true,
cwd: config.sourceDir
cwd: config.sourcePath
});

@@ -157,7 +159,23 @@

watcher.on("all", async (event, p) => {
if (!EVENTS_TO_CATCH.includes(event)) {
watcher.on("change", async p => {
const fileType = getFileType(p);
if (fileType === null) {
return;
}
console.log(`✏️ ${fileType} file is updated: ${p}`);
if (fileType === CSS_FILE) {
processCssDebounced();
} else if (fileType === MARKDOWN_FILE) {
await processMarkdown();
} else if (fileType === TEMPLATE_FILE) {
processMarkdownDebounced({ clearCache: true });
} else {
await copyFile(p);
}
});
watcher.on("add", async p => {
const fileType = getFileType(p);

@@ -169,14 +187,32 @@

console.log(getEventMessage({ event, p, fileType }));
console.log(`✨ New ${fileType} file: ${p}`);
if (fileType === CSS_FILE) {
await handleCssChangeDebounced();
processCssDebounced({ reprocessMarkdown: true });
} else if ([MARKDOWN_FILE, TEMPLATE_FILE].includes(fileType)) {
await handleMarkdownOrTemplateChangeDebounced();
processMarkdownDebounced();
} else {
await handleStaticFileChange({ event, p });
await copyFile(p);
}
});
watcher.on("unlink", async p => {
const fileType = getFileType(p);
if (fileType === null) {
return;
}
console.log(`🔥 ${fileType} is deleted: ${p}`);
if (fileType === CSS_FILE) {
processCssDebounced({ reprocessMarkdown: true });
} else if ([MARKDOWN_FILE, TEMPLATE_FILE].includes(fileType)) {
processMarkdownDebounced();
} else {
await removeFile(p);
}
});
};
module.exports = watch;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc