feat(17-03): full sitemap generation, settings, hooks and import commands

- generator in Definition::addItemToSet order: 50000 URL cap, lastmod from
  the record or the updates manifest (regular file, 5 MiB cap, fail safe),
  BeforeAddItem (skip) and AddItem (extra XML) festival events, tier or item
  priority, per-alternate expansion of list type children
- priority tiers from golem15.sitemap.priority_tiers, compiled at boot,
  defaults equal to the PHP getPriorityForUrl rules
- frontend_url rewrite of loc, xhtml:link href and the stylesheet href;
  GET /sitemap.xsl serves the PHP stylesheet byte for byte
- golem15_sitemap_settings singleton and Settings model
- sitemap:import (PHP ImportCommand) and sitemap:import-winter with the
  read-only Winter export SQL
- urlto and full goldens generated from PHP; TestSitemapImportSmoke
This commit is contained in:
2026-10-12 17:07:39 +02:00
parent fe39e26ce0
commit 4a82240429
24 changed files with 2970 additions and 54 deletions

58
classes/testdata/full.golden vendored Normal file
View File

@@ -0,0 +1,58 @@
=== escaping
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://a&amp;b&lt;c&gt;.pl/x</loc><changefreq>a&amp;b&lt;c&gt;"d'e&#13;f g
h</changefreq><priority>0.5 &amp; &lt;1&gt; "q" 'a'</priority></url><url><loc>https://api.example.test/za%C5%BC%C3%B3%C5%82%C4%87%20%26%20co</loc><lastmod>2026-01-02T03:04:05+00:00</lastmod><changefreq>x&gt;y</changefreq><priority>&lt;0.9&gt;</priority><xhtml:link rel="alternate" hreflang="x&quot;y&amp;z&lt;&#9;&#10;&#13;'&gt;" href="https://q&amp;r&lt;s&gt;.pl/p"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/za%C5%BC%C3%B3%C5%82%C4%87"/></url></urlset>
=== empty-urlset
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"/>
=== no-items
=== hreflang-list
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/pl/a</loc><lastmod>2026-02-01T00:00:00+00:00</lastmod><changefreq>monthly</changefreq><priority>0.4</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/pl/a"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/a"/></url><url><loc>https://api.example.test/en/a</loc><lastmod>2026-02-01T00:00:00+00:00</lastmod><changefreq>monthly</changefreq><priority>0.4</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/pl/a"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/a"/></url><url><loc>https://api.example.test/pl/b</loc><changefreq>monthly</changefreq><priority>0.4</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/pl/b"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/b"/><xhtml:link rel="alternate" hreflang="de" href="https://api.example.test/de/b"/></url><url><loc>https://api.example.test/en/b</loc><changefreq>monthly</changefreq><priority>0.4</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/pl/b"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/b"/><xhtml:link rel="alternate" hreflang="de" href="https://api.example.test/de/b"/></url><url><loc>https://api.example.test/de/b</loc><changefreq>monthly</changefreq><priority>0.4</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/pl/b"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/b"/><xhtml:link rel="alternate" hreflang="de" href="https://api.example.test/de/b"/></url><url><loc>https://api.example.test/solo</loc><changefreq>monthly</changefreq><priority>0.4</priority></url></urlset>
=== nested
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/kategoria/a</loc><lastmod>2026-03-01T12:00:00+00:00</lastmod><changefreq>daily</changefreq><priority>0.7</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/kategoria/a"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/category/a"/></url><url><loc>https://api.example.test/kategoria/b</loc><lastmod>2026-03-02T12:00:00+00:00</lastmod><changefreq>daily</changefreq><priority>0.7</priority><xhtml:link rel="alternate" hreflang="pl" href="https://api.example.test/kategoria/b"/><xhtml:link rel="alternate" hreflang="en" href="https://api.example.test/en/category/b"/></url><url><loc>https://api.example.test/kategoria/c</loc><changefreq>daily</changefreq><priority>0.7</priority></url></urlset>
=== tiers-default
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/</loc><changefreq>weekly</changefreq><priority>1.0</priority></url><url><loc>https://api.example.test/en</loc><changefreq>weekly</changefreq><priority>1.0</priority></url><url><loc>https://api.example.test/en</loc><changefreq>weekly</changefreq><priority>1.0</priority></url><url><loc>https://api.example.test/uslugi/x</loc><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://api.example.test/uslugi/x/y</loc><changefreq>weekly</changefreq><priority>0.3</priority></url><url><loc>https://api.example.test/realizacje/r</loc><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://api.example.test/en/work/w</loc><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://api.example.test/blog/a/b</loc><changefreq>weekly</changefreq><priority>0.6</priority></url><url><loc>https://api.example.test/en/blog/a/b</loc><changefreq>weekly</changefreq><priority>0.6</priority></url><url><loc>https://api.example.test/blog/a</loc><changefreq>weekly</changefreq><priority>0.4</priority></url><url><loc>https://api.example.test/blog</loc><changefreq>weekly</changefreq><priority>0.4</priority></url><url><loc>https://api.example.test/en/blog</loc><changefreq>weekly</changefreq><priority>0.4</priority></url><url><loc>https://api.example.test/uslugi</loc><changefreq>weekly</changefreq><priority>0.4</priority></url><url><loc>https://api.example.test/kontakt</loc><changefreq>weekly</changefreq><priority>0.2</priority></url><url><loc>https://api.example.test/kontakt</loc><changefreq>weekly</changefreq><priority>0.2</priority></url><url><loc>https://api.example.test/en/ai-lab/blob-playground</loc><changefreq>weekly</changefreq><priority>0.2</priority></url><url><loc>https://api.example.test/other</loc><changefreq>weekly</changefreq><priority>0.3</priority></url><url><loc>https://elsewhere.pl/uslugi/z</loc><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://api.example.test/o-nas?x=1</loc><changefreq>weekly</changefreq><priority>0.2</priority></url><url><loc>https://api.example.test/blog/a/b/c</loc><changefreq>weekly</changefreq><priority>0.3</priority></url></urlset>
=== tiers-settings
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/</loc><changefreq>weekly</changefreq><priority>0.95</priority></url><url><loc>https://api.example.test/blog/a/b</loc><changefreq>weekly</changefreq><priority></priority></url><url><loc>https://api.example.test/regulamin</loc><changefreq>weekly</changefreq><priority>0.15</priority></url><url><loc>https://api.example.test/x</loc><changefreq>weekly</changefreq><priority>0.3</priority></url></urlset>
=== tiers-off
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/</loc><changefreq>weekly</changefreq><priority>0.1</priority></url><url><loc>https://api.example.test/blog/a/b</loc><changefreq>weekly</changefreq><priority>0.2</priority></url></urlset>
=== rewrite
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://www.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://www.example.test/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://www.example.test/a</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://www.example.test/b?x=https%3A%2F%2Fapi.example.test%2Fc</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://other.example.test/api.example.test</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://www.example.test/p</loc><changefreq>daily</changefreq><priority>0.7</priority><xhtml:link rel="alternate" hreflang="pl" href="https://www.example.test/p"/><xhtml:link rel="alternate" hreflang="en" href="https://www.example.test/en/p"/></url><url><loc>https://www.example.test/en/p</loc><changefreq>daily</changefreq><priority>0.7</priority><xhtml:link rel="alternate" hreflang="pl" href="https://www.example.test/p"/><xhtml:link rel="alternate" hreflang="en" href="https://www.example.test/en/p"/></url></urlset>
=== rewrite-same
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/a</loc><changefreq>weekly</changefreq><priority>0.5</priority></url></urlset>
=== manifest
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/</loc><lastmod>2026-05-01T08:00:00+00:00</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/about</loc><lastmod>2026-05-02T00:00:00+00:00</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/about</loc><lastmod>2026-05-02T00:00:00+00:00</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/blog/x</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/none</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/rel</loc><lastmod>2026-05-03T01:02:03+00:00</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url><url><loc>https://api.example.test/about</loc><lastmod>2026-06-01T00:00:00+00:00</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url></urlset>
=== skip-extra
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/extra</loc><changefreq>weekly</changefreq><priority>0.5</priority><extra>a&amp;b &lt;c&gt;</extra></url><url><loc>https://api.example.test/keep</loc><changefreq>weekly</changefreq><priority>0.5</priority></url></urlset>
=== precision
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/p1</loc><changefreq>daily</changefreq><priority>0.5</priority></url><url><loc>https://api.example.test/p2</loc><changefreq>daily</changefreq><priority>1</priority></url><url><loc>https://api.example.test/p3</loc><changefreq>7</changefreq><priority>1</priority></url><url><loc>https://api.example.test/p4</loc><changefreq>daily</changefreq><priority>1.0</priority></url><url><loc>https://api.example.test/p5</loc><changefreq>daily</changefreq><priority>0.50</priority></url><url><loc>https://api.example.test/p6</loc><changefreq>daily</changefreq><priority>0.6</priority></url></urlset>
=== url-null
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://api.example.test/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>https://api.example.test/</loc><changefreq></changefreq><priority></priority></url><url><loc>https://api.example.test/0</loc><changefreq>daily</changefreq><priority>0.5</priority></url></urlset>
=== port-root
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://localhost:8096/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>http://localhost:8096/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>http://localhost:8096/a%20b</loc><changefreq>weekly</changefreq><priority>0.5</priority></url></urlset>

