@gmickel/gno 1.45.1 → 2.0.0

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 (236) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/skill/cli-reference.md +14 -6
  5. package/assets/skill/mcp-reference.md +4 -1
  6. package/assets/spa-production.json.gz +0 -0
  7. package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
  8. package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
  9. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  10. package/browser-extension/dist/manifest.json +1 -1
  11. package/browser-extension/dist/preview.html +1 -1
  12. package/browser-extension/dist/service-worker.js +32 -33
  13. package/bunfig.toml +2 -0
  14. package/package.json +40 -26
  15. package/spec/cli.md +30 -11
  16. package/spec/db/schema.sql +146 -1
  17. package/spec/mcp.md +26 -0
  18. package/src/app/context-runtime-types.ts +3 -0
  19. package/src/app/context-runtime.ts +2 -0
  20. package/src/cli/commands/ask.ts +6 -1
  21. package/src/cli/commands/daemon.ts +21 -8
  22. package/src/cli/commands/embed.ts +77 -41
  23. package/src/cli/commands/mcp/install.ts +20 -0
  24. package/src/cli/commands/mcp/paths.ts +25 -0
  25. package/src/cli/commands/mcp/status.ts +6 -0
  26. package/src/cli/detach.ts +3 -2
  27. package/src/cli/program.ts +6 -0
  28. package/src/config/types.ts +3 -3
  29. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  30. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  31. package/src/converters/versions.ts +6 -8
  32. package/src/core/context-evidence.ts +8 -4
  33. package/src/core/job-manager.ts +95 -13
  34. package/src/core/network-boundary-inventory.ts +10 -0
  35. package/src/core/shutdown-budget.ts +45 -0
  36. package/src/embed/backlog.ts +107 -4
  37. package/src/embed/batch.ts +42 -2
  38. package/src/embed/fingerprint.ts +16 -0
  39. package/src/embed/retry.ts +113 -5
  40. package/src/embed/variant-backlog.ts +105 -0
  41. package/src/embed/variant-plan.ts +62 -0
  42. package/src/embed/variant-retry.ts +113 -0
  43. package/src/ingestion/graph-reconciliation.ts +327 -0
  44. package/src/ingestion/sync.ts +9 -272
  45. package/src/llm/http-inference.ts +6 -0
  46. package/src/llm/httpEmbedding.ts +37 -6
  47. package/src/llm/httpGeneration.ts +18 -3
  48. package/src/llm/httpRerank.ts +23 -5
  49. package/src/llm/inference-cancellation.ts +168 -0
  50. package/src/llm/inference-scope.ts +202 -0
  51. package/src/llm/lazy-ports.ts +115 -0
  52. package/src/llm/native-worker/client.ts +541 -0
  53. package/src/llm/native-worker/dispatcher.ts +228 -0
  54. package/src/llm/native-worker/embedding-identity.ts +33 -0
  55. package/src/llm/native-worker/entry.ts +173 -0
  56. package/src/llm/native-worker/errors.ts +32 -0
  57. package/src/llm/native-worker/evaluation.ts +16 -0
  58. package/src/llm/native-worker/owned-exit.ts +108 -0
  59. package/src/llm/native-worker/owner.ts +141 -0
  60. package/src/llm/native-worker/ports.ts +317 -0
  61. package/src/llm/native-worker/protocol.ts +442 -0
  62. package/src/llm/native-worker/runtime-config.ts +92 -0
  63. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  64. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  65. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  66. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  67. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  68. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  69. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  70. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  71. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  72. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  73. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  74. package/src/llm/types.ts +35 -5
  75. package/src/mcp/context.ts +27 -0
  76. package/src/mcp/http-transport.ts +12 -10
  77. package/src/mcp/server.ts +3 -0
  78. package/src/mcp/tool-profile.ts +30 -8
  79. package/src/mcp/tools/context.ts +8 -11
  80. package/src/mcp/tools/embed.ts +1 -1
  81. package/src/mcp/tools/index-cmd.ts +1 -1
  82. package/src/mcp/tools/index.ts +10 -8
  83. package/src/mcp/tools/query.ts +14 -30
  84. package/src/mcp/tools/vsearch.ts +1 -1
  85. package/src/pipeline/answer.ts +23 -3
  86. package/src/pipeline/claim-verifier.ts +6 -0
  87. package/src/pipeline/expansion.ts +43 -40
  88. package/src/pipeline/explain.ts +6 -2
  89. package/src/pipeline/filters.ts +63 -0
  90. package/src/pipeline/fusion.ts +29 -9
  91. package/src/pipeline/graph-retrieval.ts +29 -9
  92. package/src/pipeline/hybrid.ts +198 -55
  93. package/src/pipeline/hydration.ts +161 -0
  94. package/src/pipeline/owner-fusion.ts +87 -0
  95. package/src/pipeline/rerank.ts +35 -11
  96. package/src/pipeline/search.ts +13 -2
  97. package/src/pipeline/types.ts +5 -3
  98. package/src/pipeline/vsearch.ts +87 -7
  99. package/src/sdk/client.ts +47 -3
  100. package/src/sdk/embed.ts +63 -39
  101. package/src/serve/background-runtime.ts +1 -1
  102. package/src/serve/context.ts +41 -56
  103. package/src/serve/embed-scheduler.ts +58 -35
  104. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  105. package/src/serve/public/globals.built.css +1 -1
  106. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  107. package/src/serve/resident-admission.ts +36 -36
  108. package/src/serve/resident-background-work.ts +20 -2
  109. package/src/serve/resident-request.ts +11 -5
  110. package/src/serve/resident-runtime.ts +97 -61
  111. package/src/serve/resident-shutdown.ts +153 -0
  112. package/src/serve/routes/api.ts +3 -1
  113. package/src/serve/server.ts +47 -26
  114. package/src/store/migrations/028-vector-variants.ts +54 -0
  115. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  116. package/src/store/migrations/index.ts +4 -0
  117. package/src/store/sqlite/adapter.ts +251 -183
  118. package/src/store/sqlite/eligibility.ts +174 -0
  119. package/src/store/sqlite/graph-edge-application.ts +66 -0
  120. package/src/store/sqlite/graph-reference-state.ts +194 -0
  121. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  122. package/src/store/types.ts +80 -12
  123. package/src/store/vector/eligibility.ts +36 -0
  124. package/src/store/vector/freshness.ts +33 -6
  125. package/src/store/vector/lazy.ts +81 -0
  126. package/src/store/vector/sqlite-vec.ts +106 -54
  127. package/src/store/vector/stats.ts +14 -3
  128. package/src/store/vector/types.ts +35 -2
  129. package/src/store/vector/variant-search.ts +192 -0
  130. package/src/store/vector/variants.ts +451 -0
  131. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  132. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  136. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  137. package/vendor/converters/markitdown-ts/package.json +77 -0
  138. package/vendor/converters/officeparser/LICENSE +21 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  140. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  142. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  144. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  145. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  146. package/vendor/converters/officeparser/dist/cli.js +381 -0
  147. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  148. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  150. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  152. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  154. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  156. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  158. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  160. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  162. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  164. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  166. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  167. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  168. package/vendor/converters/officeparser/dist/index.js +72 -0
  169. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  175. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  177. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  179. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  181. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  183. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  185. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  187. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  189. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  191. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  193. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  195. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  196. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  197. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  198. package/vendor/converters/officeparser/dist/types.js +107 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  200. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  202. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  204. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  206. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  208. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  210. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  212. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  214. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  216. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  218. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  220. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  222. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  224. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  226. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  228. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  229. package/vendor/converters/officeparser/package.json +147 -0
  230. package/vendor/converters/upstream-manifest.json +124 -0
  231. package/vendor/dependency-fixes/README.md +77 -0
  232. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
  234. package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
  235. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  236. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -0,0 +1,344 @@
