First commit
This commit is contained in:
commit
d57ad3573d
|
@ -0,0 +1,12 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[js]
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Simon Constans
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Website Checker
|
||||||
|
|
||||||
|
weck permet de vérifier des bonnes pratiques pour un site internet.
|
||||||
|
|
||||||
|
## Feature
|
||||||
|
|
||||||
|
- [x] Scanner un dossier local
|
||||||
|
- [ ] Scanner un site distant
|
||||||
|
- [~] Permettre facilement l'extension de règle
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
Les règles que weck vérifie :
|
||||||
|
- [x] Que la balises <title> comporte entre 30 et 70 caractères
|
||||||
|
- [x] Vérifier qu'il n'existe qu'un seul et même titre sur un site internet
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import * as cli from '../src/index.js'
|
|
@ -0,0 +1,303 @@
|
||||||
|
{
|
||||||
|
"name": "weck",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "weck",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"node-html-parser": "^3.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"weck": "bin/weck.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/at-least-node": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/boolbase": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||||
|
},
|
||||||
|
"node_modules/css-select": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==",
|
||||||
|
"dependencies": {
|
||||||
|
"boolbase": "^1.0.0",
|
||||||
|
"css-what": "^4.0.0",
|
||||||
|
"domhandler": "^4.0.0",
|
||||||
|
"domutils": "^2.4.3",
|
||||||
|
"nth-check": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-what": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dom-serializer": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^4.0.0",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domelementtype": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/domhandler": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domutils": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^1.0.1",
|
||||||
|
"domelementtype": "^2.2.0",
|
||||||
|
"domhandler": "^4.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs-extra": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"at-least-node": "^1.0.0",
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/graceful-fs": {
|
||||||
|
"version": "4.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
|
||||||
|
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
|
||||||
|
},
|
||||||
|
"node_modules/he": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||||
|
"bin": {
|
||||||
|
"he": "bin/he"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jsonfile": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-html-parser": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-pCE2I5UY5iOBnWdJQkbYZSk+fyq2zepw0nsELpHQjVFyCzOeZhkMhnvKqGceKgzWsWx7EG4KtMqsy9Eklf5Thw==",
|
||||||
|
"dependencies": {
|
||||||
|
"css-select": "^3.1.2",
|
||||||
|
"he": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nth-check": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"boolbase": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/universalify": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"at-least-node": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||||
|
},
|
||||||
|
"boolbase": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||||
|
},
|
||||||
|
"css-select": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==",
|
||||||
|
"requires": {
|
||||||
|
"boolbase": "^1.0.0",
|
||||||
|
"css-what": "^4.0.0",
|
||||||
|
"domhandler": "^4.0.0",
|
||||||
|
"domutils": "^2.4.3",
|
||||||
|
"nth-check": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css-what": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A=="
|
||||||
|
},
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^4.0.0",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
|
||||||
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==",
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "^1.0.1",
|
||||||
|
"domelementtype": "^2.2.0",
|
||||||
|
"domhandler": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||||
|
"requires": {
|
||||||
|
"at-least-node": "^1.0.0",
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"graceful-fs": {
|
||||||
|
"version": "4.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
|
||||||
|
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
|
||||||
|
},
|
||||||
|
"he": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.6",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-html-parser": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-pCE2I5UY5iOBnWdJQkbYZSk+fyq2zepw0nsELpHQjVFyCzOeZhkMhnvKqGceKgzWsWx7EG4KtMqsy9Eklf5Thw==",
|
||||||
|
"requires": {
|
||||||
|
"css-select": "^3.1.2",
|
||||||
|
"he": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nth-check": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
|
||||||
|
"requires": {
|
||||||
|
"boolbase": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"universalify": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "weck",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Website Checker",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"bin": {
|
||||||
|
"weck": "bin/weck.js"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.weko.io/weko/WebsiteChecker.git"
|
||||||
|
},
|
||||||
|
"author": "Simon CONSTANS",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"node-html-parser": "^3.1.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
bs4==0.0.1
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path, { dirname } from 'path';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
export const getFilenames = async (directory, files = []) => {
|
||||||
|
const dirs = fs.opendirSync(directory);
|
||||||
|
for await (const dirent of dirs) {
|
||||||
|
const dirOrFilePath = path.join(directory, dirent.name);
|
||||||
|
if (dirent.isDirectory()) {
|
||||||
|
files = await getFilenames(dirOrFilePath, files)
|
||||||
|
} else if (dirent.isFile()) {
|
||||||
|
files = [...files, ...[dirOrFilePath]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
export const extensionFilter = (filenames, extension) => {
|
||||||
|
return filenames.filter(filename => filename.match(new RegExp(`.*\.(${extension})`, 'ig')));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getContent = (filename) => {
|
||||||
|
return fs.readFileSync(filename).toString()
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import getRules from './rules/index.js'
|
||||||
|
import { getFilenames } from './helpers.js'
|
||||||
|
|
||||||
|
const checkDirectory = async (directory) => {
|
||||||
|
const filenames = await getFilenames(directory);
|
||||||
|
|
||||||
|
const rules = getRules(filenames, { directory: directory });
|
||||||
|
let issues = []
|
||||||
|
for (const rule of rules) {
|
||||||
|
const issue = rule.check()
|
||||||
|
if (issue) {
|
||||||
|
issues = [...issues, ...[issue]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createReport(issues)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createReport = (issues) => {
|
||||||
|
if (!!process.argv.find(p => p == '--md')) {
|
||||||
|
for (const rule of issues) {
|
||||||
|
if (rule.issueCount > 0) {
|
||||||
|
console.log()
|
||||||
|
console.log(`### ${rule.issueTitle}`)
|
||||||
|
console.log()
|
||||||
|
console.log(`${rule.issueDescription}`)
|
||||||
|
console.log()
|
||||||
|
for (const issue of rule.issues) {
|
||||||
|
console.log(`- element \`${issue.title}\` on \`${issue.url}\` file.`)
|
||||||
|
}
|
||||||
|
console.log()
|
||||||
|
let referenceLinks = ''
|
||||||
|
for (const reference of rule.issueReferences) {
|
||||||
|
referenceLinks += `[${reference}](${reference}), `
|
||||||
|
}
|
||||||
|
console.log(`References : ${referenceLinks}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(JSON.stringify(issues))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const directory = process.argv[2]
|
||||||
|
checkDirectory(directory)
|
|
@ -0,0 +1,5 @@
|
||||||
|
import nhp from 'node-html-parser';
|
||||||
|
|
||||||
|
export const getTitle = (html) => {
|
||||||
|
return nhp.parse(html).querySelector('title').toString();
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
export default class Rule {
|
||||||
|
constructor (filenames, options) {
|
||||||
|
this.options = options,
|
||||||
|
this.filenames = filenames
|
||||||
|
this.issueCount = 0
|
||||||
|
this.issues = []
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
report() {
|
||||||
|
return {
|
||||||
|
ruleName: this.constructor.name,
|
||||||
|
issueCount: this.issueCount,
|
||||||
|
issues: this.issues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import Rule from './Rule.js'
|
||||||
|
import { extensionFilter, getContent } from '../helpers.js'
|
||||||
|
import { getTitle } from '../parser.js'
|
||||||
|
|
||||||
|
export default class TitleLength extends Rule {
|
||||||
|
initialize() {
|
||||||
|
this.minLength = 30
|
||||||
|
this.maxLength = 70
|
||||||
|
this.filenames = extensionFilter(this.filenames, 'html');
|
||||||
|
}
|
||||||
|
|
||||||
|
report() {
|
||||||
|
return {
|
||||||
|
...super.report(),
|
||||||
|
...{
|
||||||
|
issueDescription: `The <title> should contain between ${this.minLength} and ${this.maxLength} characters.`,
|
||||||
|
issueReferences: ['https://moz.com/learn/seo/title-tag', 'https://www.authorityhacker.com/seo-title-tags/', 'https://www.codeur.com/blog/seo-optimiser-title/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
for (const filename of this.filenames) {
|
||||||
|
const content = getContent(filename);
|
||||||
|
const title = getTitle(content)
|
||||||
|
if (this.test(title)) {
|
||||||
|
this.issueCount++
|
||||||
|
const issue = {
|
||||||
|
url: filename.replace(this.options.directory, ''),
|
||||||
|
title: title
|
||||||
|
}
|
||||||
|
this.issues = [...this.issues, ...[issue]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.report()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import TitleLength from './TitleLength.js'
|
||||||
|
|
||||||
|
export default class TitleLengthTooLong extends TitleLength {
|
||||||
|
report() {
|
||||||
|
if (this.issueCount == 0) return
|
||||||
|
|
||||||
|
return {
|
||||||
|
...super.report(),
|
||||||
|
...{ issueTitle: `Your title is to long on ${this.issueCount} page${this.issueCount == 1 ? '' : 's'}` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test(title) {
|
||||||
|
return title.length > this.maxLength
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import TitleLength from './TitleLength.js'
|
||||||
|
|
||||||
|
export default class TitleLengthTooShort extends TitleLength {
|
||||||
|
report() {
|
||||||
|
if (this.issueCount == 0) return
|
||||||
|
|
||||||
|
return {
|
||||||
|
...super.report(),
|
||||||
|
...{ issueTitle: `Your title is to short on ${this.issueCount} page${this.issueCount == 1 ? '' : 's'}` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test(title) {
|
||||||
|
return title.length < this.minLength
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import Rule from './Rule.js'
|
||||||
|
import { extensionFilter, getContent } from '../helpers.js'
|
||||||
|
import { getTitle } from '../parser.js'
|
||||||
|
|
||||||
|
export default class TitleUnique extends Rule {
|
||||||
|
initialize() {
|
||||||
|
this.filenames = extensionFilter(this.filenames, 'html');
|
||||||
|
}
|
||||||
|
|
||||||
|
report() {
|
||||||
|
return {
|
||||||
|
...super.report(),
|
||||||
|
...{
|
||||||
|
issueTitle: `The <title> should be unique for every page, ${this.issueCount} pages are concerned.`,
|
||||||
|
issueDescription: `You should change title on:`,
|
||||||
|
issueReferences: ['https://moz.com/learn/seo/title-tag']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
let titles = {}
|
||||||
|
for (const filename of this.filenames) {
|
||||||
|
const content = getContent(filename);
|
||||||
|
const title = getTitle(content)
|
||||||
|
titles[title] = titles[title] ? [...titles[title], ...[filename]] : [filename]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const title in titles) {
|
||||||
|
if (titles[title].length > 1) {
|
||||||
|
this.issueCount += titles[title].length
|
||||||
|
const issue = {
|
||||||
|
title: title,
|
||||||
|
url: titles[title]
|
||||||
|
}
|
||||||
|
this.issues = [...this.issues, ...[issue]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.report()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import TitleUnique from './TitleUnique.js'
|
||||||
|
import TitleLengthTooLong from './TitleLengthTooLong.js'
|
||||||
|
import TitleLengthTooShort from './TitleLengthTooShort.js'
|
||||||
|
|
||||||
|
export default function getRules(filesnames, options) {
|
||||||
|
return [
|
||||||
|
new TitleUnique(filesnames, options),
|
||||||
|
new TitleLengthTooLong(filesnames, options),
|
||||||
|
new TitleLengthTooShort(filesnames, options),
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue