@critical-path/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/engine/index.d.ts +19 -1
  3. package/dist/engine/index.d.ts.map +1 -1
  4. package/dist/engine/index.js +129 -6
  5. package/dist/engine/index.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.test.js +96 -1
  11. package/dist/index.test.js.map +1 -1
  12. package/dist/store/firebase.d.ts +19 -7
  13. package/dist/store/firebase.d.ts.map +1 -1
  14. package/dist/store/firebase.js +98 -14
  15. package/dist/store/firebase.js.map +1 -1
  16. package/dist/store/firebase.test.js +5 -2
  17. package/dist/store/firebase.test.js.map +1 -1
  18. package/dist/store/index.d.ts +34 -8
  19. package/dist/store/index.d.ts.map +1 -1
  20. package/dist/store/index.js +79 -12
  21. package/dist/store/index.js.map +1 -1
  22. package/dist/store/sqlite.d.ts +17 -4
  23. package/dist/store/sqlite.d.ts.map +1 -1
  24. package/dist/store/sqlite.js +179 -39
  25. package/dist/store/sqlite.js.map +1 -1
  26. package/dist/types/index.d.ts +70 -9
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/utils/index.d.ts +3 -0
  29. package/dist/utils/index.d.ts.map +1 -0
  30. package/dist/utils/index.js +3 -0
  31. package/dist/utils/index.js.map +1 -0
  32. package/dist/utils/key.d.ts +14 -0
  33. package/dist/utils/key.d.ts.map +1 -0
  34. package/dist/utils/key.js +49 -0
  35. package/dist/utils/key.js.map +1 -0
  36. package/dist/utils/key.test.d.ts +2 -0
  37. package/dist/utils/key.test.d.ts.map +1 -0
  38. package/dist/utils/key.test.js +48 -0
  39. package/dist/utils/key.test.js.map +1 -0
  40. package/dist/utils/status.d.ts +14 -0
  41. package/dist/utils/status.d.ts.map +1 -0
  42. package/dist/utils/status.js +58 -0
  43. package/dist/utils/status.js.map +1 -0
  44. package/package.json +5 -1
  45. package/src/engine/index.ts +161 -8
  46. package/src/index.test.ts +113 -1
  47. package/src/index.ts +2 -0
  48. package/src/store/firebase.test.ts +8 -2
  49. package/src/store/firebase.ts +112 -18
  50. package/src/store/index.ts +113 -18
  51. package/src/store/sqlite.ts +277 -47
  52. package/src/types/index.ts +76 -10
  53. package/src/utils/index.ts +2 -0
  54. package/src/utils/key.test.ts +55 -0
  55. package/src/utils/key.ts +51 -0
  56. package/src/utils/status.ts +85 -0
  57. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateProjectKey, validateProjectKey, formatTaskKey } from './key.js';
