diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fdfaa1..1e267e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,5 +13,5 @@ jobs: - run: yarn install --immutable - run: yarn lint - run: yarn format:check - - run: yarn build - run: yarn test + - run: yarn typecheck diff --git a/.gitignore b/.gitignore index db7cad6..c2616eb 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ dist *.tgz + +.vitest_cache diff --git a/.vscode/settings.json b/.vscode/settings.json index ce77b50..e5fc04b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,12 @@ }, "prettier.prettierPath": ".yarn/sdks/prettier/index.cjs", "prettier.configPath": ".prettierrc.json", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always", + "source.fixAll.ts": "always", + "source.organizeImports": "always", + "source.removeUnusedImports": "always" + }, "js/ts.tsdk.path": ".yarn/sdks/typescript/lib", "eslint.nodePath": ".yarn/sdks" } diff --git a/tests/fixtures/other-repo/CODEOWNERS b/fixtures/other-repo/CODEOWNERS similarity index 100% rename from tests/fixtures/other-repo/CODEOWNERS rename to fixtures/other-repo/CODEOWNERS diff --git a/tests/fixtures/repo/CODEOWNERS b/fixtures/repo/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/CODEOWNERS rename to fixtures/repo/CODEOWNERS diff --git a/tests/fixtures/repo/services/ads/CODEOWNERS b/fixtures/repo/services/ads/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/ads/CODEOWNERS rename to fixtures/repo/services/ads/CODEOWNERS diff --git a/tests/fixtures/repo/services/ads/ads-platform/CODEOWNERS b/fixtures/repo/services/ads/ads-platform/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/ads/ads-platform/CODEOWNERS rename to fixtures/repo/services/ads/ads-platform/CODEOWNERS diff --git a/tests/fixtures/repo/services/auth-cert/CODEOWNERS b/fixtures/repo/services/auth-cert/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/auth-cert/CODEOWNERS rename to fixtures/repo/services/auth-cert/CODEOWNERS diff --git a/tests/fixtures/repo/services/auth/CODEOWNERS b/fixtures/repo/services/auth/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/auth/CODEOWNERS rename to fixtures/repo/services/auth/CODEOWNERS diff --git a/tests/fixtures/repo/services/auth/login/CODEOWNERS b/fixtures/repo/services/auth/login/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/auth/login/CODEOWNERS rename to fixtures/repo/services/auth/login/CODEOWNERS diff --git a/tests/fixtures/repo/services/auth/login/admin/CODEOWNERS b/fixtures/repo/services/auth/login/admin/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/auth/login/admin/CODEOWNERS rename to fixtures/repo/services/auth/login/admin/CODEOWNERS diff --git a/tests/fixtures/repo/services/builder/desktop/CODEOWNERS b/fixtures/repo/services/builder/desktop/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/builder/desktop/CODEOWNERS rename to fixtures/repo/services/builder/desktop/CODEOWNERS diff --git a/tests/fixtures/repo/services/builder/form/CODEOWNERS b/fixtures/repo/services/builder/form/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/builder/form/CODEOWNERS rename to fixtures/repo/services/builder/form/CODEOWNERS diff --git a/tests/fixtures/repo/services/cart/CODEOWNERS b/fixtures/repo/services/cart/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/services/cart/CODEOWNERS rename to fixtures/repo/services/cart/CODEOWNERS diff --git a/tests/fixtures/repo/tools/catalog-cli/CODEOWNERS b/fixtures/repo/tools/catalog-cli/CODEOWNERS similarity index 100% rename from tests/fixtures/repo/tools/catalog-cli/CODEOWNERS rename to fixtures/repo/tools/catalog-cli/CODEOWNERS diff --git a/package.json b/package.json index 0e1b808..2be5898 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ ], "scripts": { "build": "tsdown", - "test": "yarn build && node --test tests/*.test.mjs", + "test": "vitest run", "dev": "tsdown --watch", "prepack": "yarn build", "lint": "eslint .", @@ -54,7 +54,9 @@ "prettier": "^3.8.0", "tsdown": "^0.19.0", "typescript": "^5.9.2", - "typescript-eslint": "^8.27.0" + "typescript-eslint": "^8.27.0", + "vite": "^8.3.1", + "vitest": "^5.0.2" }, "dependencies": { "clipanion": "^4.0.0-rc.4", diff --git a/src/core/jobs/codeowners/codeowners-job.spec.ts b/src/core/jobs/codeowners/codeowners-job.spec.ts new file mode 100644 index 0000000..a173677 --- /dev/null +++ b/src/core/jobs/codeowners/codeowners-job.spec.ts @@ -0,0 +1,224 @@ +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { Fixture } from '@fixture-kit/core'; + +import { codeownersJob } from './codeowners-job'; + +const fixtureDirectory = fileURLToPath(new URL('../../../../fixtures/repo/', import.meta.url)); + +async function readFixtureFiles(rootDir: string, filePaths: string[]) { + return Promise.all( + filePaths.map(async (filePath) => ({ + path: filePath, + contents: await readFile(path.resolve(rootDir, filePath), 'utf8'), + })), + ); +} + +describe('codeownersJob', () => { + it('merges parent CODEOWNERS before nested files', async () => { + await using fixture = await Fixture.fromDirectory(fixtureDirectory); + const rootDir = fixture.root; + // Lexical path order places ads-platform/CODEOWNERS before ads/CODEOWNERS. + const inputFiles = await readFixtureFiles(rootDir, [ + path.join(rootDir, 'services/ads/ads-platform/CODEOWNERS'), + path.join(rootDir, 'services/ads/CODEOWNERS'), + ]); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/services/ads/ @ads-team\n' + + '/services/ads/ads-platform/ @platform-team\n' + + '/services/ads/ads-platform/special/ @special-team\n', + ); + }); + + it('keeps each directory subtree together with parents first', async () => { + await using fixture = await Fixture.fromDirectory(fixtureDirectory); + const rootDir = fixture.root; + const inputFiles = await readFixtureFiles(rootDir, [ + path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), + path.join(rootDir, 'services/auth-cert/CODEOWNERS'), + path.join(rootDir, 'services/auth/login/admin/CODEOWNERS'), + path.join(rootDir, 'services/auth/login/CODEOWNERS'), + path.join(rootDir, 'services/auth/CODEOWNERS'), + path.join(rootDir, 'CODEOWNERS'), + ]); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/ @root-team\n' + + '/docs/ @docs-team\n' + + '/services/auth/ @auth-team\n' + + '/services/auth/login/ @login-team\n' + + '/services/auth/login/admin/ @admin-team\n' + + '/services/auth-cert/ @cert-team\n' + + '/tools/catalog-cli/ @tools-team\n', + ); + }); + + it('groups nested directories even when their parent has no CODEOWNERS', async () => { + await using fixture = await Fixture.fromDirectory(fixtureDirectory); + const rootDir = fixture.root; + const inputFiles = await readFixtureFiles(rootDir, [ + path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), + path.join(rootDir, 'services/cart/CODEOWNERS'), + path.join(rootDir, 'services/builder/form/CODEOWNERS'), + path.join(rootDir, 'services/builder/desktop/CODEOWNERS'), + ]); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/services/builder/desktop/ @desktop-team\n' + + '/services/builder/form/ @form-team\n' + + '/services/cart/ @cart-team\n' + + '/tools/catalog-cli/ @tools-team\n', + ); + }); + + it('resolves relative and absolute CODEOWNERS paths against rootDir', async () => { + await using fixture = await Fixture.fromDirectory(fixtureDirectory); + const rootDir = fixture.root; + const inputFiles = await readFixtureFiles(rootDir, [ + 'services/auth/login/CODEOWNERS', + path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), + 'services/auth/CODEOWNERS', + 'CODEOWNERS', + ]); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/ @root-team\n' + + '/docs/ @docs-team\n' + + '/services/auth/ @auth-team\n' + + '/services/auth/login/ @login-team\n' + + '/tools/catalog-cli/ @tools-team\n', + ); + }); + + it.each(['./services/auth/login/CODEOWNERS', 'services/./auth/../../services/auth/login/CODEOWNERS'])( + 'normalizes %s before ordering parent and child rules', + async (childPath) => { + await using fixture = await Fixture.fromDirectory(fixtureDirectory); + const rootDir = fixture.root; + const inputFiles = await readFixtureFiles(rootDir, [childPath, 'services/auth/CODEOWNERS']); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe('/services/auth/ @auth-team\n/services/auth/login/ @login-team\n'); + }, + ); + + it('keeps normalized path aliases stable without mutating the input', async () => { + const rootDir = process.cwd(); + const inputFiles = [ + { path: 'services/auth/CODEOWNERS', contents: '* @first\n' }, + { + path: path.join(rootDir, 'services/auth/CODEOWNERS'), + contents: '* @second\n', + }, + { + path: './services/auth/login/../CODEOWNERS', + contents: '* @last\n', + }, + ].map((file) => Object.freeze(file)); + Object.freeze(inputFiles); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe('/services/auth/ @first\n' + '/services/auth/ @second\n' + '/services/auth/ @last\n'); + }); + + it('keeps locale-equivalent directory names in separate subtrees', async () => { + const rootDir = process.cwd(); + const inputFiles = [ + { + path: 'services/é/child/CODEOWNERS', + contents: '* @composed-child\n', + }, + { + path: 'services/e\u0301/CODEOWNERS', + contents: '* @decomposed-parent\n', + }, + { + path: 'services/é/CODEOWNERS', + contents: '* @composed-parent\n', + }, + { + path: 'services/e\u0301/child/CODEOWNERS', + contents: '* @decomposed-child\n', + }, + ]; + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/services/e\u0301/ @decomposed-parent\n' + + '/services/e\u0301/child/ @decomposed-child\n' + + '/services/é/ @composed-parent\n' + + '/services/é/child/ @composed-child\n', + ); + }); + + it('sorts filenames stably without mutating the input', async () => { + const rootDir = process.cwd(); + const inputFiles = [ + { + path: 'services/auth/Z-CODEOWNERS', + contents: '* @last\n', + }, + { + path: 'services/auth/é-CODEOWNERS', + contents: '* @composed\n', + }, + { + path: 'services/auth/e\u0301-CODEOWNERS', + contents: '* @decomposed\n', + }, + { + path: 'services/auth/A-CODEOWNERS', + contents: '* @first\n', + }, + ].map((file) => Object.freeze(file)); + Object.freeze(inputFiles); + + const result = await codeownersJob().transform(inputFiles, { + rootDir, + outputPath: path.join(rootDir, '.github/CODEOWNERS'), + }); + + expect(result).toBe( + '/services/auth/ @first\n' + + '/services/auth/ @composed\n' + + '/services/auth/ @decomposed\n' + + '/services/auth/ @last\n', + ); + }); +}); diff --git a/tests/codeowners-cli.test.mjs b/tests/codeowners-cli.spec.ts similarity index 59% rename from tests/codeowners-cli.test.mjs rename to tests/codeowners-cli.spec.ts index 331eafd..3085007 100644 --- a/tests/codeowners-cli.test.mjs +++ b/tests/codeowners-cli.spec.ts @@ -1,31 +1,33 @@ -import assert from 'node:assert/strict'; import { execFile } from 'node:child_process'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import path from 'node:path'; -import { test } from 'node:test'; import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; import { Fixture } from '@fixture-kit/core'; const execFileAsync = promisify(execFile); -const cliPath = fileURLToPath(new URL('../dist/bin/index.mjs', import.meta.url)); -const coreUrl = new URL('../dist/core/index.mjs', import.meta.url).href; -const config = `import { codeownersJob } from ${JSON.stringify(coreUrl)}; +const CLI_PATH = fileURLToPath(new URL('../dist/bin/index.mjs', import.meta.url)); +const CORE_URL = new URL('../dist/core/index.mjs', import.meta.url).href; +const config = `import { codeownersJob } from ${JSON.stringify(CORE_URL)}; export default [codeownersJob()]; `; -for (const scenario of [ - { name: 'the repository root', cwd: 'repo', explicitRoot: false }, - { name: 'a subdirectory', cwd: 'repo/services/auth', explicitRoot: false }, - { - name: 'another repository with --root', - cwd: 'other-repo', - explicitRoot: true, - }, -]) { - test(`sync resolves CODEOWNERS paths from ${scenario.name}`, async () => { - await using fixture = await Fixture.fromDirectory(fileURLToPath(new URL('./fixtures/', import.meta.url))); +beforeAll(async () => { + await execFileAsync('yarn', ['build'], { cwd: fileURLToPath(new URL('../', import.meta.url)) }); +}); + +describe('codeowners-cli', () => { + it.each([ + { name: 'the repository root', cwd: 'repo', explicitRoot: false }, + { name: 'a subdirectory', cwd: 'repo/services/auth', explicitRoot: false }, + { + name: 'another repository with --root', + cwd: 'other-repo', + explicitRoot: true, + }, + ])('sync resolves CODEOWNERS paths from $name', async (scenario) => { + await using fixture = await Fixture.fromDirectory(fileURLToPath(new URL('../fixtures/', import.meta.url))); const rootDir = path.join(fixture.root, 'repo'); const subdirectory = path.join(rootDir, 'services/auth'); const otherRoot = path.join(fixture.root, 'other-repo'); @@ -38,7 +40,7 @@ for (const scenario of [ for (const directory of [rootDir, subdirectory, otherRoot]) { await writeFile(path.join(directory, 'pullup.config.mjs'), config); } - const args = [cliPath, 'sync']; + const args = [CLI_PATH, 'sync']; if (scenario.explicitRoot) args.push('--root', rootDir); await execFileAsync(process.execPath, args, { @@ -46,8 +48,7 @@ for (const scenario of [ timeout: 10_000, }); - assert.equal( - await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8'), + expect(await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8')).toBe( '/ @root-team\n' + '/docs/ @docs-team\n' + '/services/ads/ @ads-team\n' + @@ -63,38 +64,37 @@ for (const scenario of [ '/tools/catalog-cli/ @tools-team\n', ); if (scenario.explicitRoot) { - await assert.rejects(readFile(path.join(otherRoot, '.github/CODEOWNERS'), 'utf8'), { code: 'ENOENT' }); + await expect(readFile(path.join(otherRoot, '.github/CODEOWNERS'), 'utf8')).rejects.toMatchObject({ + code: 'ENOENT', + }); } }); -} -for (const scenario of [ - { - name: './', - input: ['services/auth/CODEOWNERS', './services/auth/login/CODEOWNERS'], - }, - { - name: '..', - input: ['services/auth/CODEOWNERS', 'services/../services/auth/login/CODEOWNERS'], - }, -]) { - test(`sync normalizes ${scenario.name} in CODEOWNERS input paths before sorting`, async () => { - await using fixture = await Fixture.fromDirectory(fileURLToPath(new URL('./fixtures/repo/', import.meta.url))); + it.each([ + { + name: './', + input: ['services/auth/CODEOWNERS', './services/auth/login/CODEOWNERS'], + }, + { + name: '..', + input: ['services/auth/CODEOWNERS', 'services/../services/auth/login/CODEOWNERS'], + }, + ])('sync normalizes $name in CODEOWNERS input paths before sorting', async (scenario) => { + await using fixture = await Fixture.fromDirectory(fileURLToPath(new URL('../fixtures/repo/', import.meta.url))); const rootDir = fixture.root; - const customConfig = `import { codeownersJob } from ${JSON.stringify(coreUrl)}; + const customConfig = `import { codeownersJob } from ${JSON.stringify(CORE_URL)}; export default [codeownersJob({ input: ${JSON.stringify(scenario.input)} })]; `; await mkdir(path.join(rootDir, '.git')); await writeFile(path.join(rootDir, 'pullup.config.mjs'), customConfig); - await execFileAsync(process.execPath, [cliPath, 'sync'], { + await execFileAsync(process.execPath, [CLI_PATH, 'sync'], { cwd: rootDir, timeout: 10_000, }); - assert.equal( - await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8'), + expect(await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8')).toBe( '/services/auth/ @auth-team\n' + '/services/auth/login/ @login-team\n', ); }); -} +}); diff --git a/tests/codeowners-job.test.mjs b/tests/codeowners-job.test.mjs deleted file mode 100644 index 13d02c3..0000000 --- a/tests/codeowners-job.test.mjs +++ /dev/null @@ -1,231 +0,0 @@ -import assert from 'node:assert/strict'; -import { readFile } from 'node:fs/promises'; -import path from 'node:path'; -import { test } from 'node:test'; -import { fileURLToPath } from 'node:url'; - -import { Fixture } from '@fixture-kit/core'; - -import { codeownersJob } from '../dist/core/index.mjs'; - -const fixtureDirectory = fileURLToPath(new URL('./fixtures/repo/', import.meta.url)); - -async function readFixtureFiles(rootDir, filePaths) { - return Promise.all( - filePaths.map(async (filePath) => ({ - path: filePath, - contents: await readFile(path.resolve(rootDir, filePath), 'utf8'), - })), - ); -} - -test('merges parent CODEOWNERS before nested files', async () => { - await using fixture = await Fixture.fromDirectory(fixtureDirectory); - const rootDir = fixture.root; - // Lexical path order places ads-platform/CODEOWNERS before ads/CODEOWNERS. - const inputFiles = await readFixtureFiles(rootDir, [ - path.join(rootDir, 'services/ads/ads-platform/CODEOWNERS'), - path.join(rootDir, 'services/ads/CODEOWNERS'), - ]); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/services/ads/ @ads-team\n' + - '/services/ads/ads-platform/ @platform-team\n' + - '/services/ads/ads-platform/special/ @special-team\n', - ); -}); - -test('keeps each directory subtree together with parents first', async () => { - await using fixture = await Fixture.fromDirectory(fixtureDirectory); - const rootDir = fixture.root; - const inputFiles = await readFixtureFiles(rootDir, [ - path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), - path.join(rootDir, 'services/auth-cert/CODEOWNERS'), - path.join(rootDir, 'services/auth/login/admin/CODEOWNERS'), - path.join(rootDir, 'services/auth/login/CODEOWNERS'), - path.join(rootDir, 'services/auth/CODEOWNERS'), - path.join(rootDir, 'CODEOWNERS'), - ]); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/ @root-team\n' + - '/docs/ @docs-team\n' + - '/services/auth/ @auth-team\n' + - '/services/auth/login/ @login-team\n' + - '/services/auth/login/admin/ @admin-team\n' + - '/services/auth-cert/ @cert-team\n' + - '/tools/catalog-cli/ @tools-team\n', - ); -}); - -test('groups nested directories even when their parent has no CODEOWNERS', async () => { - await using fixture = await Fixture.fromDirectory(fixtureDirectory); - const rootDir = fixture.root; - const inputFiles = await readFixtureFiles(rootDir, [ - path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), - path.join(rootDir, 'services/cart/CODEOWNERS'), - path.join(rootDir, 'services/builder/form/CODEOWNERS'), - path.join(rootDir, 'services/builder/desktop/CODEOWNERS'), - ]); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/services/builder/desktop/ @desktop-team\n' + - '/services/builder/form/ @form-team\n' + - '/services/cart/ @cart-team\n' + - '/tools/catalog-cli/ @tools-team\n', - ); -}); - -test('resolves relative and absolute CODEOWNERS paths against rootDir', async () => { - await using fixture = await Fixture.fromDirectory(fixtureDirectory); - const rootDir = fixture.root; - const inputFiles = await readFixtureFiles(rootDir, [ - 'services/auth/login/CODEOWNERS', - path.join(rootDir, 'tools/catalog-cli/CODEOWNERS'), - 'services/auth/CODEOWNERS', - 'CODEOWNERS', - ]); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/ @root-team\n' + - '/docs/ @docs-team\n' + - '/services/auth/ @auth-team\n' + - '/services/auth/login/ @login-team\n' + - '/tools/catalog-cli/ @tools-team\n', - ); -}); - -for (const childPath of ['./services/auth/login/CODEOWNERS', 'services/./auth/../../services/auth/login/CODEOWNERS']) { - test(`normalizes ${childPath} before ordering parent and child rules`, async () => { - await using fixture = await Fixture.fromDirectory(fixtureDirectory); - const rootDir = fixture.root; - const inputFiles = await readFixtureFiles(rootDir, [childPath, 'services/auth/CODEOWNERS']); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal(result, '/services/auth/ @auth-team\n/services/auth/login/ @login-team\n'); - }); -} - -test('keeps normalized path aliases stable without mutating the input', async () => { - const rootDir = process.cwd(); - const inputFiles = Object.freeze( - [ - { path: 'services/auth/CODEOWNERS', contents: '* @first\n' }, - { - path: path.join(rootDir, 'services/auth/CODEOWNERS'), - contents: '* @second\n', - }, - { - path: './services/auth/login/../CODEOWNERS', - contents: '* @last\n', - }, - ].map((file) => Object.freeze(file)), - ); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal(result, '/services/auth/ @first\n' + '/services/auth/ @second\n' + '/services/auth/ @last\n'); -}); - -test('keeps locale-equivalent directory names in separate subtrees', async () => { - const rootDir = process.cwd(); - const inputFiles = [ - { - path: 'services/é/child/CODEOWNERS', - contents: '* @composed-child\n', - }, - { - path: 'services/e\u0301/CODEOWNERS', - contents: '* @decomposed-parent\n', - }, - { - path: 'services/é/CODEOWNERS', - contents: '* @composed-parent\n', - }, - { - path: 'services/e\u0301/child/CODEOWNERS', - contents: '* @decomposed-child\n', - }, - ]; - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/services/e\u0301/ @decomposed-parent\n' + - '/services/e\u0301/child/ @decomposed-child\n' + - '/services/é/ @composed-parent\n' + - '/services/é/child/ @composed-child\n', - ); -}); - -test('sorts filenames stably without mutating the input', async () => { - const rootDir = process.cwd(); - const inputFiles = Object.freeze( - [ - { - path: 'services/auth/Z-CODEOWNERS', - contents: '* @last\n', - }, - { - path: 'services/auth/é-CODEOWNERS', - contents: '* @composed\n', - }, - { - path: 'services/auth/e\u0301-CODEOWNERS', - contents: '* @decomposed\n', - }, - { - path: 'services/auth/A-CODEOWNERS', - contents: '* @first\n', - }, - ].map((file) => Object.freeze(file)), - ); - - const result = await codeownersJob().transform(inputFiles, { - rootDir, - outputPath: path.join(rootDir, '.github/CODEOWNERS'), - }); - - assert.equal( - result, - '/services/auth/ @first\n' + - '/services/auth/ @composed\n' + - '/services/auth/ @decomposed\n' + - '/services/auth/ @last\n', - ); -}); diff --git a/tsconfig.json b/tsconfig.json index c1d56bf..01c8c8d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,7 @@ "strict": true, "experimentalDecorators": true, "lib": ["ESNext", "ESNext.AsyncIterable"], + "types": ["vitest/globals", "@types/node"], "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "allowJs": false, diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..f14cad8 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + cacheDir: '.vitest_cache', + test: { + globals: true, + environment: 'node', + }, +}); diff --git a/yarn.lock b/yarn.lock index e238803..cbd0ee4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -523,6 +523,15 @@ __metadata: languageName: node linkType: hard +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.3.12": version: 0.3.13 resolution: "@jridgewell/gen-mapping@npm:0.3.13" @@ -547,7 +556,14 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": +"@jridgewell/sourcemap-codec@npm:^1.6.0": + version: 1.6.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.6.0" + checksum: 10c0/b5be700e45a775f218589c3466c4ffea630582b4988657652da464e5ab8a7d18bf928ee4fd2363fb346ede4bea9c6ff0bae05a538358c4565ece6199531b5f72 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:0.3.31, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": version: 0.3.31 resolution: "@jridgewell/trace-mapping@npm:0.3.31" dependencies: @@ -646,6 +662,13 @@ __metadata: languageName: node linkType: hard +"@oxc-project/types@npm:=0.151.0": + version: 0.151.0 + resolution: "@oxc-project/types@npm:0.151.0" + checksum: 10c0/7dac5399345abf368449735c31c218439e6c3a2acf7b8cbc715a88b45989390208f61bea0f3eb28bee5a034a509a7f4142ae60069e6611b07c70a30867c8ca84 + languageName: node + linkType: hard + "@pull-up/cli@workspace:.": version: 0.0.0-use.local resolution: "@pull-up/cli@workspace:." @@ -668,6 +691,8 @@ __metadata: tsdown: "npm:^0.19.0" typescript: "npm:^5.9.2" typescript-eslint: "npm:^8.27.0" + vite: "npm:^8.3.1" + vitest: "npm:^5.0.2" bin: pullup: ./dist/bin/index.mjs languageName: unknown @@ -682,6 +707,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-android-arm-eabi@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-android-arm-eabi@npm:1.2.11" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@rolldown/binding-android-arm64@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-android-arm64@npm:1.0.0-beta.59" @@ -696,6 +728,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-android-arm64@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-android-arm64@npm:1.2.11" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-darwin-arm64@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-beta.59" @@ -710,6 +749,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-arm64@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-darwin-arm64@npm:1.2.11" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-darwin-x64@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-beta.59" @@ -724,6 +770,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-x64@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-darwin-x64@npm:1.2.11" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-freebsd-x64@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-beta.59" @@ -738,6 +791,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-freebsd-x64@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-freebsd-x64@npm:1.2.11" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.59" @@ -752,6 +812,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm-gnueabihf@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.2.11" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.59" @@ -766,6 +833,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-gnu@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.2.11" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.59" @@ -780,6 +854,27 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-musl@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.2.11" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rolldown/binding-linux-ppc64-gnu@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.2.11" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-s390x-gnu@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.2.11" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.59" @@ -794,6 +889,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-gnu@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.2.11" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.59" @@ -808,6 +910,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-musl@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.2.11" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rolldown/binding-openharmony-arm64@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-beta.59" @@ -822,6 +931,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-openharmony-arm64@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.2.11" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-wasm32-wasi@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-beta.59" @@ -854,6 +970,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-arm64-msvc@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.2.11" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.59" @@ -868,6 +991,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-x64-msvc@npm:1.2.11": + version: 1.2.11 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.2.11" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rolldown/pluginutils@npm:1.0.0-beta.59": version: 1.0.0-beta.59 resolution: "@rolldown/pluginutils@npm:1.0.0-beta.59" @@ -882,6 +1012,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/pluginutils@npm:^1.0.0": + version: 1.0.1 + resolution: "@rolldown/pluginutils@npm:1.0.1" + checksum: 10c0/99d9b06d90196823e4d8c841f258db7a16e5dbba5824a2962b05d907b79f1ba929d56f22dd744fd530936e568c865ee56a719dc31e57e13bc0a8eb4764a8d8dd + languageName: node + linkType: hard + "@tybys/wasm-util@npm:^0.10.0, @tybys/wasm-util@npm:^0.10.1": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" @@ -891,6 +1028,30 @@ __metadata: languageName: node linkType: hard +"@types/chai@npm:^5.2.2": + version: 5.2.3 + resolution: "@types/chai@npm:5.2.3" + dependencies: + "@types/deep-eql": "npm:*" + assertion-error: "npm:^2.0.1" + checksum: 10c0/e0ef1de3b6f8045a5e473e867c8565788c444271409d155588504840ad1a53611011f85072188c2833941189400228c1745d78323dac13fcede9c2b28bacfb2f + languageName: node + linkType: hard + +"@types/deep-eql@npm:*": + version: 4.0.2 + resolution: "@types/deep-eql@npm:4.0.2" + checksum: 10c0/bf3f811843117900d7084b9d0c852da9a044d12eb40e6de73b552598a6843c21291a8a381b0532644574beecd5e3491c5ff3a0365ab86b15d59862c025384844 + languageName: node + linkType: hard + +"@types/estree@npm:^1.0.0": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + "@types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" @@ -1191,6 +1352,40 @@ __metadata: languageName: node linkType: hard +"@vitest/mocker@npm:5.0.2": + version: 5.0.2 + resolution: "@vitest/mocker@npm:5.0.2" + dependencies: + "@jridgewell/trace-mapping": "npm:0.3.31" + "@vitest/spy": "npm:5.0.2" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^1.2.3" + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10c0/e2d847563d47b61e9f3e5ed2d86af42b753311cd52c94ef7226398fd6f810b96ca4737855bcc4a59d78a0300859db50693d831ab29ca6334b159cc8e870f8149 + languageName: node + linkType: hard + +"@vitest/spy@npm:5.0.2": + version: 5.0.2 + resolution: "@vitest/spy@npm:5.0.2" + checksum: 10c0/4a52231cc7b5b8959bb15a700a761464051a6d0cc35a231fc92fd4f58d10a01012671a20ea37ebc79e98bdd5dc257a3c52db10d6a592944560fb69651f6f1296 + languageName: node + linkType: hard + +"abbrev@npm:^5.0.0": + version: 5.0.0 + resolution: "abbrev@npm:5.0.0" + checksum: 10c0/8e88f5c798ea4562d28c5a3e9ad69e3879890bc5d695d8f2dffb8609be4c890aacc8f80ef4553fdd2c6a62d70c2ce8bc57b38074e383beb7487bdafa9ed42ea5 + languageName: node + linkType: hard + "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -1274,6 +1469,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 + languageName: node + linkType: hard + "ast-kit@npm:^2.2.0": version: 2.2.0 resolution: "ast-kit@npm:2.2.0" @@ -1349,6 +1551,13 @@ __metadata: languageName: node linkType: hard +"chai@npm:^6.2.2": + version: 6.2.2 + resolution: "chai@npm:6.2.2" + checksum: 10c0/e6c69e5f0c11dffe6ea13d0290936ebb68fcc1ad688b8e952e131df6a6d5797d5e860bc55cef1aca2e950c3e1f96daf79e9d5a70fb7dbaab4e46355e2635ed53 + languageName: node + linkType: hard + "chalk@npm:^4.0.0": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -1366,6 +1575,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + "ci-info@npm:^3.7.0": version: 3.9.0 resolution: "ci-info@npm:3.9.0" @@ -1482,6 +1698,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.3": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -1527,7 +1750,7 @@ __metadata: languageName: node linkType: hard -"env-paths@npm:^2.2.1": +"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 @@ -1543,6 +1766,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^2.3.2": + version: 2.3.2 + resolution: "es-module-lexer@npm:2.3.2" + checksum: 10c0/5e7389424c43478439f12f9a6aca1750f6f99afa384fc3de329f4a45f152ab156671055008adaafc74960877abf8cc338aeebf6bed8c21297b146fd6eb7a22f8 + languageName: node + linkType: hard + "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" @@ -1719,6 +1949,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -1726,6 +1965,20 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.4.0": + version: 1.4.0 + resolution: "expect-type@npm:1.4.0" + checksum: 10c0/d40d76b8570695d36587beb3cc28494da2ca3ec8f04e67f5622ed2d372d850e401a9adef19c6835e1a8173903f157c79540b34c7b3fbd7cd8ce726cc903c57b7 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 + languageName: node + linkType: hard + "extendable-error@npm:^0.1.5": version: 0.1.7 resolution: "extendable-error@npm:0.1.7" @@ -1875,6 +2128,25 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "get-tsconfig@npm:^4.10.1, get-tsconfig@npm:^4.13.0": version: 4.13.0 resolution: "get-tsconfig@npm:4.13.0" @@ -1930,7 +2202,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0": +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -2060,6 +2332,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce + languageName: node + linkType: hard + "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -2158,6 +2437,126 @@ __metadata: languageName: node linkType: hard +"lightningcss-android-arm64@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-android-arm64@npm:1.33.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-arm64@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-darwin-arm64@npm:1.33.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-x64@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-darwin-x64@npm:1.33.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-freebsd-x64@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-freebsd-x64@npm:1.33.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-linux-arm-gnueabihf@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.33.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"lightningcss-linux-arm64-gnu@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-linux-arm64-gnu@npm:1.33.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-arm64-musl@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-linux-arm64-musl@npm:1.33.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-linux-x64-gnu@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-linux-x64-gnu@npm:1.33.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-x64-musl@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-linux-x64-musl@npm:1.33.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-win32-arm64-msvc@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-win32-arm64-msvc@npm:1.33.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-win32-x64-msvc@npm:1.33.0": + version: 1.33.0 + resolution: "lightningcss-win32-x64-msvc@npm:1.33.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"lightningcss@npm:^1.33.0": + version: 1.33.0 + resolution: "lightningcss@npm:1.33.0" + dependencies: + detect-libc: "npm:^2.0.3" + lightningcss-android-arm64: "npm:1.33.0" + lightningcss-darwin-arm64: "npm:1.33.0" + lightningcss-darwin-x64: "npm:1.33.0" + lightningcss-freebsd-x64: "npm:1.33.0" + lightningcss-linux-arm-gnueabihf: "npm:1.33.0" + lightningcss-linux-arm64-gnu: "npm:1.33.0" + lightningcss-linux-arm64-musl: "npm:1.33.0" + lightningcss-linux-x64-gnu: "npm:1.33.0" + lightningcss-linux-x64-musl: "npm:1.33.0" + lightningcss-win32-arm64-msvc: "npm:1.33.0" + lightningcss-win32-x64-msvc: "npm:1.33.0" + dependenciesMeta: + lightningcss-android-arm64: + optional: true + lightningcss-darwin-arm64: + optional: true + lightningcss-darwin-x64: + optional: true + lightningcss-freebsd-x64: + optional: true + lightningcss-linux-arm-gnueabihf: + optional: true + lightningcss-linux-arm64-gnu: + optional: true + lightningcss-linux-arm64-musl: + optional: true + lightningcss-linux-x64-gnu: + optional: true + lightningcss-linux-x64-musl: + optional: true + lightningcss-win32-arm64-msvc: + optional: true + lightningcss-win32-x64-msvc: + optional: true + checksum: 10c0/ce1f8279fbae636dbf37fa6e7385d5f98ed881d72af3362f24afbd4685e19c1fcdfecf17e5dd77f2ebee3d0c23ade276230d85842d07292229a2cffba8ff20a3 + languageName: node + linkType: hard + "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -2206,6 +2605,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^1.2.3": + version: 1.4.2 + resolution: "magic-string@npm:1.4.2" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.6.0" + checksum: 10c0/d3e222c202f99ec4861e7316f473f9b1cfe335ebdf38d4f67335f842f3fe248f01ee00fd3e1a8206bcbe9855e0c41515d7c210300d8fcf6eefbb982d79e423c6 + languageName: node + linkType: hard + "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" @@ -2250,6 +2658,22 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb + languageName: node + linkType: hard + +"minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + "mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" @@ -2264,6 +2688,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.18": + version: 3.3.19 + resolution: "nanoid@npm:3.3.19" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/ce7afa6258bfaa00bdc8de291cfe9913280eaa403b7d9cff3db4e4200c1913e7163577df74897958da144db473a96c67f74f57db0f542fbfe409df677bae3255 + languageName: node + linkType: hard + "napi-postinstall@npm:^0.3.0": version: 0.3.4 resolution: "napi-postinstall@npm:0.3.4" @@ -2294,6 +2727,37 @@ __metadata: languageName: node linkType: hard +"node-gyp@npm:latest": + version: 13.0.2 + resolution: "node-gyp@npm:13.0.2" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + nopt: "npm:^10.0.0" + proc-log: "npm:^7.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + undici: "npm:^8.4.1" + which: "npm:^7.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/29d33ccf47ffeeb5e7af925550b416f698a26a72eb10975c7eb5775c1d0cecacd76d164a4aa45503d3ddcece209db65c712be00423c69381a4cd14e2e6540559 + languageName: node + linkType: hard + +"nopt@npm:^10.0.0": + version: 10.0.1 + resolution: "nopt@npm:10.0.1" + dependencies: + abbrev: "npm:^5.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/980d89257f9587f3e1f77877ddbf905d6aa3b738ec33e49a4fa1a059a0dd82eb28063982b150654a7ae9de386f2ead60e56172db7d37cf56de545f7392a2a26a + languageName: node + linkType: hard + "obug@npm:^2.1.1": version: 2.1.1 resolution: "obug@npm:2.1.1" @@ -2301,6 +2765,13 @@ __metadata: languageName: node linkType: hard +"obug@npm:^2.1.4": + version: 2.2.1 + resolution: "obug@npm:2.2.1" + checksum: 10c0/8a7c001847d880fa6ba83c7bbee6a80fd271ee628439cd508c8647d53b217abb1759e2d5e4aaeb09a35d0a274bdb225a0a5a78eded3213d63e656153cf411b63 + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" @@ -2478,6 +2949,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.4, picomatch@npm:^4.0.7": + version: 4.0.7 + resolution: "picomatch@npm:4.0.7" + checksum: 10c0/beb6ae02c43ae44e84883b90830196d9046b1726ead292adcf7f57945e0bb0d992d68563d87e03b484b6f3c9a5c6defda7523477f047d7f0e663f126cc01787f + languageName: node + linkType: hard + "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" @@ -2485,6 +2963,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.5.28": + version: 8.5.28 + resolution: "postcss@npm:8.5.28" + dependencies: + nanoid: "npm:^3.3.18" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/9fe44215a6628d89c8a75184b92f5b2f77e16f9e5b13b39b9009bb7e8e6eccddf82c8854bae922db1f17ace6ef3445073fe38abff513caeb03e5285b1b55620a + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -2510,6 +2999,13 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^7.0.0": + version: 7.0.0 + resolution: "proc-log@npm:7.0.0" + checksum: 10c0/b89c2d862604f35fec795477b0c7e376feab3ba0d4f4d291c4e959567442697cf451ac557d0623c1cc38af45a78128b983410f397a10c5d3a67f76c33de4754b + languageName: node + linkType: hard + "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -2713,6 +3209,64 @@ __metadata: languageName: node linkType: hard +"rolldown@npm:~1.2.9": + version: 1.2.11 + resolution: "rolldown@npm:1.2.11" + dependencies: + "@oxc-project/types": "npm:=0.151.0" + "@rolldown/binding-android-arm-eabi": "npm:1.2.11" + "@rolldown/binding-android-arm64": "npm:1.2.11" + "@rolldown/binding-darwin-arm64": "npm:1.2.11" + "@rolldown/binding-darwin-x64": "npm:1.2.11" + "@rolldown/binding-freebsd-x64": "npm:1.2.11" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.2.11" + "@rolldown/binding-linux-arm64-gnu": "npm:1.2.11" + "@rolldown/binding-linux-arm64-musl": "npm:1.2.11" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.2.11" + "@rolldown/binding-linux-s390x-gnu": "npm:1.2.11" + "@rolldown/binding-linux-x64-gnu": "npm:1.2.11" + "@rolldown/binding-linux-x64-musl": "npm:1.2.11" + "@rolldown/binding-openharmony-arm64": "npm:1.2.11" + "@rolldown/binding-win32-arm64-msvc": "npm:1.2.11" + "@rolldown/binding-win32-x64-msvc": "npm:1.2.11" + "@rolldown/pluginutils": "npm:^1.0.0" + dependenciesMeta: + "@rolldown/binding-android-arm-eabi": + optional: true + "@rolldown/binding-android-arm64": + optional: true + "@rolldown/binding-darwin-arm64": + optional: true + "@rolldown/binding-darwin-x64": + optional: true + "@rolldown/binding-freebsd-x64": + optional: true + "@rolldown/binding-linux-arm-gnueabihf": + optional: true + "@rolldown/binding-linux-arm64-gnu": + optional: true + "@rolldown/binding-linux-arm64-musl": + optional: true + "@rolldown/binding-linux-ppc64-gnu": + optional: true + "@rolldown/binding-linux-s390x-gnu": + optional: true + "@rolldown/binding-linux-x64-gnu": + optional: true + "@rolldown/binding-linux-x64-musl": + optional: true + "@rolldown/binding-openharmony-arm64": + optional: true + "@rolldown/binding-win32-arm64-msvc": + optional: true + "@rolldown/binding-win32-x64-msvc": + optional: true + bin: + rolldown: ./bin/cli.mjs + checksum: 10c0/43dfd083fb625a254c039bddfe04f3dd1d7cf8b84291ead835e3702e8050b7fee5e702c8280d3000b2541c0e24aaa3110bac4251bc2ca50a85fe1c8bbb48d2f5 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -2729,6 +3283,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.3.5": + version: 7.8.5 + resolution: "semver@npm:7.8.5" + bin: + semver: bin/semver.js + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c + languageName: node + linkType: hard + "semver@npm:^7.5.3, semver@npm:^7.7.2, semver@npm:^7.7.3": version: 7.7.3 resolution: "semver@npm:7.7.3" @@ -2768,6 +3331,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + "spawndamnit@npm:^3.0.1": version: 3.0.1 resolution: "spawndamnit@npm:3.0.1" @@ -2792,6 +3362,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^4.2.0": + version: 4.2.0 + resolution: "std-env@npm:4.2.0" + checksum: 10c0/40ac525ce7b7c556abc332a7376f14356eeb1a7f17f6ff9a003eb9f52326ff1f3745d3e1b43452675b1ec6fcc319f1b1d6f3b0d386cf3f91058479ad883cff69 + languageName: node + linkType: hard + "strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -2824,6 +3401,19 @@ __metadata: languageName: node linkType: hard +"tar@npm:^7.5.4": + version: 7.5.22 + resolution: "tar@npm:7.5.22" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/1311f6be85a8157ac4c9147bae43e13923d2a1aae15e4aa1bd5239e4e03d2cf53cfe103dde7f35832fbb4c938b042856bc8e9a0afd29abd05e2d1608788c4fea + languageName: node + linkType: hard + "term-size@npm:^2.1.0": version: 2.2.1 resolution: "term-size@npm:2.2.1" @@ -2831,6 +3421,13 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^6.1.4": + version: 6.2.0 + resolution: "tinybench@npm:6.2.0" + checksum: 10c0/ae821428f0412324611d449290f8497c886c94f04bad8e19aa9b3a5060b4802e738c49f9eb493e4fd17e4d5e792290565e5079be647df1995aea731c82363815 + languageName: node + linkType: hard + "tinyexec@npm:^1.0.2": version: 1.0.2 resolution: "tinyexec@npm:1.0.2" @@ -2838,6 +3435,23 @@ __metadata: languageName: node linkType: hard +"tinyexec@npm:^1.3.0": + version: 1.3.1 + resolution: "tinyexec@npm:1.3.1" + checksum: 10c0/c590369cb3fa73cc18a3998caec8a00f9712d91309c881be3ac52b160fb2f80c7b1fbf3591858ab6abab47ad55385b0c86ec19982e32441a01f55298dab9ccd2 + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.17": + version: 0.2.17 + resolution: "tinyglobby@npm:0.2.17" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" @@ -3003,6 +3617,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^8.4.1": + version: 8.11.2 + resolution: "undici@npm:8.11.2" + checksum: 10c0/106f6991178fb7562fd90cdec7993c5f807a9428682306091f0c4b27fc474ec291f868e29972c6252988bf061ad193df943b3b99e775be157a28d92bbb95699d + languageName: node + linkType: hard + "unicorn-magic@npm:^0.3.0": version: 0.3.0 resolution: "unicorn-magic@npm:0.3.0" @@ -3109,6 +3730,124 @@ __metadata: languageName: node linkType: hard +"vite@npm:^8.3.1": + version: 8.3.1 + resolution: "vite@npm:8.3.1" + dependencies: + fsevents: "npm:~2.3.3" + lightningcss: "npm:^1.33.0" + picomatch: "npm:^4.0.7" + postcss: "npm:^8.5.28" + rolldown: "npm:~1.2.9" + tinyglobby: "npm:^0.2.17" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + "@vitejs/devtools": ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: ">=1.21.0" + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + "@vitejs/devtools": + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/a91f4fee1cd331912ee3ac45f49900044846e28b8632ae734fe1978630e643e503d04181b2aeac59f70556fc51137dd49179fd39cbeb72a3e5f0bce88d2bcd30 + languageName: node + linkType: hard + +"vitest@npm:^5.0.2": + version: 5.0.2 + resolution: "vitest@npm:5.0.2" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/mocker": "npm:5.0.2" + chai: "npm:^6.2.2" + es-module-lexer: "npm:^2.3.2" + expect-type: "npm:^1.4.0" + magic-string: "npm:^1.2.3" + obug: "npm:^2.1.4" + picomatch: "npm:^4.0.7" + std-env: "npm:^4.2.0" + tinybench: "npm:^6.1.4" + tinyexec: "npm:^1.3.0" + tinyglobby: "npm:^0.2.17" + why-is-node-running: "npm:^3.2.1" + peerDependencies: + "@edge-runtime/vm": "*" + "@opentelemetry/api": ^1.9.0 + "@types/node": ^22.0.0 || >=24.0.0 + "@vitest/browser-playwright": 5.0.2 + "@vitest/browser-preview": 5.0.2 + "@vitest/browser-webdriverio": ^5.0.0-beta.5 || >=5.0.0 + "@vitest/coverage-istanbul": 5.0.2 + "@vitest/coverage-v8": 5.0.2 + "@vitest/ui": 5.0.2 + happy-dom: "*" + jsdom: "*" + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@opentelemetry/api": + optional: true + "@types/node": + optional: true + "@vitest/browser-playwright": + optional: true + "@vitest/browser-preview": + optional: true + "@vitest/browser-webdriverio": + optional: true + "@vitest/coverage-istanbul": + optional: true + "@vitest/coverage-v8": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vite: + optional: false + bin: + vitest: ./vitest.mjs + checksum: 10c0/e86919375db85ddecc6308076341f66a9d51c3b28aa7966ea6bcb0f45234b5e2883602c17e509abfa6d729aaf8113b3adf7b59a8316079c2c9a48dbb1b248897 + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -3137,6 +3876,26 @@ __metadata: languageName: node linkType: hard +"which@npm:^7.0.0": + version: 7.0.0 + resolution: "which@npm:7.0.0" + dependencies: + isexe: "npm:^4.0.0" + bin: + node-which: bin/which.js + checksum: 10c0/ca0b54f198f78bbc4b7c02e34bda8d335cb352e0adb4cbca1c37b1a957af3a879a82c4c27ca6525bc942f548d8b64f816ef6528360af9f3de55ffb9b979b620d + languageName: node + linkType: hard + +"why-is-node-running@npm:^3.2.1": + version: 3.2.2 + resolution: "why-is-node-running@npm:3.2.2" + bin: + why-is-node-running: cli.js + checksum: 10c0/47307bfc2f48dd5228a92103dc43a7cadafbc6b6791c114fd27e03ac271a5082849a54f7e5f5cb261ea68f0d4ad40d9cb503b55812a6b62e67de0c57039fb95b + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -3144,6 +3903,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0"