From f5fa86eadfacd30e85a7425b8021c9d7f0215532 Mon Sep 17 00:00:00 2001 From: Fabiana Fonseca Date: Thu, 28 Nov 2019 14:42:48 -0300 Subject: [PATCH 1/2] configurando o cli --- .eslintrc.js | 26 ++++++++++++++++++++++++++ .gitignore | 2 ++ lib/__tests__/index.spec.js | 15 +++++++++++++++ lib/cli.js | 10 ++++++++++ lib/index.js | 34 ++++++++++++++++++++++++++++++++++ package.json | 30 ++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+) create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 lib/__tests__/index.spec.js create mode 100755 lib/cli.js create mode 100644 lib/index.js create mode 100644 package.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..eef7e319 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,26 @@ +module.exports = { + "env": { + "commonjs": true, + "es6": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 2018 + }, + "plugins": [ + "react" + ], + "rules": { + } +}; \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..11d85a3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +coverage \ No newline at end of file diff --git a/lib/__tests__/index.spec.js b/lib/__tests__/index.spec.js new file mode 100644 index 00000000..b6514c46 --- /dev/null +++ b/lib/__tests__/index.spec.js @@ -0,0 +1,15 @@ +const mdLinks = require('./index.js') + +it("mdLinks", () => { + assert.equal(typeof data, "object"); +}); + +// describe("searchTheCategory", () => { +// it("should be a function", () => { +// assert.equal(typeof data.searchTheCategory, "function"); +// }); + +// it("should return Total_Injured_Persons_Passenger_Car_Occupants: 1378000 with Year: 2015-01-04", () => { +// expect(searchTheCategory()).toContain("1378000"); +// }); +// }); \ No newline at end of file diff --git a/lib/cli.js b/lib/cli.js new file mode 100755 index 00000000..c4464e2a --- /dev/null +++ b/lib/cli.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +const mdLinks = require('./index.js'); + +// mdLinks(process.argv) + + + mdLinks() + .then((result) => console.log(result)) + .catch((err) => console.log(err)) + \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 00000000..be9cec56 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,34 @@ +const fs = require('fs'); + +const mdLinks = () =>{ + const links = /\[(.*)\]\((.*)\)/gm + const replaceBrackets = /\[/ + const repalceParentheses = /\)/ + return new Promise((resolve, reject) => { + fs.readFile('README.md', 'utf8', (err,data) => { + if(err) { + reject(err); + } else { + const matches = data.match(links) + const result = matches.map((el) => { + const splited = el.split(']('); + const text = splited[0].replace(replaceBrackets,''); + const href = splited[1].replace(repalceParentheses, ''); + + return { href, text } + }); + resolve(result); + }; + }); + }); +}; + + +// console.error("Could not open file: %s", err); +// process.exit(1); +// } + +// console.log(data.toString('utf8')); +// }); + + module.exports = mdLinks; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..e2a0e0dd --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "md-links", + "version": "1.0.0", + "description": "## Índice", + "main": "index.js", + "dependencies": { + "jest": "^24.9.0" + }, + "devDependencies": { + "eslint": "^6.7.1", + "eslint-plugin-react": "^7.16.0", + "jest": "^24.9.0" + }, + "scripts": { + "test": "jest --coverage" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Fabiana-Soares/SAP003-md-links.git" + }, + "bin": { + "md-links": "lib/cli.js" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Fabiana-Soares/SAP003-md-links/issues" + }, + "homepage": "https://github.com/Fabiana-Soares/SAP003-md-links#readme" +} From 3562c0fcdce6c9f3ccdaf70b9513842d03bd0ea9 Mon Sep 17 00:00:00 2001 From: Fabiana Fonseca Date: Wed, 4 Dec 2019 10:54:35 -0300 Subject: [PATCH 2/2] atualizando os testes --- .eslintrc | 24 +++ .eslintrc.js | 26 --- lib/__tests__/.eslintrc | 6 + lib/__tests__/index.spec.js | 36 ++-- lib/__tests__/testError.md | 347 ++++++++++++++++++++++++++++++++++++ lib/cli.js | 16 +- lib/index.js | 44 ++--- 7 files changed, 431 insertions(+), 68 deletions(-) create mode 100644 .eslintrc delete mode 100644 .eslintrc.js create mode 100644 lib/__tests__/.eslintrc create mode 100644 lib/__tests__/testError.md diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..7e86d0d8 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,24 @@ +module.exports = { + "env": { + "browser": true + }, + "parserOptions": { + "ecmaVersion": 6 + }, + "extends": "eslint:recommended", + "globals": { + "cipher": false + }, + "rules": { + "indent": ["error", 2], + "quotes": ["error", "double"], + "semi": ["error", "always"], + "camelcase": ["error", { "properties": "always" }], + "keyword-spacing": ["error", { "before": true }], + "comma-spacing": ["error", { "before": false, "after": true }], + "space-before-blocks": ["error", "always"], + "key-spacing": ["error", { "afterColon": true }], + "no-multi-spaces": ["error", { "ignoreEOLComments": true }], + "no-multiple-empty-lines": ["error", { "max": 1 }] + } + }; \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index eef7e319..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - "env": { - "commonjs": true, - "es6": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended" - ], - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": 2018 - }, - "plugins": [ - "react" - ], - "rules": { - } -}; \ No newline at end of file diff --git a/lib/__tests__/.eslintrc b/lib/__tests__/.eslintrc new file mode 100644 index 00000000..9cf67b14 --- /dev/null +++ b/lib/__tests__/.eslintrc @@ -0,0 +1,6 @@ +{ + "env": { + "node": true, + "jest": true + } + } \ No newline at end of file diff --git a/lib/__tests__/index.spec.js b/lib/__tests__/index.spec.js index b6514c46..69665a1b 100644 --- a/lib/__tests__/index.spec.js +++ b/lib/__tests__/index.spec.js @@ -1,15 +1,29 @@ -const mdLinks = require('./index.js') +const mdLinks = require('../index') -it("mdLinks", () => { - assert.equal(typeof data, "object"); +describe("mdLinks", () => { + it("is a function", () => expect(typeof mdLinks).toBe("function")); + +it("returns href and text", (done) => { + return mdLinks('./README.md').then(result => { + expect(result).toBe(result) + done() + }); }); -// describe("searchTheCategory", () => { -// it("should be a function", () => { -// assert.equal(typeof data.searchTheCategory, "function"); -// }); +it("return erro no arquivo", (done) => +{ + return mdLinks('./READM.md').catch(e => + { + expect(e).toBe(e); + done(); + }); +}); -// it("should return Total_Injured_Persons_Passenger_Car_Occupants: 1378000 with Year: 2015-01-04", () => { -// expect(searchTheCategory()).toContain("1378000"); -// }); -// }); \ No newline at end of file +it("return Nao existe arquivo", (done) => { + return mdLinks('./README.md').catch(e => + { + expect(e).toBe(e); + done(); + }); + }); +}); \ No newline at end of file diff --git a/lib/__tests__/testError.md b/lib/__tests__/testError.md new file mode 100644 index 00000000..2feb4160 --- /dev/null +++ b/lib/__tests__/testError.md @@ -0,0 +1,347 @@ +# Markdown Links + +## Índice + +* [1. Prefácio](#1-prefácio) +* [2. Resumo do projeto](#2-resumo-do-projeto) +* [3. Objetivos de aprendizagem](#3-objetivos-de-aprendizagem) +* [4. Considerações gerais](#4-considerações-gerais) +* [5. Critérios de aceitação mínimos do + projeto](#5-critérios-de-aceitação-mínimos-do-projeto) +* [6. Entregáveis](#6-entregáveis) +* [7. Guias, dicas e leituras + complementares](#7-guias-dicas-e-leituras-complementares) +* [8. Checklist](#8-checklist) + +*** + +## 1. Prefácio + +[Markdown](https://pt.wikipedia.org/wiki/Markdown) é uma linguagem de marcação +muito popular entre os programadores. É usada em muitas plataformas que +manipulam texto (GitHub, fórum, blogs e etc), e é muito comum encontrar arquivos +com este formato em qualquer repositório (começando pelo tradicional +`README.md`). + +Os arquivos `Markdown` normalmente contém _links_ que muitas vezes estão +quebrados, ou que já não são válidos e isso prejudica muito o valor da +informação que está ali. + +Uma comunidade open source nos propôs criar uma ferramenta, usando +[Node.js](https://nodejs.org/), que leia e analise arquivos no formato +`Markdown`, para verificar os arquivos que contenham links e mostrar algumas +estatísticas. + +![md-links](https://user-images.githubusercontent.com/110297/42118443-b7a5f1f0-7bc8-11e8-96ad-9cc5593715a6.jpg) + +## 2. Resumo do projeto + +[Node.js](https://nodejs.org/pt-br/) é um ambiente de execução para JavaScript +construído com o [motor de JavaScript V8 do +[Chrome](https://developers.google.com/v8/). Ele vai nos permitir executar o +JavaScript no nosso sistema operacional, seja no seu computador ou em um +servidor, o que nos abre portas para poder interagir com sistemas, arquivos, +redes e etc. + +Neste projeto vamos ficar um pouco longe do navegador para construir um programa +que seja executado com Node.js, onde iremos aprender sobre como interagir com +sistemas de arquivos e com o ambiente onde é executado o node (_process_, _env_, +_stdin/stdout/stderr_), ... + +Este projeto você criará uma ferramenta de linha de comando (CLI) assim como a +sua própria biblioteca (library) em JavaScript. + +## 3. Objetivos de aprendizagem + +Desenvolver sua própria biblioteca é uma experiência fundamental para qualquer +desenvolvedora, pois te obriga a pensar na interface (API) dos seus _módulos_ e +como ela será usada por outras desenvolvedoras. Você deve levar em conta as +peculiaridades da linguagem, convenções e boas práticas. + +A seguir você pode conferir os objetivos de aprendizagem deste projeto: + +### Javascript + +* [ ] Uso de callbacks +* [ ] Consumo de Promises +* [ ] Criação de uma Promise +* [ ] Módulos de JS (CommonJS vs ES Modules) + +### Node + +* [ ] Sistema de arquivos ([fs](https://nodejs.org/api/fs.html), [path](https://nodejs.org/api/path.html)) +* [ ] [package.json](https://docs.npmjs.com/files/package.json) +* [ ] criação de módulos [(CommonJS)](https://nodejs.org/docs/latest-v0.10.x/api/modules.html) +* [ ] Instalar e usar módulos ([npm](https://www.npmjs.com/)) +* [ ] [npm-scripts](https://docs.npmjs.com/misc/scripts) +* [ ] CLI (Command Line Interface - Interface de Linha de Comando) +* [ ] [http.get](https://nodejs.org/api/http.html#http_http_get_options_callback) + +### Testing + +* [ ] Testar suas funções +* [ ] Teste assíncrono +* [ ] Usar biblioteca de mock +* [ ] Mock manual +* [ ] Teste para múltiplos sistemas operacionais + +### Git e Github + +* [ ] Organização no Github + +### Boas práticas de desenvolvimento + +* [ ] Modularização +* [ ] Nomenclatura / Semântica +* [ ] Linting + +*** + +## 4. Considerações gerais + +* Este projeto deve ser feito individualmente. + +* A biblioteca e script executável (ferramenta de linha de comando - CLI) devem + ser implementados em JavaScript para serem executadas com Node.JS. **É permitido + usar bibliotecas externas**. + +* O seu módulo deve ser instalável via `npm install /md-links`. O + módulo deve incluir um _executável_ que pode ser chamado tanto por linha de + comando, quanto importado com `require` para ser usado em seu código. + +* Os testes unitários devem cobrir no mínimo 99,9% dos _statements_, _functions_, + _lines_ e _branches_. Recomendamos que explore o [Jest](https://jestjs.io/) + para as suas provas unitárias. + +* Neste projeto não é permitido utilizar `async/await`. + +## 5. Critérios de aceitação mínimos do projeto + +Para começar este projeto você deverá fazer um _fork_ e _clonar_ este +repositório. + + +### Arquivos do projeto + +* `README.md` com descrição do módulo, instruções de instalação e uso, + documentação da API e exemplos. Tudo que for relevante para qualquer + desenvolvedora saber como utilizar a sua biblioteca sem inconvenientes. +* `package.json` deve possuir o nome, versão, descrição, autor, licença, + dependências e scripts (eslint e test). +* `package-lock.json` arquivo gerado pelo npm, para controle dos pacotes + instalados +* `.eslintrc` com a configuração para o linter. Este arquivo não deve ser + alterado. +* `.gitignore` para ignorar o `node_modules` e outras pastas que não deve ser + incluídas no controle de versão (`git`). +* `cli.js` este arquivo deve chamar a função `mdLinks` que será executada pela + linha de comando. +* `lib/index.js` criação e exportação da função `mdLinks`. +* `lib/__test__/index.spec.js` deve conter os testes unitários para a função + `mdLinks`. + +### JavaScript API + +O módulo deve poder ser importado em outros scripts Node.js e deve oferecer a +seguinte interface: + +#### `mdLinks(path)` + +##### Argumento + +* `path`: Rota absoluta ou relativa ao arquivo. Se a rota passada é + relativa, deve resolver como sendo relativa ao diretório onde foi chamada - + _current working directory_ + +##### Valor de retorno + +A função deve retornar uma promessa (`Promise`) que resolve um array (`Array`) e +objetos(`Object`), onde cada objeto representa um link, contendo as seguintes +propriedades: + +* `href`: URL encontrada. +* `text`: Texto dentro do markdown. + +#### Exemplo + +```js +const mdLinks = require("md-links"); + +mdLinks("./example.md") + .then(links => { + // => [{ href, text }] + }) + .catch(console.error); +``` + +### CLI (Command Line Interface - Interface de Linha de Comando) + +O executável da nossa aplicação deve poder ser executado da seguinte maneira, +através do terminal: + +`md-links [options]` + +Por exemplo: + +```sh +$ md-links ./some/example.md +http://algo.com/2/3/ Link de algo +https://outra-coisa-.net/algum-doc.html algum doc +http://google.com/ Google +``` + +O comportamento padrão não deve validar se as URLs responde ok ou não, somente +deve identificar o arquivo markdown (a partir da rota que recebeu como +argumento), analisar o arquivo Markdown e imprimir os links que vão sendo +encontrados, junto com a rota do arquivo onde aparece e o texto que tem dentro +do link (truncado 50 caracteres). + + +#### Hacker Edition + +##### Argumentos + +Adicionar o argumento `option`, dentro da função `mdLinks(path, option)` + +* `path`: Rota absoluta ou relativa ao arquivo. Se a rota passada é + relativa, deve resolver como sendo relativa ao diretório onde foi chamada - + _current working directory_ +* `option`: Um objeto com a seguinte propriedade: + - `validate`: Um booleano que determina se deseja validar os links + encontrados. + +##### Valor de retorno + +Você deve adicionar o _status_ da requisição dentro do objeto da resposta de +cada url encontrada. + +* `href`: URL encontrada. +* `text`: Texto dentro do markdown. +* `status`: Status da requisição. + +##### Exemplo + +```js +const mdLinks = require("md-links"); + +mdLinks("/some/example.md", { validate: true }) + .then(links => { + // => [{ href, text, status }] + }) + .catch(console.error); +``` + +##### CLI `--validate` + +Se passamos a opção `--validate`, o módulo deve fazer uma requisição HTTP para +verificar se o link funciona ou não. Se o link resultar em um redirecionamento a +uma URL que responde ok, então consideraremos o link como ok. + +Por exemplo: + +```sh +$ md-links ./some/example.md --validate +http://algo.com/2/3/ 200 Link de algo +https://outra-coisa-.net/algum-doc.html 404 algum doc +http://google.com/ 301 Google +``` + +## 6. Entregáveis + +O módulo deve ser instalável via `npm install /md-links`. Este +módulo deve incluir um executável que pode ser chamado tanto por linha de +comando, quanto importado com `require` para usá-lo no seu código. + +## 7. Guias, dicas e leituras complementares + +### FAQs + +#### Como faço para que o meu módulo seja instalável pelo GitHub? + +Para que o módulo seja instalável pelo GitHub você tem que: + +* Deixar o seu repo público +* Ter um `package.json` válido + +Com o comando `npm install /` podemos instalar diretamente +pelo GitHub. Ver [docs oficiais dp `npm install` +aqui](https://docs.npmjs.com/cli/install) + +Por exemplo, o +[`curriculum-parser`](https://github.com/Laboratoria/curriculum-parser) que é +usado para o currículo não está publicado nos registros públicos do NPM, com +isso temos que instalar diretamente desde o GitHub com o commando `npm install +Laboratoria/curriculum-parser`. + +### Sugestões de implementação + +A implementação deste projeto tem várias partes: ler do sistema de arquivos, +receber argumento através da linha de comando, analisar um teste, fazer +consultas HTTP, ... e tudo isso pode ser feito de muitas formas, tanto com +bibliotecas quanto com JS puro. + +Para esse projeto recomendamos o uso de [expressões regulares +(`RegExp`)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Regular_Expressions) + +### Tutoriais / NodeSchool workshoppers + +* [learnyounode](https://github.com/workshopper/learnyounode) +* [how-to-npm](https://github.com/workshopper/how-to-npm) +* [promise-it-wont-hurt](https://github.com/stevekane/promise-it-wont-hurt) + +### Outros recursos + +* [Sobre Node.js - Documentação oficial](https://nodejs.org/pt-br/about/) +* [Node.js file system - Documentação oficial](https://nodejs.org/api/fs.html) +* [Node.js http.get - Documentação + oficial](https://nodejs.org/api/http.html#http_http_get_options_callback) +* [Node.js - Wikipedia](https://pt.wikipedia.org/wiki/Node.js) +* [What exactly is Node.js? - + freeCodeCamp](https://medium.freecodecamp.org/what-exactly-is-node-js-ae36e97449f5) +* [Node.js – O que é, como funciona e quais as + vantagens](https://www.opus-software.com.br/node-js/) +* [O que é npm](https://www.hostinger.com.br/tutoriais/o-que-e-npm) +* [Módulos, librerías, paquetes, frameworks... ¿cuál es la + diferencia?](http://community.laboratoria.la/t/modulos-librerias-paquetes-frameworks-cual-es-la-diferencia/175) +* [JavaScript assíncrono: callbacks, promises e async + functions](https://medium.com/@alcidesqueiroz/javascript-ass%C3%ADncrono-callbacks-promises-e-async-functions-9191b8272298) +* [NPM](https://docs.npmjs.com/getting-started/what-is-npm) +* [Publicar + package](https://docs.npmjs.com/getting-started/publishing-npm-packages) +* [Criando um módulo + Node.js](https://docs.npmjs.com/getting-started/publishing-npm-packages) +* [Ler um + arquivo](https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback) +* [Ler um + diretório](https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback) +* [Path](https://nodejs.org/api/path.html) +* [Criando sua CLI com + Node.js](https://medium.com/henriquekuwai/criando-sua-cli-com-node-js-d6dee7d03110) + +## 8. Checklist + +### General + +* [ ] Poder instalar via `npm install -g /md-links` + +### `README.md` + +* [ ] Um board com o backlog com as implementações da sua biblioteca +* [ ] Documentação técnica da sua biblioteca +* [ ] Guia de uso e instalação da biblioteca + +### API `mdLinks(path)` + +* [ ] O módulo exporta uma função com a interface (API) esperada +* [ ] Implementa suporte para arquivo individual + +### CLI + +* [ ] Possuir o executável `md-links` no path (configurado no `package.json`) +* [ ] Executar sem erros e ter o resultado esperado + +### Testes + +* [ ] Os testes unitários devem cobrir no mínimo 99,9% dos statements, functions, + lines e branches. +* [ ] Rodar os tests e linter (`npm test`). diff --git a/lib/cli.js b/lib/cli.js index c4464e2a..75e167bb 100755 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,10 +1,16 @@ #!/usr/bin/env node + const mdLinks = require('./index.js'); + const path = process.argv[2]; -// mdLinks(process.argv) - + .then((result) => result.forEach(e =>{ + if(e.text.length < 47){ + console.log(e.link, "-->", e.text.substring(0,50)) + } + else{ + console.log(e.link, "-->", e.text.substring(0,47)+ '...') - mdLinks() - .then((result) => console.log(result)) - .catch((err) => console.log(err)) + } + })) + .catch(console.log(err); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index be9cec56..364f3b86 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,34 +1,26 @@ const fs = require('fs'); -const mdLinks = () =>{ - const links = /\[(.*)\]\((.*)\)/gm - const replaceBrackets = /\[/ - const repalceParentheses = /\)/ +const mdLinks = (path) =>{ + const links = /([^\[]+)\](\([^\)]*)/gm return new Promise((resolve, reject) => { - fs.readFile('README.md', 'utf8', (err,data) => { + fs.readFile(path, 'utf8', (err,data) => { if(err) { - reject(err); + reject("Erro no arquivo ou nao encontrado"); } else { - const matches = data.match(links) - const result = matches.map((el) => { - const splited = el.split(']('); - const text = splited[0].replace(replaceBrackets,''); - const href = splited[1].replace(repalceParentheses, ''); - - return { href, text } + const matches = data.match(links); + if (matches == null){ + reject("Arquivo sem nenhum links"); + } else { + const result = matches.map((el) => { + const splited = el.split(']('); + const text = splited[0].replace('\n ',''); + const href = splited[1] + return { href, text } }); resolve(result); - }; + } + }; }); - }); -}; - - -// console.error("Could not open file: %s", err); -// process.exit(1); -// } - -// console.log(data.toString('utf8')); -// }); - - module.exports = mdLinks; \ No newline at end of file + }); +}; +module.exports = mdLinks; \ No newline at end of file