@sha3/code-standards 0.1.1 → 0.1.3

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 (36) hide show
  1. package/README.md +50 -9
  2. package/bin/code-standards.mjs +32 -37
  3. package/package.json +1 -1
  4. package/resources/ai/templates/examples/demo/src/billing/billing-service.ts +102 -0
  5. package/resources/ai/templates/examples/demo/src/invoices/invoice-errors.ts +89 -0
  6. package/resources/ai/templates/examples/demo/src/invoices/invoice-service.ts +123 -0
  7. package/resources/ai/templates/examples/demo/src/invoices/invoice-types.ts +20 -0
  8. package/resources/ai/templates/examples/rules/async-bad.ts +94 -0
  9. package/resources/ai/templates/examples/rules/async-good.ts +94 -0
  10. package/resources/ai/templates/examples/rules/class-first-bad.ts +90 -0
  11. package/resources/ai/templates/examples/rules/class-first-good.ts +99 -0
  12. package/resources/ai/templates/examples/rules/constructor-bad.ts +98 -0
  13. package/resources/ai/templates/examples/rules/constructor-good.ts +97 -0
  14. package/resources/ai/templates/examples/rules/control-flow-bad.ts +85 -0
  15. package/resources/ai/templates/examples/rules/control-flow-good.ts +92 -0
  16. package/resources/ai/templates/examples/rules/errors-bad.ts +86 -0
  17. package/resources/ai/templates/examples/rules/errors-good.ts +89 -0
  18. package/resources/ai/templates/examples/rules/functions-bad.ts +106 -0
  19. package/resources/ai/templates/examples/rules/functions-good.ts +102 -0
  20. package/resources/ai/templates/examples/rules/returns-bad.ts +92 -0
  21. package/resources/ai/templates/examples/rules/returns-good.ts +94 -0
  22. package/resources/ai/templates/examples/rules/testing-bad.ts +88 -0
  23. package/resources/ai/templates/examples/rules/testing-good.ts +92 -0
  24. package/resources/ai/templates/rules/architecture.md +5 -15
  25. package/resources/ai/templates/rules/async.md +2 -12
  26. package/resources/ai/templates/rules/class-first.md +23 -82
  27. package/resources/ai/templates/rules/control-flow.md +2 -8
  28. package/resources/ai/templates/rules/errors.md +2 -11
  29. package/resources/ai/templates/rules/functions.md +4 -15
  30. package/resources/ai/templates/rules/returns.md +2 -22
  31. package/resources/ai/templates/rules/testing.md +3 -14
  32. package/standards/architecture.md +1 -1
  33. package/standards/style.md +11 -1
  34. package/standards/testing.md +1 -1
  35. package/templates/node-lib/gitignore +5 -0
  36. package/templates/node-service/gitignore +5 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @section imports:externals
