@sha3/code-standards 0.1.0 → 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 +4 -2
  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,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
+ // empty
18
+
19
+ /**
20
+ * @section types
21
+ */
22
+
23
+ type FeatureFlagMap = Record<string, boolean>;
24
+
25
+ export class FeatureGate {
26
+ /**
27
+ * @section private:attributes
28
+ */
29
+
30
+ // empty
31
+
32
+ /**
33
+ * @section private:properties
34
+ */
35
+
36
+ private readonly flags: FeatureFlagMap;
37
+
38
+ /**
39
+ * @section public:properties
40
+ */
41
+
42
+ // empty
43
+
44
+ /**
45
+ * @section constructor
46
+ */
47
+
48
+ public constructor(flags: FeatureFlagMap) {
49
+ this.flags = flags;
50
+ }
51
+
52
+ /**
53
+ * @section static:properties
54
+ */
55
+
56
+ // empty
57
+
58
+ /**
59
+ * @section factory
60
+ */
61
+
62
+ public static from(flags: FeatureFlagMap): FeatureGate {
63
+ const gate = new FeatureGate(flags);
64
+ return gate;
65
+ }
66
+
67
+ /**
68
+ * @section private:methods
69
+ */
70
+
71
+ // empty
72
+
73
+ /**
74
+ * @section public:methods
75
+ */
76
+
77
+ public canRunTask(key: string): boolean {
78
+ let enabled = false;
79
+
80
+ if (this.flags[key] === true) {
81
+ enabled = true;
82
+ }
83
+
84
+ return enabled;
85
+ }
86
+
87
+ /**
88
+ * @section static:methods
89
+ */
90
+
91
+ // empty
92
+ }
@@ -0,0 +1,86 @@
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
+ // empty
24
+
25
+ export class InvoiceLookup {
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(): InvoiceLookup {
61
+ const lookup = new InvoiceLookup();
62
+ return lookup;
63
+ }
64
+
65
+ /**
66
+ * @section private:methods
67
+ */
68
+
69
+ // empty
70
+
71
+ /**
72
+ * @section public:methods
73
+ */
74
+
75
+ public ensureInvoiceExists(invoiceId: string, exists: boolean): void {
76
+ if (!exists) {
77
+ throw new Error(`Missing invoice ${invoiceId}`);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @section static:methods
83
+ */
84
+
85
+ // empty
86
+ }
@@ -0,0 +1,89 @@
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
+ // empty
24
+
25
+ export class InvoiceNotFoundError extends Error {
26
+ /**
27
+ * @section private:attributes
28
+ */
29
+
30
+ // empty
31
+
32
+ /**
33
+ * @section private:properties
34
+ */
35
+
36
+ private readonly invoiceId: string;
37
+
38
+ /**
39
+ * @section public:properties
40
+ */
41
+
42
+ // empty
43
+
44
+ /**
45
+ * @section constructor
46
+ */
47
+
48
+ public constructor(invoiceId: string) {
49
+ super(`Invoice not found: ${invoiceId}`);
50
+ this.name = "InvoiceNotFoundError";
51
+ this.invoiceId = invoiceId;
52
+ }
53
+
54
+ /**
55
+ * @section static:properties
56
+ */
57
+
58
+ // empty
59
+
60
+ /**
61
+ * @section factory
62
+ */
63
+
64
+ public static forId(invoiceId: string): InvoiceNotFoundError {
65
+ const error = new InvoiceNotFoundError(invoiceId);
66
+ return error;
67
+ }
68
+
69
+ /**
70
+ * @section private:methods
71
+ */
72
+
73
+ // empty
74
+
75
+ /**
76
+ * @section public:methods
77
+ */
78
+
79
+ public toLogContext(): string {
80
+ const context = `invoiceId=${this.invoiceId}`;
81
+ return context;
82
+ }
83
+
84
+ /**
85
+ * @section static:methods
86
+ */
87
+
88
+ // empty
89
+ }
@@ -0,0 +1,106 @@
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 PaymentInput = { amount?: number; currency?: string; metadata?: Record<string, string> };
24
+ type PersistedPaymentInput = PaymentInput & { normalizedAt: number; saved: boolean };
25
+
26
+ export class PaymentNormalizer {
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(): PaymentNormalizer {
62
+ const normalizer = new PaymentNormalizer();
63
+ return normalizer;
64
+ }
65
+
66
+ /**
67
+ * @section private:methods
68
+ */
69
+
70
+ // empty
71
+
72
+ /**
73
+ * @section public:methods
74
+ */
75
+
76
+ public normalize(input: PaymentInput): PersistedPaymentInput {
77
+ // Bad: too many responsibilities in one method.
78
+ const clone = { ...input };
79
+
80
+ if (!clone.currency) {
81
+ clone.currency = "usd";
82
+ }
83
+
84
+ if (typeof clone.currency === "string") {
85
+ clone.currency = clone.currency.toUpperCase();
86
+ }
87
+
88
+ if (!clone.metadata) {
89
+ clone.metadata = {};
90
+ }
91
+
92
+ clone.amount = Number(clone.amount || 0);
93
+ const persisted: PersistedPaymentInput = {
94
+ ...clone,
95
+ normalizedAt: Date.now(),
96
+ saved: true
97
+ };
98
+ return persisted;
99
+ }
100
+
101
+ /**
102
+ * @section static:methods
103
+ */
104
+
105
+ // empty
106
+ }
@@ -0,0 +1,102 @@
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 PaymentInput = { amount: number; currency: string; metadata: Record<string, string> };
24
+ type PaymentDraft = { amount: number; currency: string; metadata: Record<string, string> };
25
+
26
+ export class PaymentNormalizer {
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(): PaymentNormalizer {
62
+ const normalizer = new PaymentNormalizer();
63
+ return normalizer;
64
+ }
65
+
66
+ /**
67
+ * @section private:methods
68
+ */
69
+
70
+ private normalizeAmount(amount: number): number {
71
+ const normalizedAmount = Number(amount.toFixed(2));
72
+ return normalizedAmount;
73
+ }
74
+
75
+ private normalizeCurrency(currency: string): string {
76
+ const normalizedCurrency = currency.trim().toUpperCase();
77
+ return normalizedCurrency;
78
+ }
79
+
80
+ private sanitizeMetadata(metadata: Record<string, string>): Record<string, string> {
81
+ const sanitizedMetadata: Record<string, string> = { ...metadata };
82
+ return sanitizedMetadata;
83
+ }
84
+
85
+ /**
86
+ * @section public:methods
87
+ */
88
+
89
+ public normalize(input: PaymentInput): PaymentDraft {
90
+ const amount: number = this.normalizeAmount(input.amount);
91
+ const currency: string = this.normalizeCurrency(input.currency);
92
+ const metadata: Record<string, string> = this.sanitizeMetadata(input.metadata);
93
+ const draft: PaymentDraft = { amount, currency, metadata };
94
+ return draft;
95
+ }
96
+
97
+ /**
98
+ * @section static:methods
99
+ */
100
+
101
+ // empty
102
+ }
@@ -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
+ // empty
18
+
19
+ /**
20
+ * @section types
21
+ */
22
+
23
+ type InvoiceStatus = "paid" | "void" | "pending";
24
+
25
+ export class InvoiceStatusPresenter {
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(): InvoiceStatusPresenter {
61
+ const presenter = new InvoiceStatusPresenter();
62
+ return presenter;
63
+ }
64
+
65
+ /**
66
+ * @section private:methods
67
+ */
68
+
69
+ // empty
70
+
71
+ /**
72
+ * @section public:methods
73
+ */
74
+
75
+ public toStatusLabel(status: InvoiceStatus): string {
76
+ if (status === "paid") {
77
+ return "Paid";
78
+ }
79
+
80
+ if (status === "void") {
81
+ return "Void";
82
+ }
83
+
84
+ return "Pending";
85
+ }
86
+
87
+ /**
88
+ * @section static:methods
89
+ */
90
+
91
+ // empty
92
+ }
@@ -0,0 +1,94 @@
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 InvoiceStatus = "paid" | "void" | "pending";
24
+
25
+ export class InvoiceStatusPresenter {
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(): InvoiceStatusPresenter {
61
+ const presenter = new InvoiceStatusPresenter();
62
+ return presenter;
63
+ }
64
+
65
+ /**
66
+ * @section private:methods
67
+ */
68
+
69
+ // empty
70
+
71
+ /**
72
+ * @section public:methods
73
+ */
74
+
75
+ public toStatusLabel(status: InvoiceStatus): string {
76
+ let label: string;
77
+
78
+ if (status === "paid") {
79
+ label = "Paid";
80
+ } else if (status === "void") {
81
+ label = "Void";
82
+ } else {
83
+ label = "Pending";
84
+ }
85
+
86
+ return label;
87
+ }
88
+
89
+ /**
90
+ * @section static:methods
91
+ */
92
+
93
+ // empty
94
+ }