@trackunit/iris-app-playwright 0.1.1

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 (60) hide show
  1. package/README.md +230 -0
  2. package/generators.json +12 -0
  3. package/package.json +43 -0
  4. package/src/fixtures/baseTest.d.ts +9 -0
  5. package/src/fixtures/baseTest.js +12 -0
  6. package/src/fixtures/describe.d.ts +11 -0
  7. package/src/fixtures/describe.js +23 -0
  8. package/src/fixtures/featureFlags.fixture.d.ts +19 -0
  9. package/src/fixtures/featureFlags.fixture.js +76 -0
  10. package/src/fixtures/harRecording.fixture.d.ts +12 -0
  11. package/src/fixtures/harRecording.fixture.js +35 -0
  12. package/src/fixtures/hydrateStorageState.d.ts +36 -0
  13. package/src/fixtures/hydrateStorageState.js +43 -0
  14. package/src/fixtures/irisApp.fixture.d.ts +15 -0
  15. package/src/fixtures/irisApp.fixture.js +13 -0
  16. package/src/fixtures/localDevMode.fixture.d.ts +5 -0
  17. package/src/fixtures/localDevMode.fixture.js +17 -0
  18. package/src/fixtures/login.fixture.d.ts +24 -0
  19. package/src/fixtures/login.fixture.js +95 -0
  20. package/src/fixtures/loginCacheKey.d.ts +25 -0
  21. package/src/fixtures/loginCacheKey.js +29 -0
  22. package/src/fixtures/resolveCredentials.d.ts +14 -0
  23. package/src/fixtures/resolveCredentials.js +49 -0
  24. package/src/generators/playwright-configuration/files/root/playwright/fixtures/auth.json__tmpl__ +4 -0
  25. package/src/generators/playwright-configuration/files/root/playwright/support/fixtures.ts__tmpl__ +1 -0
  26. package/src/generators/playwright-configuration/files/root/playwright/tests/app.spec.ts__tmpl__ +16 -0
  27. package/src/generators/playwright-configuration/files/root/playwright/tsconfig.json__tmpl__ +15 -0
  28. package/src/generators/playwright-configuration/files/root/playwright.config.ts__tmpl__ +13 -0
  29. package/src/generators/playwright-configuration/generator.d.ts +18 -0
  30. package/src/generators/playwright-configuration/generator.js +77 -0
  31. package/src/generators/playwright-configuration/schema.d.ts +3 -0
  32. package/src/generators/playwright-configuration/schema.json +18 -0
  33. package/src/index.d.ts +15 -0
  34. package/src/index.js +14 -0
  35. package/src/plugins/createLogFile.d.ts +24 -0
  36. package/src/plugins/createLogFile.js +51 -0
  37. package/src/plugins/defaultPlaywrightConfig.d.ts +68 -0
  38. package/src/plugins/defaultPlaywrightConfig.js +150 -0
  39. package/src/plugins/logsReporter.d.ts +55 -0
  40. package/src/plugins/logsReporter.js +119 -0
  41. package/src/plugins/nxPreset.d.ts +9 -0
  42. package/src/plugins/nxPreset.js +17 -0
  43. package/src/plugins/redactHar.d.ts +17 -0
  44. package/src/plugins/redactHar.js +138 -0
  45. package/src/plugins/redactSensitive.d.ts +31 -0
  46. package/src/plugins/redactSensitive.js +72 -0
  47. package/src/plugins/redactTrace.d.ts +12 -0
  48. package/src/plugins/redactTrace.js +48 -0
  49. package/src/plugins/setupPlugins.d.ts +11 -0
  50. package/src/plugins/setupPlugins.js +68 -0
  51. package/src/plugins/writeFileWithPrettier.d.ts +17 -0
  52. package/src/plugins/writeFileWithPrettier.js +37 -0
  53. package/src/support.d.ts +2 -0
  54. package/src/support.js +6 -0
  55. package/src/utils/Codeowner.d.ts +26 -0
  56. package/src/utils/Codeowner.js +89 -0
  57. package/src/utils/fileNameBuilder.d.ts +18 -0
  58. package/src/utils/fileNameBuilder.js +32 -0
  59. package/src/utils/fileUpdater.d.ts +16 -0
  60. package/src/utils/fileUpdater.js +38 -0
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redactTraceFile = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_1 = require("fs");
6
+ const jszip_1 = tslib_1.__importDefault(require("jszip"));
7
+ const redactSensitive_1 = require("./redactSensitive");
8
+ /**
9
+ * File suffixes inside a Playwright trace.zip whose contents are JSON Lines
10
+ * with action/network metadata — i.e. the places where a `page.goto(url)`
11
+ * call's URL argument is recorded verbatim. Other entries (binary resources,
12
+ * screenshots, network bodies under `sha1/`) are left alone; their content is
13
+ * referenced by hash so redacting the metadata is sufficient to suppress the
14
+ * sensitive string from any human-readable trace view.
15
+ */
16
+ const TEXT_TRACE_SUFFIXES = [".trace", ".network", ".stacks"];
17
+ const isTextTraceEntry = (relPath) => TEXT_TRACE_SUFFIXES.some(s => relPath.endsWith(s));
18
+ /**
19
+ * Rewrites a Playwright trace.zip in place with sensitive values stripped from
20
+ * the action/network metadata. The `login()` fixture issues a `page.goto`
21
+ * against `/auth/manager-classic#session_token=...`; Playwright records the
22
+ * full URL as the action argument, so without this pass a retained trace zip
23
+ * would carry a live Okta session token alongside the test artifacts.
24
+ *
25
+ * The fragment is client-side only — it never reaches the HTTP server, and
26
+ * HAR/log redaction already covers everything that does — so this pass is the
27
+ * defense-in-depth layer that scrubs the remaining surface.
28
+ */
29
+ const redactTraceFile = async (filePath) => {
30
+ const buf = (0, fs_1.readFileSync)(filePath);
31
+ const zip = await jszip_1.default.loadAsync(buf);
32
+ const rewrites = [];
33
+ zip.forEach((relPath, file) => {
34
+ if (file.dir)
35
+ return;
36
+ if (!isTextTraceEntry(relPath))
37
+ return;
38
+ rewrites.push((async () => {
39
+ const text = await file.async("text");
40
+ zip.file(relPath, (0, redactSensitive_1.redactSensitive)(text));
41
+ })());
42
+ });
43
+ await Promise.all(rewrites);
44
+ const out = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
45
+ (0, fs_1.writeFileSync)(filePath, out);
46
+ };
47
+ exports.redactTraceFile = redactTraceFile;
48
+ //# sourceMappingURL=redactTrace.js.map
@@ -0,0 +1,11 @@
1
+ import type { PlaywrightTestConfig } from "@playwright/test";
2
+ import type { Formatter } from "./writeFileWithPrettier";
3
+ /**
4
+ * Augments a partial Playwright config with the Trackunit logs reporter and HAR folder env setup.
5
+ * Call this in `playwright.config.ts` after `defaultPlaywrightConfig()`.
6
+ *
7
+ * @param config - Partial config from `defaultPlaywrightConfig()`
8
+ * @param formatter - Prettier formatter used by `LogsReporter` to format JSON log files
9
+ * @returns {Partial<PlaywrightTestConfig>} A new partial config with the logs reporter merged into the reporter array
10
+ */
11
+ export declare const setupPlugins: (config: Partial<PlaywrightTestConfig>, formatter: Formatter) => Partial<PlaywrightTestConfig>;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupPlugins = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const defaultPlaywrightConfig_1 = require("./defaultPlaywrightConfig");
7
+ /**
8
+ * Resolves a Playwright `outputDir` (relative or absolute) to an absolute
9
+ * path anchored at `nxRoot`.
10
+ *
11
+ * Why this exists: `defaultPlaywrightConfig` intentionally returns a relative
12
+ * `outputDir` like `../../dist/playwright/apps/<project>/test-results` so it
13
+ * stays portable across machines and snapshot-stable for tests. Playwright
14
+ * itself resolves that string against `rootDir` (the directory containing
15
+ * `playwright.config.ts`) and writes screenshots/videos/traces in the right
16
+ * place. The custom `LogsReporter` however runs as a Playwright `Reporter`
17
+ * and calls `mkdirSync(logsFolder, { recursive: true })` directly — Node
18
+ * resolves the relative path against `process.cwd()`, which under
19
+ * `nx:run-commands` is the **workspace root**. The leading `../..` then
20
+ * walks the reporter two directories *above* the workspace, scattering log
21
+ * files (and HARs) into a sibling repo.
22
+ *
23
+ * The relative path Playwright emits always has the shape
24
+ * `<../>+<workspace-relative-subpath>`, so stripping the leading `../`s and
25
+ * anchoring the remainder at `nxRoot` yields the same absolute directory
26
+ * Playwright would land on — regardless of how the test runner was spawned.
27
+ */
28
+ const absolutiseOutputDir = (outputDir, nxRoot) => {
29
+ if (path.isAbsolute(outputDir)) {
30
+ return outputDir;
31
+ }
32
+ const withoutLeadingDotDots = outputDir.replace(/^(?:\.\.[\\/])+/, "");
33
+ return path.resolve(nxRoot, withoutLeadingDotDots);
34
+ };
35
+ /**
36
+ * Augments a partial Playwright config with the Trackunit logs reporter and HAR folder env setup.
37
+ * Call this in `playwright.config.ts` after `defaultPlaywrightConfig()`.
38
+ *
39
+ * @param config - Partial config from `defaultPlaywrightConfig()`
40
+ * @param formatter - Prettier formatter used by `LogsReporter` to format JSON log files
41
+ * @returns {Partial<PlaywrightTestConfig>} A new partial config with the logs reporter merged into the reporter array
42
+ */
43
+ const setupPlugins = (config, formatter) => {
44
+ const nxRoot = (0, defaultPlaywrightConfig_1.findWorkspaceRoot)();
45
+ // Both HARs and logs derive from the resolved `outputDir`, so every Playwright
46
+ // artifact for a run stays inside the one `dist/playwright` tree (under the
47
+ // per-executor partition on CI). This removes the legacy fixed
48
+ // `dist/playwright-results` location and the `hars_folders` env override.
49
+ const outputDirBase = typeof config.outputDir === "string"
50
+ ? absolutiseOutputDir(config.outputDir, nxRoot)
51
+ : path.join(nxRoot, "dist", "playwright");
52
+ const harsFolder = path.join(outputDirBase, "hars");
53
+ const logsFolder = path.join(outputDirBase, "logs");
54
+ const reporterOptions = {
55
+ logsFolder,
56
+ harsFolder,
57
+ nxRoot,
58
+ formatter,
59
+ };
60
+ const logsReporterEntry = [path.resolve(__dirname, "./logsReporter"), reporterOptions];
61
+ const existingReporters = Array.isArray(config.reporter) ? config.reporter : [];
62
+ return {
63
+ ...config,
64
+ reporter: [...existingReporters, logsReporterEntry],
65
+ };
66
+ };
67
+ exports.setupPlugins = setupPlugins;
68
+ //# sourceMappingURL=setupPlugins.js.map
@@ -0,0 +1,17 @@
1
+ import { WriteFileOptions } from "fs";
2
+ import { format, resolveConfig } from "prettier";
3
+ export type Formatter = {
4
+ resolveConfig: typeof resolveConfig;
5
+ format: typeof format;
6
+ };
7
+ /**
8
+ * Writes a file with Prettier formatting applied.
9
+ * Automatically detects parser based on file extension.
10
+ *
11
+ * @param nxRoot - Absolute path to the NX workspace root (used to locate `.prettierrc`)
12
+ * @param filePath - Destination file path
13
+ * @param content - Raw file content to format and write
14
+ * @param writer - Prettier formatter instance
15
+ * @param writeOptions - Node.js `writeFileSync` options (default: UTF-8)
16
+ */
17
+ export declare const writeFileWithPrettier: (nxRoot: string, filePath: string, content: string, writer: Formatter, writeOptions?: WriteFileOptions) => Promise<void>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeFileWithPrettier = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const fs_1 = require("fs");
7
+ const path = tslib_1.__importStar(require("path"));
8
+ /**
9
+ * Writes a file with Prettier formatting applied.
10
+ * Automatically detects parser based on file extension.
11
+ *
12
+ * @param nxRoot - Absolute path to the NX workspace root (used to locate `.prettierrc`)
13
+ * @param filePath - Destination file path
14
+ * @param content - Raw file content to format and write
15
+ * @param writer - Prettier formatter instance
16
+ * @param writeOptions - Node.js `writeFileSync` options (default: UTF-8)
17
+ */
18
+ const writeFileWithPrettier = async (nxRoot, filePath, content, writer, writeOptions = { encoding: "utf-8" }) => {
19
+ const prettierConfigPath = path.join(nxRoot, ".prettierrc");
20
+ const options = await writer.resolveConfig(prettierConfigPath).catch(error => {
21
+ devkit_1.logger.info(`Prettier config error: ${String(error)}`);
22
+ return undefined;
23
+ });
24
+ if (!options) {
25
+ throw new Error("Could not find prettier config");
26
+ }
27
+ if (filePath.endsWith("json")) {
28
+ options.parser = "json";
29
+ }
30
+ else {
31
+ options.parser = "typescript";
32
+ }
33
+ const prettySrc = await writer.format(content, options);
34
+ (0, fs_1.writeFileSync)(filePath, prettySrc, writeOptions);
35
+ };
36
+ exports.writeFileWithPrettier = writeFileWithPrettier;
37
+ //# sourceMappingURL=writeFileWithPrettier.js.map
@@ -0,0 +1,2 @@
1
+ export * from "./fixtures/baseTest";
2
+ export * from "./fixtures/describe";
package/src/support.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./fixtures/baseTest"), exports);
5
+ tslib_1.__exportStar(require("./fixtures/describe"), exports);
6
+ //# sourceMappingURL=support.js.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Parses lines from a CODEOWNERS-style file into a mapping of patterns → owners.
3
+ * Skips blank lines and comments (lines beginning with `#`).
4
+ *
5
+ * @param {string[]} lines - Each element is a line from your CODEOWNERS file.
6
+ * @returns {Record<string, string>} An object whose keys are normalized path patterns and values are the owner handle.
7
+ */
8
+ export declare const parseCodeowners: (lines: Array<string>) => Record<string, string>;
9
+ /**
10
+ * Converts a full team handle (potentially namespaced and with platform suffix)
11
+ * into its "short" team name.
12
+ *
13
+ * @param {string} teamName - e.g. `"@trackunit/backend-be"` or `"@trackunit/frontend-fe"`
14
+ * @returns {string | undefined} e.g. `"backend"` or `"frontend"`, or `undefined` if no name given.
15
+ */
16
+ export declare const toShortTeamName: (teamName?: string) => string | undefined;
17
+ /**
18
+ * Recursively looks up the CODEOWNER for a given file or directory path
19
+ * by reading your workspace's CODEOWNERS file.
20
+ *
21
+ * @param {string} currentPath - Absolute path to the file/directory you're querying.
22
+ * @param {string} workspaceRoot - Absolute path to your repo/workspace root.
23
+ * @param {string} [codeownersFileName="TEAM_CODEOWNERS"] - Filename to read at the root.
24
+ * @returns {string|undefined} The owner handle or `undefined` if none found.
25
+ */
26
+ export declare const getCodeowner: (currentPath: string, workspaceRoot: string, codeownersFileName?: string) => string | undefined;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCodeowner = exports.toShortTeamName = exports.parseCodeowners = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_1 = tslib_1.__importDefault(require("fs"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ /**
8
+ * Parses lines from a CODEOWNERS-style file into a mapping of patterns → owners.
9
+ * Skips blank lines and comments (lines beginning with `#`).
10
+ *
11
+ * @param {string[]} lines - Each element is a line from your CODEOWNERS file.
12
+ * @returns {Record<string, string>} An object whose keys are normalized path patterns and values are the owner handle.
13
+ */
14
+ const parseCodeowners = (lines) => {
15
+ const patterns = {};
16
+ for (const line of lines) {
17
+ const trimmed = line.trim();
18
+ if (!trimmed || trimmed.startsWith("#")) {
19
+ continue;
20
+ }
21
+ const [pattern, owner] = trimmed.split(/\s+/, 2);
22
+ if (pattern && owner) {
23
+ const normalizedPattern = pattern.replace(/^\/+|\/+$/g, "");
24
+ patterns[normalizedPattern] = owner;
25
+ }
26
+ }
27
+ return patterns;
28
+ };
29
+ exports.parseCodeowners = parseCodeowners;
30
+ /**
31
+ * Converts a full team handle (potentially namespaced and with platform suffix)
32
+ * into its "short" team name.
33
+ *
34
+ * @param {string} teamName - e.g. `"@trackunit/backend-be"` or `"@trackunit/frontend-fe"`
35
+ * @returns {string | undefined} e.g. `"backend"` or `"frontend"`, or `undefined` if no name given.
36
+ */
37
+ const toShortTeamName = (teamName) => {
38
+ if (!teamName) {
39
+ return undefined;
40
+ }
41
+ let shortName = teamName;
42
+ if (teamName.startsWith("@")) {
43
+ shortName = shortName.slice(shortName.indexOf("/") + 1);
44
+ }
45
+ if (shortName.endsWith("-be") || shortName.endsWith("-fe")) {
46
+ shortName = shortName.slice(0, shortName.lastIndexOf("-"));
47
+ }
48
+ return shortName;
49
+ };
50
+ exports.toShortTeamName = toShortTeamName;
51
+ /**
52
+ * Recursively looks up the CODEOWNER for a given file or directory path
53
+ * by reading your workspace's CODEOWNERS file.
54
+ *
55
+ * @param {string} currentPath - Absolute path to the file/directory you're querying.
56
+ * @param {string} workspaceRoot - Absolute path to your repo/workspace root.
57
+ * @param {string} [codeownersFileName="TEAM_CODEOWNERS"] - Filename to read at the root.
58
+ * @returns {string|undefined} The owner handle or `undefined` if none found.
59
+ */
60
+ const getCodeowner = (currentPath, workspaceRoot, codeownersFileName = "TEAM_CODEOWNERS") => {
61
+ if (!workspaceRoot) {
62
+ return undefined;
63
+ }
64
+ const codeownersPath = path_1.default.join(workspaceRoot, codeownersFileName);
65
+ if (!fs_1.default.existsSync(codeownersPath)) {
66
+ return undefined;
67
+ }
68
+ const codeownersLines = fs_1.default.readFileSync(codeownersPath, "utf8").split("\n");
69
+ const codeowners = (0, exports.parseCodeowners)(codeownersLines);
70
+ let relPath = path_1.default
71
+ .relative(workspaceRoot, currentPath)
72
+ .replace(/\\/g, "/")
73
+ .replace(/^\/+|\/+$/g, "");
74
+ let parent = path_1.default.posix.dirname(relPath);
75
+ while (relPath !== parent) {
76
+ const codeowner = codeowners[relPath];
77
+ if (codeowner) {
78
+ return codeowner;
79
+ }
80
+ if (parent === ".") {
81
+ break;
82
+ }
83
+ relPath = parent;
84
+ parent = path_1.default.posix.dirname(relPath);
85
+ }
86
+ return codeowners["."];
87
+ };
88
+ exports.getCodeowner = getCodeowner;
89
+ //# sourceMappingURL=Codeowner.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Sanitizes a string to be safe for use in filenames.
3
+ * Removes special characters and normalizes whitespace and hyphens.
4
+ *
5
+ * @param str - The string to sanitize (e.g., test suite or test name)
6
+ * @returns {string} Sanitized string safe for filesystem use
7
+ */
8
+ export declare function sanitizeForFilename(str: string): string;
9
+ /**
10
+ * Builds a standardized filename for test artifacts (e.g., screenshots, traces).
11
+ * Combines test name, state, and attempt number into a readable filename.
12
+ *
13
+ * @param testName - The name of the test (will be sanitized)
14
+ * @param state - The test state (e.g., 'passed', 'failed')
15
+ * @param currentRetry - The current retry attempt number (0-based)
16
+ * @returns {string} A sanitized filename in the format: "testName (state) (attempt N)"
17
+ */
18
+ export declare function fileNameBuilder(testName: string, state: string, currentRetry?: number): string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeForFilename = sanitizeForFilename;
4
+ exports.fileNameBuilder = fileNameBuilder;
5
+ /**
6
+ * Sanitizes a string to be safe for use in filenames.
7
+ * Removes special characters and normalizes whitespace and hyphens.
8
+ *
9
+ * @param str - The string to sanitize (e.g., test suite or test name)
10
+ * @returns {string} Sanitized string safe for filesystem use
11
+ */
12
+ function sanitizeForFilename(str) {
13
+ return str
14
+ .replace(/[^a-zA-Z0-9-_\s\[\]\(\)]/g, "")
15
+ .replace(/-+/g, "-")
16
+ .replace(/\s+/g, " ")
17
+ .replace(/^-|-$/g, "");
18
+ }
19
+ /**
20
+ * Builds a standardized filename for test artifacts (e.g., screenshots, traces).
21
+ * Combines test name, state, and attempt number into a readable filename.
22
+ *
23
+ * @param testName - The name of the test (will be sanitized)
24
+ * @param state - The test state (e.g., 'passed', 'failed')
25
+ * @param currentRetry - The current retry attempt number (0-based)
26
+ * @returns {string} A sanitized filename in the format: "testName (state) (attempt N)"
27
+ */
28
+ function fileNameBuilder(testName, state, currentRetry) {
29
+ const fileName = `${testName} ${currentRetry !== undefined ? `(Attempt ${currentRetry + 1})` : ""} (${state.toLowerCase()})`;
30
+ return sanitizeForFilename(fileName);
31
+ }
32
+ //# sourceMappingURL=fileNameBuilder.js.map
@@ -0,0 +1,16 @@
1
+ import { Tree } from "@nx/devkit";
2
+ /**
3
+ * Reads a file from an NX Tree, applies an updater function, and writes it back if changed.
4
+ *
5
+ * @param tree - File system tree
6
+ * @param path - Path to source file in the Tree
7
+ * @param updater - Function that maps the current file content to new content
8
+ */
9
+ export declare const updateFileInTree: (tree: Tree, path: string, updater: (fileContent: string) => string) => void;
10
+ /**
11
+ * Deletes a file from an NX Tree. No-op if the file does not exist.
12
+ *
13
+ * @param tree - File system tree
14
+ * @param path - Path to source file in the Tree
15
+ */
16
+ export declare const deleteFileInTree: (tree: Tree, path: string) => void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteFileInTree = exports.updateFileInTree = void 0;
4
+ /**
5
+ * Reads a file from an NX Tree, applies an updater function, and writes it back if changed.
6
+ *
7
+ * @param tree - File system tree
8
+ * @param path - Path to source file in the Tree
9
+ * @param updater - Function that maps the current file content to new content
10
+ */
11
+ const updateFileInTree = (tree, path, updater) => {
12
+ if (!tree.exists(path)) {
13
+ throw new Error("File not found: " + path);
14
+ }
15
+ const fileContent = tree.read(path, "utf-8");
16
+ if (!fileContent) {
17
+ throw new Error("File is empty: " + path);
18
+ }
19
+ const result = updater(fileContent);
20
+ if (result !== fileContent) {
21
+ tree.write(path, result);
22
+ }
23
+ };
24
+ exports.updateFileInTree = updateFileInTree;
25
+ /**
26
+ * Deletes a file from an NX Tree. No-op if the file does not exist.
27
+ *
28
+ * @param tree - File system tree
29
+ * @param path - Path to source file in the Tree
30
+ */
31
+ const deleteFileInTree = (tree, path) => {
32
+ if (!tree.exists(path)) {
33
+ return;
34
+ }
35
+ tree.delete(path);
36
+ };
37
+ exports.deleteFileInTree = deleteFileInTree;
38
+ //# sourceMappingURL=fileUpdater.js.map