@sergenkabakci/grept 0.0.0-stage → 1.0.0

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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -2
  3. package/bin/grept.js +2 -0
  4. package/dist/cli/args.d.ts +50 -0
  5. package/dist/cli/args.d.ts.map +1 -0
  6. package/dist/cli/args.js +501 -0
  7. package/dist/cli/args.js.map +1 -0
  8. package/dist/cli/help.d.ts +2 -0
  9. package/dist/cli/help.d.ts.map +1 -0
  10. package/dist/cli/help.js +76 -0
  11. package/dist/cli/help.js.map +1 -0
  12. package/dist/cli/version.d.ts +3 -0
  13. package/dist/cli/version.d.ts.map +1 -0
  14. package/dist/cli/version.js +11 -0
  15. package/dist/cli/version.js.map +1 -0
  16. package/dist/core/binary.d.ts +6 -0
  17. package/dist/core/binary.d.ts.map +1 -0
  18. package/dist/core/binary.js +14 -0
  19. package/dist/core/binary.js.map +1 -0
  20. package/dist/core/encoding.d.ts +10 -0
  21. package/dist/core/encoding.d.ts.map +1 -0
  22. package/dist/core/encoding.js +16 -0
  23. package/dist/core/encoding.js.map +1 -0
  24. package/dist/core/line-reader.d.ts +19 -0
  25. package/dist/core/line-reader.d.ts.map +1 -0
  26. package/dist/core/line-reader.js +69 -0
  27. package/dist/core/line-reader.js.map +1 -0
  28. package/dist/core/matcher.d.ts +58 -0
  29. package/dist/core/matcher.d.ts.map +1 -0
  30. package/dist/core/matcher.js +342 -0
  31. package/dist/core/matcher.js.map +1 -0
  32. package/dist/core/offsets.d.ts +5 -0
  33. package/dist/core/offsets.d.ts.map +1 -0
  34. package/dist/core/offsets.js +11 -0
  35. package/dist/core/offsets.js.map +1 -0
  36. package/dist/core/patterns.d.ts +17 -0
  37. package/dist/core/patterns.d.ts.map +1 -0
  38. package/dist/core/patterns.js +223 -0
  39. package/dist/core/patterns.js.map +1 -0
  40. package/dist/core/search.d.ts +5 -0
  41. package/dist/core/search.d.ts.map +1 -0
  42. package/dist/core/search.js +249 -0
  43. package/dist/core/search.js.map +1 -0
  44. package/dist/errors/errors.d.ts +17 -0
  45. package/dist/errors/errors.d.ts.map +1 -0
  46. package/dist/errors/errors.js +32 -0
  47. package/dist/errors/errors.js.map +1 -0
  48. package/dist/errors/exit-codes.d.ts +7 -0
  49. package/dist/errors/exit-codes.d.ts.map +1 -0
  50. package/dist/errors/exit-codes.js +6 -0
  51. package/dist/errors/exit-codes.js.map +1 -0
  52. package/dist/filesystem/discover.d.ts +10 -0
  53. package/dist/filesystem/discover.d.ts.map +1 -0
  54. package/dist/filesystem/discover.js +110 -0
  55. package/dist/filesystem/discover.js.map +1 -0
  56. package/dist/filesystem/glob.d.ts +9 -0
  57. package/dist/filesystem/glob.d.ts.map +1 -0
  58. package/dist/filesystem/glob.js +61 -0
  59. package/dist/filesystem/glob.js.map +1 -0
  60. package/dist/filesystem/reparse-points.d.ts +10 -0
  61. package/dist/filesystem/reparse-points.d.ts.map +1 -0
  62. package/dist/filesystem/reparse-points.js +28 -0
  63. package/dist/filesystem/reparse-points.js.map +1 -0
  64. package/dist/filesystem/traversal.d.ts +15 -0
  65. package/dist/filesystem/traversal.d.ts.map +1 -0
  66. package/dist/filesystem/traversal.js +88 -0
  67. package/dist/filesystem/traversal.js.map +1 -0
  68. package/dist/index.d.ts +9 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +50 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/output/color.d.ts +11 -0
  73. package/dist/output/color.d.ts.map +1 -0
  74. package/dist/output/color.js +25 -0
  75. package/dist/output/color.js.map +1 -0
  76. package/dist/output/context.d.ts +21 -0
  77. package/dist/output/context.d.ts.map +1 -0
  78. package/dist/output/context.js +78 -0
  79. package/dist/output/context.js.map +1 -0
  80. package/dist/output/formatter.d.ts +24 -0
  81. package/dist/output/formatter.d.ts.map +1 -0
  82. package/dist/output/formatter.js +112 -0
  83. package/dist/output/formatter.js.map +1 -0
  84. package/dist/output/writer.d.ts +10 -0
  85. package/dist/output/writer.d.ts.map +1 -0
  86. package/dist/output/writer.js +62 -0
  87. package/dist/output/writer.js.map +1 -0
  88. package/dist/utils/terminal.d.ts +7 -0
  89. package/dist/utils/terminal.d.ts.map +1 -0
  90. package/dist/utils/terminal.js +21 -0
  91. package/dist/utils/terminal.js.map +1 -0
  92. package/dist/utils/windows-paths.d.ts +21 -0
  93. package/dist/utils/windows-paths.d.ts.map +1 -0
  94. package/dist/utils/windows-paths.js +47 -0
  95. package/dist/utils/windows-paths.js.map +1 -0
  96. package/docs/COMPATIBILITY.md +118 -0
  97. package/docs/PERFORMANCE.md +58 -0
  98. package/docs/REGEX.md +99 -0
  99. package/docs/WINDOWS.md +46 -0
  100. package/package.json +65 -4
