From 6f8e75accb9b9932ad83e2c7e3af5948933e4787 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Tue, 12 May 2026 23:19:11 +0200 Subject: [PATCH] feat(core-eslint): workspace helper for conformance rules --- packages/core-eslint/rules/_workspace.js | 28 +++++++++++++++ packages/core-eslint/rules/_workspace.test.js | 34 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 packages/core-eslint/rules/_workspace.js create mode 100644 packages/core-eslint/rules/_workspace.test.js diff --git a/packages/core-eslint/rules/_workspace.js b/packages/core-eslint/rules/_workspace.js new file mode 100644 index 0000000..34cfd73 --- /dev/null +++ b/packages/core-eslint/rules/_workspace.js @@ -0,0 +1,28 @@ +import fs from "node:fs"; +import path from "node:path"; + +/** + * Reads the `packages:` list from `pnpm-workspace.yaml` at the given repo + * root. Returns an array of package glob strings (e.g. ["apps/*", "packages/*"]). + * Returns [] when the file is missing or has no `packages:` key. + * + * Uses regex extraction over YAML parsing to avoid a `js-yaml` dependency; + * the `packages:` block in pnpm-workspace.yaml has a stable, well-known + * shape and this approach is sufficient. + */ +export function readWorkspacePackages(repoRoot) { + const yamlPath = path.join(repoRoot, "pnpm-workspace.yaml"); + let src; + try { + src = fs.readFileSync(yamlPath, "utf8"); + } catch { + return []; + } + const blockMatch = src.match(/^packages:\s*\n((?:\s+-\s+.+\n?)+)/m); + if (!blockMatch) return []; + return blockMatch[1] + .split("\n") + .map((line) => line.match(/^\s+-\s+"?([^"]+?)"?\s*$/)) + .filter((m) => m !== null) + .map((m) => m[1]); +} diff --git a/packages/core-eslint/rules/_workspace.test.js b/packages/core-eslint/rules/_workspace.test.js new file mode 100644 index 0000000..a5f6f33 --- /dev/null +++ b/packages/core-eslint/rules/_workspace.test.js @@ -0,0 +1,34 @@ +import { describe, it, expect } from "vitest"; +import path from "node:path"; +import os from "node:os"; +import fs from "node:fs"; +import { readWorkspacePackages } from "./_workspace.js"; + +function writeWorkspaceYaml(contents) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "workspace-")); + const filepath = path.join(dir, "pnpm-workspace.yaml"); + fs.writeFileSync(filepath, contents); + return { dir, filepath }; +} + +describe("_workspace", () => { + it("returns the list of declared package globs", () => { + const { dir } = writeWorkspaceYaml( + `packages: + - "apps/*" + - "packages/*" +`, + ); + expect(readWorkspacePackages(dir)).toEqual(["apps/*", "packages/*"]); + }); + + it("returns [] when pnpm-workspace.yaml is missing", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "workspace-")); + expect(readWorkspacePackages(dir)).toEqual([]); + }); + + it("returns [] when packages key is absent", () => { + const { dir } = writeWorkspaceYaml(`# empty\n`); + expect(readWorkspacePackages(dir)).toEqual([]); + }); +});