Files
metabuilder/packages/shared/seed/SCRIPT_JSON_DOCSTRINGS.md
2025-12-31 13:39:47 +00:00

649 lines
16 KiB
Markdown

# JSON Script Docstring Specification
## Overview
JSON scripts support **JSDoc-style docstrings** embedded directly in JSON format. Docstrings provide:
- **Function documentation** - What the function does, parameters, return values
- **Type information** - Parameter types, return types, generic constraints
- **Usage examples** - Code samples showing how to use functions
- **Metadata** - Version, author, deprecation warnings, etc.
## Docstring Format
Docstrings are added to functions, constants, and types using a `docstring` property:
```json
{
"name": "calculateArea",
"docstring": {
"summary": "Calculates the area of a rectangle",
"description": "Takes width and height and returns the area. Values are clamped to prevent overflow.",
"params": [
{
"name": "width",
"type": "number",
"description": "Width of the rectangle in pixels"
},
{
"name": "height",
"type": "number",
"description": "Height of the rectangle in pixels"
}
],
"returns": {
"type": "number",
"description": "Area in square pixels, clamped between 0 and 1000"
},
"examples": [
{
"title": "Basic usage",
"code": "const area = calculateArea(10, 20); // Returns 200"
},
{
"title": "Large values are clamped",
"code": "const area = calculateArea(100, 100); // Returns 1000 (clamped)"
}
],
"throws": [
{
"type": "TypeError",
"description": "If width or height are not numbers"
}
],
"see": ["multiply", "clamp"],
"since": "1.0.0",
"deprecated": false
},
"params": [...],
"body": [...]
}
```
## Docstring Properties
### Required Fields
#### `summary` (string)
**Short one-line description** of what the function does.
- Keep to 80 characters or less
- No period at the end
- Use present tense ("Calculates..." not "Calculate...")
```json
{
"summary": "Validates user input against a set of rules"
}
```
### Optional Fields
#### `description` (string)
**Detailed multi-line description** providing context, behavior, edge cases.
```json
{
"description": "Validates form input by checking:\n- Name is not empty\n- Age is between 0 and 120\n- Email matches RFC 5322 format\n\nReturns a ValidationResult with errors keyed by field name."
}
```
#### `params` (array)
**Parameter documentation** - one entry per parameter.
```json
{
"params": [
{
"name": "input",
"type": "FormInput",
"description": "Form data to validate",
"optional": false,
"default": null
},
{
"name": "strict",
"type": "boolean",
"description": "Whether to use strict validation rules",
"optional": true,
"default": false
}
]
}
```
**Fields**:
- `name` (string, required) - Parameter name
- `type` (string, optional) - Type annotation
- `description` (string, required) - What the parameter is for
- `optional` (boolean, optional) - Whether parameter is optional
- `default` (any, optional) - Default value if not provided
#### `returns` (object)
**Return value documentation**.
```json
{
"returns": {
"type": "ValidationResult",
"description": "Object with 'valid' boolean and 'errors' object"
}
}
```
**Fields**:
- `type` (string, optional) - Return type
- `description` (string, required) - What is returned
#### `examples` (array)
**Usage examples** showing how to call the function.
```json
{
"examples": [
{
"title": "Valid input",
"code": "const result = validateInput({name: 'John', age: 30});\n// result.valid === true"
},
{
"title": "Invalid input",
"code": "const result = validateInput({name: '', age: -5});\n// result.errors === {name: '...', age: '...'}"
}
]
}
```
**Fields**:
- `title` (string, required) - Short description of the example
- `code` (string, required) - Example code snippet
#### `throws` (array)
**Exceptions that can be thrown**.
```json
{
"throws": [
{
"type": "TypeError",
"description": "If input is not an object"
},
{
"type": "ValidationError",
"description": "If validation fails in strict mode"
}
]
}
```
**Fields**:
- `type` (string, required) - Exception type
- `description` (string, required) - When it's thrown
#### `see` (array of strings)
**Related functions or documentation** to reference.
```json
{
"see": ["isNotEmpty", "validateRange", "FormInput"]
}
```
#### `since` (string)
**Version when function was added**.
```json
{
"since": "1.2.0"
}
```
#### `deprecated` (boolean | object)
**Whether function is deprecated** and what to use instead.
```json
{
"deprecated": {
"version": "2.0.0",
"reason": "Use validateFormData instead",
"alternative": "validateFormData"
}
}
```
Or simply:
```json
{
"deprecated": true
}
```
#### `author` (string)
**Function author**.
```json
{
"author": "John Doe <john@example.com>"
}
```
#### `version` (string)
**Current version** of the function.
```json
{
"version": "1.3.0"
}
```
#### `tags` (array of strings)
**Categorization tags**.
```json
{
"tags": ["validation", "forms", "user-input"]
}
```
#### `internal` (boolean)
**Whether function is internal-only** (not part of public API).
```json
{
"internal": true
}
```
## Complete Example
```json
{
"id": "validate_input_fn",
"name": "validateInput",
"exported": true,
"docstring": {
"summary": "Validates form input against a set of rules",
"description": "Validates user input by checking:\n- Name is not empty\n- Age is between 0 and 120\n- Email matches RFC 5322 format\n\nReturns a ValidationResult with errors keyed by field name.",
"params": [
{
"name": "input",
"type": "FormInput",
"description": "Form data containing name, age, and email fields"
},
{
"name": "strict",
"type": "boolean",
"description": "If true, throws on validation failure instead of returning errors",
"optional": true,
"default": false
}
],
"returns": {
"type": "ValidationResult",
"description": "Object with 'valid' boolean and 'errors' object containing field-specific error messages"
},
"examples": [
{
"title": "Valid input",
"code": "const result = validateInput({\n name: 'John Doe',\n age: 30,\n email: 'john@example.com'\n});\n// result.valid === true\n// result.errors === {}"
},
{
"title": "Invalid input",
"code": "const result = validateInput({\n name: '',\n age: 200,\n email: 'not-an-email'\n});\n// result.valid === false\n// result.errors === {\n// name: 'Name is required',\n// age: 'Age must be between 0 and 120',\n// email: 'Invalid email format'\n// }"
},
{
"title": "Strict mode",
"code": "try {\n validateInput({name: ''}, true);\n} catch (e) {\n // Throws ValidationError\n}"
}
],
"throws": [
{
"type": "TypeError",
"description": "If input is not an object"
},
{
"type": "ValidationError",
"description": "If validation fails and strict mode is enabled"
}
],
"see": ["isNotEmpty", "validateRange", "isValidEmail", "FormInput", "ValidationResult"],
"since": "1.0.0",
"author": "MetaBuilder Team",
"tags": ["validation", "forms", "user-input"],
"version": "1.2.0",
"deprecated": false
},
"params": [
{
"name": "input",
"type": "FormInput"
},
{
"name": "strict",
"type": "boolean",
"optional": true,
"default": false
}
],
"returnType": "ValidationResult",
"body": [...]
}
```
## Constant Docstrings
Constants can also have docstrings:
```json
{
"constants": [
{
"id": "max_retries",
"name": "MAX_RETRIES",
"value": 3,
"exported": true,
"docstring": {
"summary": "Maximum number of retry attempts for failed requests",
"description": "After this many retries, the request will fail permanently. Set to 0 to disable retries.",
"since": "1.0.0",
"see": ["retryRequest", "RETRY_DELAY"]
}
}
]
}
```
## Type Docstrings
Types in `types.json` can have docstrings:
```json
{
"types": [
{
"id": "validation_result",
"name": "ValidationResult",
"type": "object",
"exported": true,
"docstring": {
"summary": "Result of input validation operation",
"description": "Contains validation status and error messages for each invalid field.",
"examples": [
{
"title": "Valid result",
"code": "{ valid: true, errors: {} }"
},
{
"title": "Invalid result",
"code": "{ valid: false, errors: { name: 'Name is required' } }"
}
],
"see": ["validateInput", "ValidationErrors"],
"since": "1.0.0"
},
"properties": {
"valid": {
"type": "boolean",
"required": true,
"description": "Whether input passed validation"
},
"errors": {
"type": "ValidationErrors",
"description": "Error messages keyed by field name"
}
}
}
]
}
```
## Generating Documentation
Docstrings can be extracted to generate:
### 1. Markdown Documentation
```markdown
# validateInput
Validates form input against a set of rules
## Description
Validates user input by checking:
- Name is not empty
- Age is between 0 and 120
- Email matches RFC 5322 format
Returns a ValidationResult with errors keyed by field name.
## Parameters
- **input** (`FormInput`) - Form data containing name, age, and email fields
- **strict** (`boolean`, optional, default: `false`) - If true, throws on validation failure instead of returning errors
## Returns
`ValidationResult` - Object with 'valid' boolean and 'errors' object containing field-specific error messages
## Examples
### Valid input
\`\`\`javascript
const result = validateInput({
name: 'John Doe',
age: 30,
email: 'john@example.com'
});
// result.valid === true
// result.errors === {}
\`\`\`
### Invalid input
\`\`\`javascript
const result = validateInput({
name: '',
age: 200,
email: 'not-an-email'
});
// result.valid === false
\`\`\`
## Throws
- `TypeError` - If input is not an object
- `ValidationError` - If validation fails and strict mode is enabled
## See Also
- isNotEmpty
- validateRange
- isValidEmail
- FormInput
- ValidationResult
## Version
1.2.0 (since 1.0.0)
```
### 2. TypeScript Definitions
```typescript
/**
* Validates form input against a set of rules
*
* Validates user input by checking:
* - Name is not empty
* - Age is between 0 and 120
* - Email matches RFC 5322 format
*
* @param input - Form data containing name, age, and email fields
* @param strict - If true, throws on validation failure instead of returning errors
* @returns Object with 'valid' boolean and 'errors' object containing field-specific error messages
* @throws {TypeError} If input is not an object
* @throws {ValidationError} If validation fails and strict mode is enabled
* @since 1.0.0
* @version 1.2.0
* @see isNotEmpty
* @see validateRange
*/
export function validateInput(
input: FormInput,
strict?: boolean
): ValidationResult;
```
### 3. Storybook Integration
Docstrings can automatically generate Storybook documentation:
```typescript
export const ValidateInputStory: Story = {
name: 'validateInput',
parameters: {
docs: {
description: {
story: 'Validates form input against a set of rules\n\n' +
'Validates user input by checking:\n' +
'- Name is not empty\n' +
'- Age is between 0 and 120'
}
}
},
argTypes: {
input: {
description: 'Form data containing name, age, and email fields',
type: { name: 'object', required: true }
},
strict: {
description: 'If true, throws on validation failure',
type: { name: 'boolean', required: false },
defaultValue: false
}
}
}
```
## Runtime Integration
### JavaScript/TypeScript
The script executor can expose docstrings via a metadata API:
```javascript
import { getDocstring } from './script_executor.js'
const doc = getDocstring(scriptJson, 'validateInput')
console.log(doc.summary)
console.log(doc.params)
console.log(doc.examples)
```
### Lua
```lua
local executor = require('script_executor')
local doc = executor.get_docstring(script, 'validateInput')
print(doc.summary)
```
## Best Practices
### ✅ DO
- **Write clear summaries** - One line, present tense, under 80 chars
- **Document all parameters** - Even if types are obvious
- **Provide examples** - Show common use cases and edge cases
- **Link related functions** - Use `see` to cross-reference
- **Keep descriptions current** - Update docs when code changes
- **Use proper formatting** - Newlines, bullets, code blocks
### ❌ DON'T
- **Repeat type information** - Types are already in `params`/`returnType`
- **Write obvious docs** - "Gets the name" for `getName()` is useless
- **Use jargon** - Explain acronyms and domain terms
- **Forget examples** - Code samples are worth 1000 words
- **Leave deprecated functions** - Mark with `deprecated` or remove
## Schema Validation
Docstrings should validate against JSON Schema:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"summary": { "type": "string", "maxLength": 200 },
"description": { "type": "string" },
"params": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "description"],
"properties": {
"name": { "type": "string" },
"type": { "type": "string" },
"description": { "type": "string" },
"optional": { "type": "boolean" },
"default": {}
}
}
},
"returns": {
"type": "object",
"required": ["description"],
"properties": {
"type": { "type": "string" },
"description": { "type": "string" }
}
},
"examples": {
"type": "array",
"items": {
"type": "object",
"required": ["title", "code"],
"properties": {
"title": { "type": "string" },
"code": { "type": "string" }
}
}
},
"throws": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "description"],
"properties": {
"type": { "type": "string" },
"description": { "type": "string" }
}
}
},
"see": { "type": "array", "items": { "type": "string" } },
"since": { "type": "string" },
"deprecated": { "oneOf": [
{ "type": "boolean" },
{
"type": "object",
"properties": {
"version": { "type": "string" },
"reason": { "type": "string" },
"alternative": { "type": "string" }
}
}
]},
"author": { "type": "string" },
"version": { "type": "string" },
"tags": { "type": "array", "items": { "type": "string" } },
"internal": { "type": "boolean" }
},
"required": ["summary"]
}
```
## See Also
- [JSON Script Specification](SCRIPT_JSON_SPEC_ISSUES.md)
- [Type Definitions Guide](../../json_script_example/TYPES.md)
- [Testing Guide](../../json_script_example/tests/README.md)