planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

View File

@@ -0,0 +1,28 @@
var normalizeUri = require('micromark/dist/util/normalize-uri')
exports.exit = {
literalAutolinkEmail: literalAutolinkEmail,
literalAutolinkHttp: literalAutolinkHttp,
literalAutolinkWww: literalAutolinkWww
}
function literalAutolinkWww(token) {
return anchorFromToken.call(this, token, 'http://')
}
function literalAutolinkEmail(token) {
return anchorFromToken.call(this, token, 'mailto:')
}
function literalAutolinkHttp(token) {
return anchorFromToken.call(this, token)
}
function anchorFromToken(token, protocol) {
var url = this.sliceSerialize(token)
this.tag(
'<a href="' + this.encode(normalizeUri((protocol || '') + url)) + '">'
)
this.raw(this.encode(url))
this.tag('</a>')
}

View File

@@ -0,0 +1 @@
module.exports = require('./syntax')

View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>
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.

View File

@@ -0,0 +1,76 @@
{
"name": "micromark-extension-gfm-autolink-literal",
"version": "0.5.7",
"description": "micromark extension to support GFM autolink literals",
"license": "MIT",
"keywords": [
"micromark",
"micromark-extension",
"literal",
"url",
"autolink",
"auto",
"link",
"gfm",
"markdown",
"unified"
],
"repository": "micromark/micromark-extension-gfm-autolink-literal",
"bugs": "https://github.com/micromark/micromark-extension-gfm-autolink-literal/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"contributors": [
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
],
"files": [
"index.js",
"html.js",
"syntax.js"
],
"dependencies": {
"micromark": "~2.11.3"
},
"devDependencies": {
"nyc": "^15.0.0",
"prettier": "^2.0.0",
"remark-cli": "^9.0.0",
"remark-preset-wooorm": "^8.0.0",
"tape": "^5.0.0",
"xo": "^0.38.0"
},
"scripts": {
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test-api": "node test",
"test-coverage": "nyc --reporter lcov tape test/index.js",
"test": "npm run format && npm run test-coverage"
},
"nyc": {
"check-coverage": true,
"lines": 100,
"functions": 100,
"branches": 100
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"bracketSpacing": false,
"semi": false,
"trailingComma": "none"
},
"xo": {
"prettier": true,
"esnext": false,
"rules": {
"unicorn/no-this-assignment": "off"
}
},
"remarkConfig": {
"plugins": [
"preset-wooorm"
]
}
}

View File

