@describe-me/core 0.5.0-next.0 → 0.5.0-next.1
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.
- package/README.md +2 -1
- package/dist/css-references.d.ts +17 -0
- package/dist/css-references.js +129 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +9 -3
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -32,7 +32,8 @@ The manifest types live in `@describe-me/core/types`, for tools that want to
|
|
|
32
32
|
read `.describe-me/manifest.json` themselves. Stored snapshots point into
|
|
33
33
|
`assets/` and `styles/` through `ASSET_URL_PREFIX` and `STYLE_URL_PREFIX`
|
|
34
34
|
([Output directory](https://github.com/grzehub/describe-me#output-directory) in
|
|
35
|
-
the root README).
|
|
35
|
+
the root README). `@describe-me/core/css-references` lists the `url()` and
|
|
36
|
+
`@import` references in CSS text.
|
|
36
37
|
|
|
37
38
|
See the [root README](https://github.com/grzehub/describe-me#readme) for the
|
|
38
39
|
full picture.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** A `url()` or `@import` target in CSS text. */
|
|
2
|
+
export interface CssReference {
|
|
3
|
+
/** The URL as written, without quotes or surrounding whitespace. */
|
|
4
|
+
url: string;
|
|
5
|
+
/** Offset of the URL's first character in the scanned text. */
|
|
6
|
+
start: number;
|
|
7
|
+
/** Offset just past the URL's last character. */
|
|
8
|
+
end: number;
|
|
9
|
+
/** `import` for an `@import` target, written as a string or as `url()`. */
|
|
10
|
+
kind: 'url' | 'import';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Every `url()` and `@import` target in CSS text, in source order, remote,
|
|
14
|
+
* `data:` and `#fragment` URLs included. Comments and other strings are
|
|
15
|
+
* skipped, so `content: "url(x)"` yields nothing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function cssReferences(cssText: string): CssReference[];
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** Where a scan step can start: a comment, a string, an escape, `@import` or `url(`. */
|
|
2
|
+
const TOKEN = /\/\*|["'\\]|@import|url\(/gi;
|
|
3
|
+
const NAME_CHARACTER = /[\w\u0080-\uffff-]/;
|
|
4
|
+
const WHITESPACE = /\s/;
|
|
5
|
+
function isNameCharacter(char) {
|
|
6
|
+
return char !== undefined && NAME_CHARACTER.test(char);
|
|
7
|
+
}
|
|
8
|
+
function isQuote(char) {
|
|
9
|
+
return char === '"' || char === "'";
|
|
10
|
+
}
|
|
11
|
+
/** The offset of the quote that closes the string opening at `open`. A newline ends a broken string. */
|
|
12
|
+
function closingQuote(css, open) {
|
|
13
|
+
let index = open + 1;
|
|
14
|
+
while (index < css.length) {
|
|
15
|
+
const char = css[index];
|
|
16
|
+
if (char === '\\') {
|
|
17
|
+
index += 2;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (char === css[open] || char === '\n') {
|
|
21
|
+
return index;
|
|
22
|
+
}
|
|
23
|
+
index++;
|
|
24
|
+
}
|
|
25
|
+
return css.length;
|
|
26
|
+
}
|
|
27
|
+
/** The offset just past the comment opening at `open`. */
|
|
28
|
+
function commentEnd(css, open) {
|
|
29
|
+
const close = css.indexOf('*/', open + 2);
|
|
30
|
+
return close === -1 ? css.length : close + 2;
|
|
31
|
+
}
|
|
32
|
+
function skipWhitespaceAndComments(css, start) {
|
|
33
|
+
let index = start;
|
|
34
|
+
while (index < css.length) {
|
|
35
|
+
if (WHITESPACE.test(css[index])) {
|
|
36
|
+
index++;
|
|
37
|
+
}
|
|
38
|
+
else if (css.startsWith('/*', index)) {
|
|
39
|
+
index = commentEnd(css, index);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return index;
|
|
46
|
+
}
|
|
47
|
+
/** `url(` at `index` as a function of its own, not the tail of a longer name such as `my-url(`. */
|
|
48
|
+
function isUrlFunction(css, index) {
|
|
49
|
+
return css.slice(index, index + 4).toLowerCase() === 'url(' && !isNameCharacter(css[index - 1]);
|
|
50
|
+
}
|
|
51
|
+
function referenceOf(css, start, end, kind) {
|
|
52
|
+
if (end <= start) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return { url: css.slice(start, end), start, end, kind };
|
|
56
|
+
}
|
|
57
|
+
/** The quoted string opening at `open`, as a reference. */
|
|
58
|
+
function scanString(css, open, kind) {
|
|
59
|
+
const close = closingQuote(css, open);
|
|
60
|
+
return { reference: referenceOf(css, open + 1, close, kind), next: close + 1 };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The target of the `url(` starting at `index`. An unquoted URL runs until the
|
|
64
|
+
* first `)`, because a Google Fonts `css2` URL contains semicolons.
|
|
65
|
+
*/
|
|
66
|
+
function scanUrl(css, index, kind) {
|
|
67
|
+
let start = index + 'url('.length;
|
|
68
|
+
while (start < css.length && WHITESPACE.test(css[start])) {
|
|
69
|
+
start++;
|
|
70
|
+
}
|
|
71
|
+
if (isQuote(css[start])) {
|
|
72
|
+
return scanString(css, start, kind);
|
|
73
|
+
}
|
|
74
|
+
const close = css.indexOf(')', start);
|
|
75
|
+
if (close === -1) {
|
|
76
|
+
return { reference: null, next: start };
|
|
77
|
+
}
|
|
78
|
+
let end = close;
|
|
79
|
+
while (end > start && WHITESPACE.test(css[end - 1])) {
|
|
80
|
+
end--;
|
|
81
|
+
}
|
|
82
|
+
return { reference: referenceOf(css, start, end, kind), next: close + 1 };
|
|
83
|
+
}
|
|
84
|
+
/** The target of the `@import` starting at `index`: a string or a `url()`. */
|
|
85
|
+
function scanImport(css, index) {
|
|
86
|
+
const target = skipWhitespaceAndComments(css, index + '@import'.length);
|
|
87
|
+
if (isQuote(css[target])) {
|
|
88
|
+
return scanString(css, target, 'import');
|
|
89
|
+
}
|
|
90
|
+
if (isUrlFunction(css, target)) {
|
|
91
|
+
return scanUrl(css, target, 'import');
|
|
92
|
+
}
|
|
93
|
+
return { reference: null, next: target };
|
|
94
|
+
}
|
|
95
|
+
function scanToken(css, index, token) {
|
|
96
|
+
const skipped = (next) => ({ reference: null, next });
|
|
97
|
+
if (token === '/*') {
|
|
98
|
+
return skipped(commentEnd(css, index));
|
|
99
|
+
}
|
|
100
|
+
if (token === '\\') {
|
|
101
|
+
return skipped(index + 2);
|
|
102
|
+
}
|
|
103
|
+
if (isQuote(token)) {
|
|
104
|
+
return skipped(closingQuote(css, index) + 1);
|
|
105
|
+
}
|
|
106
|
+
if (token.startsWith('@')) {
|
|
107
|
+
return isNameCharacter(css[index + token.length]) ? skipped(index + 1) : scanImport(css, index);
|
|
108
|
+
}
|
|
109
|
+
return isUrlFunction(css, index) ? scanUrl(css, index, 'url') : skipped(index + 1);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Every `url()` and `@import` target in CSS text, in source order, remote,
|
|
113
|
+
* `data:` and `#fragment` URLs included. Comments and other strings are
|
|
114
|
+
* skipped, so `content: "url(x)"` yields nothing.
|
|
115
|
+
*/
|
|
116
|
+
export function cssReferences(cssText) {
|
|
117
|
+
const references = [];
|
|
118
|
+
const token = new RegExp(TOKEN);
|
|
119
|
+
let match = token.exec(cssText);
|
|
120
|
+
while (match !== null) {
|
|
121
|
+
const scanned = scanToken(cssText, match.index, match[0]);
|
|
122
|
+
if (scanned.reference) {
|
|
123
|
+
references.push(scanned.reference);
|
|
124
|
+
}
|
|
125
|
+
token.lastIndex = scanned.next;
|
|
126
|
+
match = token.exec(cssText);
|
|
127
|
+
}
|
|
128
|
+
return references;
|
|
129
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
|
+
export { cssReferences, type CssReference } from './css-references.js';
|
|
2
3
|
export { describeComponentType } from './describe-component-type.js';
|
|
3
4
|
export { elementLabel } from './element-label.js';
|
|
4
5
|
export { manifestDiagnostics } from './manifest-diagnostics.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
|
+
export { cssReferences } from './css-references.js';
|
|
2
3
|
export { describeComponentType } from './describe-component-type.js';
|
|
3
4
|
export { elementLabel } from './element-label.js';
|
|
4
5
|
export { manifestDiagnostics } from './manifest-diagnostics.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -136,11 +136,17 @@ export interface Manifest {
|
|
|
136
136
|
/** Keyed by component name, as reported by the framework adapter. */
|
|
137
137
|
components: Record<string, ComponentDoc>;
|
|
138
138
|
/**
|
|
139
|
-
* Asset URLs the snapshots
|
|
140
|
-
* be found in the project, as root-relative paths
|
|
139
|
+
* Asset URLs the snapshots, the preview head or copied CSS files point at
|
|
140
|
+
* that could not be found in the project, as root-relative paths
|
|
141
|
+
* (`/lib/images/logo.svg`). Paths outside the root use the `/@fs/` form.
|
|
141
142
|
* They will not load in the viewer. Absent in manifests written before 0.4.
|
|
142
143
|
*/
|
|
143
144
|
assetsMissing?: string[];
|
|
145
|
+
/**
|
|
146
|
+
* The preview head HTML, with project files as `describe-me-asset:` URLs.
|
|
147
|
+
* Absent when `previewHead` is not set.
|
|
148
|
+
*/
|
|
149
|
+
head?: string;
|
|
144
150
|
}
|
|
145
151
|
/** The name adapters fall back to when a component has no usable name. */
|
|
146
152
|
export declare const ANONYMOUS_COMPONENT: "Anonymous";
|
|
@@ -156,6 +162,6 @@ export interface ManifestDiagnostics {
|
|
|
156
162
|
name: string;
|
|
157
163
|
tests: number;
|
|
158
164
|
}[];
|
|
159
|
-
/**
|
|
165
|
+
/** Asset paths that will not load in the viewer, root-relative or in the `/@fs/` form. */
|
|
160
166
|
assetsMissing: string[];
|
|
161
167
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@describe-me/core",
|
|
3
|
-
"version": "0.5.0-next.
|
|
3
|
+
"version": "0.5.0-next.1",
|
|
4
4
|
"description": "Recorder and manifest types for describe-me: living component docs from your tests",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vitest",
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
"./diagnostics": {
|
|
39
39
|
"types": "./dist/manifest-diagnostics.d.ts",
|
|
40
40
|
"default": "./dist/manifest-diagnostics.js"
|
|
41
|
+
},
|
|
42
|
+
"./css-references": {
|
|
43
|
+
"types": "./dist/css-references.d.ts",
|
|
44
|
+
"default": "./dist/css-references.js"
|
|
41
45
|
}
|
|
42
46
|
},
|
|
43
47
|
"files": [
|