693
classes/testdata/full.json vendored Normal file
View File

@@ -0,0 +1,693 @@
{
"cases": [
{
"name": "escaping",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "https://a&b<c>.pl/x",
"changefreq": "a&b<c>\"d'e\rf\tg\nh",
"priority": "0.5 & <1> \"q\" 'a'"
},
{
"type": "acme-post",
"reference": "1",
"urlPattern": "",
"changefreq": "x>y",
"priority": "<0.9>",
"nesting": "1"
}
],
"types": {
"acme-post": {
"1": {
"url": "/zażółć & co",
"mtime": "2026-01-02T03:04:05+00:00",
"alternates": [
[
"x\"y&z<\t\n\r'>",
"https://q&r<s>.pl/p"
],
[
"en",
"/en/zażółć"
]
]
}
}
}
},
{
"name": "empty-urlset",
"root": "https://api.example.test",
"items": [
{
"type": "acme-post",
"reference": "404",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
},
{
"type": "unknown-type",
"reference": "1",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
}
],
"types": {
"acme-post": {}
}
},
{
"name": "no-items",
"root": "https://api.example.test",
"items": []
},
{
"name": "hreflang-list",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "acme-list",
"reference": "",
"urlPattern": "",
"changefreq": "monthly",
"priority": "0.4",
"nesting": "1"
}
],
"types": {
"acme-list": {
"": {
"url": "",
"items": [
{
"url": "/pl/a",
"mtime": "2026-02-01T00:00:00+00:00",
"alternates": [
[
"pl",
"/pl/a"
],
[
"en",
"/en/a"
]
]
},
{
"url": "/pl/b",
"mtime": null,
"alternates": [
[
"pl",
"/pl/b"
],
[
"en",
"/en/b"
],
[
"de",
"/de/b"
]
]
},
{
"url": "/solo",
"alternates": []
}
]
}
}
}
},
{
"name": "nested",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "acme-cat",
"reference": "5",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
}
],
"types": {
"acme-cat": {
"5": {
"url": "/kategoria/a",
"mtime": "2026-03-01T12:00:00+00:00",
"alternates": [
[
"pl",
"/kategoria/a"
],
[
"en",
"/en/category/a"
]
],
"items": [
{
"url": "/kategoria/b",
"mtime": "2026-03-02T12:00:00+00:00",
"alternates": [
[
"pl",
"/kategoria/b"
],
[
"en",
"/en/category/b"
]
],
"items": [
{
"url": "/kategoria/c",
"alternates": [
[
"x-default",
"/kategoria/c"
]
]
}
]
}
]
}
}
}
},
{
"name": "tiers-default",
"root": "https://api.example.test",
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en/",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/uslugi/x",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/uslugi/x/y",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/realizacje/r",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en/work/w",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/blog/a/b",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en/blog/a/b",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/blog/a",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/blog",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en/blog/",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/uslugi",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/kontakt",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/kontakt/",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/en/ai-lab/blob-playground",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/other",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "https://elsewhere.pl/uslugi/z",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/o-nas?x=1",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/blog/a/b/c",
"changefreq": "weekly",
"priority": "0.3"
}
]
},
{
"name": "tiers-settings",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": true,
"priority_homepage": "0.95",
"priority_blog": "",
"priority_legal": "0.15"
},
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/blog/a/b",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/regulamin",
"changefreq": "weekly",
"priority": "0.3"
},
{
"type": "url",
"url": "/x",
"changefreq": "weekly",
"priority": "0.3"
}
]
},
{
"name": "tiers-off",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.1"
},
{
"type": "url",
"url": "/blog/a/b",
"changefreq": "weekly",
"priority": "0.2"
}
]
},
{
"name": "rewrite",
"root": "https://api.example.test",
"settings": {
"frontend_url": "https://www.example.test/",
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/a",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "https://api.example.test/b?x=https://api.example.test/c",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "https://other.example.test/api.example.test",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "acme-list",
"reference": "",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
}
],
"types": {
"acme-list": {
"": {
"url": "",
"items": [
{
"url": "/p",
"alternates": [
[
"pl",
"/p"
],
[
"en",
"https://api.example.test/en/p"
]
]
}
]
}
}
}
},
{
"name": "rewrite-same",
"root": "https://api.example.test",
"settings": {
"frontend_url": "https://api.example.test",
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "/a",
"changefreq": "weekly",
"priority": "0.5"
}
]
},
{
"name": "manifest",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"manifest": {
"/": "2026-05-01T10:00:00+02:00",
"about/": "2026-05-02",
"/blog/x": "not a date",
"/rel": "2026-05-03T01:02:03Z"
},
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/about",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/about/",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/blog/x",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/none",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "acme-post",
"reference": "2",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
},
{
"type": "acme-post",
"reference": "3",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
}
],
"types": {
"acme-post": {
"2": {
"url": "/rel",
"mtime": null,
"alternates": [
[
"pl",
"/rel"
]
]
},
"3": {
"url": "/about",
"mtime": "2026-06-01T00:00:00+00:00",
"alternates": [
[
"pl",
"/about"
]
]
}
}
}
},
{
"name": "skip-extra",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"skip": [
"https://api.example.test/skip-me",
"/rel-skip"
],
"extra": {
"https://api.example.test/extra": "a&b <c>"
},
"items": [
{
"type": "url",
"url": "/skip-me",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/extra",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/keep",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "acme-post",
"reference": "9",
"urlPattern": "",
"changefreq": "daily",
"priority": "0.7",
"nesting": "1"
}
],
"types": {
"acme-post": {
"9": {
"url": "/rel-skip",
"alternates": [
[
"pl",
"/rel-skip"
]
]
}
}
}
},
{
"name": "precision",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "/p1",
"changefreq": "daily",
"priority": 0.5
},
{
"type": "url",
"url": "/p2",
"changefreq": "daily",
"priority": 1.0
},
{
"type": "url",
"url": "/p3",
"changefreq": 7,
"priority": 1
},
{
"type": "url",
"url": "/p4",
"changefreq": "daily",
"priority": "1.0"
},
{
"type": "url",
"url": "/p5",
"changefreq": "daily",
"priority": "0.50"
},
{
"url": "/p6",
"changefreq": "daily",
"priority": "0.6",
"cmsPage": "x",
"exists": true,
"fillable": [
"a"
]
}
]
},
{
"name": "url-null",
"root": "https://api.example.test",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": null,
"changefreq": null,
"priority": null
},
{
"type": "url",
"url": "0",
"changefreq": "daily",
"priority": "0.5"
}
]
},
{
"name": "port-root",
"root": "http://localhost:8096",
"settings": {
"enable_priority_tiers": false
},
"items": [
{
"type": "url",
"url": "/",
"changefreq": "weekly",
"priority": "0.5"
},
{
"type": "url",
"url": "/a b",
"changefreq": "weekly",
"priority": "0.5"
}
]
}
]
}

