# textlint-rule-allowed-uris [](https://github.com/lumirlumir/npm-textlint-rule-allowed-uris/actions/workflows/lint.yml) [](https://github.com/lumirlumir/npm-textlint-rule-allowed-uris/actions/workflows/test.yml) [](https://codecov.io/gh/lumirlumir/npm-textlint-rule-allowed-uris) [](https://www.npmjs.com/package/textlint-rule-allowed-uris) A textlint rule for checking **allowed or disallowed URIs** in ***links*** and ***images*** of Markdown.🔥 > [!IMPORTANT] > > 1. This rule only supports **Markdown(`.md` or `.mdx`)** files. Note that it does not recognize URIs in **~~Text~~(`.txt`)** files. > 1. The linting process includes HTTP requests, so an <u>**internet connection is required**</u>. Otherwise, an error will occur. > 1. Note that every URIs should be recognized by Markdown. URIs which are not recognized by Markdown cannot be inspected. For example, URIs without `https://...` or `http://...`. > > ```markdown > www.google.com > <www.google.com> > ``` ## Features ### Supported You can use any ***link*** or ***image*** formats which are supported by Markdown. (Even **HTML tags** are available!) - [Click to see detailed Markdown examples](/tests/textlint-rule-allowed-uris.data.md). Look at **raw** codes. these all types are considered. - You can also check out the [AST Tree of the above examples](https://textlint.github.io/astexplorer/#/snippet/woXCqHBhcnNlcklEwrh0ZXh0bGludDptxINrZG93bi10by1hc3TCqMSFdHTEkGdzwoHEisSMxI7EkMSSxJRyxJbEmMSaxJzEnsSgw4DCqHbEhnNpb27EqMSqxI3Ej8SRxJPElcSXxJnEm8SdxJ90wqYxNC4wLjXCqGZpbGVuYW1lwrBzb3VyY2UudW5kZcWUbmVkwqRjb8Wmw5oJezwhLS0gxK_EscSZxYJ0LWRpc2FixZYgxbU-CgojIyBMxJBrc8aHxbPFtcW3xYXEssSedcScxYJrLXJhd8aELcaGCmjEpHBzOi8vd8aqLmdvb2fFli7FrW3Gh8SMxZlwxZZAZ8SUxZXGsm_GtArGkcW2xbjFhsSaYcaXb8aZLWLGnGNrZXTGn8ahPMajdMalxqfGqcarxq3Gr8axxrPHk8a2bca4Zca6xrxsxr5tx5PFtMeDxpTFh8SQxYJlx5LGh1vHm8awZV0ox5XHl8aoxqp3xqzGrse1x6cgIkhlbGxvIEfHv8WWIinHsse0xZbHtykgx4IgZcehdHkgxpnHsQpbxKXEjse2KCNoZWHFvm5nyJPIlWjEn2goZsacxrvFl3TIk8aFx7JSRUFETUUubWTHty4uL8i5yLvIvci_ZMirx6ogcsiFYcSlxLkgxIJ0aMidyJXHhMaVyY5mxIbFl8WhLWZ1yIbIncezyIvHtlvGmTFdx7LJqV06IMe5xqbHu8eayabIgciDyIXIh8iJyaYixpDJjMmZxYfJm8mdbsmfxa3IhmHGpcWqyaTGmTJdW8mryJ7Ki8muybDGpMmyx5nHvciQxaLGs8iCyITIhsiIyIrHnGXJvMeByb7HrMSayoHJjsqDZS1zaG9ydGPGl8qKxo0zyo_JqMq0ypLJsceYx7zHvsqgybbKnMm5yp_HtcqiyKx0bWzJl2HJsMmbPSLKusmzypfJtcazIj7KmDwvYcahxokgScSUZ2XGj8qjxpLJv8Sax67EkMewyLcKIVvHoMeix7fLjy91xrhvyKcud2lracWaxb5hLsquZ8apy7hpcMWqaWEvxZfLmMuYOS9FeMa3xrFqcGfIgsyOzJDHsMudYcufyI3JvcujyqXGm8WnyoLJn8mhyaPLqcury63IkVvLusyaZcmqx7LMq8ufyarJr8uwy7LIh8u1y7fLucu7zIbLvnLMgMy4zIPMhcyHzInMh2HMjMyWx6HMkcyTzJXMj82IzJjLnsqhzJ3Hq8Swx4XMoMmcyqjKhMeJbMqHxIVkyJ3Lq8ywZcqMyo7Mr82PyozMs8qUx5jMtcu0ZMu2zILMusu9y7_Mgcu5zITLvMyIbsyKzYXMjc2Mx6IuzJLMlCLNh8eiy5zNj8uEyqTNk8mazKHNl8qqyqzKrsqwyrLMpsyqzY_Ktc2kzKzKtc2nx5bKlc2qzLfNrs2BzLzMvsyCzbTMhs22zbjNhs27zYnNv86BxoPMmcybzZHKk8uHyZfLusyUc8Wgy43MtMuzzpvMuc6dzbHMv86hzYLNt82EzqXMl829zJPLlMaQxb52PjzOsSDOs2POtc2oxqjOms2szL_Nr86ezbLNgM21zYPMi826z4LNvsuUz4ptzrLOtMuOz5DLsc63z5POnMu8z5bOvM2BzqPPgM-czY3Pg2fPny_Ph8eTz7YKIMiUz4vPjc-PzpjNqc-nza3Ouc-qzrvOoM-tz5rNuc6pxaLPnsaGz7rPoM-iz47PpM-_z5HQgc-UzrrMvc-Xzr3Prs-b0IrPss-Fy5fPuMaIxorOq8ewy7fJlSDLisaZx7LMp86myKLOtsy2z6jQg8y70IXNs9CHzr_QnNCtz7LNi8yXzoPMrMiNy6_PpcWX0ILPmNCz0JjMvy9GxZVlOtCdzb7IjtCiIEPGv8WaxJHLoVvGqMqSxoooVGjFvyBiZcitxLlzyJvLuMewy4rGs9GUyLXIntGYya_GiiLRnNGe0aDRosug0aXHj9CoINGpyLTJvNGXL9GZICfRsdGk0bNh0aPRttGn0bnRk8i0J8ie0brEkcqSPD4g0ZvRndKD0aHShdG1xI_Rt9Go0orEkciOW9KOdNKQ0pLRsNKV0Z_Sl9KG0prSiNKh0bzSodKj0oDSgtKn0bTRpNKq0bjSodKM0ZBPyZXEusmsxo1Mb2NhbMyuypDSvtOA04LMsiDJhci6yLzIvsmAypvJuMiIyYbTjcqiW8WpxLlyVc2cypIvTElDRU5TRciC05fEhtOaxarLhM-40I7PvM-j0K_Nq9GDz5XQtNGEzr7OpM-wzbzQjDzHjNCNyJTLimjLjNCSx7rKlsq9yIDLk8uVyabLl8uZ07py07zQj8-M067Ppc-S07HQl86f0LXPmdC30InQudO507vHgc-1ac-ICg}). ### Only URIs are inspected? No! We check not only for URIs, but also for **local paths**. Below patterns are inspected too. ```text README.md (Relative path) /README.md (Absolute path) ../README.md (Relative path) /learn/start-a-new-react-project#can-i-use-react-without-a-framework (With hash) /images/languages/javascript/composition-of-javascript/2.png?raw=true (With query parameters) And more... ``` ### Patterns Only **regular expressions** are used for URIs pattern matching. You can define the pattern you want to inspect by yourself. ### Allowed URIs > Related: `allowed.links`, `allowed.images` Allowed URIs act like an <u>**whitelist**</u>. Only those written on the whitelist **can** pass through. For example, If you pass an empty array to the option, it allows nothing. i.e. Every ***links*** or ***images*** will be detected. (For a detailed explanation, see [Configs](#configs).) ### Disallowed URIs > Related: `disallowed.links`, `disallowed.images` On the contrary, disallowed URIs act like an <u>**blacklist**</u>. Only those written on the blacklist **cannot** pass through. For example, If you pass an empty array to the option, it allows everything. i.e. no ***links*** or ***images*** will be detected. (For a detailed explanation, see [Configs](#configs).) ## Installation ### `npm` ```bash npm install --save-dev textlint-rule-allowed-uris ``` ### `yarn` ```bash yarn add --dev textlint-rule-allowed-uris ``` ## Configs ### Interface Every options are optional. If you pass nothing, then nothing just happens! ```typescript { rules: { "allowed-uris": { allowed?: { // Optional links?: RegExp[], // Optional images?: RegExp[], // Optional }, disallowed?: { // Optional links?: RegExp[], // Optional images?: RegExp[], // Optional }, } } } ``` ### Options 1. `allowed.links`: `RegExp[]`, Optional - Allowed `links` act like an <u>**whitelist**</u>. Only those written on the whitelist can pass through. - If you want to turn off this option, then pass nothing. **NOTE: DO NOT PASS AN EMPTY ARRAY TO TURN OFF THIS OPTION.** ```javascript /* .textlintrc.js */ // Correct way of turning off this option. module.exports = { rules: { "allowed-uris": { allowed: { // links: [], => turned off images: [/example/], }, disallowed: { links: [/example/], images: [/example/], }, } } } ``` - Default value passed: `[/.*/]` 1. `allowed.images`: `RegExp[]`, Optional - Allowed `images` act like an <u>**whitelist**</u>. Only those written on the whitelist can pass through. - If you want to turn off this option, then pass nothing. **NOTE: DO NOT PASS AN EMPTY ARRAY TO TURN OFF THIS OPTION.** ```javascript /* .textlintrc.js */ // Correct way of turning off this option. module.exports = { rules: { "allowed-uris": { allowed: { links: [/example/], // images: [], => turned off }, disallowed: { links: [/example/], images: [/example/], }, } } } ``` - Default value passed: `[/.*/]` 1. `disallowed.links`: `RegExp[]`, Optional - Disallowed `links` act like an <u>**blacklist**</u>. Only those written on the blacklist **cannot** pass through. - If you want to turn off this option, then pass nothing. or here, you can pass an empty array. (because the default value passed is an empty array too.) ```javascript /* .textlintrc.js */ // Correct way of turning off this option. module.exports = { rules: { "allowed-uris": { allowed: { links: [/example/], images: [/example/], }, disallowed: { // links: [], => turned off images: [/example/], }, } } } ``` - Default value passed: `[]` 1. `disallowed.images`: `RegExp[]`, Optional - Disallowed `images` act like an <u>**blacklist**</u>. Only those written on the blacklist **cannot** pass through. - If you want to turn off this option, then pass nothing. or here, you can pass an empty array. (because the default value passed is an empty array too.) ```javascript /* .textlintrc.js */ // Correct way of turning off this option. module.exports = { rules: { "allowed-uris": { allowed: { links: [/example/], images: [/example/], }, disallowed: { links: [/example/], // images: [], => turned off }, } } } ``` - Default value passed: `[]` ### Example (`.textlintrc.js`) ```javascript module.exports = { rules: { "allowed-uris": { allowed: { links: [ // regular expressions ], images: [ // regular expressions ], }, disallowed: { links: [ // regular expressions ], images: [ // regular expressions ], }, } } } ``` ## Usages ```bash textlint [options] file.md [file|dir|glob*] ``` ### Without a config file ```bash npx textlint --rule allowed-uris -f pretty-error file.md ``` ### With a config file ```bash npx textlint -f pretty-error file.md ``` ## Sample Outputs When configured like below. ```javascript module.exports = { rules: { "allowed-uris": { allowed: { links: [/google/], }, } } } ``` ### `-f pretty-error` option <details> <summary> Click to see sample outputs </summary> ```text > npx textlint tests/textlint-rule-allowed-uris.data.md --rulesdir ./src -f pretty-error textlint-rule-allowed-uris: allowed.links - problem: 'mailto:example@gmail.com' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:9:1 v 8. 9. example@gmail.com 10. ^ textlint-rule-allowed-uris: allowed.links - problem: 'mailto:example@gmail.com' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:15:1 v 14. 15. <example@gmail.com> 16. ^ textlint-rule-allowed-uris: allowed.links - problem: '' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:21:1 v 20. 21. [google]() <!-- empty link --> 22. ^ textlint-rule-allowed-uris: allowed.links - problem: '#heading' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:23:1 v 22. 23. [title](#heading) <!-- hash(fragment) --> 24. ^ textlint-rule-allowed-uris: allowed.links - problem: '../README.md' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:25:1 v 24. 25. [README.md](../README.md) <!-- relative path --> 26. ^ textlint-rule-allowed-uris: allowed.links - problem: 'https://en.wikipedia.org/wiki/File:Example.jpg' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:86:1 v 85. 86. [](https://en.wikipedia.org/wiki/File:Example.jpg) 87. ^ textlint-rule-allowed-uris: allowed.links - problem: '/README.md' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:101:1 v 100. 101. [linkLocal1]: /README.md "Hello README" 102. ^ textlint-rule-allowed-uris: allowed.links - problem: '/LICENSE' - allowed regular expressions: '/google/' textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md:103:1 v 102. 103. [neverUsed]: /LICENSE "neverUsed" 104. ^ ✖ 8 problems (8 errors, 0 warnings) ``` </details> ### `-f stylish` option <details> <summary> Click to see sample outputs </summary> ```text > npx textlint tests/textlint-rule-allowed-uris.data.md --rulesdir ./src -f stylish textlint-rule-allowed-uris/tests/textlint-rule-allowed-uris.data.md 9:1 error allowed.links - problem: 'mailto:example@gmail.com' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 15:1 error allowed.links - problem: 'mailto:example@gmail.com' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 21:1 error allowed.links - problem: '' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 23:1 error allowed.links - problem: '#heading' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 25:1 error allowed.links - problem: '../README.md' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 86:1 error allowed.links - problem: 'https://en.wikipedia.org/wiki/File:Example.jpg' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 101:1 error allowed.links - problem: '/README.md' - allowed regular expressions: '/google/' textlint-rule-allowed-uris 103:1 error allowed.links - problem: '/LICENSE' - allowed regular expressions: '/google/' textlint-rule-allowed-uris ✖ 8 problems (8 errors, 0 warnings) ``` </details> ## Q&A ### How to distinguish email links? Email links like `<example@gmail.com>` are interpreted as `mailto:example@gmail.com`. Therefore, use `/^mailto:/` in regular expressions. ## Contributing Thanks for having attention to this package.🙇♂️ Issues and PRs are always welcome.🎉 I recommend you to read [textlint guides](https://textlint.github.io/) before contributing. And check out the [Installation](#installation) and [Concepts of `textlint-rule-allowed-uris`](#concepts-of-textlint-rule-allowed-uris) guides below. It will help you to understand how this package works. After that, refer to the comments in source codes. It contains useful information to help you. ### Installation 1. Fork it. 1. Clone it to your local directory. ([Git](https://git-scm.com/downloads) is required.) ```bash git clone https://github.com/lumirlumir/npm-textlint-rule-allowed-uris.git ``` 1. Move to the `npm-textlint-rule-allowed-uris` directory. ```bash cd npm-textlint-rule-allowed-uris ``` 1. Install npm packages. ([Node.js](https://nodejs.org/en) is required.) ```bash npm install ``` 1. Edit codes. 1. Create `my-branch` branch. ```bash git switch -c my-branch ``` 1. Commit your changes. (`husky` and `lint-staged` will lint and test your changed files!) ```bash git commit -am "commit type: title" ``` 1. Push them to your remote branch. 1. Submit a pull request.👍 ### Concepts of `textlint-rule-allowed-uris` `textlint-rule-allowed-uris` rule checks **allowed or disallowed URIs** in ***links*** and ***images*** of Markdown. #### Detailed node types which are checked by this rule 1. ***Links*** node type 1. `Link`(`ASTNodeTypes.Link`) 1. `Definition` (We don't use ~~`LinkReference`~~) 1. `Html`(`ASTNodeTypes.Html`) 1. ***Images*** node type 1. `Image`(`ASTNodeTypes.Image`) 1. `Definition` (We don't use ~~`ImageReference`~~) 1. `Html`(`ASTNodeTypes.Html`) > [!NOTE] > > `LinkReference`, `ImageReference` and `Definition` are types parsed by [`@textlint/text-to-ast`](https://github.com/textlint/textlint/tree/master/packages/@textlint/markdown-to-ast/). But, It is not defined in [`@textlint/ast-node-types`](https://github.com/textlint/textlint/tree/master/packages/%40textlint/ast-node-types). > > However, you can use these three node types. It is described in [textlint guides](https\://github.com/textlint/textlint/blob/master/docs/txtnode.md). See below. > > > > Other plugin has defined other node type that is not defined in `@textlint/ast-node-types`, but you can specify it as just a string. > > > > ```js > > // A rule can treat "Example" node type > > export default () => { > > return { > > ["Example"](node) { > > // do something > > } > > }; > > }; > > ``` > > i.e. you can use other node types that is not defined in `@textlint/ast-node-types`. like `Definition` type. #### AST Tree You can see detailed parsed AST Tree in [here](https://textlint.github.io/astexplorer/#/snippet/woXCqHBhcnNlcklEwrh0ZXh0bGludDptxINrZG93bi10by1hc3TCqMSFdHTEkGdzwoHEisSMxI7EkMSSxJRyxJbEmMSaxJzEnsSgw4DCqHbEhnNpb27EqMSqxI3Ej8SRxJPElcSXxJnEm8SdxJ90wqYxNC4wLjXCqGZpbGVuYW1lwrBzb3VyY2UudW5kZcWUbmVkwqRjb8Wmw5oJezwhLS0gxK_EscSZxYJ0LWRpc2FixZYgxbU-CgojIyBMxJBrc8aHxbPFtcW3xYXEssSedcScxYJrLXJhd8aELcaGCmjEpHBzOi8vd8aqLmdvb2fFli7FrW3Gh8SMxZlwxZZAZ8SUxZXGsm_GtArGkcW2xbjFhsSaYcaXb8aZLWLGnGNrZXTGn8ahPMajdMalxqfGqcarxq3Gr8axxrPHk8a2bca4Zca6xrxsxr5tx5PFtMeDxpTFh8SQxYJlx5LGh1vHm8awZV0ox5XHl8aoxqp3xqzGrse1x6cgIkhlbGxvIEfHv8WWIinHsse0xZbHtykgx4IgZcehdHkgxpnHsQpbxKXEjse2KCNoZWHFvm5nyJPIlWjEn2goZsacxrvFl3TIk8aFx7JSRUFETUUubWTHty4uL8i5yLvIvci_ZMirx6ogcsiFYcSlxLkgxIJ0aMidyJXHhMaVyY5mxIbFl8WhLWZ1yIbIncezyIvHtlvGmTFdx7LJqV06IMe5xqbHu8eayabIgciDyIXIh8iJyaYixpDJjMmZxYfJm8mdbsmfxa3IhmHGpcWqyaTGmTJdW8mryJ7Ki8muybDGpMmyx5nHvciQxaLGs8iCyITIhsiIyIrHnGXJvMeByb7HrMSayoHJjsqDZS1zaG9ydGPGl8qKxo0zyo_JqMq0ypLJsceYx7zHvsqgybbKnMm5yp_HtcqiyKx0bWzJl2HJsMmbPSLKusmzypfJtcazIj7KmDwvYcahxokgScSUZ2XGj8qjxpLJv8Sax67EkMewyLcKIVvHoMeix7fLjy91xrhvyKcud2lracWaxb5hLsquZ8apy7hpcMWqaWEvxZfLmMuYOS9FeMa3xrFqcGfIgsyOzJDHsMudYcufyI3JvcujyqXGm8WnyoLJn8mhyaPLqcury63IkVvLusyaZcmqx7LMq8ufyarJr8uwy7LIh8u1y7fLucu7zIbLvnLMgMy4zIPMhcyHzInMh2HMjMyWx6HMkcyTzJXMj82IzJjLnsqhzJ3Hq8Swx4XMoMmcyqjKhMeJbMqHxIVkyJ3Lq8ywZcqMyo7Mr82PyozMs8qUx5jMtcu0ZMu2zILMusu9y7_Mgcu5zITLvMyIbsyKzYXMjc2Mx6IuzJLMlCLNh8eiy5zNj8uEyqTNk8mazKHNl8qqyqzKrsqwyrLMpsyqzY_Ktc2kzKzKtc2nx5bKlc2qzLfNrs2BzLzMvsyCzbTMhs22zbjNhs27zYnNv86BxoPMmcybzZHKk8uHyZfLusyUc8Wgy43MtMuzzpvMuc6dzbHMv86hzYLNt82EzqXMl829zJPLlMaQxb52PjzOsSDOs2POtc2oxqjOms2szL_Nr86ezbLNgM21zYPMi826z4LNvsuUz4ptzrLOtMuOz5DLsc63z5POnMu8z5bOvM2BzqPPgM-czY3Pg2fPny_Ph8eTz7YKIMiUz4vPjc-PzpjNqc-nza3Ouc-qzrvOoM-tz5rNuc6pxaLPnsaGz7rPoM-iz47PpM-_z5HQgc-UzrrMvc-Xzr3Prs-b0IrPss-Fy5fPuMaIxorOq8ewy7fJlSDLisaZx7LMp86myKLOtsy2z6jQg8y70IXNs9CHzr_QnNCtz7LNi8yXzoPMrMiNy6_PpcWX0ILPmNCz0JjMvy9GxZVlOtCdzb7IjtCiIEPGv8WaxJHLoVvGqMqSxoooVGjFvyBiZcitxLlzyJvLuMewy4rGs9GUyLXIntGYya_GiiLRnNGe0aDRosug0aXHj9CoINGpyLTJvNGXL9GZICfRsdGk0bNh0aPRttGn0bnRk8i0J8ie0brEkcqSPD4g0ZvRndKD0aHShdG1xI_Rt9Go0orEkciOW9KOdNKQ0pLRsNKV0Z_Sl9KG0prSiNKh0bzSodKj0oDSgtKn0bTRpNKq0bjSodKM0ZBPyZXEusmsxo1Mb2NhbMyuypDSvtOA04LMsiDJhci6yLzIvsmAypvJuMiIyYbTjcqiW8WpxLlyVc2cypIvTElDRU5TRciC05fEhtOaxarLhM-40I7PvM-j0K_Nq9GDz5XQtNGEzr7OpM-wzbzQjDzHjNCNyJTLimjLjNCSx7rKlsq9yIDLk8uVyabLl8uZ07py07zQj8-M067Ppc-S07HQl86f0LXPmdC30InQudO507vHgc-1ac-ICg}). (Already mentioned above.) Look which kind of types are exist for ***links*** and ***images***. ## Versioning This project adheres to [Semantic Versioning](https://semver.org/). ## Change Log See [`CHANGELOG.md`](/CHANGELOG.md) ## License [MIT](/LICENSE)