3
+
4
+ describe('Project Key Utilities', () => {
5
+ describe('generateProjectKey', () => {
6
+ it('generates a key for a single word name', () => {
7
+ expect(generateProjectKey('Operative')).toBe('OPE');
8
+ expect(generateProjectKey('App')).toBe('APP');
9
+ expect(generateProjectKey('Go')).toBe('GO');
10
+ });
11
+
12
+ it('generates a key for multi-word names', () => {
13
+ expect(generateProjectKey('Mobile App')).toBe('MA');
14
+ expect(generateProjectKey('Frontend Core Platform')).toBe('FCP');
15
+ expect(generateProjectKey('Very Long Project Name Here')).toBe('VLPN');
16
+ });
17
+
18
+ it('handles special characters and whitespace', () => {
19
+ expect(generateProjectKey(' v2.0 ')).toBe('V20');
20
+ expect(generateProjectKey('Project #1')).toBe('P1');
21
+ });
22
+
23
+ it('returns default PRJ fallback for empty input', () => {
24
+ expect(generateProjectKey('')).toBe('PRJ');
25
+ expect(generateProjectKey(' ')).toBe('PRJ');
26
+ });
27
+ });
28
+
29
+ describe('validateProjectKey', () => {
30
+ it('returns true for valid keys', () => {
31
+ expect(validateProjectKey('CP')).toBe(true);
32
+ expect(validateProjectKey('PROJ')).toBe(true);
33
+ expect(validateProjectKey('APP123')).toBe(true);
34
+ });
35
+
36
+ it('returns false for invalid keys', () => {
37
+ expect(validateProjectKey('A')).toBe(false); // too short
38
+ expect(validateProjectKey('TOOLONGKEY')).toBe(false); // too long
39
+ expect(validateProjectKey('proj')).toBe(false); // lowercase
40
+ expect(validateProjectKey('P-1')).toBe(false); // special char
41
+ expect(validateProjectKey('')).toBe(false);
42
+ });
43
+ });
44
+
45
+ describe('formatTaskKey', () => {
46
+ it('formats project key and task number', () => {
47
+ expect(formatTaskKey('MOB', 42)).toBe('MOB-42');
48
+ expect(formatTaskKey('op', 1)).toBe('OP-1');
49
+ });
50
+
51
+ it('uses fallback for missing project key', () => {
52
+ expect(formatTaskKey('', 10)).toBe('TASK-10');
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Generates a 2-6 character uppercase project short code/key from a project name.
3
+ * e.g., "Mobile App" -> "MA", "Frontend Core" -> "FC", "Operative" -> "OPE".
4
+ */
5
+ export function generateProjectKey(name: string): string {
6
+ if (!name || !name.trim()) {
7
+ return 'PRJ';
8
+ }
9
+
10
+ const words = name.trim().split(/\s+/).filter(Boolean);
11
+ let rawKey = '';
12
+
13
+ if (words.length === 1) {
14
+ const word = words[0].replace(/[^a-zA-Z0-9]/g, '');
15
+ if (word.length <= 3) {
16
+ rawKey = word.toUpperCase();
17
+ } else {
18
+ rawKey = word.substring(0, 3).toUpperCase();
19
+ }
20
+ } else {
21
+ rawKey = words
22
+ .map((w) => w.replace(/[^a-zA-Z0-9]/g, '')[0] || '')
23
+ .join('')
24
+ .substring(0, 4)
25
+ .toUpperCase();
26
+ }
27
+
28
+ // Ensure key meets basic 2-6 char alphanumeric requirement
29
+ const cleanKey = rawKey.replace(/[^A-Z0-9]/g, '');
30
+ if (cleanKey.length >= 2 && cleanKey.length <= 6) {
31
+ return cleanKey;
32
+ }
33
+
34
+ return 'PRJ';
35
+ }
36
+
37
+ /**
38
+ * Validates whether a given key meets project key format rules (2-6 uppercase alphanumeric characters).
39
+ */
40
+ export function validateProjectKey(key: string): boolean {
41
+ if (!key) return false;
42
+ return /^[A-Z0-9]{2,6}$/.test(key);
43
+ }
44
+
45
+ /**
46
+ * Formats a task key using a project key and task index (e.g. "MOB-12").
47
+ */
48
+ export function formatTaskKey(projectKey: string, taskNumber: number): string {
49
+ const prefix = projectKey ? projectKey.toUpperCase() : 'TASK';
50
+ return `${prefix}-${taskNumber}`;
51
+ }
@@ -0,0 +1,85 @@
1
+ import type {
2
+ Task,
3
+ StatusDefinition,
4
+ CompletionState,
5
+ ExecutionState
6
+ } from '../types/index.js';
7
+
8
+ export const DEFAULT_STATUS_DEFINITIONS: Record<string, StatusDefinition> = {
9
+ backlog: { key: 'backlog', label: 'Backlog', completionState: 'not_done', executionState: 'inactive' },
10
+ todo: { key: 'todo', label: 'To Do', completionState: 'not_done', executionState: 'inactive' },
11
+ in_progress: { key: 'in_progress', label: 'In Progress', completionState: 'not_done', executionState: 'active' },
12
+ in_review: { key: 'in_review', label: 'In Review', completionState: 'not_done', executionState: 'active' },
13
+ done: { key: 'done', label: 'Done', completionState: 'done', executionState: 'inactive' },
14
+ canceled: { key: 'canceled', label: 'Canceled', completionState: 'done', executionState: 'inactive', isCancelled: true }
15
+ };
16
+
17
+ export interface TaskLifecycleState {
18
+ completionState: CompletionState;
19
+ executionState: ExecutionState;
20
+ isDone: boolean;
21
+ isActive: boolean;
22
+ isCancelled: boolean;
23
+ isOverdue: boolean;
24
+ isUpcoming: boolean;
25
+ }
26
+
27
+ export function resolveStatusDefinition(
28
+ statusKey: string,
29
+ customDefinitions?: StatusDefinition[]
30
+ ): StatusDefinition {
31
+ if (customDefinitions) {
32
+ const found = customDefinitions.find((def) => def.key === statusKey);
33
+ if (found) return found;
34
+ }
35
+ if (DEFAULT_STATUS_DEFINITIONS[statusKey]) {
36
+ return DEFAULT_STATUS_DEFINITIONS[statusKey];
37
+ }
38
+ // Fallback heuristic for unknown custom statuses:
39
+ const isDoneKey = ['done', 'completed', 'finished', 'closed', 'canceled', 'cancelled'].includes(statusKey.toLowerCase());
40
+ const isActiveKey = ['in_progress', 'active', 'working', 'in_review', 'review'].includes(statusKey.toLowerCase());
41
+ return {
42
+ key: statusKey,
43
+ label: statusKey,
44
+ completionState: isDoneKey ? 'done' : 'not_done',
45
+ executionState: isActiveKey ? 'active' : 'inactive',
46
+ isCancelled: statusKey.toLowerCase().includes('cancel')
47
+ };
48
+ }
49
+
50
+ export function deriveTaskLifecycleState(
51
+ task: Task,
52
+ customDefinitions?: StatusDefinition[],
53
+ referenceDate: Date = new Date()
54
+ ): TaskLifecycleState {
55
+ const def = resolveStatusDefinition(task.status, customDefinitions);
56
+ const isDone = def.completionState === 'done';
57
+ const isActive = def.executionState === 'active';
58
+ const isCancelled = Boolean(def.isCancelled);
59
+
60
+ let isOverdue = false;
61
+ if (!isDone && task.dueDate) {
62
+ const due = new Date(task.dueDate);
63
+ if (!isNaN(due.getTime()) && due < referenceDate) {
64
+ isOverdue = true;
65
+ }
66
+ }
67
+
68
+ let isUpcoming = false;
69
+ if (!isDone && !isActive && task.plannedStartDate) {
70
+ const plannedStart = new Date(task.plannedStartDate);
71
+ if (!isNaN(plannedStart.getTime()) && plannedStart > referenceDate) {
72
+ isUpcoming = true;
73
+ }
74
+ }
75
+
76
+ return {
77
+ completionState: def.completionState,
78
+ executionState: def.executionState,
79
+ isDone,
80
+ isActive,
81
+ isCancelled,
82
+ isOverdue,
83
+ isUpcoming
84
+ };
85
+ }
@@ -1 +1 @@
1
- {"root":["./src/index.test.ts","./src/index.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts"],"version":"5.9.3"}
1
+ {"root":["./src/index.test.ts","./src/index.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/index.ts","./src/utils/key.test.ts","./src/utils/key.ts","./src/utils/status.ts"],"version":"5.9.3"}