2022-03-05 22:57:23 +04:00
|
|
|
import fs from 'fs';
|
|
|
|
import path from 'path';
|
|
|
|
import config from 'config';
|
2022-08-24 17:05:40 +03:00
|
|
|
import { fileURLToPath } from 'url';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The __dirname CommonJS variables are not available in ES modules.
|
|
|
|
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
|
|
|
|
*/
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
2022-03-05 22:57:23 +04:00
|
|
|
|
|
|
|
const rcPath = path.resolve(__dirname, '../../../', config.get('rcFile') || './.codexdocsrc');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {object} menu
|
|
|
|
* @property {string} title - menu option title
|
|
|
|
* @property {string} uri - menu option href
|
|
|
|
*/
|
|
|
|
interface Menu {
|
|
|
|
title: string;
|
|
|
|
uri: string;
|
|
|
|
[key: string]: string;
|
|
|
|
}
|
2018-10-07 19:15:10 +03:00
|
|
|
|
|
|
|
/**
|
2020-05-09 05:38:25 +03:00
|
|
|
* @typedef {object} RCData
|
2018-10-07 19:15:10 +03:00
|
|
|
* @property {string} title - website title
|
2022-03-05 22:57:23 +04:00
|
|
|
* @property {Menu[]} menu - options for website menu
|
2018-10-07 19:15:10 +03:00
|
|
|
*/
|
2022-03-05 22:57:23 +04:00
|
|
|
interface RCData {
|
|
|
|
title: string;
|
|
|
|
menu: Menu[];
|
|
|
|
[key: string]: string | Menu[];
|
|
|
|
}
|
2018-10-07 19:15:10 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @class RCParser
|
|
|
|
* @classdesc Class to parse runtime configuration file for CodeX Docs engine
|
|
|
|
*/
|
2022-03-05 22:57:23 +04:00
|
|
|
export default class RCParser {
|
2018-10-07 19:15:10 +03:00
|
|
|
/**
|
|
|
|
* Default CodeX Docs configuration
|
|
|
|
*
|
|
|
|
* @static
|
2020-05-09 05:38:25 +03:00
|
|
|
* @returns {{title: string, menu: Array}}
|
2018-10-07 19:15:10 +03:00
|
|
|
*/
|
2022-03-05 22:57:23 +04:00
|
|
|
public static get DEFAULTS():RCData {
|
2018-10-07 19:15:10 +03:00
|
|
|
return {
|
|
|
|
title: 'CodeX Docs',
|
2020-05-09 05:38:25 +03:00
|
|
|
menu: [],
|
2018-10-07 19:15:10 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find and parse runtime configuration file
|
|
|
|
*
|
|
|
|
* @static
|
2020-05-09 05:38:25 +03:00
|
|
|
* @returns {{title: string, menu: []}}
|
2018-10-07 19:15:10 +03:00
|
|
|
*/
|
2022-03-05 22:57:23 +04:00
|
|
|
public static getConfiguration(): RCData {
|
2018-10-07 19:15:10 +03:00
|
|
|
if (!fs.existsSync(rcPath)) {
|
|
|
|
return RCParser.DEFAULTS;
|
|
|
|
}
|
|
|
|
|
2022-03-05 22:57:23 +04:00
|
|
|
const file = fs.readFileSync(rcPath, 'utf-8');
|
2019-02-15 17:56:56 +03:00
|
|
|
const rConfig = RCParser.DEFAULTS;
|
2018-10-07 19:15:10 +03:00
|
|
|
let userConfig;
|
|
|
|
|
|
|
|
try {
|
|
|
|
userConfig = JSON.parse(file);
|
|
|
|
} catch (e) {
|
|
|
|
console.log('CodeX Docs rc file should be in JSON format.');
|
2020-05-09 05:38:25 +03:00
|
|
|
|
2018-10-07 19:15:10 +03:00
|
|
|
return RCParser.DEFAULTS;
|
|
|
|
}
|
|
|
|
|
2020-05-09 05:38:25 +03:00
|
|
|
for (const option in userConfig) {
|
|
|
|
if (Object.prototype.hasOwnProperty.call(userConfig, option)) {
|
2019-02-15 17:56:56 +03:00
|
|
|
rConfig[option] = userConfig[option] || RCParser.DEFAULTS[option] || undefined;
|
|
|
|
}
|
|
|
|
}
|
2018-10-07 19:15:10 +03:00
|
|
|
|
|
|
|
if (!(rConfig.menu instanceof Array)) {
|
|
|
|
console.log('Menu section in the rc file must be an array.');
|
|
|
|
rConfig.menu = RCParser.DEFAULTS.menu;
|
|
|
|
}
|
|
|
|
|
2022-03-05 22:57:23 +04:00
|
|
|
rConfig.menu = rConfig.menu.filter((option: string | Menu, i:number) => {
|
2018-10-07 19:15:10 +03:00
|
|
|
i = i + 1;
|
|
|
|
if (typeof option === 'string') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!option || option instanceof Array || typeof option !== 'object') {
|
|
|
|
console.log(`Menu option #${i} in rc file must be a string or an object`);
|
2020-05-09 05:38:25 +03:00
|
|
|
|
2018-10-07 19:15:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-15 17:56:56 +03:00
|
|
|
const { title, uri } = option;
|
2018-10-07 19:15:10 +03:00
|
|
|
|
|
|
|
if (!title || typeof title !== 'string') {
|
|
|
|
console.log(`Menu option #${i} title must be a string.`);
|
2020-05-09 05:38:25 +03:00
|
|
|
|
2018-10-07 19:15:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!uri || typeof uri !== 'string') {
|
|
|
|
console.log(`Menu option #${i} uri must be a string.`);
|
2020-05-09 05:38:25 +03:00
|
|
|
|
2018-10-07 19:15:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2022-03-05 22:57:23 +04:00
|
|
|
rConfig.menu = rConfig.menu.map((option: string | Menu) => {
|
2018-10-07 19:15:10 +03:00
|
|
|
if (typeof option === 'string') {
|
|
|
|
return {
|
|
|
|
title: option,
|
|
|
|
/* Replace all non alpha- and numeric-symbols with '-' */
|
2020-05-09 05:38:25 +03:00
|
|
|
uri: '/' + option.toLowerCase().replace(/[ -/:-@[-`{-~]+/, '-'),
|
2018-10-07 19:15:10 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return option;
|
|
|
|
});
|
|
|
|
|
|
|
|
return rConfig;
|
|
|
|
}
|
2022-03-05 22:57:23 +04:00
|
|
|
}
|