@mxfb/tools 0.3.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/TODO.md +1 -0
  2. package/agnostic/@publisher/index.d.ts +47 -0
  3. package/agnostic/@publisher/index.js +361 -0
  4. package/agnostic/elo/index.d.ts +23 -0
  5. package/agnostic/elo/index.js +28 -0
  6. package/agnostic/elo/index.test.d.ts +1 -0
  7. package/agnostic/elo/index.test.js +67 -0
  8. package/agnostic/index.d.ts +5 -4
  9. package/agnostic/index.js +5 -0
  10. package/agnostic/poetry/generate-rhymes/index.d.ts +1 -0
  11. package/agnostic/poetry/generate-rhymes/index.js +125 -0
  12. package/agnostic/poetry/index.d.ts +1 -0
  13. package/agnostic/poetry/index.js +1 -0
  14. package/agnostic/scrapers/@meteociel/index.d.ts +36 -0
  15. package/agnostic/scrapers/@meteociel/index.js +248 -0
  16. package/agnostic/scrapers/@meteociel/index.test.d.ts +1 -0
  17. package/agnostic/scrapers/@meteociel/index.test.js +43 -0
  18. package/agnostic/scrapers/@meteociel/locations/index.d.ts +11 -0
  19. package/agnostic/scrapers/@meteociel/locations/index.js +10 -0
  20. package/agnostic/scrapers/@meteociel/types.d.ts +1 -0
  21. package/agnostic/scrapers/@meteociel/types.js +1 -0
  22. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.d.ts +22 -0
  23. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.js +124 -0
  24. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.test.d.ts +1 -0
  25. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.test.js +107 -0
  26. package/agnostic/scrapers/@tumblr/blogs/index.d.ts +8 -0
  27. package/agnostic/scrapers/@tumblr/blogs/index.js +23 -0
  28. package/agnostic/scrapers/@tumblr/index.d.ts +73 -0
  29. package/agnostic/scrapers/@tumblr/index.js +180 -0
  30. package/agnostic/scrapers/@tumblr/index.test.d.ts +1 -0
  31. package/agnostic/scrapers/@tumblr/index.test.js +319 -0
  32. package/agnostic/scrapers/@tumblr/types.d.ts +238 -0
  33. package/agnostic/scrapers/@tumblr/types.js +38 -0
  34. package/agnostic/scrapers/@tumblr/utils.d.ts +12 -0
  35. package/agnostic/scrapers/@tumblr/utils.js +407 -0
  36. package/agnostic/scrapers/index.d.ts +2 -0
  37. package/agnostic/scrapers/index.js +2 -0
  38. package/agnostic/weather/index.d.ts +1 -0
  39. package/agnostic/weather/index.js +1 -0
  40. package/agnostic/weather/types.d.ts +181 -0
  41. package/agnostic/weather/types.js +8 -0
  42. package/components/index.d.ts +1 -1
  43. package/components/index.js +1 -0
  44. package/components/public-classnames.d.ts +5 -0
  45. package/components/public-classnames.js +5 -0
  46. package/components/utils/index.d.ts +1 -0
  47. package/components/utils/index.js +12 -0
  48. package/components/utils/types.d.ts +3 -0
  49. package/components/utils/types.js +1 -0
  50. package/index.d.ts +3 -3
  51. package/index.js +3 -0
  52. package/node/headless-browser/index.d.ts +37 -0
  53. package/node/headless-browser/index.js +126 -0
  54. package/node/headless-browser/types.d.ts +47 -0
  55. package/node/headless-browser/types.js +5 -0
  56. package/node/index.d.ts +1 -2
  57. package/node/index.js +1 -0
  58. package/node/index.test.d.ts +1 -0
  59. package/node/index.test.js +6 -0
  60. package/node/scrapers/@tumblr/index.d.ts +61 -0
  61. package/node/scrapers/@tumblr/index.js +182 -0
  62. package/node/scrapers/@tumblr/index.test.d.ts +1 -0
  63. package/node/scrapers/@tumblr/index.test.js +185 -0
  64. package/node/scrapers/@tumblr/types.d.ts +91 -0
  65. package/node/scrapers/@tumblr/types.js +1 -0
  66. package/node/scrapers/@tumblr/utils.d.ts +23 -0
  67. package/node/scrapers/@tumblr/utils.js +328 -0
  68. package/node/scrapers/index.d.ts +1 -0
  69. package/node/scrapers/index.js +1 -0
  70. package/package.json +211 -14
  71. package/agnostic/_WIP_tennis/index.d.ts +0 -2
  72. package/agnostic/_WIP_tennis/index.js +0 -62
  73. package/agnostic/arrays/index.d.ts +0 -11
  74. package/agnostic/arrays/is-array-of/index.d.ts +0 -5
  75. package/agnostic/arrays/is-array-of/index.js +0 -23
  76. package/agnostic/async/index.d.ts +0 -8
  77. package/agnostic/async/index.js +0 -20
  78. package/agnostic/async/timeout-call/index.d.ts +0 -1
  79. package/agnostic/async/timeout-call/index.js +0 -6
  80. package/agnostic/async/transitions/index.d.ts +0 -41
  81. package/agnostic/async/transitions/index.js +0 -7
  82. package/agnostic/async/wait/index.d.ts +0 -1
  83. package/agnostic/async/wait/index.js +0 -6
  84. package/agnostic/booleans/index.d.ts +0 -8
  85. package/agnostic/booleans/index.js +0 -17
  86. package/agnostic/booleans/is-falsy/index.d.ts +0 -7
  87. package/agnostic/booleans/is-falsy/index.js +0 -11
  88. package/agnostic/css/bem/BEM.d.ts +0 -29
  89. package/agnostic/css/bem/getNamesArr.d.ts +0 -2
  90. package/agnostic/css/bem/index.d.ts +0 -7
  91. package/agnostic/css/bem/index.js +0 -9
  92. package/agnostic/css/generate-nice-color/index.d.ts +0 -2
  93. package/agnostic/css/generate-nice-color/index.js +0 -8
  94. package/agnostic/css/index.d.ts +0 -14
  95. package/agnostic/css/index.js +0 -177
  96. package/agnostic/css/is-valid-css-class-name/index.d.ts +0 -2
  97. package/agnostic/css/is-valid-css-class-name/index.js +0 -8
  98. package/agnostic/css/styles-set/index.d.ts +0 -37
  99. package/agnostic/errors/index.d.ts +0 -30
  100. package/agnostic/errors/index.js +0 -6
  101. package/agnostic/html/get-node-ancestors/index.d.ts +0 -1
  102. package/agnostic/html/get-node-ancestors/index.js +0 -6
  103. package/agnostic/html/get-position-inside-parent/index.d.ts +0 -1
  104. package/agnostic/html/get-position-inside-parent/index.js +0 -6
  105. package/agnostic/html/index.d.ts +0 -17
  106. package/agnostic/html/index.js +0 -39
  107. package/agnostic/html/insert-node/index.d.ts +0 -2
  108. package/agnostic/html/insert-node/index.js +0 -6
  109. package/agnostic/html/placeholders/index.d.ts +0 -9
  110. package/agnostic/html/placeholders/index.js +0 -6
  111. package/agnostic/html/sanitize/index.d.ts +0 -24
  112. package/agnostic/html/sanitize/index.js +0 -9
  113. package/agnostic/html/selector-to-element/index.d.ts +0 -1
  114. package/agnostic/html/selector-to-element/index.js +0 -9
  115. package/agnostic/html/string-to-nodes/index.d.ts +0 -7
  116. package/agnostic/html/string-to-nodes/index.js +0 -10
  117. package/agnostic/misc/assert/index.d.ts +0 -5
  118. package/agnostic/misc/assert/index.js +0 -6
  119. package/agnostic/misc/cast/index.d.ts +0 -9
  120. package/agnostic/misc/cast/index.js +0 -8
  121. package/agnostic/misc/crossenv/index.d.ts +0 -13
  122. package/agnostic/misc/crossenv/index.js +0 -6
  123. package/agnostic/misc/elo/index.d.ts +0 -31
  124. package/agnostic/misc/elo/index.js +0 -6
  125. package/agnostic/misc/get-current-downlink/index.d.ts +0 -1
  126. package/agnostic/misc/get-current-downlink/index.js +0 -6
  127. package/agnostic/misc/index.d.ts +0 -6
  128. package/agnostic/misc/index.js +0 -16
  129. package/agnostic/misc/is-constructor-function/index.d.ts +0 -2
  130. package/agnostic/misc/is-constructor-function/index.js +0 -6
  131. package/agnostic/misc/is-nullish/index.d.ts +0 -4
  132. package/agnostic/misc/is-nullish/index.js +0 -10
  133. package/agnostic/misc/logs/index.d.ts +0 -55
  134. package/agnostic/misc/logs/index.js +0 -6
  135. package/agnostic/misc/random/index.d.ts +0 -10
  136. package/agnostic/misc/random/index.js +0 -6
  137. package/agnostic/misc/tennis/index.d.ts +0 -60
  138. package/agnostic/misc/tennis/index.js +0 -6
  139. package/agnostic/numbers/absolute-modulo/index.d.ts +0 -1
  140. package/agnostic/numbers/absolute-modulo/index.js +0 -6
  141. package/agnostic/numbers/clamp/index.d.ts +0 -1
  142. package/agnostic/numbers/clamp/index.js +0 -6
  143. package/agnostic/numbers/index.d.ts +0 -13
  144. package/agnostic/numbers/index.js +0 -30
  145. package/agnostic/numbers/interpolate/index.d.ts +0 -1
  146. package/agnostic/numbers/interpolate/index.js +0 -6
  147. package/agnostic/numbers/responsive-harmonics/index.d.ts +0 -10
  148. package/agnostic/numbers/responsive-harmonics/index.js +0 -9
  149. package/agnostic/numbers/round/index.d.ts +0 -1
  150. package/agnostic/numbers/round/index.js +0 -6
  151. package/agnostic/objects/enums/index.d.ts +0 -4
  152. package/agnostic/objects/enums/index.js +0 -7
  153. package/agnostic/objects/enums/is-in-enum/index.d.ts +0 -1
  154. package/agnostic/objects/enums/is-in-enum/index.js +0 -6
  155. package/agnostic/objects/flatten-getters/index.d.ts +0 -1
  156. package/agnostic/objects/flatten-getters/index.js +0 -9
  157. package/agnostic/objects/index.d.ts +0 -12
  158. package/agnostic/objects/index.js +0 -32
  159. package/agnostic/objects/is-object/index.d.ts +0 -1
  160. package/agnostic/objects/is-object/index.js +0 -6
  161. package/agnostic/objects/is-record/index.d.ts +0 -1
  162. package/agnostic/objects/is-record/index.js +0 -6
  163. package/agnostic/objects/record-format/index.d.ts +0 -11
  164. package/agnostic/objects/record-format/index.js +0 -16
  165. package/agnostic/objects/validation/index.d.ts +0 -3
  166. package/agnostic/objects/validation/index.js +0 -6
  167. package/agnostic/optim/index.d.ts +0 -7
  168. package/agnostic/optim/index.js +0 -18
  169. package/agnostic/optim/memoize/index.d.ts +0 -3
  170. package/agnostic/optim/memoize/index.js +0 -6
  171. package/agnostic/optim/throttle-debounce/index.d.ts +0 -30
  172. package/agnostic/optim/throttle-debounce/index.js +0 -8
  173. package/agnostic/optim/throttle-debounce/types.d.ts +0 -2
  174. package/agnostic/regexps/index.d.ts +0 -23
  175. package/agnostic/regexps/index.js +0 -89
  176. package/agnostic/strings/char-codes/index.d.ts +0 -17
  177. package/agnostic/strings/char-codes/index.js +0 -6
  178. package/agnostic/strings/index.d.ts +0 -14
  179. package/agnostic/strings/index.js +0 -32
  180. package/agnostic/strings/matches/index.d.ts +0 -3
  181. package/agnostic/strings/matches/index.js +0 -10
  182. package/agnostic/strings/normalize-indent/index.d.ts +0 -1
  183. package/agnostic/strings/normalize-indent/index.js +0 -6
  184. package/agnostic/strings/replace-all/index.d.ts +0 -1
  185. package/agnostic/strings/replace-all/index.js +0 -6
  186. package/agnostic/strings/to-alphanum/index.d.ts +0 -1
  187. package/agnostic/strings/to-alphanum/index.js +0 -6
  188. package/chunks/chunk-32IRF4OP.js +0 -9
  189. package/chunks/chunk-34U4HX4V.js +0 -73
  190. package/chunks/chunk-4GDNHUCZ.js +0 -162
  191. package/chunks/chunk-4QQBKBYH.js +0 -59
  192. package/chunks/chunk-4VC5PT5T.js +0 -13
  193. package/chunks/chunk-5LNUCDQ6.js +0 -132
  194. package/chunks/chunk-7AWTHZLY.js +0 -12
  195. package/chunks/chunk-7DBNMU6N.js +0 -14
  196. package/chunks/chunk-COVPTTAD.js +0 -10
  197. package/chunks/chunk-DNIOWD7K.js +0 -8
  198. package/chunks/chunk-DQNJQBC6.js +0 -10
  199. package/chunks/chunk-E6MSDKON.js +0 -13
  200. package/chunks/chunk-EDVNAV3G.js +0 -72
  201. package/chunks/chunk-EW46EXFB.js +0 -8
  202. package/chunks/chunk-FPEW3A27.js +0 -14
  203. package/chunks/chunk-GJOU3UAL.js +0 -36
  204. package/chunks/chunk-HC6ZOHCS.js +0 -14
  205. package/chunks/chunk-HGCG2J77.js +0 -122
  206. package/chunks/chunk-IFD7GSGK.js +0 -130
  207. package/chunks/chunk-JQXNEJAP.js +0 -18
  208. package/chunks/chunk-JWBDZPQG.js +0 -18
  209. package/chunks/chunk-K37RALUX.js +0 -8
  210. package/chunks/chunk-KIONYWA7.js +0 -168
  211. package/chunks/chunk-KQT5CTGF.js +0 -21
  212. package/chunks/chunk-LEXQ6E6L.js +0 -31
  213. package/chunks/chunk-LQFKUNVQ.js +0 -19
  214. package/chunks/chunk-MF56TTC5.js +0 -15
  215. package/chunks/chunk-MT74WIQR.js +0 -41
  216. package/chunks/chunk-NRITRUZW.js +0 -10
  217. package/chunks/chunk-NRJQKVQV.js +0 -31
  218. package/chunks/chunk-OSAXBA7G.js +0 -10
  219. package/chunks/chunk-PO3V3I57.js +0 -23
  220. package/chunks/chunk-QXAJXTXV.js +0 -19
  221. package/chunks/chunk-RCO57B6F.js +0 -9
  222. package/chunks/chunk-SQZGZ3VT.js +0 -15
  223. package/chunks/chunk-TTZHPIH7.js +0 -237
  224. package/chunks/chunk-UYTXXUU7.js +0 -54
  225. package/chunks/chunk-VTPRO4NJ.js +0 -10
  226. package/chunks/chunk-VYW4IADX.js +0 -35
  227. package/chunks/chunk-VZDUZTW6.js +0 -113
  228. package/chunks/chunk-W5A2TON3.js +0 -10
  229. package/chunks/chunk-W7YBGJ4H.js +0 -28
  230. package/chunks/chunk-WLL3FNVL.js +0 -40
  231. package/chunks/chunk-WOAYU6LB.js +0 -13
  232. package/chunks/chunk-XA4HVHJ4.js +0 -18
  233. package/chunks/chunk-XN3PZIVL.js +0 -38
  234. package/chunks/chunk-Y3OZHZUF.js +0 -237
  235. package/chunks/chunk-YDIBNEGA.js +0 -9
  236. package/chunks/chunk-ZC5RZBNY.js +0 -33
  237. package/components/Comp/index.d.ts +0 -1
  238. package/node/files/index.d.ts +0 -9
  239. package/node/files/index.js +0 -21
  240. package/node/files/is-in-directory/index.d.ts +0 -1
  241. package/node/files/is-in-directory/index.js +0 -6
  242. package/node/files/read-write/index.d.ts +0 -9
  243. package/node/files/read-write/index.js +0 -6
  244. package/node/files/subpaths/index.d.ts +0 -34
  245. package/node/files/subpaths/index.js +0 -7
  246. package/node/image/index.d.ts +0 -9
  247. package/node/image/index.js +0 -74
  248. package/node/mxfb-cli-config/index.d.ts +0 -19
  249. package/node/mxfb-cli-config/index.js +0 -113
  250. package/node/process/index.d.ts +0 -8
  251. package/node/process/index.js +0 -20
  252. package/node/process/on-exit/index.d.ts +0 -5
  253. package/node/process/on-exit/index.js +0 -14
  254. package/shared/errors/index.d.ts +0 -138
  255. package/shared/index.d.ts +0 -0
