Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
671 changes: 671 additions & 0 deletions README copy.md

Large diffs are not rendered by default.

675 changes: 22 additions & 653 deletions README.md

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env node
const yargs = require('yargs');
const { mdLinks } = require('./index.js');
const { countTotalAndUnique, countBrokenLinks } = require('./functions.js');
const chalk = require('chalk');

console.log(chalk.magentaBright("*************************************"));
console.log(chalk.magentaBright('Hey! :) Here is Lin md-links library!'));
console.log(chalk.magentaBright("*************************************"));

console.log(" /\\_/\\");
console.log("=( o.o )=");
console.log(" > - <");

console.log(chalk.yellow("Quick tip! If your path has inverted backslashes instead of '/',\n please enter your path within double quotes, ty! ;) \n"));


// Yargs hace el CLI ejecutable
//Yargs se encarga del análisis de los argumentos y opciones proporcionados por el usuario

yargs
.usage(chalk.bold.cyanBright('md-links ./path/to/file.md -v -s'))
.command('$0', chalk.cyan('Default command'))
.option('v', {
alias: 'validate',
describe: chalk.cyan('-v to check the status of each link'),
type: 'boolean',
default: false,
})
.option('s', {
alias: 'stats',
describe: 'Show statistics about the links',
type: 'boolean',
default: false,
})
.help('h')
.alias('h', 'help')
.argv;

const args = yargs.argv;
const filePath = args._[0];
const options = {
validate: args.validate,
stats: args.stats,
};

if (!filePath) {
console.error(chalk.red('Error: You must provide a path.'));
process.exit(1);
}

mdLinks(filePath, options)
.then((linksWithStatus) => {
if (options.stats) {
const totalStats = `Total: ${linksWithStatus.length}`;
const uniqueStats = countTotalAndUnique(linksWithStatus);
const brokenStats = `Broken: ${countBrokenLinks(linksWithStatus)}`;
console.log(chalk.cyanBright(totalStats));
console.log(chalk.cyanBright(`Unique: ${uniqueStats.unique}`));
console.log(chalk.cyanBright(brokenStats));
}
if (options.validate) {
linksWithStatus.forEach((link) => {
const statusInfo = link.ok === 'OK' ? 'OK' : 'Fail';
console.log(
`${chalk.magenta('Text:')} ${chalk.green(link.text)}\n` +
`${chalk.magenta('href:')} ${chalk.green(link.href)}\n` +
`${chalk.magenta('File:')} ${chalk.green(link.file)}\n` +
`${chalk.magenta('Status:')} ${chalk.green(link.status)}\n` +
`${chalk.magenta('StatusInfo:')} ${chalk.green(statusInfo)}\n`
);
});
} else {
linksWithStatus.forEach((link) => {
console.log(
`${chalk.magenta('Text:')} ${chalk.green(link.text)}\n` +
`${chalk.magenta('href:')} ${chalk.green(link.href)}\n` +
`${chalk.magenta('File:')} ${chalk.green(link.file)}\n`
);
});
}
})
.catch((error) => {
console.error(error);
});


35 changes: 35 additions & 0 deletions extra.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## 3. Objetivos de aprendizaje

Reflexiona y luego marca los objetivos que has llegado a entender y aplicar en tu proyecto. Piensa en eso al decidir tu estrategia de trabajo.

### JavaScript

- [ ] **Diferenciar entre tipos de datos primitivos y no primitivos**

- [ ] **Arrays (arreglos)**

<details><summary>Links</summary><p>