58
classes/testdata/urlto.golden vendored Normal file
View File

@@ -0,0 +1,58 @@
https://api.ex.pl/
https://api.ex.pl/
https://api.ex.pl/
https://api.ex.pl/blog
https://api.ex.pl/blog
https://api.ex.pl/blog
https://api.ex.pl/blog/za%C5%BC%C3%B3%C5%82%C4%87%20g%C4%99%C5%9Bl%C4%85
https://api.ex.pl/en/blog/%3Aslug
https://x.pl/q/
http://x.pl/
HTTP://X.pl:443/a
https://h:8080/a
https://h/a
http://h/
https://api.ex.pl/a?b=1&c=2
https://api.ex.pl/a?x%5B%5D=1&x%5B%5D=2&0=y
https://api.ex.pl/a?q=a&0=b%20c
https://api.ex.pl/a
https://api.ex.pl/a?b=&0=c
https://api.ex.pl/a?x&y
https://api.ex.pl/a?a=2
https://api.ex.pl/a?a%5Bb%5D=1
https://api.ex.pl/a#b%20c
https://api.ex.pl/a
#frag
cdn.x/a
mailto:a%40b.pl
tel:%2B48%20123
sms:%2B48123
https://api.ex.pl/a/c
https://api.ex.pl/a//b
https://api.ex.pl/a/%20b/%25zz
https://api.ex.pl/a%2Fb
https://api.ex.pl/%C5%9Bcie%C5%BCka/%C4%85%C4%99?x=%C5%BC#%C5%82
https://api.ex.pl/ftp%3A//x.pl/a%20b
ftp://x.pl/a
news:///comp.x
https://api.ex.pl/a%3Ab
https://api.ex.pl/a%3A1
https://api.ex.pl/user%40host
https://user:pass@h/x
https://api.ex.pl/%20%20/lead
https://api.ex.pl/trail
https://api.ex.pl/tab_here
https://api.ex.pl/new_line
https://api.ex.pl/
https://api.ex.pl/javascript%3Aalert%281%29
https://a&b<c>.pl/x
https://h/
https://api.ex.pl/en
https://api.ex.pl/en
https://api.ex.pl/a?x=%2B
https://api.ex.pl/a?k=v%20w
https://api.ex.pl/a%20b?x=1#y%20z
https://h/a?b=1#c
https://api.ex.pl/~tilde/_under.dot-dash
https://api.ex.pl/a%27b%22c
https://api.ex.pl/%3Cx%3E%26y

