@redpanda-data/docs-extensions-and-macros 5.38.1 → 5.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -33,7 +33,11 @@ const CONVENTION = {
|
|
|
33
33
|
case: 'sentence',
|
|
34
34
|
terminal_period: true,
|
|
35
35
|
verbatim_asciidoc: true,
|
|
36
|
-
state_default:
|
|
36
|
+
// Not state_default. The rendered page builds a "Default:" row from the
|
|
37
|
+
// extractor's own field, so prose restating a concrete default duplicates
|
|
38
|
+
// structured data. Only a sentinel default (null, 0, -1, "") carries
|
|
39
|
+
// behavior that row cannot express.
|
|
40
|
+
state_sentinel_default: true
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
function run (cmd, args, options = {}) {
|
|
@@ -133,8 +137,9 @@ function mapExtractorJson (json, repo, options = {}) {
|
|
|
133
137
|
|
|
134
138
|
const lineStart = prop.line_start != null ? prop.line_start : null
|
|
135
139
|
const lineEnd = prop.line_end != null ? prop.line_end : lineStart
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
// null and "" are defaults too: the extractor emits null for every
|
|
141
|
+
// std::nullopt, and those are exactly the sentinels the rule below is for.
|
|
142
|
+
const hasDefault = Object.prototype.hasOwnProperty.call(prop, 'default')
|
|
138
143
|
|
|
139
144
|
declarations.push({
|
|
140
145
|
surface: 'properties',
|
|
@@ -148,6 +153,7 @@ function mapExtractorJson (json, repo, options = {}) {
|
|
|
148
153
|
meta: {
|
|
149
154
|
has_default: hasDefault,
|
|
150
155
|
default: hasDefault ? prop.default : null,
|
|
156
|
+
type: typeof prop.type === 'string' ? prop.type : null,
|
|
151
157
|
is_enum: Boolean(prop.is_enum),
|
|
152
158
|
nullable: Boolean(prop.nullable)
|
|
153
159
|
}
|
|
@@ -184,16 +190,52 @@ const RULES = [
|
|
|
184
190
|
}
|
|
185
191
|
},
|
|
186
192
|
{
|
|
187
|
-
name: 'default-
|
|
188
|
-
description: 'Property
|
|
193
|
+
name: 'sentinel-default-unexplained',
|
|
194
|
+
description: 'Property defaults to a sentinel whose meaning the description never explains',
|
|
189
195
|
severity: 'info',
|
|
196
|
+
// The rendered page already carries a "Default:" row built from the
|
|
197
|
+
// extractor's own `default` field, so asking the prose to restate a
|
|
198
|
+
// concrete default duplicates structured data -- and duplicated facts go
|
|
199
|
+
// stale. A real example: tombstone_retention_ms's description claimed "a
|
|
200
|
+
// typical default setting is 86400000" while the actual default was null.
|
|
201
|
+
//
|
|
202
|
+
// A SENTINEL default is the exception. null, 0, -1 and "" usually mean
|
|
203
|
+
// disabled, unlimited or unset, and which one is not inferable from the
|
|
204
|
+
// value, so "Default: null" leaves the reader guessing. That meaning is
|
|
205
|
+
// information the structured field cannot carry, which is the only case
|
|
206
|
+
// worth a finding.
|
|
190
207
|
check: (decl) => {
|
|
191
|
-
const text = decl.string || ''
|
|
208
|
+
const text = (decl.string || '').trim()
|
|
192
209
|
if (!text || !decl.meta || !decl.meta.has_default) return []
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
const value = decl.meta.default
|
|
211
|
+
// Booleans are never sentinels: `false` is a real setting, not a
|
|
212
|
+
// stand-in for "off".
|
|
213
|
+
if (typeof value === 'boolean') return []
|
|
214
|
+
// A string-typed property defaulting to null or "" is plainly "not
|
|
215
|
+
// configured" (credentials, bucket names, endpoints); the "Default:" row
|
|
216
|
+
// says that on its own, so only non-string sentinels are ambiguous.
|
|
217
|
+
if (decl.meta.type === 'string' && (value === null || value === '')) return []
|
|
218
|
+
const sentinels = [
|
|
219
|
+
{ match: (v) => v === null || v === 'null', token: /\bnull\b/i, label: 'null' },
|
|
220
|
+
{ match: (v) => v === '' , token: /\b(empty|blank)\b/i, label: 'an empty string' },
|
|
221
|
+
{ match: (v) => v === 0 || v === '0', token: /\b(0|zero)\b/i, label: '0' },
|
|
222
|
+
{ match: (v) => v === -1 || v === '-1', token: /-1\b/, label: '-1' }
|
|
223
|
+
]
|
|
224
|
+
const sentinel = sentinels.find((s) => s.match(value))
|
|
225
|
+
if (!sentinel) return []
|
|
226
|
+
// Either name the sentinel, or say what it does. Both forms explain it;
|
|
227
|
+
// neither is satisfied by an unrelated digit elsewhere in the sentence.
|
|
228
|
+
// "default"/"falls back"/"inherits"/"omitted" cover descriptions that
|
|
229
|
+
// explain the null case by naming what is used instead, which is the
|
|
230
|
+
// explanation being asked for.
|
|
231
|
+
const MEANING = /\b(disabl\w*|unlimited|no limit|unbounded|infinite|unset|not set|never|off|ignored|no maximum|no minimum|defaults?|inherit\w*|blank|omitted|not specified|falls? back)\b/i
|
|
232
|
+
if (sentinel.token.test(text) || MEANING.test(text)) return []
|
|
233
|
+
return [{
|
|
234
|
+
message: `Property defaults to ${sentinel.label}, and the description does not say what that means. `
|
|
235
|
+
+ 'A sentinel default carries behavior the rendered "Default:" row cannot: say whether it disables '
|
|
236
|
+
+ 'the property, means unlimited, or leaves it unset. There is no need to restate a concrete '
|
|
237
|
+
+ 'default value; the page already renders it from structured data.'
|
|
238
|
+
}]
|
|
197
239
|
}
|
|
198
240
|
}
|
|
199
241
|
]
|