c-next 0.2.12 → 0.2.13

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 (66) hide show
  1. package/README.md +80 -649
  2. package/dist/index.js +7387 -6211
  3. package/dist/index.js.map +4 -4
  4. package/grammar/C.g4 +9 -3
  5. package/package.json +1 -2
  6. package/src/__tests__/index.test.ts +1 -1
  7. package/src/cli/CleanCommand.ts +8 -12
  8. package/src/cli/Cli.ts +29 -6
  9. package/src/cli/Runner.ts +42 -62
  10. package/src/cli/__tests__/CleanCommand.test.ts +10 -10
  11. package/src/cli/__tests__/Cli.test.ts +59 -7
  12. package/src/cli/__tests__/ConfigPrinter.test.ts +12 -12
  13. package/src/cli/__tests__/PathNormalizer.test.ts +5 -5
  14. package/src/cli/__tests__/Runner.test.ts +108 -82
  15. package/src/cli/serve/ServeCommand.ts +1 -1
  16. package/src/cli/types/ICliConfig.ts +2 -2
  17. package/src/lib/parseWithSymbols.ts +21 -21
  18. package/src/transpiler/Transpiler.ts +88 -43
  19. package/src/transpiler/__tests__/DualCodePaths.test.ts +29 -29
  20. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +244 -72
  21. package/src/transpiler/__tests__/Transpiler.test.ts +32 -72
  22. package/src/transpiler/__tests__/determineProjectRoot.test.ts +30 -28
  23. package/src/transpiler/__tests__/needsConditionalPreprocessing.test.ts +1 -1
  24. package/src/transpiler/data/CNextMarkerDetector.ts +34 -0
  25. package/src/transpiler/data/CppEntryPointScanner.ts +174 -0
  26. package/src/transpiler/data/FileDiscovery.ts +2 -105
  27. package/src/transpiler/data/InputExpansion.ts +37 -81
  28. package/src/transpiler/data/__tests__/CNextMarkerDetector.test.ts +62 -0
  29. package/src/transpiler/data/__tests__/CppEntryPointScanner.test.ts +239 -0
  30. package/src/transpiler/data/__tests__/FileDiscovery.test.ts +45 -191
  31. package/src/transpiler/data/__tests__/InputExpansion.test.ts +36 -204
  32. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +2 -2
  33. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +4 -5
  34. package/src/transpiler/logic/parser/c/grammar/C.interp +19 -1
  35. package/src/transpiler/logic/parser/c/grammar/C.tokens +231 -213
  36. package/src/transpiler/logic/parser/c/grammar/CLexer.interp +28 -1
  37. package/src/transpiler/logic/parser/c/grammar/CLexer.tokens +231 -213
  38. package/src/transpiler/logic/parser/c/grammar/CLexer.ts +654 -600
  39. package/src/transpiler/logic/parser/c/grammar/CParser.ts +1175 -1099
  40. package/src/transpiler/logic/symbols/SymbolTable.ts +19 -7
  41. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +78 -0
  42. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +6 -6
  43. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +28 -27
  44. package/src/transpiler/logic/symbols/cnext/index.ts +4 -4
  45. package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +5 -5
  46. package/src/transpiler/output/codegen/CodeGenerator.ts +7 -1
  47. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +15 -0
  48. package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +3 -3
  49. package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +14 -14
  50. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
  51. package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +7 -7
  52. package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +3 -3
  53. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +10 -1
  54. package/src/transpiler/output/headers/HeaderGenerator.ts +3 -0
  55. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +6 -2
  56. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +16 -0
  57. package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +19 -19
  58. package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +5 -5
  59. package/src/transpiler/state/SymbolRegistry.ts +10 -12
  60. package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +11 -13
  61. package/src/transpiler/types/IPipelineFile.ts +3 -0
  62. package/src/transpiler/types/ITranspilerConfig.ts +2 -2
  63. package/src/transpiler/types/symbols/IScopeSymbol.ts +1 -1
  64. package/src/utils/FunctionUtils.ts +3 -3
  65. package/src/utils/__tests__/FunctionUtils.test.ts +6 -4
  66. package/src/transpiler/data/types/IDiscoveryOptions.ts +0 -15