@@ -0,0 +1,112 @@
1
+ import { getMatchByteOffset } from '../core/offsets.js';
2
+ export class OutputFormatter {
3
+ options;
4
+ colors;
5
+ constructor(options, colors) {
6
+ this.options = options;
7
+ this.colors = colors;
8
+ }
9
+ /**
10
+ * Formats a normal matching or context line.
11
+ */
12
+ formatLine(displayPath, showFilename, lineNum, byteOffset, text, isContext, matchRanges) {
13
+ const sepChar = isContext ? '-' : ':';
14
+ let prefix = '';
15
+ if (showFilename) {
16
+ const coloredFilename = this.colors.filename(displayPath);
17
+ if (this.options.nullByteFilename) {
18
+ prefix += coloredFilename + '\0';
19
+ }
20
+ else {
21
+ prefix += coloredFilename + this.colors.separator(sepChar);
22
+ }
23
+ }
24
+ if (this.options.lineNumber) {
25
+ const numStr = String(lineNum);
26
+ prefix += this.colors.lineNumber(numStr) + this.colors.separator(sepChar);
27
+ }
28
+ if (this.options.byteOffset) {
29
+ const offsetStr = String(byteOffset);
30
+ prefix += this.colors.byteOffset(offsetStr) + this.colors.separator(sepChar);
31
+ }
32
+ if (this.options.initialTab && prefix.length > 0) {
33
+ prefix += '\t';
34
+ }
35
+ // Apply color highlighting to matched text if not context
36
+ let formattedText = text;
37
+ if (!isContext && matchRanges.length > 0) {
38
+ formattedText = this.highlightMatches(text, matchRanges);
39
+ }
40
+ return prefix + formattedText;
41
+ }
42
+ /**
43
+ * Formats only-matching (-o) output lines.
44
+ */
45
+ formatOnlyMatching(displayPath, showFilename, lineNum, lineByteOffset, lineText, matches) {
46
+ const lines = [];
47
+ const sepChar = ':';
48
+ for (const m of matches) {
49
+ if (m.text.length === 0)
50
+ continue; // GNU grep ignores empty matches with -o
51
+ let prefix = '';
52
+ if (showFilename) {
53
+ const coloredFilename = this.colors.filename(displayPath);
54
+ if (this.options.nullByteFilename) {
55
+ prefix += coloredFilename + '\0';
56
+ }
57
+ else {
58
+ prefix += coloredFilename + this.colors.separator(sepChar);
59
+ }
60
+ }
61
+ if (this.options.lineNumber) {
62
+ prefix += this.colors.lineNumber(String(lineNum)) + this.colors.separator(sepChar);
63
+ }
64
+ if (this.options.byteOffset) {
65
+ const matchByteOffset = getMatchByteOffset(lineByteOffset, lineText, m.start);
66
+ prefix += this.colors.byteOffset(String(matchByteOffset)) + this.colors.separator(sepChar);
67
+ }
68
+ if (this.options.initialTab && prefix.length > 0) {
69
+ prefix += '\t';
70
+ }
71
+ const matchText = this.colors.matchedText(m.text);
72
+ lines.push(prefix + matchText);
73
+ }
74
+ return lines;
75
+ }
76
+ /**
77
+ * Highlights match ranges inside text using ANSI sequences.
78
+ */
79
+ highlightMatches(text, ranges) {
80
+ let result = '';
81
+ let lastIdx = 0;
82
+ for (const r of ranges) {
83
+ if (r.start > lastIdx) {
84
+ result += text.slice(lastIdx, r.start);
85
+ }
86
+ result += this.colors.matchedText(text.slice(r.start, r.end));
87
+ lastIdx = Math.max(lastIdx, r.end);
88
+ }
89
+ if (lastIdx < text.length) {
90
+ result += text.slice(lastIdx);
91
+ }
92
+ return result;
93
+ }
94
+ formatBinaryMatch(displayPath) {
95
+ return `Binary file ${displayPath} matches`;
96
+ }
97
+ formatCount(displayPath, showFilename, count) {
98
+ if (showFilename) {
99
+ if (this.options.nullByteFilename) {
100
+ return `${this.colors.filename(displayPath)}\0${count}`;
101
+ }
102
+ return `${this.colors.filename(displayPath)}:${count}`;
103
+ }
104
+ return String(count);
105
+ }
106
+ formatGroupSeparator() {
107
+ if (this.options.groupSeparator === null)
108
+ return null;
109
+ return this.colors.groupSeparator(this.options.groupSeparator);
110
+ }
111
+ }
112
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare class OutputWriter {
2
+ private stdout;
3
+ private stderr;
4
+ private nullData;
5
+ readonly lineBuffered: boolean;
6
+ constructor(stdout?: NodeJS.WriteStream, stderr?: NodeJS.WriteStream, nullData?: boolean, lineBuffered?: boolean);
7
+ writeLine(line: string): void;
8
+ writeError(message: string): void;
9
+ }
10
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAsBA,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAU;IAC1B,SAAgB,YAAY,EAAE,OAAO,CAAC;gBAGpC,MAAM,GAAE,MAAM,CAAC,WAA4B,EAC3C,MAAM,GAAE,MAAM,CAAC,WAA4B,EAC3C,QAAQ,UAAQ,EAChB,YAAY,UAAQ;IAUtB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAgB7B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAWlC"}
@@ -0,0 +1,62 @@
1
+ let pipeHandlersInstalled = false;
2
+ function ensurePipeHandlersInstalled() {
3
+ if (pipeHandlersInstalled)
4
+ return;
5
+ pipeHandlersInstalled = true;
6
+ if (process.stdout && typeof process.stdout.on === 'function') {
7
+ process.stdout.on('error', (err) => {
8
+ if (err.code === 'EPIPE') {
9
+ process.exit(0);
10
+ }
11
+ });
12
+ }
13
+ if (process.stderr && typeof process.stderr.on === 'function') {
14
+ process.stderr.on('error', (err) => {
15
+ if (err.code === 'EPIPE') {
16
+ process.exit(0);
17
+ }
18
+ });
19
+ }
20
+ }
21
+ export class OutputWriter {
22
+ stdout;
23
+ stderr;
24
+ nullData;
25
+ lineBuffered;
26
+ constructor(stdout = process.stdout, stderr = process.stderr, nullData = false, lineBuffered = false) {
27
+ this.stdout = stdout;
28
+ this.stderr = stderr;
29
+ this.nullData = nullData;
30
+ this.lineBuffered = lineBuffered;
31
+ ensurePipeHandlersInstalled();
32
+ }
33
+ writeLine(line) {
34
+ const endChar = this.nullData ? '\0' : '\n';
35
+ try {
36
+ this.stdout.write(line + endChar);
37
+ if (this.lineBuffered && typeof this.stdout.uncork === 'function') {
38
+ this.stdout.uncork();
39
+ }
40
+ }
41
+ catch (err) {
42
+ const code = err?.code;
43
+ if (code === 'EPIPE') {
44
+ process.exit(0);
45
+ }
46
+ throw err;
47
+ }
48
+ }
49
+ writeError(message) {
50
+ try {
51
+ this.stderr.write(message + '\n');
52
+ }
53
+ catch (err) {
54
+ const code = err?.code;
55
+ if (code === 'EPIPE') {
56
+ process.exit(0);
57
+ }
58
+ throw err;
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAAA,IAAI,qBAAqB,GAAG,KAAK,CAAC;AAElC,SAAS,2BAA2B;IAClC,IAAI,qBAAqB;QAAE,OAAO;IAClC,qBAAqB,GAAG,IAAI,CAAC;IAE7B,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,UAAU,EAAE,CAAC;QAC9D,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YACxD,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,UAAU,EAAE,CAAC;QAC9D,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YACxD,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,OAAO,YAAY;IACf,MAAM,CAAqB;IAC3B,MAAM,CAAqB;IAC3B,QAAQ,CAAU;IACV,YAAY,CAAU;IAEtC,YACE,SAA6B,OAAO,CAAC,MAAM,EAC3C,SAA6B,OAAO,CAAC,MAAM,EAC3C,QAAQ,GAAG,KAAK,EAChB,YAAY,GAAG,KAAK;QAEpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QAEjC,2BAA2B,EAAE,CAAC;IAChC,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,YAAY,IAAI,OAAQ,IAAI,CAAC,MAAc,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC1E,IAAI,CAAC,MAAc,CAAC,MAAM,EAAE,CAAC;YAChC,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;YAClD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,UAAU,CAAC,OAAe;QACxB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;YAClD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export type ColorChoice = 'never' | 'always' | 'auto';
2
+ /**
3
+ * Determines whether color escape sequences should be output based on
4
+ * the user option, environment variables (NO_COLOR, TERM), and TTY status.
5
+ */
6
+ export declare function shouldEnableColor(colorChoice: ColorChoice): boolean;
7
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/utils/terminal.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAkBnE"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Determines whether color escape sequences should be output based on
3
+ * the user option, environment variables (NO_COLOR, TERM), and TTY status.
4
+ */
5
+ export function shouldEnableColor(colorChoice) {
6
+ if (colorChoice === 'never') {
7
+ return false;
8
+ }
9
+ if (colorChoice === 'always') {
10
+ return true;
11
+ }
12
+ // Auto mode
13
+ if (process.env['NO_COLOR'] !== undefined && process.env['NO_COLOR'] !== '') {
14
+ return false;
15
+ }
16
+ if (process.env['TERM'] === 'dumb') {
17
+ return false;
18
+ }
19
+ return Boolean(process.stdout && process.stdout.isTTY);
20
+ }
21
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/utils/terminal.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAwB;IACxD,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY;IACZ,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Normalizes Windows paths (slashes, casing where applicable, extended paths)
3
+ */
4
+ export declare function normalizeWindowsPath(p: string): string;
5
+ /**
6
+ * Checks if two paths refer to the same file or directory on Windows (case-insensitive comparison)
7
+ */
8
+ export declare function pathsEqual(p1: string, p2: string): boolean;
9
+ /**
10
+ * Resolves path safely, handling extended-length path prefix if needed
11
+ */
12
+ export declare function resolveWindowsPath(p: string): string;
13
+ /**
14
+ * Checks if a path is a UNC network path
15
+ */
16
+ export declare function isUncPath(p: string): boolean;
17
+ /**
18
+ * Strips extended-length path prefix for display purposes if present
19
+ */
20
+ export declare function displayPath(p: string): string;
21
+ //# sourceMappingURL=windows-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-paths.d.ts","sourceRoot":"","sources":["../../src/utils/windows-paths.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAStD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ7C"}
@@ -0,0 +1,47 @@
1
+ import path from 'node:path';
2
+ /**
3
+ * Normalizes Windows paths (slashes, casing where applicable, extended paths)
4
+ */
5
+ export function normalizeWindowsPath(p) {
6
+ if (!p)
7
+ return '';
8
+ // Standardize backslashes for Windows path operations
9
+ let normalized = path.normalize(p);
10
+ // Ensure drive letters are uppercase for consistent internal comparisons
11
+ if (/^[a-zA-Z]:/.test(normalized)) {
12
+ normalized = normalized[0].toUpperCase() + normalized.slice(1);
13
+ }
14
+ return normalized;
15
+ }
16
+ /**
17
+ * Checks if two paths refer to the same file or directory on Windows (case-insensitive comparison)
18
+ */
19
+ export function pathsEqual(p1, p2) {
20
+ return normalizeWindowsPath(p1).toLowerCase() === normalizeWindowsPath(p2).toLowerCase();
21
+ }
22
+ /**
23
+ * Resolves path safely, handling extended-length path prefix if needed
24
+ */
25
+ export function resolveWindowsPath(p) {
26
+ const resolved = path.resolve(p);
27
+ return normalizeWindowsPath(resolved);
28
+ }
29
+ /**
30
+ * Checks if a path is a UNC network path
31
+ */
32
+ export function isUncPath(p) {
33
+ return /^\\\\[^\\/]+[\\/][^\\/]+/.test(p);
34
+ }
35
+ /**
36
+ * Strips extended-length path prefix for display purposes if present
37
+ */
38
+ export function displayPath(p) {
39
+ if (p.startsWith('\\\\?\\UNC\\')) {
40
+ return '\\\\' + p.slice(8);
41
+ }
42
+ if (p.startsWith('\\\\?\\')) {
43
+ return p.slice(4);
44
+ }
45
+ return p;
46
+ }
47
+ //# sourceMappingURL=windows-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-paths.js","sourceRoot":"","sources":["../../src/utils/windows-paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,CAAS;IAC5C,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAClB,sDAAsD;IACtD,IAAI,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACnC,yEAAyE;IACzE,IAAI,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,UAAU,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,EAAU,EAAE,EAAU;IAC/C,OAAO,oBAAoB,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,oBAAoB,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC3F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,OAAO,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,IAAI,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,118 @@
1
+ # GNU grep Compatibility Matrix
2
+
3
+ This document details the compatibility of `grept` with GNU `grep` (GNU grep 3.11 specification).
4
+ Each option supported or evaluated is categorized into one of four states:
5
+ - **Fully supported**: Matches GNU grep specification and behavior.
6
+ - **Partially supported**: Functional on Windows with specific architectural differences documented.
7
+ - **Unsupported**: Not implemented with technical justification.
8
+ - **Not applicable on Windows**: Concept or option is specific to POSIX environments (e.g., POSIX device inodes or TTY ioctls not present on Win32).
9
+
10
+ ---
11
+
12
+ ## 1. Pattern Selection Options
13
+
14
+ | Option | Long Option | Status | Notes / Behavioral Differences |
15
+ | :--- | :--- | :--- | :--- |
16
+ | `-E` | `--extended-regexp` | **Fully supported** | Interprets patterns as POSIX Extended Regular Expressions (ERE). Unescaped `?`, `+`, `{`, `}`, `\|`, `(`, `)` are special operators. |
17
+ | `-F` | `--fixed-strings` | **Fully supported** | Interprets patterns as fixed strings (literal matching). Extremely fast multi-string matching. |
18
+ | `-G` | `--basic-regexp` | **Fully supported** | Interprets patterns as POSIX Basic Regular Expressions (BRE, default). `?`, `+`, `{`, `}`, `\|`, `(`, `)` are literals unless escaped. |
19
+ | `-P` | `--perl-regexp` | **Fully supported** | Interprets patterns as Perl-compatible regular expressions using WebAssembly-compiled PCRE2. Supports lookarounds, atomic groups, Unicode properties. |
20
+ | `-e PATTERN` | `--regexp=PATTERN` | **Fully supported** | Specifies matching pattern. Multiple `-e` options are combined (logical OR). Protects patterns beginning with `-`. |
21
+ | `-f FILE` | `--file=FILE` | **Fully supported** | Obtains patterns from file, one per line. Empty pattern lines match any input line. |
22
+ | `-i`, `-y` | `--ignore-case` | **Fully supported** | Case-insensitive matching across ASCII and Unicode characters (including Turkish dotted/dotless I). |
23
+ | `--no-ignore-case` | `--no-ignore-case` | **Fully supported** | Resets case-insensitive matching if previously specified. |
24
+ | `-v` | `--invert-match` | **Fully supported** | Inverts the sense of matching, to select non-matching lines. |
25
+ | `-w` | `--word-regexp` | **Fully supported** | Selects only those lines containing matches that form whole words (bounded by word/non-word boundaries). |
26
+ | `-x` | `--line-regexp` | **Fully supported** | Selects only those matches that exactly match the whole line. |
27
+
28
+ ---
29
+
30
+ ## 2. Matching Control Options
31
+
32
+ | Option | Long Option | Status | Notes / Behavioral Differences |
33
+ | :--- | :--- | :--- | :--- |
34
+ | `-m NUM` | `--max-count=NUM` | **Fully supported** | Stop reading a file after `NUM` matching lines. If context is specified, trailing context is printed. |
35
+ | `--line-buffered` | `--line-buffered` | **Fully supported** | Flushes output after every line. Useful for real-time streaming in PowerShell and CMD pipelines. |
36
+ | `-a` | `--text` | **Fully supported** | Process binary files as if they were text; equivalent to `--binary-files=text`. |
37
+ | `-I` | *(none)* | **Fully supported** | Process a binary file as if it did not contain any matches; equivalent to `--binary-files=without-match`. |
38
+ | `-U` | `--binary` | **Fully supported** | Treat input file as binary data, reading verbatim without CR/LF translation. |
39
+ | *(none)* | `--binary-files=TYPE` | **Fully supported** | `TYPE` can be `binary`, `text`, or `without-match`. In `binary` mode, matches output `Binary file <NAME> matches`. |
40
+
41
+ ---
42
+
43
+ ## 3. General Output Control Options
44
+
45
+ | Option | Long Option | Status | Notes / Behavioral Differences |
46
+ | :--- | :--- | :--- | :--- |
47
+ | `-c` | `--count` | **Fully supported** | Suppress normal output; instead print a count of matching lines for each input file. |
48
+ | `--color[=WHEN]` | `--colour[=WHEN]` | **Fully supported** | `WHEN` may be `never`, `always`, or `auto`. Respects `NO_COLOR` env var and Windows Terminal / conhost capabilities. |
49
+ | `-L` | `--files-without-match` | **Fully supported** | Suppress normal output; print the name of each input file from which no output would have normally been produced. |
50
+ | `-l` | `--files-with-matches` | **Fully supported** | Suppress normal output; print the name of each input file with matches (stops scanning upon first match). |
51
+ | `-o` | `--only-matching` | **Fully supported** | Print only the matched (non-empty) parts of a matching line, each on a separate output line. |
52
+ | `-q` | `--quiet`, `--silent` | **Fully supported** | Quiet mode. Exit immediately with zero status if any match is found, even if an error was detected. |
53
+ | `-s` | `--no-messages` | **Fully supported** | Suppress error messages about nonexistent or unreadable files. Argument errors still reported. |
54
+
55
+ ---
56
+
57
+ ## 4. Output Line Prefix Control Options
58
+
59
+ | Option | Long Option | Status | Notes / Behavioral Differences |
60
+ | :--- | :--- | :--- | :--- |
61
+ | `-b` | `--byte-offset` | **Fully supported** | Print the 0-based byte offset within the input file before each line of output. With `-o`, prints offset of match. |
62
+ | `-H` | `--with-filename` | **Fully supported** | Print the file name for each match. Default when searching multiple files or recursive directories. |
63
+ | `-h` | `--no-filename` | **Fully supported** | Suppress the prefixing of file names on output. Default when searching a single file or stdin. |
64
+ | `--label=LABEL` | *(none)* | **Fully supported** | Display input from standard input as if it came from file `LABEL`. |
65
+ | `-n` | `--line-number` | **Fully supported** | Prefix each line of output with the 1-based line number within its input file. |
66
+ | `-T` | `--initial-tab` | **Fully supported** | Pad prefix with a tab so that line content aligns across lines with varying number widths. |
67
+ | `-u` | `--unix-byte-offsets` | **Fully supported** | Report Unix-style byte offsets as if the file were Unix text (CRLF `\r\n` pairs are counted as 1 byte `\n` instead of 2 bytes). Matches GNU grep on MS-Windows. |
68
+ | `-Z` | `--null` | **Fully supported** | Output a zero byte (`NUL`) instead of the character that normally follows a file name (e.g. `:`). |
69
+ | `-z` | `--null-data` | **Fully supported** | Treat input and output data as sequences of lines, each terminated by a zero byte (`NUL`) instead of a newline. |
70
+
71
+ ---
72
+
73
+ ## 5. Context Control Options
74
+
75
+ | Option | Long Option | Status | Notes / Behavioral Differences |
76
+ | :--- | :--- | :--- | :--- |
77
+ | `-A NUM` | `--after-context=NUM` | **Fully supported** | Print `NUM` lines of trailing context after matching lines. Overlapping contexts are merged. |
78
+ | `-B NUM` | `--before-context=NUM` | **Fully supported** | Print `NUM` lines of leading context before matching lines. Overlapping contexts are merged. |
79
+ | `-C NUM`, `-NUM` | `--context=NUM` | **Fully supported** | Print `NUM` lines of leading and trailing context. |
80
+ | *(none)* | `--group-separator=SEP` | **Fully supported** | Use `SEP` as group separator between contiguous groups of matches. Default is `--`. |
81
+ | *(none)* | `--no-group-separator` | **Fully supported** | Suppress the group separator between contiguous groups of matches. |
82
+
83
+ ---
84
+
85
+ ## 6. File and Directory Selection Options
86
+
87
+ | Option | Long Option | Status | Notes / Behavioral Differences |
88
+ | :--- | :--- | :--- | :--- |
89
+ | `-r` | `--recursive` | **Fully supported** | Read all files under each directory recursively. Follows symbolic links only if they are on the command line. |
90
+ | `-R` | `--dereference-recursive` | **Fully supported** | Recurse directories and dereference directory symbolic links / NTFS junctions, with cycle detection. |
91
+ | `--follow` | *(none)* | **Fully supported** | Follow symlinks and reparse points during traversal. |
92
+ | `--include=GLOB` | *(none)* | **Fully supported** | Search only files whose base name matches `GLOB` (case-insensitive on Windows). |
93
+ | `--exclude=GLOB` | *(none)* | **Fully supported** | Skip any command-line file with a name suffix that matches the pattern `GLOB`. |
94
+ | `--exclude-from=FILE` | *(none)* | **Fully supported** | Skip files whose base name matches any of the file-name globs read from `FILE`. |
95
+ | `--exclude-dir=GLOB` | *(none)* | **Fully supported** | Skip directories matching `GLOB`. By default skips `node_modules`, `.git`, and hidden directories. |
96
+ | `--max-depth=NUM` | *(none)* | **Fully supported** | Descend at most `NUM` directory levels below command-line targets. |
97
+ | `-d ACTION` | `--directories=ACTION` | **Fully supported** | If input is a directory, `ACTION` is `read`, `recurse`, or `skip`. |
98
+ | `-D ACTION` | `--devices=ACTION` | **Fully supported** | If input file is a device, FIFO, or socket, `ACTION` can be `read` or `skip`. |
99
+
100
+ ---
101
+
102
+ ## 7. Other Options
103
+
104
+ | Option | Long Option | Status | Notes / Behavioral Differences |
105
+ | :--- | :--- | :--- | :--- |
106
+ | `--mmap` | *(none)* | **Fully supported (no-op)** | Deprecated and ignored in GNU grep 3.8+; accepted safely without error for CLI script compatibility. |
107
+ | `--debug` | *(none)* | **Fully supported** | Output internal debugging diagnostics regarding regex parsing, matching, and traversal. |
108
+ | `--help` | *(none)* | **Fully supported** | Display comprehensive help message and exit with 0. |
109
+ | `-V` | `--version` | **Fully supported** | Display version information and exit with 0. |
110
+
111
+ ---
112
+
113
+ ## Exit Status
114
+
115
+ - `0`: Selected lines or matches were found.
116
+ - `1`: No lines or matches were found.
117
+ - `2`: An error occurred (e.g., invalid regex syntax, unreadable file without `-s`, invalid option).
118
+ - In `-q` mode, if a match is found, exit code is always `0`.
@@ -0,0 +1,58 @@
1
+ # Performance Architecture and Benchmarks in `grept`
2
+
3
+ `grept` is engineered specifically for fast text searching on modern Windows systems with NVMe and SATA SSDs.
4
+
5
+ ---
6
+
7
+ ## 1. Architectural Highlights
8
+
9
+ 1. **Streaming Input Processing**:
10
+ - Files are read in fixed 64 KB binary chunks rather than loaded entirely into memory.
11
+ - Lines are parsed on-the-fly, bounding peak memory consumption regardless of file size.
12
+ - Dynamic buffer growth safely accommodates long lines without truncation.
13
+
14
+ 2. **One-Time Pattern Compilation**:
15
+ - Regular expressions and string matchers are compiled once during CLI startup and reused across all files and lines.
16
+ - For PCRE2, patterns are compiled into WebAssembly memory once per search session.
17
+
18
+ 3. **Fast Substring Search (`-F`)**:
19
+ - Literal string matching bypasses regex engines completely, using optimized substring searches.
20
+ - Case-insensitive literal matching converts input lines with minimal object churn.
21
+
22
+ 4. **Zero-Allocation Byte Offsets**:
23
+ - Byte offsets (`-b`) are accumulated directly from incoming buffer byte counts rather than recalculating UTF-8 character lengths from string slices.
24
+
25
+ 5. **Early Termination**:
26
+ - `-q` (`--quiet`): Terminates the process immediately upon the first match found, closing open file descriptors cleanly.
27
+ - `-m NUM` (`--max-count`): Halts file scanning as soon as `NUM` matching lines and their after-context are satisfied.
28
+ - `-l` (`--files-with-matches`): Halts scanning the current file on its first match and moves to the next file.
29
+
30
+ 6. **Bounded Memory Footprint**:
31
+ - Heap usage remains under ~15 MB even when scanning multi-gigabyte files.
32
+
33
+ ---
34
+
35
+ ## 2. Benchmark Methodology and Environment
36
+
37
+ - **Host Operating System**: Windows 11 (x64)
38
+ - **Runtime**: Node.js v22.17.1
39
+ - **File System**: NTFS
40
+ - **Dataset**:
41
+ - Synthetic ~20 MB server application log (140,000 CRLF lines).
42
+ - Nested directory hierarchy containing 500 TypeScript source files across 20 directories.
43
+
44
+ ### Benchmark Results
45
+
46
+ | Scenario | Execution Time (ms) | Measured Throughput | Matches |
47
+ | :--- | :--- | :--- | :--- |
48
+ | **Fixed-string search (`-F`)** | ~207 ms | **95.31 MB/s** | 280 |
49
+ | **Extended RegEx search (`-E`)** | ~200 ms | **98.67 MB/s** | 280 |
50
+ | **Case-insensitive search (`-i`)** | ~350 ms | **56.49 MB/s** | 280 |
51
+ | **High-density match count (`-c`)** | ~337 ms | **58.67 MB/s** | 1 (aggregated count) |
52
+ | **Recursive 500 files (`-r --include=*.ts`)** | ~401 ms | *I/O bound* | 500 |
53
+ | **PCRE2 lookaround search (`-P`)** | ~6.0 s | **3.25 MB/s** (WASM bridge) | 0 |
54
+
55
+ ### Memory Consumption
56
+
57
+ - **Peak Heap Used**: 12.65 MB
58
+ - **Peak RSS**: 154.95 MB (including Node.js V8 runtime + WASM PCRE2 binary)
package/docs/REGEX.md ADDED
@@ -0,0 +1,99 @@
1
+ # Regular Expression Engines and Matching Semantics in `grept`
2
+
3
+ `grept` supports four distinct regex and string matching modes corresponding to GNU grep:
4
+
5
+ 1. **Basic Regular Expressions (`-G`, `--basic-regexp`)** [Default]
6
+ 2. **Extended Regular Expressions (`-E`, `--extended-regexp`)**
7
+ 3. **Fixed Strings (`-F`, `--fixed-strings`)**
8
+ 4. **Perl-Compatible Regular Expressions (`-P`, `--perl-regexp`)**
9
+
10
+ ---
11
+
12
+ ## 1. Engine Modes
13
+
14
+ ### Basic Regular Expressions (BRE, `-G`)
15
+ In GNU Basic Regular Expression mode:
16
+ - Meta-characters `?`, `+`, `{`, `}`, `|`, `(`, and `)` are treated as ordinary literal characters.
17
+ - To activate their special meaning, they must be backslash-escaped:
18
+ - `\?` : Zero or one occurrence
19
+ - `\+` : One or more occurrences
20
+ - `\{m,n\}` : Between `m` and `n` occurrences
21
+ - `\|` : Alternation (OR)
22
+ - `\(` and `\)` : Capturing groups
23
+ - Unescaped `.` matches any character except newline (unless `-z` is enabled).
24
+ - `^` anchors to the start of the line; `$` anchors to the end.
25
+ - `*` matches zero or more occurrences of the preceding element.
26
+ - Backreferences `\1` through `\9` refer back to matched groups.
27
+
28
+ ### Extended Regular Expressions (ERE, `-E`)
29
+ In GNU Extended Regular Expression mode:
30
+ - Meta-characters `?`, `+`, `{`, `}`, `|`, `(`, and `)` are special operators by default.
31
+ - Preceding them with a backslash makes them literal characters.
32
+ - Supports POSIX character classes and alternation without backslashes.
33
+
34
+ ### Fixed Strings (`-F`)
35
+ - All characters in the pattern are treated as literal characters.
36
+ - Fast multi-string search using direct substring matching.
37
+ - Avoids regular expression compilation overhead.
38
+
39
+ ### Perl-Compatible Regular Expressions (PCRE, `-P`)
40
+ - Backed by WebAssembly-compiled **PCRE2 (10.49+)**.
41
+ - Zero native build dependencies; 100% portable on Windows Node.js.
42
+ - Supports:
43
+ - Lookahead (`(?=...)`, `(?!...)`) and Lookbehind (`(?<=...)`, `(?<!...)`)
44
+ - Non-capturing groups (`(?:...)`) and Named groups (`(?P<name>...)`)
45
+ - Possessive quantifiers (`*+`, `++`, `?+`) and Atomic groups (`(?>...)`)
46
+ - Unicode character properties (`\p{...}`) and PCRE control verbs
47
+ - Configurable backtracking step limits for ReDoS protection.
48
+
49
+ ---
50
+
51
+ ## 2. POSIX Character Classes
52
+
53
+ Both BRE and ERE support POSIX character classes within bracket expressions:
54
+
55
+ | POSIX Class | Matches |
56
+ | :--- | :--- |
57
+ | `[:alnum:]` | Alphanumeric characters (`[0-9A-Za-z]`) |
58
+ | `[:alpha:]` | Alphabetic characters (`[A-Za-z]`) |
59
+ | `[:blank:]` | Space and tab characters (`[ \t]`) |
60
+ | `[:cntrl:]` | Control characters (`[\x00-\x1F\x7F]`) |
61
+ | `[:digit:]` | Digits (`[0-9]`) |
62
+ | `[:graph:]` | Non-blank printable characters (`[\x21-\x7E]`) |
63
+ | `[:lower:]` | Lowercase letters (`[a-z]`) |
64
+ | `[:print:]` | Printable characters including space (`[\x20-\x7E]`) |
65
+ | `[:punct:]` | Punctuation characters (`[!-/:-@[-`{-~]`) |
66
+ | `[:space:]` | Whitespace characters (`[ \t\r\n\v\f]`) |
67
+ | `[:upper:]` | Uppercase letters (`[A-Z]`) |
68
+ | `[:xdigit:]` | Hexadecimal digits (`[0-9A-Fa-f]`) |
69
+
70
+ ---
71
+
72
+ ## 3. Word Boundaries and GNU Extensions
73
+
74
+ - `\b` : Word boundary
75
+ - `\B` : Non-word boundary
76
+ - `\<` : Start of word boundary (`(?<=\W|^)(?=\w)`)
77
+ - `\>` : End of word boundary (`(?<=\w)(?=\W|$)`)
78
+ - `\w` : Word character (`[a-zA-Z0-9_]`)
79
+ - `\W` : Non-word character (`[^a-zA-Z0-9_]`)
80
+ - `\s` : Whitespace character (`[ \t\r\n\v\f]`)
81
+ - `\S` : Non-whitespace character
82
+
83
+ ---
84
+
85
+ ## 4. Unicode and Case Folding
86
+
87
+ - When `-i` (`--ignore-case`) is active, case folding applies across both ASCII and Unicode text.
88
+ - Special handling is included for Turkish characters:
89
+ - Capital dotted `İ` (U+0130) and lowercase `i` (U+0069)
90
+ - Capital dotless `I` (U+0049) and lowercase dotless `ı` (U+0131)
91
+ - In `-P` mode, `FLAGS.UTF` and `FLAGS.UCP` ensure full Unicode code-point matching.
92
+
93
+ ---
94
+
95
+ ## 5. Security & ReDoS Mitigation
96
+
97
+ - In PCRE2 mode, execution limits (`matchLimit: 1_000_000`, `depthLimit: 10_000`) prevent runaway backtracking.
98
+ - Empty patterns match every line (matching GNU grep behavior).
99
+ - Invalid regular expressions emit diagnostic error messages to `stderr` and exit with code `2`.
@@ -0,0 +1,46 @@
1
+ # Windows Native Filesystem & Shell Semantics in `grept`
2
+
3
+ `grept` is designed from the ground up for Windows 10 and 11 environments, prioritizing NTFS characteristics, PowerShell, CMD, and Windows Terminal.
4
+
5
+ ---
6
+
7
+ ## 1. Path Handling
8
+
9
+ - **Drive-Letter Paths**: Fully supports standard DOS drive paths such as `C:\Projects\App` and forward-slash normalized variants `C:/Projects/App`.
10
+ - **Spaces in Paths**: Paths containing whitespace (e.g. `C:\Program Files\App`) are preserved without unescaping corruption.
11
+ - **UNC Paths**: Network paths such as `\\server\share\folder` are traversed and reported correctly.
12
+ - **Extended-Length Paths**: Paths exceeding 260 characters (`\\?\C:\Very\Deep\...`) are supported natively using Node.js filesystem APIs.
13
+ - **Case-Insensitive Filesystem**: Windows file and directory comparisons are case-insensitive by default while preserving display casing in output.
14
+
15
+ ---
16
+
17
+ ## 2. Reparse Points, Junctions & NTFS Symlinks
18
+
19
+ - **Reparse Points**: NTFS junctions (`IO_REPARSE_TAG_MOUNT_POINT`) and symbolic links are detected via `fs.lstat()`.
20
+ - **Traversal Modes**:
21
+ - `-r` (`--recursive`): Recurses normal subdirectories; directory reparse points and symlinks are **not** followed unless passed as command-line arguments.
22
+ - `-R` (`--dereference-recursive`) or `--follow`: Traverses into directory reparse points and symlinks.
23
+ - **Cycle Detection**:
24
+ - Traversal maintains a set of canonical target identifiers (`${dev}:${ino}`) and realpaths to detect loops and cyclic junctions.
25
+ - When a loop is detected, traversal logs a warning (suppressed by `-s`) and skips the cycle, avoiding infinite recursion.
26
+
27
+ ---
28
+
29
+ ## 3. Windows Shells & Pipelines
30
+
31
+ ### PowerShell (Windows PowerShell 5.1 & PowerShell 7+)
32
+ - PowerShell cmdlets pass objects through the pipeline; when piping text to external executables, PowerShell streams UTF-8 (PowerShell 7) or ANSI/OEM (PowerShell 5.1).
33
+ - `grept` automatically handles raw byte streams from stdin without corrupting non-ASCII characters.
34
+ - Examples:
35
+ ```powershell
36
+ Get-Content app.log | grept "Error"
37
+ Get-Content -Raw data.bin | grept -z "record"
38
+ ```
39
+
40
+ ### CMD.exe
41
+ - Pipes (`type app.log | grept "Error"`) and standard redirection (`grept "Error" < app.log > results.txt`) work seamlessly.
42
+
43
+ ### Console & Color Detection
44
+ - Respects `process.stdout.isTTY` and `NO_COLOR`.
45
+ - When output is redirected to a file or another command, ANSI color codes are automatically stripped to keep the data clean.
46
+ - Windows Virtual Terminal processing is supported across Windows Terminal and conhost.