1
+ "use strict";
2
+ /**
3
+ * Shared output-sanitization helpers.
4
+ *
5
+ * Every string in the parsed AST originates from an untrusted document, so any
6
+ * value interpolated into generated output (HTML, XHTML, CSS, URLs, inline
7
+ * scripts, CSV, RTF, Markdown) must be escaped for its destination context.
8
+ * These are the single source of truth — each generator delegates to them so
9
+ * escaping stays consistent and a gap fixed here is fixed everywhere.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.isSafeHtmlAttributeName = isSafeHtmlAttributeName;
13
+ exports.isSafeStyleMapTag = isSafeStyleMapTag;
14
+ exports.escapeHtml = escapeHtml;
15
+ exports.escapeXml = escapeXml;
16
+ exports.sanitizeCssValue = sanitizeCssValue;
17
+ exports.sanitizeUrl = sanitizeUrl;
18
+ exports.iframeAllowed = iframeAllowed;
19
+ exports.sanitizeImageUrl = sanitizeImageUrl;
20
+ exports.serializeForInlineScript = serializeForInlineScript;
21
+ exports.csvSafeCell = csvSafeCell;
22
+ exports.sanitizeRtfUrl = sanitizeRtfUrl;
23
+ exports.escapeRtf = escapeRtf;
24
+ exports.markdownEscapeText = markdownEscapeText;
25
+ exports.sanitizeMarkdownUrl = sanitizeMarkdownUrl;
26
+ /**
27
+ * Whether a string is a plain HTML attribute *name*, safe to interpolate before `="..."`.
28
+ *
29
+ * Escaping the value is not enough on its own: a key containing a quote or `=` closes the
30
+ * attribute and opens another, so `x" onmouseover="alert(1)" z` yields a real event handler no
31
+ * matter how carefully the value is escaped. This is the shape an attribute-injection payload
32
+ * takes, and rejecting it outright is simpler and safer than trying to escape a name.
33
+ *
34
+ * The predicate is shared rather than restated because it is now applied at four independent
35
+ * points (the parser's attribute collection, the generator's attribute bag, and two
36
+ * styleMap-driven paths). Each of those still keeps its own skip-list inline: the lists are the
37
+ * same policy expressed for different layers, and collapsing them would erase the defence in
38
+ * depth the surrounding comments describe.
39
+ */
40
+ function isSafeHtmlAttributeName(name) {
41
+ return typeof name === 'string' && /^[a-zA-Z][a-zA-Z0-9-]*$/.test(name);
42
+ }
43
+ /**
44
+ * Element names a `styleMap` may map a node onto.
45
+ *
46
+ * An allowlist rather than a pattern: a tag name is interpolated into both `<TAG …>` and
47
+ * `</TAG>`, so it is not enough for it to *look* like a name - `script`, `style`, `iframe` and
48
+ * friends are perfectly well-formed names that would introduce an active context the rest of the
49
+ * generator's escaping assumes does not exist. This is the semantic set a style mapping is for:
50
+ * block containers, headings, and the inline emphasis elements.
51
+ */
52
+ const SAFE_STYLE_MAP_TAGS = new Set([
53
+ 'p', 'div', 'span', 'section', 'article', 'aside', 'header', 'footer', 'main', 'figure', 'figcaption',
54
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
55
+ 'blockquote', 'pre', 'code', 'q', 'cite', 'address',
56
+ 'ul', 'ol', 'li', 'dl', 'dt', 'dd',
57
+ 'b', 'strong', 'i', 'em', 'u', 'ins', 'del', 's', 'strike', 'mark', 'small', 'sub', 'sup', 'kbd', 'samp', 'var', 'abbr',
58
+ ]);
59
+ /**
60
+ * Whether a `styleMap` `output.tag` may be emitted as an element name.
61
+ *
62
+ * Callers must fall back to their default tag when this returns false, never emit the value.
63
+ */
64
+ function isSafeStyleMapTag(tag) {
65
+ return typeof tag === 'string' && SAFE_STYLE_MAP_TAGS.has(tag.toLowerCase());
66
+ }
67
+ /**
68
+ * Escapes text for an HTML text node or a double-quoted attribute value.
69
+ * Includes the single quote so the result is also safe inside single-quoted
70
+ * attributes.
71
+ */
72
+ function escapeHtml(text) {
73
+ if (typeof text !== 'string')
74
+ return text;
75
+ return text
76
+ .replace(/&/g, '&amp;')
77
+ .replace(/</g, '&lt;')
78
+ .replace(/>/g, '&gt;')
79
+ .replace(/"/g, '&quot;')
80
+ .replace(/'/g, '&#39;');
81
+ }
82
+ /**
83
+ * Escapes text for an XML text node or attribute (XHTML/OPF/NCX). Same as
84
+ * escapeHtml but emits the XML-canonical `&apos;` for the single quote.
85
+ */
86
+ function escapeXml(text) {
87
+ if (typeof text !== 'string')
88
+ return '';
89
+ return text
90
+ .replace(/&/g, '&amp;')
91
+ .replace(/</g, '&lt;')
92
+ .replace(/>/g, '&gt;')
93
+ .replace(/"/g, '&quot;')
94
+ .replace(/'/g, '&apos;');
95
+ }
96
+ /**
97
+ * Sanitizes a single CSS value (e.g. a color/size/font/alignment pulled from a
98
+ * document) for placement inside a `style="prop: VALUE"` attribute.
99
+ *
100
+ * - Drops the whole value if it contains a resource-fetching or executing
101
+ * construct (`url()`, `expression()`, `@import`, `image-set()`, `javascript:`)
102
+ * or angle brackets that could break out of the attribute/tag.
103
+ * - Strips characters that break out of `prop: value` (`;`, quotes), out of a
104
+ * `<style>` rule (`{}`), CSS escapes (`\`), and control characters.
105
+ *
106
+ * `rgb()/hsl()` and hex/named colors, lengths, and (unquoted) font names all
107
+ * survive; the trade-off is that legitimately quoted font names lose their
108
+ * quotes, which browsers tolerate.
109
+ */
110
+ function sanitizeCssValue(value) {
111
+ if (typeof value !== 'string')
112
+ return '';
113
+ // Strip every form of intra-token noise FIRST, then test for dangerous constructs.
114
+ // Order matters: a payload like "u\nrl(", "url/*x*/(" or "u\rl(" would survive the test if
115
+ // tested before removal, then reassemble into "url(" once the noise is stripped.
116
+ //
117
+ // The backslash strip belongs here, not after the test. CSS treats `\` as an escape a
118
+ // browser resolves away, so `u\rl(http://evil)` IS `url(http://evil)` to a renderer -
119
+ // stripping it downstream of the test meant the sanitizer handed back a live `url()` it
120
+ // had just declared safe. Every construct in the denylist is reachable this way
121
+ // (`expr\ession(`, `image\-set(`), so the fix is the ordering, not another pattern.
122
+ const cleaned = value
123
+ .replace(/[\x00-\x1F\x7F]/g, '') // control chars (incl. newlines/tabs)
124
+ .replace(/\/\*[\s\S]*?\*\//g, '') // CSS comments used to obfuscate
125
+ .replace(/\\/g, ''); // CSS escapes; see above
126
+ if (/(?:url|expression|image-set|element|-moz-binding)\s*\(|@import|javascript:|[<>]/i.test(cleaned)) {
127
+ return '';
128
+ }
129
+ // Backslash is already gone above; the rest still have work to do here.
130
+ return cleaned.replace(/[;{}"'`]/g, '').trim();
131
+ }
132
+ /**
133
+ * Escapes a document-supplied URL for use in an href/src attribute. Beyond the
134
+ * usual attribute escaping, this rejects script-executing schemes (javascript:,
135
+ * vbscript:, data:, etc.) so a hyperlink extracted from an untrusted document
136
+ * can't run code when clicked — only http(s)/mailto/tel and relative/fragment
137
+ * URLs are passed through.
138
+ */
139
+ function sanitizeUrl(url) {
140
+ if (typeof url !== 'string')
141
+ return '';
142
+ const trimmed = url.trim();
143
+ // Browsers ignore control characters when parsing a URL scheme, so strip them
144
+ // first to catch obfuscated payloads like "java\tscript:alert(1)".
145
+ const stripped = trimmed.replace(/[\x00-\x1F\x7F]+/g, '');
146
+ const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);
147
+ if (schemeMatch && !/^(https?|mailto|tel)$/i.test(schemeMatch[1])) {
148
+ return '';
149
+ }
150
+ // Emit the same normalized string that was validated.
151
+ return escapeHtml(stripped);
152
+ }
153
+ /**
154
+ * Decide whether a non-provider `<iframe>` should be preserved, per
155
+ * `HtmlParserConfig.preserveIframes`. `true` allows any src; an array is a hostname allowlist,
156
+ * where an entry matches the src's host exactly or as a `.`-suffix (so `"vimeo.com"` also matches
157
+ * `player.vimeo.com`). A relative or unparseable src is allowed only under `true`. This is a
158
+ * preservation gate, not a sanitizer - the src is still scheme-checked with `sanitizeUrl` on
159
+ * generation.
160
+ */
161
+ function iframeAllowed(src, preserve) {
162
+ if (preserve === true)
163
+ return true;
164
+ if (!Array.isArray(preserve) || preserve.length === 0)
165
+ return false;
166
+ let host;
167
+ try {
168
+ host = new URL(src).hostname.toLowerCase();
169
+ }
170
+ catch {
171
+ return false;
172
+ }
173
+ return preserve.some(entry => {
174
+ const e = String(entry).toLowerCase().trim();
175
+ return e.length > 0 && (host === e || host.endsWith('.' + e));
176
+ });
177
+ }
178
+ /**
179
+ * Like sanitizeUrl but for an <img>/<source> src: additionally permits
180
+ * `data:image/*` URIs (embedded document images) while still rejecting
181
+ * script-executing schemes and non-image data URIs (e.g. data:text/html).
182
+ */
183
+ function sanitizeImageUrl(url) {
184
+ if (typeof url !== 'string')
185
+ return '';
186
+ const trimmed = url.trim();
187
+ const stripped = trimmed.replace(/[\x00-\x1F\x7F]+/g, '');
188
+ const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);
189
+ if (schemeMatch) {
190
+ const scheme = schemeMatch[1].toLowerCase();
191
+ if (scheme === 'data') {
192
+ if (!/^data:image\//i.test(stripped))
193
+ return '';
194
+ }
195
+ else if (scheme !== 'http' && scheme !== 'https') {
196
+ return '';
197
+ }
198
+ }
199
+ return escapeHtml(stripped);
200
+ }
201
+ /**
202
+ * Serializes data for embedding inside an inline <script> block. JSON.stringify
203
+ * alone doesn't escape "<", so a value containing "</script>" (e.g. a chart
204
+ * label from attacker-controlled document XML) would close the script early and
205
+ * inject markup. Also escapes the U+2028/U+2029 line separators, which are
206
+ * invalid in JS string literals.
207
+ */
208
+ function serializeForInlineScript(data) {
209
+ // U+2028/U+2029 (line/paragraph separators) are valid in JSON but break
210
+ // JS string literals; reference them by code point to keep the source ASCII.
211
+ const lineSep = String.fromCharCode(0x2028);
212
+ const paraSep = String.fromCharCode(0x2029);
213
+ return JSON.stringify(data)
214
+ .replace(/</g, '\\u003C')
215
+ .replace(/>/g, '\\u003E')
216
+ .split(lineSep).join('\\u2028')
217
+ .split(paraSep).join('\\u2029');
218
+ }
219
+ /**
220
+ * Formats a value for a CSV field: guards against spreadsheet formula/DDE
221
+ * injection (CWE-1236) and applies RFC 4180 quoting.
222
+ *
223
+ * A cell beginning with `= + - @` (or a tab/CR that some apps treat as a
224
+ * formula start) is prefixed with a single quote so Excel/Sheets render it as
225
+ * literal text rather than executing it. Genuine numbers (including negatives)
226
+ * are exempt so numeric columns are preserved.
227
+ */
228
+ function csvSafeCell(value, delimiter) {
229
+ let v = typeof value === 'string' ? value : String(value ?? '');
230
+ // A plain signed number (e.g. "-8", "+7", "-5.3") can't be a formula, so exempt it —
231
+ // otherwise numeric columns get quoted as text. Anything else starting with a formula
232
+ // trigger (including "+1+1", "-1+cmd", "=", "@") is prefixed with a quote.
233
+ const isNumber = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(v.trim());
234
+ // Test the trimmed value: the numeric exemption above already trims, so testing the raw
235
+ // string here meant a leading space slipped a trigger past the guard (" =1+1" was emitted
236
+ // unprefixed). Most spreadsheet apps treat a leading-space cell as text and would not
237
+ // evaluate it, so this is defence in depth rather than a demonstrated bypass - but the
238
+ // asymmetry between the two tests was an accident, not a decision.
239
+ if (!isNumber && /^[=+\-@\t\r]/.test(v.trim())) {
240
+ v = `'${v}`;
241
+ }
242
+ if (v.includes(delimiter) || v.includes('"') || v.includes('\n') || v.includes('\r')) {
243
+ return `"${v.replace(/"/g, '""')}"`;
244
+ }
245
+ return v;
246
+ }
247
+ /**
248
+ * Validates and escapes a document-supplied URL for an RTF `HYPERLINK` field argument.
249
+ *
250
+ * Mirrors `sanitizeUrl`'s contract (validate the scheme, then encode for the destination, else
251
+ * return `''`) but cannot reuse it: `sanitizeUrl` returns `escapeHtml(...)`, which would emit
252
+ * `&amp;` into an RTF field. The scheme allowlist is deliberately identical to `sanitizeUrl`'s
253
+ * and `sanitizeMarkdownUrl`'s, so all three text generators agree on what a hyperlink may point at.
254
+ *
255
+ * **Additionally rejects UNC paths (`\\host\share`), which the HTML allowlist does not.** In a
256
+ * browser `\\evil.com\share` is an inert relative path; in Word it is a live UNC reference that
257
+ * triggers an SMB fetch and an NTLM handshake on click, which is a credential-leak vector rather
258
+ * than a rendering quirk. That asymmetry is why this is a separate function and not a flag on
259
+ * `sanitizeUrl` - the HTML helper must NOT gain this behaviour, since there the path is harmless
260
+ * and rejecting it would break legitimate relative links.
261
+ *
262
+ * Returns `''` for a rejected URL; callers emit the link text without the field wrapper, matching
263
+ * how HTML degrades to `href=""` and Markdown to `[text]()`.
264
+ */
265
+ function sanitizeRtfUrl(url) {
266
+ if (typeof url !== 'string')
267
+ return '';
268
+ const trimmed = url.trim();
269
+ // Control characters are stripped before scheme matching for the same reason as sanitizeUrl:
270
+ // they are ignored when the target application parses the scheme.
271
+ const stripped = trimmed.replace(/[\x00-\x1F\x7F]+/g, '');
272
+ if (/^[\\/]{2}[^\\/]/.test(stripped))
273
+ return ''; // UNC (\\host\share, //host\share)
274
+ const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);
275
+ if (schemeMatch && !/^(https?|mailto|tel)$/i.test(schemeMatch[1])) {
276
+ return '';
277
+ }
278
+ return escapeRtf(stripped);
279
+ }
280
+ /**
281
+ * Escapes text for RTF: neutralizes the control/group metacharacters `\ { }`
282
+ * (which would otherwise inject RTF control words or groups), encodes the double
283
+ * quote (so a hyperlink field argument can't be terminated early), and hex/unicode
284
+ * encodes non-ASCII characters.
285
+ */
286
+ function escapeRtf(text) {
287
+ if (typeof text !== 'string')
288
+ return '';
289
+ return text
290
+ .replace(/\\/g, '\\\\')
291
+ .replace(/{/g, '\\{')
292
+ .replace(/}/g, '\\}')
293
+ .replace(/"/g, "\\'22")
294
+ .replace(/[^\x00-\x7F]/g, (match) => {
295
+ let code = match.charCodeAt(0);
296
+ if (code < 256) {
297
+ return `\\'${code.toString(16).padStart(2, '0')}`;
298
+ }
299
+ if (code > 32767) {
300
+ code -= 65536;
301
+ }
302
+ return `{\\uc0\\u${code}}`;
303
+ });
304
+ }
305
+ /**
306
+ * Escapes document text for a Markdown text position. Markdown passes raw HTML
307
+ * through to the renderer, so a `<` that begins an HTML tag or comment must be
308
+ * neutralized to prevent `<script>`/`<img onerror>` injection when the Markdown
309
+ * is later rendered to HTML.
310
+ *
311
+ * Deliberately narrow — only a `<` immediately followed by a letter, `/`, `!` or
312
+ * `?` (i.e. one that actually opens a tag/comment/PI, matching how browsers
313
+ * detect tags) is encoded. A bare `<` (e.g. `a < b`), `>`, `&`, `[]` and other
314
+ * Markdown metacharacters are left untouched: they can't start a tag, and
315
+ * MarkdownParser round-trips this output without decoding entities, so encoding
316
+ * them would corrupt re-parsed content. URL schemes are handled by
317
+ * sanitizeMarkdownUrl.
318
+ */
319
+ function markdownEscapeText(text) {
320
+ if (typeof text !== 'string')
321
+ return '';
322
+ return text.replace(/<(?=[a-zA-Z/!?])/g, '&lt;');
323
+ }
324
+ /**
325
+ * Sanitizes a document-supplied URL for a Markdown `[text](url)` / `![alt](url)`
326
+ * target. Rejects script-executing schemes (returning '' → a dead link) and
327
+ * percent-encodes the characters that would break out of the `(...)` or inject
328
+ * markup. `&` is preserved so query strings survive; set `allowDataImage` for
329
+ * image targets so embedded `data:image/*` URIs are permitted.
330
+ */
331
+ function sanitizeMarkdownUrl(url, opts) {
332
+ if (typeof url !== 'string')
333
+ return '';
334
+ const stripped = url.trim().replace(/[\x00-\x1F\x7F]+/g, '');
335
+ const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);
336
+ if (schemeMatch) {
337
+ const scheme = schemeMatch[1].toLowerCase();
338
+ const ok = /^(?:https?|mailto|tel)$/.test(scheme)
339
+ || (opts?.allowDataImage === true && /^data:image\//i.test(stripped));
340
+ if (!ok)
341
+ return '';
342
+ }
343
+ return stripped.replace(/[\s()<>"`\\]/g, (c) => '%' + c.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'));
344
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Parses a range string (e.g., "1", "1-3", "1,2", "1,3-5, 7") into an array of numbers.
3
+ *
4
+ * @param rangeStr - The range string to parse
5
+ * @returns An array of unique, sorted numbers (1-based indices)
6
+ */
7
+ export declare function parseRangeString(rangeStr: string): number[];
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRangeString = parseRangeString;
4
+ /**
5
+ * Parses a range string (e.g., "1", "1-3", "1,2", "1,3-5, 7") into an array of numbers.
6
+ *
7
+ * @param rangeStr - The range string to parse
8
+ * @returns An array of unique, sorted numbers (1-based indices)
9
+ */
10
+ function parseRangeString(rangeStr) {
11
+ const result = new Set();
12
+ const segments = rangeStr.split(',');
13
+ for (const segment of segments) {
14
+ const trimmed = segment.trim();
15
+ if (trimmed.includes('-')) {
16
+ const [startStr, endStr] = trimmed.split('-');
17
+ const start = parseInt(startStr, 10);
18
+ const end = parseInt(endStr, 10);
19
+ if (!isNaN(start) && !isNaN(end)) {
20
+ const actualStart = Math.min(start, end);
21
+ const actualEnd = Math.max(start, end);
22
+ for (let i = actualStart; i <= actualEnd; i++) {
23
+ result.add(i);
24
+ }
25
+ }
26
+ }
27
+ else {
28
+ const val = parseInt(trimmed, 10);
29
+ if (!isNaN(val)) {
30
+ result.add(val);
31
+ }
32
+ }
33
+ }
34
+ return Array.from(result).sort((a, b) => a - b);
35
+ }
@@ -0,0 +1,36 @@
1
+ import { OfficeContentNode, StructuredStyleMapping } from '../types.js';
2
+ export interface StyleMapping {
3
+ selector: {
4
+ nodeType?: string;
5
+ attributes: Record<string, {
6
+ value: string | number | boolean;
7
+ operator: '=' | '~=';
8
+ compiled?: RegExp;
9
+ }>;
10
+ };
11
+ output: {
12
+ tag: string;
13
+ classes: string[];
14
+ attributes: Record<string, string>;
15
+ fresh: boolean;
16
+ };
17
+ }
18
+ /**
19
+ * Parser and matcher for the style mapping DSL.
20
+ * Supports a structured JSON format and a legacy string DSL.
21
+ */
22
+ export declare class StyleMapper {
23
+ private mappings;
24
+ constructor(mappings?: string[] | StructuredStyleMapping[] | Record<string, any>, ignoreDefaults?: boolean);
25
+ /**
26
+ * Finds the best matching mapping for a node.
27
+ */
28
+ getMapping(node: OfficeContentNode): StyleMapping['output'] | undefined;
29
+ private matches;
30
+ private getNodeAttribute;
31
+ private convertStructuredMapping;
32
+ /**
33
+ * Parses a mapping string like "p[style-name='Heading 1'] => h1.title:fresh"
34
+ */
35
+ private parseMappingString;
36
+ }
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StyleMapper = void 0;
4
+ const types_js_1 = require("../types.js");
5
+ const errorUtils_js_1 = require("./errorUtils.js");
6
+ const DEFAULT_MAPPINGS = [
7
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 1' } }, output: { tag: 'h1' } },
8
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 2' } }, output: { tag: 'h2' } },
9
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 3' } }, output: { tag: 'h3' } },
10
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 4' } }, output: { tag: 'h4' } },
11
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 5' } }, output: { tag: 'h5' } },
12
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Heading 6' } }, output: { tag: 'h6' } },
13
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Title' } }, output: { tag: 'h1', classes: ['title'] } },
14
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Subtitle' } }, output: { tag: 'p', classes: ['subtitle'] } },
15
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Quote' } }, output: { tag: 'blockquote' } },
16
+ { selector: { nodeType: 'paragraph', attributes: { 'style-name': 'Intense Quote' } }, output: { tag: 'blockquote', classes: ['intense'] } },
17
+ ];
18
+ /**
19
+ * Parser and matcher for the style mapping DSL.
20
+ * Supports a structured JSON format and a legacy string DSL.
21
+ */
22
+ class StyleMapper {
23
+ mappings = [];
24
+ constructor(mappings, ignoreDefaults = false) {
25
+ // 1. Add user mappings (they take precedence)
26
+ if (mappings) {
27
+ if (Array.isArray(mappings)) {
28
+ for (const m of mappings) {
29
+ if (typeof m === 'string') {
30
+ this.mappings.push(this.parseMappingString(m));
31
+ }
32
+ else {
33
+ this.mappings.push(this.convertStructuredMapping(m));
34
+ }
35
+ }
36
+ }
37
+ else {
38
+ // Support legacy object format: { 'Heading 1': { tag: 'h1', class: 'title' } }
39
+ for (const [styleName, target] of Object.entries(mappings)) {
40
+ this.mappings.push({
41
+ selector: {
42
+ attributes: { style: { value: styleName, operator: '=' } }
43
+ },
44
+ output: {
45
+ tag: target.tag || 'div',
46
+ classes: target.class ? target.class.split(' ') : [],
47
+ attributes: {},
48
+ fresh: false
49
+ }
50
+ });
51
+ }
52
+ }
53
+ }
54
+ // 2. Add default mappings if not ignored
55
+ if (!ignoreDefaults) {
56
+ this.mappings.push(...DEFAULT_MAPPINGS.map(m => this.convertStructuredMapping(m)));
57
+ }
58
+ }
59
+ /**
60
+ * Finds the best matching mapping for a node.
61
+ */
62
+ getMapping(node) {
63
+ for (const mapping of this.mappings) {
64
+ if (this.matches(node, mapping.selector)) {
65
+ return mapping.output;
66
+ }
67
+ }
68
+ return undefined;
69
+ }
70
+ matches(node, selector) {
71
+ // Match node type if specified
72
+ if (selector.nodeType && node.type !== selector.nodeType) {
73
+ return false;
74
+ }
75
+ // Match attributes (style, level, etc.)
76
+ for (const [attr, { value, operator, compiled }] of Object.entries(selector.attributes)) {
77
+ const actualValue = this.getNodeAttribute(node, attr);
78
+ if (actualValue === undefined)
79
+ return false;
80
+ if (operator === '=') {
81
+ if (String(actualValue) !== String(value))
82
+ return false;
83
+ }
84
+ else if (operator === '~=') {
85
+ const regex = compiled || new RegExp(String(value));
86
+ if (!regex.test(String(actualValue)))
87
+ return false;
88
+ }
89
+ }
90
+ return true;
91
+ }
92
+ getNodeAttribute(node, attr) {
93
+ // Special case for style (alias style-name for mammoth.js compatibility)
94
+ if (attr === 'style' || attr === 'style-name') {
95
+ return node.metadata?.style || node.formatting?.font;
96
+ }
97
+ // Metadata attributes
98
+ if (node.metadata && attr in node.metadata) {
99
+ return node.metadata[attr];
100
+ }
101
+ // Formatting attributes
102
+ if (node.formatting && attr in node.formatting) {
103
+ return node.formatting[attr];
104
+ }
105
+ return undefined;
106
+ }
107
+ convertStructuredMapping(m) {
108
+ const attributes = {};
109
+ if (m.selector.attributes) {
110
+ for (const [key, val] of Object.entries(m.selector.attributes)) {
111
+ if (typeof val === 'object' && val !== null && 'value' in val) {
112
+ const operator = val.operator || '=';
113
+ attributes[key] = {
114
+ value: val.value,
115
+ operator,
116
+ compiled: operator === '~=' ? new RegExp(String(val.value)) : undefined
117
+ };
118
+ }
119
+ else {
120
+ attributes[key] = {
121
+ value: val,
122
+ operator: '='
123
+ };
124
+ }
125
+ }
126
+ }
127
+ return {
128
+ selector: {
129
+ nodeType: m.selector.nodeType,
130
+ attributes
131
+ },
132
+ output: {
133
+ tag: m.output.tag,
134
+ classes: m.output.classes || [],
135
+ attributes: m.output.attributes || {},
136
+ fresh: m.output.fresh || false
137
+ }
138
+ };
139
+ }
140
+ /**
141
+ * Parses a mapping string like "p[style-name='Heading 1'] => h1.title:fresh"
142
+ */
143
+ parseMappingString(mapping) {
144
+ const lastIndex = mapping.lastIndexOf('=>');
145
+ if (lastIndex === -1) {
146
+ throw (0, errorUtils_js_1.getOfficeError)(types_js_1.OfficeErrorType.INVALID_STYLE_MAPPING, undefined, mapping);
147
+ }
148
+ const selectorStr = mapping.substring(0, lastIndex).trim();
149
+ const outputStr = mapping.substring(lastIndex + 2).trim();
150
+ // Parse Selector
151
+ const selectorMatch = selectorStr.match(/^([a-z]+)?(?:\[(.+?)\])?$/);
152
+ if (!selectorMatch) {
153
+ throw (0, errorUtils_js_1.getOfficeError)(types_js_1.OfficeErrorType.INVALID_SELECTOR, undefined, selectorStr);
154
+ }
155
+ const typeMap = {
156
+ 'p': 'paragraph',
157
+ 'h': 'heading',
158
+ 't': 'table',
159
+ 'tr': 'row',
160
+ 'td': 'cell',
161
+ 'li': 'list',
162
+ 'img': 'image'
163
+ };
164
+ const nodeType = selectorMatch[1] ? (typeMap[selectorMatch[1]] || selectorMatch[1]) : undefined;
165
+ const attrStr = selectorMatch[2];
166
+ const attributes = {};
167
+ if (attrStr) {
168
+ // Improved attribute parsing to handle commas inside quotes
169
+ const attrParts = [];
170
+ let currentPart = '';
171
+ let inQuotes = false;
172
+ for (let i = 0; i < attrStr.length; i++) {
173
+ const char = attrStr[i];
174
+ if (char === "'" || char === '"')
175
+ inQuotes = !inQuotes;
176
+ if (char === ',' && !inQuotes) {
177
+ attrParts.push(currentPart.trim());
178
+ currentPart = '';
179
+ }
180
+ else {
181
+ currentPart += char;
182
+ }
183
+ }
184
+ if (currentPart)
185
+ attrParts.push(currentPart.trim());
186
+ for (const part of attrParts) {
187
+ const m = part.match(/^([\w-]+)\s*(=|~=)\s*(?:(["'])(.*?)\3|(.+))$/);
188
+ if (m) {
189
+ const operator = m[2];
190
+ const value = m[4] !== undefined ? m[4] : m[5];
191
+ attributes[m[1]] = {
192
+ operator,
193
+ value,
194
+ compiled: operator === '~=' ? new RegExp(value) : undefined
195
+ };
196
+ }
197
+ }
198
+ }
199
+ // Parse Output
200
+ const outputParts = outputStr.split(':');
201
+ const fresh = outputParts.includes('fresh');
202
+ const mainOutput = outputParts[0];
203
+ const outputMatch = mainOutput.match(/^([a-z0-9]+)?((?:\.[\w-]+)*)(?:\[(.+?)\])?$/);
204
+ if (!outputMatch) {
205
+ throw (0, errorUtils_js_1.getOfficeError)(types_js_1.OfficeErrorType.INVALID_OUTPUT_MAPPING, undefined, mainOutput);
206
+ }
207
+ const tag = outputMatch[1] || 'div';
208
+ const classes = outputMatch[2] ? outputMatch[2].split('.').filter(Boolean) : [];
209
+ const outAttrs = {};
210
+ if (outputMatch[3]) {
211
+ const outAttrParts = outputMatch[3].split(',').map(a => a.trim());
212
+ for (const part of outAttrParts) {
213
+ const m = part.match(/^([\w-]+)\s*=\s*(?:(["'])(.*?)\2|(.+))$/);
214
+ if (m)
215
+ outAttrs[m[1]] = m[3] !== undefined ? m[3] : m[4];
216
+ }
217
+ }
218
+ return {
219
+ selector: { nodeType, attributes },
220
+ output: { tag, classes, attributes: outAttrs, fresh }
221
+ };
222
+ }
223
+ }
224
+ exports.StyleMapper = StyleMapper;