@vernikr/size-report 2.8.7 → 2.8.8
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/package.json +2 -2
- package/src/config.js +2 -5
- package/src/git.js +23 -21
- package/src/page/table.js +5 -3
- package/src/project.js +17 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vernikr/size-report",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.8",
|
|
4
4
|
"author": "vernikr",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"report"
|
|
66
66
|
],
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@vernikr/size-report": "2.8.
|
|
68
|
+
"@vernikr/size-report": "2.8.7",
|
|
69
69
|
"c8": "10",
|
|
70
70
|
"dependency-cruiser": "17",
|
|
71
71
|
"eslint": "^9.18.0",
|
package/src/config.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
4
|
-
import { MAX_BUF, gitArgv, gitEnv } from './git.js';
|
|
3
|
+
import { gitRead } from './git.js';
|
|
5
4
|
import { advicePath, cliCommand, invocation, refuseCause } from './refusal.js';
|
|
6
5
|
import { LOCALES } from './locales.js';
|
|
7
6
|
import { METRICS, MINIFY_ENGINES } from './metrics.js';
|
|
@@ -51,9 +50,7 @@ export function argValue(args, name) {
|
|
|
51
50
|
|
|
52
51
|
export function gitRoot() {
|
|
53
52
|
try {
|
|
54
|
-
return
|
|
55
|
-
encoding: 'utf8', maxBuffer: MAX_BUF, env: gitEnv()
|
|
56
|
-
}).trim();
|
|
53
|
+
return gitRead(process.cwd(), ['rev-parse', '--show-toplevel']).trim();
|
|
57
54
|
} catch (e) {
|
|
58
55
|
// Two dead ends with different fixes — "git did not start" and "there is no repository here" —
|
|
59
56
|
// are told apart by what git itself said rather than by a guess: ENOENT means the program was not
|
package/src/git.js
CHANGED
|
@@ -36,10 +36,21 @@ export function gitEnv() {
|
|
|
36
36
|
return Object.assign({}, process.env, { LC_ALL: 'C', LANG: 'C' });
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/* How git is started here: the options that make a read the same on any machine, written once. A caller
|
|
40
|
+
* adds what only it needs — `input` for a batch, `encoding: undefined` where the answer is the bytes of a
|
|
41
|
+
* blob rather than text, an environment on top of the boundary's own (the hook builds its commit in a
|
|
42
|
+
* separate index with it). */
|
|
43
|
+
function gitOptions(root, extra) {
|
|
44
|
+
return Object.assign({ cwd: root, encoding: 'utf8', maxBuffer: MAX_BUF, env: gitEnv() }, extra || {});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* A read: stdout as text, and an exception where git did not answer. */
|
|
48
|
+
export function gitRead(root, args, extra) {
|
|
49
|
+
return execFileSync('git', gitArgv(args), gitOptions(root, extra));
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
export function git(root, args) {
|
|
40
|
-
return
|
|
41
|
-
cwd: root, encoding: 'utf8', maxBuffer: MAX_BUF, env: gitEnv()
|
|
42
|
-
});
|
|
53
|
+
return gitRead(root, args);
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
/* The same read, but with the exit code: where a non-zero code is an expected answer rather than
|
|
@@ -48,10 +59,7 @@ export function git(root, args) {
|
|
|
48
59
|
* environment — the hook builds the report commit in a separate index with it, leaving the real
|
|
49
60
|
* one untouched (`src/hook.js`). */
|
|
50
61
|
export function gitTry(root, args, env) {
|
|
51
|
-
const res = spawnSync('git', gitArgv(args), {
|
|
52
|
-
cwd: root, encoding: 'utf8', maxBuffer: MAX_BUF,
|
|
53
|
-
env: Object.assign(gitEnv(), env || {})
|
|
54
|
-
});
|
|
62
|
+
const res = spawnSync('git', gitArgv(args), gitOptions(root, { env: Object.assign(gitEnv(), env || {}) }));
|
|
55
63
|
return { status: res.status, stdout: res.stdout || '', stderr: res.stderr || '' };
|
|
56
64
|
}
|
|
57
65
|
|
|
@@ -66,15 +74,14 @@ export function gitTry(root, args, env) {
|
|
|
66
74
|
const BLOB_CHUNK = 1000; // specs per batch: it bounds both stdin and memory
|
|
67
75
|
|
|
68
76
|
function catFileCheck(root, specs) {
|
|
69
|
-
const out =
|
|
70
|
-
|
|
71
|
-
});
|
|
77
|
+
const out = gitRead(root, ['cat-file', '--batch-check=%(objectname) %(objecttype) %(objectsize)'],
|
|
78
|
+
{ input: specs.join('\n') + '\n' });
|
|
72
79
|
return out.split('\n');
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
function catFileBatch(root, shas) {
|
|
76
|
-
const buf =
|
|
77
|
-
|
|
83
|
+
const buf = gitRead(root, ['cat-file', '--batch'], {
|
|
84
|
+
input: shas.join('\n') + '\n', encoding: undefined
|
|
78
85
|
});
|
|
79
86
|
const out = new Map();
|
|
80
87
|
let i = 0;
|
|
@@ -124,9 +131,7 @@ export function readBlobs(root, specs, needText) {
|
|
|
124
131
|
* the output is split by NUL (`-z`), or paths with spaces would have to be unquoted. */
|
|
125
132
|
export function headTree(root) {
|
|
126
133
|
const out = new Map();
|
|
127
|
-
const tree =
|
|
128
|
-
cwd: root, encoding: 'utf8', maxBuffer: MAX_BUF, env: gitEnv()
|
|
129
|
-
});
|
|
134
|
+
const tree = gitRead(root, ['ls-tree', '-r', '-z', 'HEAD']);
|
|
130
135
|
tree.split('\u0000').forEach((rec) => {
|
|
131
136
|
const tab = rec.indexOf('\t');
|
|
132
137
|
if (tab < 0) return;
|
|
@@ -142,9 +147,8 @@ export function headTree(root) {
|
|
|
142
147
|
* the answers are positional, as with `cat-file`. */
|
|
143
148
|
export function diskHashes(root, paths) {
|
|
144
149
|
const out = new Map();
|
|
145
|
-
const lines =
|
|
146
|
-
|
|
147
|
-
}).split('\n');
|
|
150
|
+
const lines = gitRead(root, ['hash-object', '--stdin-paths'],
|
|
151
|
+
{ input: paths.join('\n') + '\n' }).split('\n');
|
|
148
152
|
paths.forEach((p, i) => { out.set(p, lines[i] === undefined ? '' : lines[i].trim()); });
|
|
149
153
|
return out;
|
|
150
154
|
}
|
|
@@ -155,9 +159,7 @@ export function diskHashes(root, paths) {
|
|
|
155
159
|
* while "cleaning" would turn it back into LF — git warns about such files and puts exactly this
|
|
156
160
|
* on disk. */
|
|
157
161
|
export function diskForm(root, rev, p) {
|
|
158
|
-
return
|
|
159
|
-
cwd: root, maxBuffer: MAX_BUF, env: gitEnv()
|
|
160
|
-
});
|
|
162
|
+
return gitRead(root, ['cat-file', '--filters', rev + ':' + p], { encoding: undefined });
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
// The content of a file in a revision, or null when the file is not there.
|
package/src/page/table.js
CHANGED
|
@@ -332,9 +332,11 @@ export function appWindow(cache, redraw) {
|
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
334
|
appHead(cache, span);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
/* Walking the map itself rather than a copy of its keys: a step down the table does not allocate,
|
|
336
|
+
* and the entry the window keeps is taken where it is rather than looked up a second time. */
|
|
337
|
+
cache.rows.forEach((entry, r) => {
|
|
338
|
+
if (r >= span.r0 && r <= span.r1) { appCells(entry, cache, span); return; }
|
|
339
|
+
entry.el.remove();
|
|
338
340
|
cache.rows.delete(r);
|
|
339
341
|
});
|
|
340
342
|
for (let r = span.r0; r <= span.r1; r++) {
|
package/src/project.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
4
|
-
import { MAX_BUF, git, gitArgv, gitEnv, gitTry, readHistory } from './git.js';
|
|
3
|
+
import { git, gitRead, gitTry, readHistory } from './git.js';
|
|
5
4
|
import { cliCommand, invocation } from './refusal.js';
|
|
6
5
|
|
|
7
6
|
/* Settings derived from the project itself: what to measure, where the journal is, where to write,
|
|
@@ -41,21 +40,24 @@ const JOURNALS = ['WORKLOG.md', 'CHANGELOG.md', 'CHANGES.md', 'HISTORY.md'];
|
|
|
41
40
|
const MAX_BYTES = 512 * 1024;
|
|
42
41
|
|
|
43
42
|
/* The index gives paths and sizes: `ls-files -s` yields the objects, and their sizes are asked for in
|
|
44
|
-
* one batch (`cat-file --batch-check`) rather than by reading the content.
|
|
43
|
+
* one batch (`cat-file --batch-check`) rather than by reading the content. One call per run: the tree
|
|
44
|
+
* is asked for once and the answer is handed to whoever needs it (`allPaths`, `projectConfig`). */
|
|
45
45
|
function indexFiles(root) {
|
|
46
46
|
const listed = git(root, ['ls-files', '-s']).split('\n').filter((l) => l !== '');
|
|
47
47
|
const sizes = new Map();
|
|
48
48
|
const shas = listed.map((l) => l.split(/\s+/)[1]);
|
|
49
49
|
if (shas.length > 0) {
|
|
50
|
-
const checked =
|
|
51
|
-
|
|
52
|
-
});
|
|
50
|
+
const checked = gitRead(root, ['cat-file', '--batch-check=%(objectname)\t%(objectsize)'],
|
|
51
|
+
{ input: shas.join('\n') + '\n' });
|
|
53
52
|
checked.split('\n').forEach((l) => {
|
|
54
53
|
const [sha, size] = l.split('\t');
|
|
55
54
|
sizes.set(sha, Number(size));
|
|
56
55
|
});
|
|
57
56
|
}
|
|
58
|
-
return listed.map((line) =>
|
|
57
|
+
return listed.map((line) => {
|
|
58
|
+
const [meta, p] = line.split('\t');
|
|
59
|
+
return { p: p, size: sizes.get(meta.split(' ')[1]) || 0 };
|
|
60
|
+
});
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
/* The history is the union of the paths of every commit, read the same way coverage reads it
|
|
@@ -76,9 +78,10 @@ function historyPaths(root) {
|
|
|
76
78
|
return seen;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
// The tree and the history in one list: everything the history touched may become a column.
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
// The tree and the history in one list: everything the history touched may become a column. The index
|
|
82
|
+
// comes from outside rather than being read here, so that one run asks git for it once.
|
|
83
|
+
function allPaths(root, index) {
|
|
84
|
+
const files = index.slice();
|
|
82
85
|
const known = new Set(files.map((f) => f.p));
|
|
83
86
|
historyPaths(root).forEach((p) => {
|
|
84
87
|
if (!known.has(p)) files.push({ p: p, size: 0 });
|
|
@@ -206,11 +209,12 @@ function columnsOf(files, journal) {
|
|
|
206
209
|
export function projectConfig(root) {
|
|
207
210
|
const output = outputOf();
|
|
208
211
|
const journal = journalOf(root);
|
|
209
|
-
const
|
|
212
|
+
const index = indexFiles(root);
|
|
210
213
|
/* Only what git tracks becomes a column: a file absent at HEAD has nothing to measure (it would be
|
|
211
214
|
* empty in every row of the report). A path living only in the history is therefore an exception
|
|
212
215
|
* rather than a column, while the list of paths stays complete either way. */
|
|
213
|
-
const tracked = new Set(
|
|
216
|
+
const tracked = new Set(index.map((f) => f.p));
|
|
217
|
+
const files = allPaths(root, index);
|
|
214
218
|
const readable = files.filter((f) => tracked.has(f.p) && !generated(f.p, output) && f.size <= MAX_BYTES);
|
|
215
219
|
const columns = columnsOf(readable, journal);
|
|
216
220
|
const taken = new Set(columns.reduce((all, c) => all.concat(c.paths), []));
|
|
@@ -272,7 +276,7 @@ export function projectTree(root, output, measured) {
|
|
|
272
276
|
* (`test/api.test.js` holds the list of names), and the shape of the answer is the same — columns,
|
|
273
277
|
* the extensions the project knows, and how many paths there are in total. */
|
|
274
278
|
export function sniffColumns(root) {
|
|
275
|
-
const files = allPaths(root);
|
|
279
|
+
const files = allPaths(root, indexFiles(root));
|
|
276
280
|
const exts = [...new Set(files.map((f) => path.extname(f.p).toLowerCase()))]
|
|
277
281
|
.filter((e) => KNOWN_EXTS.indexOf(e) >= 0).sort();
|
|
278
282
|
return { columns: projectConfig(root).columns, exts: exts, total: files.length };
|