gitnexus 1.6.3-rc.41 → 1.6.3-rc.42
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/cli/index.js
CHANGED
|
@@ -30,7 +30,9 @@ program
|
|
|
30
30
|
.option('--max-file-size <kb>', 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).')
|
|
31
31
|
.addHelpText('after', '\nEnvironment variables:\n' +
|
|
32
32
|
' GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)\n' +
|
|
33
|
-
' GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768
|
|
33
|
+
' GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n' +
|
|
34
|
+
'\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n' +
|
|
35
|
+
' `!__tests__/` to index a directory that is auto-filtered by default (#771).')
|
|
34
36
|
.action(createLazyAction(() => import('./analyze.js'), 'analyzeCommand'));
|
|
35
37
|
program
|
|
36
38
|
.command('index [path...]')
|
|
@@ -19,6 +19,15 @@ export declare const loadIgnoreRules: (repoPath: string, options?: IgnoreOptions
|
|
|
19
19
|
*
|
|
20
20
|
* Returns an IgnoreLike object for glob's `ignore` option,
|
|
21
21
|
* enabling directory-level pruning during traversal.
|
|
22
|
+
*
|
|
23
|
+
* Precedence (#771): user's `.gitnexusignore` negation patterns take
|
|
24
|
+
* priority over the hardcoded list, matching `.gitignore` semantics.
|
|
25
|
+
* An explicit `!pattern` rule unignores descendants even when they
|
|
26
|
+
* would otherwise be blocked by DEFAULT_IGNORE_LIST — UNLESS a more
|
|
27
|
+
* specific rule in the same file re-ignores a subset (e.g.
|
|
28
|
+
* `!__tests__/` paired with `__tests__/generated/` blocks the child
|
|
29
|
+
* while leaving the parent negated). Last-match-wins is enforced by
|
|
30
|
+
* consulting `ig.ignores(rel)` after `hasExplicitUnignore`.
|
|
22
31
|
*/
|
|
23
32
|
export declare const createIgnoreFilter: (repoPath: string, options?: IgnoreOptions) => Promise<{
|
|
24
33
|
ignored(p: Path): boolean;
|
|
@@ -245,16 +245,20 @@ const IGNORED_FILES = new Set([
|
|
|
245
245
|
'.env.test',
|
|
246
246
|
'.env.example',
|
|
247
247
|
]);
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
248
|
+
// The hardcoded DEFAULT_IGNORE_LIST is the "safety net" default: directories
|
|
249
|
+
// that are almost never source code (node_modules, .git, dist, __tests__,
|
|
250
|
+
// etc.). Users who legitimately need to index one of these can negate the
|
|
251
|
+
// hardcoded rule via a `!pattern` line in `.gitnexusignore` (#771) — same
|
|
252
|
+
// semantics as `.gitignore` negation. That override is applied in
|
|
253
|
+
// `createIgnoreFilter` below; `shouldIgnorePath` itself stays a pure
|
|
254
|
+
// hardcoded-list check so its callers (wiki generator, tests) get
|
|
255
|
+
// deterministic results independent of per-repo config.
|
|
252
256
|
export const shouldIgnorePath = (filePath) => {
|
|
253
257
|
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
254
258
|
const parts = normalizedPath.split('/');
|
|
255
259
|
const fileName = parts[parts.length - 1];
|
|
256
260
|
const fileNameLower = fileName.toLowerCase();
|
|
257
|
-
// Check if any path segment is in ignore list
|
|
261
|
+
// Check if any path segment is in the hardcoded ignore list.
|
|
258
262
|
for (const part of parts) {
|
|
259
263
|
if (DEFAULT_IGNORE_LIST.has(part)) {
|
|
260
264
|
return true;
|
|
@@ -320,6 +324,44 @@ export const loadIgnoreRules = async (repoPath, options) => {
|
|
|
320
324
|
}
|
|
321
325
|
return hasRules ? ig : null;
|
|
322
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* Walk ancestor segments of `rel` and check whether `.gitnexusignore`
|
|
329
|
+
* (or `.gitignore`) contains an explicit `!pattern` negation that
|
|
330
|
+
* applies. Returns true as soon as any segment — or the path itself —
|
|
331
|
+
* is matched by a negation rule.
|
|
332
|
+
*
|
|
333
|
+
* Why this exists (#771): the hardcoded DEFAULT_IGNORE_LIST would
|
|
334
|
+
* otherwise block indexing of directories like `__tests__/` even when
|
|
335
|
+
* the user has an explicit `!__tests__/` line in `.gitnexusignore`.
|
|
336
|
+
* Mirroring `.gitignore` negation semantics: a user's explicit
|
|
337
|
+
* unignore of a parent directory implicitly unignores everything
|
|
338
|
+
* underneath, so we walk the ancestor chain rather than only testing
|
|
339
|
+
* the leaf.
|
|
340
|
+
*
|
|
341
|
+
* The `ignore` package's `test(path)` returns `{ignored, unignored}`;
|
|
342
|
+
* `unignored: true` is the "a negation rule matched this path"
|
|
343
|
+
* signal. Children of a negated directory return
|
|
344
|
+
* `{ignored: false, unignored: false}` on a direct test, which is why
|
|
345
|
+
* we also walk the ancestors here.
|
|
346
|
+
*/
|
|
347
|
+
const hasExplicitUnignore = (ig, rel) => {
|
|
348
|
+
// Direct match on the path (as a file).
|
|
349
|
+
if (ig.test(rel).unignored)
|
|
350
|
+
return true;
|
|
351
|
+
// Direct match on the path treated as a directory — `!dir/` matches
|
|
352
|
+
// here when rel is the directory itself.
|
|
353
|
+
if (ig.test(rel + '/').unignored)
|
|
354
|
+
return true;
|
|
355
|
+
// Walk ancestor segments. `!parent/` should propagate to every
|
|
356
|
+
// descendant the same way `.gitignore` negation propagates.
|
|
357
|
+
const parts = rel.split('/');
|
|
358
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
359
|
+
const ancestor = parts.slice(0, i).join('/') + '/';
|
|
360
|
+
if (ig.test(ancestor).unignored)
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
};
|
|
323
365
|
/**
|
|
324
366
|
* Create a glob-compatible ignore filter combining:
|
|
325
367
|
* - .gitignore / .gitnexusignore patterns (via `ignore` package)
|
|
@@ -327,6 +369,15 @@ export const loadIgnoreRules = async (repoPath, options) => {
|
|
|
327
369
|
*
|
|
328
370
|
* Returns an IgnoreLike object for glob's `ignore` option,
|
|
329
371
|
* enabling directory-level pruning during traversal.
|
|
372
|
+
*
|
|
373
|
+
* Precedence (#771): user's `.gitnexusignore` negation patterns take
|
|
374
|
+
* priority over the hardcoded list, matching `.gitignore` semantics.
|
|
375
|
+
* An explicit `!pattern` rule unignores descendants even when they
|
|
376
|
+
* would otherwise be blocked by DEFAULT_IGNORE_LIST — UNLESS a more
|
|
377
|
+
* specific rule in the same file re-ignores a subset (e.g.
|
|
378
|
+
* `!__tests__/` paired with `__tests__/generated/` blocks the child
|
|
379
|
+
* while leaving the parent negated). Last-match-wins is enforced by
|
|
380
|
+
* consulting `ig.ignores(rel)` after `hasExplicitUnignore`.
|
|
330
381
|
*/
|
|
331
382
|
export const createIgnoreFilter = async (repoPath, options) => {
|
|
332
383
|
const ig = await loadIgnoreRules(repoPath, options);
|
|
@@ -337,6 +388,15 @@ export const createIgnoreFilter = async (repoPath, options) => {
|
|
|
337
388
|
const rel = p.relative();
|
|
338
389
|
if (!rel)
|
|
339
390
|
return false;
|
|
391
|
+
// User's .gitnexusignore negation takes precedence over hardcoded
|
|
392
|
+
// rules (#771). If any ancestor or the path itself was explicitly
|
|
393
|
+
// unignored AND no more-specific rule re-ignores this exact path,
|
|
394
|
+
// allow it through. The `!ig.ignores(rel)` guard matches
|
|
395
|
+
// .gitignore's last-match-wins semantics: `!__tests__/` followed
|
|
396
|
+
// by `__tests__/generated/` negates the parent but still blocks
|
|
397
|
+
// the re-ignored child.
|
|
398
|
+
if (ig && hasExplicitUnignore(ig, rel) && !ig.ignores(rel))
|
|
399
|
+
return false;
|
|
340
400
|
// Check .gitignore / .gitnexusignore patterns
|
|
341
401
|
if (ig && ig.ignores(rel))
|
|
342
402
|
return true;
|
|
@@ -344,10 +404,20 @@ export const createIgnoreFilter = async (repoPath, options) => {
|
|
|
344
404
|
return shouldIgnorePath(rel);
|
|
345
405
|
},
|
|
346
406
|
childrenIgnored(p) {
|
|
347
|
-
// Fast path: check directory name against hardcoded list.
|
|
348
407
|
// Note: dot-directories (.git, .vscode, etc.) are primarily excluded by
|
|
349
|
-
// glob's `dot: false` option in filesystem-walker.ts.
|
|
350
|
-
// defense-in-depth — do not remove `dot: false`
|
|
408
|
+
// glob's `dot: false` option in filesystem-walker.ts. The hardcoded
|
|
409
|
+
// list check below is defense-in-depth — do not remove `dot: false`
|
|
410
|
+
// assuming this covers it.
|
|
411
|
+
const rel = p.relative();
|
|
412
|
+
// User's .gitnexusignore negation takes precedence (#771) — if the
|
|
413
|
+
// user explicitly unignored this directory or any ancestor via a
|
|
414
|
+
// !pattern rule, allow descent even if the directory name is in
|
|
415
|
+
// DEFAULT_IGNORE_LIST. The `!ig.ignores(rel + '/')` guard keeps
|
|
416
|
+
// last-match-wins: `!__tests__/` + `__tests__/generated/` still
|
|
417
|
+
// blocks descent into `__tests__/generated/`.
|
|
418
|
+
if (ig && rel && hasExplicitUnignore(ig, rel) && !ig.ignores(rel + '/'))
|
|
419
|
+
return false;
|
|
420
|
+
// Hardcoded list: block descent into well-known noise directories.
|
|
351
421
|
if (DEFAULT_IGNORE_LIST.has(p.name))
|
|
352
422
|
return true;
|
|
353
423
|
// Check against .gitignore / .gitnexusignore patterns.
|
|
@@ -358,11 +428,8 @@ export const createIgnoreFilter = async (repoPath, options) => {
|
|
|
358
428
|
// Bare-name patterns (e.g. `local`) still match `local/` per gitignore spec:
|
|
359
429
|
// the `ignore` package normalizes `dir` and `dir/` to match directories.
|
|
360
430
|
// See: https://github.com/kaelzhang/node-ignore#2-filenames-and-dirnames
|
|
361
|
-
if (ig)
|
|
362
|
-
|
|
363
|
-
if (rel && ig.ignores(rel + '/'))
|
|
364
|
-
return true;
|
|
365
|
-
}
|
|
431
|
+
if (ig && rel && ig.ignores(rel + '/'))
|
|
432
|
+
return true;
|
|
366
433
|
return false;
|
|
367
434
|
},
|
|
368
435
|
};
|
package/package.json
CHANGED