Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124/** * Plugin Layer Isolation Lint Rule Test * * Verifies that the Oxlint no-restricted-imports rule correctly: * 1. BLOCKS imports from src/services/, src/editor/, src/layout/ in src/plugins/ * 2. ALLOWS imports from 'obsidian' (the public API) * 3. DOES NOT apply to __tests__/ files (test setup needs internal access) * * This test runs Oxlint on test fixtures to verify the production rule works. * * @see chainlink issue #392 * @see docs/audits/core-services-audit.md — reach-behind findings */
import { describe, it, expect } from 'vitest'import { execFile } from 'node:child_process'import { randomUUID } from 'node:crypto'import { readFileSync, rmSync, writeFileSync } from 'node:fs'import { createRequire } from 'node:module'import path from 'path'import { promisify } from 'node:util'
// Fixtures are NOT in __tests__ so the no-restricted-imports rule applies to themconst FIXTURES_DIR = path.join(__dirname, '../__lint-test-fixtures__')const PROJECT_ROOT = path.resolve(__dirname, '../../..')const require = createRequire(import.meta.url)const oxlint = path.join(path.dirname(require.resolve('oxlint/package.json')), 'bin/oxlint')const execFileAsync = promisify(execFile)type OxlintOutput = { diagnostics: Array<{ code?: string; message: string }> }
function parseResult(stdout: string): { hasRestrictedImportError: boolean; output: string } { const { diagnostics } = JSON.parse(stdout) as OxlintOutput const output = diagnostics.map(diagnostic => `${diagnostic.code ?? ''} ${diagnostic.message}`).join('\n') return { hasRestrictedImportError: diagnostics.some( diagnostic => diagnostic.code === 'eslint(no-restricted-imports)', ), output, }}
/** * Run Oxlint on a single file and return { passed, output }. * Uses the production .oxlintrc.json. * * The production config ignores intentionally invalid fixture files during * routine lint. For this probe, remove only that ignore from a temporary copy * of the same config; all production rule overrides remain in force. */async function runOxlintOnFile( filePath: string,): Promise<{ hasRestrictedImportError: boolean; output: string }> { const config = JSON.parse(readFileSync(path.join(PROJECT_ROOT, '.oxlintrc.json'), 'utf8')) as { ignorePatterns: string[] } config.ignorePatterns = config.ignorePatterns.filter(pattern => !pattern.includes('__lint-test-fixtures__')) const testConfig = path.join(PROJECT_ROOT, `.oxlintrc.fixture-${randomUUID()}.json`) writeFileSync(testConfig, JSON.stringify(config)) try { try { const { stdout } = await execFileAsync(oxlint, [ '--config', testConfig, '--no-ignore', '--format=json', path.relative(PROJECT_ROOT, filePath), ], { cwd: PROJECT_ROOT, }) return parseResult(stdout) } catch (error) { const stdout = (error as { stdout?: string }).stdout ?? '[]' return parseResult(stdout) } } finally { rmSync(testConfig, { force: true }) }}
describe('Plugin layer isolation lint rule', () => { it('flags imports from src/services/ in plugin code', async () => { const filePath = path.join(FIXTURES_DIR, 'forbidden-services-import.ts') const result = await runOxlintOnFile(filePath)
expect(result.hasRestrictedImportError).toBe(true) expect(result.output).toContain('no-restricted-imports') expect(result.output).toContain('services') })
it('flags imports from src/editor/ in plugin code', async () => { const filePath = path.join(FIXTURES_DIR, 'forbidden-editor-import.ts') const result = await runOxlintOnFile(filePath)
expect(result.hasRestrictedImportError).toBe(true) expect(result.output).toContain('no-restricted-imports') expect(result.output).toContain('editor') })
it('flags imports from src/layout/ in plugin code', async () => { const filePath = path.join(FIXTURES_DIR, 'forbidden-layout-import.ts') const result = await runOxlintOnFile(filePath)
expect(result.hasRestrictedImportError).toBe(true) expect(result.output).toContain('no-restricted-imports') expect(result.output).toContain('layout') })
it('allows imports from obsidian in plugin code', async () => { const filePath = path.join(FIXTURES_DIR, 'allowed-obsidian-import.ts') const result = await runOxlintOnFile(filePath)
// This file should not violate the layer-isolation rule. expect(result.hasRestrictedImportError).toBe(false) })
it('does NOT flag forbidden imports in __tests__/ files (test setup exception)', async () => { // Test files that import from services are allowed — they need internal access // for test setup (constructing FileIndex, MetadataCache, etc.). // We verify by running lint on an existing test file that imports FileIndex. const testFilePath = path.resolve( __dirname, '../wikilink/__tests__/wikilink-plugin.test.ts' ) const result = await runOxlintOnFile(testFilePath)
// Test files should be allowed to import from services expect(result.hasRestrictedImportError).toBe(false) })})