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.
- package/README.md +80 -649
- package/dist/index.js +7387 -6211
- package/dist/index.js.map +4 -4
- package/grammar/C.g4 +9 -3
- package/package.json +1 -2
- package/src/__tests__/index.test.ts +1 -1
- package/src/cli/CleanCommand.ts +8 -12
- package/src/cli/Cli.ts +29 -6
- package/src/cli/Runner.ts +42 -62
- package/src/cli/__tests__/CleanCommand.test.ts +10 -10
- package/src/cli/__tests__/Cli.test.ts +59 -7
- package/src/cli/__tests__/ConfigPrinter.test.ts +12 -12
- package/src/cli/__tests__/PathNormalizer.test.ts +5 -5
- package/src/cli/__tests__/Runner.test.ts +108 -82
- package/src/cli/serve/ServeCommand.ts +1 -1
- package/src/cli/types/ICliConfig.ts +2 -2
- package/src/lib/parseWithSymbols.ts +21 -21
- package/src/transpiler/Transpiler.ts +88 -43
- package/src/transpiler/__tests__/DualCodePaths.test.ts +29 -29
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +244 -72
- package/src/transpiler/__tests__/Transpiler.test.ts +32 -72
- package/src/transpiler/__tests__/determineProjectRoot.test.ts +30 -28
- package/src/transpiler/__tests__/needsConditionalPreprocessing.test.ts +1 -1
- package/src/transpiler/data/CNextMarkerDetector.ts +34 -0
- package/src/transpiler/data/CppEntryPointScanner.ts +174 -0
- package/src/transpiler/data/FileDiscovery.ts +2 -105
- package/src/transpiler/data/InputExpansion.ts +37 -81
- package/src/transpiler/data/__tests__/CNextMarkerDetector.test.ts +62 -0
- package/src/transpiler/data/__tests__/CppEntryPointScanner.test.ts +239 -0
- package/src/transpiler/data/__tests__/FileDiscovery.test.ts +45 -191
- package/src/transpiler/data/__tests__/InputExpansion.test.ts +36 -204
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +2 -2
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +4 -5
- package/src/transpiler/logic/parser/c/grammar/C.interp +19 -1
- package/src/transpiler/logic/parser/c/grammar/C.tokens +231 -213
- package/src/transpiler/logic/parser/c/grammar/CLexer.interp +28 -1
- package/src/transpiler/logic/parser/c/grammar/CLexer.tokens +231 -213
- package/src/transpiler/logic/parser/c/grammar/CLexer.ts +654 -600
- package/src/transpiler/logic/parser/c/grammar/CParser.ts +1175 -1099
- package/src/transpiler/logic/symbols/SymbolTable.ts +19 -7
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +78 -0
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +6 -6
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +28 -27
- package/src/transpiler/logic/symbols/cnext/index.ts +4 -4
- package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +5 -5
- package/src/transpiler/output/codegen/CodeGenerator.ts +7 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +15 -0
- package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +3 -3
- package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +14 -14
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +7 -7
- package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +3 -3
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +10 -1
- package/src/transpiler/output/headers/HeaderGenerator.ts +3 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +6 -2
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +16 -0
- package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +19 -19
- package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +5 -5
- package/src/transpiler/state/SymbolRegistry.ts +10 -12
- package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +11 -13
- package/src/transpiler/types/IPipelineFile.ts +3 -0
- package/src/transpiler/types/ITranspilerConfig.ts +2 -2
- package/src/transpiler/types/symbols/IScopeSymbol.ts +1 -1
- package/src/utils/FunctionUtils.ts +3 -3
- package/src/utils/__tests__/FunctionUtils.test.ts +6 -4
- package/src/transpiler/data/types/IDiscoveryOptions.ts +0 -15
|
@@ -21,10 +21,7 @@ describe("Transpiler", () => {
|
|
|
21
21
|
// because it doesn't rely on FileDiscovery for the main code path
|
|
22
22
|
|
|
23
23
|
it("transpiles source string without file I/O", async () => {
|
|
24
|
-
const transpiler = new Transpiler(
|
|
25
|
-
{ inputs: [], noCache: true },
|
|
26
|
-
mockFs,
|
|
27
|
-
);
|
|
24
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
28
25
|
|
|
29
26
|
const result = (
|
|
30
27
|
await transpiler.transpile({
|
|
@@ -39,10 +36,7 @@ describe("Transpiler", () => {
|
|
|
39
36
|
});
|
|
40
37
|
|
|
41
38
|
it("returns parse errors for invalid source", async () => {
|
|
42
|
-
const transpiler = new Transpiler(
|
|
43
|
-
{ inputs: [], noCache: true },
|
|
44
|
-
mockFs,
|
|
45
|
-
);
|
|
39
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
46
40
|
|
|
47
41
|
const result = await transpiler.transpile({
|
|
48
42
|
kind: "source",
|
|
@@ -54,10 +48,7 @@ describe("Transpiler", () => {
|
|
|
54
48
|
});
|
|
55
49
|
|
|
56
50
|
it("generates header code for exported functions", async () => {
|
|
57
|
-
const transpiler = new Transpiler(
|
|
58
|
-
{ inputs: [], noCache: true },
|
|
59
|
-
mockFs,
|
|
60
|
-
);
|
|
51
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
61
52
|
|
|
62
53
|
const result = (
|
|
63
54
|
await transpiler.transpile({
|
|
@@ -76,10 +67,7 @@ describe("Transpiler", () => {
|
|
|
76
67
|
});
|
|
77
68
|
|
|
78
69
|
it("returns undefined headerCode when no exports", async () => {
|
|
79
|
-
const transpiler = new Transpiler(
|
|
80
|
-
{ inputs: [], noCache: true },
|
|
81
|
-
mockFs,
|
|
82
|
-
);
|
|
70
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
83
71
|
|
|
84
72
|
const result = (
|
|
85
73
|
await transpiler.transpile({
|
|
@@ -94,7 +82,7 @@ describe("Transpiler", () => {
|
|
|
94
82
|
|
|
95
83
|
it("respects parseOnly mode", async () => {
|
|
96
84
|
const transpiler = new Transpiler(
|
|
97
|
-
{
|
|
85
|
+
{ input: "", parseOnly: true, noCache: true },
|
|
98
86
|
mockFs,
|
|
99
87
|
);
|
|
100
88
|
|
|
@@ -110,10 +98,7 @@ describe("Transpiler", () => {
|
|
|
110
98
|
});
|
|
111
99
|
|
|
112
100
|
it("handles code generation errors gracefully", async () => {
|
|
113
|
-
const transpiler = new Transpiler(
|
|
114
|
-
{ inputs: [], noCache: true },
|
|
115
|
-
mockFs,
|
|
116
|
-
);
|
|
101
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
117
102
|
|
|
118
103
|
// This should parse but might have semantic issues
|
|
119
104
|
const result = (
|
|
@@ -128,10 +113,7 @@ describe("Transpiler", () => {
|
|
|
128
113
|
});
|
|
129
114
|
|
|
130
115
|
it("reports narrowing error at the correct line", async () => {
|
|
131
|
-
const transpiler = new Transpiler(
|
|
132
|
-
{ inputs: [], noCache: true },
|
|
133
|
-
mockFs,
|
|
134
|
-
);
|
|
116
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
135
117
|
|
|
136
118
|
const result = (
|
|
137
119
|
await transpiler.transpile({
|
|
@@ -148,10 +130,7 @@ describe("Transpiler", () => {
|
|
|
148
130
|
});
|
|
149
131
|
|
|
150
132
|
it("defaults to line 1 for errors without location info", async () => {
|
|
151
|
-
const transpiler = new Transpiler(
|
|
152
|
-
{ inputs: [], noCache: true },
|
|
153
|
-
mockFs,
|
|
154
|
-
);
|
|
133
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
155
134
|
|
|
156
135
|
// Ternary with bare variable produces error without line prefix
|
|
157
136
|
const result = (
|
|
@@ -168,10 +147,7 @@ describe("Transpiler", () => {
|
|
|
168
147
|
});
|
|
169
148
|
|
|
170
149
|
it("transpiles various C-Next types correctly", async () => {
|
|
171
|
-
const transpiler = new Transpiler(
|
|
172
|
-
{ inputs: [], noCache: true },
|
|
173
|
-
mockFs,
|
|
174
|
-
);
|
|
150
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
175
151
|
|
|
176
152
|
const result = (
|
|
177
153
|
await transpiler.transpile({
|
|
@@ -201,10 +177,7 @@ describe("Transpiler", () => {
|
|
|
201
177
|
});
|
|
202
178
|
|
|
203
179
|
it("handles assignment operator correctly", async () => {
|
|
204
|
-
const transpiler = new Transpiler(
|
|
205
|
-
{ inputs: [], noCache: true },
|
|
206
|
-
mockFs,
|
|
207
|
-
);
|
|
180
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
208
181
|
|
|
209
182
|
const result = (
|
|
210
183
|
await transpiler.transpile({
|
|
@@ -223,10 +196,7 @@ describe("Transpiler", () => {
|
|
|
223
196
|
});
|
|
224
197
|
|
|
225
198
|
it("handles equality operator correctly", async () => {
|
|
226
|
-
const transpiler = new Transpiler(
|
|
227
|
-
{ inputs: [], noCache: true },
|
|
228
|
-
mockFs,
|
|
229
|
-
);
|
|
199
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
230
200
|
|
|
231
201
|
const result = (
|
|
232
202
|
await transpiler.transpile({
|
|
@@ -244,10 +214,7 @@ describe("Transpiler", () => {
|
|
|
244
214
|
});
|
|
245
215
|
|
|
246
216
|
it("generates struct definitions", async () => {
|
|
247
|
-
const transpiler = new Transpiler(
|
|
248
|
-
{ inputs: [], noCache: true },
|
|
249
|
-
mockFs,
|
|
250
|
-
);
|
|
217
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
251
218
|
|
|
252
219
|
const result = (
|
|
253
220
|
await transpiler.transpile({
|
|
@@ -268,10 +235,7 @@ describe("Transpiler", () => {
|
|
|
268
235
|
});
|
|
269
236
|
|
|
270
237
|
it("generates enum definitions", async () => {
|
|
271
|
-
const transpiler = new Transpiler(
|
|
272
|
-
{ inputs: [], noCache: true },
|
|
273
|
-
mockFs,
|
|
274
|
-
);
|
|
238
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
275
239
|
|
|
276
240
|
const result = (
|
|
277
241
|
await transpiler.transpile({
|
|
@@ -294,10 +258,7 @@ describe("Transpiler", () => {
|
|
|
294
258
|
});
|
|
295
259
|
|
|
296
260
|
it("handles scope definitions", async () => {
|
|
297
|
-
const transpiler = new Transpiler(
|
|
298
|
-
{ inputs: [], noCache: true },
|
|
299
|
-
mockFs,
|
|
300
|
-
);
|
|
261
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
301
262
|
|
|
302
263
|
const result = (
|
|
303
264
|
await transpiler.transpile({
|
|
@@ -326,7 +287,7 @@ describe("Transpiler", () => {
|
|
|
326
287
|
|
|
327
288
|
const transpiler = new Transpiler(
|
|
328
289
|
{
|
|
329
|
-
|
|
290
|
+
input: "/project/src/main.cnx",
|
|
330
291
|
outDir: "/project/build",
|
|
331
292
|
noCache: true,
|
|
332
293
|
},
|
|
@@ -349,7 +310,7 @@ describe("Transpiler", () => {
|
|
|
349
310
|
|
|
350
311
|
const transpiler = new Transpiler(
|
|
351
312
|
{
|
|
352
|
-
|
|
313
|
+
input: "/project/src/main.cnx",
|
|
353
314
|
outDir: "/project/build",
|
|
354
315
|
noCache: true,
|
|
355
316
|
},
|
|
@@ -367,7 +328,7 @@ describe("Transpiler", () => {
|
|
|
367
328
|
|
|
368
329
|
const transpiler = new Transpiler(
|
|
369
330
|
{
|
|
370
|
-
|
|
331
|
+
input: "/project/src/main.cnx",
|
|
371
332
|
outDir: "/project/build",
|
|
372
333
|
headerOutDir: "/project/include",
|
|
373
334
|
noCache: true,
|
|
@@ -395,7 +356,7 @@ describe("Transpiler", () => {
|
|
|
395
356
|
|
|
396
357
|
const transpiler = new Transpiler(
|
|
397
358
|
{
|
|
398
|
-
|
|
359
|
+
input: "/project/src/lib.cnx",
|
|
399
360
|
outDir: "/project/build",
|
|
400
361
|
noCache: true,
|
|
401
362
|
},
|
|
@@ -412,10 +373,10 @@ describe("Transpiler", () => {
|
|
|
412
373
|
expect(hFile?.content).toContain("Math_add");
|
|
413
374
|
});
|
|
414
375
|
|
|
415
|
-
it("returns
|
|
376
|
+
it("returns no files for non-existent input", async () => {
|
|
416
377
|
const transpiler = new Transpiler(
|
|
417
378
|
{
|
|
418
|
-
|
|
379
|
+
input: "/nonexistent/file.cnx",
|
|
419
380
|
noCache: true,
|
|
420
381
|
},
|
|
421
382
|
mockFs,
|
|
@@ -423,8 +384,7 @@ describe("Transpiler", () => {
|
|
|
423
384
|
|
|
424
385
|
const result = await transpiler.transpile({ kind: "files" });
|
|
425
386
|
|
|
426
|
-
expect(result.
|
|
427
|
-
expect(result.errors[0].message).toContain("Input not found");
|
|
387
|
+
expect(result.filesProcessed).toBe(0);
|
|
428
388
|
});
|
|
429
389
|
|
|
430
390
|
it("returns warning when no C-Next files found", async () => {
|
|
@@ -432,7 +392,7 @@ describe("Transpiler", () => {
|
|
|
432
392
|
|
|
433
393
|
const transpiler = new Transpiler(
|
|
434
394
|
{
|
|
435
|
-
|
|
395
|
+
input: "/project/empty",
|
|
436
396
|
noCache: true,
|
|
437
397
|
},
|
|
438
398
|
mockFs,
|
|
@@ -448,7 +408,7 @@ describe("Transpiler", () => {
|
|
|
448
408
|
|
|
449
409
|
const transpiler = new Transpiler(
|
|
450
410
|
{
|
|
451
|
-
|
|
411
|
+
input: "/project/src/invalid.cnx",
|
|
452
412
|
noCache: true,
|
|
453
413
|
},
|
|
454
414
|
mockFs,
|
|
@@ -480,7 +440,7 @@ describe("Transpiler", () => {
|
|
|
480
440
|
writeFileSync(testFile, "u32 getValue() { return 42; }");
|
|
481
441
|
|
|
482
442
|
const transpiler = new Transpiler({
|
|
483
|
-
|
|
443
|
+
input: testFile,
|
|
484
444
|
outDir: testDir,
|
|
485
445
|
noCache: true,
|
|
486
446
|
});
|
|
@@ -497,7 +457,7 @@ describe("Transpiler", () => {
|
|
|
497
457
|
writeFileSync(testFile, "void foo( { }");
|
|
498
458
|
|
|
499
459
|
const transpiler = new Transpiler({
|
|
500
|
-
|
|
460
|
+
input: testFile,
|
|
501
461
|
noCache: true,
|
|
502
462
|
});
|
|
503
463
|
|
|
@@ -513,7 +473,7 @@ describe("Transpiler", () => {
|
|
|
513
473
|
writeFileSync(testFile, "void foo() {\n @@@invalid\n}");
|
|
514
474
|
|
|
515
475
|
const transpiler = new Transpiler({
|
|
516
|
-
|
|
476
|
+
input: testFile,
|
|
517
477
|
noCache: true,
|
|
518
478
|
});
|
|
519
479
|
|
|
@@ -530,7 +490,7 @@ describe("Transpiler", () => {
|
|
|
530
490
|
writeFileSync(testFile, "@@@ $$$ %%%");
|
|
531
491
|
|
|
532
492
|
const transpiler = new Transpiler({
|
|
533
|
-
|
|
493
|
+
input: testFile,
|
|
534
494
|
noCache: true,
|
|
535
495
|
});
|
|
536
496
|
|
|
@@ -546,7 +506,7 @@ describe("Transpiler", () => {
|
|
|
546
506
|
writeFileSync(testFile, "void main() { }");
|
|
547
507
|
|
|
548
508
|
const transpiler = new Transpiler({
|
|
549
|
-
|
|
509
|
+
input: testFile,
|
|
550
510
|
outDir: outputDir,
|
|
551
511
|
noCache: true,
|
|
552
512
|
});
|
|
@@ -569,7 +529,7 @@ describe("Transpiler", () => {
|
|
|
569
529
|
);
|
|
570
530
|
|
|
571
531
|
const transpiler = new Transpiler({
|
|
572
|
-
|
|
532
|
+
input: testFile,
|
|
573
533
|
outDir: testDir,
|
|
574
534
|
noCache: true,
|
|
575
535
|
});
|
|
@@ -592,7 +552,7 @@ describe("Transpiler", () => {
|
|
|
592
552
|
});
|
|
593
553
|
|
|
594
554
|
it("transpile({ kind: 'source' }) returns ITranspilerResult with files[]", async () => {
|
|
595
|
-
const transpiler = new Transpiler({
|
|
555
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
596
556
|
|
|
597
557
|
const result = await transpiler.transpile({
|
|
598
558
|
kind: "source",
|
|
@@ -604,7 +564,7 @@ describe("Transpiler", () => {
|
|
|
604
564
|
});
|
|
605
565
|
|
|
606
566
|
it("transpile({ kind: 'source' }) returns header in files[0].headerCode", async () => {
|
|
607
|
-
const transpiler = new Transpiler({
|
|
567
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
608
568
|
|
|
609
569
|
const result = await transpiler.transpile({
|
|
610
570
|
kind: "source",
|
|
@@ -619,7 +579,7 @@ describe("Transpiler", () => {
|
|
|
619
579
|
});
|
|
620
580
|
|
|
621
581
|
it("transpile({ kind: 'source' }) returns errors in result", async () => {
|
|
622
|
-
const transpiler = new Transpiler({
|
|
582
|
+
const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
|
|
623
583
|
|
|
624
584
|
const result = await transpiler.transpile({
|
|
625
585
|
kind: "source",
|
|
@@ -42,7 +42,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
42
42
|
describe("no inputs", () => {
|
|
43
43
|
it("returns undefined when inputs array is empty", () => {
|
|
44
44
|
const transpiler = new Transpiler({
|
|
45
|
-
|
|
45
|
+
input: "",
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
expect(getProjectRoot(transpiler)).toBeUndefined();
|
|
@@ -50,7 +50,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
50
50
|
|
|
51
51
|
it("disables caching when inputs array is empty", () => {
|
|
52
52
|
const transpiler = new Transpiler({
|
|
53
|
-
|
|
53
|
+
input: "",
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
expect(hasCacheManager(transpiler)).toBe(false);
|
|
@@ -66,7 +66,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
66
66
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
67
67
|
|
|
68
68
|
const transpiler = new Transpiler({
|
|
69
|
-
|
|
69
|
+
input: join(projectDir, "main.cnx"),
|
|
70
70
|
noCache: true, // Disable cache to avoid side effects
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -82,7 +82,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
82
82
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
83
83
|
|
|
84
84
|
const transpiler = new Transpiler({
|
|
85
|
-
|
|
85
|
+
input: join(srcDir, "main.cnx"),
|
|
86
86
|
noCache: true,
|
|
87
87
|
});
|
|
88
88
|
|
|
@@ -97,7 +97,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
97
97
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
98
98
|
|
|
99
99
|
const transpiler = new Transpiler({
|
|
100
|
-
|
|
100
|
+
input: join(srcDir, "main.cnx"),
|
|
101
101
|
noCache: true,
|
|
102
102
|
});
|
|
103
103
|
|
|
@@ -112,7 +112,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
112
112
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
113
113
|
|
|
114
114
|
const transpiler = new Transpiler({
|
|
115
|
-
|
|
115
|
+
input: join(srcDir, "main.cnx"),
|
|
116
116
|
noCache: true,
|
|
117
117
|
});
|
|
118
118
|
|
|
@@ -127,7 +127,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
127
127
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
128
128
|
|
|
129
129
|
const transpiler = new Transpiler({
|
|
130
|
-
|
|
130
|
+
input: join(srcDir, "main.cnx"),
|
|
131
131
|
noCache: true,
|
|
132
132
|
});
|
|
133
133
|
|
|
@@ -142,7 +142,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
142
142
|
writeFileSync(join(deepDir, "helper.cnx"), "void helper() {}");
|
|
143
143
|
|
|
144
144
|
const transpiler = new Transpiler({
|
|
145
|
-
|
|
145
|
+
input: join(deepDir, "helper.cnx"),
|
|
146
146
|
noCache: true,
|
|
147
147
|
});
|
|
148
148
|
|
|
@@ -159,7 +159,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
159
159
|
// Note: newfile.cnx does NOT exist
|
|
160
160
|
|
|
161
161
|
const transpiler = new Transpiler({
|
|
162
|
-
|
|
162
|
+
input: join(srcDir, "newfile.cnx"),
|
|
163
163
|
noCache: true,
|
|
164
164
|
});
|
|
165
165
|
|
|
@@ -173,7 +173,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
173
173
|
// Note: the nested directories and file do NOT exist
|
|
174
174
|
|
|
175
175
|
const transpiler = new Transpiler({
|
|
176
|
-
|
|
176
|
+
input: join(projectDir, "src", "deep", "nested", "file.cnx"),
|
|
177
177
|
noCache: true,
|
|
178
178
|
});
|
|
179
179
|
|
|
@@ -181,28 +181,30 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
181
181
|
});
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
describe("input
|
|
185
|
-
it("
|
|
184
|
+
describe("input file in project root", () => {
|
|
185
|
+
it("finds marker in same directory as input file", () => {
|
|
186
186
|
const projectDir = join(testDir, "project");
|
|
187
187
|
mkdirSync(projectDir, { recursive: true });
|
|
188
188
|
writeFileSync(join(projectDir, "cnext.config.json"), "{}");
|
|
189
|
+
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
189
190
|
|
|
190
191
|
const transpiler = new Transpiler({
|
|
191
|
-
|
|
192
|
+
input: join(projectDir, "main.cnx"),
|
|
192
193
|
noCache: true,
|
|
193
194
|
});
|
|
194
195
|
|
|
195
196
|
expect(getProjectRoot(transpiler)).toBe(projectDir);
|
|
196
197
|
});
|
|
197
198
|
|
|
198
|
-
it("finds marker in parent when input is
|
|
199
|
+
it("finds marker in parent when input file is in subdirectory", () => {
|
|
199
200
|
const projectDir = join(testDir, "project");
|
|
200
201
|
const srcDir = join(projectDir, "src");
|
|
201
202
|
mkdirSync(srcDir, { recursive: true });
|
|
202
203
|
writeFileSync(join(projectDir, "cnext.config.json"), "{}");
|
|
204
|
+
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
203
205
|
|
|
204
206
|
const transpiler = new Transpiler({
|
|
205
|
-
|
|
207
|
+
input: join(srcDir, "main.cnx"),
|
|
206
208
|
noCache: true,
|
|
207
209
|
});
|
|
208
210
|
|
|
@@ -220,7 +222,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
220
222
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
221
223
|
|
|
222
224
|
const transpiler = new Transpiler({
|
|
223
|
-
|
|
225
|
+
input: join(projectDir, "main.cnx"),
|
|
224
226
|
noCache: true,
|
|
225
227
|
});
|
|
226
228
|
|
|
@@ -238,7 +240,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
238
240
|
writeFileSync(join(innerDir, "main.cnx"), "void main() {}");
|
|
239
241
|
|
|
240
242
|
const transpiler = new Transpiler({
|
|
241
|
-
|
|
243
|
+
input: join(innerDir, "main.cnx"),
|
|
242
244
|
noCache: true,
|
|
243
245
|
});
|
|
244
246
|
|
|
@@ -257,7 +259,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
257
259
|
writeFileSync(join(isolatedDir, "orphan.cnx"), "void orphan() {}");
|
|
258
260
|
|
|
259
261
|
const transpiler = new Transpiler({
|
|
260
|
-
|
|
262
|
+
input: join(isolatedDir, "orphan.cnx"),
|
|
261
263
|
noCache: true,
|
|
262
264
|
});
|
|
263
265
|
|
|
@@ -280,7 +282,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
280
282
|
// This is hard to test in practice because we're inside the c-next repo
|
|
281
283
|
// We can at least verify the noCache flag works
|
|
282
284
|
const transpiler = new Transpiler({
|
|
283
|
-
|
|
285
|
+
input: join(testDir, "some.cnx"),
|
|
284
286
|
noCache: true,
|
|
285
287
|
});
|
|
286
288
|
|
|
@@ -296,7 +298,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
296
298
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
297
299
|
|
|
298
300
|
const transpiler = new Transpiler({
|
|
299
|
-
|
|
301
|
+
input: join(projectDir, "main.cnx"),
|
|
300
302
|
noCache: true,
|
|
301
303
|
});
|
|
302
304
|
|
|
@@ -313,7 +315,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
313
315
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
314
316
|
|
|
315
317
|
const transpiler = new Transpiler({
|
|
316
|
-
|
|
318
|
+
input: join(projectDir, "main.cnx"),
|
|
317
319
|
noCache: false,
|
|
318
320
|
});
|
|
319
321
|
|
|
@@ -333,7 +335,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
333
335
|
const relativePath = join("test-project-root-tmp", "project", "main.cnx");
|
|
334
336
|
|
|
335
337
|
const transpiler = new Transpiler({
|
|
336
|
-
|
|
338
|
+
input: relativePath,
|
|
337
339
|
noCache: true,
|
|
338
340
|
});
|
|
339
341
|
|
|
@@ -352,7 +354,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
352
354
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
353
355
|
|
|
354
356
|
const transpiler = new Transpiler({
|
|
355
|
-
|
|
357
|
+
input: join(srcDir, "main.cnx"),
|
|
356
358
|
noCache: true,
|
|
357
359
|
});
|
|
358
360
|
|
|
@@ -367,7 +369,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
367
369
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
368
370
|
|
|
369
371
|
const transpiler = new Transpiler({
|
|
370
|
-
|
|
372
|
+
input: join(projectDir, "main.cnx"),
|
|
371
373
|
noCache: true,
|
|
372
374
|
});
|
|
373
375
|
|
|
@@ -385,7 +387,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
385
387
|
writeFileSync(join(project2, "b.cnx"), "void b() {}");
|
|
386
388
|
|
|
387
389
|
const transpiler = new Transpiler({
|
|
388
|
-
|
|
390
|
+
input: join(project1, "a.cnx"),
|
|
389
391
|
noCache: true,
|
|
390
392
|
});
|
|
391
393
|
|
|
@@ -400,7 +402,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
400
402
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
401
403
|
|
|
402
404
|
const transpiler = new Transpiler({
|
|
403
|
-
|
|
405
|
+
input: join(projectDir, "main.cnx"),
|
|
404
406
|
noCache: true,
|
|
405
407
|
});
|
|
406
408
|
|
|
@@ -417,7 +419,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
417
419
|
writeFileSync(join(srcDir, "main.cnx"), "void main() {}");
|
|
418
420
|
|
|
419
421
|
const transpiler = new Transpiler({
|
|
420
|
-
|
|
422
|
+
input: join(srcDir, "main.cnx"),
|
|
421
423
|
noCache: false,
|
|
422
424
|
});
|
|
423
425
|
|
|
@@ -436,7 +438,7 @@ describe("Transpiler.determineProjectRoot", () => {
|
|
|
436
438
|
writeFileSync(join(projectDir, "main.cnx"), "void main() {}");
|
|
437
439
|
|
|
438
440
|
const transpiler = new Transpiler({
|
|
439
|
-
|
|
441
|
+
input: join(projectDir, "main.cnx"),
|
|
440
442
|
noCache: true,
|
|
441
443
|
});
|
|
442
444
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects C-Next generation markers in header files.
|
|
3
|
+
*
|
|
4
|
+
* Used by the C/C++ entry point feature to discover which headers
|
|
5
|
+
* were generated from .cnx source files.
|
|
6
|
+
*/
|
|
7
|
+
class CNextMarkerDetector {
|
|
8
|
+
/**
|
|
9
|
+
* Regex to extract source path from generation marker.
|
|
10
|
+
* Matches: "Generated by C-Next Transpiler from: <path>"
|
|
11
|
+
*/
|
|
12
|
+
private static readonly SOURCE_PATH_REGEX =
|
|
13
|
+
/Generated by C-Next Transpiler from:\s*(\S+)/;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if content contains any C-Next generation marker.
|
|
17
|
+
*/
|
|
18
|
+
static isCNextGenerated(content: string): boolean {
|
|
19
|
+
return content.includes("Generated by C-Next Transpiler");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extract the source .cnx path from a C-Next generation marker.
|
|
24
|
+
*
|
|
25
|
+
* @param content - File content (typically first 500 chars is sufficient)
|
|
26
|
+
* @returns The source path (e.g., "led.cnx") or null if no marker found
|
|
27
|
+
*/
|
|
28
|
+
static extractSourcePath(content: string): string | null {
|
|
29
|
+
const match = this.SOURCE_PATH_REGEX.exec(content);
|
|
30
|
+
return match ? match[1] : null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default CNextMarkerDetector;
|