@hawkeyexl/manni 2.12.1 → 4.0.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/README.md +16 -12
- package/dist/{chunk-EM53FMKG.js → chunk-J3KIKNWZ.js} +25 -9
- package/dist/chunk-J3KIKNWZ.js.map +1 -0
- package/dist/{chunk-F6CE4LEJ.js → chunk-O7RMPQZ4.js} +5517 -1068
- package/dist/chunk-O7RMPQZ4.js.map +1 -0
- package/dist/chunk-YDUFTHBZ.js +13908 -0
- package/dist/chunk-YDUFTHBZ.js.map +1 -0
- package/dist/cli.js +348 -35
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +2 -2
- package/dist/index.d.ts +1943 -467
- package/dist/index.js +112 -3
- package/dist/index.js.map +1 -1
- package/package.json +18 -3
- package/schemas/lint/config.json +73 -0
- package/schemas/lint/template.json +346 -0
- package/templates/lint/tgdp/concept.yaml +77 -0
- package/templates/lint/tgdp/how-to.yaml +64 -0
- package/templates/lint/tgdp/manifest.json +57 -0
- package/templates/lint/tgdp/readme.yaml +163 -0
- package/templates/lint/tgdp/reference.yaml +67 -0
- package/templates/lint/tgdp/release-notes.yaml +108 -0
- package/templates/lint/tgdp/troubleshooting.yaml +98 -0
- package/templates/lint/tgdp/tutorial.yaml +74 -0
- package/dist/chunk-7X4QMQX4.js +0 -6621
- package/dist/chunk-7X4QMQX4.js.map +0 -1
- package/dist/chunk-EM53FMKG.js.map +0 -1
- package/dist/chunk-F6CE4LEJ.js.map +0 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "manni-lint:template:2",
|
|
4
|
+
"title": "manni lint template file",
|
|
5
|
+
"description": "A template file: named doctype templates, plus the reusable fragments they point at with `$ref`. Validated after dereferencing, so no `$ref` survives to be seen here. A template is itself a rule: it describes the page, and it takes every rule key plus `title`, `types` and `extends`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["templates"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"$schema": {
|
|
11
|
+
"description": "URL of this schema, so an editor can offer completion. Read by editors, never by the linter.",
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
"info": {
|
|
15
|
+
"description": "Free-form metadata about the file (title, version, author). Never read by the linter; declared so a file that carries it is not rejected.",
|
|
16
|
+
"type": "object"
|
|
17
|
+
},
|
|
18
|
+
"templates": {
|
|
19
|
+
"description": "The doctype templates this file defines, keyed by name.",
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"patternProperties": {
|
|
23
|
+
"^[A-Za-z][A-Za-z0-9-_]*$": { "$ref": "#/definitions/template" }
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"components": {
|
|
27
|
+
"description": "Reusable fragments, targeted by `$ref` from elsewhere in the file. Left unconstrained: a fragment is validated where it is inlined, not where it is declared.",
|
|
28
|
+
"type": "object"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"definitions": {
|
|
32
|
+
"min": {
|
|
33
|
+
"description": "Fewest occurrences. Absent means one. Deliberately carries no JSON Schema `default`, and neither does any other key in this file: Ajv's `useDefaults` would write one in at load time, and a written-in value is indistinguishable from a value the author typed, so it wins the `extends` merge against the parent's real value. The code reads `undefined` instead.",
|
|
34
|
+
"type": "integer",
|
|
35
|
+
"minimum": 0
|
|
36
|
+
},
|
|
37
|
+
"max": {
|
|
38
|
+
"description": "Most occurrences. Absent is unbounded, so write `max: 1` for exactly once and `max: 0` to forbid. Must be at least `min` where both are written; the loader checks that, because JSON Schema cannot compare two siblings.",
|
|
39
|
+
"type": "integer",
|
|
40
|
+
"minimum": 0
|
|
41
|
+
},
|
|
42
|
+
"id": {
|
|
43
|
+
"description": "Handle for this rule, unique among its siblings. It appears in messages, and `extends` targets it to replace one inherited rule in place.",
|
|
44
|
+
"type": "string",
|
|
45
|
+
"pattern": "^[A-Za-z][A-Za-z0-9-_]*$"
|
|
46
|
+
},
|
|
47
|
+
"description": {
|
|
48
|
+
"description": "Prose description of what the rule is for. Never checked.",
|
|
49
|
+
"type": "string"
|
|
50
|
+
},
|
|
51
|
+
"heading": {
|
|
52
|
+
"description": "The heading of the section this rule describes. Absent means any heading, or none. A string is exact text, a list is one-of, `{ pattern }` is an unanchored regular expression, and `false` means the section has no heading of its own.",
|
|
53
|
+
"oneOf": [
|
|
54
|
+
{ "type": "string", "minLength": 1 },
|
|
55
|
+
{
|
|
56
|
+
"type": "array",
|
|
57
|
+
"minItems": 1,
|
|
58
|
+
"items": { "type": "string", "minLength": 1 }
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "object",
|
|
62
|
+
"additionalProperties": false,
|
|
63
|
+
"required": ["pattern"],
|
|
64
|
+
"properties": {
|
|
65
|
+
"pattern": { "type": "string", "minLength": 1 }
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{ "const": false }
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"attributes": {
|
|
72
|
+
"description": "Literal attributes the node must carry. A string is the required value; `true` requires the attribute to be present, and `false` requires it to be absent.",
|
|
73
|
+
"type": "object",
|
|
74
|
+
"additionalProperties": {
|
|
75
|
+
"oneOf": [{ "type": "string" }, { "type": "boolean" }]
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"oneOfSequenceOrContains": {
|
|
79
|
+
"description": "A rule says what it holds in order (`sequence`) or in any order (`contains`), never both.",
|
|
80
|
+
"type": "object",
|
|
81
|
+
"not": { "required": ["sequence", "contains"] }
|
|
82
|
+
},
|
|
83
|
+
"noHeadingOnRepeat": {
|
|
84
|
+
"description": "`repeat` groups sibling rules into one repeated unit, so the group has no heading of its own. Put the heading on the first rule inside it.",
|
|
85
|
+
"type": "object",
|
|
86
|
+
"not": { "required": ["heading", "repeat"] }
|
|
87
|
+
},
|
|
88
|
+
"noInstructions": {
|
|
89
|
+
"description": "`instructions` was the language-model hook of doc-structure-lint. manni lint is deterministic and has no model, so a template carrying it is rejected outright rather than silently ignored; the loader turns this into a migration message pointing at manni docevals.",
|
|
90
|
+
"type": "object",
|
|
91
|
+
"not": { "required": ["instructions"] }
|
|
92
|
+
},
|
|
93
|
+
"template": {
|
|
94
|
+
"description": "One doctype template. A template is a rule describing the page itself, so it takes every rule key, plus `title`, `types` and `extends`.",
|
|
95
|
+
"type": "object",
|
|
96
|
+
"additionalProperties": false,
|
|
97
|
+
"allOf": [
|
|
98
|
+
{ "$ref": "#/definitions/noInstructions" },
|
|
99
|
+
{ "$ref": "#/definitions/oneOfSequenceOrContains" },
|
|
100
|
+
{ "$ref": "#/definitions/noHeadingOnRepeat" }
|
|
101
|
+
],
|
|
102
|
+
"properties": {
|
|
103
|
+
"title": {
|
|
104
|
+
"description": "Human-readable name for the template, shown by `manni lint templates`.",
|
|
105
|
+
"type": "string"
|
|
106
|
+
},
|
|
107
|
+
"types": {
|
|
108
|
+
"description": "Doctypes this template serves, matched against a page's `type` frontmatter.",
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": { "type": "string", "minLength": 1 }
|
|
111
|
+
},
|
|
112
|
+
"extends": {
|
|
113
|
+
"description": "Template reference (built-in id, path, or URL, optionally with a `#name` fragment) whose rules this template inherits.",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"minLength": 1
|
|
116
|
+
},
|
|
117
|
+
"id": { "$ref": "#/definitions/id" },
|
|
118
|
+
"description": { "$ref": "#/definitions/description" },
|
|
119
|
+
"heading": { "$ref": "#/definitions/heading" },
|
|
120
|
+
"repeat": { "$ref": "#/definitions/repeat" },
|
|
121
|
+
"min": {
|
|
122
|
+
"description": "Refused on a template: a page is one page. Declared here only so the loader can say that in a sentence, rather than leaving Ajv to report an unexpected key.",
|
|
123
|
+
"type": "integer",
|
|
124
|
+
"minimum": 0
|
|
125
|
+
},
|
|
126
|
+
"max": {
|
|
127
|
+
"description": "Refused on a template, for the same reason as `min`.",
|
|
128
|
+
"type": "integer",
|
|
129
|
+
"minimum": 0
|
|
130
|
+
},
|
|
131
|
+
"sequence": { "$ref": "#/definitions/sequence" },
|
|
132
|
+
"contains": { "$ref": "#/definitions/blockRules" },
|
|
133
|
+
"sections": { "$ref": "#/definitions/rules" }
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"rule": {
|
|
137
|
+
"description": "One rule. It describes a section of the page, or, with `repeat`, a run of sections matched as one unit.",
|
|
138
|
+
"type": "object",
|
|
139
|
+
"additionalProperties": false,
|
|
140
|
+
"allOf": [
|
|
141
|
+
{ "$ref": "#/definitions/noInstructions" },
|
|
142
|
+
{ "$ref": "#/definitions/oneOfSequenceOrContains" },
|
|
143
|
+
{ "$ref": "#/definitions/noHeadingOnRepeat" }
|
|
144
|
+
],
|
|
145
|
+
"properties": {
|
|
146
|
+
"id": { "$ref": "#/definitions/id" },
|
|
147
|
+
"description": { "$ref": "#/definitions/description" },
|
|
148
|
+
"heading": { "$ref": "#/definitions/heading" },
|
|
149
|
+
"repeat": { "$ref": "#/definitions/repeat" },
|
|
150
|
+
"min": { "$ref": "#/definitions/min" },
|
|
151
|
+
"max": { "$ref": "#/definitions/max" },
|
|
152
|
+
"sequence": { "$ref": "#/definitions/sequence" },
|
|
153
|
+
"contains": { "$ref": "#/definitions/blockRules" },
|
|
154
|
+
"sections": { "$ref": "#/definitions/rules" }
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"rules": {
|
|
158
|
+
"description": "Rules for the subsections, in document order.",
|
|
159
|
+
"type": "array",
|
|
160
|
+
"items": { "$ref": "#/definitions/rule" }
|
|
161
|
+
},
|
|
162
|
+
"repeat": {
|
|
163
|
+
"description": "Rules matched in order as one unit, repeated by this rule's `min` and `max`.",
|
|
164
|
+
"type": "array",
|
|
165
|
+
"minItems": 1,
|
|
166
|
+
"items": { "$ref": "#/definitions/rule" }
|
|
167
|
+
},
|
|
168
|
+
"sequence": {
|
|
169
|
+
"description": "What the section holds, in order. Each entry is one run of one content kind.",
|
|
170
|
+
"type": "array",
|
|
171
|
+
"minItems": 1,
|
|
172
|
+
"items": {
|
|
173
|
+
"allOf": [
|
|
174
|
+
{ "$ref": "#/definitions/blockRules" },
|
|
175
|
+
{ "type": "object", "maxProperties": 1 }
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"blockRules": {
|
|
180
|
+
"description": "Block rules, keyed by content kind. The key is plural because it carries a count: the node model says `codeBlock`, a template says `codeBlocks: { min: 1 }`.",
|
|
181
|
+
"type": "object",
|
|
182
|
+
"additionalProperties": false,
|
|
183
|
+
"minProperties": 1,
|
|
184
|
+
"properties": {
|
|
185
|
+
"paragraphs": { "$ref": "#/definitions/paragraphs" },
|
|
186
|
+
"codeBlocks": { "$ref": "#/definitions/codeBlocks" },
|
|
187
|
+
"lists": { "$ref": "#/definitions/lists" },
|
|
188
|
+
"tables": { "$ref": "#/definitions/tables" },
|
|
189
|
+
"admonitions": { "$ref": "#/definitions/admonitions" },
|
|
190
|
+
"images": { "$ref": "#/definitions/images" },
|
|
191
|
+
"blockquotes": { "$ref": "#/definitions/counted" },
|
|
192
|
+
"definitionLists": { "$ref": "#/definitions/counted" },
|
|
193
|
+
"elements": { "$ref": "#/definitions/elements" }
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"counted": {
|
|
197
|
+
"description": "A block rule that only counts.",
|
|
198
|
+
"type": "object",
|
|
199
|
+
"additionalProperties": false,
|
|
200
|
+
"properties": {
|
|
201
|
+
"min": { "$ref": "#/definitions/min" },
|
|
202
|
+
"max": { "$ref": "#/definitions/max" }
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"paragraphs": {
|
|
206
|
+
"description": "Paragraph requirements.",
|
|
207
|
+
"type": "object",
|
|
208
|
+
"additionalProperties": false,
|
|
209
|
+
"properties": {
|
|
210
|
+
"min": { "$ref": "#/definitions/min" },
|
|
211
|
+
"max": { "$ref": "#/definitions/max" },
|
|
212
|
+
"pattern": {
|
|
213
|
+
"description": "Unanchored regular expression every paragraph in the run must match.",
|
|
214
|
+
"type": "string",
|
|
215
|
+
"minLength": 1
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"codeBlocks": {
|
|
220
|
+
"description": "Code block requirements.",
|
|
221
|
+
"type": "object",
|
|
222
|
+
"additionalProperties": false,
|
|
223
|
+
"properties": {
|
|
224
|
+
"min": { "$ref": "#/definitions/min" },
|
|
225
|
+
"max": { "$ref": "#/definitions/max" },
|
|
226
|
+
"language": {
|
|
227
|
+
"description": "Language every code block must be tagged with, as the node model spells it. A list is one-of: the block must declare one of them.",
|
|
228
|
+
"oneOf": [
|
|
229
|
+
{ "type": "string", "minLength": 1 },
|
|
230
|
+
{
|
|
231
|
+
"type": "array",
|
|
232
|
+
"minItems": 1,
|
|
233
|
+
"items": { "type": "string", "minLength": 1 }
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
},
|
|
237
|
+
"fenceInfo": {
|
|
238
|
+
"description": "Info-string tail after the language, where the format carries one.",
|
|
239
|
+
"type": "string"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"lists": {
|
|
244
|
+
"description": "List requirements.",
|
|
245
|
+
"type": "object",
|
|
246
|
+
"additionalProperties": false,
|
|
247
|
+
"properties": {
|
|
248
|
+
"min": { "$ref": "#/definitions/min" },
|
|
249
|
+
"max": { "$ref": "#/definitions/max" },
|
|
250
|
+
"ordered": {
|
|
251
|
+
"description": "Whether the list must be ordered. Absent accepts either.",
|
|
252
|
+
"type": "boolean"
|
|
253
|
+
},
|
|
254
|
+
"items": { "$ref": "#/definitions/listItems" }
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"listItems": {
|
|
258
|
+
"description": "Requirements applied to every item of every list in the run. Recurses arbitrarily deep.",
|
|
259
|
+
"type": "object",
|
|
260
|
+
"additionalProperties": false,
|
|
261
|
+
"allOf": [{ "$ref": "#/definitions/oneOfSequenceOrContains" }],
|
|
262
|
+
"properties": {
|
|
263
|
+
"min": { "$ref": "#/definitions/min" },
|
|
264
|
+
"max": { "$ref": "#/definitions/max" },
|
|
265
|
+
"sequence": { "$ref": "#/definitions/sequence" },
|
|
266
|
+
"contains": { "$ref": "#/definitions/blockRules" }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"tables": {
|
|
270
|
+
"description": "Table requirements.",
|
|
271
|
+
"type": "object",
|
|
272
|
+
"additionalProperties": false,
|
|
273
|
+
"properties": {
|
|
274
|
+
"min": { "$ref": "#/definitions/min" },
|
|
275
|
+
"max": { "$ref": "#/definitions/max" },
|
|
276
|
+
"columns": {
|
|
277
|
+
"description": "The header cells, in order.",
|
|
278
|
+
"type": "array",
|
|
279
|
+
"items": { "type": "string" }
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"admonitions": {
|
|
284
|
+
"description": "Admonition requirements.",
|
|
285
|
+
"type": "object",
|
|
286
|
+
"additionalProperties": false,
|
|
287
|
+
"properties": {
|
|
288
|
+
"min": { "$ref": "#/definitions/min" },
|
|
289
|
+
"max": { "$ref": "#/definitions/max" },
|
|
290
|
+
"variant": {
|
|
291
|
+
"description": "Which flavor of admonition. The node model's `variant`, not any one format's spelling.",
|
|
292
|
+
"enum": [
|
|
293
|
+
"note",
|
|
294
|
+
"tip",
|
|
295
|
+
"important",
|
|
296
|
+
"caution",
|
|
297
|
+
"warning",
|
|
298
|
+
"danger"
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"images": {
|
|
304
|
+
"description": "Image requirements.",
|
|
305
|
+
"type": "object",
|
|
306
|
+
"additionalProperties": false,
|
|
307
|
+
"properties": {
|
|
308
|
+
"min": { "$ref": "#/definitions/min" },
|
|
309
|
+
"max": { "$ref": "#/definitions/max" },
|
|
310
|
+
"url": {
|
|
311
|
+
"description": "Where the image must point.",
|
|
312
|
+
"type": "string"
|
|
313
|
+
},
|
|
314
|
+
"alt": {
|
|
315
|
+
"description": "Alternative text the image must carry.",
|
|
316
|
+
"type": "string"
|
|
317
|
+
},
|
|
318
|
+
"attributes": { "$ref": "#/definitions/attributes" }
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"elements": {
|
|
322
|
+
"description": "Named-wrapper requirements. `sequence` and `contains` here describe what the element holds, which is never the enclosing section's content.",
|
|
323
|
+
"type": "object",
|
|
324
|
+
"additionalProperties": false,
|
|
325
|
+
"allOf": [{ "$ref": "#/definitions/oneOfSequenceOrContains" }],
|
|
326
|
+
"properties": {
|
|
327
|
+
"min": { "$ref": "#/definitions/min" },
|
|
328
|
+
"max": { "$ref": "#/definitions/max" },
|
|
329
|
+
"tag": {
|
|
330
|
+
"description": "The element's name, as an author of the format would write it. A list is one-of: an element counts when it carries any of them.",
|
|
331
|
+
"oneOf": [
|
|
332
|
+
{ "type": "string", "minLength": 1 },
|
|
333
|
+
{
|
|
334
|
+
"type": "array",
|
|
335
|
+
"minItems": 1,
|
|
336
|
+
"items": { "type": "string", "minLength": 1 }
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
},
|
|
340
|
+
"attributes": { "$ref": "#/definitions/attributes" },
|
|
341
|
+
"sequence": { "$ref": "#/definitions/sequence" },
|
|
342
|
+
"contains": { "$ref": "#/definitions/blockRules" }
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Concept, derived from The Good Docs Project's `concept/template_concept.md`
|
|
2
|
+
# at release v1.6.0. The upstream Markdown is vendored at
|
|
3
|
+
# `test/lint/fixtures/tgdp/template_concept.md` and linted against this file, so the
|
|
4
|
+
# two cannot drift.
|
|
5
|
+
#
|
|
6
|
+
# Serves Diataxis's "explanation" as well as TGDP's "concept": they are the
|
|
7
|
+
# same shape under two names.
|
|
8
|
+
#
|
|
9
|
+
# Almost every heading in this doctype is optional - upstream marks all but
|
|
10
|
+
# "Use cases" with an `(Optional)` prefix - so this template mostly constrains
|
|
11
|
+
# *which* sections may appear and *in what order*, and says very little about
|
|
12
|
+
# what goes inside them. That is deliberate: a concept page is prose, and a
|
|
13
|
+
# minimum paragraph count per section would fail pages a reader would call
|
|
14
|
+
# correct.
|
|
15
|
+
#
|
|
16
|
+
# The `(\(Optional\) )?` alternative in each pattern is what lets upstream's own
|
|
17
|
+
# file lint clean: it ships the authoring marker in the literal heading text,
|
|
18
|
+
# where a real page writes just the section name.
|
|
19
|
+
#
|
|
20
|
+
# v2: the page's own body - the summary and the definition that follows it,
|
|
21
|
+
# which upstream deliberately leaves without a heading of its own - is the
|
|
22
|
+
# template's own `contains:` rather than a `title` section's. A concept page
|
|
23
|
+
# explains something, and explanations grow sections the published template
|
|
24
|
+
# never named; the trailing `min: 0` rule is what lets those through.
|
|
25
|
+
info:
|
|
26
|
+
title: Concept (The Good Docs Project)
|
|
27
|
+
version: "1.6.0"
|
|
28
|
+
source: https://gitlab.com/tgdp/templates/-/blob/v1.6.0/concept/template_concept.md
|
|
29
|
+
|
|
30
|
+
templates:
|
|
31
|
+
concept:
|
|
32
|
+
types:
|
|
33
|
+
- concept
|
|
34
|
+
- explanation
|
|
35
|
+
description: >-
|
|
36
|
+
The page title, whatever the author calls the concept. Its body is the
|
|
37
|
+
summary that introduces the concept and the definition that follows -
|
|
38
|
+
upstream notes the definition deliberately carries no heading of its
|
|
39
|
+
own, so it is checked here rather than in a section.
|
|
40
|
+
contains:
|
|
41
|
+
paragraphs:
|
|
42
|
+
min: 1
|
|
43
|
+
sections:
|
|
44
|
+
- id: background
|
|
45
|
+
description: Context, prehistory, or background for the concept.
|
|
46
|
+
heading:
|
|
47
|
+
pattern: '^(\(Optional\) )?Background$'
|
|
48
|
+
min: 0
|
|
49
|
+
max: 1
|
|
50
|
+
- id: use-cases
|
|
51
|
+
description: >-
|
|
52
|
+
How a reader benefits from the concept. The one section upstream
|
|
53
|
+
does not mark optional.
|
|
54
|
+
heading: Use cases
|
|
55
|
+
max: 1
|
|
56
|
+
- id: comparison
|
|
57
|
+
description: >-
|
|
58
|
+
A comparison of the options or alternatives the concept sits
|
|
59
|
+
among. Upstream titles it `Comparison of {thing being compared}`,
|
|
60
|
+
so only the literal prefix is anchored.
|
|
61
|
+
heading:
|
|
62
|
+
pattern: '^(\(Optional\) )?Comparison( of .+)?$'
|
|
63
|
+
min: 0
|
|
64
|
+
max: 1
|
|
65
|
+
- id: related-resources
|
|
66
|
+
description: >-
|
|
67
|
+
Links out to related documentation. Upstream recommends "Related
|
|
68
|
+
concepts" or "Additional information" as more descriptive names,
|
|
69
|
+
so all three are accepted.
|
|
70
|
+
heading:
|
|
71
|
+
pattern: '^(\(Optional\) )?(Related resources|Related concepts|Additional information)$'
|
|
72
|
+
min: 0
|
|
73
|
+
max: 1
|
|
74
|
+
# A concept page explains something, and explanations grow sections the
|
|
75
|
+
# published template never named. The four above are the ones TGDP
|
|
76
|
+
# names; anything else the author needs is allowed through.
|
|
77
|
+
- min: 0
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Derived from The Good Docs Project "how-to" template, pinned to v1.6.0:
|
|
2
|
+
# https://gitlab.com/tgdp/templates/-/blob/v1.6.0/how-to/template_how-to.md
|
|
3
|
+
#
|
|
4
|
+
# The upstream Markdown is vendored at test/lint/fixtures/tgdp/template_how-to.md and
|
|
5
|
+
# linted against this file, so the two cannot drift. Where they disagree,
|
|
6
|
+
# upstream is right.
|
|
7
|
+
#
|
|
8
|
+
# v2: the template *is* the page (proposal 0061's grammar). Upstream's `# Title`
|
|
9
|
+
# is a placeholder, so what used to be a `title` section wrapping everything is
|
|
10
|
+
# now the template's own `sections:` directly - there is nothing to say about
|
|
11
|
+
# the H1's heading text or its own content.
|
|
12
|
+
info:
|
|
13
|
+
title: How-to guide (The Good Docs Project)
|
|
14
|
+
version: "1.6.0"
|
|
15
|
+
source: https://gitlab.com/tgdp/templates/-/blob/v1.6.0/how-to/template_how-to.md
|
|
16
|
+
|
|
17
|
+
templates:
|
|
18
|
+
how-to:
|
|
19
|
+
types:
|
|
20
|
+
- how-to
|
|
21
|
+
sections:
|
|
22
|
+
- id: overview
|
|
23
|
+
description: >-
|
|
24
|
+
What the guide explains, and optionally when and why a reader
|
|
25
|
+
would want to do it. A how-to that does not say what task it
|
|
26
|
+
covers is not a how-to, so at least one paragraph is required.
|
|
27
|
+
heading: Overview
|
|
28
|
+
max: 1
|
|
29
|
+
contains:
|
|
30
|
+
paragraphs:
|
|
31
|
+
min: 1
|
|
32
|
+
- id: before-you-start
|
|
33
|
+
description: >-
|
|
34
|
+
Prerequisites. Upstream marks this "{This section is optional}",
|
|
35
|
+
and the authoring guide repeats that, so it is not required.
|
|
36
|
+
Its shape varies too much to constrain - a lead-in and a bullet
|
|
37
|
+
list in the template, but prose or grouped categories in the
|
|
38
|
+
guide's own examples - so no content counts are set.
|
|
39
|
+
heading: Before you start
|
|
40
|
+
min: 0
|
|
41
|
+
max: 1
|
|
42
|
+
- id: task
|
|
43
|
+
description: >-
|
|
44
|
+
The steps. Upstream's heading is the placeholder "{Task name}",
|
|
45
|
+
so this is a slot; leaving `max` unbounded lets a page carry
|
|
46
|
+
several task sections, which the guide explicitly contemplates
|
|
47
|
+
("you may break down the task into multiple logical sub-tasks").
|
|
48
|
+
No `lists` floor: a task that delegates its procedure to
|
|
49
|
+
sub-tasks legitimately holds no ordered list of its own.
|
|
50
|
+
sections:
|
|
51
|
+
- id: sub-task
|
|
52
|
+
description: >-
|
|
53
|
+
"### {Sub-task}" - another placeholder heading, and upstream
|
|
54
|
+
says to "include a sub-task only if the task is big and
|
|
55
|
+
complex", so it is optional and may occur more than once.
|
|
56
|
+
min: 0
|
|
57
|
+
- id: see-also
|
|
58
|
+
description: >-
|
|
59
|
+
Related reading. Upstream includes it unconditionally and does not
|
|
60
|
+
mark it optional the way it marks "Before you start", so it is
|
|
61
|
+
required. Its body is a mix of prose and links, so nothing is
|
|
62
|
+
counted.
|
|
63
|
+
heading: See also
|
|
64
|
+
max: 1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Built-in doctype templates derived from The Good Docs Project templates, pinned to release v1.6.0 (\"Iron\"): https://gitlab.com/tgdp/templates/-/tree/v1.6.0. Each entry's `file` is a YAML template beside this manifest; `source` is the upstream Markdown it was derived from, vendored under test/lint/fixtures/tgdp/ and linted against the derived template so the two cannot drift. Run `npm run check:tgdp-pin` to see whether upstream has moved past the pin.",
|
|
3
|
+
"vendor": "tgdp",
|
|
4
|
+
"upstream": "https://gitlab.com/tgdp/templates",
|
|
5
|
+
"pin": "v1.6.0",
|
|
6
|
+
"templates": [
|
|
7
|
+
{
|
|
8
|
+
"id": "tgdp:how-to:1.6",
|
|
9
|
+
"file": "tgdp/how-to.yaml",
|
|
10
|
+
"title": "How-to guide (The Good Docs Project)",
|
|
11
|
+
"types": ["how-to"],
|
|
12
|
+
"source": "how-to/template_how-to.md"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "tgdp:tutorial:1.6",
|
|
16
|
+
"file": "tgdp/tutorial.yaml",
|
|
17
|
+
"title": "Tutorial (The Good Docs Project)",
|
|
18
|
+
"types": ["tutorial"],
|
|
19
|
+
"source": "tutorial/template_tutorial.md"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "tgdp:reference:1.6",
|
|
23
|
+
"file": "tgdp/reference.yaml",
|
|
24
|
+
"title": "Reference (The Good Docs Project)",
|
|
25
|
+
"types": ["reference"],
|
|
26
|
+
"source": "reference/template_reference.md"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "tgdp:concept:1.6",
|
|
30
|
+
"file": "tgdp/concept.yaml",
|
|
31
|
+
"title": "Concept (The Good Docs Project)",
|
|
32
|
+
"types": ["concept", "explanation"],
|
|
33
|
+
"source": "concept/template_concept.md"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "tgdp:troubleshooting:1.6",
|
|
37
|
+
"file": "tgdp/troubleshooting.yaml",
|
|
38
|
+
"title": "Troubleshooting (The Good Docs Project)",
|
|
39
|
+
"types": ["troubleshooting"],
|
|
40
|
+
"source": "troubleshooting/template_troubleshooting.md"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "tgdp:release-notes:1.6",
|
|
44
|
+
"file": "tgdp/release-notes.yaml",
|
|
45
|
+
"title": "Release notes (The Good Docs Project)",
|
|
46
|
+
"types": ["release-notes"],
|
|
47
|
+
"source": "release-notes/template_release-notes.md"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "tgdp:readme:1.6",
|
|
51
|
+
"file": "tgdp/readme.yaml",
|
|
52
|
+
"title": "README (The Good Docs Project)",
|
|
53
|
+
"types": ["readme"],
|
|
54
|
+
"source": "readme/template_readme.md"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|