3
+ */
4
+
5
+ // empty
6
+
7
+ /**
8
+ * @section imports:internals
9
+ */
10
+
11
+ // empty
12
+
13
+ /**
14
+ * @section consts
15
+ */
16
+
17
+ // empty
18
+
19
+ /**
20
+ * @section types
21
+ */
22
+
23
+ type Invoice = { issuedAt: Date };
24
+
25
+ export class InvoiceEscalationPolicy {
26
+ /**
27
+ * @section private:attributes
28
+ */
29
+
30
+ // empty
31
+
32
+ /**
33
+ * @section private:properties
34
+ */
35
+
36
+ // empty
37
+
38
+ /**
39
+ * @section public:properties
40
+ */
41
+
42
+ // empty
43
+
44
+ /**
45
+ * @section constructor
46
+ */
47
+
48
+ // empty
49
+
50
+ /**
51
+ * @section static:properties
52
+ */
53
+
54
+ // empty
55
+
56
+ /**
57
+ * @section factory
58
+ */
59
+
60
+ public static create(): InvoiceEscalationPolicy {
61
+ const policy = new InvoiceEscalationPolicy();
62
+ return policy;
63
+ }
64
+
65
+ /**
66
+ * @section private:methods
67
+ */
68
+
69
+ // empty
70
+
71
+ /**
72
+ * @section public:methods
73
+ */
74
+
75
+ public evaluateEscalation(invoice: Invoice, now: Date): Promise<string> {
76
+ return Promise.resolve(invoice).then((current: Invoice) => {
77
+ const hasAge = now.getTime() - current.issuedAt.getTime() > 0;
78
+ const decision = hasAge ? "x" : "y";
79
+ return decision;
80
+ });
81
+ }
82
+
83
+ /**
84
+ * @section static:methods
85
+ */
86
+
87
+ // empty
88
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @section imports:externals
3
+ */
4
+
5
+ // empty
6
+
7
+ /**
8
+ * @section imports:internals
9
+ */
10
+
11
+ // empty
12
+
13
+ /**
14
+ * @section consts
15
+ */
16
+
17
+ const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
18
+
19
+ /**
20
+ * @section types
21
+ */
22
+
23
+ type Invoice = { issuedAt: Date };
24
+ type EscalationDecision = "manual-review" | "no-escalation";
25
+
26
+ export class InvoiceEscalationPolicy {
27
+ /**
28
+ * @section private:attributes
29
+ */
30
+
31
+ // empty
32
+
33
+ /**
34
+ * @section private:properties
35
+ */
36
+
37
+ // empty
38
+
39
+ /**
40
+ * @section public:properties
41
+ */
42
+
43
+ // empty
44
+
45
+ /**
46
+ * @section constructor
47
+ */
48
+
49
+ // empty
50
+
51
+ /**
52
+ * @section static:properties
53
+ */
54
+
55
+ // empty
56
+
57
+ /**
58
+ * @section factory
59
+ */
60
+
61
+ public static create(): InvoiceEscalationPolicy {
62
+ const policy = new InvoiceEscalationPolicy();
63
+ return policy;
64
+ }
65
+
66
+ /**
67
+ * @section private:methods
68
+ */
69
+
70
+ private daysBetween(from: Date, to: Date): number {
71
+ const diffInMilliseconds = to.getTime() - from.getTime();
72
+ const dayCount = Math.floor(diffInMilliseconds / MILLISECONDS_PER_DAY);
73
+ return dayCount;
74
+ }
75
+
76
+ /**
77
+ * @section public:methods
78
+ */
79
+
80
+ // Business rule: invoices older than 30 days are escalated for manual review.
81
+ public evaluateEscalation(invoice: Invoice, now: Date): EscalationDecision {
82
+ const ageInDays: number = this.daysBetween(invoice.issuedAt, now);
83
+ const decision: EscalationDecision = ageInDays > 30 ? "manual-review" : "no-escalation";
84
+ return decision;
85
+ }
86
+
87
+ /**
88
+ * @section static:methods
89
+ */
90
+
91
+ // empty
92
+ }
@@ -6,21 +6,11 @@
6
6
 
7
7
  Good example:
8
8
 
9
- ```text
10
- src/
11
- invoices/
12
- invoice-service.ts
13
- invoice-repository.ts
14
- invoice-types.ts
15
- billing/
16
- billing-service.ts
17
- ```
9
+ - `ai/examples/demo/src/invoices/invoice-service.ts`
10
+ - `ai/examples/demo/src/invoices/invoice-errors.ts`
11
+ - `ai/examples/demo/src/invoices/invoice-types.ts`
12
+ - `ai/examples/demo/src/billing/billing-service.ts`
18
13
 
19
14
  Bad example:
20
15
 
21
- ```text
22
- src/
23
- services/
24
- repositories/
25
- models/
26
- ```
16
+ - `ai/examples/rules/class-first-bad.ts` (mixes concerns and does not keep feature boundaries)
@@ -6,18 +6,8 @@
6
6
 
7
7
  Good example:
8
8
 
9
- ```ts
10
- public async execute(command: SyncInvoicesCommand): Promise<SyncResult> {
11
- const invoices: Invoice[] = await this.source.fetch(command.accountId);
12
- const result: SyncResult = await this.writer.persist(invoices);
13
- return result;
14
- }
15
- ```
9
+ - `ai/examples/rules/async-good.ts`
16
10
 
17
11
  Bad example:
18
12
 
19
- ```ts
20
- public execute(command: SyncInvoicesCommand): Promise<SyncResult> {
21
- return this.source.fetch(command.accountId).then((invoices) => this.writer.persist(invoices));
22
- }
23
- ```
13
+ - `ai/examples/rules/async-bad.ts`
@@ -4,93 +4,34 @@
4
4
  - Each class MUST use constructor injection for dependencies.
5
5
  - A source file MUST expose one public class.
6
6
  - Mutable shared state MUST be avoided; prefer `readonly` fields and deterministic methods.
7
- - Class-oriented files MUST always include all section comment blocks using this exact format:
8
- - `/** @section imports:externals */`
9
- - `/** @section imports:internals */`
10
- - `/** @section consts */`
11
- - `/** @section types */`
12
- - `/** @section private:attributes */`
13
- - `/** @section private:properties */`
14
- - `/** @section public:properties */`
15
- - `/** @section constructor */`
16
- - `/** @section static:properties */`
17
- - `/** @section factory */`
18
- - `/** @section private:methods */`
19
- - `/** @section public:methods */`
20
- - `/** @section static:methods */`
7
+ - Class-oriented files MUST always include all section comment blocks using this exact 3-line format:
8
+ - `/**`
9
+ - ` * @section <block-name>`
10
+ - ` */`
11
+ - Required section block names (in order):
12
+ - `imports:externals`
13
+ - `imports:internals`
14
+ - `consts`
15
+ - `types`
16
+ - `private:attributes`
17
+ - `private:properties`
18
+ - `public:properties`
19
+ - `constructor`
20
+ - `static:properties`
21
+ - `factory`
22
+ - `private:methods`
23
+ - `public:methods`
24
+ - `static:methods`
21
25
  - All section blocks MUST exist even when empty, using `// empty` after the section marker.
22
26
  - `factory` MUST only contain methods that create and return instances of the same class.
23
27
 
24
28
  Good example:
25
29
 
26
- ```ts
27
- /** @section imports:externals */
28
- import { randomUUID } from "node:crypto";
29
-
30
- /** @section imports:internals */
31
- import type { InvoiceRepository } from "./invoice-repository.js";
32
- import type { CreateInvoiceCommand, Invoice } from "./invoice-types.js";
33
-
34
- /** @section consts */
35
- const SERVICE_NAME = "invoice-service";
36
-
37
- /** @section types */
38
- type InvoiceDraft = { customerId: string; amount: number };
39
-
40
- export class InvoiceService {
41
- /** @section private:attributes */
42
- private readonly requestId: string;
43
-
44
- /** @section private:properties */
45
- private readonly repository: InvoiceRepository;
46
-
47
- /** @section public:properties */
48
- public readonly serviceName: string;
49
-
50
- /** @section constructor */
51
- public constructor(repository: InvoiceRepository) {
52
- this.repository = repository;
53
- this.requestId = randomUUID();
54
- this.serviceName = SERVICE_NAME;
55
- }
56
-
57
- /** @section static:properties */
58
- // empty
59
-
60
- /** @section factory */
61
- public static create(repository: InvoiceRepository): InvoiceService {
62
- const service = new InvoiceService(repository);
63
- return service;
64
- }
65
-
66
- /** @section private:methods */
67
- private toInvoiceDraft(command: CreateInvoiceCommand): InvoiceDraft {
68
- const draft: InvoiceDraft = { customerId: command.customerId, amount: command.amount };
69
- return draft;
70
- }
71
-
72
- /** @section public:methods */
73
- public async create(command: CreateInvoiceCommand): Promise<Invoice> {
74
- const draft: InvoiceDraft = this.toInvoiceDraft(command);
75
- const invoice: Invoice = await this.repository.save(draft);
76
- return invoice;
77
- }
78
-
79
- /** @section static:methods */
80
- // empty
81
- }
82
- ```
30
+ - `ai/examples/rules/class-first-good.ts`
31
+ - `ai/examples/rules/constructor-good.ts`
32
+ - `ai/examples/demo/src/invoices/invoice-service.ts`
83
33
 
84
34
  Bad example:
85
35
 
86
- ```ts
87
- import { randomUUID } from "node:crypto";
88
-
89
- export class InvoiceService {
90
- public async create(command: CreateInvoiceCommand): Promise<Invoice> {
91
- const repository = new InvoiceRepository();
92
- if (!command.customerId) return Promise.reject(new Error("invalid"));
93
- return repository.save(command as any);
94
- }
95
- }
96
- ```
36
+ - `ai/examples/rules/class-first-bad.ts`
37
+ - `ai/examples/rules/constructor-bad.ts`
@@ -6,14 +6,8 @@
6
6
 
7
7
  Good example:
8
8
 
9
- ```ts
10
- if (isEnabled) {
11
- executeTask();
12
- }
13
- ```
9
+ - `ai/examples/rules/control-flow-good.ts`
14
10
 
15
11
  Bad example:
16
12
 
17
- ```ts
18
- if (isEnabled) executeTask();
19
- ```
13
+ - `ai/examples/rules/control-flow-bad.ts`
@@ -6,17 +6,8 @@
6
6
 
7
7
  Good example:
8
8
 
9
- ```ts
10
- export class InvoiceNotFoundError extends Error {
11
- public constructor(invoiceId: string) {
12
- super(`Invoice not found: ${invoiceId}`);
13
- this.name = "InvoiceNotFoundError";
14
- }
15
- }
16
- ```
9
+ - `ai/examples/rules/errors-good.ts`
17
10
 
18
11
  Bad example:
19
12
 
20
- ```ts
21
- throw new Error("Oops");
22
- ```
13
+ - `ai/examples/rules/errors-bad.ts`
@@ -4,24 +4,13 @@
4
4
  - Functions MUST implement one responsibility.
5
5
  - Long functions MUST be split into private helper methods.
6
6
  - Types MUST be preferred over interfaces for local modeling unless a public contract requires an interface.
7
+ - New implementation and test files MUST be `.ts`.
8
+ - JavaScript source files (`.js`, `.mjs`, `.cjs`) are not allowed in `src/` or `test/`.
7
9
 
8
10
  Good example:
9
11
 
10
- ```ts
11
- private normalize(input: PaymentInput): PaymentDraft {
12
- const amount: number = normalizeAmount(input.amount);
13
- const currency: CurrencyCode = normalizeCurrency(input.currency);
14
- const metadata: PaymentMetadata = sanitizeMetadata(input.metadata);
15
- return { amount, currency, metadata };
16
- }
17
- ```
12
+ - `ai/examples/rules/functions-good.ts`
18
13
 
19
14
  Bad example:
20
15
 
21
- ```ts
22
- private normalize(input: any): any {
23
- // huge branchy function with parsing, IO, validation and persistence mixed together
24
- // ... 80+ lines omitted
25
- return input;
26
- }
27
- ```
16
+ - `ai/examples/rules/functions-bad.ts`
@@ -6,28 +6,8 @@
6
6
 
7
7
  Good example:
8
8
 
9
- ```ts
10
- public toStatusLabel(status: InvoiceStatus): string {
11
- let label: string;
12
-
13
- if (status === "paid") {
14
- label = "Paid";
15
- } else if (status === "void") {
16
- label = "Void";
17
- } else {
18
- label = "Pending";
19
- }
20
-
21
- return label;
22
- }
23
- ```
9
+ - `ai/examples/rules/returns-good.ts`
24
10
 
25
11
  Bad example:
26
12
 
27
- ```ts
28
- public toStatusLabel(status: InvoiceStatus): string {
29
- if (status === "paid") return "Paid";
30
- if (status === "void") return "Void";
31
- return "Pending";
32
- }
33
- ```
13
+ - `ai/examples/rules/returns-bad.ts`
@@ -2,25 +2,14 @@
2
2
 
3
3
  - Any behavior change MUST include or update tests.
4
4
  - Tests MUST validate behavior, not implementation details.
5
+ - Test files MUST be TypeScript (`*.test.ts`).
5
6
  - Comments MUST be explicit and extensive when logic is non-trivial.
6
7
  - Async workflows MUST use `async/await` style only.
7
8
 
8
9
  Good example:
9
10
 
10
- ```ts
11
- // Business rule: invoices older than 30 days are escalated for manual review.
12
- public evaluateEscalation(invoice: Invoice, now: Date): EscalationDecision {
13
- const ageInDays: number = daysBetween(invoice.issuedAt, now);
14
- const decision: EscalationDecision =
15
- ageInDays > 30 ? "manual-review" : "no-escalation";
16
- return decision;
17
- }
18
- ```
11
+ - `ai/examples/rules/testing-good.ts`
19
12
 
20
13
  Bad example:
21
14
 
22
- ```ts
23
- public evaluateEscalation(invoice: any, now: Date): any {
24
- return Promise.resolve(invoice).then((it) => (Date.now() - it.issuedAt > 0 ? "x" : "y"));
25
- }
26
- ```
15
+ - `ai/examples/rules/testing-bad.ts`
@@ -15,7 +15,7 @@ Both templates SHOULD keep this baseline structure:
15
15
 
16
16
  - `src/` for implementation.
17
17
  - `test/` for automated tests.
18
- - `eslint.config.mjs`, `prettier.config.cjs`, and `tsconfig.json` at root.
18
+ - Root tooling config files (`eslint`, `prettier`, `tsconfig`) at project root.
19
19
 
20
20
  ## Boundary Rules
21
21
 
@@ -12,6 +12,8 @@ All code MUST follow the canonical rules in `standards/manifest.json`.
12
12
  ## TypeScript
13
13
 
14
14
  - Use strict TypeScript mode.
15
+ - Project implementation and tests MUST be TypeScript-only (`.ts`).
16
+ - JavaScript source files (`.js`, `.mjs`, `.cjs`) are not allowed in `src/` or `test/`.
15
17
  - Avoid `any` unless there is no viable alternative.
16
18
  - Prefer explicit return types for exported functions.
17
19
  - Use type-only imports when possible.
@@ -25,7 +27,15 @@ All code MUST follow the canonical rules in `standards/manifest.json`.
25
27
 
26
28
  ## Class File Comment Blocks
27
29
 
28
- Class-oriented files MUST use `/** @section ... */` markers in this exact order:
30
+ Class-oriented files MUST use 3-line JSDoc section markers in this exact order:
31
+
32
+ ```ts
33
+ /**
34
+ * @section <block-name>
35
+ */
36
+ ```
37
+
38
+ Required block names:
29
39
 
30
40
  1. `imports:externals`
31
41
  2. `imports:internals`
@@ -5,7 +5,7 @@ Projects MUST use the Node test runner.
5
5
  ## Location
6
6
 
7
7
  - Store tests under `test/`.
8
- - Use `*.test.ts` or `*.test.js` naming.
8
+ - Use `*.test.ts` naming only.
9
9
 
10
10
  ## Commands
11
11
 
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+ *.tsbuildinfo
5
+ .DS_Store
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+ *.tsbuildinfo
5
+ .DS_Store