@sha3/code-standards 0.1.1 → 0.1.2

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 (34) hide show
  1. package/README.md +47 -9
  2. package/bin/code-standards.mjs +30 -36
  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 +2 -15
  30. package/resources/ai/templates/rules/returns.md +2 -22
  31. package/resources/ai/templates/rules/testing.md +2 -14
  32. package/standards/style.md +9 -1
  33. package/templates/node-lib/gitignore +5 -0
  34. 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`
@@ -7,21 +7,8 @@
7
7
 
8
8
  Good example:
9
9
 
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
- ```
10
+ - `ai/examples/rules/functions-good.ts`
18
11
 
19
12
  Bad example:
20
13
 
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
- ```
14
+ - `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`
@@ -7,20 +7,8 @@
7
7
 
8
8
  Good example:
9
9
 
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
- ```
10
+ - `ai/examples/rules/testing-good.ts`
19
11
 
20
12
  Bad example:
21
13
 
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
- ```
14
+ - `ai/examples/rules/testing-bad.ts`
@@ -25,7 +25,15 @@ All code MUST follow the canonical rules in `standards/manifest.json`.
25
25
 
26
26
  ## Class File Comment Blocks
27
27
 
28
- Class-oriented files MUST use `/** @section ... */` markers in this exact order:
28
+ Class-oriented files MUST use 3-line JSDoc section markers in this exact order:
29
+
30
+ ```ts
31
+ /**
32
+ * @section <block-name>
33
+ */
34
+ ```
35
+
36
+ Required block names:
29
37
 
30
38
  1. `imports:externals`
31
39
  2. `imports:internals`
@@ -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