@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/data/tsdoc.ttl ADDED
@@ -0,0 +1,216 @@
1
+ @prefix cso: <http://pragma.canonical.com/codestandards#> .
2
+ @prefix cs: <http://pragma.canonical.com/codestandards/instances#> .
3
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
5
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
6
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
7
+
8
+ # TSDoc Category
9
+ cs:TSDocCategory a cso:Category ;
10
+ rdfs:label "TSDoc"@en ;
11
+ rdfs:comment "Standards for TypeScript documentation comments — placement, layering, and tag usage."@en ;
12
+ cso:slug "tsdoc" .
13
+
14
+ # Module Tag Location
15
+ cs:TSDocModuleTagLocation a cso:CodeStandard ;
16
+ cso:name "tsdoc/module-tag-location" ;
17
+ cso:hasCategory cs:TSDocCategory ;
18
+ cso:description "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." ;
19
+ cso:dos """
20
+ (Do) Use `@module` on a barrel file that defines a package or folder-level API.
21
+ ```typescript
22
+ /**
23
+ * Public protocol API.
24
+ * @module protocol
25
+ */
26
+ export { createRequest, matchResponse } from './index.js';
27
+ ```
28
+
29
+ (Do) Document an ordinary source file at the exported symbol instead of using `@module`.
30
+ ```typescript
31
+ /** Build a completion item for a CSS variable. */
32
+ export default function buildCompletionItem(name: string) {
33
+ // ...
34
+ }
35
+ ```
36
+ """ ;
37
+ cso:donts """
38
+ (Don't) Add `@module` to a single-purpose implementation file.
39
+ ```typescript
40
+ /**
41
+ * Build a completion item.
42
+ * @module providers/completions/buildCompletionItem
43
+ */
44
+ export default function buildCompletionItem(name: string) {
45
+ // ...
46
+ }
47
+ ```
48
+
49
+ (Don't) Use file-level `@module` tags as a substitute for export documentation.
50
+ ```typescript
51
+ /** @module helpers/formatCurrency */
52
+ export default function formatCurrency(value: number) {
53
+ return `$${value}`;
54
+ }
55
+ ```
56
+ """ .
57
+
58
+ # Documentation Layers
59
+ cs:TSDocDocumentationLayers a cso:CodeStandard ;
60
+ cso:name "tsdoc/documentation-layers" ;
61
+ cso:hasCategory cs:TSDocCategory ;
62
+ cso:description "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." ;
63
+ cso:dos """
64
+ (Do) In single-export files, document only at the export level — the API contract belongs on the symbol.
65
+ ```typescript
66
+ // resolveDefinition.ts — single export, no file-level block needed
67
+ /** Resolve definition locations for a CSS custom property. */
68
+ export default function resolveDefinition(cssVar: string, graph: TokenGraph) {
69
+ // ...
70
+ }
71
+ ```
72
+
73
+ (Do) In multi-export files, use a file-level block to explain the module's architectural purpose — why these exports are grouped.
74
+ ```typescript
75
+ // types.ts — multiple exports, file-level explains cohesion
76
+ /**
77
+ * Shared types for diagnostic rule modules.
78
+ *
79
+ * Each diagnostic check receives one of these context objects,
80
+ * ensuring a uniform interface across per-usage and file-level rules.
81
+ */
82
+
83
+ export interface UsageRuleContext { /* ... */ }
84
+ export interface FileRuleContext { /* ... */ }
85
+ ```
86
+
87
+ (Do) Use export-level TSDoc to describe the API contract: what the symbol does, its parameters, return value, and any side effects.
88
+ ```typescript
89
+ /**
90
+ * Check: css/missing-fallback — var() without a fallback on an unregistered property.
91
+ *
92
+ * Pushes a diagnostic when a var() usage has no fallback and the property
93
+ * is not registered via @property.
94
+ */
95
+ export default function checkMissingFallback(ctx: UsageRuleContext, results: Diagnostic[]) {
96
+ // ...
97
+ }
98
+ ```
99
+ """ ;
100
+ cso:donts """
101
+ (Don't) Add a file-level block in a single-export file that restates what the export-level doc already says.
102
+ ```typescript
103
+ // Bad: file-level repeats the export's own description
104
+ /** Resolve definitions for CSS custom property usages. */
105
+
106
+ /** Resolve definitions for CSS custom property usages. */
107
+ export default function resolveDefinition() { /* ... */ }
108
+ ```
109
+
110
+ (Don't) Use file-level docs to describe *what* an export does — that belongs on the export itself.
111
+ ```typescript
112
+ // Bad: file-level describes the function instead of the module's role
113
+ /** Build a completion item for a CSS variable. */
114
+
115
+ export default function buildCompletionItem(name: string) { /* ... */ }
116
+ ```
117
+
118
+ (Don't) Omit file-level docs on multi-export modules where the grouping rationale is non-obvious.
119
+ ```typescript
120
+ // Bad: reader cannot tell why these live together
121
+ export function isCompletionRequest(req: WorkerRequest) { /* ... */ }
122
+ export function isHoverRequest(req: WorkerRequest) { /* ... */ }
123
+ export function isDiagnosticsRequest(req: WorkerRequest) { /* ... */ }
124
+ ```
125
+ """ .
126
+
127
+ # Self-Contained Documentation
128
+ cs:TSDocSelfContained a cso:CodeStandard ;
129
+ cso:name "tsdoc/self-contained" ;
130
+ cso:hasCategory cs:TSDocCategory ;
131
+ cso:description "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." ;
132
+ cso:dos """
133
+ (Do) Explain the concept inline so the reader needs nothing else:
134
+ ```typescript
135
+ /**
136
+ * Encode a string as a percent-encoded URI component.
137
+ *
138
+ * Replaces every character that is not an unreserved character
139
+ * (A-Z, a-z, 0-9, `-`, `.`, `_`, `~`) with its UTF-8 percent-encoded form.
140
+ */
141
+ export function encodeComponent(value: string): string {
142
+ // ...
143
+ }
144
+ ```
145
+
146
+ (Do) Add an external link as a supplementary reference after a self-sufficient explanation:
147
+ ```typescript
148
+ /**
149
+ * Compare two semantic version strings.
150
+ *
151
+ * Compares major, minor, and patch numerically in that order.
152
+ * Returns a negative number if `a < b`, zero if equal, or a positive number if `a > b`.
153
+ * Pre-release versions (e.g. `1.0.0-alpha`) sort before their release counterpart.
154
+ *
155
+ * @see https://semver.org
156
+ */
157
+ export function compareVersions(a: string, b: string): number {
158
+ // ...
159
+ }
160
+ ```
161
+
162
+ (Do) Reference a GitHub issue for additional context when the comment already explains the behaviour:
163
+ ```typescript
164
+ /**
165
+ * Truncate session tokens to 64 characters before storage.
166
+ *
167
+ * Tokens longer than 64 characters exceed the column width in the
168
+ * sessions table and would be silently truncated by the database,
169
+ * so we enforce the limit explicitly.
170
+ *
171
+ * @see https://github.com/acme/backend/issues/412
172
+ */
173
+ export function truncateToken(token: string): string {
174
+ // ...
175
+ }
176
+ ```
177
+ """ ;
178
+ cso:donts """
179
+ (Don't) Point the reader to an external resource instead of explaining the behaviour:
180
+ ```typescript
181
+ /**
182
+ * Encode a URI component.
183
+ *
184
+ * Implements RFC 3986 §2.1.
185
+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.1
186
+ */
187
+ export function encodeComponent(value: string): string {
188
+ // ...
189
+ }
190
+ ```
191
+
192
+ (Don't) Reference a wiki or internal doc as a substitute for inline explanation:
193
+ ```typescript
194
+ /**
195
+ * Truncate session tokens before storage.
196
+ *
197
+ * See the security review document for rationale:
198
+ * https://wiki.internal/security/session-token-length
199
+ */
200
+ export function truncateToken(token: string): string {
201
+ // ...
202
+ }
203
+ ```
204
+
205
+ (Don't) Leave the reader unable to understand the symbol without following a link:
206
+ ```typescript
207
+ /**
208
+ * Compare two semantic version strings.
209
+ *
210
+ * @see https://semver.org for the full specification.
211
+ */
212
+ export function compareVersions(a: string, b: string): number {
213
+ // ...
214
+ }
215
+ ```
216
+ """ .
@@ -0,0 +1,179 @@
1
+ @prefix cs: <http://pragma.canonical.com/codestandards#> .
2
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
4
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
5
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
6
+
7
+ # Turtle Category
8
+ cs:TurtleCategory a cs:Category ;
9
+ rdfs:label "Turtle"@en ;
10
+ rdfs:comment "Standards specific to Turtle (RDF) file authoring"@en ;
11
+ cs:slug "turtle" .
12
+
13
+ # Definitions vs Data Files Standard
14
+ cs:DefinitionsVsData a cs:CodeStandard ;
15
+ cs:name "turtle/structure/definitions-vs-data" ;
16
+ cs:hasCategory cs:TurtleCategory ;
17
+ cs:description """Turtle files must be organized into two directories based on their content:
18
+
19
+ - `definitions/` contains schema files (ontologies) with classes, properties, and datatypes
20
+ - `data/` contains instance files with actual data conforming to the schema
21
+
22
+ This separation allows tools to distinguish between schema and instance data, enables different validation rules, and makes the codebase easier to navigate.""" ;
23
+ cs:dos """
24
+ (Do) Place ontology definitions (classes, properties, datatypes) in the `definitions/` directory.
25
+ ```turtle
26
+ # definitions/ontology.ttl
27
+ @prefix ds: <https://ds.canonical.com/> .
28
+
29
+ ds:Component a owl:Class ;
30
+ rdfs:label "Component" .
31
+
32
+ ds:name a owl:DatatypeProperty ;
33
+ rdfs:domain ds:UIElement ;
34
+ rdfs:range xsd:string .
35
+ ```
36
+
37
+ (Do) Place instance data in the `data/` directory.
38
+ ```turtle
39
+ # data/global/component/button.ttl
40
+ @prefix ds: <https://ds.canonical.com/> .
41
+
42
+ ds:global.component.button a ds:Component ;
43
+ ds:name "Button" .
44
+ ```
45
+ """ ;
46
+ cs:donts """
47
+ (Don't) Mix class definitions and instance data in the same file.
48
+ ```turtle
49
+ # Bad: Mixing schema and data
50
+ ds:Component a owl:Class .
51
+ ds:global.component.button a ds:Component .
52
+ ```
53
+
54
+ (Don't) Place instance data in the `definitions/` directory.
55
+ ```
56
+ # Bad: Data file in definitions
57
+ definitions/
58
+ └── button.ttl # Contains instance data
59
+ ```
60
+ """ .
61
+
62
+ # Local Name Casing Convention Standard
63
+ cs:LocalNameCasing a cs:CodeStandard ;
64
+ cs:name "turtle/naming/local-name-casing" ;
65
+ cs:hasCategory cs:TurtleCategory ;
66
+ cs:description """Within a unified prefix namespace, differentiate between schema elements and instances using casing conventions for the local name (the part after the prefix colon):
67
+
68
+ - **PascalCase** for classes (e.g., `ds:Component`, `ds:UIElement`)
69
+ - **camelCase** for properties (e.g., `ds:name`, `ds:hasProperty`)
70
+ - **lowercase** (often with dots or hyphens) for instances (e.g., `ds:global.component.button`)
71
+
72
+ This convention allows a single prefix to serve both definitions and data, with the casing clearly indicating the type of resource.""" ;
73
+ cs:dos """
74
+ (Do) Use PascalCase for class names.
75
+ ```turtle
76
+ ds:Component a owl:Class .
77
+ ds:UIBlock a owl:Class .
78
+ ds:ModifierFamily a owl:Class .
79
+ ```
80
+
81
+ (Do) Use camelCase for property names.
82
+ ```turtle
83
+ ds:name a owl:DatatypeProperty .
84
+ ds:hasProperty a owl:ObjectProperty .
85
+ ds:parentComponent a owl:ObjectProperty .
86
+ ```
87
+
88
+ (Do) Use lowercase (with dots or hyphens as separators) for instance identifiers.
89
+ ```turtle
90
+ ds:global.component.button a ds:Component .
91
+ ds:global.modifier_family.importance a ds:ModifierFamily .
92
+ ```
93
+ """ ;
94
+ cs:donts """
95
+ (Don't) Use lowercase for class names.
96
+ ```turtle
97
+ # Bad: Class names should be PascalCase
98
+ ds:component a owl:Class .
99
+ ```
100
+
101
+ (Don't) Use PascalCase for instance identifiers.
102
+ ```turtle
103
+ # Bad: Instance names should be lowercase
104
+ ds:GlobalComponentButton a ds:Component .
105
+ ```
106
+
107
+ (Don't) Use PascalCase or uppercase for property names.
108
+ ```turtle
109
+ # Bad: Property names should be camelCase
110
+ ds:HasProperty a owl:ObjectProperty .
111
+ ds:NAME a owl:DatatypeProperty .
112
+ ```
113
+ """ .
114
+
115
+ # Unified Prefix Standard
116
+ cs:UnifiedPrefix a cs:CodeStandard ;
117
+ cs:name "turtle/naming/unified-prefix" ;
118
+ cs:hasCategory cs:TurtleCategory ;
119
+ cs:description """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.
120
+
121
+ 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/`).""" ;
122
+ cs:dos """
123
+ (Do) Use a single prefix for both definitions and data.
124
+ ```turtle
125
+ # In both definitions/ and data/ files:
126
+ @prefix ds: <https://ds.canonical.com/> .
127
+
128
+ # Definitions use PascalCase/camelCase
129
+ ds:Component a owl:Class .
130
+ ds:name a owl:DatatypeProperty .
131
+
132
+ # Data uses lowercase
133
+ ds:global.component.button a ds:Component ;
134
+ ds:name "Button" .
135
+ ```
136
+ """ ;
137
+ cs:donts """
138
+ (Don't) Use separate prefixes for ontology and data when a unified prefix is preferred.
139
+ ```turtle
140
+ # Bad: Unnecessarily complex when unified prefix suffices
141
+ @prefix dso: <https://ds.canonical.com/ontology#> .
142
+ @prefix ds: <https://ds.canonical.com/data/> .
143
+
144
+ ds:global.component.button a dso:Component .
145
+ ```
146
+ """ .
147
+
148
+ # Prefix Declaration Standard
149
+ cs:PrefixDeclaration a cs:CodeStandard ;
150
+ cs:name "turtle/syntax/prefix-declaration" ;
151
+ cs:hasCategory cs:TurtleCategory ;
152
+ cs:description """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.""" ;
153
+ cs:dos """
154
+ (Do) Declare all prefixes at the top of the file.
155
+ ```turtle
156
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
157
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
158
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
159
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
160
+ @prefix ds: <https://ds.canonical.com/> .
161
+
162
+ ds:Component a owl:Class ;
163
+ rdfs:label "Component" .
164
+ ```
165
+ """ ;
166
+ cs:donts """
167
+ (Don't) Declare the same prefix multiple times.
168
+ ```turtle
169
+ # Bad: Duplicate prefix declaration
170
+ @prefix ds: <https://ds.canonical.com/> .
171
+ @prefix ds: <https://ds.canonical.com/> .
172
+ ```
173
+
174
+ (Don't) Use prefixes without declaring them.
175
+ ```turtle
176
+ # Bad: Missing prefix declaration for ds:
177
+ ds:Component a owl:Class .
178
+ ```
179
+ """ .
@@ -0,0 +1,80 @@
1
+ @prefix cs: <http://pragma.canonical.com/codestandards#> .
2
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
4
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
5
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
6
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
7
+
8
+ # Ontology Declaration
9
+ cs: a owl:Ontology ;
10
+ rdfs:label "Code Standards Ontology"@en ;
11
+ rdfs:comment "An ontology for describing software development code standards and best practices. This ontology provides a structured way to document coding standards including categories, descriptions, do's and don'ts."@en ;
12
+ owl:versionInfo "1.0.0" .
13
+
14
+ # Classes
15
+ cs:CodeStandard a owl:Class ;
16
+ rdfs:label "Code Standard"@en ;
17
+ rdfs:comment "A coding standard or best practice guideline for software development"@en .
18
+
19
+ cs:Category a owl:Class ;
20
+ rdfs:label "Category"@en ;
21
+ rdfs:comment "A category for grouping related code standards (e.g., testing, components, react, typescript)"@en ;
22
+ rdfs:subClassOf skos:Concept .
23
+
24
+ # Datatype properties
25
+ cs:slug a owl:DatatypeProperty ;
26
+ rdfs:label "slug"@en ;
27
+ rdfs:comment "A short identifier for the category or standard, used for domain annotation."@en ;
28
+ rdfs:domain cs:Category ;
29
+ rdfs:range xsd:string .
30
+
31
+ # Datatypes
32
+ cs:NamePattern a owl:Datatype ;
33
+ owl:onDatatype xsd:string ;
34
+ owl:withRestrictions (
35
+ [ xsd:pattern "^[a-z]+(/[a-z0-9-]+){2,}$" ]
36
+ ) .
37
+
38
+ # Object Properties
39
+ cs:hasCategory a owl:ObjectProperty ;
40
+ rdfs:label "has category"@en ;
41
+ rdfs:comment "Associates a code standard with its category"@en ;
42
+ rdfs:domain cs:CodeStandard ;
43
+ rdfs:range cs:Category .
44
+
45
+ cs:extends a owl:ObjectProperty ;
46
+ rdfs:label "extends"@en ;
47
+ rdfs:comment "Associates a code standard with another standard that it extends or adds further context to"@en ;
48
+ rdfs:domain cs:CodeStandard ;
49
+ rdfs:range cs:CodeStandard .
50
+
51
+
52
+ cs:name a owl:DatatypeProperty ;
53
+ rdfs:label "name"@en ;
54
+ rdfs:comment "The domain-based identifier name of the code standard (e.g., 'react/component/folder-structure')."@en ;
55
+ rdfs:domain cs:CodeStandard ;
56
+ rdfs:range cs:NamePattern .
57
+
58
+ cs:description a owl:DatatypeProperty ;
59
+ rdfs:label "description"@en ;
60
+ rdfs:comment "A general description of the code standard in markdown format"@en ;
61
+ rdfs:domain cs:CodeStandard ;
62
+ rdfs:range xsd:string .
63
+
64
+ cs:dos a owl:DatatypeProperty ;
65
+ rdfs:label "do's"@en ;
66
+ rdfs:comment "Examples of what should be done, in markdown format"@en ;
67
+ rdfs:domain cs:CodeStandard ;
68
+ rdfs:range xsd:string .
69
+
70
+ cs:donts a owl:DatatypeProperty ;
71
+ rdfs:label "don'ts"@en ;
72
+ rdfs:comment "Examples of what should not be done, in markdown format"@en ;
73
+ rdfs:domain cs:CodeStandard ;
74
+ rdfs:range xsd:string .
75
+
76
+ cs:slug a owl:DatatypeProperty ;
77
+ rdfs:label "slug"@en ;
78
+ rdfs:comment "A short identifier for the category or standard, used for domain annotation."@en ;
79
+ rdfs:domain cs:Category ;
80
+ rdfs:range xsd:string .