@samitouri / QOS-React-1 / commits / 5669fc73c0

[snap] Refactor fixture utils to separate package

--- Move shared functions to `fixture-test-utils` package.

Mofei Zhang committed Aug 14, 2023 at 19:26 UTC 5669fc73c0d0ac00d744e22b067bcfc3312b8314
11 files changed +375 -309
compiler/forget/packages/fixture-test-utils/package.json new
+25
@@ -0,0 +1,25 @@
1 +{
2 + "name": "fixture-test-utils",
3 + "version": "1.0.0",
4 + "main": "dist/index.js",
5 + "license": "MIT",
6 + "scripts": {
7 + "build": "rimraf dist && tsc",
8 + "test": "echo 'no tests'",
9 + "prettier": "prettier --write src"
10 + },
11 + "dependencies": {
12 + "@parcel/watcher": "^2.1.0",
13 + "chalk": "4",
14 + "readline": "^1.3.0",
15 + "typescript": "^5.1.0",
16 + "yargs": "^17.7.1"
17 + },
18 + "devDependencies": {
19 + "@types/node": "^18.7.18",
20 + "@typescript-eslint/eslint-plugin": "^5.51.0",
21 + "@typescript-eslint/parser": "^5.51.0",
22 + "prettier": "2.8.8",
23 + "rimraf": "^3.0.2"
24 + }
25 +}
compiler/forget/packages/fixture-test-utils/src/compiler-utils.ts new
+122
@@ -0,0 +1,122 @@
1 +import type { runReactForgetBabelPlugin as RunReactForgetBabelPlugin } from "babel-plugin-react-forget/src/Babel/RunReactForgetBabelPlugin";
2 +import type { Effect, ValueKind } from "babel-plugin-react-forget/src/HIR";
3 +
4 +const FlowPragmas = [/\/\/\s@flow$/gm, /\*\s@flow$/gm];
5 +
6 +export function parseLanguage(source: string): "flow" | "typescript" {
7 + let useFlow = false;
8 + for (const flowPragma of FlowPragmas) {
9 + useFlow ||= !!source.match(flowPragma);
10 + }
11 + return useFlow ? "flow" : "typescript";
12 +}
13 +
14 +export function transformFixtureInput(
15 + input: string,
16 + basename: string,
17 + pluginFn: typeof RunReactForgetBabelPlugin,
18 + includeAst: boolean = false
19 +) {
20 + // Extract the first line to quickly check for custom test directives
21 + const firstLine = input.substring(0, input.indexOf("\n"));
22 +
23 + let language = parseLanguage(firstLine);
24 + let enableOnlyOnUseForgetDirective = false;
25 + let gating = null;
26 + let instrumentForget = null;
27 + let panicOnBailout = true;
28 + let memoizeJsxElements = true;
29 + let enableAssumeHooksFollowRulesOfReact = false;
30 + let enableTreatHooksAsFunctions = true;
31 + let disableAllMemoization = false;
32 + let validateRefAccessDuringRender = true;
33 + let validateNoSetStateInRender = true;
34 + let enableEmitFreeze = null;
35 + let enableOptimizeFunctionExpressions = true;
36 + let enableOnlyOnReactScript = false;
37 +
38 + if (firstLine.indexOf("@forgetDirective") !== -1) {
39 + enableOnlyOnUseForgetDirective = true;
40 + }
41 + if (firstLine.includes("@gating")) {
42 + gating = {
43 + source: "ReactForgetFeatureFlag",
44 + importSpecifierName: "isForgetEnabled_Fixtures",
45 + };
46 + }
47 + if (firstLine.includes("@instrumentForget")) {
48 + instrumentForget = {
49 + source: "react-forget-runtime",
50 + importSpecifierName: "useRenderCounter",
51 + };
52 + }
53 + if (firstLine.includes("@panicOnBailout false")) {
54 + panicOnBailout = false;
55 + }
56 + if (firstLine.includes("@memoizeJsxElements false")) {
57 + memoizeJsxElements = false;
58 + }
59 + if (firstLine.includes("@enableAssumeHooksFollowRulesOfReact true")) {
60 + enableAssumeHooksFollowRulesOfReact = true;
61 + }
62 + if (firstLine.includes("@enableTreatHooksAsFunctions false")) {
63 + enableTreatHooksAsFunctions = false;
64 + }
65 + if (firstLine.includes("@disableAllMemoization true")) {
66 + disableAllMemoization = true;
67 + }
68 + if (firstLine.includes("@validateRefAccessDuringRender false")) {
69 + validateRefAccessDuringRender = false;
70 + }
71 + if (firstLine.includes("@validateNoSetStateInRender false")) {
72 + validateNoSetStateInRender = false;
73 + }
74 + if (firstLine.includes("@enableOptimizeFunctionExpressions false")) {
75 + enableOptimizeFunctionExpressions = false;
76 + }
77 + if (firstLine.includes("@enableEmitFreeze")) {
78 + enableEmitFreeze = {
79 + source: "react-forget-runtime",
80 + importSpecifierName: "makeReadOnly",
81 + };
82 + }
83 + if (firstLine.indexOf("@reactScriptDirective") !== -1) {
84 + enableOnlyOnReactScript = true;
85 + language = "flow";
86 + }
87 +
88 + return pluginFn(input, basename, language, {
89 + environment: {
90 + customHooks: new Map([
91 + [
92 + "useFreeze",
93 + {
94 + valueKind: "frozen" as ValueKind,
95 + effectKind: "freeze" as Effect,
96 + },
97 + ],
98 + ]),
99 + enableAssumeHooksFollowRulesOfReact,
100 + enableFunctionCallSignatureOptimizations: true,
101 + disableAllMemoization,
102 + enableTreatHooksAsFunctions,
103 + inlineUseMemo: true,
104 + memoizeJsxElements,
105 + validateHooksUsage: true,
106 + validateRefAccessDuringRender,
107 + validateFrozenLambdas: true,
108 + validateNoSetStateInRender,
109 + enableEmitFreeze,
110 + enableOptimizeFunctionExpressions,
111 + assertValidMutableRanges: true,
112 + },
113 + enableOnlyOnUseForgetDirective,
114 + enableOnlyOnReactScript,
115 + logger: null,
116 + gating,
117 + instrumentForget,
118 + panicOnBailout,
119 + isDev: true,
120 + noEmit: false,
121 + });
122 +}
compiler/forget/packages/fixture-test-utils/src/constants.ts new
+24
@@ -0,0 +1,24 @@
1 +import path from "path";
2 +
3 +// We assume this is run from `babel-plugin-react-forget`
4 +export const COMPILER_PATH = path.join(
5 + process.cwd(),
6 + "dist",
7 + "Babel",
8 + "RunReactForgetBabelPlugin.js"
9 +);
10 +export const LOGGER_PATH = path.join(
11 + process.cwd(),
12 + "dist",
13 + "Utils",
14 + "logger.js"
15 +);
16 +export const FIXTURES_PATH = path.join(
17 + process.cwd(),
18 + "src",
19 + "__tests__",
20 + "fixtures",
21 + "compiler"
22 +);
23 +export const FILTER_FILENAME = "testfilter.txt";
24 +export const FILTER_PATH = path.join(process.cwd(), FILTER_FILENAME);
compiler/forget/packages/fixture-test-utils/src/fixture-utils.ts new
+161
@@ -0,0 +1,161 @@
1 +import fs from "fs/promises";
2 +import glob from "glob";
3 +import invariant from "invariant";
4 +import path from "path";
5 +import { FILTER_PATH, FIXTURES_PATH } from "./constants";
6 +
7 +export type TestFilter =
8 + | {
9 + kind: "only";
10 + paths: Array<string>;
11 + }
12 + | {
13 + kind: "skip";
14 + paths: Array<string>;
15 + };
16 +
17 +async function exists(file: string): Promise<boolean> {
18 + try {
19 + await fs.access(file);
20 + return true;
21 + } catch {
22 + return false;
23 + }
24 +}
25 +
26 +export async function readTestFilter(): Promise<TestFilter | null> {
27 + if (!(await exists(FILTER_PATH))) {
28 + throw new Error(`testfilter file not found at ${FILTER_PATH}`);
29 + }
30 +
31 + const input = await fs.readFile(FILTER_PATH, "utf8");
32 + const lines = input.trim().split("\n");
33 + if (lines.length < 2) {
34 + console.warn("Misformed filter file. Expected at least two lines.");
35 + return null;
36 + }
37 +
38 + let filter: "only" | "skip" | null = null;
39 + if (lines[0]!.indexOf("@only") !== -1) {
40 + filter = "only";
41 + }
42 + if (lines[0]!.indexOf("@skip") !== -1) {
43 + filter = "skip";
44 + }
45 + if (filter === null) {
46 + console.warn(
47 + "Misformed filter file. Expected first line to contain @only or @skip"
48 + );
49 + return null;
50 + }
51 + lines.shift();
52 + return {
53 + kind: filter,
54 + paths: lines,
55 + };
56 +}
57 +
58 +export type TestFixture = {
59 + basename: string;
60 + inputPath: string;
61 + inputExists: boolean;
62 + outputPath: string;
63 + outputExists: boolean;
64 +};
65 +
66 +export function getFixtures(
67 + filter: TestFilter | null
68 +): Map<string, TestFixture> {
69 + // search for fixtures within nested directories
70 + const files = glob.sync(`**/*.{js,md}`, {
71 + cwd: FIXTURES_PATH,
72 + });
73 + const fixtures: Map<string, TestFixture> = new Map();
74 +
75 + for (const filePath of files) {
76 + const basename = path.basename(
77 + path.basename(filePath, ".js"),
78 + ".expect.md"
79 + );
80 + // "partial" paths do not include suffixes
81 + const partialRelativePath = path.join(path.dirname(filePath), basename);
82 + // Replicate jest test behavior
83 + if (basename.startsWith("todo.")) {
84 + continue;
85 + }
86 + if (filter) {
87 + if (
88 + filter.kind === "only" &&
89 + filter.paths.indexOf(partialRelativePath) === -1
90 + ) {
91 + continue;
92 + } else if (
93 + filter.kind === "skip" &&
94 + filter.paths.indexOf(partialRelativePath) !== -1
95 + ) {
96 + continue;
97 + }
98 + }
99 +
100 + let fixtureInfo = fixtures.get(partialRelativePath);
101 + if (fixtureInfo === undefined) {
102 + const partialAbsolutePath = path.join(FIXTURES_PATH, partialRelativePath);
103 + fixtureInfo = {
104 + basename,
105 + inputPath: `${partialAbsolutePath}.js`,
106 + inputExists: false,
107 + outputPath: `${partialAbsolutePath}.expect.md`,
108 + outputExists: false,
109 + };
110 + fixtures.set(partialRelativePath, fixtureInfo);
111 + }
112 +
113 + if (filePath.endsWith(".js")) {
114 + fixtureInfo.inputExists = true;
115 + } else {
116 + fixtureInfo.outputExists = true;
117 + }
118 + }
119 +
120 + return fixtures;
121 +}
122 +
123 +function wrapWithTripleBackticks(s: string, ext: string | null = null): string {
124 + return `\`\`\`${ext ?? ""}
125 +${s}
126 +\`\`\``;
127 +}
128 +
129 +export function writeOutputToString(
130 + input: string,
131 + output: string | null,
132 + error: Error | null
133 +) {
134 + // leading newline intentional
135 + let result = `
136 +## Input
137 +
138 +${wrapWithTripleBackticks(input, "javascript")}
139 +`; // trailing newline + space internional
140 +
141 + if (output != null) {
142 + result += `
143 +## Code
144 +
145 +${output == null ? "[ none ]" : wrapWithTripleBackticks(output, "javascript")}
146 +`;
147 + } else {
148 + result += "\n";
149 + }
150 +
151 + if (error != null) {
152 + const errorMessage = error.message.replace(/^\/.*?:\s/, "");
153 +
154 + result += `
155 +## Error
156 +
157 +${wrapWithTripleBackticks(errorMessage)}
158 + \n`;
159 + }
160 + return result + ` `;
161 +}
compiler/forget/packages/fixture-test-utils/src/index.ts new
+3
@@ -0,0 +1,3 @@
1 +export * from "./constants";
2 +export * from "./fixture-utils";
3 +export * from "./compiler-utils";
compiler/forget/packages/fixture-test-utils/tsconfig.json new
+20
@@ -0,0 +1,20 @@
1 +{
2 + "extends": "@tsconfig/node16-strictest/tsconfig.json",
3 + "compilerOptions": {
4 + "declaration": true,
5 + "outDir": "dist",
6 + "jsx": "react-jsxdev",
7 +
8 + // weaken strictness from preset
9 + "importsNotUsedAsValues": "remove",
10 + "noUncheckedIndexedAccess": false,
11 + "noUnusedParameters": false,
12 + "useUnknownInCatchVariables": false,
13 + "target": "ES2015",
14 + // ideally turn off only during dev, or on a per-file basis
15 + "noUnusedLocals": false,
16 + "sourceMap": true
17 + },
18 + "exclude": ["node_modules"],
19 + "include": ["src/**/*.ts"]
20 +}
compiler/forget/packages/snap/package.json
+3 -2
@@ -9,7 +9,7 @@
9 "src"
10 ],
11 "scripts": {
12 - "build": "rimraf dist && tsc",
12 + "build": "yarn workspace fixture-test-utils run build && rimraf dist && tsc",
13 "test": "echo 'no tests'",
14 "lint": "yarn eslint src"
15 },
@@ -22,7 +22,8 @@
22 "chalk": "4",
23 "readline": "^1.3.0",
24 "typescript": "^5.1.0",
25 - "yargs": "^17.7.1"
25 + "yargs": "^17.7.1",
26 + "fixture-test-utils": "*"
27 },
28 "devDependencies": {
29 "@types/node": "^18.7.18",
compiler/forget/packages/snap/src/compiler-worker.ts
+13 -185
@@ -6,9 +6,8 @@
6 */
7
8 import type { runReactForgetBabelPlugin as RunReactForgetBabelPlugin } from 'babel-plugin-react-forget/src/Babel/RunReactForgetBabelPlugin';
9 -import type { Effect, ValueKind } from 'babel-plugin-react-forget/src/HIR';
9 +import { TestFixture, transformFixtureInput, writeOutputToString } from 'fixture-test-utils';
10 import fs from "fs/promises";
11 -import { exists } from "./utils";
11
12 const originalConsoleError = console.error;
13
@@ -33,12 +32,6 @@ export type TestResult = {
32 unexpectedError: string | null;
33 };
34
36 -export type TestFixture = {
37 - basename: string;
38 - inputPath: string;
39 - outputPath: string;
40 -};
41 -
35 export async function compile(
36 compilerPath: string,
37 loggerPath: string,
@@ -54,11 +47,11 @@ export async function compile(
47 clearRequireCache();
48 }
49 version = compilerVersion;
57 - const { inputPath, outputPath, basename } = fixture;
58 - const input = (await exists(inputPath))
50 + const { inputPath, inputExists, outputPath, outputExists, basename } = fixture;
51 + const input = inputExists
52 ? await fs.readFile(inputPath, "utf8")
53 : null;
61 - const expected = (await exists(outputPath))
54 + const expected = outputExists
55 ? await fs.readFile(outputPath, "utf8")
56 : null;
57
@@ -86,108 +79,7 @@ export async function compile(
79 // since console log order is non-deterministic
80 const shouldLogPragma = input.split("\n")[0].includes("@debug");
81 toggleLogging(isOnlyFixture && shouldLogPragma);
89 -
90 - // Extract the first line to quickly check for custom test directives
91 - const firstLine = input.substring(0, input.indexOf("\n"));
92 - let language = parseLanguage(firstLine);
93 -
94 - let enableOnlyOnUseForgetDirective = false;
95 - let gating = null;
96 - let instrumentForget = null;
97 - let panicOnBailout = true;
98 - let memoizeJsxElements = true;
99 - let enableAssumeHooksFollowRulesOfReact = false;
100 - let enableTreatHooksAsFunctions = true;
101 - let disableAllMemoization = false;
102 - let validateRefAccessDuringRender = true;
103 - let validateNoSetStateInRender = true;
104 - let enableEmitFreeze = null;
105 - let enableOptimizeFunctionExpressions = true;
106 - let enableOnlyOnReactScript = false;
107 - if (firstLine.indexOf("@forgetDirective") !== -1) {
108 - enableOnlyOnUseForgetDirective = true;
109 - }
110 - if (firstLine.includes("@gating")) {
111 - gating = {
112 - source: "ReactForgetFeatureFlag",
113 - importSpecifierName: "isForgetEnabled_Fixtures",
114 - };
115 - }
116 - if (firstLine.includes("@instrumentForget")) {
117 - instrumentForget = {
118 - source: "react-forget-runtime",
119 - importSpecifierName: "useRenderCounter",
120 - };
121 - }
122 - if (firstLine.includes("@panicOnBailout false")) {
123 - panicOnBailout = false;
124 - }
125 - if (firstLine.includes("@memoizeJsxElements false")) {
126 - memoizeJsxElements = false;
127 - }
128 - if (firstLine.includes("@enableAssumeHooksFollowRulesOfReact true")) {
129 - enableAssumeHooksFollowRulesOfReact = true;
130 - }
131 - if (firstLine.includes("@enableTreatHooksAsFunctions false")) {
132 - enableTreatHooksAsFunctions = false;
133 - }
134 - if (firstLine.includes("@disableAllMemoization true")) {
135 - disableAllMemoization = true;
136 - }
137 - if (firstLine.includes("@validateRefAccessDuringRender false")) {
138 - validateRefAccessDuringRender = false;
139 - }
140 - if (firstLine.includes("@validateNoSetStateInRender false")) {
141 - validateNoSetStateInRender = false;
142 - }
143 - if (firstLine.includes("@enableOptimizeFunctionExpressions false")) {
144 - enableOptimizeFunctionExpressions = false;
145 - }
146 - if (firstLine.includes("@enableEmitFreeze")) {
147 - enableEmitFreeze = {
148 - source: "react-forget-runtime",
149 - importSpecifierName: "makeReadOnly",
150 - };
151 - }
152 - if (firstLine.indexOf("@reactScriptDirective") !== -1) {
153 - enableOnlyOnReactScript = true;
154 - language = "flow";
155 - }
156 -
157 - code = runReactForgetBabelPlugin(input, basename, language, {
158 - environment: {
159 - customHooks: new Map([
160 - [
161 - "useFreeze",
162 - {
163 - valueKind: "frozen" as ValueKind,
164 - effectKind: "freeze" as Effect,
165 - },
166 - ],
167 - ]),
168 - enableAssumeHooksFollowRulesOfReact,
169 - enableFunctionCallSignatureOptimizations: true,
170 - disableAllMemoization,
171 - enableTreatHooksAsFunctions,
172 - inlineUseMemo: true,
173 - memoizeJsxElements,
174 - validateHooksUsage: true,
175 - validateRefAccessDuringRender,
176 - validateFrozenLambdas: true,
177 - validateNoSetStateInRender,
178 - enableEmitFreeze,
179 - enableOptimizeFunctionExpressions,
180 - assertValidMutableRanges: true,
181 - },
182 - enableOnlyOnUseForgetDirective,
183 - enableOnlyOnReactScript,
184 - logger: null,
185 - gating,
186 - instrumentForget,
187 - panicOnBailout,
188 - isDev: true,
189 - noEmit: false,
190 - }).code;
82 + code = transformFixtureInput(input, basename, runReactForgetBabelPlugin).code;
83 } catch (e) {
84 error = e;
85 }
@@ -202,92 +94,28 @@ export async function compile(
94 }
95 }
96
205 - let output: string;
97 + const output = writeOutputToString(input, code, error);
98 const expectError = basename.startsWith("error.");
99 + let unexpectedError: string | null = null;
100 if (expectError) {
101 if (error === null) {
209 - return {
210 - inputPath,
211 - outputPath,
212 - actual: code,
213 - expected,
214 - unexpectedError: `Expected an error to be thrown for fixture: '${basename}', remove the 'error.' prefix if an error is not expected.`,
215 - };
216 - } else if (code != null) {
217 - output = `${formatOutput(code)}\n${formatErrorOutput(error)}`;
218 - } else {
219 - output = formatErrorOutput(error);
102 + unexpectedError = `Expected an error to be thrown for fixture: '${basename}', remove the 'error.' prefix if an error is not expected.`;
103 }
104 } else {
105 if (error !== null) {
223 - return {
224 - inputPath,
225 - outputPath,
226 - actual: code,
227 - expected,
228 - unexpectedError: `Expected fixture '${basename}' to succeed but it failed with error:\n\n${error.message}`,
229 - };
106 + unexpectedError = `Expected fixture '${basename}' to succeed but it failed with error:\n\n${error.message}`;
107 + } else if (code == null || code.length === 0) {
108 + unexpectedError = `Expected output for fixture '${basename}'.`;
109 }
231 - if (code == null || code.length === 0) {
232 - return {
233 - inputPath,
234 - outputPath,
235 - actual: code,
236 - expected,
237 - unexpectedError: `Expected output for fixture '${basename}'.`,
238 - };
239 - }
240 - output = formatOutput(code);
110 }
111
243 - // leading newline intentional
244 - const actual = `
245 -## Input
246 -
247 -${wrapWithTripleBackticks(input, "javascript")}
248 -
249 -${output}
250 - `; // trailing newline + space internional
251 -
112 console.error = originalConsoleError;
113
114 return {
115 inputPath,
116 outputPath,
257 - actual,
117 + actual: output,
118 expected,
259 - unexpectedError: null,
119 + unexpectedError,
120 };
121 }
262 -
263 -function formatErrorOutput(error: Error): string {
264 - error.message = error.message.replace(/^\/.*?:\s/, "");
265 - return `
266 -## Error
267 -
268 -${wrapWithTripleBackticks(error.message)}
269 - `;
270 -}
271 -
272 -function formatOutput(code: string): string {
273 - return `
274 -## Code
275 -
276 -${wrapWithTripleBackticks(code, "javascript")}
277 - `.trim();
278 -}
279 -
280 -function wrapWithTripleBackticks(s: string, ext: string | null = null): string {
281 - return `\`\`\`${ext ?? ""}
282 -${s}
283 -\`\`\``;
284 -}
285 -
286 -const FlowPragmas = [/\/\/\s@flow$/gm, /\*\s@flow$/gm];
287 -function parseLanguage(source: string): "flow" | "typescript" {
288 - let useFlow = false;
289 - for (const flowPragma of FlowPragmas) {
290 - useFlow ||= !!source.match(flowPragma);
291 - }
292 - return useFlow ? "flow" : "typescript";
293 -}
compiler/forget/packages/snap/src/main.ts
+1 -1
@@ -17,7 +17,7 @@ if (process.stdin.isTTY) {
17 process.stdin.setRawMode(true);
18 }
19
20 -process.stdin.on("keypress", function (chunk, key) {
20 +process.stdin.on("keypress", function (_, key) {
21 if (key && key.name === "c" && key.ctrl) {
22 // handle sigint
23 if (childProc) {
compiler/forget/packages/snap/src/runner.ts
+3 -104
@@ -7,8 +7,8 @@
7
8 import watcher from "@parcel/watcher";
9 import chalk from "chalk";
10 +import { COMPILER_PATH, LOGGER_PATH, FIXTURES_PATH, FILTER_FILENAME, FILTER_PATH, readTestFilter, TestFilter } from 'fixture-test-utils';
11 import fs from "fs/promises";
11 -import glob from "glob";
12 import invariant from "invariant";
13 import { diff } from "jest-diff";
14 import { Worker } from "jest-worker";
@@ -19,26 +19,10 @@ import ts from "typescript";
19 import yargs from "yargs";
20 import { hideBin } from "yargs/helpers";
21 import { TestResult } from "./compiler-worker";
22 -import * as compiler from "./compiler-worker.js";
23 -import { exists } from "./utils";
22 +import * as compiler from "./compiler-worker";
23 +import {getFixtures} from 'fixture-test-utils';
24
25 const WORKER_PATH = require.resolve("./compiler-worker.js");
26 -const COMPILER_PATH = path.join(
27 - process.cwd(),
28 - "dist",
29 - "Babel",
30 - "RunReactForgetBabelPlugin.js"
31 -);
32 -const LOGGER_PATH = path.join(process.cwd(), "dist", "Utils", "logger.js");
33 -const FIXTURES_PATH = path.join(
34 - process.cwd(),
35 - "src",
36 - "__tests__",
37 - "fixtures",
38 - "compiler"
39 -);
40 -const FILTER_FILENAME = "testfilter.txt";
41 -const FILTER_PATH = path.join(process.cwd(), FILTER_FILENAME);
26
27 readline.emitKeypressEvents(process.stdin);
28
@@ -109,49 +93,6 @@ function clearConsole() {
93 console.log("\u001Bc");
94 }
95
112 -function getFixtures(
113 - filter: TestFilter | null
114 -): Map<string, compiler.TestFixture> {
115 - // search for fixtures within nested directories
116 - const files = glob.sync(`**/*.{js,md}`, {
117 - cwd: FIXTURES_PATH,
118 - });
119 - const fixtures = new Map();
120 -
121 - for (const filePath of files) {
122 - const basename = path.basename(
123 - path.basename(filePath, ".js"),
124 - ".expect.md"
125 - );
126 - // "partial" paths do not include suffixes
127 - const partialRelativePath = path.join(path.dirname(filePath), basename);
128 - const partialAbsolutePath = path.join(FIXTURES_PATH, partialRelativePath);
129 - // Replicate jest test behavior
130 - if (basename.startsWith("todo.")) {
131 - continue;
132 - }
133 - if (filter) {
134 - if (
135 - filter.kind === "only" &&
136 - filter.paths.indexOf(partialRelativePath) === -1
137 - ) {
138 - continue;
139 - } else if (
140 - filter.kind === "skip" &&
141 - filter.paths.indexOf(partialRelativePath) !== -1
142 - ) {
143 - continue;
144 - }
145 - }
146 - fixtures.set(partialRelativePath, {
147 - basename,
148 - inputPath: `${partialAbsolutePath}.js`,
149 - outputPath: `${partialAbsolutePath}.expect.md`,
150 - });
151 - }
152 - // console.log("fixtures!", JSON.stringify(Array.from(fixtures.keys())));
153 - return fixtures;
154 -}
96 /**
97 * Do a test run and return the test results
98 */
@@ -395,48 +336,6 @@ enum Mode {
336 Update = "Update",
337 }
338
398 -type TestFilter =
399 - | {
400 - kind: "only";
401 - paths: Array<string>;
402 - }
403 - | {
404 - kind: "skip";
405 - paths: Array<string>;
406 - };
407 -
408 -async function readTestFilter(): Promise<TestFilter | null> {
409 - if (!(await exists(FILTER_PATH))) {
410 - throw new Error(`testfilter file not found at ${FILTER_PATH}`);
411 - }
412 -
413 - const input = await fs.readFile(FILTER_PATH, "utf8");
414 - const lines = input.trim().split("\n");
415 - if (lines.length < 2) {
416 - console.warn("Misformed filter file. Expected at least two lines.");
417 - return null;
418 - }
419 -
420 - let filter: "only" | "skip" | null = null;
421 - if (lines[0]!.indexOf("@only") !== -1) {
422 - filter = "only";
423 - }
424 - if (lines[0]!.indexOf("@skip") !== -1) {
425 - filter = "skip";
426 - }
427 - if (filter === null) {
428 - console.warn(
429 - "Misformed filter file. Expected first line to contain @only or @skip"
430 - );
431 - return null;
432 - }
433 - lines.shift();
434 - return {
435 - kind: filter,
436 - paths: lines,
437 - };
438 -}
439 -
339 /**
340 * Runs the compiler in watch or single-execution mode
341 */
compiler/forget/packages/snap/src/utils.ts deleted
-17
@@ -1,17 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import fs from "fs/promises";
9 -
10 -export async function exists(file: string): Promise<boolean> {
11 - try {
12 - await fs.access(file);
13 - return true;
14 - } catch {
15 - return false;
16 - }
17 -}