Skip to content
Open
36 changes: 36 additions & 0 deletions src/app/lint/lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const titleOrCommentLinePattern = /^\s*((##)|(<!-- \.slide: class="page-).*)$/;
const nPreviousEmpty = 3;

function allEmpty(lines) {
return lines.every((l) => l.trim() === "");
}

export async function checkLines(readStream) {
// Buffer circulaire pour stocker les nPreviousEmpty lignes précédentes
const prevLines = [];
var index = 1;
var containsError = false;

for await (const line of readStream) {
// Vérifie si la ligne courante match le pattern
if (titleOrCommentLinePattern.test(line)) {
if (!allEmpty(prevLines)) {
console.info(
`Il faut minimum ${nPreviousEmpty} lignes vides devant le bloc "${line}" ligne n°${index}.`
);
containsError = true;
}
}

// Increment du nombre de ligne
index += 1;

// Ajoute la ligne actuelle dans le buffer, limite la taille à nPreviousEmpty
prevLines.push(line);
if (prevLines.length > nPreviousEmpty) {
prevLines.shift(); // enlève la plus vieille ligne
}
}

return containsError;
}
48 changes: 48 additions & 0 deletions src/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
const spawn = require("child_process").spawn;
const fork = require("child_process").fork;
const fs = require("fs");
const readline = require("readline");
const path = require("path");
const WebpackDevServer = require("webpack-dev-server");
const webpackConfig = require("../build/webpack.config");
const webpack = require("webpack");
const yargs = require("yargs/yargs");
const { checkLines } = require("../app/lint/lint");

/**
*
Expand Down Expand Up @@ -36,6 +38,9 @@ async function cli(args, env) {
case "pdf":
await pdf(options);
break;
case "lint":
await lint(options);
break;
default:
throw new Error(`unknown command: '${command}'`);
}
Expand All @@ -61,6 +66,45 @@ async function serve(buildOptions, serveOptions) {
}
}

async function lint(options) {
const material = options.material;
console.info(`Start linting from material '${material}...`);

for (const f of fs.readdirSync(material)) {
await lintMardownFiles(path.join(material, f));
}
}

async function lintMardownFiles(file) {
if (fs.lstatSync(file).isDirectory()) {
console.info(
`The path '${file}' is a directory. Recursively reading its contents...`
);

for (const f of fs.readdirSync(file)) {
await lintMardownFiles(path.join(file, f));
}
} else if (fs.lstatSync(file).isFile() && file.endsWith(".md")) {
const containsError = await checkLines(createReadStream(file));

if (containsError) {
console.error(
`\x1b[41mLe fichier "${file}" contient une ou plusieurs erreurs.\x1b[0m`
);
process.exit(0);
} else {
console.debug(`Le fichier "${file}" ne contient pas d'erreurs.`);
}
}
}

function createReadStream(filePath) {
console.debug("Create read stream for file at : ", filePath);
return readline.createInterface({
input: fs.createReadStream(filePath),
});
}

function build(options) {
console.log("Build slides & labs");
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -254,6 +298,10 @@ cli(
"build the static web site",
describePositionalArguments
)
.command(
"lint [material]",
"lint each Markdown files (e.g. clears line break before new slides)"
)
.option("config", {
type: "string",
describe:
Expand Down