@canonical/code-standards 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp.json +8 -0
- package/README.md +297 -0
- package/data/code.ttl +437 -0
- package/data/css.ttl +265 -0
- package/data/icons.ttl +359 -0
- package/data/packaging.ttl +464 -0
- package/data/react.ttl +752 -0
- package/data/rust.ttl +1806 -0
- package/data/storybook.ttl +403 -0
- package/data/styling.ttl +165 -0
- package/data/tsdoc.ttl +216 -0
- package/data/turtle.ttl +179 -0
- package/definitions/CodeStandard.ttl +80 -0
- package/docs/code.md +720 -0
- package/docs/css.md +275 -0
- package/docs/icons.md +367 -0
- package/docs/index.md +15 -0
- package/docs/react.md +766 -0
- package/docs/rust.md +1784 -0
- package/docs/storybook.md +413 -0
- package/docs/styling.md +163 -0
- package/docs/tsdoc.md +213 -0
- package/docs/turtle.md +179 -0
- package/package.json +9 -0
- package/skills/add-standard/SKILL.md +288 -0
- package/src/scripts/generate-docs.ts +131 -0
- package/src/scripts/index.ts +19 -0
package/docs/tsdoc.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# TSDoc Standards
|
|
2
|
+
|
|
3
|
+
Standards for tsdoc development.
|
|
4
|
+
|
|
5
|
+
## tsdoc/documentation-layers
|
|
6
|
+
|
|
7
|
+
File-level and export-level TSDoc serve fundamentally different purposes. Export-level documentation describes *what the symbol does* — its API contract, parameters, return semantics, and side effects. File-level documentation describes *why this module exists* — its architectural role, the design invariants it upholds, and how its exports relate to each other. In single-export files the file exists solely to house that export, so file-level documentation is redundant; document only the exported symbol. In multi-export files, a file-level block is warranted when it explains the cohesion principle that binds the exports together — the reason they live in one file rather than separate ones.
|
|
8
|
+
|
|
9
|
+
### Do
|
|
10
|
+
|
|
11
|
+
(Do) In single-export files, document only at the export level — the API contract belongs on the symbol.
|
|
12
|
+
```typescript
|
|
13
|
+
// resolveDefinition.ts — single export, no file-level block needed
|
|
14
|
+
/** Resolve definition locations for a CSS custom property. */
|
|
15
|
+
export default function resolveDefinition(cssVar: string, graph: TokenGraph) {
|
|
16
|
+
// ...
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
(Do) In multi-export files, use a file-level block to explain the module's architectural purpose — why these exports are grouped.
|
|
21
|
+
```typescript
|
|
22
|
+
// types.ts — multiple exports, file-level explains cohesion
|
|
23
|
+
/**
|
|
24
|
+
* Shared types for diagnostic rule modules.
|
|
25
|
+
*
|
|
26
|
+
* Each diagnostic check receives one of these context objects,
|
|
27
|
+
* ensuring a uniform interface across per-usage and file-level rules.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export interface UsageRuleContext { /* ... */ }
|
|
31
|
+
export interface FileRuleContext { /* ... */ }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
(Do) Use export-level TSDoc to describe the API contract: what the symbol does, its parameters, return value, and any side effects.
|
|
35
|
+
```typescript
|
|
36
|
+
/**
|
|
37
|
+
* Check: css/missing-fallback — var() without a fallback on an unregistered property.
|
|
38
|
+
*
|
|
39
|
+
* Pushes a diagnostic when a var() usage has no fallback and the property
|
|
40
|
+
* is not registered via @property.
|
|
41
|
+
*/
|
|
42
|
+
export default function checkMissingFallback(ctx: UsageRuleContext, results: Diagnostic[]) {
|
|
43
|
+
// ...
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Don't
|
|
48
|
+
|
|
49
|
+
(Don't) Add a file-level block in a single-export file that restates what the export-level doc already says.
|
|
50
|
+
```typescript
|
|
51
|
+
// Bad: file-level repeats the export's own description
|
|
52
|
+
/** Resolve definitions for CSS custom property usages. */
|
|
53
|
+
|
|
54
|
+
/** Resolve definitions for CSS custom property usages. */
|
|
55
|
+
export default function resolveDefinition() { /* ... */ }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
(Don't) Use file-level docs to describe *what* an export does — that belongs on the export itself.
|
|
59
|
+
```typescript
|
|
60
|
+
// Bad: file-level describes the function instead of the module's role
|
|
61
|
+
/** Build a completion item for a CSS variable. */
|
|
62
|
+
|
|
63
|
+
export default function buildCompletionItem(name: string) { /* ... */ }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
(Don't) Omit file-level docs on multi-export modules where the grouping rationale is non-obvious.
|
|
67
|
+
```typescript
|
|
68
|
+
// Bad: reader cannot tell why these live together
|
|
69
|
+
export function isCompletionRequest(req: WorkerRequest) { /* ... */ }
|
|
70
|
+
export function isHoverRequest(req: WorkerRequest) { /* ... */ }
|
|
71
|
+
export function isDiagnosticsRequest(req: WorkerRequest) { /* ... */ }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## tsdoc/module-tag-location
|
|
77
|
+
|
|
78
|
+
The `@module` TSDoc tag must appear only on barrel files such as `index.ts`. Ordinary source files must document their exported API directly and must not use file-level `@module` tags.
|
|
79
|
+
|
|
80
|
+
### Do
|
|
81
|
+
|
|
82
|
+
(Do) Use `@module` on a barrel file that defines a package or folder-level API.
|
|
83
|
+
```typescript
|
|
84
|
+
/**
|
|
85
|
+
* Public protocol API.
|
|
86
|
+
* @module protocol
|
|
87
|
+
*/
|
|
88
|
+
export { createRequest, matchResponse } from './index.js';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
(Do) Document an ordinary source file at the exported symbol instead of using `@module`.
|
|
92
|
+
```typescript
|
|
93
|
+
/** Build a completion item for a CSS variable. */
|
|
94
|
+
export default function buildCompletionItem(name: string) {
|
|
95
|
+
// ...
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Don't
|
|
100
|
+
|
|
101
|
+
(Don't) Add `@module` to a single-purpose implementation file.
|
|
102
|
+
```typescript
|
|
103
|
+
/**
|
|
104
|
+
* Build a completion item.
|
|
105
|
+
* @module providers/completions/buildCompletionItem
|
|
106
|
+
*/
|
|
107
|
+
export default function buildCompletionItem(name: string) {
|
|
108
|
+
// ...
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
(Don't) Use file-level `@module` tags as a substitute for export documentation.
|
|
113
|
+
```typescript
|
|
114
|
+
/** @module helpers/formatCurrency */
|
|
115
|
+
export default function formatCurrency(value: number) {
|
|
116
|
+
return `$${value}`;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## tsdoc/self-contained
|
|
123
|
+
|
|
124
|
+
TSDoc comments must be self-contained — a reader should fully understand the documented symbol from its comment alone. External links (public specs, RFCs, GitHub issues) are allowed as supplementary references, but the comment itself must never depend on them for comprehension. If an external concept drives the implementation, distill the essential information into the comment.
|
|
125
|
+
|
|
126
|
+
### Do
|
|
127
|
+
|
|
128
|
+
(Do) Explain the concept inline so the reader needs nothing else:
|
|
129
|
+
```typescript
|
|
130
|
+
/**
|
|
131
|
+
* Encode a string as a percent-encoded URI component.
|
|
132
|
+
*
|
|
133
|
+
* Replaces every character that is not an unreserved character
|
|
134
|
+
* (A-Z, a-z, 0-9, `-`, `.`, `_`, `~`) with its UTF-8 percent-encoded form.
|
|
135
|
+
*/
|
|
136
|
+
export function encodeComponent(value: string): string {
|
|
137
|
+
// ...
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
(Do) Add an external link as a supplementary reference after a self-sufficient explanation:
|
|
142
|
+
```typescript
|
|
143
|
+
/**
|
|
144
|
+
* Compare two semantic version strings.
|
|
145
|
+
*
|
|
146
|
+
* Compares major, minor, and patch numerically in that order.
|
|
147
|
+
* Returns a negative number if `a < b`, zero if equal, or a positive number if `a > b`.
|
|
148
|
+
* Pre-release versions (e.g. `1.0.0-alpha`) sort before their release counterpart.
|
|
149
|
+
*
|
|
150
|
+
* @see https://semver.org
|
|
151
|
+
*/
|
|
152
|
+
export function compareVersions(a: string, b: string): number {
|
|
153
|
+
// ...
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
(Do) Reference a GitHub issue for additional context when the comment already explains the behaviour:
|
|
158
|
+
```typescript
|
|
159
|
+
/**
|
|
160
|
+
* Truncate session tokens to 64 characters before storage.
|
|
161
|
+
*
|
|
162
|
+
* Tokens longer than 64 characters exceed the column width in the
|
|
163
|
+
* sessions table and would be silently truncated by the database,
|
|
164
|
+
* so we enforce the limit explicitly.
|
|
165
|
+
*
|
|
166
|
+
* @see https://github.com/acme/backend/issues/412
|
|
167
|
+
*/
|
|
168
|
+
export function truncateToken(token: string): string {
|
|
169
|
+
// ...
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Don't
|
|
174
|
+
|
|
175
|
+
(Don't) Point the reader to an external resource instead of explaining the behaviour:
|
|
176
|
+
```typescript
|
|
177
|
+
/**
|
|
178
|
+
* Encode a URI component.
|
|
179
|
+
*
|
|
180
|
+
* Implements RFC 3986 §2.1.
|
|
181
|
+
* @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.1
|
|
182
|
+
*/
|
|
183
|
+
export function encodeComponent(value: string): string {
|
|
184
|
+
// ...
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
(Don't) Reference a wiki or internal doc as a substitute for inline explanation:
|
|
189
|
+
```typescript
|
|
190
|
+
/**
|
|
191
|
+
* Truncate session tokens before storage.
|
|
192
|
+
*
|
|
193
|
+
* See the security review document for rationale:
|
|
194
|
+
* https://wiki.internal/security/session-token-length
|
|
195
|
+
*/
|
|
196
|
+
export function truncateToken(token: string): string {
|
|
197
|
+
// ...
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
(Don't) Leave the reader unable to understand the symbol without following a link:
|
|
202
|
+
```typescript
|
|
203
|
+
/**
|
|
204
|
+
* Compare two semantic version strings.
|
|
205
|
+
*
|
|
206
|
+
* @see https://semver.org for the full specification.
|
|
207
|
+
*/
|
|
208
|
+
export function compareVersions(a: string, b: string): number {
|
|
209
|
+
// ...
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
package/docs/turtle.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Turtle Standards
|
|
2
|
+
|
|
3
|
+
Standards for turtle development.
|
|
4
|
+
|
|
5
|
+
## turtle/naming/local-name-casing
|
|
6
|
+
|
|
7
|
+
Within a unified prefix namespace, differentiate between schema elements and instances using casing conventions for the local name (the part after the prefix colon):
|
|
8
|
+
|
|
9
|
+
- **PascalCase** for classes (e.g., `ds:Component`, `ds:UIElement`)
|
|
10
|
+
- **camelCase** for properties (e.g., `ds:name`, `ds:hasProperty`)
|
|
11
|
+
- **lowercase** (often with dots or hyphens) for instances (e.g., `ds:global.component.button`)
|
|
12
|
+
|
|
13
|
+
This convention allows a single prefix to serve both definitions and data, with the casing clearly indicating the type of resource.
|
|
14
|
+
|
|
15
|
+
### Do
|
|
16
|
+
|
|
17
|
+
(Do) Use PascalCase for class names.
|
|
18
|
+
```turtle
|
|
19
|
+
ds:Component a owl:Class .
|
|
20
|
+
ds:UIBlock a owl:Class .
|
|
21
|
+
ds:ModifierFamily a owl:Class .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
(Do) Use camelCase for property names.
|
|
25
|
+
```turtle
|
|
26
|
+
ds:name a owl:DatatypeProperty .
|
|
27
|
+
ds:hasProperty a owl:ObjectProperty .
|
|
28
|
+
ds:parentComponent a owl:ObjectProperty .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
(Do) Use lowercase (with dots or hyphens as separators) for instance identifiers.
|
|
32
|
+
```turtle
|
|
33
|
+
ds:global.component.button a ds:Component .
|
|
34
|
+
ds:global.modifier_family.importance a ds:ModifierFamily .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Don't
|
|
38
|
+
|
|
39
|
+
(Don't) Use lowercase for class names.
|
|
40
|
+
```turtle
|
|
41
|
+
# Bad: Class names should be PascalCase
|
|
42
|
+
ds:component a owl:Class .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
(Don't) Use PascalCase for instance identifiers.
|
|
46
|
+
```turtle
|
|
47
|
+
# Bad: Instance names should be lowercase
|
|
48
|
+
ds:GlobalComponentButton a ds:Component .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
(Don't) Use PascalCase or uppercase for property names.
|
|
52
|
+
```turtle
|
|
53
|
+
# Bad: Property names should be camelCase
|
|
54
|
+
ds:HasProperty a owl:ObjectProperty .
|
|
55
|
+
ds:NAME a owl:DatatypeProperty .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## turtle/naming/unified-prefix
|
|
61
|
+
|
|
62
|
+
When a package uses a single namespace for both ontology and data, use a unified prefix with casing to distinguish between classes, properties, and instances. This simplifies prefix management and makes the relationship between schema and data more apparent.
|
|
63
|
+
|
|
64
|
+
The namespace URI should be a base URI without a fragment or trailing path segment for ontology vs data (e.g., `https://ds.canonical.com/` rather than separate `https://ds.canonical.com/ontology#` and `https://ds.canonical.com/data/`).
|
|
65
|
+
|
|
66
|
+
### Do
|
|
67
|
+
|
|
68
|
+
(Do) Use a single prefix for both definitions and data.
|
|
69
|
+
```turtle
|
|
70
|
+
# In both definitions/ and data/ files:
|
|
71
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
72
|
+
|
|
73
|
+
# Definitions use PascalCase/camelCase
|
|
74
|
+
ds:Component a owl:Class .
|
|
75
|
+
ds:name a owl:DatatypeProperty .
|
|
76
|
+
|
|
77
|
+
# Data uses lowercase
|
|
78
|
+
ds:global.component.button a ds:Component ;
|
|
79
|
+
ds:name "Button" .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Don't
|
|
83
|
+
|
|
84
|
+
(Don't) Use separate prefixes for ontology and data when a unified prefix is preferred.
|
|
85
|
+
```turtle
|
|
86
|
+
# Bad: Unnecessarily complex when unified prefix suffices
|
|
87
|
+
@prefix dso: <https://ds.canonical.com/ontology#> .
|
|
88
|
+
@prefix ds: <https://ds.canonical.com/data/> .
|
|
89
|
+
|
|
90
|
+
ds:global.component.button a dso:Component .
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## turtle/structure/definitions-vs-data
|
|
96
|
+
|
|
97
|
+
Turtle files must be organized into two directories based on their content:
|
|
98
|
+
|
|
99
|
+
- `definitions/` contains schema files (ontologies) with classes, properties, and datatypes
|
|
100
|
+
- `data/` contains instance files with actual data conforming to the schema
|
|
101
|
+
|
|
102
|
+
This separation allows tools to distinguish between schema and instance data, enables different validation rules, and makes the codebase easier to navigate.
|
|
103
|
+
|
|
104
|
+
### Do
|
|
105
|
+
|
|
106
|
+
(Do) Place ontology definitions (classes, properties, datatypes) in the `definitions/` directory.
|
|
107
|
+
```turtle
|
|
108
|
+
# definitions/ontology.ttl
|
|
109
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
110
|
+
|
|
111
|
+
ds:Component a owl:Class ;
|
|
112
|
+
rdfs:label "Component" .
|
|
113
|
+
|
|
114
|
+
ds:name a owl:DatatypeProperty ;
|
|
115
|
+
rdfs:domain ds:UIElement ;
|
|
116
|
+
rdfs:range xsd:string .
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
(Do) Place instance data in the `data/` directory.
|
|
120
|
+
```turtle
|
|
121
|
+
# data/global/component/button.ttl
|
|
122
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
123
|
+
|
|
124
|
+
ds:global.component.button a ds:Component ;
|
|
125
|
+
ds:name "Button" .
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Don't
|
|
129
|
+
|
|
130
|
+
(Don't) Mix class definitions and instance data in the same file.
|
|
131
|
+
```turtle
|
|
132
|
+
# Bad: Mixing schema and data
|
|
133
|
+
ds:Component a owl:Class .
|
|
134
|
+
ds:global.component.button a ds:Component .
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
(Don't) Place instance data in the `definitions/` directory.
|
|
138
|
+
```
|
|
139
|
+
# Bad: Data file in definitions
|
|
140
|
+
definitions/
|
|
141
|
+
└── button.ttl # Contains instance data
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## turtle/syntax/prefix-declaration
|
|
147
|
+
|
|
148
|
+
Every Turtle file must declare all prefixes used within the file at the top of the file. Each prefix should be declared exactly once. Standard prefixes (rdf, rdfs, owl, xsd, skos) should be declared when used but are commonly understood.
|
|
149
|
+
|
|
150
|
+
### Do
|
|
151
|
+
|
|
152
|
+
(Do) Declare all prefixes at the top of the file.
|
|
153
|
+
```turtle
|
|
154
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
155
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
156
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
157
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
158
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
159
|
+
|
|
160
|
+
ds:Component a owl:Class ;
|
|
161
|
+
rdfs:label "Component" .
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Don't
|
|
165
|
+
|
|
166
|
+
(Don't) Declare the same prefix multiple times.
|
|
167
|
+
```turtle
|
|
168
|
+
# Bad: Duplicate prefix declaration
|
|
169
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
170
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
(Don't) Use prefixes without declaring them.
|
|
174
|
+
```turtle
|
|
175
|
+
# Bad: Missing prefix declaration for ds:
|
|
176
|
+
ds:Component a owl:Class .
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
package/package.json
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Add Standard
|
|
2
|
+
|
|
3
|
+
Create and add a new code standard to the code-standards package.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when:
|
|
8
|
+
- "Add a standard for..."
|
|
9
|
+
- "Create a coding standard..."
|
|
10
|
+
- "Document a new convention..."
|
|
11
|
+
- "Add guidance for..."
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
### 1. Check for Existing Standards
|
|
16
|
+
|
|
17
|
+
Before creating a new standard, always check if one already exists:
|
|
18
|
+
|
|
19
|
+
```sparql
|
|
20
|
+
PREFIX cs: <http://pragma.canonical.com/codestandards#>
|
|
21
|
+
|
|
22
|
+
SELECT ?standard ?name ?description WHERE {
|
|
23
|
+
?standard a cs:CodeStandard ;
|
|
24
|
+
cs:name ?name ;
|
|
25
|
+
cs:description ?description .
|
|
26
|
+
FILTER(CONTAINS(LCASE(?name), "your-topic"))
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or use lookup:
|
|
31
|
+
```
|
|
32
|
+
sem_lookup(type: "cs:CodeStandard", filters: {"cs:name": {"$contains": "your-topic"}})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Determine the Category
|
|
36
|
+
|
|
37
|
+
List existing categories to find the right fit:
|
|
38
|
+
|
|
39
|
+
```sparql
|
|
40
|
+
PREFIX cs: <http://pragma.canonical.com/codestandards#>
|
|
41
|
+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
42
|
+
|
|
43
|
+
SELECT ?category ?label ?slug WHERE {
|
|
44
|
+
?category a cs:Category ;
|
|
45
|
+
rdfs:label ?label ;
|
|
46
|
+
cs:slug ?slug .
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Available Categories:**
|
|
51
|
+
|
|
52
|
+
| Category | Slug | Description |
|
|
53
|
+
|----------|------|-------------|
|
|
54
|
+
| React | `react` | React component development |
|
|
55
|
+
| CSS | `css` | CSS technical implementation |
|
|
56
|
+
| Styling | `styling` | Design system styling patterns |
|
|
57
|
+
| Code | `code` | General TypeScript standards |
|
|
58
|
+
| Storybook | `storybook` | Storybook documentation |
|
|
59
|
+
| Icons | `icons` | Icon implementation |
|
|
60
|
+
|
|
61
|
+
If no existing category fits, create a new one (see Section 5).
|
|
62
|
+
|
|
63
|
+
### 3. Design the Standard Name
|
|
64
|
+
|
|
65
|
+
Standard names follow a hierarchical pattern: `{category}/{domain}/{topic}`
|
|
66
|
+
|
|
67
|
+
**Pattern:** `^[a-z]+(/[a-z0-9-]+){2,}$`
|
|
68
|
+
|
|
69
|
+
**Examples:**
|
|
70
|
+
- `react/component/structure/folder`
|
|
71
|
+
- `css/selectors/namespace`
|
|
72
|
+
- `styling/tokens/creation`
|
|
73
|
+
- `react/hooks/naming`
|
|
74
|
+
|
|
75
|
+
**Guidelines:**
|
|
76
|
+
- Use lowercase with hyphens for multi-word segments
|
|
77
|
+
- Minimum 3 segments (category/domain/topic)
|
|
78
|
+
- Be specific but not overly verbose
|
|
79
|
+
- Follow existing naming patterns in the same category
|
|
80
|
+
|
|
81
|
+
### 4. Write the Standard
|
|
82
|
+
|
|
83
|
+
Create a new standard instance in the appropriate data file under `data/`.
|
|
84
|
+
|
|
85
|
+
**Template:**
|
|
86
|
+
|
|
87
|
+
```turtle
|
|
88
|
+
cs:YourStandardName a cs:CodeStandard ;
|
|
89
|
+
cs:name "category/domain/topic" ;
|
|
90
|
+
cs:hasCategory cs:CategoryName ;
|
|
91
|
+
cs:description "Clear, concise description of what this standard covers and why it matters." ;
|
|
92
|
+
cs:dos """
|
|
93
|
+
(Do) First recommended practice with example.
|
|
94
|
+
```code
|
|
95
|
+
// Example showing the correct approach
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
(Do) Second recommended practice.
|
|
99
|
+
```code
|
|
100
|
+
// Another example
|
|
101
|
+
```
|
|
102
|
+
""" ;
|
|
103
|
+
cs:donts """
|
|
104
|
+
(Don't) First anti-pattern to avoid.
|
|
105
|
+
```code
|
|
106
|
+
// Example showing what NOT to do
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
(Don't) Second anti-pattern.
|
|
110
|
+
```code
|
|
111
|
+
// Another bad example
|
|
112
|
+
```
|
|
113
|
+
""" .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Required Properties:**
|
|
117
|
+
- `cs:name` - Hierarchical identifier (must match NamePattern)
|
|
118
|
+
- `cs:hasCategory` - Reference to a Category instance
|
|
119
|
+
- `cs:description` - What and why (plain text or markdown)
|
|
120
|
+
- `cs:dos` - What TO do with examples
|
|
121
|
+
- `cs:donts` - What NOT to do with examples
|
|
122
|
+
|
|
123
|
+
**Optional Properties:**
|
|
124
|
+
- `cs:extends` - Reference to a parent standard this builds upon
|
|
125
|
+
|
|
126
|
+
### 5. Create a New Category (if needed)
|
|
127
|
+
|
|
128
|
+
If your standard doesn't fit existing categories:
|
|
129
|
+
|
|
130
|
+
```turtle
|
|
131
|
+
cs:NewCategory a cs:Category ;
|
|
132
|
+
rdfs:label "Category Name"@en ;
|
|
133
|
+
rdfs:comment "Description of what this category covers"@en ;
|
|
134
|
+
cs:slug "slug-name" .
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 6. Extending Existing Standards
|
|
138
|
+
|
|
139
|
+
When your standard builds on another:
|
|
140
|
+
|
|
141
|
+
```turtle
|
|
142
|
+
cs:SpecificStandard a cs:CodeStandard ;
|
|
143
|
+
cs:name "react/component/props/special-case" ;
|
|
144
|
+
cs:extends cs:ComponentProps ; # Reference to parent
|
|
145
|
+
cs:hasCategory cs:ReactCategory ;
|
|
146
|
+
cs:description "Specific guidance that builds on the general props standard." ;
|
|
147
|
+
# ... dos and donts ...
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Query to find potential parent standards:
|
|
151
|
+
```sparql
|
|
152
|
+
PREFIX cs: <http://pragma.canonical.com/codestandards#>
|
|
153
|
+
|
|
154
|
+
SELECT ?standard ?name WHERE {
|
|
155
|
+
?standard a cs:CodeStandard ;
|
|
156
|
+
cs:name ?name .
|
|
157
|
+
FILTER(STRSTARTS(?name, "react/component/props"))
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 7. Validate Before Committing
|
|
162
|
+
|
|
163
|
+
After writing the standard, validate the Turtle syntax:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
sem check code-standards
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Then verify the standard loads correctly:
|
|
170
|
+
```
|
|
171
|
+
sem_lookup(type: "cs:CodeStandard", filters: {"cs:name": "your/new/standard"})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## File Organization
|
|
175
|
+
|
|
176
|
+
Standards are organized by category in `data/`:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
code-standards/
|
|
180
|
+
├── definitions/
|
|
181
|
+
│ └── CodeStandard.ttl # Ontology schema
|
|
182
|
+
├── data/
|
|
183
|
+
│ ├── react.ttl # React standards
|
|
184
|
+
│ ├── css.ttl # CSS standards
|
|
185
|
+
│ ├── styling.ttl # Styling standards
|
|
186
|
+
│ ├── code.ttl # General code standards
|
|
187
|
+
│ ├── storybook.ttl # Storybook standards
|
|
188
|
+
│ └── icons.ttl # Icon standards
|
|
189
|
+
└── skills/
|
|
190
|
+
└── standards-guide/
|
|
191
|
+
└── SKILL.md
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Add new standards to the file matching their category.
|
|
195
|
+
|
|
196
|
+
## Writing Quality Standards
|
|
197
|
+
|
|
198
|
+
### Description Guidelines
|
|
199
|
+
- Start with WHAT the standard covers
|
|
200
|
+
- Explain WHY it matters
|
|
201
|
+
- Keep it concise but complete
|
|
202
|
+
- Use markdown for complex descriptions
|
|
203
|
+
|
|
204
|
+
### Do's Guidelines
|
|
205
|
+
- Start each item with `(Do)`
|
|
206
|
+
- Provide concrete, runnable examples
|
|
207
|
+
- Show the COMPLETE correct pattern
|
|
208
|
+
- Explain the reasoning when not obvious
|
|
209
|
+
|
|
210
|
+
### Don'ts Guidelines
|
|
211
|
+
- Start each item with `(Don't)`
|
|
212
|
+
- Show realistic mistakes developers make
|
|
213
|
+
- Explain WHY it's problematic
|
|
214
|
+
- Mirror the structure of the do's section
|
|
215
|
+
|
|
216
|
+
### Example Quality Checklist
|
|
217
|
+
- [ ] Examples are syntactically correct
|
|
218
|
+
- [ ] Examples are self-contained (can be understood without context)
|
|
219
|
+
- [ ] Examples use realistic code, not `foo`/`bar`
|
|
220
|
+
- [ ] Examples include comments explaining key points
|
|
221
|
+
- [ ] Both do's and don'ts cover the same scenarios
|
|
222
|
+
|
|
223
|
+
## Complete Example
|
|
224
|
+
|
|
225
|
+
Adding a new standard for React error boundaries:
|
|
226
|
+
|
|
227
|
+
```turtle
|
|
228
|
+
# In data/react.ttl
|
|
229
|
+
|
|
230
|
+
cs:ErrorBoundaryUsage a cs:CodeStandard ;
|
|
231
|
+
cs:name "react/component/error-boundaries" ;
|
|
232
|
+
cs:hasCategory cs:ReactCategory ;
|
|
233
|
+
cs:description "Error boundaries must be used to catch JavaScript errors in component trees and display fallback UI. They should be placed strategically to isolate failures without breaking the entire application." ;
|
|
234
|
+
cs:dos """
|
|
235
|
+
(Do) Wrap feature sections with error boundaries to isolate failures.
|
|
236
|
+
```tsx
|
|
237
|
+
const Dashboard = () => (
|
|
238
|
+
<div className="ds dashboard">
|
|
239
|
+
<ErrorBoundary fallback={<WidgetError />}>
|
|
240
|
+
<AnalyticsWidget />
|
|
241
|
+
</ErrorBoundary>
|
|
242
|
+
<ErrorBoundary fallback={<WidgetError />}>
|
|
243
|
+
<ActivityWidget />
|
|
244
|
+
</ErrorBoundary>
|
|
245
|
+
</div>
|
|
246
|
+
);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
(Do) Provide meaningful fallback UI that helps users understand and recover.
|
|
250
|
+
```tsx
|
|
251
|
+
const WidgetError = () => (
|
|
252
|
+
<div className="ds widget-error">
|
|
253
|
+
<p>This section couldn't load.</p>
|
|
254
|
+
<button onClick={() => window.location.reload()}>
|
|
255
|
+
Refresh page
|
|
256
|
+
</button>
|
|
257
|
+
</div>
|
|
258
|
+
);
|
|
259
|
+
```
|
|
260
|
+
""" ;
|
|
261
|
+
cs:donts """
|
|
262
|
+
(Don't) Wrap the entire application in a single error boundary.
|
|
263
|
+
```tsx
|
|
264
|
+
// Bad: One error anywhere crashes everything
|
|
265
|
+
const App = () => (
|
|
266
|
+
<ErrorBoundary>
|
|
267
|
+
<Header />
|
|
268
|
+
<Main />
|
|
269
|
+
<Footer />
|
|
270
|
+
</ErrorBoundary>
|
|
271
|
+
);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
(Don't) Use generic or unhelpful fallback messages.
|
|
275
|
+
```tsx
|
|
276
|
+
// Bad: Doesn't help the user
|
|
277
|
+
const fallback = <div>Something went wrong</div>;
|
|
278
|
+
```
|
|
279
|
+
""" .
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Tips
|
|
283
|
+
|
|
284
|
+
1. **Check before creating**: Always search for existing standards first - you might need to extend rather than create new
|
|
285
|
+
2. **Follow patterns**: Look at existing standards in the same category for style guidance
|
|
286
|
+
3. **Be specific**: Vague standards are hard to follow - include concrete examples
|
|
287
|
+
4. **Test your examples**: Make sure code examples actually work
|
|
288
|
+
5. **Consider hierarchy**: Use `cs:extends` when your standard builds on another
|