speckeeper 0.1.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.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Term Model Definition
3
+ */
4
+ import { z } from 'zod';
5
+ import { Model, RelationSchema } from 'speckeeper';
6
+ import type { LintRule, Exporter, ModelLevel } from 'speckeeper';
7
+
8
+ // =============================================================================
9
+ // Schema Definition
10
+ // =============================================================================
11
+
12
+ export const TermSchema = z.object({
13
+ id: z.string(),
14
+ term: z.string(),
15
+ definition: z.string(),
16
+ category: z.enum(['business', 'technical', 'acronym', 'process', 'role']),
17
+ abbreviation: z.string().optional(),
18
+ expandedForm: z.string().optional(),
19
+ relations: z.array(RelationSchema).optional(),
20
+ });
21
+
22
+ // =============================================================================
23
+ // Type Export
24
+ // =============================================================================
25
+
26
+ export type Term = z.input<typeof TermSchema>;
27
+
28
+ // =============================================================================
29
+ // Model Class
30
+ // =============================================================================
31
+
32
+ class TermModel extends Model<typeof TermSchema> {
33
+ readonly id = 'term';
34
+ readonly name = 'Term';
35
+ readonly idPrefix = 'TERM';
36
+ readonly schema = TermSchema;
37
+ readonly description = 'Defines terms (glossary)';
38
+ protected modelLevel: ModelLevel = 'L0';
39
+
40
+ protected lintRules: LintRule<Term>[] = [
41
+ {
42
+ id: 'term-has-definition',
43
+ severity: 'error',
44
+ message: 'Term must have a definition',
45
+ check: (spec) => !spec.definition || spec.definition.trim() === '',
46
+ },
47
+ {
48
+ id: 'term-acronym-has-expanded-form',
49
+ severity: 'warning',
50
+ message: 'Acronym terms should have an expanded form',
51
+ check: (spec) => spec.category === 'acronym' && !spec.expandedForm,
52
+ },
53
+ ];
54
+
55
+ protected exporters: Exporter<Term>[] = [];
56
+ }
57
+
58
+ export { TermModel };
@@ -0,0 +1,99 @@
1
+ /**
2
+ * UseCase Model Definition
3
+ */
4
+ import { z } from 'zod';
5
+ import { Model, RelationSchema } from 'speckeeper';
6
+ import type { LintRule, Exporter, ModelLevel } from 'speckeeper';
7
+
8
+ // =============================================================================
9
+ // Schema Definition
10
+ // =============================================================================
11
+
12
+ export const ActorSchema = z.object({
13
+ id: z.string(),
14
+ name: z.string(),
15
+ description: z.string().optional(),
16
+ type: z.enum(['human', 'system', 'external']),
17
+ relations: z.array(RelationSchema).optional(),
18
+ });
19
+
20
+ export const UseCaseStepSchema = z.object({
21
+ stepNumber: z.number(),
22
+ type: z.enum(['user_action', 'system_response', 'alternative']),
23
+ description: z.string(),
24
+ });
25
+
26
+ export const UseCaseSchema = z.object({
27
+ id: z.string(),
28
+ name: z.string(),
29
+ description: z.string(),
30
+ actor: z.string(),
31
+ preconditions: z.array(z.string()).optional().default([]),
32
+ postconditions: z.array(z.string()).optional().default([]),
33
+ mainFlow: z.array(UseCaseStepSchema),
34
+ relations: z.array(RelationSchema).optional(),
35
+ });
36
+
37
+ // =============================================================================
38
+ // Type Export
39
+ // =============================================================================
40
+
41
+ export type Actor = z.input<typeof ActorSchema>;
42
+ export type UseCaseStep = z.infer<typeof UseCaseStepSchema>;
43
+ export type UseCase = z.input<typeof UseCaseSchema>;
44
+
45
+ // =============================================================================
46
+ // Actor Model Class
47
+ // =============================================================================
48
+
49
+ class ActorModel extends Model<typeof ActorSchema> {
50
+ readonly id = 'actor';
51
+ readonly name = 'Actor';
52
+ readonly idPrefix = 'ACT';
53
+ readonly schema = ActorSchema;
54
+ readonly description = 'Defines actors';
55
+ protected modelLevel: ModelLevel = 'L0';
56
+
57
+ protected lintRules: LintRule<Actor>[] = [
58
+ {
59
+ id: 'actor-has-description',
60
+ severity: 'warning',
61
+ message: 'Actor should have a description',
62
+ check: (spec) => !spec.description || spec.description.trim() === '',
63
+ },
64
+ ];
65
+
66
+ protected exporters: Exporter<Actor>[] = [];
67
+ }
68
+
69
+ // =============================================================================
70
+ // UseCase Model Class
71
+ // =============================================================================
72
+
73
+ class UseCaseModel extends Model<typeof UseCaseSchema> {
74
+ readonly id = 'usecase';
75
+ readonly name = 'UseCase';
76
+ readonly idPrefix = 'UC';
77
+ readonly schema = UseCaseSchema;
78
+ readonly description = 'Defines use cases (business flows)';
79
+ protected modelLevel: ModelLevel = 'L0';
80
+
81
+ protected lintRules: LintRule<UseCase>[] = [
82
+ {
83
+ id: 'usecase-has-main-flow',
84
+ severity: 'error',
85
+ message: 'UseCase must have a main flow',
86
+ check: (spec) => !spec.mainFlow || spec.mainFlow.length === 0,
87
+ },
88
+ {
89
+ id: 'usecase-has-actor',
90
+ severity: 'error',
91
+ message: 'UseCase must have an actor',
92
+ check: (spec) => !spec.actor || spec.actor.trim() === '',
93
+ },
94
+ ];
95
+
96
+ protected exporters: Exporter<UseCase>[] = [];
97
+ }
98
+
99
+ export { ActorModel, UseCaseModel };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Design specifications index
3
+ */
4
+
5
+ // Requirements
6
+ export { requirements } from './requirements.ts';
7
+
8
+ console.log('Design specifications loaded!');
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Requirements
3
+ */
4
+ import type { Requirement } from './_models/requirement.ts';
5
+
6
+ export const requirements: Requirement[] = [
7
+ {
8
+ id: 'FR-001',
9
+ name: 'User Authentication',
10
+ type: 'functional',
11
+ priority: 'must',
12
+ description: 'Users can authenticate using email and password',
13
+ acceptanceCriteria: [
14
+ { id: 'FR-001-01', description: 'Valid credentials grant access', verificationMethod: 'test' },
15
+ { id: 'FR-001-02', description: 'Invalid credentials show error message', verificationMethod: 'test' },
16
+ ],
17
+ },
18
+ ];
19
+
20
+ console.log(`Requirements loaded: ${requirements.length} items`);
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "typecheck": "tsc --noEmit",
7
+ "lint": "speckeeper lint",
8
+ "check": "speckeeper check"
9
+ },
10
+ "dependencies": {
11
+ "speckeeper": "^0.1.0",
12
+ "zod": "^3.22.4"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.3.0"
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * speckeeper configuration file
3
+ */
4
+ import { defineConfig } from 'speckeeper';
5
+ import { allModels } from './design/_models/index';
6
+
7
+ export default defineConfig({
8
+ projectName: 'my-project',
9
+ version: '1.0.0',
10
+ models: allModels,
11
+ });
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowImportingTsExtensions": true,
7
+ "noEmit": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true
12
+ },
13
+ "include": ["design/**/*", "speckeeper.config.ts"]
14
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "speckeeper",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript-first specification validation framework with external SSOT integration",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./dsl": {
15
+ "import": "./dist/dsl/index.js",
16
+ "types": "./dist/dsl/index.d.ts"
17
+ }
18
+ },
19
+ "bin": {
20
+ "speckeeper": "./bin/speckeeper.js"
21
+ },
22
+ "engines": {
23
+ "node": ">=20.0.0"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "bin"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "build:docs": "npm run build && embedoc build",
32
+ "dev": "tsup --watch",
33
+ "lint": "eslint",
34
+ "lint:design": "eslint design/",
35
+ "test": "vitest",
36
+ "test:run": "vitest run",
37
+ "typecheck": "tsc --noEmit",
38
+ "prepublishOnly": "npm run build",
39
+ "docs": "embedoc build",
40
+ "docs:watch": "embedoc watch",
41
+ "ci": "npm run ci:validate && npm run ci:generate && npm run ci:verify",
42
+ "ci:validate": "npm run typecheck && npm run lint && npm run lint:design && npm run build && npx speckeeper lint && npm run test:run",
43
+ "ci:generate": "embedoc build",
44
+ "ci:verify": "npx speckeeper check external-ssot && npx speckeeper check test && npx speckeeper check test --coverage"
45
+ },
46
+ "keywords": [
47
+ "requirements",
48
+ "design",
49
+ "documentation",
50
+ "markdown",
51
+ "mermaid",
52
+ "typescript",
53
+ "dsl",
54
+ "architecture",
55
+ "c4-model"
56
+ ],
57
+ "author": "",
58
+ "license": "MIT",
59
+ "dependencies": {
60
+ "chalk": "^5.3.0",
61
+ "commander": "^12.1.0",
62
+ "embedoc": "^0.10.1",
63
+ "glob": "^10.3.10",
64
+ "tsx": "^4.21.0",
65
+ "yaml": "^2.3.4",
66
+ "zod": "^3.22.4"
67
+ },
68
+ "devDependencies": {
69
+ "@eslint/js": "^9.39.2",
70
+ "@types/node": "^20.11.0",
71
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
72
+ "@typescript-eslint/parser": "^8.54.0",
73
+ "@vitest/coverage-v8": "^1.6.1",
74
+ "eslint": "^9.39.2",
75
+ "tsup": "^8.0.1",
76
+ "typescript": "^5.3.3",
77
+ "typescript-eslint": "^8.54.0",
78
+ "vitest": "^1.2.0"
79
+ }
80
+ }