kminek / marklink
A simple standard allowing embedding (and parsing) categorized lists of links inside Markdown files.
Installs: 33
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 0
Open Issues: 2
pkg:composer/kminek/marklink
Requires
- php: >=8.0.0
- ext-json: *
- doctrine/collections: 1.6.7
- guzzlehttp/guzzle: 7.2.*
- league/commonmark: 1.5.7
Requires (Dev)
- friendsofphp/php-cs-fixer: 2.18.3
- justinrainbow/json-schema: 5.2.10
- phpstan/phpstan: 0.12.81
- phpunit/phpunit: 9.5.2
- symfony/var-dumper: 5.2.5
This package is auto-updated.
Last update: 2025-10-20 01:44:06 UTC
README
Marklink
A simple standard allowing embedding (and parsing) categorized lists of links inside Markdown files.
Marklink was born as an attempt to standardize various awesome lists of links available on GitHub.
Schema
Every Markdown document with embedded well-formed Marklink sections can be parsed by Marklink parser into tree-like JSON structure with categories and links. This JSON data structure is described by schema file (see marklink.schema.json for reference). Schema file allows JSON structure to be validated (see JSON Schema for reference).
Schema rules
- there are two types of nodes:
categorylink
- there are four types of node fields (apart from
typefield which determines node type):titleurldescriptionchildren
- there is only one root
categorynode categorynodes below root node REQUIRE validtitleand may optionally contain other fieldscategorynode CAN have childcategorynodes ORlinknodes - but not both mixed at the same timelinknode REQUIRE validtitleand validurl, CAN have childlinknodes and CANNOT have childcategorynodes
Examples
Here are some examples how Markdown fragments are parsed by Marklink parser into
JSON data (see tests/ directory for more).
Basic example
Input:
- [Link A](http://a.example.com) - Link A description - [Link B](http://b.example.com) - Link B description with [link](http://link.example.com)
Output:
{
"type": "category",
"children": [
{
"type": "link",
"title": "Link A",
"url": "http://a.example.com",
"description": "Link A description"
},
{
"type": "link",
"title": "Link B",
"url": "http://b.example.com",
"description": "Link B description with [link](http://link.example.com)"
}
]
}
Advanced example
Input:
## Category A Category A description ### Sub-category A - Sub-sub-category A - [Link A](http://a.example.com) - Link A description - [Link B](http://b.example.com) - Link B description with [link](http://link.example.com) - [Link C](http://c.example.com) - Link C description
Output:
{
"type": "category",
"children": [
{
"type": "category",
"title": "Category A",
"description": "Category A description",
"children": [
{
"type": "category",
"title": "Sub-category A",
"children": [
{
"type": "category",
"title": "Sub-sub-category A",
"children": [
{
"type": "link",
"title": "Link A",
"url": "http://a.example.com",
"description": "Link A description"
},
{
"type": "link",
"title": "Link B",
"url": "http://b.example.com",
"description": "Link B description with [link](http://link.example.com)",
"children": [
{
"type": "link",
"title": "Link C",
"url": "http://c.example.com",
"description": "Link C description",
}
]
}
]
}
]
}
]
}
]
}
Input with markers
By default Marklink parser will parse whole document unless it finds following markers:
<!-- marklink:start --> - [Link A](http://a.example.com) - Link A description - [Link B](http://b.example.com) - Link B description with [link](http://link.example.com) <!-- marklink:end -->
In that case only content between markers will be parsed.
Online Marklink parsing service
Initial Markling parser implementation is available as a service.
Web interface
https://awesomelist.kminek.pl/marklink
cURL example
curl --request POST \ --url https://awesomelist.kminek.pl/api/markdown \ --header 'cache-control: no-cache' \ --header 'content-type: application/json' \ --data '{"input": "- [Link A](http://a.example.com) - Link A description\n- [Link B](http://b.example.com) - Link B description with [link](http://link.example.com)"}'
PHP example
composer require kminek/marklink
use Kminek\Marklink\ParserService; $markdown = <<<MARKDOWN - [Link A](http://a.example.com) - Link A description - [Link B](http://b.example.com) - Link B description with [link](http://link.example.com) MARKDOWN; $parser = new ParserService; $result = $parser->parse($markdown);