63
classes/testdata/urlto.json vendored Normal file
View File

@@ -0,0 +1,63 @@
{
"root": "https://api.ex.pl",
"urls": [
"/",
"",
null,
"/blog/",
"/blog",
"blog",
"/blog/zażółć gęślą",
"/en/blog/:slug",
"https://x.pl/q/",
"http://x.pl",
"HTTP://X.pl:443/a",
"https://h:8080/a",
"https://h:443/a",
"http://h:80/",
"/a?b=1&c=2",
"/a?x[]=1&x[]=2&y",
"/a?q=a%26b+c",
"/a?",
"/a?b=&c",
"/a?0=x&1=y",
"/a?a=1&a=2",
"/a?a[b]=1",
"/a#b c",
"/a#",
"#frag",
"//cdn.x/a",
"mailto:a@b.pl",
"tel:+48 123",
"sms:+48123",
"/../a/./b/../c",
"/a//b",
"/a/%20b/%zz",
"/a%2Fb",
"/ścieżka/ąę?x=ż#ł",
"ftp://x.pl/a b",
"ftp://x.pl/a",
"news:comp.x",
"/a:b",
"a:1",
"/user@host",
"https://user:pass@h/x",
" /lead",
"/trail ",
"/tab\there",
"/new\nline",
"/a/b/../../..",
"javascript:alert(1)",
"https://a&b<c>.pl/x",
"https://h/./",
"/en",
"/en/",
"/a?x=%2B",
"/a?k=v w",
"/a b?x=1#y z",
"https://h/a?b=1#c",
"/~tilde/_under.dot-dash",
"/a'b\"c",
"/<x>&y"
]
}