@@ -0,0 +1,407 @@
1
+ const TUMBLR_HOSTNAME_SUFFIX = '.tumblr.com';
2
+ const TUMBLR_CANONICAL_HOSTNAMES = ['www.tumblr.com', 'tumblr.com'];
3
+ const PERMALINK_PATHNAME_PATTERN = /^\/post\/(\d+)(?:\/|$)/v;
4
+ const INDEX_PAGE_PATHNAME_PATTERN = /^\/page\/(\d+)(?:\/|$)/v;
5
+ const ARCHIVE_PATHNAME_PATTERN = /^\/archive(?:\/|$)/v;
6
+ const TAGGED_PATHNAME_PATTERN = /^\/tagged\//v;
7
+ // A post block never reaches across one of these, so they stop the walk up the tree on a
8
+ // permalink page, where no sibling post is there to stop it.
9
+ const PAGE_LANDMARK_SELECTOR = 'nav, header, footer, aside';
10
+ export function toIntegerOrNull(raw) {
11
+ if (raw === null)
12
+ return null;
13
+ const parsed = Number.parseInt(raw, 10);
14
+ return Number.isNaN(parsed) ? null : parsed;
15
+ }
16
+ export function readSitemapChildUrls(document) {
17
+ const urls = [];
18
+ for (const entry of Array.from(document.getElementsByTagName('sitemap'))) {
19
+ const url = readFirstChildText(entry, 'loc');
20
+ if (url !== null)
21
+ urls.push(url);
22
+ }
23
+ return urls;
24
+ }
25
+ export function readSitemapLocations(document) {
26
+ const locations = [];
27
+ for (const entry of Array.from(document.getElementsByTagName('url'))) {
28
+ const url = readFirstChildText(entry, 'loc');
29
+ if (url === null)
30
+ continue;
31
+ locations.push({
32
+ url,
33
+ lastModifiedOn: toDateOrNull(readFirstChildText(entry, 'lastmod'))
34
+ });
35
+ }
36
+ return locations;
37
+ }
38
+ export function toOrigin(url) {
39
+ if (url === null)
40
+ return null;
41
+ try {
42
+ return new URL(url).origin;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ export function readMetaProperty(document, property) {
49
+ return readAttribute(document, `meta[property="${property}"]`, 'content');
50
+ }
51
+ export function extractCanonicalUrl(document) {
52
+ return readLinkHref(document, 'canonical')
53
+ ?? readMetaProperty(document, 'og:url');
54
+ }
55
+ export function extractPageKind(pageUrl) {
56
+ const pathname = toPathname(pageUrl);
57
+ if (pathname === null)
58
+ return 'unknown';
59
+ if (PERMALINK_PATHNAME_PATTERN.test(pathname))
60
+ return 'permalink';
61
+ if (ARCHIVE_PATHNAME_PATTERN.test(pathname))
62
+ return 'archive';
63
+ // Kept as a pattern to stay symmetric with the three above.
64
+ /* eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with */
65
+ if (TAGGED_PATHNAME_PATTERN.test(pathname))
66
+ return 'tagged';
67
+ if (INDEX_PAGE_PATHNAME_PATTERN.test(pathname))
68
+ return 'index';
69
+ if (pathname === '/')
70
+ return 'index';
71
+ return 'custom';
72
+ }
73
+ export function extractBlog(document, pageUrl, canonicalUrl, pageKind) {
74
+ const baseUrl = toOrigin(pageUrl);
75
+ const iconHref = readLinkHref(document, 'apple-touch-icon')
76
+ ?? readLinkHref(document, 'icon');
77
+ return {
78
+ name: extractBlogName(pageUrl, canonicalUrl),
79
+ title: readMetaProperty(document, 'og:site_name')
80
+ ?? toTextOrNull(document.querySelector('title')?.textContent ?? null),
81
+ description: extractBlogDescription(document, pageKind),
82
+ baseUrl,
83
+ avatarUrl: toAbsoluteUrl(iconHref, baseUrl),
84
+ navLinks: extractNavLinks(document, baseUrl)
85
+ };
86
+ }
87
+ export function extractPostFromPermalinkPage(document, pageUrl) {
88
+ const id = extractPostIdFromUrl(pageUrl);
89
+ const postIdByAnchor = indexPostAnchors(document, toOrigin(pageUrl));
90
+ return {
91
+ ...createIdentifiedPost(id, pageUrl),
92
+ type: extractPostType(readMetaProperty(document, 'og:type')),
93
+ publishedOn: toDateOrNull(readMetaProperty(document, 'article:published_time')),
94
+ title: readMetaProperty(document, 'og:title'),
95
+ tags: readEveryMetaProperty(document, 'article:tag'),
96
+ media: extractMedia(document),
97
+ ...readRawHtml(findPostElement(document, id, postIdByAnchor), 'permalink')
98
+ };
99
+ }
100
+ export function extractPostsFromListingPage(document, baseUrl) {
101
+ const postIdByAnchor = indexPostAnchors(document, baseUrl);
102
+ const postsById = new Map();
103
+ for (const [anchor, id] of postIdByAnchor) {
104
+ if (postsById.has(id))
105
+ continue;
106
+ const url = toAbsoluteUrl(anchor.getAttribute('href'), baseUrl);
107
+ postsById.set(id, {
108
+ ...createIdentifiedPost(id, url),
109
+ ...readRawHtml(findPostElement(document, id, postIdByAnchor), 'listing')
110
+ });
111
+ }
112
+ return Array.from(postsById.values());
113
+ }
114
+ export function extractPagination(document, pageUrl, baseUrl) {
115
+ const currentPageNumber = extractCurrentPageNumber(pageUrl);
116
+ const pageUrlsByNumber = collectPageUrlsByNumber(document, baseUrl);
117
+ const siblingPageUrl = (offset) => {
118
+ if (currentPageNumber === null)
119
+ return null;
120
+ return pageUrlsByNumber.get(currentPageNumber + offset) ?? null;
121
+ };
122
+ return {
123
+ currentPageNumber,
124
+ nextPageUrl: toAbsoluteUrl(readLinkHref(document, 'next'), baseUrl) ?? siblingPageUrl(1),
125
+ previousPageUrl: toAbsoluteUrl(readLinkHref(document, 'prev'), baseUrl) ?? siblingPageUrl(-1)
126
+ };
127
+ }
128
+ function readFirstChildText(element, tagName) {
129
+ return toTextOrNull(element.getElementsByTagName(tagName)[0]?.textContent ?? null);
130
+ }
131
+ function normalizeWhitespace(raw) {
132
+ return raw.replace(/\s+/gv, ' ').trim();
133
+ }
134
+ function toTextOrNull(raw) {
135
+ if (raw === null)
136
+ return null;
137
+ const normalized = normalizeWhitespace(raw);
138
+ return normalized === '' ? null : normalized;
139
+ }
140
+ function toDateOrNull(raw) {
141
+ if (raw === null)
142
+ return null;
143
+ const parsed = new Date(raw);
144
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
145
+ }
146
+ function toAbsoluteUrl(href, baseUrl) {
147
+ if (href === null)
148
+ return null;
149
+ try {
150
+ return new URL(href, baseUrl ?? undefined).href;
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ function toPathname(url) {
157
+ if (url === null)
158
+ return null;
159
+ try {
160
+ return new URL(url).pathname;
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ function sharesOrigin(url, baseUrl) {
167
+ if (baseUrl === null)
168
+ return true;
169
+ return toOrigin(url) === toOrigin(baseUrl);
170
+ }
171
+ function readAttribute(document, selector, attributeName) {
172
+ return toTextOrNull(document.querySelector(selector)?.getAttribute(attributeName) ?? null);
173
+ }
174
+ function readMetaName(document, name) {
175
+ return readAttribute(document, `meta[name="${name}"]`, 'content');
176
+ }
177
+ function readLinkHref(document, relation) {
178
+ return readAttribute(document, `link[rel="${relation}"]`, 'href');
179
+ }
180
+ function readEveryMetaProperty(document, property) {
181
+ return Array
182
+ .from(document.querySelectorAll(`meta[property="${property}"]`))
183
+ .map(element => toTextOrNull(element.getAttribute('content')))
184
+ .filter((content) => content !== null);
185
+ }
186
+ function extractBlogName(pageUrl, canonicalUrl) {
187
+ return readBlogNameFromCanonicalUrl(canonicalUrl)
188
+ ?? readBlogNameFromHostname(pageUrl);
189
+ }
190
+ function readBlogNameFromCanonicalUrl(canonicalUrl) {
191
+ if (canonicalUrl === null)
192
+ return null;
193
+ let url;
194
+ try {
195
+ url = new URL(canonicalUrl);
196
+ }
197
+ catch {
198
+ return null;
199
+ }
200
+ if (!TUMBLR_CANONICAL_HOSTNAMES.includes(url.hostname))
201
+ return null;
202
+ const segments = url.pathname.split('/').filter(segment => segment !== '');
203
+ return segments[0] ?? null;
204
+ }
205
+ function readBlogNameFromHostname(pageUrl) {
206
+ let hostname;
207
+ try {
208
+ hostname = new URL(pageUrl).hostname;
209
+ }
210
+ catch {
211
+ return null;
212
+ }
213
+ if (!hostname.endsWith(TUMBLR_HOSTNAME_SUFFIX))
214
+ return null;
215
+ const name = hostname.slice(0, -TUMBLR_HOSTNAME_SUFFIX.length);
216
+ if (name === '' || name === 'www' || name.includes('.'))
217
+ return null;
218
+ return name;
219
+ }
220
+ function extractBlogDescription(document, pageKind) {
221
+ if (pageKind === 'permalink')
222
+ return null;
223
+ return readMetaName(document, 'description')
224
+ ?? readMetaProperty(document, 'og:description');
225
+ }
226
+ function extractNavLinks(document, baseUrl) {
227
+ const navLinks = [];
228
+ const seenUrls = new Set();
229
+ for (const anchor of document.querySelectorAll('nav a[href], header a[href]')) {
230
+ const url = toAbsoluteUrl(anchor.getAttribute('href'), baseUrl);
231
+ const label = toTextOrNull(anchor.textContent);
232
+ if (url === null || label === null)
233
+ continue;
234
+ if (!sharesOrigin(url, baseUrl) || seenUrls.has(url))
235
+ continue;
236
+ seenUrls.add(url);
237
+ navLinks.push({ label, url });
238
+ }
239
+ return navLinks;
240
+ }
241
+ function extractPostIdFromUrl(url) {
242
+ const pathname = toPathname(url);
243
+ if (pathname === null)
244
+ return null;
245
+ return PERMALINK_PATHNAME_PATTERN.exec(pathname)?.[1] ?? null;
246
+ }
247
+ function extractPageNumberFromUrl(url) {
248
+ const pathname = toPathname(url);
249
+ if (pathname === null)
250
+ return null;
251
+ return toIntegerOrNull(INDEX_PAGE_PATHNAME_PATTERN.exec(pathname)?.[1] ?? null);
252
+ }
253
+ function extractPostType(openGraphType) {
254
+ if (openGraphType === null)
255
+ return 'unknown';
256
+ if (openGraphType.startsWith('video'))
257
+ return 'video';
258
+ if (openGraphType.startsWith('music'))
259
+ return 'audio';
260
+ return 'unknown';
261
+ }
262
+ function extractMedia(document) {
263
+ const media = [];
264
+ const imageUrl = readMetaProperty(document, 'og:image');
265
+ if (imageUrl !== null) {
266
+ media.push({
267
+ kind: 'image',
268
+ url: imageUrl,
269
+ widthPx: toIntegerOrNull(readMetaProperty(document, 'og:image:width')),
270
+ heightPx: toIntegerOrNull(readMetaProperty(document, 'og:image:height')),
271
+ alternativeText: readMetaProperty(document, 'og:image:alt')
272
+ });
273
+ }
274
+ const videoUrl = readMetaProperty(document, 'og:video');
275
+ if (videoUrl !== null) {
276
+ media.push({
277
+ kind: 'video',
278
+ url: videoUrl,
279
+ widthPx: toIntegerOrNull(readMetaProperty(document, 'og:video:width')),
280
+ heightPx: toIntegerOrNull(readMetaProperty(document, 'og:video:height')),
281
+ alternativeText: null
282
+ });
283
+ }
284
+ const audioUrl = readMetaProperty(document, 'og:audio');
285
+ if (audioUrl !== null) {
286
+ media.push({
287
+ kind: 'audio',
288
+ url: audioUrl,
289
+ widthPx: null,
290
+ heightPx: null,
291
+ alternativeText: null
292
+ });
293
+ }
294
+ return media;
295
+ }
296
+ function indexPostAnchors(document, baseUrl) {
297
+ const postIdByAnchor = new Map();
298
+ for (const anchor of document.querySelectorAll('a[href]')) {
299
+ const url = toAbsoluteUrl(anchor.getAttribute('href'), baseUrl);
300
+ if (url === null || !sharesOrigin(url, baseUrl))
301
+ continue;
302
+ const id = extractPostIdFromUrl(url);
303
+ if (id === null)
304
+ continue;
305
+ postIdByAnchor.set(anchor, id);
306
+ }
307
+ return postIdByAnchor;
308
+ }
309
+ function findPostElement(document, postId, postIdByAnchor) {
310
+ if (postId === null)
311
+ return null;
312
+ const blocks = [];
313
+ for (const [anchor, id] of postIdByAnchor) {
314
+ if (id !== postId)
315
+ continue;
316
+ const block = climbToPostBlock(anchor, postId, postIdByAnchor);
317
+ if (block !== null && !blocks.includes(block))
318
+ blocks.push(block);
319
+ }
320
+ if (blocks.length === 0)
321
+ return document.querySelector('article');
322
+ const namedBlocks = blocks.filter(block => namesPost(block, postId));
323
+ return widestElement(namedBlocks.length > 0 ? namedBlocks : blocks);
324
+ }
325
+ function climbToPostBlock(anchor, postId, postIdByAnchor) {
326
+ let candidate = anchor;
327
+ let widestBlock = null;
328
+ let nearestNamedBlock = null;
329
+ while (holdsOnlyThisPost(candidate, postId, postIdByAnchor)) {
330
+ widestBlock = candidate;
331
+ if (nearestNamedBlock === null && namesPost(candidate, postId))
332
+ nearestNamedBlock = candidate;
333
+ const parent = candidate.parentElement;
334
+ if (parent === null || parent.tagName === 'BODY' || parent.tagName === 'HTML')
335
+ break;
336
+ candidate = parent;
337
+ }
338
+ return nearestNamedBlock ?? widestBlock;
339
+ }
340
+ function widestElement(elements) {
341
+ let widest = null;
342
+ for (const element of elements) {
343
+ if (widest === null || element.outerHTML.length > widest.outerHTML.length)
344
+ widest = element;
345
+ }
346
+ return widest;
347
+ }
348
+ function holdsOnlyThisPost(element, postId, postIdByAnchor) {
349
+ if (element.matches(PAGE_LANDMARK_SELECTOR))
350
+ return false;
351
+ if (element.querySelector(PAGE_LANDMARK_SELECTOR) !== null)
352
+ return false;
353
+ for (const anchor of element.querySelectorAll('a[href]')) {
354
+ const id = postIdByAnchor.get(anchor);
355
+ if (id !== undefined && id !== postId)
356
+ return false;
357
+ }
358
+ return true;
359
+ }
360
+ function namesPost(element, postId) {
361
+ return element.tagName === 'ARTICLE' || element.id.includes(postId);
362
+ }
363
+ function readRawHtml(postElement, source) {
364
+ if (postElement === null)
365
+ return { rawHtml: null, rawHtmlSource: null };
366
+ return { rawHtml: postElement.outerHTML, rawHtmlSource: source };
367
+ }
368
+ function createIdentifiedPost(id, url) {
369
+ return {
370
+ id,
371
+ url,
372
+ type: 'unknown',
373
+ publishedOn: null,
374
+ title: null,
375
+ contentHtml: null,
376
+ rawHtml: null,
377
+ rawHtmlSource: null,
378
+ detail: null,
379
+ tags: [],
380
+ media: [],
381
+ notesCount: null,
382
+ reblogOfUrl: null,
383
+ lastModifiedOn: null
384
+ };
385
+ }
386
+ function collectPageUrlsByNumber(document, baseUrl) {
387
+ const pageUrlsByNumber = new Map();
388
+ for (const anchor of document.querySelectorAll('a[href]')) {
389
+ const url = toAbsoluteUrl(anchor.getAttribute('href'), baseUrl);
390
+ if (url === null || !sharesOrigin(url, baseUrl))
391
+ continue;
392
+ const pageNumber = extractPageNumberFromUrl(url);
393
+ if (pageNumber === null || pageUrlsByNumber.has(pageNumber))
394
+ continue;
395
+ pageUrlsByNumber.set(pageNumber, url);
396
+ }
397
+ return pageUrlsByNumber;
398
+ }
399
+ function extractCurrentPageNumber(pageUrl) {
400
+ const pathname = toPathname(pageUrl);
401
+ if (pathname === null)
402
+ return null;
403
+ const declaredPageNumber = extractPageNumberFromUrl(pageUrl);
404
+ if (declaredPageNumber !== null)
405
+ return declaredPageNumber;
406
+ return pathname === '/' ? 1 : null;
407
+ }
@@ -0,0 +1,2 @@
1
+ export * as meteociel from './@meteociel/index.js'
2
+ export * as tumblr from './@tumblr/index.js'
@@ -0,0 +1,2 @@
1
+ export * as meteociel from './@meteociel/index.js'
2
+ export * as tumblr from './@tumblr/index.js'
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Core weather data types for archiving and exchanging meteorological information.
3
+ *
4
+ * The structures are inspired by WMO (World Meteorological Organization) guidance
5
+ * and CF Conventions. Units are encoded explicitly in property names to avoid
6
+ * ambiguity and to make transformations between systems easier and safer.
7
+ */
8
+ /** Geographic location following the WGS84 reference system. */
9
+ export type GeoLocation = {
10
+ /** Latitude in decimal degrees (-90 to +90). */ latitudeDeg: number;
11
+ /** Longitude in decimal degrees (-180 to +180). */ longitudeDeg: number;
12
+ /** Elevation in meters above mean sea level. */ elevationM?: number;
13
+ /** Human-readable place name (city, station, etc.). */ name?: string;
14
+ /** Country code in ISO 3166-1 alpha-2 format (e.g. "FR", "US"). */ countryCode31661a2?: string;
15
+ /** Administrative region, state, or province name. */ region?: string;
16
+ };
17
+ /** Source of observed meteorological data. */
18
+ export type ObservationDataSource = {
19
+ /** Data provider name */ provider: string;
20
+ /** High-level type of source */ type: 'satellite' | 'radar' | 'station' | 'derived' | 'manual' | 'other';
21
+ /** Identifier of the observing station or sensor when applicable. */ stationId?: string;
22
+ /** URL pointing to the data source or documentation. */ url?: string;
23
+ /** Data license or usage terms (short free-text). */ license?: string;
24
+ };
25
+ /** Source of forecast data. Describes both deterministic and ensemble-based forecast systems. */
26
+ export type ForecastDataSource = {
27
+ /** Provider or operator name */ provider: string;
28
+ /** Type of forecast product. */ type: 'model' | 'ensemble' | 'derived' | 'other';
29
+ /** Model name or product identifier (e.g. "GFS", "AROME"). */ model?: string;
30
+ /** Model version, configuration, or cycle identifier. */ modelVersion?: string;
31
+ /** Model initialization date */ runTime?: Date;
32
+ /** Ensemble member identifier for probabilistic forecasts. */ ensembleMember?: string;
33
+ /** URL pointing to model documentation or the data endpoint. */ url?: string;
34
+ /** Data license or usage terms for the forecast. */ license?: string;
35
+ };
36
+ /** Temperature-related fields. */
37
+ export type Temperature = {
38
+ /** Air temperature in degrees Celsius. */ tempC: number;
39
+ /** Feels-like temperature in °C (wind chill or heat index depending on conditions). */ feelsLikeC?: number;
40
+ /** Dew point temperature in °C. */ dewPointC?: number;
41
+ /** Minimum temperature over the period in °C. */ minC?: number;
42
+ /** Maximum temperature over the period in °C. */ maxC?: number;
43
+ };
44
+ /** Humidity parameters. */
45
+ export type Humidity = {
46
+ /** Relative humidity in percent (0–100). */ relativePercent: number;
47
+ /** Absolute humidity in grams per cubic meter. */ absoluteGm3?: number;
48
+ };
49
+ /** Wind according to common WMO conventions. */
50
+ export type Wind = {
51
+ /** Mean wind speed in meters per second. */ speedMs: number;
52
+ /** Wind direction in degrees (0–360, where 0/360 = North, 90 = East). */ directionDeg: number;
53
+ /** Maximum gust speed in meters per second over the period. */ gustMs?: number;
54
+ };
55
+ /** Canonical list of WMO cloud genera. */
56
+ export type CloudType = 'cirrus' | 'cirrocumulus' | 'cirrostratus' | 'altocumulus' | 'altostratus' | 'nimbostratus' | 'stratocumulus' | 'stratus' | 'cumulus' | 'cumulonimbus';
57
+ /** Cloud cover information following common WMO recommendations. */
58
+ export type CloudCover = {
59
+ /** Total cloud cover in percent (0–100). */ totalPercent: number;
60
+ /** Low-level cloud fraction in percent (0–100). */ lowPercent?: number;
61
+ /** Mid-level cloud fraction in percent (0–100). */ middlePercent?: number;
62
+ /** High-level cloud fraction in percent (0–100). */ highPercent?: number;
63
+ /** Cloud base height in meters above ground level. */ cloudBaseHeightM?: number;
64
+ /** Dominant cloud genus when it can be identified. */ dominantGenre?: CloudType;
65
+ };
66
+ /** Canonical list of atmospheric phenomena based on WMO classification. */
67
+ export type AtmosphericPhenomenon = 'rain' | 'drizzle' | 'freezing-rain' | 'snow' | 'snow-grains' | 'ice-pellets' | 'hail' | 'fog' | 'mist' | 'haze' | 'smoke' | 'dust' | 'sand' | 'volcanic-ash' | 'thunderstorm' | 'squall' | 'funnel-cloud';
68
+ /** Single atmospheric phenomenon, observed or forecast. */
69
+ export type WeatherPhenomenon = {
70
+ /** Phenomenon type according to the WMO-inspired list. */ phenomenon: AtmosphericPhenomenon;
71
+ /** Qualitative intensity: "+" for heavy, "-" for light, or null for normal. */ intensity: '+' | '-' | null;
72
+ /** Optional free-text remark describing special characteristics. */ remark?: string;
73
+ };
74
+ /** Atmospheric pressure. */
75
+ export type Pressure = {
76
+ /** Sea-level pressure in hectopascals (millibars). */ seaLevelHpa?: number;
77
+ /** Station-level pressure in hectopascals at the observing elevation. */ stationLevelHpa: number;
78
+ };
79
+ /** Visibility metrics. */
80
+ export type Visibility = {
81
+ /** Horizontal visibility in meters. */ horizontalM?: number;
82
+ /** Vertical visibility in meters (e.g. ceiling height). */ verticalM?: number;
83
+ };
84
+ /** Solar radiation and UV information. */
85
+ export type Solar = {
86
+ /** Global solar radiation in watts per square meter. */ radiationWm2?: number;
87
+ /** Dimensionless UV index, typically between 0 and ~12. */ uvIndex?: number;
88
+ };
89
+ /** Air quality indicators. */
90
+ export type AirQuality = {
91
+ /** Fine particulate matter PM2.5 in micrograms per cubic meter. */ pm25Ugm3?: number;
92
+ /** Particulate matter PM10 in micrograms per cubic meter. */ pm10Ugm3?: number;
93
+ /** Ozone (O₃) concentration in micrograms per cubic meter. */ o3Ugm3?: number;
94
+ /** Nitrogen dioxide (NO₂) concentration in micrograms per cubic meter. */ no2Ugm3?: number;
95
+ /** Sulfur dioxide (SO₂) concentration in micrograms per cubic meter. */ so2Ugm3?: number;
96
+ /** Carbon monoxide (CO) concentration in micrograms per cubic meter. */ coUgm3?: number;
97
+ };
98
+ /** Quality metadata attached to an observation or measurement. */
99
+ export type ObservationQualityMetadata = {
100
+ /** Status of the data, typically resulting from QC checks or post-processing. */ status?: 'verified' | 'unverified' | 'estimated' | 'interpolated' | 'suspect';
101
+ /** Free-text notes or comments about the data quality. */ notes?: string;
102
+ };
103
+ /** Validity period of a forecast or alert. */
104
+ export type ValidityPeriod = {
105
+ /** Start of validity */ from: Date;
106
+ /** End of validity */ to: Date;
107
+ };
108
+ /** Weather alert or warning issued by an authority or provider. */
109
+ export type WeatherAlert = {
110
+ /** Alert type or category (e.g. "wind", "flood", "heat"). */ type: string;
111
+ /** Severity level as a normalized qualitative scale. */ severity: 'minor' | 'moderate' | 'severe' | 'extreme';
112
+ /** Human-readable description of the alert and its expected impacts. */ description?: string;
113
+ /** Validity period of a forecast or alert. */ validity?: ValidityPeriod;
114
+ };
115
+ /** Probabilistic forecast data for a single parameter. */
116
+ export type ProbabilisticData = {
117
+ /** Confidence level for the forecast (0–100%). */ confidencePercent?: number;
118
+ /** Temperature 10th percentile in °C (optimistic or cooler scenario). */ tempP10C?: number;
119
+ /** Temperature 90th percentile in °C (pessimistic or warmer scenario). */ tempP90C?: number;
120
+ };
121
+ /**
122
+ * Core weather data structure containing essential meteorological measurements.
123
+ *
124
+ * This type represents the fundamental weather parameters that can be used
125
+ * for both observations and forecasts. It follows WMO conventions and uses
126
+ * explicit unit encoding in property names to ensure clarity and type safety.
127
+ *
128
+ * All core measurements are required, while some extended parameters
129
+ * (visibility, solar, air quality, alerts) are optional.
130
+ *
131
+ * @see WeatherObservation - For observation-specific data with location and time
132
+ * @see WeatherForecast - For forecast-specific data with validity periods
133
+ */
134
+ export type WeatherDataCore = {
135
+ /** Temperature-related measurements at the observation time. */ temperature: Temperature;
136
+ /** Humidity-related measurements at the observation time. */ humidity: Humidity;
137
+ /** Wind conditions at the observation time. */ wind: Wind;
138
+ /** Instantaneous precipitation rates at the observation time. */ precipitationMmh: number;
139
+ /** Atmospheric pressure at or reduced to station/sea level. */ pressure: Pressure;
140
+ /** List of significant weather phenomena observed. */ phenomena?: WeatherPhenomenon[];
141
+ /** Cloud cover information at the observation time. */ clouds?: CloudCover;
142
+ /** Visibility metrics at the observation time. */ visibility?: Visibility;
143
+ /** Solar radiation and UV information at the observation time. */ solar?: Solar;
144
+ /** Air quality indicators at or near the observation site. */ airQuality?: AirQuality;
145
+ /** Weather alerts that are active for this forecast period and location. */ alerts?: WeatherAlert[];
146
+ };
147
+ /**
148
+ * Weather observation.
149
+ *
150
+ * Represents a real-world measurement or observation at a specific point in time,
151
+ * typically coming from an instrumented station or human report.
152
+ */
153
+ export type WeatherObservation = WeatherDataCore & {
154
+ /** Exact time when the observation was made. */ observedOn: Date;
155
+ /** Geographic location of the observation. */ location: GeoLocation;
156
+ /** Observation metadata */ metadata?: {
157
+ /** Observation source metadata (station, provider, license...). */ source?: ObservationDataSource;
158
+ /** Time when the data was collected or ingested by the system. */ collectedOn?: Date;
159
+ /** Human-readable description or summary of the observation. */ description?: string;
160
+ /** Raw source data as received from the provider. */ rawData?: Record<string, unknown> | string;
161
+ /** Quality control and processing metadata for the observation. */ observationQuality?: ObservationQualityMetadata;
162
+ };
163
+ };
164
+ /**
165
+ * Weather forecast.
166
+ *
167
+ * Represents a forecast for a given future period, possibly including a mix
168
+ * of deterministic and probabilistic information as provided by a model.
169
+ */
170
+ export type WeatherForecast = WeatherDataCore & {
171
+ /** Time when the forecast was issued. */ issuedOn: Date;
172
+ /** Period of time this forecast is valid for. */ validity: ValidityPeriod;
173
+ /** Geographic location to which the forecast applies. */ location: GeoLocation;
174
+ /** Observation metadata */ metadata?: {
175
+ /** Forecast model and source metadata. */ source?: ForecastDataSource;
176
+ /** Time when the data was collected or ingested by the system. */ collectedOn?: Date;
177
+ /** Human-readable description or summary of the observation. */ description?: string;
178
+ /** Raw source data as received from the provider. */ rawData?: Record<string, unknown> | string;
179
+ /** Associated probabilistic forecast information, if available. */ probabilistic?: ProbabilisticData;
180
+ };
181
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Core weather data types for archiving and exchanging meteorological information.
3
+ *
4
+ * The structures are inspired by WMO (World Meteorological Organization) guidance
5
+ * and CF Conventions. Units are encoded explicitly in property names to avoid
6
+ * ambiguity and to make transformations between systems easier and safer.
7
+ */
8
+ export {};
@@ -1 +1 @@
1
- export declare namespace Components { }
1
+ export * as utils from './utils/index.js'
@@ -0,0 +1 @@
1
+ export * as utils from './utils/index.js'
@@ -0,0 +1,5 @@
1
+ export declare const button = "mxfb-button";
2
+ export declare const input = "mxfb-input";
3
+ export declare const jsonEditor = "mxfb-json-editor";
4
+ export declare const select = "mxfb-select";
5
+ export declare const textarea = "mxfb-textarea";
@@ -0,0 +1,5 @@
1
+ export const button = 'mxfb-button';
2
+ export const input = 'mxfb-input';
3
+ export const jsonEditor = 'mxfb-json-editor';
4
+ export const select = 'mxfb-select';
5
+ export const textarea = 'mxfb-textarea';
@@ -0,0 +1 @@
1
+ export declare function mergeClassNames(...names: Array<string | null | undefined | Array<string | null | undefined>>): string;
@@ -0,0 +1,12 @@
1
+ export function mergeClassNames(...names) {
2
+ return names.map(name => {
3
+ if (typeof name !== 'string' && !Array.isArray(name))
4
+ return false;
5
+ if (Array.isArray(name))
6
+ return mergeClassNames(...name);
7
+ if (name.trim() === '')
8
+ return false;
9
+ return name.trim();
10
+ }).filter((name) => typeof name === 'string')
11
+ .join(' ');
12
+ }
@@ -0,0 +1,3 @@
1
+ export type WithClassName<T extends Record<string, unknown>> = T & {
2
+ className?: string | Array<string | null | undefined>;
3
+ };
@@ -0,0 +1 @@
1
+ export {};
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { Agnostic } from './agnostic';
2
- export { Components } from './components';
3
- export { Node } from './node';
1
+ export * as agnostic from './agnostic/index.js'
2
+ export * as components from './components/index.js'
3
+ export * as node from './node/index.js'
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * as agnostic from './agnostic/index.js'
2
+ export * as components from './components/index.js'
3
+ export * as node from './node/index.js'