@@ -0,0 +1,174 @@
1
+ import { dirname, join, resolve } from "node:path";
2
+ import IncludeDiscovery from "./IncludeDiscovery";
3
+ import CNextMarkerDetector from "./CNextMarkerDetector";
4
+ import IFileSystem from "../types/IFileSystem";
5
+ import NodeFileSystem from "../NodeFileSystem";
6
+
7
+ /**
8
+ * Result of scanning a C/C++ entry point for C-Next sources.
9
+ */
10
+ interface IScanResult {
11
+ /** Absolute paths to discovered .cnx source files */
12
+ cnextSources: string[];
13
+ /** Errors encountered (e.g., missing .cnx files referenced by markers) */
14
+ errors: string[];
15
+ /** Warnings encountered (e.g., includes that couldn't be resolved) */
16
+ warnings: string[];
17
+ /** True if no C-Next markers were found (not an error, just informational) */
18
+ noCNextFound: boolean;
19
+ }
20
+
21
+ /**
22
+ * Scans C/C++ entry point files to discover C-Next source dependencies.
23
+ *
24
+ * Walks the include tree starting from a C/C++ file, looks for C-Next
25
+ * generation markers in headers, and extracts the source .cnx paths.
26
+ * Follows includes transitively through discovered .cnx files.
27
+ *
28
+ * Used by the C/C++ entry point feature (ADR-XXX) to enable compilation
29
+ * where the entry point is a C/C++ file that #includes C-Next generated headers.
30
+ */
31
+ class CppEntryPointScanner {
32
+ private readonly fs: IFileSystem;
33
+ private readonly searchPaths: string[];
34
+ private readonly visited = new Set<string>();
35
+ private readonly cnextSources = new Set<string>();
36
+ private readonly errors: string[] = [];
37
+ private readonly warnings: string[] = [];
38
+
39
+ constructor(
40
+ searchPaths: string[],
41
+ fs: IFileSystem = NodeFileSystem.instance,
42
+ ) {
43
+ this.searchPaths = searchPaths;
44
+ this.fs = fs;
45
+ }
46
+
47
+ /**
48
+ * Scan an entry point file for C-Next source dependencies.
49
+ *
50
+ * @param entryPath - Path to the C/C++ entry point file
51
+ * @returns Scan result with discovered sources, errors, and warnings
52
+ */
53
+ scan(entryPath: string): IScanResult {
54
+ const absolutePath = resolve(entryPath);
55
+ this._scanFile(absolutePath);
56
+
57
+ return {
58
+ cnextSources: Array.from(this.cnextSources),
59
+ errors: this.errors,
60
+ warnings: this.warnings,
61
+ noCNextFound: this.cnextSources.size === 0 && this.errors.length === 0,
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Scan a file for includes and process them.
67
+ */
68
+ private _scanFile(filePath: string): void {
69
+ if (this.visited.has(filePath)) return;
70
+ this.visited.add(filePath);
71
+
72
+ let content: string;
73
+ try {
74
+ content = this.fs.readFile(filePath);
75
+ } catch {
76
+ this.warnings.push(`Warning: Could not read ${filePath}`);
77
+ return;
78
+ }
79
+
80
+ const includes = IncludeDiscovery.extractIncludesWithInfo(content);
81
+ const fileDir = dirname(filePath);
82
+ const localSearchPaths = [fileDir, ...this.searchPaths];
83
+
84
+ for (const includeInfo of includes) {
85
+ this._processInclude(includeInfo, localSearchPaths, filePath);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Process a single include directive.
91
+ */
92
+ private _processInclude(
93
+ includeInfo: { path: string; isLocal: boolean },
94
+ searchPaths: string[],
95
+ fromFile: string,
96
+ ): void {
97
+ const resolved = IncludeDiscovery.resolveInclude(
98
+ includeInfo.path,
99
+ searchPaths,
100
+ this.fs,
101
+ );
102
+
103
+ if (!resolved) {
104
+ // Only warn for local includes that couldn't be resolved
105
+ // System includes (like <stdio.h>) are expected to not be found
106
+ if (includeInfo.isLocal) {
107
+ this.warnings.push(
108
+ `Warning: #include "${includeInfo.path}" not found (from ${fromFile})`,
109
+ );
110
+ }
111
+ return;
112
+ }
113
+
114
+ const absolutePath = resolve(resolved);
115
+ if (this.visited.has(absolutePath)) return;
116
+
117
+ let headerContent: string;
118
+ try {
119
+ headerContent = this.fs.readFile(absolutePath);
120
+ } catch {
121
+ return;
122
+ }
123
+
124
+ // Check if this is a C-Next generated header
125
+ const sourcePath = CNextMarkerDetector.extractSourcePath(headerContent);
126
+ if (sourcePath) {
127
+ // New-style marker with source path
128
+ this._handleCNextMarker(sourcePath, absolutePath);
129
+ } else if (CNextMarkerDetector.isCNextGenerated(headerContent)) {
130
+ // Old-style marker without source path - treat as leaf node
131
+ // (we know it's C-Next generated but can't determine the source)
132
+ this.visited.add(absolutePath);
133
+ } else {
134
+ // Not a C-Next generated header - scan it for nested includes
135
+ this._scanFile(absolutePath);
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Handle a C-Next generation marker found in a header.
141
+ *
142
+ * Resolves the source path by first checking relative to the header location,
143
+ * then searching the include paths. This supports both default behavior (header
144
+ * next to source) and --header-out (header in separate directory).
145
+ */
146
+ private _handleCNextMarker(sourcePath: string, headerPath: string): void {
147
+ const headerDir = dirname(headerPath);
148
+ let absoluteSourcePath = resolve(join(headerDir, sourcePath));
149
+
150
+ // If not found next to header, search include paths (supports --header-out)
151
+ if (!this.fs.exists(absoluteSourcePath)) {
152
+ for (const searchPath of this.searchPaths) {
153
+ const candidate = resolve(join(searchPath, sourcePath));
154
+ if (this.fs.exists(candidate)) {
155
+ absoluteSourcePath = candidate;
156
+ break;
157
+ }
158
+ }
159
+ }
160
+
161
+ if (!this.fs.exists(absoluteSourcePath)) {
162
+ this.errors.push(
163
+ `C-Next source not found: ${sourcePath} (referenced by ${headerPath})`,
164
+ );
165
+ return;
166
+ }
167
+
168
+ this.cnextSources.add(absoluteSourcePath);
169
+ // Scan the .cnx file for its own includes (transitive discovery)
170
+ this._scanFile(absoluteSourcePath);
171
+ }
172
+ }
173
+
174
+ export default CppEntryPointScanner;
@@ -1,13 +1,11 @@
1
1
  /**
2
2
  * File Discovery
3
- * Scans directories for source files using fast-glob
3
+ * Classifies source files by type
4
4
  */
5
5
 
6
- import fg from "fast-glob";
7
6
  import { extname, resolve } from "node:path";
8
7
  import EFileType from "./types/EFileType";
9
8
  import IDiscoveredFile from "./types/IDiscoveredFile";
10
- import IDiscoveryOptions from "./types/IDiscoveryOptions";
11
9
  import IFileSystem from "../types/IFileSystem";
12
10
  import NodeFileSystem from "../NodeFileSystem";
13
11
 
@@ -31,34 +29,9 @@ const EXTENSION_MAP: Record<string, EFileType> = {
31
29
  };
32
30
 
33
31
  /**
34
- * Default ignore patterns for fast-glob
35
- * Issue #355: Exclude .pio/build (compiled artifacts) but allow .pio/libdeps (library headers)
36
- */
37
- const DEFAULT_IGNORE_GLOBS = [
38
- "**/node_modules/**",
39
- "**/.git/**",
40
- "**/.build/**",
41
- "**/.pio/build/**",
42
- ];
43
-
44
- /**
45
- * Discovers source files in directories
32
+ * Classifies and discovers source files
46
33
  */
47
34
  class FileDiscovery {
48
- /**
49
- * Convert RegExp patterns to glob ignore patterns
50
- */
51
- private static regexToGlob(pattern: RegExp): string {
52
- // Convert common patterns
53
- const src = pattern.source;
54
- if (src === "node_modules") return "**/node_modules/**";
55
- if (src === String.raw`\.git`) return "**/.git/**";
56
- if (src === String.raw`\.build`) return "**/.build/**";
57
- if (src === String.raw`\.pio[/\\]build`) return "**/.pio/build/**";
58
- // Fallback: wrap in wildcards
59
- return `**/*${src.replaceAll("\\", "")}*/**`;
60
- }
61
-
62
35
  /**
63
36
  * Classify a file path into a discovered file
64
37
  */
@@ -72,82 +45,6 @@ class FileDiscovery {
72
45
  };
73
46
  }
74
47
 
75
- /**
76
- * Discover files in the given directories
77
- *
78
- * Issue #331: Uses fast-glob's unique option to avoid duplicates
79
- * when overlapping directories are provided.
80
- *
81
- * Note: fast-glob accesses the filesystem directly; the fs parameter
82
- * is used only for directory existence checks.
83
- *
84
- * @param directories - Directories to scan
85
- * @param options - Discovery options
86
- * @param fs - File system abstraction (defaults to NodeFileSystem)
87
- */
88
- static discover(
89
- directories: string[],
90
- options: IDiscoveryOptions = {},
91
- fs: IFileSystem = defaultFs,
92
- ): IDiscoveredFile[] {
93
- const recursive = options.recursive ?? true;
94
- const extensions = options.extensions ?? Object.keys(EXTENSION_MAP);
95
-
96
- // Build ignore patterns
97
- let ignorePatterns: string[];
98
- if (options.excludePatterns) {
99
- ignorePatterns = options.excludePatterns.map((r) => this.regexToGlob(r));
100
- } else {
101
- ignorePatterns = DEFAULT_IGNORE_GLOBS;
102
- }
103
-
104
- // Build glob pattern for extensions
105
- const extPattern =
106
- extensions.length === 1
107
- ? `*${extensions[0]}`
108
- : `*{${extensions.join(",")}}`;
109
- const pattern = recursive ? `**/${extPattern}` : extPattern;
110
-
111
- const allFiles: IDiscoveredFile[] = [];
112
-
113
- for (const dir of directories) {
114
- const resolvedDir = resolve(dir);
115
-
116
- if (!fs.exists(resolvedDir)) {
117
- console.warn(`Warning: Directory not found: ${dir}`);
118
- continue;
119
- }
120
-
121
- try {
122
- // Use fast-glob to find files
123
- const files = fg.sync(pattern, {
124
- cwd: resolvedDir,
125
- absolute: true,
126
- ignore: ignorePatterns,
127
- deep: recursive ? Infinity : 1,
128
- onlyFiles: true,
129
- followSymbolicLinks: false,
130
- });
131
-
132
- for (const file of files) {
133
- allFiles.push(this.classifyFile(file));
134
- }
135
- } catch {
136
- console.warn(`Warning: Cannot read directory: ${dir}`);
137
- }
138
- }
139
-
140
- // Issue #331: Remove duplicates from overlapping directories
141
- const seenPaths = new Set<string>();
142
- return allFiles.filter((file) => {
143
- if (seenPaths.has(file.path)) {
144
- return false;
145
- }
146
- seenPaths.add(file.path);
147
- return true;
148
- });
149
- }
150
-
151
48
  /**
152
49
  * Discover a single file
153
50
  *
@@ -1,17 +1,24 @@
1
1
  import { resolve, extname, basename } from "node:path";
2
- import { existsSync, statSync, readdirSync } from "node:fs";
2
+ import { existsSync } from "node:fs";
3
3
 
4
4
  /**
5
5
  * Input expansion for C-Next CLI
6
6
  *
7
- * Expands file paths and directories into a list of .cnx files to compile.
8
- * Handles recursive directory scanning and file validation.
7
+ * Validates and resolves file paths for compilation.
9
8
  */
10
9
  class InputExpansion {
10
+ private static readonly CPP_EXTENSIONS = [
11
+ ".c",
12
+ ".cpp",
13
+ ".cc",
14
+ ".cxx",
15
+ ".c++",
16
+ ];
17
+ private static readonly CNEXT_EXTENSIONS = [".cnx", ".cnext"];
11
18
  /**
12
- * Expand inputs (files or directories) to list of .cnx files
19
+ * Expand inputs (files) to list of .cnx files
13
20
  *
14
- * @param inputs - Array of file paths or directories
21
+ * @param inputs - Array of file paths
15
22
  * @returns Array of .cnx file paths
16
23
  */
17
24
  static expandInputs(inputs: string[]): string[] {
@@ -24,75 +31,17 @@ class InputExpansion {
24
31
  throw new Error(`Input not found: ${input}`);
25
32
  }
26
33
 
27
- const stats = statSync(resolvedPath);
28
-
29
- if (stats.isDirectory()) {
30
- // Recursively find .cnx files
31
- const cnextFiles = this.findCNextFiles(resolvedPath);
32
- files.push(...cnextFiles);
33
- } else if (stats.isFile()) {
34
- // Validate and add file
35
- this.validateFileExtension(resolvedPath);
36
- files.push(resolvedPath);
37
- }
34
+ this.validateFileExtension(resolvedPath);
35
+ files.push(resolvedPath);
38
36
  }
39
37
 
40
- // Remove duplicates
41
38
  return Array.from(new Set(files));
42
39
  }
43
40
 
44
- /**
45
- * Recursively find .cnx files in directory
46
- *
47
- * @param dir - Directory to scan
48
- * @returns Array of .cnx file paths
49
- */
50
- static findCNextFiles(dir: string): string[] {
51
- const files: string[] = [];
52
-
53
- try {
54
- const entries = readdirSync(dir, { withFileTypes: true });
55
-
56
- for (const entry of entries) {
57
- const fullPath = resolve(dir, entry.name);
58
-
59
- // Skip hidden directories and common build/dependency directories
60
- if (entry.isDirectory()) {
61
- const dirName = entry.name;
62
- if (
63
- dirName.startsWith(".") ||
64
- dirName === "node_modules" ||
65
- dirName === "build" ||
66
- dirName === ".pio" ||
67
- dirName === "dist"
68
- ) {
69
- continue;
70
- }
71
-
72
- // Recursively scan subdirectory
73
- const subFiles = this.findCNextFiles(fullPath);
74
- files.push(...subFiles);
75
- } else if (entry.isFile()) {
76
- const ext = extname(entry.name);
77
- if (ext === ".cnx" || ext === ".cnext") {
78
- files.push(fullPath);
79
- }
80
- }
81
- }
82
- } catch (error) {
83
- throw new Error(`Failed to scan directory ${dir}: ${error}`, {
84
- cause: error,
85
- });
86
- }
87
-
88
- return files;
89
- }
90
-
91
41
  /**
92
42
  * Validate file extension
93
43
  *
94
- * Accepts: .cnx, .cnext
95
- * Rejects: .c, .cpp, .cc, .cxx, .c++ (implementation files)
44
+ * Accepts: .cnx, .cnext, .c, .cpp, .cc, .cxx, .c++
96
45
  *
97
46
  * @param path - File path to validate
98
47
  * @throws Error if extension is invalid
@@ -101,24 +50,31 @@ class InputExpansion {
101
50
  const ext = extname(path);
102
51
  const fileName = basename(path);
103
52
 
104
- // Reject implementation files
105
- const rejectedExtensions = [".c", ".cpp", ".cc", ".cxx", ".c++"];
106
- if (rejectedExtensions.includes(ext)) {
107
- throw new Error(
108
- `Cannot process implementation file '${fileName}'. ` +
109
- `C-Next only compiles .cnx files. ` +
110
- `If you need to include this file, create a header (.h) instead.`,
111
- );
53
+ // Accept C-Next source files
54
+ if (InputExpansion.CNEXT_EXTENSIONS.includes(ext)) {
55
+ return;
112
56
  }
113
57
 
114
- // Accept C-Next source files
115
- const acceptedExtensions = [".cnx", ".cnext"];
116
- if (!acceptedExtensions.includes(ext)) {
117
- throw new Error(
118
- `Invalid file extension '${ext}' for file '${fileName}'. ` +
119
- `C-Next only accepts .cnx or .cnext files.`,
120
- );
58
+ // Accept C/C++ entry point files
59
+ if (InputExpansion.CPP_EXTENSIONS.includes(ext)) {
60
+ return;
121
61
  }
62
+
63
+ throw new Error(
64
+ `Invalid file extension '${ext}' for file '${fileName}'. ` +
65
+ `C-Next only accepts .cnx, .cnext, .c, .cpp, .cc, .cxx, or .c++ files.`,
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Check if a file is a C/C++ entry point
71
+ *
72
+ * @param path - File path to check
73
+ * @returns true if the file has a C/C++ extension
74
+ */
75
+ static isCppEntryPoint(path: string): boolean {
76
+ const ext = extname(path);
77
+ return InputExpansion.CPP_EXTENSIONS.includes(ext);
122
78
  }
123
79
  }
124
80
 
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import CNextMarkerDetector from "../CNextMarkerDetector";
3
+
4
+ describe("CNextMarkerDetector", () => {
5
+ describe("extractSourcePath", () => {
6
+ it("should extract source path from valid marker", () => {
7
+ const content = `/**
8
+ * Generated by C-Next Transpiler from: led.cnx
9
+ * Header file for cross-language interoperability
10
+ */`;
11
+ expect(CNextMarkerDetector.extractSourcePath(content)).toBe("led.cnx");
12
+ });
13
+
14
+ it("should return null for header without marker", () => {
15
+ const content = `/**
16
+ * Some other header
17
+ */
18
+ #ifndef FOO_H
19
+ #define FOO_H`;
20
+ expect(CNextMarkerDetector.extractSourcePath(content)).toBeNull();
21
+ });
22
+
23
+ it("should return null for old-style marker without source path", () => {
24
+ const content = `/**
25
+ * Generated by C-Next Transpiler
26
+ * Header file for cross-language interoperability
27
+ */`;
28
+ expect(CNextMarkerDetector.extractSourcePath(content)).toBeNull();
29
+ });
30
+
31
+ it("should handle paths with directories", () => {
32
+ const content = `/**
33
+ * Generated by C-Next Transpiler from: ../lib/utils.cnx
34
+ */`;
35
+ expect(CNextMarkerDetector.extractSourcePath(content)).toBe(
36
+ "../lib/utils.cnx",
37
+ );
38
+ });
39
+ });
40
+
41
+ describe("isCNextGenerated", () => {
42
+ it("should return true for C-Next generated header", () => {
43
+ const content = `/**
44
+ * Generated by C-Next Transpiler from: led.cnx
45
+ */`;
46
+ expect(CNextMarkerDetector.isCNextGenerated(content)).toBe(true);
47
+ });
48
+
49
+ it("should return true for old-style marker", () => {
50
+ const content = `/**
51
+ * Generated by C-Next Transpiler
52
+ */`;
53
+ expect(CNextMarkerDetector.isCNextGenerated(content)).toBe(true);
54
+ });
55
+
56
+ it("should return false for non-generated header", () => {
57
+ const content = `#ifndef FOO_H
58
+ #define FOO_H`;
59
+ expect(CNextMarkerDetector.isCNextGenerated(content)).toBe(false);
60
+ });
61
+ });
62
+ });