@bamboocss/reporter 1.11.1 → 1.11.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.
- package/dist/index.cjs +596 -0
- package/dist/index.d.cts +85 -0
- package/dist/index.d.mts +85 -0
- package/dist/index.mjs +550 -426
- package/package.json +13 -13
- package/dist/index.js +0 -485
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/reporter",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Track and report usage of tokens and recipes",
|
|
5
5
|
"homepage": "https://bamboo-css.com",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Segun Adebayo <joseshegs@gmail.com>",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/
|
|
10
|
+
"url": "git+https://github.com/bamboocss/bamboo.git",
|
|
11
11
|
"directory": "packages/reporter"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist"
|
|
15
15
|
],
|
|
16
16
|
"sideEffects": false,
|
|
17
|
-
"main": "dist/index.
|
|
17
|
+
"main": "dist/index.cjs",
|
|
18
18
|
"module": "dist/index.mjs",
|
|
19
|
-
"types": "dist/index.d.
|
|
19
|
+
"types": "dist/index.d.cts",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
22
|
"source": "./src/index.ts",
|
|
23
|
-
"types": "./dist/index.d.
|
|
24
|
-
"require": "./dist/index.
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"require": "./dist/index.cjs",
|
|
25
25
|
"import": {
|
|
26
26
|
"types": "./dist/index.d.mts",
|
|
27
27
|
"default": "./dist/index.mjs"
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"table": "6.9.0",
|
|
37
37
|
"wordwrapjs": "5.1.1",
|
|
38
|
-
"@bamboocss/core": "1.11.
|
|
39
|
-
"@bamboocss/
|
|
40
|
-
"@bamboocss/
|
|
41
|
-
"@bamboocss/shared": "1.11.
|
|
42
|
-
"@bamboocss/types": "1.11.
|
|
38
|
+
"@bamboocss/core": "1.11.2",
|
|
39
|
+
"@bamboocss/logger": "1.11.2",
|
|
40
|
+
"@bamboocss/generator": "1.11.2",
|
|
41
|
+
"@bamboocss/shared": "1.11.2",
|
|
42
|
+
"@bamboocss/types": "1.11.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"markdown-table": "3.0.4"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
|
-
"build": "
|
|
49
|
-
"build-fast": "
|
|
48
|
+
"build": "tsdown src/index.ts --format=esm,cjs --dts",
|
|
49
|
+
"build-fast": "tsdown --dts=false src/index.ts --format=esm,cjs",
|
|
50
50
|
"dev": "pnpm build-fast --watch"
|
|
51
51
|
}
|
|
52
52
|
}
|
package/dist/index.js
DELETED
|
@@ -1,485 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
Reporter: () => Reporter,
|
|
34
|
-
formatRecipeReport: () => formatRecipeReport,
|
|
35
|
-
formatTokenReport: () => formatTokenReport
|
|
36
|
-
});
|
|
37
|
-
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
|
|
39
|
-
// ../../node_modules/.pnpm/markdown-table@3.0.4/node_modules/markdown-table/index.js
|
|
40
|
-
function defaultStringLength(value) {
|
|
41
|
-
return value.length;
|
|
42
|
-
}
|
|
43
|
-
function markdownTable(table2, options) {
|
|
44
|
-
const settings = options || {};
|
|
45
|
-
const align = (settings.align || []).concat();
|
|
46
|
-
const stringLength = settings.stringLength || defaultStringLength;
|
|
47
|
-
const alignments = [];
|
|
48
|
-
const cellMatrix = [];
|
|
49
|
-
const sizeMatrix = [];
|
|
50
|
-
const longestCellByColumn = [];
|
|
51
|
-
let mostCellsPerRow = 0;
|
|
52
|
-
let rowIndex = -1;
|
|
53
|
-
while (++rowIndex < table2.length) {
|
|
54
|
-
const row2 = [];
|
|
55
|
-
const sizes2 = [];
|
|
56
|
-
let columnIndex2 = -1;
|
|
57
|
-
if (table2[rowIndex].length > mostCellsPerRow) {
|
|
58
|
-
mostCellsPerRow = table2[rowIndex].length;
|
|
59
|
-
}
|
|
60
|
-
while (++columnIndex2 < table2[rowIndex].length) {
|
|
61
|
-
const cell = serialize(table2[rowIndex][columnIndex2]);
|
|
62
|
-
if (settings.alignDelimiters !== false) {
|
|
63
|
-
const size = stringLength(cell);
|
|
64
|
-
sizes2[columnIndex2] = size;
|
|
65
|
-
if (longestCellByColumn[columnIndex2] === void 0 || size > longestCellByColumn[columnIndex2]) {
|
|
66
|
-
longestCellByColumn[columnIndex2] = size;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
row2.push(cell);
|
|
70
|
-
}
|
|
71
|
-
cellMatrix[rowIndex] = row2;
|
|
72
|
-
sizeMatrix[rowIndex] = sizes2;
|
|
73
|
-
}
|
|
74
|
-
let columnIndex = -1;
|
|
75
|
-
if (typeof align === "object" && "length" in align) {
|
|
76
|
-
while (++columnIndex < mostCellsPerRow) {
|
|
77
|
-
alignments[columnIndex] = toAlignment(align[columnIndex]);
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
const code = toAlignment(align);
|
|
81
|
-
while (++columnIndex < mostCellsPerRow) {
|
|
82
|
-
alignments[columnIndex] = code;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
columnIndex = -1;
|
|
86
|
-
const row = [];
|
|
87
|
-
const sizes = [];
|
|
88
|
-
while (++columnIndex < mostCellsPerRow) {
|
|
89
|
-
const code = alignments[columnIndex];
|
|
90
|
-
let before = "";
|
|
91
|
-
let after = "";
|
|
92
|
-
if (code === 99) {
|
|
93
|
-
before = ":";
|
|
94
|
-
after = ":";
|
|
95
|
-
} else if (code === 108) {
|
|
96
|
-
before = ":";
|
|
97
|
-
} else if (code === 114) {
|
|
98
|
-
after = ":";
|
|
99
|
-
}
|
|
100
|
-
let size = settings.alignDelimiters === false ? 1 : Math.max(
|
|
101
|
-
1,
|
|
102
|
-
longestCellByColumn[columnIndex] - before.length - after.length
|
|
103
|
-
);
|
|
104
|
-
const cell = before + "-".repeat(size) + after;
|
|
105
|
-
if (settings.alignDelimiters !== false) {
|
|
106
|
-
size = before.length + size + after.length;
|
|
107
|
-
if (size > longestCellByColumn[columnIndex]) {
|
|
108
|
-
longestCellByColumn[columnIndex] = size;
|
|
109
|
-
}
|
|
110
|
-
sizes[columnIndex] = size;
|
|
111
|
-
}
|
|
112
|
-
row[columnIndex] = cell;
|
|
113
|
-
}
|
|
114
|
-
cellMatrix.splice(1, 0, row);
|
|
115
|
-
sizeMatrix.splice(1, 0, sizes);
|
|
116
|
-
rowIndex = -1;
|
|
117
|
-
const lines = [];
|
|
118
|
-
while (++rowIndex < cellMatrix.length) {
|
|
119
|
-
const row2 = cellMatrix[rowIndex];
|
|
120
|
-
const sizes2 = sizeMatrix[rowIndex];
|
|
121
|
-
columnIndex = -1;
|
|
122
|
-
const line = [];
|
|
123
|
-
while (++columnIndex < mostCellsPerRow) {
|
|
124
|
-
const cell = row2[columnIndex] || "";
|
|
125
|
-
let before = "";
|
|
126
|
-
let after = "";
|
|
127
|
-
if (settings.alignDelimiters !== false) {
|
|
128
|
-
const size = longestCellByColumn[columnIndex] - (sizes2[columnIndex] || 0);
|
|
129
|
-
const code = alignments[columnIndex];
|
|
130
|
-
if (code === 114) {
|
|
131
|
-
before = " ".repeat(size);
|
|
132
|
-
} else if (code === 99) {
|
|
133
|
-
if (size % 2) {
|
|
134
|
-
before = " ".repeat(size / 2 + 0.5);
|
|
135
|
-
after = " ".repeat(size / 2 - 0.5);
|
|
136
|
-
} else {
|
|
137
|
-
before = " ".repeat(size / 2);
|
|
138
|
-
after = before;
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
after = " ".repeat(size);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (settings.delimiterStart !== false && !columnIndex) {
|
|
145
|
-
line.push("|");
|
|
146
|
-
}
|
|
147
|
-
if (settings.padding !== false && // Don’t add the opening space if we’re not aligning and the cell is
|
|
148
|
-
// empty: there will be a closing space.
|
|
149
|
-
!(settings.alignDelimiters === false && cell === "") && (settings.delimiterStart !== false || columnIndex)) {
|
|
150
|
-
line.push(" ");
|
|
151
|
-
}
|
|
152
|
-
if (settings.alignDelimiters !== false) {
|
|
153
|
-
line.push(before);
|
|
154
|
-
}
|
|
155
|
-
line.push(cell);
|
|
156
|
-
if (settings.alignDelimiters !== false) {
|
|
157
|
-
line.push(after);
|
|
158
|
-
}
|
|
159
|
-
if (settings.padding !== false) {
|
|
160
|
-
line.push(" ");
|
|
161
|
-
}
|
|
162
|
-
if (settings.delimiterEnd !== false || columnIndex !== mostCellsPerRow - 1) {
|
|
163
|
-
line.push("|");
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
lines.push(
|
|
167
|
-
settings.delimiterEnd === false ? line.join("").replace(/ +$/, "") : line.join("")
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
return lines.join("\n");
|
|
171
|
-
}
|
|
172
|
-
function serialize(value) {
|
|
173
|
-
return value === null || value === void 0 ? "" : String(value);
|
|
174
|
-
}
|
|
175
|
-
function toAlignment(value) {
|
|
176
|
-
const code = typeof value === "string" ? value.codePointAt(0) : 0;
|
|
177
|
-
return code === 67 || code === 99 ? 99 : code === 76 || code === 108 ? 108 : code === 82 || code === 114 ? 114 : 0;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// src/report-format.ts
|
|
181
|
-
var import_table = require("table");
|
|
182
|
-
var import_wordwrapjs = __toESM(require("wordwrapjs"));
|
|
183
|
-
var plural = (count, singular) => {
|
|
184
|
-
const pr = new Intl.PluralRules("en-US").select(count);
|
|
185
|
-
const plural2 = pr === "one" || count === 0 ? singular : `${singular}s`;
|
|
186
|
-
return `${count} ${plural2}`;
|
|
187
|
-
};
|
|
188
|
-
var createWrapFn = (enabled) => (str) => enabled ? import_wordwrapjs.default.wrap(str, { width: 20 }) : str;
|
|
189
|
-
function formatTokenReport(result, format) {
|
|
190
|
-
const headers = ["Token", "Usage %", "Most used", "Hardcoded", "Found in"];
|
|
191
|
-
function getFormatted(entry, wrap) {
|
|
192
|
-
const wrapFn = createWrapFn(wrap);
|
|
193
|
-
return [
|
|
194
|
-
`${entry.category} (${plural(entry.count, "token")})`,
|
|
195
|
-
`${entry.percentUsed}% (${plural(entry.usedCount, "token")})`,
|
|
196
|
-
wrapFn(entry.mostUsedNames.join(", ")),
|
|
197
|
-
entry.hardcoded.toString(),
|
|
198
|
-
`${plural(entry.usedInXFiles, "file")}`
|
|
199
|
-
];
|
|
200
|
-
}
|
|
201
|
-
switch (format) {
|
|
202
|
-
case "json":
|
|
203
|
-
return JSON.stringify(result, null, 2);
|
|
204
|
-
case "markdown": {
|
|
205
|
-
return markdownTable([headers, ...result.map((entry) => getFormatted(entry, true))]);
|
|
206
|
-
}
|
|
207
|
-
case "csv": {
|
|
208
|
-
return [headers.join(","), ...result.map((entry) => getFormatted(entry, false).join(","))].join("\n");
|
|
209
|
-
}
|
|
210
|
-
case "table": {
|
|
211
|
-
return (0, import_table.table)([headers, ...result.map((entry) => getFormatted(entry, true))]);
|
|
212
|
-
}
|
|
213
|
-
case "text":
|
|
214
|
-
default: {
|
|
215
|
-
const formatted = result.map((entry) => getFormatted(entry, false));
|
|
216
|
-
return headers.map((header, index) => `${header}: ${formatted[index]}`).join("\n");
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
function formatRecipeReport(result, format) {
|
|
221
|
-
function getFormatted(entry, wrap) {
|
|
222
|
-
const wrapFn = createWrapFn(wrap);
|
|
223
|
-
return [
|
|
224
|
-
`${entry.recipeName} (${plural(entry.variantCount, "variant")})`,
|
|
225
|
-
`${plural(entry.possibleCombinations.length, "value")}`,
|
|
226
|
-
`${entry.percentUsed}% (${plural(entry.usedCombinations, "value")})`,
|
|
227
|
-
wrapFn(entry.mostUsedCombinations.join(", ")),
|
|
228
|
-
`${plural(entry.usedInXFiles, "file")}`,
|
|
229
|
-
`jsx: ${entry.jsxPercentUsed}%
|
|
230
|
-
fn: ${entry.fnPercentUsed}%`
|
|
231
|
-
];
|
|
232
|
-
}
|
|
233
|
-
const headers = ["Recipe", "Variant values", "Usage %", "Most used", "Found in", "Used as"];
|
|
234
|
-
switch (format) {
|
|
235
|
-
case "json": {
|
|
236
|
-
return JSON.stringify(result, null, 2);
|
|
237
|
-
}
|
|
238
|
-
case "markdown": {
|
|
239
|
-
return (0, import_table.table)([headers, ...result.map((entry) => getFormatted(entry, true))]);
|
|
240
|
-
}
|
|
241
|
-
case "csv": {
|
|
242
|
-
return [headers.join(","), ...result.map((entry) => getFormatted(entry, false).join(","))].join("\n");
|
|
243
|
-
}
|
|
244
|
-
case "table": {
|
|
245
|
-
return (0, import_table.table)([headers, ...result.map((entry) => getFormatted(entry, true))]);
|
|
246
|
-
}
|
|
247
|
-
case "text":
|
|
248
|
-
default: {
|
|
249
|
-
const formatted = result.map((entry) => getFormatted(entry, false));
|
|
250
|
-
return headers.map((header, index) => `${header}: ${formatted[index]}`).join("\n");
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// src/reporter.ts
|
|
256
|
-
var import_logger = require("@bamboocss/logger");
|
|
257
|
-
|
|
258
|
-
// package.json
|
|
259
|
-
var version = "1.11.1";
|
|
260
|
-
|
|
261
|
-
// src/reporter-recipe.ts
|
|
262
|
-
function analyzeRecipes(ctx, result) {
|
|
263
|
-
const recipesReportItems = Array.from(result.componentByIndex.values()).filter(
|
|
264
|
-
(reportItem) => reportItem.reportItemType === "recipe" || reportItem.reportItemType === "jsx-recipe"
|
|
265
|
-
);
|
|
266
|
-
const recipeReportMap = /* @__PURE__ */ new Map();
|
|
267
|
-
recipesReportItems.forEach((reportItem) => {
|
|
268
|
-
const recipeOrComponentName = reportItem.componentName;
|
|
269
|
-
const recipe = ctx.recipes.details.find(
|
|
270
|
-
(node) => node.match.test(recipeOrComponentName) || node.baseName === recipeOrComponentName
|
|
271
|
-
);
|
|
272
|
-
if (!recipe) return;
|
|
273
|
-
const recipeName = recipe?.baseName;
|
|
274
|
-
if (!recipeReportMap.has(recipeName)) {
|
|
275
|
-
recipeReportMap.set(recipeName, /* @__PURE__ */ new Set());
|
|
276
|
-
}
|
|
277
|
-
recipeReportMap.get(recipeName).add(reportItem);
|
|
278
|
-
});
|
|
279
|
-
const reportMap = Array.from(recipeReportMap.entries());
|
|
280
|
-
const normalizedReportMap = reportMap.map(
|
|
281
|
-
([recipeName, reportItems]) => [recipeName, Array.from(reportItems)]
|
|
282
|
-
);
|
|
283
|
-
return normalizedReportMap.map(([recipeName, reportItems]) => {
|
|
284
|
-
const usedCombinations = reportItems.map(
|
|
285
|
-
(component) => component.contains.map((id) => {
|
|
286
|
-
const reportItem = result.propByIndex.get(id);
|
|
287
|
-
const recipe2 = ctx.recipes.getRecipe(recipeName);
|
|
288
|
-
if (!recipe2?.variantKeys.includes(reportItem.propName)) return;
|
|
289
|
-
return reportItem.propName + "." + reportItem.value;
|
|
290
|
-
}).filter(Boolean)
|
|
291
|
-
).flat();
|
|
292
|
-
const distinctUsedCombinations = Array.from(new Set(usedCombinations)).sort();
|
|
293
|
-
const usedCount = reportItems.length;
|
|
294
|
-
const recipe = ctx.recipes.getRecipe(recipeName);
|
|
295
|
-
const variantMap = recipe.variantKeyMap ?? {};
|
|
296
|
-
const possibleCombinations = Object.keys(variantMap).reduce((acc, variantName) => {
|
|
297
|
-
return acc.concat(variantMap[variantName].map((value) => `${variantName}.${value}`));
|
|
298
|
-
}, []);
|
|
299
|
-
const variantCount = recipe.variantKeys.length;
|
|
300
|
-
const percentUsed = Math.ceil(distinctUsedCombinations.length / (possibleCombinations.length || 1) * 1e4) / 100;
|
|
301
|
-
const jsxUsage = reportItems.filter((component) => component.reportItemType === "jsx-recipe");
|
|
302
|
-
const fnUsage = reportItems.filter((component) => component.reportItemType === "recipe");
|
|
303
|
-
const jsxPercentUsed = Math.ceil(jsxUsage.length / (reportItems.length || 1) * 100);
|
|
304
|
-
const fnPercentUsed = Math.ceil(fnUsage.length / (reportItems.length || 1) * 100);
|
|
305
|
-
const usedInXFiles = new Set(reportItems.flatMap((component) => component.filepath)).size;
|
|
306
|
-
return {
|
|
307
|
-
recipeName,
|
|
308
|
-
usedInXFiles,
|
|
309
|
-
usedCount,
|
|
310
|
-
variantCount,
|
|
311
|
-
possibleCombinations,
|
|
312
|
-
usedCombinations: distinctUsedCombinations.length,
|
|
313
|
-
percentUsed,
|
|
314
|
-
jsxPercentUsed,
|
|
315
|
-
fnPercentUsed,
|
|
316
|
-
unusedCombinations: possibleCombinations.length - distinctUsedCombinations.length,
|
|
317
|
-
mostUsedCombinations: distinctUsedCombinations.slice(0, 5)
|
|
318
|
-
};
|
|
319
|
-
}).sort((a, b) => b.percentUsed - a.percentUsed);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// src/reporter-token.ts
|
|
323
|
-
var import_shared = require("@bamboocss/shared");
|
|
324
|
-
var formatter = new Intl.NumberFormat("en-US", {
|
|
325
|
-
maximumFractionDigits: 2,
|
|
326
|
-
minimumFractionDigits: 2
|
|
327
|
-
});
|
|
328
|
-
var getPercent = (used, total) => {
|
|
329
|
-
return Number(formatter.format(used / (total || 1) * 100));
|
|
330
|
-
};
|
|
331
|
-
function analyzeTokens(ctx, result) {
|
|
332
|
-
const categoryMap = result.derived.globalMaps.byTokenType;
|
|
333
|
-
const categoryEntries = Array.from(categoryMap.entries());
|
|
334
|
-
const usageMap = /* @__PURE__ */ new Map();
|
|
335
|
-
const totalMap = /* @__PURE__ */ new Map();
|
|
336
|
-
categoryEntries.forEach(([category, categoryIds]) => {
|
|
337
|
-
const usage = usageMap.get(category) || usageMap.set(category, []).get(category);
|
|
338
|
-
categoryIds.forEach((id) => {
|
|
339
|
-
const item = result.propByIndex.get(id);
|
|
340
|
-
if (item?.value == null) return;
|
|
341
|
-
const type = item.isKnownValue ? "token" : "nonToken";
|
|
342
|
-
const value = item.value.toString();
|
|
343
|
-
const filePath = item.filepath;
|
|
344
|
-
const loc = item.range ? {
|
|
345
|
-
line: item.range.startLineNumber,
|
|
346
|
-
column: item.range.startColumn
|
|
347
|
-
} : null;
|
|
348
|
-
usage.push({ category, value, filePath, loc, type });
|
|
349
|
-
});
|
|
350
|
-
const totalTokens = ctx.tokens.view.categoryMap.get(category)?.size ?? 0;
|
|
351
|
-
totalMap.set(category, totalTokens);
|
|
352
|
-
});
|
|
353
|
-
const usageEntries = Array.from(usageMap.entries());
|
|
354
|
-
const percentMap = usageEntries.reduce((map, [category, usage]) => {
|
|
355
|
-
const total = totalMap.get(category) ?? 0;
|
|
356
|
-
const tokens = usage.reduce((acc, item) => {
|
|
357
|
-
return item.type === "token" ? acc.add(item.value) : acc;
|
|
358
|
-
}, /* @__PURE__ */ new Set());
|
|
359
|
-
const percent = getPercent(tokens.size, total);
|
|
360
|
-
return map.set(category, {
|
|
361
|
-
total,
|
|
362
|
-
used: tokens.size,
|
|
363
|
-
unused: total - tokens.size,
|
|
364
|
-
percent
|
|
365
|
-
});
|
|
366
|
-
}, /* @__PURE__ */ new Map());
|
|
367
|
-
const tokenNameMap = usageEntries.reduce((map, [category, usage]) => {
|
|
368
|
-
const existing = map.get(category) ?? [];
|
|
369
|
-
usage.forEach(({ value, type }) => {
|
|
370
|
-
if (type === "token") existing.push(value);
|
|
371
|
-
});
|
|
372
|
-
const sorted = (0, import_shared.uniq)(existing).sort(
|
|
373
|
-
(a, b) => (result.derived.globalMaps.byTokenName.get(b)?.size ?? 0) - (result.derived.globalMaps.byTokenName.get(a)?.size ?? 0)
|
|
374
|
-
);
|
|
375
|
-
return map.set(category, sorted);
|
|
376
|
-
}, /* @__PURE__ */ new Map());
|
|
377
|
-
const fileUsageMap = usageEntries.reduce((map, [category, usage]) => {
|
|
378
|
-
const existing = map.get(category) ?? /* @__PURE__ */ new Set();
|
|
379
|
-
usage.forEach(({ filePath }) => {
|
|
380
|
-
if (filePath.startsWith("@config")) return;
|
|
381
|
-
existing.add(filePath);
|
|
382
|
-
});
|
|
383
|
-
return map.set(category, existing);
|
|
384
|
-
}, /* @__PURE__ */ new Map());
|
|
385
|
-
const hardcodedTokenMap = usageEntries.reduce((map, [category, usage]) => {
|
|
386
|
-
const items = /* @__PURE__ */ new Set();
|
|
387
|
-
usage.forEach(({ type, value }) => {
|
|
388
|
-
if (type === "nonToken") items.add(value);
|
|
389
|
-
});
|
|
390
|
-
return map.set(category, items.size);
|
|
391
|
-
}, /* @__PURE__ */ new Map());
|
|
392
|
-
return {
|
|
393
|
-
usageMap,
|
|
394
|
-
percentMap,
|
|
395
|
-
tokenNameMap,
|
|
396
|
-
fileUsageMap,
|
|
397
|
-
hardcodedTokenMap,
|
|
398
|
-
totalMap,
|
|
399
|
-
getSummary() {
|
|
400
|
-
const summary = categoryEntries.map(([category]) => {
|
|
401
|
-
const percent = percentMap.get(category);
|
|
402
|
-
return {
|
|
403
|
-
category,
|
|
404
|
-
count: percent?.total ?? 0,
|
|
405
|
-
usedInXFiles: fileUsageMap.get(category)?.size ?? 0,
|
|
406
|
-
usedCount: percent?.used ?? 0,
|
|
407
|
-
percentUsed: percent?.percent ?? 0,
|
|
408
|
-
hardcoded: hardcodedTokenMap.get(category) ?? 0,
|
|
409
|
-
mostUsedNames: tokenNameMap.get(category)?.slice(0, 5) ?? []
|
|
410
|
-
};
|
|
411
|
-
});
|
|
412
|
-
return summary.sort((a, b) => b.percentUsed - a.percentUsed);
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// src/reporter.ts
|
|
418
|
-
var Reporter = class {
|
|
419
|
-
constructor(ctx, options) {
|
|
420
|
-
this.ctx = ctx;
|
|
421
|
-
this.options = options;
|
|
422
|
-
}
|
|
423
|
-
#parserResults = /* @__PURE__ */ new Map();
|
|
424
|
-
#extractTimes = /* @__PURE__ */ new Map();
|
|
425
|
-
#sheet;
|
|
426
|
-
#report;
|
|
427
|
-
setup = () => {
|
|
428
|
-
this.#sheet = this.ctx.createSheet();
|
|
429
|
-
this.ctx.appendLayerParams(this.#sheet);
|
|
430
|
-
this.ctx.appendBaselineCss(this.#sheet);
|
|
431
|
-
this.parseFiles();
|
|
432
|
-
this.ctx.appendParserCss(this.#sheet);
|
|
433
|
-
};
|
|
434
|
-
get report() {
|
|
435
|
-
return this.#report;
|
|
436
|
-
}
|
|
437
|
-
parseFiles = () => {
|
|
438
|
-
const { getFiles } = this.options;
|
|
439
|
-
const files = getFiles();
|
|
440
|
-
import_logger.logger.info("analyze", `Analyzing ${files.length} file(s) for token and recipe usage...`);
|
|
441
|
-
for (const file of files) {
|
|
442
|
-
this.parseFile(file);
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
parseFile = (file) => {
|
|
446
|
-
const { project, getRelativePath, onResult } = this.options;
|
|
447
|
-
const { config } = this.ctx;
|
|
448
|
-
const start = performance.now();
|
|
449
|
-
const result = project.parseSourceFile?.(file);
|
|
450
|
-
const extractMs = performance.now() - start;
|
|
451
|
-
const filePath = getRelativePath(config.cwd, file);
|
|
452
|
-
this.#extractTimes.set(filePath, extractMs);
|
|
453
|
-
import_logger.logger.debug("analyze", `Parsed ${file} in ${extractMs}ms`);
|
|
454
|
-
if (result) {
|
|
455
|
-
this.#parserResults.set(filePath, result);
|
|
456
|
-
onResult?.(file, result);
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
init = () => {
|
|
460
|
-
const { project } = this.options;
|
|
461
|
-
this.setup();
|
|
462
|
-
const classify = project.classify(this.#parserResults);
|
|
463
|
-
this.#report = {
|
|
464
|
-
schemaVersion: version,
|
|
465
|
-
details: classify.details,
|
|
466
|
-
propByIndex: classify.propById,
|
|
467
|
-
componentByIndex: classify.componentById,
|
|
468
|
-
derived: classify.derived
|
|
469
|
-
};
|
|
470
|
-
};
|
|
471
|
-
getTokenReport = () => {
|
|
472
|
-
const { project } = this.options;
|
|
473
|
-
return analyzeTokens(project.parserOptions, this.#report);
|
|
474
|
-
};
|
|
475
|
-
getRecipeReport = () => {
|
|
476
|
-
const { project } = this.options;
|
|
477
|
-
return analyzeRecipes(project.parserOptions, this.#report);
|
|
478
|
-
};
|
|
479
|
-
};
|
|
480
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
481
|
-
0 && (module.exports = {
|
|
482
|
-
Reporter,
|
|
483
|
-
formatRecipeReport,
|
|
484
|
-
formatTokenReport
|
|
485
|
-
});
|