@@ -0,0 +1,133 @@
# micromark-extension-gfm-autolink-literal
[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
**[micromark][]** extension to support GitHub flavored markdown [literal
autolinks][].
This syntax extension matches the GFM spec and how literal autolinks work
in several places on github.com.
Do note that GH employs two algorithms to autolink: one at parse time,
one at compile time (similar to how @mentions are done at compile time).
This difference can be observed because character references and escapes
are handled differently.
But also because issues/PRs/comments omit (perhaps by accident?) the second
algorithm for `www.`, `http://`, and `https://` links (but not for email links).
As this is a syntax extension, it focuses on the first algorithm.
The `html` part of this extension does not operate on an AST and hence cant
perform the second algorithm.
`mdast-util-gfm-autolink-literal` adds support for the second.
This package provides the low-level modules for integrating with the micromark
tokenizer and the micromark HTML compiler.
You probably should use this package with
[`mdast-util-gfm-autolink-literal`][mdast-util-gfm-autolink-literal].
## Install
[npm][]:
```sh
npm install micromark-extension-gfm-autolink-literal
```
## API
### `html`
### `syntax`
> Note: `syntax` is the default export of this module, `html` is available at
> `micromark-extension-gfm-autolink-literal/html`.
Support [literal autolinks][].
The exports are extensions for the micromark parser (to tokenize; can be passed
in `extensions`) and the default HTML compiler (to compile as `<a>` elements;
can be passed in `htmlExtensions`).
## Related
* [`remarkjs/remark`][remark]
— markdown processor powered by plugins
* [`micromark/micromark`][micromark]
— the smallest commonmark-compliant markdown parser that exists
* [`syntax-tree/mdast-util-gfm-autolink-literal`](https://github.com/syntax-tree/mdast-util-gfm-autolink-literal)
— mdast utility to support autolink literals
* [`syntax-tree/mdast-util-from-markdown`][from-markdown]
— mdast parser using `micromark` to create mdast from markdown
* [`syntax-tree/mdast-util-to-markdown`][to-markdown]
— mdast serializer to create markdown from mdast
## Contribute
See [`contributing.md` in `micromark/.github`][contributing] for ways to get
started.
See [`support.md`][support] for ways to get help.
This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][license] © [Titus Wormer][author]
<!-- Definitions -->
[build-badge]: https://github.com/micromark/micromark-extension-gfm-autolink-literal/workflows/main/badge.svg
[build]: https://github.com/micromark/micromark-extension-gfm-autolink-literal/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/micromark/micromark-extension-gfm-autolink-literal.svg
[coverage]: https://codecov.io/github/micromark/micromark-extension-gfm-autolink-literal
[downloads-badge]: https://img.shields.io/npm/dm/micromark-extension-gfm-autolink-literal.svg
[downloads]: https://www.npmjs.com/package/micromark-extension-gfm-autolink-literal
[size-badge]: https://img.shields.io/bundlephobia/minzip/micromark-extension-gfm-autolink-literal.svg
[size]: https://bundlephobia.com/result?p=micromark-extension-gfm-autolink-literal
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[chat]: https://github.com/micromark/micromark/discussions
[npm]: https://docs.npmjs.com/cli/install
[license]: license
[author]: https://wooorm.com
[contributing]: https://github.com/micromark/.github/blob/HEAD/contributing.md
[support]: https://github.com/micromark/.github/blob/HEAD/support.md
[coc]: https://github.com/micromark/.github/blob/HEAD/code-of-conduct.md
[micromark]: https://github.com/micromark/micromark
[from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown
[to-markdown]: https://github.com/syntax-tree/mdast-util-to-markdown
[remark]: https://github.com/remarkjs/remark
[mdast-util-gfm-autolink-literal]: https://github.com/syntax-tree/mdast-util-gfm-autolink-literal
[literal autolinks]: https://github.github.com/gfm/#autolinks-extension-

View File

@@ -0,0 +1,581 @@
var asciiAlpha = require('micromark/dist/character/ascii-alpha')
var asciiAlphanumeric = require('micromark/dist/character/ascii-alphanumeric')
var asciiControl = require('micromark/dist/character/ascii-control')
var markdownLineEnding = require('micromark/dist/character/markdown-line-ending')
var unicodePunctuation = require('micromark/dist/character/unicode-punctuation')
var unicodeWhitespace = require('micromark/dist/character/unicode-whitespace')
var www = {tokenize: tokenizeWww, partial: true}
var domain = {tokenize: tokenizeDomain, partial: true}
var path = {tokenize: tokenizePath, partial: true}
var punctuation = {tokenize: tokenizePunctuation, partial: true}
var namedCharacterReference = {
tokenize: tokenizeNamedCharacterReference,
partial: true
}
var wwwAutolink = {tokenize: tokenizeWwwAutolink, previous: previousWww}
var httpAutolink = {tokenize: tokenizeHttpAutolink, previous: previousHttp}
var emailAutolink = {tokenize: tokenizeEmailAutolink, previous: previousEmail}
var text = {}
// Export hooked constructs.
exports.text = text
// `0`
var code = 48
// While the code is smaller than `{`.
while (code < 123) {
text[code] = emailAutolink
code++
// Jump from `:` -> `A`
if (code === 58) code = 65
// Jump from `[` -> `a`
else if (code === 91) code = 97
}
// `+`
text[43] = emailAutolink
// `-`
text[45] = emailAutolink
// `.`
text[46] = emailAutolink
// `_`
text[95] = emailAutolink
// `h`.
text[72] = [emailAutolink, httpAutolink]
text[104] = [emailAutolink, httpAutolink]
// `w`.
text[87] = [emailAutolink, wwwAutolink]
text[119] = [emailAutolink, wwwAutolink]
function tokenizeEmailAutolink(effects, ok, nok) {
var self = this
var hasDot
return start
function start(code) {
/* istanbul ignore next - hooks. */
if (
!gfmAtext(code) ||
!previousEmail(self.previous) ||
previous(self.events)
) {
return nok(code)
}
effects.enter('literalAutolink')
effects.enter('literalAutolinkEmail')
return atext(code)
}
function atext(code) {
if (gfmAtext(code)) {
effects.consume(code)
return atext
}
// `@`
if (code === 64) {
effects.consume(code)
return label
}
return nok(code)
}
function label(code) {
// `.`
if (code === 46) {
return effects.check(punctuation, done, dotContinuation)(code)
}
if (
// `-`
code === 45 ||
// `_`
code === 95
) {
return effects.check(punctuation, nok, dashOrUnderscoreContinuation)(code)
}
if (asciiAlphanumeric(code)) {
effects.consume(code)
return label
}
return done(code)
}
function dotContinuation(code) {
effects.consume(code)
hasDot = true
return label
}
function dashOrUnderscoreContinuation(code) {
effects.consume(code)
return afterDashOrUnderscore
}
function afterDashOrUnderscore(code) {
// `.`
if (code === 46) {
return effects.check(punctuation, nok, dotContinuation)(code)
}
return label(code)
}
function done(code) {
if (hasDot) {
effects.exit('literalAutolinkEmail')
effects.exit('literalAutolink')
return ok(code)
}
return nok(code)
}
}
function tokenizeWwwAutolink(effects, ok, nok) {
var self = this
return start
function start(code) {
/* istanbul ignore next - hooks. */
if (
(code !== 87 && code - 32 !== 87) ||
!previousWww(self.previous) ||
previous(self.events)
) {
return nok(code)
}
effects.enter('literalAutolink')
effects.enter('literalAutolinkWww')
// For `www.` we check instead of attempt, because when it matches, GH
// treats it as part of a domain (yes, it says a valid domain must come
// after `www.`, but thats not how its implemented by them).
return effects.check(
www,
effects.attempt(domain, effects.attempt(path, done), nok),
nok
)(code)
}
function done(code) {
effects.exit('literalAutolinkWww')
effects.exit('literalAutolink')
return ok(code)
}
}
function tokenizeHttpAutolink(effects, ok, nok) {
var self = this
return start
function start(code) {
/* istanbul ignore next - hooks. */
if (
(code !== 72 && code - 32 !== 72) ||
!previousHttp(self.previous) ||
previous(self.events)
) {
return nok(code)
}
effects.enter('literalAutolink')
effects.enter('literalAutolinkHttp')
effects.consume(code)
return t1
}
function t1(code) {
// `t`
if (code === 84 || code - 32 === 84) {
effects.consume(code)
return t2
}
return nok(code)
}
function t2(code) {
// `t`
if (code === 84 || code - 32 === 84) {
effects.consume(code)
return p
}
return nok(code)
}
function p(code) {
// `p`
if (code === 80 || code - 32 === 80) {
effects.consume(code)
return s
}
return nok(code)
}
function s(code) {
// `s`
if (code === 83 || code - 32 === 83) {
effects.consume(code)
return colon
}
return colon(code)
}
function colon(code) {
// `:`
if (code === 58) {
effects.consume(code)
return slash1
}
return nok(code)
}
function slash1(code) {
// `/`
if (code === 47) {
effects.consume(code)
return slash2
}
return nok(code)
}
function slash2(code) {
// `/`
if (code === 47) {
effects.consume(code)
return after
}
return nok(code)
}
function after(code) {
return asciiControl(code) ||
unicodeWhitespace(code) ||
unicodePunctuation(code)
? nok(code)
: effects.attempt(domain, effects.attempt(path, done), nok)(code)
}
function done(code) {
effects.exit('literalAutolinkHttp')
effects.exit('literalAutolink')
return ok(code)
}
}
function tokenizeWww(effects, ok, nok) {
return start
function start(code) {
// Assume a `w`.
effects.consume(code)
return w2
}
function w2(code) {
// `w`
if (code === 87 || code - 32 === 87) {
effects.consume(code)
return w3
}
return nok(code)
}
function w3(code) {
// `w`
if (code === 87 || code - 32 === 87) {
effects.consume(code)
return dot
}
return nok(code)
}
function dot(code) {
// `.`
if (code === 46) {
effects.consume(code)
return after
}
return nok(code)
}
function after(code) {
return code === null || markdownLineEnding(code) ? nok(code) : ok(code)
}
}
function tokenizeDomain(effects, ok, nok) {
var hasUnderscoreInLastSegment
var hasUnderscoreInLastLastSegment
return domain
function domain(code) {
// `&`
if (code === 38) {
return effects.check(
namedCharacterReference,
done,
punctuationContinuation
)(code)
}
if (code === 46 /* `.` */ || code === 95 /* `_` */) {
return effects.check(punctuation, done, punctuationContinuation)(code)
}
// GH documents that only alphanumerics (other than `-`, `.`, and `_`) can
// occur, which sounds like ASCII only, but they also support `www.點看.com`,
// so thats Unicode.
// Instead of some new production for Unicode alphanumerics, markdown
// already has that for Unicode punctuation and whitespace, so use those.
if (
asciiControl(code) ||
unicodeWhitespace(code) ||
(code !== 45 /* `-` */ && unicodePunctuation(code))
) {
return done(code)
}
effects.consume(code)
return domain
}
function punctuationContinuation(code) {
// `.`
if (code === 46) {
hasUnderscoreInLastLastSegment = hasUnderscoreInLastSegment
hasUnderscoreInLastSegment = undefined
effects.consume(code)
return domain
}
// `_`
if (code === 95) hasUnderscoreInLastSegment = true
effects.consume(code)
return domain
}
function done(code) {
if (!hasUnderscoreInLastLastSegment && !hasUnderscoreInLastSegment) {
return ok(code)
}
return nok(code)
}
}
function tokenizePath(effects, ok) {
var balance = 0
return inPath
function inPath(code) {
// `&`
if (code === 38) {
return effects.check(
namedCharacterReference,
ok,
continuedPunctuation
)(code)
}
// `(`
if (code === 40) {
balance++
}
// `)`
if (code === 41) {
return effects.check(
punctuation,
parenAtPathEnd,
continuedPunctuation
)(code)
}
if (pathEnd(code)) {
return ok(code)
}
if (trailingPunctuation(code)) {
return effects.check(punctuation, ok, continuedPunctuation)(code)
}
effects.consume(code)
return inPath
}
function continuedPunctuation(code) {
effects.consume(code)
return inPath
}
function parenAtPathEnd(code) {
balance--
return balance < 0 ? ok(code) : continuedPunctuation(code)
}
}
function tokenizeNamedCharacterReference(effects, ok, nok) {
return start
function start(code) {
// Assume an ampersand.
effects.consume(code)
return inside
}
function inside(code) {
if (asciiAlpha(code)) {
effects.consume(code)
return inside
}
// `;`
if (code === 59) {
effects.consume(code)
return after
}
return nok(code)
}
function after(code) {
// If the named character reference is followed by the end of the path, its
// not continued punctuation.
return pathEnd(code) ? ok(code) : nok(code)
}
}
function tokenizePunctuation(effects, ok, nok) {
return start
function start(code) {
// Always a valid trailing punctuation marker.
effects.consume(code)
return after
}
function after(code) {
// Check the next.
if (trailingPunctuation(code)) {
effects.consume(code)
return after
}
// If the punctuation marker is followed by the end of the path, its not
// continued punctuation.
return pathEnd(code) ? ok(code) : nok(code)
}
}
function trailingPunctuation(code) {
return (
// `!`
code === 33 ||
// `"`
code === 34 ||
// `'`
code === 39 ||
// `)`
code === 41 ||
// `*`
code === 42 ||
// `,`
code === 44 ||
// `.`
code === 46 ||
// `:`
code === 58 ||
// `;`
code === 59 ||
// `<`
code === 60 ||
// `?`
code === 63 ||
// `_`.
code === 95 ||
// `~`
code === 126
)
}
function pathEnd(code) {
return (
// EOF.
code === null ||
// CR, LF, CRLF, HT, VS.
code < 0 ||
// Space.
code === 32 ||
// `<`
code === 60
)
}
function gfmAtext(code) {
return (
code === 43 /* `+` */ ||
code === 45 /* `-` */ ||
code === 46 /* `.` */ ||
code === 95 /* `_` */ ||
asciiAlphanumeric(code)
)
}
function previousWww(code) {
return (
code === null ||
code < 0 ||
code === 32 /* ` ` */ ||
code === 40 /* `(` */ ||
code === 42 /* `*` */ ||
code === 95 /* `_` */ ||
code === 126 /* `~` */
)
}
function previousHttp(code) {
return code === null || !asciiAlpha(code)
}
function previousEmail(code) {
return code !== 47 /* `/` */ && previousHttp(code)
}
function previous(events) {
var index = events.length
while (index--) {
if (
(events[index][1].type === 'labelLink' ||
events[index][1].type === 'labelImage') &&
!events[index][1]._balanced
) {
return true
}
}
}