feat: add project context model
This commit is contained in:
parent
0e3815ac3c
commit
0b127b5404
4 changed files with 54 additions and 1 deletions
|
|
@ -9,7 +9,7 @@
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"test": "node --test tests/bootstrap.test.mjs && node --import tsx --test tests/lib/parser.test.ts && node --import tsx --test tests/lib/pathing.test.ts && node --import tsx --test tests/lib/kanban.test.ts && node --import tsx --test tests/lib/read-issues.test.ts && node --test tests/guards/no-direct-jsonl-write.test.mjs && node --test tests/guards/no-inline-style-in-kanban.test.mjs && node --test tests/guards/kanban-responsive-contract.test.mjs"
|
"test": "node --test tests/bootstrap.test.mjs && node --import tsx --test tests/lib/parser.test.ts && node --import tsx --test tests/lib/pathing.test.ts && node --import tsx --test tests/lib/project-context.test.ts && node --import tsx --test tests/lib/kanban.test.ts && node --import tsx --test tests/lib/read-issues.test.ts && node --test tests/guards/no-direct-jsonl-write.test.mjs && node --test tests/guards/no-inline-style-in-kanban.test.mjs && node --test tests/guards/kanban-responsive-contract.test.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"framer-motion": "^11.18.2",
|
"framer-motion": "^11.18.2",
|
||||||
|
|
|
||||||
25
src/lib/project-context.ts
Normal file
25
src/lib/project-context.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
import { canonicalizeWindowsPath, toDisplayPath, windowsPathKey } from './pathing';
|
||||||
|
import type { ProjectContext, ProjectSource } from './types';
|
||||||
|
|
||||||
|
interface BuildProjectContextOptions {
|
||||||
|
source?: ProjectSource;
|
||||||
|
addedAt?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildProjectContext(root: string, options: BuildProjectContextOptions = {}): ProjectContext {
|
||||||
|
if (!root) {
|
||||||
|
throw new Error('Project root is required to build project context.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedRoot = canonicalizeWindowsPath(root);
|
||||||
|
return {
|
||||||
|
key: windowsPathKey(normalizedRoot),
|
||||||
|
root: normalizedRoot,
|
||||||
|
displayPath: toDisplayPath(normalizedRoot),
|
||||||
|
name: path.basename(normalizedRoot),
|
||||||
|
source: options.source ?? 'local',
|
||||||
|
addedAt: options.addedAt ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -59,3 +59,16 @@ export interface ParseableBeadIssue extends Partial<BeadIssue> {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProjectSource = 'local' | 'registry' | 'scanner';
|
||||||
|
|
||||||
|
export interface ProjectContext {
|
||||||
|
key: string;
|
||||||
|
root: string;
|
||||||
|
displayPath: string;
|
||||||
|
name: string;
|
||||||
|
source: ProjectSource;
|
||||||
|
addedAt: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BeadIssueWithProject = BeadIssue & { project: ProjectContext };
|
||||||
|
|
|
||||||
15
tests/lib/project-context.test.ts
Normal file
15
tests/lib/project-context.test.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
|
||||||
|
import { buildProjectContext } from '../../src/lib/project-context';
|
||||||
|
|
||||||
|
test('buildProjectContext derives normalized project identity', () => {
|
||||||
|
const project = buildProjectContext('C:/Repo/Project');
|
||||||
|
|
||||||
|
assert.equal(project.root, 'C:\\Repo\\Project');
|
||||||
|
assert.equal(project.key, 'c:\\repo\\project');
|
||||||
|
assert.equal(project.displayPath, 'C:/Repo/Project');
|
||||||
|
assert.equal(project.name, 'Project');
|
||||||
|
assert.equal(project.source, 'local');
|
||||||
|
assert.equal(project.addedAt, null);
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue