bestax-migrate 2.25.5 → 2.25.6

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.
@@ -0,0 +1,355 @@
1
+ /**
2
+ * A parsed HTML tree → JSX source, laid out the way the HTML was.
3
+ *
4
+ * Each element keeps its tag (SVG's with the casing parse5 restores, so
5
+ * `foreignObject`), its attributes become props (`attributes.ts`), and its
6
+ * children follow the source's own lines: a run of whitespace with a line
7
+ * break in it is a line break in the JSX, at two spaces an indent. JSX drops
8
+ * such a run, so where the run renders (`whitespace.ts`) and a line break
9
+ * would lose it, the space is written out as `{" "}`; between two texts JSX
10
+ * joins the lines with a space already. Preformatted content is written on
11
+ * the lines it has, with a template literal for text that spans several, and
12
+ * a script's or stylesheet's text is always one.
13
+ *
14
+ * Void elements close themselves, and so does an element with nothing left
15
+ * in it. A comment becomes a JSX comment, except Internet Explorer's
16
+ * conditional ones, which no supported browser reads. What can't be written
17
+ * as it was is reported, with the HTML line it is on, for the caller to turn
18
+ * into TODOs: `HtmlIssue` lists the kinds, and which of them are emitted.
19
+ */
20
+ import { convertAttributes, isCustomElement, printProp, } from './attributes.js';
21
+ import { isComment, } from './parse.js';
22
+ import { isConditionalComment, jsxComment, jsxText, templateLiteral, } from './text.js';
23
+ import { defaultDisplayOf, layoutWhitespace, } from './whitespace.js';
24
+ const HTML = 'http://www.w3.org/1999/xhtml';
25
+ const VOID = new Set([
26
+ 'area',
27
+ 'base',
28
+ 'basefont',
29
+ 'bgsound',
30
+ 'br',
31
+ 'col',
32
+ 'embed',
33
+ 'frame',
34
+ 'hr',
35
+ 'img',
36
+ 'input',
37
+ 'keygen',
38
+ 'link',
39
+ 'meta',
40
+ 'param',
41
+ 'source',
42
+ 'track',
43
+ 'wbr',
44
+ ]);
45
+ /** Elements whose text is code, never markup. */
46
+ const RAW_TEXT = new Set(['script', 'style']);
47
+ /** The current elements of the HTML standard. */
48
+ const KNOWN = new Set(('a abbr address area article aside audio b base bdi bdo blockquote body ' +
49
+ 'br button canvas caption cite code col colgroup data datalist dd del ' +
50
+ 'details dfn dialog div dl dt em embed fieldset figcaption figure footer ' +
51
+ 'form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ' +
52
+ 'ins kbd label legend li link main map mark menu meta meter nav noscript ' +
53
+ 'object ol optgroup option output p picture pre progress q rp rt ruby s ' +
54
+ 'samp script search section select selectedcontent slot small source ' +
55
+ 'span strong style sub summary sup table tbody td template textarea ' +
56
+ 'tfoot th thead time title tr track u ul var video wbr').split(' '));
57
+ /** Its obsolete ones, which still parse. */
58
+ const OBSOLETE = new Set(('acronym applet basefont bgsound big blink center dir font frame ' +
59
+ 'frameset isindex keygen listing marquee menuitem multicol nextid nobr ' +
60
+ 'noembed noframes param plaintext rb rtc spacer strike tt xmp').split(' '));
61
+ /** A tag JSX reads as an intrinsic element: lowercase first, no `.` or `:`. */
62
+ const JSX_TAG = /^[a-z][\w$-]*$/;
63
+ const INDENT = ' ';
64
+ /** Lines of output, each write going on the end of the open one. */
65
+ class Writer {
66
+ lines = [];
67
+ open = null;
68
+ /**
69
+ * Write on the open line, or open one at `depth`. A line break in `text`
70
+ * (a template literal's) is kept as it is, with no indent after it.
71
+ */
72
+ write(text, depth, html) {
73
+ const [first, ...rest] = text.split('\n');
74
+ if (!this.open) {
75
+ this.open = { depth, text: '', html };
76
+ this.lines.push(this.open);
77
+ }
78
+ this.open.text += first;
79
+ this.open.html ??= html;
80
+ rest.forEach((part, index) => {
81
+ this.open = {
82
+ depth: null,
83
+ text: part,
84
+ html: html === null ? null : html + index + 1,
85
+ };
86
+ this.lines.push(this.open);
87
+ });
88
+ }
89
+ /** End the line; the next write starts a new one. */
90
+ break() {
91
+ this.open = null;
92
+ }
93
+ blank() {
94
+ this.break();
95
+ this.lines.push({ depth: 0, text: '', html: null });
96
+ }
97
+ }
98
+ /**
99
+ * Pieces as items: words and the spaces between them on one line joined
100
+ * into texts, a run with a line break in it as a break, and a run that
101
+ * renders nothing on one line dropped.
102
+ *
103
+ * Two runs meet only where a dropped comment was between them, and then a
104
+ * space that renders can end up beside a line break, where JSX would trim
105
+ * it. Such a space is the break's to write, so a text never starts or ends
106
+ * with a space next to a break.
107
+ */
108
+ function itemsOf(pieces) {
109
+ const items = [];
110
+ for (const piece of pieces) {
111
+ let last = items[items.length - 1];
112
+ if (piece.kind === 'node') {
113
+ items.push({ kind: 'node', node: piece.node });
114
+ }
115
+ else if (piece.kind === 'space' && piece.newlines > 0) {
116
+ let kept = piece.kept;
117
+ if (last?.kind === 'text' && last.text.endsWith(' ')) {
118
+ kept = true;
119
+ last.text = last.text.slice(0, -1);
120
+ if (last.text === '')
121
+ items.pop();
122
+ last = items[items.length - 1];
123
+ }
124
+ const blank = piece.newlines > 1;
125
+ if (last?.kind === 'break') {
126
+ last.kept ||= kept;
127
+ last.blank ||= blank;
128
+ }
129
+ else {
130
+ items.push({ kind: 'break', kept, blank });
131
+ }
132
+ }
133
+ else if (piece.kind === 'space' && piece.kept && last?.kind === 'break') {
134
+ last.kept = true;
135
+ }
136
+ else if (piece.kind !== 'space' || piece.kept) {
137
+ const text = piece.kind === 'space' ? ' ' : piece.text;
138
+ if (last?.kind === 'text')
139
+ last.text += text;
140
+ else
141
+ items.push({ kind: 'text', text, line: piece.line });
142
+ }
143
+ }
144
+ return items;
145
+ }
146
+ /**
147
+ * Items that run over several lines, given a line break at each end too, so
148
+ * the tags sit on lines of their own. JSX drops a line break beside a tag,
149
+ * so that changes nothing, except that a space a text starts or ends with
150
+ * would go with it: that space becomes the break's.
151
+ */
152
+ function framed(items) {
153
+ if (!items.some(item => item.kind === 'break'))
154
+ return items;
155
+ const out = [...items];
156
+ const edge = (at) => {
157
+ const index = at === 'start' ? 0 : out.length - 1;
158
+ const item = out[index];
159
+ if (item.kind === 'break')
160
+ return;
161
+ let kept = false;
162
+ if (item.kind === 'text') {
163
+ const space = at === 'start' ? /^ / : / $/;
164
+ kept = space.test(item.text);
165
+ const text = item.text.replace(space, '');
166
+ if (text === '')
167
+ out.splice(index, 1);
168
+ else
169
+ out[index] = { ...item, text };
170
+ }
171
+ const added = { kind: 'break', kept, blank: false };
172
+ if (at === 'start')
173
+ out.unshift(added);
174
+ else
175
+ out.push(added);
176
+ };
177
+ edge('start');
178
+ edge('end');
179
+ return out;
180
+ }
181
+ export function emitJsx(root, options = {}) {
182
+ const layout = layoutWhitespace(root, options.displayOf ?? defaultDisplayOf);
183
+ const out = new Writer();
184
+ const reported = [];
185
+ const report = (issue, line) => {
186
+ reported.push({ ...issue, line });
187
+ };
188
+ /**
189
+ * A parent's pieces as they are written, reporting what changes: a
190
+ * comment no browser reads goes, and an element JSX can't name gives way
191
+ * to its children, which join the text around them.
192
+ */
193
+ const piecesOf = (parent) => (layout.get(parent) ?? []).flatMap(piece => {
194
+ if (piece.kind !== 'node')
195
+ return [piece];
196
+ const node = piece.node;
197
+ const line = node.sourceCodeLocation?.startLine ?? null;
198
+ if (isComment(node)) {
199
+ if (!isConditionalComment(node.data))
200
+ return [piece];
201
+ report({ kind: 'conditional-comment', token: 'comment' }, line);
202
+ return [];
203
+ }
204
+ if (JSX_TAG.test(node.tagName))
205
+ return [piece];
206
+ report({ kind: 'element-name', token: node.tagName }, line);
207
+ return piecesOf(node);
208
+ });
209
+ const comment = (node, depth) => {
210
+ const line = node.sourceCodeLocation?.startLine ?? null;
211
+ jsxComment(node.data).forEach((text, index) => {
212
+ if (index > 0)
213
+ out.break();
214
+ out.write(text, depth, line);
215
+ });
216
+ };
217
+ /** Preformatted children: every character, on the lines it has. */
218
+ const exact = (parent, pieces, depth) => {
219
+ for (const piece of pieces) {
220
+ if (piece.kind === 'node') {
221
+ if (isComment(piece.node))
222
+ comment(piece.node, depth);
223
+ else
224
+ element(piece.node, depth);
225
+ }
226
+ else if (piece.kind === 'exact' && piece.text !== '') {
227
+ const literal = RAW_TEXT.has(parent.tagName) || piece.text.includes('\n');
228
+ out.write(literal ? `{${templateLiteral(piece.text)}}` : jsxText(piece.text), depth, piece.line);
229
+ }
230
+ }
231
+ };
232
+ /** Children laid out on the source's lines, one indent in from `depth`. */
233
+ const flow = (items, depth) => {
234
+ items.forEach((item, index) => {
235
+ if (item.kind === 'break') {
236
+ const before = items[index - 1];
237
+ const after = items[index + 1];
238
+ const betweenTexts = before?.kind === 'text' && after?.kind === 'text';
239
+ // JSX joins two texts across a line break with a space, so a run
240
+ // that renders nothing between them stays on one line.
241
+ if (betweenTexts && !item.kept)
242
+ return;
243
+ if (item.kept && !betweenTexts)
244
+ out.write('{" "}', depth + 1, null);
245
+ if (item.blank && before && after)
246
+ out.blank();
247
+ out.break();
248
+ }
249
+ else if (item.kind === 'text') {
250
+ out.write(jsxText(item.text), depth + 1, item.line);
251
+ }
252
+ else if (isComment(item.node)) {
253
+ comment(item.node, depth + 1);
254
+ }
255
+ else {
256
+ element(item.node, depth + 1);
257
+ }
258
+ });
259
+ };
260
+ /** Report an element that is written as it was but isn't plain HTML. */
261
+ const reportElement = (node, line) => {
262
+ if (node.namespaceURI !== HTML)
263
+ return;
264
+ const tag = node.tagName;
265
+ if (tag === 'template') {
266
+ report({ kind: 'template', token: tag }, line);
267
+ }
268
+ else if (isCustomElement(node)) {
269
+ report({ kind: 'custom-element', token: tag }, line);
270
+ }
271
+ else if (OBSOLETE.has(tag)) {
272
+ report({ kind: 'obsolete-element', token: tag }, line);
273
+ }
274
+ else if (!KNOWN.has(tag)) {
275
+ report({ kind: 'unknown-element', token: tag }, line);
276
+ }
277
+ };
278
+ const element = (node, depth) => {
279
+ const tag = node.tagName;
280
+ const location = node.sourceCodeLocation;
281
+ const line = location?.startLine ?? null;
282
+ reportElement(node, line);
283
+ const { props, issues } = convertAttributes(node);
284
+ for (const issue of issues) {
285
+ const at = issue.attribute && location?.attrs?.[issue.attribute];
286
+ report(issue, at ? at.startLine : line);
287
+ }
288
+ const pieces = piecesOf(node);
289
+ const preformatted = pieces.some(piece => piece.kind === 'exact');
290
+ const items = preformatted ? [] : framed(itemsOf(pieces));
291
+ const empty = VOID.has(tag) ||
292
+ tag === 'textarea' ||
293
+ pieces.every(piece => (piece.kind === 'space' && !piece.kept) ||
294
+ (piece.kind === 'exact' && piece.text === ''));
295
+ const startTag = location?.startTag;
296
+ const tall = props.length > 1 &&
297
+ startTag !== undefined &&
298
+ startTag.endLine > startTag.startLine;
299
+ out.write(`<${tag}`, depth, line);
300
+ for (const prop of props) {
301
+ const at = location?.attrs?.[prop.attribute]?.startLine ?? line;
302
+ if (tall) {
303
+ out.break();
304
+ out.write(printProp(prop), depth + 1, at);
305
+ }
306
+ else {
307
+ out.write(` ${printProp(prop)}`, depth, at);
308
+ }
309
+ }
310
+ if (tall)
311
+ out.break();
312
+ const close = tall ? '' : ' ';
313
+ out.write(empty ? `${close}/>` : '>', depth, startTag?.endLine ?? line);
314
+ if (empty)
315
+ return;
316
+ if (preformatted)
317
+ exact(node, pieces, depth);
318
+ else
319
+ flow(items, depth);
320
+ const end = location?.endTag?.startLine ?? location?.endLine ?? null;
321
+ out.write(`</${tag}>`, depth, end);
322
+ };
323
+ const items = itemsOf(piecesOf(root));
324
+ const content = items.filter(item => item.kind !== 'break');
325
+ const only = content.length === 1 ? content[0] : undefined;
326
+ if (only?.kind === 'node' && !isComment(only.node)) {
327
+ element(only.node, 0);
328
+ }
329
+ else {
330
+ // A block holds the content, so whitespace at either end renders
331
+ // nothing, and the fragment's tags can sit on lines of their own.
332
+ while (items[0]?.kind === 'break')
333
+ items.shift();
334
+ while (items[items.length - 1]?.kind === 'break')
335
+ items.pop();
336
+ out.write('<>', 0, null);
337
+ if (items.length > 0) {
338
+ out.break();
339
+ flow(items, 0);
340
+ out.break();
341
+ }
342
+ out.write('</>', 0, null);
343
+ }
344
+ const base = options.indent ?? 0;
345
+ const code = out.lines
346
+ .map(entry => entry.depth === null || entry.text === ''
347
+ ? entry.text
348
+ : INDENT.repeat(base + entry.depth) + entry.text)
349
+ .join('\n');
350
+ return {
351
+ code,
352
+ htmlLineOf: line => out.lines[line - 1]?.html ?? null,
353
+ reported,
354
+ };
355
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * HTML source → the DOM a browser builds from it, by parse5.
3
+ *
4
+ * A page is parsed as a document and a partial as a fragment, so a partial
5
+ * gains no `<html>`/`<head>`/`<body>` and a document keeps what the parser
6
+ * moves into its head. Either way the caller gets the content of the body,
7
+ * which is what becomes JSX, and the rest separately: the head's children,
8
+ * the `<html>` and `<body>` attributes, and the comments outside both.
9
+ *
10
+ * Scripting is off, as it is for a page with JavaScript disabled: a
11
+ * `<noscript>` holds markup rather than text, which is what it means to
12
+ * someone reading the page.
13
+ */
14
+ import { type DefaultTreeAdapterMap, type Token } from 'parse5';
15
+ export type Node = DefaultTreeAdapterMap['node'];
16
+ export type ParentNode = DefaultTreeAdapterMap['parentNode'];
17
+ export type ChildNode = DefaultTreeAdapterMap['childNode'];
18
+ export type Element = DefaultTreeAdapterMap['element'];
19
+ export type Template = DefaultTreeAdapterMap['template'];
20
+ export type TextNode = DefaultTreeAdapterMap['textNode'];
21
+ export type CommentNode = DefaultTreeAdapterMap['commentNode'];
22
+ export type Attribute = Token.Attribute;
23
+ export interface HtmlParseError {
24
+ /** parse5's code for it, from the HTML spec (`missing-end-tag-name`). */
25
+ code: string;
26
+ line: number;
27
+ col: number;
28
+ }
29
+ export interface ParsedHtml {
30
+ kind: 'document' | 'fragment';
31
+ /**
32
+ * What holds the content: the `<body>` of a document, or the fragment.
33
+ * Its children are the content; its attributes are the body's.
34
+ */
35
+ root: Element | DefaultTreeAdapterMap['documentFragment'];
36
+ head: ChildNode[];
37
+ htmlAttributes: Attribute[];
38
+ bodyAttributes: Attribute[];
39
+ /**
40
+ * Comments a document has outside its head and body, before `<html>` or
41
+ * after `</body>`, where a credit or licence notice often sits.
42
+ */
43
+ outsideComments: CommentNode[];
44
+ errors: HtmlParseError[];
45
+ }
46
+ /** Whether parse5 should read this source as a whole document. */
47
+ export declare function isDocument(source: string): boolean;
48
+ export declare function isElement(node: Node): node is Element;
49
+ export declare function isText(node: Node): node is TextNode;
50
+ export declare function isComment(node: Node): node is CommentNode;
51
+ /** An element's children, or a `<template>`'s content, which holds them. */
52
+ export declare function childrenOf(node: ParentNode): ChildNode[];
53
+ export declare function parseHtml(source: string): ParsedHtml;
54
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../../src/sources/_shared/html/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAGL,KAAK,qBAAqB,EAE1B,KAAK,KAAK,EACX,MAAM,QAAQ,CAAC;AAEhB,MAAM,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AACjD,MAAM,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;AAC3D,MAAM,MAAM,OAAO,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;AACvD,MAAM,MAAM,QAAQ,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;AACzD,MAAM,MAAM,QAAQ,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;AACzD,MAAM,MAAM,WAAW,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;AAC/D,MAAM,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B;;;OAGG;IACH,IAAI,EAAE,OAAO,GAAG,qBAAqB,CAAC,kBAAkB,CAAC,CAAC;IAC1D,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,cAAc,EAAE,SAAS,EAAE,CAAC;IAC5B,cAAc,EAAE,SAAS,EAAE,CAAC;IAC5B;;;OAGG;IACH,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAQD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,OAAO,CAErD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,QAAQ,CAEnD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,WAAW,CAEzD;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,CAIxD;AAQD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CA6CpD"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * HTML source → the DOM a browser builds from it, by parse5.
3
+ *
4
+ * A page is parsed as a document and a partial as a fragment, so a partial
5
+ * gains no `<html>`/`<head>`/`<body>` and a document keeps what the parser
6
+ * moves into its head. Either way the caller gets the content of the body,
7
+ * which is what becomes JSX, and the rest separately: the head's children,
8
+ * the `<html>` and `<body>` attributes, and the comments outside both.
9
+ *
10
+ * Scripting is off, as it is for a page with JavaScript disabled: a
11
+ * `<noscript>` holds markup rather than text, which is what it means to
12
+ * someone reading the page.
13
+ */
14
+ import { parse, parseFragment, } from 'parse5';
15
+ /**
16
+ * The tags that make HTML a document rather than a partial, wherever they
17
+ * sit outside a comment. `<head` is not `<header`.
18
+ */
19
+ const DOCUMENT_MARKER = /<(?:!doctype|html|head|body)(?=[\s/>])/i;
20
+ /** Whether parse5 should read this source as a whole document. */
21
+ export function isDocument(source) {
22
+ return DOCUMENT_MARKER.test(source.replace(/<!--[\s\S]*?(?:-->|$)/g, ''));
23
+ }
24
+ export function isElement(node) {
25
+ return 'tagName' in node;
26
+ }
27
+ export function isText(node) {
28
+ return node.nodeName === '#text';
29
+ }
30
+ export function isComment(node) {
31
+ return node.nodeName === '#comment';
32
+ }
33
+ /** An element's children, or a `<template>`'s content, which holds them. */
34
+ export function childrenOf(node) {
35
+ return node.nodeName === 'template'
36
+ ? node.content.childNodes
37
+ : node.childNodes;
38
+ }
39
+ function find(nodes, tag) {
40
+ return nodes.find((node) => isElement(node) && node.tagName === tag);
41
+ }
42
+ export function parseHtml(source) {
43
+ const errors = [];
44
+ const options = {
45
+ sourceCodeLocationInfo: true,
46
+ scriptingEnabled: false,
47
+ onParseError: (error) => {
48
+ errors.push({
49
+ code: error.code,
50
+ line: error.startLine,
51
+ col: error.startCol,
52
+ });
53
+ },
54
+ };
55
+ if (!isDocument(source)) {
56
+ return {
57
+ kind: 'fragment',
58
+ root: parseFragment(source, options),
59
+ head: [],
60
+ htmlAttributes: [],
61
+ bodyAttributes: [],
62
+ outsideComments: [],
63
+ errors,
64
+ };
65
+ }
66
+ const document = parse(source, options);
67
+ // The parser always builds `<html>`, and inside it `<head>` and `<body>`
68
+ // (a `<frameset>` page has no body, and gets an empty one here).
69
+ const html = find(document.childNodes, 'html');
70
+ const head = find(html.childNodes, 'head');
71
+ const body = find(html.childNodes, 'body');
72
+ const outsideComments = [...document.childNodes, ...html.childNodes].filter(isComment);
73
+ return {
74
+ kind: 'document',
75
+ root: body ?? {
76
+ nodeName: '#document-fragment',
77
+ childNodes: [],
78
+ },
79
+ head: head?.childNodes ?? [],
80
+ htmlAttributes: html.attrs,
81
+ bodyAttributes: body?.attrs ?? [],
82
+ outsideComments,
83
+ errors,
84
+ };
85
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * A `style="…"` attribute as the object literal React takes.
3
+ *
4
+ * The declarations are split by hand, since a style attribute is a flat list
5
+ * and the only syntax that matters is what can hide a `;` or a `:`: quoted
6
+ * strings, parentheses (`url(a;b)`), and comments. Property names are camel
7
+ * cased the way React hyphenates them back: `-ms-` becomes `ms`, any other
8
+ * vendor prefix a capital (`WebkitTransition`), and a custom property keeps
9
+ * its name, quoted. Which declaration of a property applies is CSS's choice:
10
+ * an `!important` one over the rest, else the last.
11
+ *
12
+ * As in CSS, a declaration that can't be read (an IE hack like `*zoom: 1`,
13
+ * an empty value, a string or parenthesis left open) is skipped and the rest
14
+ * apply; it is handed back for the caller to report. So is an `!important`
15
+ * one, which is written without its priority, since React sets every value
16
+ * without one.
17
+ */
18
+ export type StyleIssue =
19
+ /** A declaration that can't be read, left out. */
20
+ {
21
+ kind: 'style';
22
+ detail: string;
23
+ }
24
+ /** A declaration written without the `!important` React can't set. */
25
+ | {
26
+ kind: 'style-important';
27
+ token: string;
28
+ detail: string;
29
+ };
30
+ export interface StyleObject {
31
+ /** The object literal's source, or null when there is nothing to write. */
32
+ code: string | null;
33
+ issues: StyleIssue[];
34
+ }
35
+ /** The key React reads for a CSS property name. */
36
+ export declare function styleKey(property: string): string;
37
+ export interface Declaration {
38
+ /** As written, but for its case: lowercase unless a custom property. */
39
+ property: string;
40
+ value: string;
41
+ important: boolean;
42
+ /** The declaration's own text, for a report to quote. */
43
+ text: string;
44
+ }
45
+ export interface Style {
46
+ /** The declarations it could read, in order. */
47
+ declarations: Declaration[];
48
+ /** The text of each one it couldn't, which CSS skips too. */
49
+ skipped: string[];
50
+ }
51
+ /** A style attribute's declarations, read one at a time. */
52
+ export declare function readStyle(text: string): Style;
53
+ /**
54
+ * The declaration that applies for each property, as the cascade picks it
55
+ * inside one attribute: an `!important` one over any other, else the last.
56
+ * In the order of the declarations that apply.
57
+ */
58
+ export declare function applied(declarations: Declaration[]): Map<string, Declaration>;
59
+ /** A style attribute's text as a React style object. */
60
+ export declare function styleObject(text: string): StyleObject;
61
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../../src/sources/_shared/html/style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,MAAM,UAAU;AACpB,kDAAkD;AAChD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACnC,sEAAsE;GACpE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAqFD,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWjD;AAMD,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,KAAK;IACpB,gDAAgD;IAChD,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAoB7C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAS7E;AAED,wDAAwD;AACxD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAuBrD"}