@shrkcrft/presets 0.1.0-alpha.4 → 0.1.0-alpha.6
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.
- package/dist/builtin/angular21-presets.d.ts +9 -0
- package/dist/builtin/angular21-presets.d.ts.map +1 -0
- package/dist/builtin/angular21-presets.js +218 -0
- package/dist/builtin/angular21-snippets.d.ts +28 -0
- package/dist/builtin/angular21-snippets.d.ts.map +1 -0
- package/dist/builtin/angular21-snippets.js +243 -0
- package/dist/builtin/builtin-presets.d.ts.map +1 -1
- package/dist/builtin/builtin-presets.js +15 -9
- package/dist/builtin/r26-presets.d.ts.map +1 -1
- package/dist/builtin/r26-presets.js +3 -3
- package/dist/builtin/r45-presets.d.ts.map +1 -1
- package/dist/builtin/r45-presets.js +3 -3
- package/dist/builtin/r47-presets.d.ts.map +1 -1
- package/dist/builtin/r47-presets.js +3 -3
- package/dist/builtin/shared-snippets.d.ts +18 -0
- package/dist/builtin/shared-snippets.d.ts.map +1 -1
- package/dist/builtin/shared-snippets.js +213 -0
- package/package.json +4 -4
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IPreset } from '../model/preset.js';
|
|
2
|
+
export declare const ANGULAR_21_SIGNALS: IPreset;
|
|
3
|
+
export declare const ANGULAR_21_ZONELESS: IPreset;
|
|
4
|
+
export declare const ANGULAR_21_CONTROL_FLOW: IPreset;
|
|
5
|
+
export declare const ANGULAR_21_RESOURCE: IPreset;
|
|
6
|
+
export declare const ANGULAR_21_MODERN_DI: IPreset;
|
|
7
|
+
export declare const ANGULAR_21_MODERN: IPreset;
|
|
8
|
+
export declare const ANGULAR_21_PRESETS: readonly IPreset[];
|
|
9
|
+
//# sourceMappingURL=angular21-presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular21-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/angular21-presets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAmDlD,eAAO,MAAM,kBAAkB,EAAE,OAiC/B,CAAC;AAIH,eAAO,MAAM,mBAAmB,EAAE,OA8BhC,CAAC;AAIH,eAAO,MAAM,uBAAuB,EAAE,OAgCpC,CAAC;AAIH,eAAO,MAAM,mBAAmB,EAAE,OA6BhC,CAAC;AAIH,eAAO,MAAM,oBAAoB,EAAE,OA8BjC,CAAC;AAIH,eAAO,MAAM,iBAAiB,EAAE,OAgD9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,SAAS,OAAO,EAO/C,CAAC"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// Modern Angular 18 / 19 / 20 / 21 preset family.
|
|
2
|
+
//
|
|
3
|
+
// Six presets — five focused on a single area of the modernisation surface,
|
|
4
|
+
// one comprehensive that composes the rest. They target Angular workspaces
|
|
5
|
+
// (HasAngular) with `weight` set above `modern-angular` (R26, weight 9) so
|
|
6
|
+
// the recommender prefers them when the workspace shape allows.
|
|
7
|
+
//
|
|
8
|
+
// Each preset's `paths` includes the standard Angular structure
|
|
9
|
+
// (src/app/, src/app/components/, src/app/services/) so the init paths
|
|
10
|
+
// advisory annotator can verify against the live workspace.
|
|
11
|
+
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
12
|
+
import { definePreset } from "../define/define-preset.js";
|
|
13
|
+
import { ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES, COMMON_AGENT_BRIEFING, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_SAFETY_RULE, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
14
|
+
import { NG21_AFTER_RENDER, NG21_BOOTSTRAP_APPLICATION, NG21_CONTROL_FLOW, NG21_DEFER, NG21_HTTP_RESOURCE, NG21_HYBRID_RENDERING, NG21_INJECT_FN, NG21_LET_TEMPLATE, NG21_LINKED_SIGNAL, NG21_MODEL_TWO_WAY, NG21_NG_OPTIMIZED_IMAGE, NG21_NO_EFFECT_FOR_DERIVED, NG21_NO_NGMODULES, NG21_NO_ZONE_APIS, NG21_PROVIDE_HTTP_FETCH, NG21_PROVIDED_IN_ROOT, NG21_RESOURCE_API, NG21_SELF_CLOSING_TAGS, NG21_SIGNAL_CONTENT_CHILD, NG21_SIGNAL_FORMS_INTEROP, NG21_SIGNAL_INPUTS, NG21_SIGNAL_OUTPUTS, NG21_SIGNAL_STATE, NG21_SIGNAL_VIEW_CHILD, NG21_TEST_NO_DETECT_CHANGES_OUTSIDE, NG21_TEST_SIGNAL_INPUT, NG21_ZONELESS, } from "./angular21-snippets.js";
|
|
15
|
+
const NG21_TAGS = ['angular', 'angular-21', 'modern'];
|
|
16
|
+
const NG21_NEXT_COMMANDS = [
|
|
17
|
+
'shrk doctor',
|
|
18
|
+
'shrk task "<task>"',
|
|
19
|
+
'shrk ci scaffold github-actions --quickstart',
|
|
20
|
+
];
|
|
21
|
+
// ─── 1) Signals — state, queries, inputs, outputs, model ─────────────────
|
|
22
|
+
export const ANGULAR_21_SIGNALS = definePreset({
|
|
23
|
+
id: 'angular-21-signals',
|
|
24
|
+
title: 'Angular 21 — signal-everything',
|
|
25
|
+
description: 'Signal-based local state, queries (viewChild / viewChildren / contentChild / contentChildren as functions), inputs (input() / input.required()), outputs (output()), and two-way bindings (model()). Replaces every @Input/@Output/@ViewChild decorator with its signal-era counterpart.',
|
|
26
|
+
tags: [...NG21_TAGS, 'signals'],
|
|
27
|
+
appliesTo: [WorkspaceProfile.HasAngular],
|
|
28
|
+
weight: 11,
|
|
29
|
+
includes: {
|
|
30
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
31
|
+
rules: [
|
|
32
|
+
COMMON_SAFETY_RULE,
|
|
33
|
+
NG21_SIGNAL_STATE,
|
|
34
|
+
NG21_LINKED_SIGNAL,
|
|
35
|
+
NG21_NO_EFFECT_FOR_DERIVED,
|
|
36
|
+
NG21_SIGNAL_VIEW_CHILD,
|
|
37
|
+
NG21_SIGNAL_CONTENT_CHILD,
|
|
38
|
+
NG21_SIGNAL_INPUTS,
|
|
39
|
+
NG21_SIGNAL_OUTPUTS,
|
|
40
|
+
NG21_MODEL_TWO_WAY,
|
|
41
|
+
NG21_SIGNAL_FORMS_INTEROP,
|
|
42
|
+
],
|
|
43
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
44
|
+
templates: [],
|
|
45
|
+
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
46
|
+
docs: {
|
|
47
|
+
'overview.md': OVERVIEW_DOC('Angular 21 signals', 'No @Input, no @Output, no @ViewChild, no EventEmitter. Local state in signal(), derived in computed()/linkedSignal(), side effects in effect(), queries via viewChild()/contentChild(), I/O via input()/output()/model().'),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
recommendedNextCommands: NG21_NEXT_COMMANDS,
|
|
51
|
+
});
|
|
52
|
+
// ─── 2) Zoneless ──────────────────────────────────────────────────────────
|
|
53
|
+
export const ANGULAR_21_ZONELESS = definePreset({
|
|
54
|
+
id: 'angular-21-zoneless',
|
|
55
|
+
title: 'Angular 21 — zoneless change detection',
|
|
56
|
+
description: 'Bootstrap with provideZonelessChangeDetection() and remove zone.js entirely. Codifies the "no NgZone APIs, signals drive CD" posture, plus the migration hints (signal-first state, afterNextRender for DOM-aware work).',
|
|
57
|
+
tags: [...NG21_TAGS, 'zoneless', 'performance'],
|
|
58
|
+
appliesTo: [WorkspaceProfile.HasAngular],
|
|
59
|
+
weight: 11,
|
|
60
|
+
includes: {
|
|
61
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
62
|
+
rules: [
|
|
63
|
+
COMMON_SAFETY_RULE,
|
|
64
|
+
NG21_ZONELESS,
|
|
65
|
+
NG21_NO_ZONE_APIS,
|
|
66
|
+
NG21_SIGNAL_STATE,
|
|
67
|
+
NG21_AFTER_RENDER,
|
|
68
|
+
NG21_BOOTSTRAP_APPLICATION,
|
|
69
|
+
NG21_PROVIDE_HTTP_FETCH,
|
|
70
|
+
],
|
|
71
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
72
|
+
templates: [],
|
|
73
|
+
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
74
|
+
docs: {
|
|
75
|
+
'overview.md': OVERVIEW_DOC('Angular 21 zoneless', 'CD runs when signals change, inputs update, or events fire — not on every microtask. No NgZone.run / runOutsideAngular. DOM-aware code uses afterNextRender(). HttpClient uses the fetch backend.'),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
recommendedNextCommands: NG21_NEXT_COMMANDS,
|
|
79
|
+
});
|
|
80
|
+
// ─── 3) Modern control flow + template ergonomics ────────────────────────
|
|
81
|
+
export const ANGULAR_21_CONTROL_FLOW = definePreset({
|
|
82
|
+
id: 'angular-21-control-flow',
|
|
83
|
+
title: 'Angular 21 — modern template control flow',
|
|
84
|
+
description: 'Built-in @if / @for / @switch / @defer / @let blocks instead of *ngIf / *ngFor / [ngSwitch], self-closing component tags, NgOptimizedImage. Includes the migration guidance for legacy templates.',
|
|
85
|
+
tags: [...NG21_TAGS, 'templates', 'control-flow'],
|
|
86
|
+
appliesTo: [WorkspaceProfile.HasAngular],
|
|
87
|
+
weight: 11,
|
|
88
|
+
includes: {
|
|
89
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
90
|
+
rules: [
|
|
91
|
+
COMMON_SAFETY_RULE,
|
|
92
|
+
NG21_CONTROL_FLOW,
|
|
93
|
+
NG21_DEFER,
|
|
94
|
+
NG21_LET_TEMPLATE,
|
|
95
|
+
NG21_SELF_CLOSING_TAGS,
|
|
96
|
+
NG21_NG_OPTIMIZED_IMAGE,
|
|
97
|
+
],
|
|
98
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS],
|
|
99
|
+
templates: [],
|
|
100
|
+
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
101
|
+
docs: {
|
|
102
|
+
'overview.md': OVERVIEW_DOC('Angular 21 control flow', '@if / @for (track is REQUIRED) / @switch / @defer / @let. Self-closing tags for content-less components. NgOptimizedImage with explicit width/height for every raster image.'),
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
recommendedNextCommands: [
|
|
106
|
+
...NG21_NEXT_COMMANDS,
|
|
107
|
+
'ng generate @angular/core:control-flow',
|
|
108
|
+
],
|
|
109
|
+
});
|
|
110
|
+
// ─── 4) Resource API — declarative async (signal-native) ─────────────────
|
|
111
|
+
export const ANGULAR_21_RESOURCE = definePreset({
|
|
112
|
+
id: 'angular-21-resource',
|
|
113
|
+
title: 'Angular 21 — resource() / httpResource() / linkedSignal',
|
|
114
|
+
description: 'Declarative async state via resource() and httpResource(). Replaces the hand-rolled subscribe+loading+error triplet with a typed state machine driven by signals. Includes the linkedSignal pattern for writable derived values.',
|
|
115
|
+
tags: [...NG21_TAGS, 'async', 'resource'],
|
|
116
|
+
appliesTo: [WorkspaceProfile.HasAngular],
|
|
117
|
+
weight: 11,
|
|
118
|
+
includes: {
|
|
119
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
120
|
+
rules: [
|
|
121
|
+
COMMON_SAFETY_RULE,
|
|
122
|
+
NG21_RESOURCE_API,
|
|
123
|
+
NG21_HTTP_RESOURCE,
|
|
124
|
+
NG21_LINKED_SIGNAL,
|
|
125
|
+
NG21_PROVIDE_HTTP_FETCH,
|
|
126
|
+
NG21_SIGNAL_STATE,
|
|
127
|
+
],
|
|
128
|
+
paths: [ANGULAR_PATH_SERVICES, ANGULAR_PATH_APP],
|
|
129
|
+
templates: [],
|
|
130
|
+
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
131
|
+
docs: {
|
|
132
|
+
'overview.md': OVERVIEW_DOC('Angular 21 resource API', 'resource({ request, loader }) is the canonical async primitive — exposes value()/status()/error()/reload() as signals. httpResource(() => `/api/...`) for read endpoints. linkedSignal for writable state that follows a source.'),
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
recommendedNextCommands: NG21_NEXT_COMMANDS,
|
|
136
|
+
});
|
|
137
|
+
// ─── 5) Modern DI + lifecycle + bootstrap ────────────────────────────────
|
|
138
|
+
export const ANGULAR_21_MODERN_DI = definePreset({
|
|
139
|
+
id: 'angular-21-modern-di',
|
|
140
|
+
title: 'Angular 21 — inject(), no NgModules, bootstrap modern',
|
|
141
|
+
description: 'inject() function over constructor parameters, providedIn root for tree-shakeable services, no new NgModules, bootstrapApplication() with the provideX() function family, afterNextRender() for DOM-aware lifecycle.',
|
|
142
|
+
tags: [...NG21_TAGS, 'di', 'lifecycle', 'bootstrap'],
|
|
143
|
+
appliesTo: [WorkspaceProfile.HasAngular],
|
|
144
|
+
weight: 11,
|
|
145
|
+
includes: {
|
|
146
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
147
|
+
rules: [
|
|
148
|
+
COMMON_SAFETY_RULE,
|
|
149
|
+
NG21_INJECT_FN,
|
|
150
|
+
NG21_PROVIDED_IN_ROOT,
|
|
151
|
+
NG21_NO_NGMODULES,
|
|
152
|
+
NG21_BOOTSTRAP_APPLICATION,
|
|
153
|
+
NG21_AFTER_RENDER,
|
|
154
|
+
NG21_PROVIDE_HTTP_FETCH,
|
|
155
|
+
],
|
|
156
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_SERVICES],
|
|
157
|
+
templates: [],
|
|
158
|
+
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
159
|
+
docs: {
|
|
160
|
+
'overview.md': OVERVIEW_DOC('Angular 21 modern DI + bootstrap', 'inject() over constructor injection. @Injectable({ providedIn: "root" }) for tree-shakeable services. No new @NgModule. main.ts uses bootstrapApplication(AppComponent, { providers: [provideRouter, provideHttpClient(withFetch()), provideZonelessChangeDetection(), provideAnimationsAsync()] }).'),
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
recommendedNextCommands: NG21_NEXT_COMMANDS,
|
|
164
|
+
});
|
|
165
|
+
// ─── 6) The whole stack — composes all of the above ──────────────────────
|
|
166
|
+
export const ANGULAR_21_MODERN = definePreset({
|
|
167
|
+
id: 'angular-21-modern',
|
|
168
|
+
title: 'Angular 21 — modern stack (signals + zoneless + control-flow + resource + DI)',
|
|
169
|
+
description: 'The canonical preset for a new Angular 21 app. Composes signals-everything, zoneless CD, modern control flow, resource() async, and inject()-based DI — plus the testing rules for signal inputs and SSR-safe HTTP. Use this unless you specifically want a narrower slice.',
|
|
170
|
+
tags: [...NG21_TAGS, 'comprehensive'],
|
|
171
|
+
appliesTo: [WorkspaceProfile.HasAngular, WorkspaceProfile.IsFrontend],
|
|
172
|
+
weight: 12,
|
|
173
|
+
composes: [
|
|
174
|
+
'angular-21-signals',
|
|
175
|
+
'angular-21-zoneless',
|
|
176
|
+
'angular-21-control-flow',
|
|
177
|
+
'angular-21-resource',
|
|
178
|
+
'angular-21-modern-di',
|
|
179
|
+
],
|
|
180
|
+
includes: {
|
|
181
|
+
knowledge: [COMMON_AGENT_BRIEFING],
|
|
182
|
+
rules: [
|
|
183
|
+
COMMON_SAFETY_RULE,
|
|
184
|
+
// Extras that don't fit into any single focused preset:
|
|
185
|
+
NG21_HYBRID_RENDERING,
|
|
186
|
+
NG21_TEST_SIGNAL_INPUT,
|
|
187
|
+
NG21_TEST_NO_DETECT_CHANGES_OUTSIDE,
|
|
188
|
+
],
|
|
189
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
190
|
+
templates: [],
|
|
191
|
+
pipelines: [
|
|
192
|
+
COMMON_PIPELINE_CONTEXT_ONLY,
|
|
193
|
+
COMMON_PIPELINE_FEATURE_DEV,
|
|
194
|
+
COMMON_PIPELINE_UNIT_TEST,
|
|
195
|
+
],
|
|
196
|
+
docs: {
|
|
197
|
+
'overview.md': OVERVIEW_DOC('Angular 21 modern stack', 'No decorators where a signal-era function exists. Zoneless CD. @if/@for/@defer/@let templates. resource() and httpResource() for async. inject() everywhere. bootstrapApplication with provideX functions — no NgModules. SSR via per-route RenderMode tags. Test signal inputs via fixture.componentRef.setInput().'),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
recommendedNextCommands: [
|
|
201
|
+
'shrk doctor',
|
|
202
|
+
'shrk surface list',
|
|
203
|
+
'shrk task "<task>"',
|
|
204
|
+
'ng generate @angular/core:control-flow',
|
|
205
|
+
'ng generate @angular/core:signal-input-migration',
|
|
206
|
+
'ng generate @angular/core:signal-queries-migration',
|
|
207
|
+
'ng generate @angular/core:output-migration',
|
|
208
|
+
],
|
|
209
|
+
surfaceProfile: 'small-app',
|
|
210
|
+
});
|
|
211
|
+
export const ANGULAR_21_PRESETS = Object.freeze([
|
|
212
|
+
ANGULAR_21_SIGNALS,
|
|
213
|
+
ANGULAR_21_ZONELESS,
|
|
214
|
+
ANGULAR_21_CONTROL_FLOW,
|
|
215
|
+
ANGULAR_21_RESOURCE,
|
|
216
|
+
ANGULAR_21_MODERN_DI,
|
|
217
|
+
ANGULAR_21_MODERN,
|
|
218
|
+
]);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const NG21_SIGNAL_STATE: string;
|
|
2
|
+
export declare const NG21_LINKED_SIGNAL: string;
|
|
3
|
+
export declare const NG21_NO_EFFECT_FOR_DERIVED: string;
|
|
4
|
+
export declare const NG21_SIGNAL_VIEW_CHILD: string;
|
|
5
|
+
export declare const NG21_SIGNAL_CONTENT_CHILD: string;
|
|
6
|
+
export declare const NG21_SIGNAL_INPUTS: string;
|
|
7
|
+
export declare const NG21_SIGNAL_OUTPUTS: string;
|
|
8
|
+
export declare const NG21_MODEL_TWO_WAY: string;
|
|
9
|
+
export declare const NG21_ZONELESS: string;
|
|
10
|
+
export declare const NG21_NO_ZONE_APIS: string;
|
|
11
|
+
export declare const NG21_CONTROL_FLOW: string;
|
|
12
|
+
export declare const NG21_DEFER: string;
|
|
13
|
+
export declare const NG21_LET_TEMPLATE: string;
|
|
14
|
+
export declare const NG21_SELF_CLOSING_TAGS: string;
|
|
15
|
+
export declare const NG21_NG_OPTIMIZED_IMAGE: string;
|
|
16
|
+
export declare const NG21_INJECT_FN: string;
|
|
17
|
+
export declare const NG21_AFTER_RENDER: string;
|
|
18
|
+
export declare const NG21_PROVIDED_IN_ROOT: string;
|
|
19
|
+
export declare const NG21_NO_NGMODULES: string;
|
|
20
|
+
export declare const NG21_BOOTSTRAP_APPLICATION: string;
|
|
21
|
+
export declare const NG21_RESOURCE_API: string;
|
|
22
|
+
export declare const NG21_HTTP_RESOURCE: string;
|
|
23
|
+
export declare const NG21_HYBRID_RENDERING: string;
|
|
24
|
+
export declare const NG21_PROVIDE_HTTP_FETCH: string;
|
|
25
|
+
export declare const NG21_SIGNAL_FORMS_INTEROP: string;
|
|
26
|
+
export declare const NG21_TEST_SIGNAL_INPUT: string;
|
|
27
|
+
export declare const NG21_TEST_NO_DETECT_CHANGES_OUTSIDE: string;
|
|
28
|
+
//# sourceMappingURL=angular21-snippets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular21-snippets.d.ts","sourceRoot":"","sources":["../../src/builtin/angular21-snippets.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAQ7B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAIH,eAAO,MAAM,kBAAkB,QAQ7B,CAAC;AAEH,eAAO,MAAM,mBAAmB,QAQ9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAQ7B,CAAC;AAIH,eAAO,MAAM,aAAa,QAQxB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAIH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,UAAU,QAQrB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAIH,eAAO,MAAM,cAAc,QAQzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAIH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAIH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAQ7B,CAAC;AAIH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAIH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,mCAAmC,QAQ9C,CAAC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Modern Angular 18 / 19 / 20 / 21 rule snippets.
|
|
2
|
+
//
|
|
3
|
+
// Covers the post-decorators wave: signal-based reactivity, signal-based
|
|
4
|
+
// queries (`viewChild()` / `contentChild()` etc.), signal-based I/O
|
|
5
|
+
// (`input()` / `output()` / `model()`), zoneless change detection, the new
|
|
6
|
+
// template control flow (`@if` / `@for` / `@switch` / `@defer` / `@let`),
|
|
7
|
+
// `inject()` over constructor DI, `afterRender` / `afterNextRender`,
|
|
8
|
+
// `resource()` / `httpResource()`, `linkedSignal`, `NgOptimizedImage`,
|
|
9
|
+
// self-closing component tags, and the no-NgModules / hybrid-rendering
|
|
10
|
+
// posture.
|
|
11
|
+
//
|
|
12
|
+
// Each snippet is a string injected verbatim into a generated
|
|
13
|
+
// `sharkcraft/*.ts` file; `defineKnowledgeEntry`, `KnowledgeType`, and
|
|
14
|
+
// `KnowledgePriority` are provided by the local-mirror preamble the
|
|
15
|
+
// synthesizer prepends.
|
|
16
|
+
import { ruleSnippet } from "./r26-snippets.js";
|
|
17
|
+
// ─── Signal-based reactivity (Angular 16+, fully baked by 19/20) ──────────
|
|
18
|
+
export const NG21_SIGNAL_STATE = ruleSnippet({
|
|
19
|
+
id: 'angular21.signal-state',
|
|
20
|
+
title: 'Local component state lives in signals',
|
|
21
|
+
priority: 'critical',
|
|
22
|
+
tags: ['angular', 'angular-21', 'signals'],
|
|
23
|
+
appliesWhen: ['generate-component', 'generate-code'],
|
|
24
|
+
content: 'Use signal() for every piece of component-local mutable state. Derive read-only values with computed(). Reserve effect() for side effects only (DOM imperative code, logging, external I/O) — never write to a signal from inside an effect.',
|
|
25
|
+
});
|
|
26
|
+
export const NG21_LINKED_SIGNAL = ruleSnippet({
|
|
27
|
+
id: 'angular21.linked-signal',
|
|
28
|
+
title: 'Use linkedSignal for writable derived state',
|
|
29
|
+
priority: 'high',
|
|
30
|
+
tags: ['angular', 'angular-21', 'signals'],
|
|
31
|
+
appliesWhen: ['generate-component', 'refactor'],
|
|
32
|
+
content: 'When you need a writable signal that resets whenever a source signal changes (e.g. a selection that follows a filtered list), use linkedSignal({ source, computation }) instead of an effect that pokes a writable signal — that pattern is officially discouraged.',
|
|
33
|
+
});
|
|
34
|
+
export const NG21_NO_EFFECT_FOR_DERIVED = ruleSnippet({
|
|
35
|
+
id: 'angular21.no-effect-for-derived',
|
|
36
|
+
title: 'Never derive state inside an effect()',
|
|
37
|
+
priority: 'critical',
|
|
38
|
+
tags: ['angular', 'angular-21', 'signals'],
|
|
39
|
+
appliesWhen: ['generate-code', 'review'],
|
|
40
|
+
content: 'If you find yourself writing effect(() => mySignal.set(compute(otherSignal()))), switch to computed() or linkedSignal(). Writing inside effects breaks single-source-of-truth and reintroduces the very glitches signals were designed to remove.',
|
|
41
|
+
});
|
|
42
|
+
// ─── Signal-based queries (Angular 17.2+) ─────────────────────────────────
|
|
43
|
+
export const NG21_SIGNAL_VIEW_CHILD = ruleSnippet({
|
|
44
|
+
id: 'angular21.signal-view-child',
|
|
45
|
+
title: 'Use viewChild() / viewChildren() functions, not @ViewChild',
|
|
46
|
+
priority: 'critical',
|
|
47
|
+
tags: ['angular', 'angular-21', 'queries', 'signals'],
|
|
48
|
+
appliesWhen: ['generate-component', 'refactor'],
|
|
49
|
+
content: 'Replace @ViewChild and @ViewChildren with the viewChild() / viewChildren() functions. The signal form is reactive (you can pipe it through computed()/effect()), avoids the "expression has changed after it was checked" class of bug, and integrates with OnPush + zoneless out of the box. Use viewChild.required<ElementRef>("name") when the element is guaranteed.',
|
|
50
|
+
});
|
|
51
|
+
export const NG21_SIGNAL_CONTENT_CHILD = ruleSnippet({
|
|
52
|
+
id: 'angular21.signal-content-child',
|
|
53
|
+
title: 'Use contentChild() / contentChildren() functions, not @ContentChild',
|
|
54
|
+
priority: 'critical',
|
|
55
|
+
tags: ['angular', 'angular-21', 'queries', 'signals'],
|
|
56
|
+
appliesWhen: ['generate-component', 'refactor'],
|
|
57
|
+
content: 'Replace @ContentChild and @ContentChildren with the contentChild() / contentChildren() functions. Same reactivity story as viewChild — and contentChild() resolves at the same lifecycle moment regardless of static/dynamic, so you no longer need the {static: true} workaround.',
|
|
58
|
+
});
|
|
59
|
+
// ─── Signal-based inputs / outputs (Angular 17.1+ / 17.3+) ───────────────
|
|
60
|
+
export const NG21_SIGNAL_INPUTS = ruleSnippet({
|
|
61
|
+
id: 'angular21.signal-inputs',
|
|
62
|
+
title: 'Use input() and input.required(), not @Input()',
|
|
63
|
+
priority: 'critical',
|
|
64
|
+
tags: ['angular', 'angular-21', 'inputs', 'signals'],
|
|
65
|
+
appliesWhen: ['generate-component', 'refactor'],
|
|
66
|
+
content: 'Declare inputs as `readonly user = input<User>()` or `readonly id = input.required<string>()` instead of @Input(). Signal inputs are read-only signals — call them as a function in the template (`{{ user() }}`) or pipe them through computed() in the class. Use the transform option for coerced inputs: `input(false, { transform: booleanAttribute })`.',
|
|
67
|
+
});
|
|
68
|
+
export const NG21_SIGNAL_OUTPUTS = ruleSnippet({
|
|
69
|
+
id: 'angular21.signal-outputs',
|
|
70
|
+
title: 'Use output(), not @Output() EventEmitter',
|
|
71
|
+
priority: 'critical',
|
|
72
|
+
tags: ['angular', 'angular-21', 'outputs', 'signals'],
|
|
73
|
+
appliesWhen: ['generate-component', 'refactor'],
|
|
74
|
+
content: 'Declare outputs as `readonly select = output<UserId>()` instead of `@Output() select = new EventEmitter<UserId>()`. The output() helper drops the RxJS dependency, is fully typed, and emits via `this.select.emit(id)`. It still composes with `outputToObservable()` when a stream is needed.',
|
|
75
|
+
});
|
|
76
|
+
export const NG21_MODEL_TWO_WAY = ruleSnippet({
|
|
77
|
+
id: 'angular21.model-two-way',
|
|
78
|
+
title: 'Use model() for two-way bindings',
|
|
79
|
+
priority: 'high',
|
|
80
|
+
tags: ['angular', 'angular-21', 'inputs', 'outputs', 'signals'],
|
|
81
|
+
appliesWhen: ['generate-component'],
|
|
82
|
+
content: 'For components that own a piece of state the parent wants to bind two-way, use `readonly value = model<string>("")`. Banana-in-a-box syntax (`[(value)]="x"`) wires up automatically — no manual @Input + @Output pair, no `valueChange` EventEmitter.',
|
|
83
|
+
});
|
|
84
|
+
// ─── Zoneless change detection (stable in Angular 21) ─────────────────────
|
|
85
|
+
export const NG21_ZONELESS = ruleSnippet({
|
|
86
|
+
id: 'angular21.zoneless',
|
|
87
|
+
title: 'Configure zoneless change detection',
|
|
88
|
+
priority: 'critical',
|
|
89
|
+
tags: ['angular', 'angular-21', 'zoneless', 'performance'],
|
|
90
|
+
appliesWhen: ['bootstrap', 'configure'],
|
|
91
|
+
content: 'Bootstrap with provideZonelessChangeDetection() and remove `zone.js` from polyfills + angular.json. Once zoneless, change detection runs only when a signal changes, an input updates, an event handler fires, or a marked component opts in via markForCheck(). Verify by reading the platform: ApplicationRef.componentTypes should not include any zone-aware regressions.',
|
|
92
|
+
});
|
|
93
|
+
export const NG21_NO_ZONE_APIS = ruleSnippet({
|
|
94
|
+
id: 'angular21.no-zone-apis',
|
|
95
|
+
title: 'Do not call NgZone APIs in zoneless code',
|
|
96
|
+
priority: 'high',
|
|
97
|
+
tags: ['angular', 'angular-21', 'zoneless'],
|
|
98
|
+
appliesWhen: ['generate-code', 'review'],
|
|
99
|
+
content: 'In zoneless apps NgZone.run / runOutsideAngular are no-ops. Replace them with explicit ChangeDetectorRef.markForCheck() (rare), afterNextRender() for DOM-aware logic, or simply let the signal graph propagate.',
|
|
100
|
+
});
|
|
101
|
+
// ─── New template control flow (Angular 17+) ──────────────────────────────
|
|
102
|
+
export const NG21_CONTROL_FLOW = ruleSnippet({
|
|
103
|
+
id: 'angular21.control-flow',
|
|
104
|
+
title: 'Use @if / @for / @switch, not *ngIf / *ngFor / [ngSwitch]',
|
|
105
|
+
priority: 'critical',
|
|
106
|
+
tags: ['angular', 'angular-21', 'templates'],
|
|
107
|
+
appliesWhen: ['generate-template', 'refactor'],
|
|
108
|
+
content: 'Built-in control flow is the canonical form. `@if`, `@else if`, `@else`; `@for (item of items; track item.id)` — track is REQUIRED, not optional; `@switch (x) { @case (\'a\') { … } @default { … } }`. Migrate legacy structural directives with `ng generate @angular/core:control-flow`.',
|
|
109
|
+
});
|
|
110
|
+
export const NG21_DEFER = ruleSnippet({
|
|
111
|
+
id: 'angular21.defer',
|
|
112
|
+
title: 'Use @defer for non-critical UI',
|
|
113
|
+
priority: 'high',
|
|
114
|
+
tags: ['angular', 'angular-21', 'templates', 'performance'],
|
|
115
|
+
appliesWhen: ['generate-template', 'optimize-bundle'],
|
|
116
|
+
content: 'Wrap heavy, below-the-fold, or interaction-gated UI in `@defer (on viewport)` / `(on hover)` / `(on idle)` / `(when condition())`. Pair with `@placeholder`, `@loading`, and `@error` blocks. Each @defer block is its own lazy-loaded chunk — no manual `loadComponent` plumbing needed.',
|
|
117
|
+
});
|
|
118
|
+
export const NG21_LET_TEMPLATE = ruleSnippet({
|
|
119
|
+
id: 'angular21.let-template',
|
|
120
|
+
title: 'Use @let for template-local values',
|
|
121
|
+
priority: 'medium',
|
|
122
|
+
tags: ['angular', 'angular-21', 'templates'],
|
|
123
|
+
appliesWhen: ['generate-template'],
|
|
124
|
+
content: 'Introduce template-scoped names with `@let total = items().reduce(...)`. This replaces the `*ngIf="x as y"` aliasing trick — works anywhere in the template, no implicit-element baggage.',
|
|
125
|
+
});
|
|
126
|
+
export const NG21_SELF_CLOSING_TAGS = ruleSnippet({
|
|
127
|
+
id: 'angular21.self-closing-tags',
|
|
128
|
+
title: 'Self-close components with no content children',
|
|
129
|
+
priority: 'low',
|
|
130
|
+
tags: ['angular', 'angular-21', 'templates'],
|
|
131
|
+
appliesWhen: ['generate-template'],
|
|
132
|
+
content: 'Components / directives that take no projected content should be written `<app-foo [x]="y" />`, not `<app-foo …></app-foo>`. Saves a token and matches modern Angular / JSX conventions.',
|
|
133
|
+
});
|
|
134
|
+
export const NG21_NG_OPTIMIZED_IMAGE = ruleSnippet({
|
|
135
|
+
id: 'angular21.ng-optimized-image',
|
|
136
|
+
title: 'Use NgOptimizedImage for raster images',
|
|
137
|
+
priority: 'high',
|
|
138
|
+
tags: ['angular', 'angular-21', 'performance', 'a11y'],
|
|
139
|
+
appliesWhen: ['generate-template'],
|
|
140
|
+
content: 'Replace `<img src="...">` with `<img ngSrc="..." width="…" height="…" priority? />`. NgOptimizedImage adds automatic responsive `srcset`, lazy-loads non-priority images, sets fetchpriority on LCP images, and enforces explicit dimensions to prevent layout shift.',
|
|
141
|
+
});
|
|
142
|
+
// ─── inject(), afterRender, modern lifecycle (Angular 14+ / 16+) ──────────
|
|
143
|
+
export const NG21_INJECT_FN = ruleSnippet({
|
|
144
|
+
id: 'angular21.inject-fn',
|
|
145
|
+
title: 'Use inject(), not constructor parameters',
|
|
146
|
+
priority: 'high',
|
|
147
|
+
tags: ['angular', 'angular-21', 'di'],
|
|
148
|
+
appliesWhen: ['generate-component', 'generate-service', 'refactor'],
|
|
149
|
+
content: 'Default to `private readonly users = inject(UsersService)` over constructor-parameter injection. Required for functional guards / interceptors, makes inheritance straightforward, and removes the need for `@Self()` / `@SkipSelf()` / `@Optional()` decorator stacks (use the options bag instead).',
|
|
150
|
+
});
|
|
151
|
+
export const NG21_AFTER_RENDER = ruleSnippet({
|
|
152
|
+
id: 'angular21.after-render',
|
|
153
|
+
title: 'Use afterNextRender / afterRender for DOM-aware logic',
|
|
154
|
+
priority: 'high',
|
|
155
|
+
tags: ['angular', 'angular-21', 'lifecycle'],
|
|
156
|
+
appliesWhen: ['generate-component'],
|
|
157
|
+
content: 'For code that needs the DOM (measuring, focusing, third-party libs): use afterNextRender(() => …) for one-shot setup or afterRender(() => …) for every CD pass. Both run only in the browser, so they\'re SSR-safe by construction — replacing the ngAfterViewInit + isPlatformBrowser dance.',
|
|
158
|
+
});
|
|
159
|
+
export const NG21_PROVIDED_IN_ROOT = ruleSnippet({
|
|
160
|
+
id: 'angular21.provided-in-root',
|
|
161
|
+
title: 'Services use providedIn: \'root\' (tree-shakeable)',
|
|
162
|
+
priority: 'high',
|
|
163
|
+
tags: ['angular', 'angular-21', 'di', 'services'],
|
|
164
|
+
appliesWhen: ['generate-service'],
|
|
165
|
+
content: 'Inject services via `@Injectable({ providedIn: "root" })` so unused services tree-shake out. Only override with component / route providers when you need a fresh instance per consumer.',
|
|
166
|
+
});
|
|
167
|
+
// ─── No NgModules / standalone-only ───────────────────────────────────────
|
|
168
|
+
export const NG21_NO_NGMODULES = ruleSnippet({
|
|
169
|
+
id: 'angular21.no-ngmodules',
|
|
170
|
+
title: 'Do not create new NgModules',
|
|
171
|
+
priority: 'critical',
|
|
172
|
+
tags: ['angular', 'angular-21', 'architecture'],
|
|
173
|
+
appliesWhen: ['generate-code', 'create-feature'],
|
|
174
|
+
content: 'Angular 21 starter apps are NgModule-free. Components, directives, and pipes are standalone by default (the `standalone: true` flag is the default since v19). Configure providers via `provideX()` functions in bootstrapApplication() or route data, never with @NgModule. If you find yourself writing @NgModule, you are working against the grain.',
|
|
175
|
+
});
|
|
176
|
+
export const NG21_BOOTSTRAP_APPLICATION = ruleSnippet({
|
|
177
|
+
id: 'angular21.bootstrap-application',
|
|
178
|
+
title: 'bootstrap via bootstrapApplication + provideX functions',
|
|
179
|
+
priority: 'high',
|
|
180
|
+
tags: ['angular', 'angular-21', 'bootstrap'],
|
|
181
|
+
appliesWhen: ['bootstrap'],
|
|
182
|
+
content: 'main.ts uses bootstrapApplication(AppComponent, { providers: [provideRouter(routes), provideHttpClient(withFetch()), provideZonelessChangeDetection(), provideAnimationsAsync()] }). Each capability has a provideX() — no AppModule needed.',
|
|
183
|
+
});
|
|
184
|
+
// ─── Async data: resource() / httpResource() (Angular 19/20+) ────────────
|
|
185
|
+
export const NG21_RESOURCE_API = ruleSnippet({
|
|
186
|
+
id: 'angular21.resource-api',
|
|
187
|
+
title: 'Model async state with resource()',
|
|
188
|
+
priority: 'high',
|
|
189
|
+
tags: ['angular', 'angular-21', 'async', 'signals'],
|
|
190
|
+
appliesWhen: ['generate-component', 'generate-service'],
|
|
191
|
+
content: 'For "fetch X based on signal Y" patterns, use resource({ request: () => y(), loader: ({ request, abortSignal }) => fetch(...) }). The resource exposes `.value()`, `.status()`, `.error()`, and `.reload()` — a fully-typed state machine driven by signals. Don\'t hand-roll subscription + loading-state + error-state triplets anymore.',
|
|
192
|
+
});
|
|
193
|
+
export const NG21_HTTP_RESOURCE = ruleSnippet({
|
|
194
|
+
id: 'angular21.http-resource',
|
|
195
|
+
title: 'Use httpResource() for declarative HTTP',
|
|
196
|
+
priority: 'high',
|
|
197
|
+
tags: ['angular', 'angular-21', 'http', 'signals'],
|
|
198
|
+
appliesWhen: ['generate-service'],
|
|
199
|
+
content: 'For straight reads, `const user = httpResource<User>(() => \\`/api/users/${id()}\\`)` replaces an HttpClient.get + BehaviorSubject + loading flag triple. The signal in the URL closure is tracked; updating it refetches.',
|
|
200
|
+
});
|
|
201
|
+
// ─── Modern SSR / hybrid rendering (Angular 19+) ─────────────────────────
|
|
202
|
+
export const NG21_HYBRID_RENDERING = ruleSnippet({
|
|
203
|
+
id: 'angular21.hybrid-rendering',
|
|
204
|
+
title: 'Configure routes with server-rendering modes',
|
|
205
|
+
priority: 'medium',
|
|
206
|
+
tags: ['angular', 'angular-21', 'ssr'],
|
|
207
|
+
appliesWhen: ['configure-routes'],
|
|
208
|
+
content: 'In app.routes.server.ts, tag each route with a RenderMode: `Prerender` for static, `Server` for per-request SSR, `Client` for CSR-only. The default `provideServerRouting(serverRoutes)` enforces the boundary — no more "did this code accidentally run on the server?" guesswork.',
|
|
209
|
+
});
|
|
210
|
+
export const NG21_PROVIDE_HTTP_FETCH = ruleSnippet({
|
|
211
|
+
id: 'angular21.provide-http-fetch',
|
|
212
|
+
title: 'provideHttpClient(withFetch()) — never the XHR backend',
|
|
213
|
+
priority: 'high',
|
|
214
|
+
tags: ['angular', 'angular-21', 'http', 'ssr'],
|
|
215
|
+
appliesWhen: ['configure'],
|
|
216
|
+
content: 'Provide HttpClient with the fetch backend (`provideHttpClient(withFetch())`). XHR breaks under SSR and pays a startup cost; fetch is universal, supports streaming, and is required for resource transfer between server and client.',
|
|
217
|
+
});
|
|
218
|
+
// ─── Forms — modern signal-compatible patterns ───────────────────────────
|
|
219
|
+
export const NG21_SIGNAL_FORMS_INTEROP = ruleSnippet({
|
|
220
|
+
id: 'angular21.signal-forms-interop',
|
|
221
|
+
title: 'Bridge reactive forms into signals with toSignal()',
|
|
222
|
+
priority: 'medium',
|
|
223
|
+
tags: ['angular', 'angular-21', 'forms', 'signals'],
|
|
224
|
+
appliesWhen: ['generate-component'],
|
|
225
|
+
content: 'When you need a form value as a signal, do `const value = toSignal(form.valueChanges, { initialValue: form.getRawValue() })`. Don\'t mix .subscribe() into a component that otherwise relies on signal-driven CD — that subscription will leak.',
|
|
226
|
+
});
|
|
227
|
+
// ─── Testing — modern flow ───────────────────────────────────────────────
|
|
228
|
+
export const NG21_TEST_SIGNAL_INPUT = ruleSnippet({
|
|
229
|
+
id: 'angular21.test-signal-input',
|
|
230
|
+
title: 'Set signal inputs in tests via setInput()',
|
|
231
|
+
priority: 'medium',
|
|
232
|
+
tags: ['angular', 'angular-21', 'testing'],
|
|
233
|
+
appliesWhen: ['generate-test'],
|
|
234
|
+
content: 'In TestBed, set signal-input values with `fixture.componentRef.setInput("user", u)` — not by assigning `component.user`. Detection runs only when the input signal is updated, and setInput is the supported path that triggers it.',
|
|
235
|
+
});
|
|
236
|
+
export const NG21_TEST_NO_DETECT_CHANGES_OUTSIDE = ruleSnippet({
|
|
237
|
+
id: 'angular21.test-no-detect-changes-outside',
|
|
238
|
+
title: 'Let the framework drive CD in tests',
|
|
239
|
+
priority: 'low',
|
|
240
|
+
tags: ['angular', 'angular-21', 'testing'],
|
|
241
|
+
appliesWhen: ['generate-test'],
|
|
242
|
+
content: 'In zoneless tests, call `fixture.detectChanges()` only at deliberate "settle" points; signal updates inside the test run schedule the next CD automatically. Sprinkling detectChanges() after every assignment masks real reactivity bugs.',
|
|
243
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/builtin-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"builtin-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/builtin-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AA4jBlD,eAAO,MAAM,eAAe,EAAE,SAAS,OAAO,EA+B5C,CAAC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
2
2
|
import { definePreset } from "../define/define-preset.js";
|
|
3
|
-
import { COMMON_AGENT_BRIEFING, COMMON_PATH_SERVICES, COMMON_PATH_TESTS, COMMON_PATH_UTILS, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_TEST, COMMON_TEMPLATE_UTILITY, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
3
|
+
import { ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES, COMMON_AGENT_BRIEFING, COMMON_PATH_SERVICES, COMMON_PATH_TESTS, COMMON_PATH_UTILS, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_TEST, COMMON_TEMPLATE_UTILITY, GO_PATH_CMD, GO_PATH_INTERNAL, GO_PATH_PKG, JAVA_MAVEN_PATH_MAIN, JAVA_MAVEN_PATH_TESTS, NX_PATH_APPS, NX_PATH_LIBS, OVERVIEW_DOC, PYTHON_PATH_SRC, PYTHON_PATH_TESTS, RUST_PATH_SRC, RUST_PATH_TESTS, } from "./shared-snippets.js";
|
|
4
4
|
import { R26_PRESETS } from "./r26-presets.js";
|
|
5
5
|
import { R45_PRESETS } from "./r45-presets.js";
|
|
6
6
|
import { R47_PRESETS } from "./r47-presets.js";
|
|
7
|
+
import { ANGULAR_21_PRESETS } from "./angular21-presets.js";
|
|
7
8
|
const GENERIC = definePreset({
|
|
8
9
|
id: 'generic',
|
|
9
10
|
title: 'Generic SharkCraft setup',
|
|
@@ -133,7 +134,7 @@ const ANGULAR_APP = definePreset({
|
|
|
133
134
|
includes: {
|
|
134
135
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
135
136
|
rules: [COMMON_SAFETY_RULE, COMMON_RULE_ONE_EXPORT],
|
|
136
|
-
paths: [
|
|
137
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
137
138
|
templates: [COMMON_TEMPLATE_UTILITY, COMMON_TEMPLATE_TEST],
|
|
138
139
|
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
139
140
|
docs: {
|
|
@@ -177,11 +178,11 @@ const NX_MONOREPO = definePreset({
|
|
|
177
178
|
})`,
|
|
178
179
|
],
|
|
179
180
|
rules: [COMMON_SAFETY_RULE, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_ONE_EXPORT],
|
|
180
|
-
paths: [
|
|
181
|
+
paths: [NX_PATH_LIBS, NX_PATH_APPS],
|
|
181
182
|
templates: [COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_UTILITY, COMMON_TEMPLATE_TEST],
|
|
182
183
|
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST],
|
|
183
184
|
docs: {
|
|
184
|
-
'overview.md': OVERVIEW_DOC('Nx monorepo', 'Many libraries. Layer order is enforced.'),
|
|
185
|
+
'overview.md': OVERVIEW_DOC('Nx monorepo', 'Many libraries. Layer order is enforced. Code lives under libs/<area>/src/lib/; apps under apps/<app>/.'),
|
|
185
186
|
},
|
|
186
187
|
},
|
|
187
188
|
recommendedNextCommands: [
|
|
@@ -374,7 +375,7 @@ const JAVA_MAVEN_SERVICE = definePreset({
|
|
|
374
375
|
includes: {
|
|
375
376
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
376
377
|
rules: [COMMON_SAFETY_RULE],
|
|
377
|
-
paths: [],
|
|
378
|
+
paths: [JAVA_MAVEN_PATH_MAIN, JAVA_MAVEN_PATH_TESTS],
|
|
378
379
|
templates: [],
|
|
379
380
|
pipelines: [],
|
|
380
381
|
docs: {
|
|
@@ -392,7 +393,7 @@ const JAVA_GRADLE_SERVICE = definePreset({
|
|
|
392
393
|
includes: {
|
|
393
394
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
394
395
|
rules: [COMMON_SAFETY_RULE],
|
|
395
|
-
paths: [],
|
|
396
|
+
paths: [JAVA_MAVEN_PATH_MAIN, JAVA_MAVEN_PATH_TESTS],
|
|
396
397
|
templates: [],
|
|
397
398
|
pipelines: [],
|
|
398
399
|
docs: {
|
|
@@ -428,7 +429,7 @@ const PYTHON_SERVICE = definePreset({
|
|
|
428
429
|
includes: {
|
|
429
430
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
430
431
|
rules: [COMMON_SAFETY_RULE],
|
|
431
|
-
paths: [],
|
|
432
|
+
paths: [PYTHON_PATH_SRC, PYTHON_PATH_TESTS],
|
|
432
433
|
templates: [],
|
|
433
434
|
pipelines: [],
|
|
434
435
|
docs: {
|
|
@@ -446,7 +447,7 @@ const GO_MODULE = definePreset({
|
|
|
446
447
|
includes: {
|
|
447
448
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
448
449
|
rules: [COMMON_SAFETY_RULE],
|
|
449
|
-
paths: [],
|
|
450
|
+
paths: [GO_PATH_CMD, GO_PATH_PKG, GO_PATH_INTERNAL],
|
|
450
451
|
templates: [],
|
|
451
452
|
pipelines: [],
|
|
452
453
|
docs: {
|
|
@@ -464,7 +465,7 @@ const RUST_CRATE = definePreset({
|
|
|
464
465
|
includes: {
|
|
465
466
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
466
467
|
rules: [COMMON_SAFETY_RULE],
|
|
467
|
-
paths: [],
|
|
468
|
+
paths: [RUST_PATH_SRC, RUST_PATH_TESTS],
|
|
468
469
|
templates: [],
|
|
469
470
|
pipelines: [],
|
|
470
471
|
docs: {
|
|
@@ -517,4 +518,9 @@ export const BUILTIN_PRESETS = Object.freeze([
|
|
|
517
518
|
...R45_PRESETS,
|
|
518
519
|
// Universal adoption top-5: nest-service, angular-app canonical aliases
|
|
519
520
|
...R47_PRESETS,
|
|
521
|
+
// Angular 18 / 19 / 20 / 21 — signal queries, signal I/O, zoneless,
|
|
522
|
+
// @if/@for/@defer/@let, resource() / httpResource(), inject(), no
|
|
523
|
+
// NgModules. Weight 11-12 so the recommender prefers these over
|
|
524
|
+
// R26 `modern-angular` (weight 9) when the workspace is Angular.
|
|
525
|
+
...ANGULAR_21_PRESETS,
|
|
520
526
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r26-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r26-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"r26-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r26-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAoDlD,eAAO,MAAM,iBAAiB,EAAE,OAe9B,CAAC;AAEH,eAAO,MAAM,yBAAyB,EAAE,OAgBtC,CAAC;AAEH,eAAO,MAAM,uBAAuB,EAAE,OAoBpC,CAAC;AAIH,eAAO,MAAM,iBAAiB,EAAE,OAgC9B,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,OAiBzB,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,OAiBxB,CAAC;AAIH,eAAO,MAAM,cAAc,EAAE,OAmC3B,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,OAelC,CAAC;AAEH,eAAO,MAAM,wBAAwB,EAAE,OAerC,CAAC;AAEH,eAAO,MAAM,6BAA6B,EAAE,OAe1C,CAAC;AAEH,eAAO,MAAM,+BAA+B,EAAE,OAe5C,CAAC;AAEH,eAAO,MAAM,mBAAmB,EAAE,OAehC,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,OAe5B,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,OAelC,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,OAe7B,CAAC;AAEH,eAAO,MAAM,uBAAuB,EAAE,OAepC,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,OASnC,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,OAS5B,CAAC;AAEH,eAAO,MAAM,yBAAyB,EAAE,OAStC,CAAC;AAIH,eAAO,MAAM,cAAc,EAAE,OAQ3B,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,OAQzB,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,OAO/B,CAAC;AAIH,eAAO,MAAM,gBAAgB,EAAE,OAS7B,CAAC;AAEH,eAAO,MAAM,cAAc,EAAE,OAS3B,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,OAQlC,CAAC;AAIH,eAAO,MAAM,cAAc,EAAE,OAS3B,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,OAS5B,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,OAS5B,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,SAAS,OAAO,EA6BxC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
2
2
|
import { definePreset } from "../define/define-preset.js";
|
|
3
|
-
import { COMMON_AGENT_BRIEFING, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
3
|
+
import { ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES, COMMON_AGENT_BRIEFING, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, NEST_PATH_E2E, NEST_PATH_SRC, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
4
4
|
import { NG_ACCESSIBLE, NG_AVOID_BYPASS_SECURITY, NG_DOMAIN_NO_UI_IMPORTS, NG_FEATURE_FOLDERS, NG_GUARDS_SMALL, NG_LAZY_ROUTES, NG_LIFECYCLE_SAFE_CLEANUP, NG_NO_BUSINESS_LOGIC_IN_TEMPLATE, NG_NO_DEEP_LIB_IMPORTS, NG_NO_GOD_SERVICES, NG_ON_PUSH, NG_PLUGIN_NO_DEEP_IMPORTS, NG_PLUGIN_STABLE_CONTRACT, NG_RXJS_NO_NESTED_SUBSCRIBE, NG_SIGNALS_FIRST, NG_STANDALONE_COMPONENTS, NG_TRACK_BY, NG_TYPED_REACTIVE_FORMS, TS_AGENT_SMALL_DIFFS, TS_BRANDED_IDS, TS_DISCRIMINATED_UNIONS, TS_ERROR_HANDLING, TS_NO_ANY, TS_NO_CIRCULAR_IMPORTS, TS_NO_DEEP_IMPORTS, TS_NO_FLOATING_PROMISES, TS_PREFER_SATISFIES, TS_PUBLIC_RETURN_TYPES, TS_READONLY_DEFAULT, TS_VALIDATE_BOUNDARY_INPUT, } from "./r26-snippets.js";
|
|
5
5
|
// ─── Core ──────────────────────────────────────────────────────────────────
|
|
6
6
|
export const GENERIC_SAFE_REPO = definePreset({
|
|
@@ -156,7 +156,7 @@ export const MODERN_ANGULAR = definePreset({
|
|
|
156
156
|
NG_ACCESSIBLE,
|
|
157
157
|
NG_AVOID_BYPASS_SECURITY,
|
|
158
158
|
],
|
|
159
|
-
paths: [],
|
|
159
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
160
160
|
templates: [],
|
|
161
161
|
pipelines: [COMMON_PIPELINE_FEATURE_DEV],
|
|
162
162
|
docs: { 'overview.md': OVERVIEW_DOC('Modern Angular', 'Signals-first reactivity, RxJS used deliberately, standalone components, OnPush CD, lazy routes, typed forms, Nx-style boundaries.') },
|
|
@@ -404,7 +404,7 @@ export const NESTJS_SERVICE = definePreset({
|
|
|
404
404
|
appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
|
|
405
405
|
weight: 7,
|
|
406
406
|
composes: ['node-service'],
|
|
407
|
-
includes: { knowledge: [], rules: [TS_VALIDATE_BOUNDARY_INPUT], paths: [], templates: [], pipelines: [], docs: { 'overview.md': OVERVIEW_DOC('NestJS service', 'Validate DTOs at controllers. Keep services thin. Use modules to enforce layers.') } },
|
|
407
|
+
includes: { knowledge: [], rules: [TS_VALIDATE_BOUNDARY_INPUT], paths: [NEST_PATH_SRC, NEST_PATH_E2E], templates: [], pipelines: [], docs: { 'overview.md': OVERVIEW_DOC('NestJS service', 'Validate DTOs at controllers. Keep services thin. Use modules to enforce layers.') } },
|
|
408
408
|
});
|
|
409
409
|
export const EXPRESS_SERVICE = definePreset({
|
|
410
410
|
id: 'express-service',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r45-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r45-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"r45-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r45-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AA0BlD,eAAO,MAAM,eAAe,EAAE,OA+C5B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,OA+C7B,CAAC;AAEH,eAAO,MAAM,wBAAwB,EAAE,OAuCrC,CAAC;AAEH,eAAO,MAAM,4BAA4B,EAAE,OAoDzC,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,SAAS,OAAO,EAKxC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
2
2
|
import { definePreset } from "../define/define-preset.js";
|
|
3
|
-
import { COMMON_AGENT_BRIEFING, COMMON_PATH_SERVICES, COMMON_PATH_TESTS, COMMON_PATH_UTILS, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_TEST, COMMON_TEMPLATE_UTILITY, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
3
|
+
import { COMMON_AGENT_BRIEFING, COMMON_PATH_SERVICES, COMMON_PATH_TESTS, COMMON_PATH_UTILS, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_NO_LOGIC_CONSTRUCTORS, COMMON_RULE_ONE_EXPORT, COMMON_SAFETY_RULE, COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_TEST, COMMON_TEMPLATE_UTILITY, OVERVIEW_DOC, WORKSPACE_PATH_APPS, WORKSPACE_PATH_PACKAGES, } from "./shared-snippets.js";
|
|
4
4
|
// Universal adoption — fills four Phase-1 preset gaps:
|
|
5
5
|
// next-app, turborepo, package-workspace, clean-architecture-ts.
|
|
6
6
|
// Each preset is generic — no project-specific anchors, no per-stack jargon
|
|
@@ -80,7 +80,7 @@ export const TURBOREPO_PRESET = definePreset({
|
|
|
80
80
|
})`,
|
|
81
81
|
],
|
|
82
82
|
rules: [COMMON_SAFETY_RULE, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_ONE_EXPORT],
|
|
83
|
-
paths: [
|
|
83
|
+
paths: [WORKSPACE_PATH_APPS, WORKSPACE_PATH_PACKAGES],
|
|
84
84
|
templates: [COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_UTILITY, COMMON_TEMPLATE_TEST],
|
|
85
85
|
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST],
|
|
86
86
|
docs: {
|
|
@@ -116,7 +116,7 @@ export const PACKAGE_WORKSPACE_PRESET = definePreset({
|
|
|
116
116
|
})`,
|
|
117
117
|
],
|
|
118
118
|
rules: [COMMON_SAFETY_RULE, COMMON_RULE_INTERFACE_PREFIX, COMMON_RULE_ONE_EXPORT],
|
|
119
|
-
paths: [
|
|
119
|
+
paths: [WORKSPACE_PATH_PACKAGES],
|
|
120
120
|
templates: [COMMON_TEMPLATE_SERVICE, COMMON_TEMPLATE_UTILITY, COMMON_TEMPLATE_TEST],
|
|
121
121
|
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST],
|
|
122
122
|
docs: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r47-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r47-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"r47-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/r47-presets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAuBlD,eAAO,MAAM,mBAAmB,EAAE,OA2BhC,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,OA2B/B,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,SAAS,OAAO,EAGxC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
2
2
|
import { definePreset } from "../define/define-preset.js";
|
|
3
|
-
import { COMMON_AGENT_BRIEFING, COMMON_SAFETY_RULE, OVERVIEW_DOC } from "./shared-snippets.js";
|
|
3
|
+
import { ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES, COMMON_AGENT_BRIEFING, COMMON_SAFETY_RULE, NEST_PATH_E2E, NEST_PATH_SRC, OVERVIEW_DOC, } from "./shared-snippets.js";
|
|
4
4
|
// Universal adoption (top 5) — canonical-id aliases.
|
|
5
5
|
//
|
|
6
6
|
// Why: canonical preset ids are `nest-service` and `angular-app`. The
|
|
@@ -22,7 +22,7 @@ export const NEST_SERVICE_PRESET = definePreset({
|
|
|
22
22
|
includes: {
|
|
23
23
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
24
24
|
rules: [COMMON_SAFETY_RULE],
|
|
25
|
-
paths: [],
|
|
25
|
+
paths: [NEST_PATH_SRC, NEST_PATH_E2E],
|
|
26
26
|
templates: [],
|
|
27
27
|
pipelines: [],
|
|
28
28
|
docs: {
|
|
@@ -46,7 +46,7 @@ export const ANGULAR_APP_PRESET = definePreset({
|
|
|
46
46
|
includes: {
|
|
47
47
|
knowledge: [COMMON_AGENT_BRIEFING],
|
|
48
48
|
rules: [COMMON_SAFETY_RULE],
|
|
49
|
-
paths: [],
|
|
49
|
+
paths: [ANGULAR_PATH_APP, ANGULAR_PATH_COMPONENTS, ANGULAR_PATH_SERVICES],
|
|
50
50
|
templates: [],
|
|
51
51
|
pipelines: [],
|
|
52
52
|
docs: {
|
|
@@ -10,6 +10,24 @@ export declare const TEMPLATE_HELPERS = "function kebab(s: string): string {\n
|
|
|
10
10
|
export declare const COMMON_PATH_SERVICES = "defineKnowledgeEntry({\n id: 'paths.services',\n title: 'Services live in src/services/',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'services'],\n scope: ['app'],\n appliesWhen: ['generate-service'],\n content: 'Service classes live in src/services/. One service per file.',\n metadata: { path: 'src/services' },\n })";
|
|
11
11
|
export declare const COMMON_PATH_UTILS = "defineKnowledgeEntry({\n id: 'paths.utils',\n title: 'Utilities live in src/utils/',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'utils'],\n appliesWhen: ['generate-utility'],\n content: 'Pure helpers live in src/utils/. One function per file.',\n metadata: { path: 'src/utils' },\n })";
|
|
12
12
|
export declare const COMMON_PATH_TESTS = "defineKnowledgeEntry({\n id: 'paths.tests',\n title: 'Tests live in tests/',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'tests'],\n appliesWhen: ['generate-test'],\n content: 'Unit tests live under tests/, mirroring src/. Use *.spec.ts.',\n metadata: { path: 'tests' },\n })";
|
|
13
|
+
export declare const NX_PATH_LIBS = "defineKnowledgeEntry({\n id: 'paths.nx.libs',\n title: 'Nx libs root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'nx', 'libs'],\n scope: ['nx', 'monorepo'],\n appliesWhen: ['generate-service', 'generate-utility', 'create-feature'],\n content: 'Shared library code lives under libs/<area>/src/lib/. Each lib has a public index.ts; cross-lib imports go through the package name, never relative paths into src/.',\n metadata: { path: 'libs' },\n })";
|
|
14
|
+
export declare const NX_PATH_APPS = "defineKnowledgeEntry({\n id: 'paths.nx.apps',\n title: 'Nx apps root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'nx', 'apps'],\n scope: ['nx', 'monorepo'],\n appliesWhen: ['create-feature', 'create-app'],\n content: 'Applications live under apps/<app>/. Frontends use apps/<app>/src/app/; backends use apps/<app>/src/. Keep app-specific code here and shared code in libs/.',\n metadata: { path: 'apps' },\n })";
|
|
15
|
+
export declare const WORKSPACE_PATH_PACKAGES = "defineKnowledgeEntry({\n id: 'paths.workspace.packages',\n title: 'Workspace packages root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'workspaces', 'monorepo'],\n scope: ['monorepo', 'turborepo', 'workspaces'],\n appliesWhen: ['generate-code', 'create-feature'],\n content: 'Shared packages live under packages/<name>/. Each package exposes a stable public entry (package.json main/exports); cross-package imports go through the package name, never relative paths into src/.',\n metadata: { path: 'packages' },\n })";
|
|
16
|
+
export declare const WORKSPACE_PATH_APPS = "defineKnowledgeEntry({\n id: 'paths.workspace.apps',\n title: 'Workspace apps root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'workspaces', 'monorepo'],\n scope: ['monorepo', 'turborepo', 'workspaces'],\n appliesWhen: ['create-feature', 'create-app'],\n content: 'Applications live under apps/<app>/. Each app has its own src/ root and depends on shared packages by name.',\n metadata: { path: 'apps' },\n })";
|
|
17
|
+
export declare const ANGULAR_PATH_APP = "defineKnowledgeEntry({\n id: 'paths.angular.app',\n title: 'Angular app root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Critical,\n tags: ['paths', 'angular', 'app'],\n scope: ['angular'],\n appliesWhen: ['create-feature', 'generate-code'],\n content: 'Angular workspace source lives under src/app/. Components, services, pipes and modules sit under here. Tests are co-located as *.spec.ts beside the unit under test.',\n metadata: { path: 'src/app' },\n })";
|
|
18
|
+
export declare const ANGULAR_PATH_COMPONENTS = "defineKnowledgeEntry({\n id: 'paths.angular.components',\n title: 'Angular components',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'angular', 'components'],\n scope: ['angular'],\n appliesWhen: ['generate-component'],\n content: 'Components live under src/app/components/ or src/app/<feature>/. Use the .component.ts suffix. Pair each component with a co-located *.spec.ts test.',\n metadata: { path: 'src/app/components' },\n })";
|
|
19
|
+
export declare const ANGULAR_PATH_SERVICES = "defineKnowledgeEntry({\n id: 'paths.angular.services',\n title: 'Angular services',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'angular', 'services'],\n scope: ['angular'],\n appliesWhen: ['generate-service'],\n content: 'Injectable services live under src/app/services/ (or alongside their feature folder). Use the .service.ts suffix. Provide via providedIn root unless feature-scoped.',\n metadata: { path: 'src/app/services' },\n })";
|
|
20
|
+
export declare const NEST_PATH_SRC = "defineKnowledgeEntry({\n id: 'paths.nest.src',\n title: 'Nest module roots',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Critical,\n tags: ['paths', 'nest', 'modules'],\n scope: ['nestjs'],\n appliesWhen: ['create-feature', 'generate-service', 'generate-code'],\n content: 'Nest source lives under src/. Each feature gets a folder src/<feature>/ containing controller, service, module, and DTOs (one construct per file). Controllers stay thin; business logic lives in services.',\n metadata: { path: 'src' },\n })";
|
|
21
|
+
export declare const NEST_PATH_E2E = "defineKnowledgeEntry({\n id: 'paths.nest.e2e',\n title: 'Nest e2e tests',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'nest', 'testing'],\n scope: ['nestjs'],\n appliesWhen: ['generate-test'],\n content: 'End-to-end tests live under test/ (Nest convention, not tests/). Unit tests can be co-located as *.spec.ts next to the unit.',\n metadata: { path: 'test' },\n })";
|
|
22
|
+
export declare const JAVA_MAVEN_PATH_MAIN = "defineKnowledgeEntry({\n id: 'paths.java.maven.main',\n title: 'Java Maven main source',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Critical,\n tags: ['paths', 'java', 'maven'],\n scope: ['java', 'maven'],\n appliesWhen: ['generate-code'],\n content: 'Main Java source lives under src/main/java/<package>/. Resources under src/main/resources/. Mirror tests under src/test/java/.',\n metadata: { path: 'src/main/java' },\n })";
|
|
23
|
+
export declare const JAVA_MAVEN_PATH_TESTS = "defineKnowledgeEntry({\n id: 'paths.java.maven.tests',\n title: 'Java Maven tests',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'java', 'maven', 'tests'],\n scope: ['java', 'maven'],\n appliesWhen: ['generate-test'],\n content: 'JUnit / Spring tests live under src/test/java/. Run via mvn test.',\n metadata: { path: 'src/test/java' },\n })";
|
|
24
|
+
export declare const PYTHON_PATH_SRC = "defineKnowledgeEntry({\n id: 'paths.python.src',\n title: 'Python source root',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Critical,\n tags: ['paths', 'python'],\n scope: ['python'],\n appliesWhen: ['generate-code'],\n content: 'Source lives under src/<package>/ (PEP 517 src layout) or directly under <package>/ at the repo root. Pick one and stay consistent.',\n metadata: { path: 'src' },\n })";
|
|
25
|
+
export declare const PYTHON_PATH_TESTS = "defineKnowledgeEntry({\n id: 'paths.python.tests',\n title: 'Python tests',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'python', 'tests'],\n scope: ['python'],\n appliesWhen: ['generate-test'],\n content: 'Pytest tests live under tests/. Each test_*.py mirrors a module under src/.',\n metadata: { path: 'tests' },\n })";
|
|
26
|
+
export declare const GO_PATH_CMD = "defineKnowledgeEntry({\n id: 'paths.go.cmd',\n title: 'Go entry points',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.High,\n tags: ['paths', 'go'],\n scope: ['go'],\n appliesWhen: ['create-app'],\n content: 'Binary entry points live under cmd/<name>/main.go. Shared library code under pkg/ (public) or internal/ (module-private).',\n metadata: { path: 'cmd' },\n })";
|
|
27
|
+
export declare const GO_PATH_PKG = "defineKnowledgeEntry({\n id: 'paths.go.pkg',\n title: 'Go shared packages',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'go'],\n scope: ['go'],\n appliesWhen: ['generate-code'],\n content: 'Public packages live under pkg/<name>/. Tests are co-located as <name>_test.go. Run via go test ./...',\n metadata: { path: 'pkg' },\n })";
|
|
28
|
+
export declare const GO_PATH_INTERNAL = "defineKnowledgeEntry({\n id: 'paths.go.internal',\n title: 'Go internal packages',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'go'],\n scope: ['go'],\n appliesWhen: ['generate-code'],\n content: 'Module-private packages live under internal/<name>/. The Go compiler enforces that only the parent module can import these.',\n metadata: { path: 'internal' },\n })";
|
|
29
|
+
export declare const RUST_PATH_SRC = "defineKnowledgeEntry({\n id: 'paths.rust.src',\n title: 'Rust crate source',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Critical,\n tags: ['paths', 'rust'],\n scope: ['rust'],\n appliesWhen: ['generate-code'],\n content: 'Crate source lives under src/. The entry point is src/lib.rs (library) or src/main.rs (binary). Modules nest as src/<mod>/mod.rs or src/<mod>.rs.',\n metadata: { path: 'src' },\n })";
|
|
30
|
+
export declare const RUST_PATH_TESTS = "defineKnowledgeEntry({\n id: 'paths.rust.tests',\n title: 'Rust integration tests',\n type: KnowledgeType.Path,\n priority: KnowledgePriority.Medium,\n tags: ['paths', 'rust', 'tests'],\n scope: ['rust'],\n appliesWhen: ['generate-test'],\n content: 'Integration tests live under tests/<name>.rs. Unit tests live inline with #[cfg(test)] modules inside src/. Run via cargo test.',\n metadata: { path: 'tests' },\n })";
|
|
13
31
|
export declare const COMMON_RULE_INTERFACE_PREFIX = "defineKnowledgeEntry({\n id: 'typescript.interfaces.i-prefix',\n title: 'Prefix interfaces with I',\n type: KnowledgeType.Rule,\n priority: KnowledgePriority.High,\n tags: ['typescript', 'naming'],\n appliesWhen: ['generate-code', 'refactor'],\n content: 'Interfaces use an I-prefix (IUser, IConfig). Enums are preferred over unions for closed sets.',\n })";
|
|
14
32
|
export declare const COMMON_RULE_ONE_EXPORT = "defineKnowledgeEntry({\n id: 'typescript.files.one-export',\n title: 'One exported construct per file',\n type: KnowledgeType.Rule,\n priority: KnowledgePriority.High,\n tags: ['typescript', 'structure'],\n appliesWhen: ['generate-code'],\n content: 'Each TypeScript file exports exactly one top-level construct. Helpers live in their own file.',\n })";
|
|
15
33
|
export declare const COMMON_RULE_NO_LOGIC_CONSTRUCTORS = "defineKnowledgeEntry({\n id: 'typescript.constructors.no-logic',\n title: 'No business logic in constructors',\n type: KnowledgeType.Rule,\n priority: KnowledgePriority.High,\n tags: ['typescript'],\n appliesWhen: ['generate-code'],\n content: 'Constructors wire dependencies only. Initialization belongs in init().',\n })";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-snippets.d.ts","sourceRoot":"","sources":["../../src/builtin/shared-snippets.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,m9BAuB7B,CAAC;AAEN,eAAO,MAAM,kBAAkB,45BAoB1B,CAAC;AAEN,eAAO,MAAM,2BAA2B,s9CA6CnC,CAAC;AAEN,eAAO,MAAM,4BAA4B,s5BA6BpC,CAAC;AAEN,eAAO,MAAM,yBAAyB,yVAajC,CAAC;AAEN,eAAO,MAAM,uBAAuB,mtBAkB/B,CAAC;AAEN,eAAO,MAAM,uBAAuB,8mBAiB/B,CAAC;AAEN,eAAO,MAAM,oBAAoB,ytBAkB5B,CAAC;AAKN,eAAO,MAAM,gBAAgB,8JAK3B,CAAC;AAEH,eAAO,MAAM,oBAAoB,sYAU5B,CAAC;AAEN,eAAO,MAAM,iBAAiB,mWASzB,CAAC;AAEN,eAAO,MAAM,iBAAiB,yVASzB,CAAC;AAEN,eAAO,MAAM,4BAA4B,+XAQpC,CAAC;AAEN,eAAO,MAAM,sBAAsB,0XAQ9B,CAAC;AAEN,eAAO,MAAM,iCAAiC,6VAQzC,CAAC;AAEN,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MAK1D,CAAC"}
|
|
1
|
+
{"version":3,"file":"shared-snippets.d.ts","sourceRoot":"","sources":["../../src/builtin/shared-snippets.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,m9BAuB7B,CAAC;AAEN,eAAO,MAAM,kBAAkB,45BAoB1B,CAAC;AAEN,eAAO,MAAM,2BAA2B,s9CA6CnC,CAAC;AAEN,eAAO,MAAM,4BAA4B,s5BA6BpC,CAAC;AAEN,eAAO,MAAM,yBAAyB,yVAajC,CAAC;AAEN,eAAO,MAAM,uBAAuB,mtBAkB/B,CAAC;AAEN,eAAO,MAAM,uBAAuB,8mBAiB/B,CAAC;AAEN,eAAO,MAAM,oBAAoB,ytBAkB5B,CAAC;AAKN,eAAO,MAAM,gBAAgB,8JAK3B,CAAC;AAEH,eAAO,MAAM,oBAAoB,sYAU5B,CAAC;AAEN,eAAO,MAAM,iBAAiB,mWASzB,CAAC;AAEN,eAAO,MAAM,iBAAiB,yVASzB,CAAC;AAaN,eAAO,MAAM,YAAY,sgBAUpB,CAAC;AAEN,eAAO,MAAM,YAAY,meAUpB,CAAC;AAIN,eAAO,MAAM,uBAAuB,6kBAU/B,CAAC;AAEN,eAAO,MAAM,mBAAmB,keAU3B,CAAC;AAGN,eAAO,MAAM,gBAAgB,2fAUxB,CAAC;AAEN,eAAO,MAAM,uBAAuB,qfAU/B,CAAC;AAEN,eAAO,MAAM,qBAAqB,2fAU7B,CAAC;AAGN,eAAO,MAAM,aAAa,gjBAUrB,CAAC;AAEN,eAAO,MAAM,aAAa,ubAUrB,CAAC;AAIN,eAAO,MAAM,oBAAoB,wdAU5B,CAAC;AAEN,eAAO,MAAM,qBAAqB,2ZAU7B,CAAC;AAEN,eAAO,MAAM,eAAe,4bAUvB,CAAC;AAEN,eAAO,MAAM,iBAAiB,uYAUzB,CAAC;AAEN,eAAO,MAAM,WAAW,4ZAUnB,CAAC;AAEN,eAAO,MAAM,WAAW,gZAUnB,CAAC;AAEN,eAAO,MAAM,gBAAgB,kbAUxB,CAAC;AAEN,eAAO,MAAM,aAAa,mcAUrB,CAAC;AAEN,eAAO,MAAM,eAAe,icAUvB,CAAC;AAEN,eAAO,MAAM,4BAA4B,+XAQpC,CAAC;AAEN,eAAO,MAAM,sBAAsB,0XAQ9B,CAAC;AAEN,eAAO,MAAM,iCAAiC,6VAQzC,CAAC;AAEN,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MAK1D,CAAC"}
|
|
@@ -232,6 +232,219 @@ export const COMMON_PATH_TESTS = `defineKnowledgeEntry({
|
|
|
232
232
|
content: 'Unit tests live under tests/, mirroring src/. Use *.spec.ts.',
|
|
233
233
|
metadata: { path: 'tests' },
|
|
234
234
|
})`;
|
|
235
|
+
// ─── Framework-specific path snippets ─────────────────────────────────────
|
|
236
|
+
//
|
|
237
|
+
// Each snippet uses the structured `metadata: { path: '<x>' }` field so
|
|
238
|
+
// the init paths-advisory annotator can verify the path against the live
|
|
239
|
+
// workspace. When an entry is emitted into a fresh repo whose layout
|
|
240
|
+
// doesn't match, the user sees a `⚠️ Workspace-shape advisory` block
|
|
241
|
+
// listing the absent paths.
|
|
242
|
+
// Nx workspaces — `libs/<area>/src/lib/<feature>.service.ts`,
|
|
243
|
+
// `apps/<app>/src/app/`. The exact lib/app folder names are
|
|
244
|
+
// project-specific; we point at the roots.
|
|
245
|
+
export const NX_PATH_LIBS = `defineKnowledgeEntry({
|
|
246
|
+
id: 'paths.nx.libs',
|
|
247
|
+
title: 'Nx libs root',
|
|
248
|
+
type: KnowledgeType.Path,
|
|
249
|
+
priority: KnowledgePriority.High,
|
|
250
|
+
tags: ['paths', 'nx', 'libs'],
|
|
251
|
+
scope: ['nx', 'monorepo'],
|
|
252
|
+
appliesWhen: ['generate-service', 'generate-utility', 'create-feature'],
|
|
253
|
+
content: 'Shared library code lives under libs/<area>/src/lib/. Each lib has a public index.ts; cross-lib imports go through the package name, never relative paths into src/.',
|
|
254
|
+
metadata: { path: 'libs' },
|
|
255
|
+
})`;
|
|
256
|
+
export const NX_PATH_APPS = `defineKnowledgeEntry({
|
|
257
|
+
id: 'paths.nx.apps',
|
|
258
|
+
title: 'Nx apps root',
|
|
259
|
+
type: KnowledgeType.Path,
|
|
260
|
+
priority: KnowledgePriority.High,
|
|
261
|
+
tags: ['paths', 'nx', 'apps'],
|
|
262
|
+
scope: ['nx', 'monorepo'],
|
|
263
|
+
appliesWhen: ['create-feature', 'create-app'],
|
|
264
|
+
content: 'Applications live under apps/<app>/. Frontends use apps/<app>/src/app/; backends use apps/<app>/src/. Keep app-specific code here and shared code in libs/.',
|
|
265
|
+
metadata: { path: 'apps' },
|
|
266
|
+
})`;
|
|
267
|
+
// Generic workspace monorepo (Turborepo, pnpm/yarn/npm workspaces): the
|
|
268
|
+
// idiomatic layout is `apps/` + `packages/` rather than Nx's `libs/`.
|
|
269
|
+
export const WORKSPACE_PATH_PACKAGES = `defineKnowledgeEntry({
|
|
270
|
+
id: 'paths.workspace.packages',
|
|
271
|
+
title: 'Workspace packages root',
|
|
272
|
+
type: KnowledgeType.Path,
|
|
273
|
+
priority: KnowledgePriority.High,
|
|
274
|
+
tags: ['paths', 'workspaces', 'monorepo'],
|
|
275
|
+
scope: ['monorepo', 'turborepo', 'workspaces'],
|
|
276
|
+
appliesWhen: ['generate-code', 'create-feature'],
|
|
277
|
+
content: 'Shared packages live under packages/<name>/. Each package exposes a stable public entry (package.json main/exports); cross-package imports go through the package name, never relative paths into src/.',
|
|
278
|
+
metadata: { path: 'packages' },
|
|
279
|
+
})`;
|
|
280
|
+
export const WORKSPACE_PATH_APPS = `defineKnowledgeEntry({
|
|
281
|
+
id: 'paths.workspace.apps',
|
|
282
|
+
title: 'Workspace apps root',
|
|
283
|
+
type: KnowledgeType.Path,
|
|
284
|
+
priority: KnowledgePriority.High,
|
|
285
|
+
tags: ['paths', 'workspaces', 'monorepo'],
|
|
286
|
+
scope: ['monorepo', 'turborepo', 'workspaces'],
|
|
287
|
+
appliesWhen: ['create-feature', 'create-app'],
|
|
288
|
+
content: 'Applications live under apps/<app>/. Each app has its own src/ root and depends on shared packages by name.',
|
|
289
|
+
metadata: { path: 'apps' },
|
|
290
|
+
})`;
|
|
291
|
+
// Single-app Angular workspaces — angular.json + src/app convention.
|
|
292
|
+
export const ANGULAR_PATH_APP = `defineKnowledgeEntry({
|
|
293
|
+
id: 'paths.angular.app',
|
|
294
|
+
title: 'Angular app root',
|
|
295
|
+
type: KnowledgeType.Path,
|
|
296
|
+
priority: KnowledgePriority.Critical,
|
|
297
|
+
tags: ['paths', 'angular', 'app'],
|
|
298
|
+
scope: ['angular'],
|
|
299
|
+
appliesWhen: ['create-feature', 'generate-code'],
|
|
300
|
+
content: 'Angular workspace source lives under src/app/. Components, services, pipes and modules sit under here. Tests are co-located as *.spec.ts beside the unit under test.',
|
|
301
|
+
metadata: { path: 'src/app' },
|
|
302
|
+
})`;
|
|
303
|
+
export const ANGULAR_PATH_COMPONENTS = `defineKnowledgeEntry({
|
|
304
|
+
id: 'paths.angular.components',
|
|
305
|
+
title: 'Angular components',
|
|
306
|
+
type: KnowledgeType.Path,
|
|
307
|
+
priority: KnowledgePriority.High,
|
|
308
|
+
tags: ['paths', 'angular', 'components'],
|
|
309
|
+
scope: ['angular'],
|
|
310
|
+
appliesWhen: ['generate-component'],
|
|
311
|
+
content: 'Components live under src/app/components/ or src/app/<feature>/. Use the .component.ts suffix. Pair each component with a co-located *.spec.ts test.',
|
|
312
|
+
metadata: { path: 'src/app/components' },
|
|
313
|
+
})`;
|
|
314
|
+
export const ANGULAR_PATH_SERVICES = `defineKnowledgeEntry({
|
|
315
|
+
id: 'paths.angular.services',
|
|
316
|
+
title: 'Angular services',
|
|
317
|
+
type: KnowledgeType.Path,
|
|
318
|
+
priority: KnowledgePriority.High,
|
|
319
|
+
tags: ['paths', 'angular', 'services'],
|
|
320
|
+
scope: ['angular'],
|
|
321
|
+
appliesWhen: ['generate-service'],
|
|
322
|
+
content: 'Injectable services live under src/app/services/ (or alongside their feature folder). Use the .service.ts suffix. Provide via providedIn root unless feature-scoped.',
|
|
323
|
+
metadata: { path: 'src/app/services' },
|
|
324
|
+
})`;
|
|
325
|
+
// NestJS services — module-per-folder convention; e2e tests in `test/`.
|
|
326
|
+
export const NEST_PATH_SRC = `defineKnowledgeEntry({
|
|
327
|
+
id: 'paths.nest.src',
|
|
328
|
+
title: 'Nest module roots',
|
|
329
|
+
type: KnowledgeType.Path,
|
|
330
|
+
priority: KnowledgePriority.Critical,
|
|
331
|
+
tags: ['paths', 'nest', 'modules'],
|
|
332
|
+
scope: ['nestjs'],
|
|
333
|
+
appliesWhen: ['create-feature', 'generate-service', 'generate-code'],
|
|
334
|
+
content: 'Nest source lives under src/. Each feature gets a folder src/<feature>/ containing controller, service, module, and DTOs (one construct per file). Controllers stay thin; business logic lives in services.',
|
|
335
|
+
metadata: { path: 'src' },
|
|
336
|
+
})`;
|
|
337
|
+
export const NEST_PATH_E2E = `defineKnowledgeEntry({
|
|
338
|
+
id: 'paths.nest.e2e',
|
|
339
|
+
title: 'Nest e2e tests',
|
|
340
|
+
type: KnowledgeType.Path,
|
|
341
|
+
priority: KnowledgePriority.Medium,
|
|
342
|
+
tags: ['paths', 'nest', 'testing'],
|
|
343
|
+
scope: ['nestjs'],
|
|
344
|
+
appliesWhen: ['generate-test'],
|
|
345
|
+
content: 'End-to-end tests live under test/ (Nest convention, not tests/). Unit tests can be co-located as *.spec.ts next to the unit.',
|
|
346
|
+
metadata: { path: 'test' },
|
|
347
|
+
})`;
|
|
348
|
+
// ─── Polyglot path snippets ──────────────────────────────────────────────
|
|
349
|
+
export const JAVA_MAVEN_PATH_MAIN = `defineKnowledgeEntry({
|
|
350
|
+
id: 'paths.java.maven.main',
|
|
351
|
+
title: 'Java Maven main source',
|
|
352
|
+
type: KnowledgeType.Path,
|
|
353
|
+
priority: KnowledgePriority.Critical,
|
|
354
|
+
tags: ['paths', 'java', 'maven'],
|
|
355
|
+
scope: ['java', 'maven'],
|
|
356
|
+
appliesWhen: ['generate-code'],
|
|
357
|
+
content: 'Main Java source lives under src/main/java/<package>/. Resources under src/main/resources/. Mirror tests under src/test/java/.',
|
|
358
|
+
metadata: { path: 'src/main/java' },
|
|
359
|
+
})`;
|
|
360
|
+
export const JAVA_MAVEN_PATH_TESTS = `defineKnowledgeEntry({
|
|
361
|
+
id: 'paths.java.maven.tests',
|
|
362
|
+
title: 'Java Maven tests',
|
|
363
|
+
type: KnowledgeType.Path,
|
|
364
|
+
priority: KnowledgePriority.High,
|
|
365
|
+
tags: ['paths', 'java', 'maven', 'tests'],
|
|
366
|
+
scope: ['java', 'maven'],
|
|
367
|
+
appliesWhen: ['generate-test'],
|
|
368
|
+
content: 'JUnit / Spring tests live under src/test/java/. Run via mvn test.',
|
|
369
|
+
metadata: { path: 'src/test/java' },
|
|
370
|
+
})`;
|
|
371
|
+
export const PYTHON_PATH_SRC = `defineKnowledgeEntry({
|
|
372
|
+
id: 'paths.python.src',
|
|
373
|
+
title: 'Python source root',
|
|
374
|
+
type: KnowledgeType.Path,
|
|
375
|
+
priority: KnowledgePriority.Critical,
|
|
376
|
+
tags: ['paths', 'python'],
|
|
377
|
+
scope: ['python'],
|
|
378
|
+
appliesWhen: ['generate-code'],
|
|
379
|
+
content: 'Source lives under src/<package>/ (PEP 517 src layout) or directly under <package>/ at the repo root. Pick one and stay consistent.',
|
|
380
|
+
metadata: { path: 'src' },
|
|
381
|
+
})`;
|
|
382
|
+
export const PYTHON_PATH_TESTS = `defineKnowledgeEntry({
|
|
383
|
+
id: 'paths.python.tests',
|
|
384
|
+
title: 'Python tests',
|
|
385
|
+
type: KnowledgeType.Path,
|
|
386
|
+
priority: KnowledgePriority.High,
|
|
387
|
+
tags: ['paths', 'python', 'tests'],
|
|
388
|
+
scope: ['python'],
|
|
389
|
+
appliesWhen: ['generate-test'],
|
|
390
|
+
content: 'Pytest tests live under tests/. Each test_*.py mirrors a module under src/.',
|
|
391
|
+
metadata: { path: 'tests' },
|
|
392
|
+
})`;
|
|
393
|
+
export const GO_PATH_CMD = `defineKnowledgeEntry({
|
|
394
|
+
id: 'paths.go.cmd',
|
|
395
|
+
title: 'Go entry points',
|
|
396
|
+
type: KnowledgeType.Path,
|
|
397
|
+
priority: KnowledgePriority.High,
|
|
398
|
+
tags: ['paths', 'go'],
|
|
399
|
+
scope: ['go'],
|
|
400
|
+
appliesWhen: ['create-app'],
|
|
401
|
+
content: 'Binary entry points live under cmd/<name>/main.go. Shared library code under pkg/ (public) or internal/ (module-private).',
|
|
402
|
+
metadata: { path: 'cmd' },
|
|
403
|
+
})`;
|
|
404
|
+
export const GO_PATH_PKG = `defineKnowledgeEntry({
|
|
405
|
+
id: 'paths.go.pkg',
|
|
406
|
+
title: 'Go shared packages',
|
|
407
|
+
type: KnowledgeType.Path,
|
|
408
|
+
priority: KnowledgePriority.Medium,
|
|
409
|
+
tags: ['paths', 'go'],
|
|
410
|
+
scope: ['go'],
|
|
411
|
+
appliesWhen: ['generate-code'],
|
|
412
|
+
content: 'Public packages live under pkg/<name>/. Tests are co-located as <name>_test.go. Run via go test ./...',
|
|
413
|
+
metadata: { path: 'pkg' },
|
|
414
|
+
})`;
|
|
415
|
+
export const GO_PATH_INTERNAL = `defineKnowledgeEntry({
|
|
416
|
+
id: 'paths.go.internal',
|
|
417
|
+
title: 'Go internal packages',
|
|
418
|
+
type: KnowledgeType.Path,
|
|
419
|
+
priority: KnowledgePriority.Medium,
|
|
420
|
+
tags: ['paths', 'go'],
|
|
421
|
+
scope: ['go'],
|
|
422
|
+
appliesWhen: ['generate-code'],
|
|
423
|
+
content: 'Module-private packages live under internal/<name>/. The Go compiler enforces that only the parent module can import these.',
|
|
424
|
+
metadata: { path: 'internal' },
|
|
425
|
+
})`;
|
|
426
|
+
export const RUST_PATH_SRC = `defineKnowledgeEntry({
|
|
427
|
+
id: 'paths.rust.src',
|
|
428
|
+
title: 'Rust crate source',
|
|
429
|
+
type: KnowledgeType.Path,
|
|
430
|
+
priority: KnowledgePriority.Critical,
|
|
431
|
+
tags: ['paths', 'rust'],
|
|
432
|
+
scope: ['rust'],
|
|
433
|
+
appliesWhen: ['generate-code'],
|
|
434
|
+
content: 'Crate source lives under src/. The entry point is src/lib.rs (library) or src/main.rs (binary). Modules nest as src/<mod>/mod.rs or src/<mod>.rs.',
|
|
435
|
+
metadata: { path: 'src' },
|
|
436
|
+
})`;
|
|
437
|
+
export const RUST_PATH_TESTS = `defineKnowledgeEntry({
|
|
438
|
+
id: 'paths.rust.tests',
|
|
439
|
+
title: 'Rust integration tests',
|
|
440
|
+
type: KnowledgeType.Path,
|
|
441
|
+
priority: KnowledgePriority.Medium,
|
|
442
|
+
tags: ['paths', 'rust', 'tests'],
|
|
443
|
+
scope: ['rust'],
|
|
444
|
+
appliesWhen: ['generate-test'],
|
|
445
|
+
content: 'Integration tests live under tests/<name>.rs. Unit tests live inline with #[cfg(test)] modules inside src/. Run via cargo test.',
|
|
446
|
+
metadata: { path: 'tests' },
|
|
447
|
+
})`;
|
|
235
448
|
export const COMMON_RULE_INTERFACE_PREFIX = `defineKnowledgeEntry({
|
|
236
449
|
id: 'typescript.interfaces.i-prefix',
|
|
237
450
|
title: 'Prefix interfaces with I',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/presets",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
4
|
"description": "SharkCraft presets: reusable project setups (knowledge/rules/paths/templates/pipelines/docs) that can be applied to a target repo through the CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
46
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
47
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
45
|
+
"@shrkcrft/core": "^0.1.0-alpha.6",
|
|
46
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.6",
|
|
47
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.6"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|