Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@
"build:all": "turbo run build",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project ui",
"test:integration": "vitest run --project dom --project dom-heavy",
"test:dist": "turbo run test:dist --filter=@object-ui/components",
"site:dev": "pnpm --filter @object-ui/site dev",
"site:build": "pnpm --filter @object-ui/site build",
Expand Down
197 changes: 197 additions & 0 deletions scripts/__tests__/package-scripts-vitest-projects.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

/**
* `pnpm test:integration` was `vitest run --project ui` while no project named
* `ui` existed anywhere in the config (objectui#7096).
*
* The drift is structural, not a typo. `ui` was a real project once: it was
* declared in `vitest.workspace.ts` (1bdba0693, 2026-02-28) as the COMPLEMENT
* of `unit` — every `*.test.{ts,tsx}` under `packages`/`apps`/`examples` except
* the four pure-logic packages. That file was deleted in 85c872487 (2026-05-24)
* because Vitest 4 removed `defineWorkspace` and had been silently ignoring it,
* which took `unit` AND `ui` down together. `unit` came back as an inline
* project in `vitest.config.mts` (e850c5695) and `test:unit` started resolving
* again by accident — that commit never touched `package.json`. Nothing ever
* re-declared `ui`, so `test:integration` was left naming a project that had
* stopped existing three months earlier, and no run of it ever reported that:
* a script nobody invokes is a script nobody sees fail.
*
* So the two halves are pinned to each other here: every `--project` name a
* ROOT script passes must be a project this repo actually declares.
*
* Direction matters. The assertion is `script names ⊆ declared names`, so an
* over-wide declared set never fails — which makes every leg of the derivation
* silently vacuous unless it has its own control. Each one below is asserted
* against a name measured on this tree.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const ROOT_PACKAGE_JSON = path.join(repoRoot, 'package.json');
const ROOT_VITEST_CONFIG = path.join(repoRoot, 'vitest.config.mts');

/**
* Every `--project` value in a command string, in order.
*
* Written here rather than reused from `scripts/vitest-invocation-guard.mjs`:
* that parser keeps flags in a plain object, so a REPEATED flag collapses to
* its last value — and `--project dom --project dom-heavy` (what `test:integration`
* became) is exactly that shape. Reusing it would have checked `dom-heavy` and
* quietly skipped `dom`.
*/
function projectNamesIn(command: string): string[] {
const names: string[] = [];
const tokens = command.split(/\s+/).filter(Boolean);

for (let i = 0; i < tokens.length; i += 1) {
const token = tokens[i];
if (token.startsWith('--project=')) {
names.push(token.slice('--project='.length));
continue;
}
if (token === '--project' && tokens[i + 1] !== undefined) {
names.push(tokens[i + 1]);
i += 1;
}
}

return names;
}

/** `{ scriptName: [project, …] }` for every root script that filters on a project. */
function projectFiltersInRootScripts(): Record<string, string[]> {
const pkg = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8')) as {
scripts?: Record<string, string>;
};
const out: Record<string, string[]> = {};

for (const [scriptName, command] of Object.entries(pkg.scripts ?? {})) {
const names = projectNamesIn(command);
if (names.length > 0) out[scriptName] = names;
}

return out;
}