* [Arreglos](https://curriculum.laboratoria.la/es/topics/javascript/04-arrays)
* [Array - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/)
* [Array.prototype.sort() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
* [Array.prototype.forEach() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
* [Array.prototype.map() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
* [Array.prototype.filter() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
* [Array.prototype.reduce() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)
</p></details>

- [ ] **Objetos (key, value)**

<details><summary>Links</summary><p>

* [Objetos en JavaScript](https://curriculum.laboratoria.la/es/topics/javascript/05-objects/01-objects)
</p></details>

- [ ] **Uso de condicionales (if-else, switch, operador ternario, lógica booleana)**

<details><summary>Links</summary><p>

* [Estructuras condicionales y repetitivas](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/01-conditionals-and-loops)
* [Tomando decisiones en tu código — condicionales - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/conditionals)
</p></details>
165 changes: 165 additions & 0 deletions functions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
const fs = require("fs");
const path = require("path");
const axios = require('axios');


// Función para verificar si un archivo o directorio existe
function fileOrDirExists(filePath) {
return fs.existsSync(filePath);
}
//console.log("Path exists:", fileOrDirExists('./extra.md'));

// Función para convertir una ruta relativa en absoluta
function convertToAbsolute(filePath) {
return path.resolve(filePath);
}
//console.log("Absolute path:", convertToAbsolute ('./extra.md'));
//console.log("Absolute path:", convertToAbsolute ('./index.js'));

// Confirmar si es un archivo .md
function isMarkdownFile(filePath) {
return path.extname(filePath) === ".md";
}
//console.log("Is markdown file:", isMarkdownFile('./extra.md'));

//const filePath = 'D:/Laboratoria/DEV008-md-links/README.md';
//const filePath = 'D:/Laboratoria/DEV008-md-links/extra.md'; //error al copiar path?


// Leer el archivo .md
function readFileContent(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}


// Buscar links dentro del .md

const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;

function findLinksInMarkdown(markdownContent, filePath) {
return new Promise((resolve, reject) => {
const links = [];
let match;

while ((match = linkRegex.exec(markdownContent)) !== null) {
const [, linkText, linkUrl] = match;
links.push({
text: linkText,
href: linkUrl,
file: filePath
});
}

resolve(links);
});
}

/*
readFileContent(filePath)
.then((markdownContent) => {
return findLinksInMarkdown(markdownContent, filePath);
})
.then((links) => {
return getStatusLinks(links);
})
.then((linksWithStatus) => {
//linksWithStatus no está declarada porque se obtiene como resultado de la promesa
console.log("Links with status:", linksWithStatus);

const totalAndUnique = countTotalAndUnique(linksWithStatus);
const brokenLinkCount = countBrokenLinks(linksWithStatus);

console.log('Total Links:', totalAndUnique.total);
console.log('Unique Links:', totalAndUnique.unique);
console.log('Broken Links:', brokenLinkCount);
})

.catch((error) => {
console.error("Error:", error);
}); */



// Pedir el código status HTTP -fetch o axios
//Axios aquí

//transforma en newPromise
function getStatusLinks(linksArray) {
const promises = linksArray.map((link) => {
return axios.get(link.href)
.then((response) => {
const statusText = `${response.status}`;
const ok = response.status === 200 ? "OK" : "fail";
return { ...link, status: statusText, ok };
})
.catch((error) => {
let statusText = 'HTTP Status Code: Unknown Error';
const ok = "fail";

if (error.response) {
statusText = `${error.response.status} ${error.response.statusText}`;
}

return { ...link, status: statusText, ok };
});
});

return Promise.all(promises);
}

// Spread Syntax (...)
// eso agrega los elementos individuales al arreglo links.

//-----------------------------Here functions for stats!!!-------------------------------------
// Count total and unique links
function countTotalAndUnique(linksArray) {
const totalLinks = linksArray.length;

//con Set NO sirve lenght, usar .size*
//Set-estructura de datos Js que representa una colección de valores únicos
const uniqueLinks = new Set(linksArray.map((link) => link.href));
return {
total: totalLinks,
unique: uniqueLinks.size,
};
}


// count broken links
function countBrokenLinks(linksArray) {
let count = 0;
for (const link of linksArray) {
if (link.ok !== 'OK') {
count++;
}
}
return count;
}
/* function countBrokenLinks(linksArray) {
return linksArray.reduce((count, link) => {
if (link.ok !== 'OK') {
count++;
}
return count;
}, 0);
} */


module.exports = {
fileOrDirExists,
convertToAbsolute,
isMarkdownFile,
readFileContent,
getStatusLinks,
findLinksInMarkdown,
countTotalAndUnique,
countBrokenLinks,
};
63 changes: 60 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,60 @@
module.exports = () => {
// ...
};
const fs = require("fs");
const {
fileOrDirExists,
convertToAbsolute,
isMarkdownFile,
readFileContent,
getStatusLinks,
findLinksInMarkdown,
} = require('./functions.js');



// aquí va mdLinks
//función principal que tomará una ruta de archivo y opciones, y devolverá una promesa.
const mdLinks = (filePath, options = { validate: false, stats: false }) => new Promise((resolve, reject) => {
//const shouldValidate = options.validate;
//const shouldShowStats = options.stats;
const absolutePath = convertToAbsolute(filePath);
const pathExist = fs.existsSync(absolutePath);

if (!pathExist) {
return reject(new Error('Path does not exist' + absolutePath));
}

const isMdFile = isMarkdownFile(absolutePath);
if (!isMdFile) {
return reject(new Error('File is not a markdown!'));
}

readFileContent(filePath)
.then((markdownContent) => {
return findLinksInMarkdown(markdownContent, filePath);
})
.then((links) => {
return getStatusLinks(links);
})
.then((linksWithStatus) => {
//linksWithStatus no está declarada porque se obtiene como resultado de la promesa
resolve(linksWithStatus);
})
.catch((error) => {
// En caso de error, rechazamos la promesa
reject(error);
});
});




//..to try mdLinks promise
/* mdLinks('D:/Laboratoria/DEV008-md-links/README.md', { validate: true }).then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
}); */


module.exports = {
mdLinks,
};
Loading