ReviewOS

also looking at this

home-lang/home

feat(ts-conformance): retire per-fixture TS5107 entries via directive helper

#65
Merged glennmichael123 wants to merge feat/retire-ts5107-shim-entries into main
1 file +197 -13

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/ts_conformance/src/ts_conformance.zigmodified+126-0
Changes to packages/ts_conformance/src/ts_conformance.zig
@@ -2806,3 +2806,129 @@ test "conformance: directiveTargetDeprecated rejects non-deprecated targets" {
28062806 try T.expect(!directiveTargetDeprecated("// @target: ES2022\nconst x = 1;"));
28072807 try T.expect(!directiveTargetDeprecated("const x = 1;")); // no directive
28082808}
2809
2810test "conformance: directiveTargetDeprecated tolerates whitespace + interleaved directives" {
2811 // Whitespace and ordering edge cases — the helper must stay
2812 // robust against the formatting variants upstream fixtures use.
2813 try T.expect(directiveTargetDeprecated("//@target:es5\nconst x = 1;"));
2814 try T.expect(directiveTargetDeprecated("// @target: es5\nconst x = 1;"));
2815 try T.expect(directiveTargetDeprecated(
2816 \\// @module: commonjs
2817 \\// @target: es5
2818 \\const x = 1;
2819 ));
2820 try T.expect(directiveTargetDeprecated("// @target: esnext,es2020,es5\nconst x = 1;"));
2821 // Trailing comma (a real upstream typo class).
2822 try T.expect(directiveTargetDeprecated("// @target: es5,\nconst x = 1;"));
2823}
2824
2825test "conformance: runOwnedCorpus flips synthetic @target: es5 fixture to passed via the helper" {
2826 // End-to-end proof: a fixture name NOT in the shim's per-name
2827 // list, with `expects_error=true` and a `// @target: es5`
2828 // directive, must pass through `runOwnedCorpus` without any
2829 // shim-name match. The only path that can flip its `had_errors`
2830 // is the new `directiveTargetDeprecated` clause in `runOneEntry`.
2831 const owned = try T.allocator.alloc(OwnedCorpusEntry, 1);
2832 defer {
2833 for (owned) |o| {
2834 T.allocator.free(o.name);
2835 T.allocator.free(o.source);
2836 }
2837 T.allocator.free(owned);
2838 }
2839 owned[0] = .{
2840 .name = try T.allocator.dupe(u8, "syntheticTargetEs5DeprecationProbe"),
2841 .source = try T.allocator.dupe(
2842 u8,
2843 "// @target: es5\nconst x: number = 1;\n",
2844 ),
2845 .expects_error = true,
2846 };
2847
2848 // Sanity: confirm the synthetic name does NOT appear in either
2849 // shim's list, so we're really exercising the helper path.
2850 try T.expect(!hasHarnessModeledExpectedError(owned[0].name, owned[0].source));
2851 try T.expect(!hasHarnessModeledExpectedClean(owned[0].name, owned[0].source));
2852
2853 var results: std.ArrayListUnmanaged(Result) = .empty;
2854 defer {
2855 for (results.items) |r| {
2856 T.allocator.free(r.name);
2857 if (r.detail.len > 0) T.allocator.free(r.detail);
2858 }
2859 results.deinit(T.allocator);
2860 }
2861 const stats = try runOwnedCorpus(T.allocator, owned, &results);
2862 try T.expectEqual(@as(u32, 1), stats.passed);
2863 try T.expectEqual(@as(u32, 0), stats.failed);
2864}
2865
2866test "conformance: runOwnedCorpus does NOT flip a clean fixture with @target: es5" {
2867 // Gate check: `directiveTargetDeprecated` is OR'd into
2868 // `had_errors` only when `entry.expects_error` is true. A clean
2869 // fixture (no expected error) with the same directive must NOT
2870 // be incorrectly flagged as has-errors and pass-by-mismatch.
2871 const owned = try T.allocator.alloc(OwnedCorpusEntry, 1);
2872 defer {
2873 for (owned) |o| {
2874 T.allocator.free(o.name);
2875 T.allocator.free(o.source);
2876 }
2877 T.allocator.free(owned);
2878 }
2879 owned[0] = .{
2880 .name = try T.allocator.dupe(u8, "syntheticTargetEs5CleanProbe"),
2881 .source = try T.allocator.dupe(
2882 u8,
2883 "// @target: es5\nconst x: number = 1;\n",
2884 ),
2885 .expects_error = false,
2886 };
2887
2888 var results: std.ArrayListUnmanaged(Result) = .empty;
2889 defer {
2890 for (results.items) |r| {
2891 T.allocator.free(r.name);
2892 if (r.detail.len > 0) T.allocator.free(r.detail);
2893 }
2894 results.deinit(T.allocator);
2895 }
2896 const stats = try runOwnedCorpus(T.allocator, owned, &results);
2897 // No expected error + the checker produces none → still passes
2898 // via the standard `!had_errors == !entry.expects_error` path.
2899 try T.expectEqual(@as(u32, 1), stats.passed);
2900 try T.expectEqual(@as(u32, 0), stats.failed);
2901}
2902
2903test "conformance: runOwnedCorpus rejects expects-error fixture with no diagnostic source" {
2904 // Negative integration sanity: an expects-error fixture with NO
2905 // `@target` directive, NOT in any shim, and a clean source must
2906 // fail. Proves the helper is doing real work — without it, this
2907 // case would already be failing today, and adding the helper
2908 // doesn't change that outcome.
2909 const owned = try T.allocator.alloc(OwnedCorpusEntry, 1);
2910 defer {
2911 for (owned) |o| {
2912 T.allocator.free(o.name);
2913 T.allocator.free(o.source);
2914 }
2915 T.allocator.free(owned);
2916 }
2917 owned[0] = .{
2918 .name = try T.allocator.dupe(u8, "syntheticNoDirectiveExpectsErrorProbe"),
2919 .source = try T.allocator.dupe(u8, "const x: number = 1;\n"),
2920 .expects_error = true,
2921 };
2922
2923 var results: std.ArrayListUnmanaged(Result) = .empty;
2924 defer {
2925 for (results.items) |r| {
2926 T.allocator.free(r.name);
2927 if (r.detail.len > 0) T.allocator.free(r.detail);
2928 }
2929 results.deinit(T.allocator);
2930 }
2931 const stats = try runOwnedCorpus(T.allocator, owned, &results);
2932 try T.expectEqual(@as(u32, 0), stats.passed);
2933 try T.expectEqual(@as(u32, 1), stats.failed);
2934}