/**
* Every project name this repo declares, from BOTH shapes the `projects` array
* uses:
*
* - inline objects with a literal `name:` (`unit`, `dom`, `dom-heavy`, and the
* env-gated `dist`) — read off the source text rather than by importing the
* config, because an import answers a DIFFERENT question: `dist` only
* materialises when `OBJECTUI_DIST_PINS=1`, so the imported list depends on
* the environment while the declaration surface does not. Importing would
* also execute that file's module scope (including its `--project dist`
* argv guard, which throws) inside this test process.
* - a path to another config (`./apps/console/vitest.config.ts`), whose
* project name Vitest derives from that directory's `package.json` when the
* config declares none. `@object-ui/console` is a usable `--project` filter
* and appears as no `name:` literal anywhere, so a pin that read only the
* literals would go red on a root script that legitimately named it.
*/
function declaredProjectNames(): Set<string> {
const configText = fs.readFileSync(ROOT_VITEST_CONFIG, 'utf8');
const names = new Set<string>();

for (const [, name] of configText.matchAll(/\bname:\s*'([^']+)'/g)) names.add(name);

for (const [, relative] of configText.matchAll(/__dirname,\s*'(\.\/[^']*vitest\.config\.[cm]?ts)'/g)) {
const configPath = path.resolve(repoRoot, relative);
if (!fs.existsSync(configPath)) continue;

const ownName = fs.readFileSync(configPath, 'utf8').match(/\bname:\s*'([^']+)'/);
if (ownName) {
names.add(ownName[1]);
continue;
}

const packageJsonPath = path.join(path.dirname(configPath), 'package.json');
if (!fs.existsSync(packageJsonPath)) continue;
const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (name) names.add(name);
}

return names;
}

describe('projectNamesIn', () => {
it('collects EVERY --project value, not just the last one', () => {
// The regression this exists for: `test:integration` passes two.
expect(projectNamesIn('vitest run --project dom --project dom-heavy')).toEqual([
'dom',
'dom-heavy',
]);
});

it('reads the `--project=name` form too', () => {
expect(projectNamesIn('vitest run --project=unit')).toEqual(['unit']);
});

it('finds nothing in a command that filters on no project', () => {
expect(projectNamesIn('vitest run')).toEqual([]);
// `--project` is not a prefix match: `--projects` is a different flag.
expect(projectNamesIn('vitest run --projects foo')).toEqual([]);
});
});

describe('root package.json --project filters', () => {
it('names at least the scripts this pin exists for (an extractor that found nothing would pass vacuously)', () => {
const filters = projectFiltersInRootScripts();

expect(filters['test:unit']).toEqual(['unit']);
expect(filters['test:integration']).toBeDefined();
expect(filters['test:integration']!.length).toBeGreaterThan(0);
});

it('every project a root script filters on is declared', () => {
const declared = declaredProjectNames();
const offenders: string[] = [];

for (const [scriptName, names] of Object.entries(projectFiltersInRootScripts())) {
for (const name of names) {
if (!declared.has(name)) {
offenders.push(`pnpm ${scriptName} → --project ${name}`);
}
}
}

expect(
offenders,
`Root scripts filter on ${offenders.length} project(s) that vitest.config.mts does not ` +
`declare, so those scripts cannot run:\n ${offenders.join('\n ')}\n` +
`Declared: ${[...declaredProjectNames()].sort().join(', ')}\n` +
'Point the script at a project that exists — do NOT add a project to make the ' +
'stale name resolve (objectui#7096).'
).toEqual([]);
});
});

describe('declaredProjectNames controls', () => {
it('finds the inline projects (a regex matching nothing would make the pin vacuous)', () => {
const declared = declaredProjectNames();

expect(declared.has('unit')).toBe(true);
expect(declared.has('dom')).toBe(true);
expect(declared.has('dom-heavy')).toBe(true);
// Declared inside the `OBJECTUI_DIST_PINS` branch — present in the source
// text either way, which is what this reads.
expect(declared.has('dist')).toBe(true);
});

it('finds the project brought in by config path, whose name is nowhere a `name:` literal', () => {
// Measured: `pnpm exec vitest list --project @object-ui/console` resolves.
expect(declaredProjectNames().has('@object-ui/console')).toBe(true);
});

it('does not answer yes to everything', () => {
// The negative half of the control: a derivation that returned a universal
// set would satisfy the subset assertion above no matter what the scripts
// said. Deliberately a name nobody would ever declare, so this control
// stays a control and does not quietly become policy about which project
// names are allowed.
expect(declaredProjectNames().has('__no_such_vitest_project__')).toBe(false);
});
});
Loading