├── README.md ├── journal.txt ├── journal ├── 2018-08-26.txt ├── 2018-09-20.txt └── 2018-09-21.txt └── spec.md /README.md: -------------------------------------------------------------------------------- 1 | # dx-spec 2 | 3 | Issue-only repository for the development of a spec that would succeed JSDoc. 4 | -------------------------------------------------------------------------------- /journal.txt: -------------------------------------------------------------------------------- 1 | august 25, 2018 2 | 3 | thoughts on testable documentation 4 | 5 | i only have had a few projects with fully testable documentation - mostly just 6 | simple-statistics. that project has a lot of documentation. not sure if it's 7 | a gimmick or something worthwhile. documentation examples being testable is 8 | something that a lot of people write about wanting it, but there are some 9 | drawbacks. 10 | 11 | anyway, rustdoc does it 12 | 13 | https://doc.rust-lang.org/beta/rustdoc/documentation-tests.html 14 | 15 | i like rustdoc's approach more than the one i used for simple-statistics, which 16 | used jsdoctest. mostly because rustdoc just relies on examples completing 17 | or not completing, whereas jsdoc creates, sort of, assertions built into 18 | comments. which is a little easy for rustdoc to do because it has rust's built-in 19 | assert_eq method, but, what if i used console.assert 20 | 21 | ---- 22 | 23 | ```js 24 | import fs from 'fs'; 25 | import assert from "assert"; 26 | 27 | const about = './index.mjs'; 28 | const txt = `assert(score(10) === 'AA');` 29 | 30 | import(about).then(({ score }) => { 31 | const fn = new Function(['assert', 'score'], txt); 32 | fn.apply(undefined, [assert, score]); 33 | }).catch(e => { 34 | console.log('Documentation example failed'); 35 | }); 36 | ``` 37 | 38 | this is kind of neat. does similar stuff to rustdoc. to make it real it 39 | would need to get the ability to detect globals like 'score' so it can import 40 | them, and also to maybe be able to run import on its own. maybe these should 41 | run in a vm. 42 | 43 | ------------------------------------------------------------------------------- 44 | ------------------------------------------------------------------------------- 45 | 46 | august 26, 2018 47 | 48 | do parameters need names? 49 | 50 | back to thinking about parameters. back in javascript... 1.0 or whatever, they 51 | were simpler. basically, they all had names. 52 | 53 | now, this is also not that simple. parameter names aren't necessarily informative. 54 | builtins like Math.sin don’t even have them, in the 'native' stringification 55 | of those functions. 56 | 57 | but anyway, back in the day, we almost always had parameter names. but now there 58 | are forms like `foo({ a }) {}` where the first parameter doesn't have a name. 59 | we get 'a' property out of it but the parameter isn't called a. 60 | 61 | documentation.js was kind of awkward about this, always calling those $0 and $1 62 | and so on, for what spot they played in the function. 63 | 64 | also i think in a lot of cases, parameters don't really _need_ a name. a function 65 | like 66 | 67 | export function luminance(a, b) { 68 | const l1 = Math.max(a, b); 69 | const l2 = Math.min(a, b); 70 | return (l1 + 0.05) / (l2 + 0.05); 71 | } 72 | 73 | why would the documentation want to say 'a', other than as a way to permalink 74 | to it? maybe like luminanceValue is better. i just wonder about this because 75 | it's not like you have to call luminance(a = 10, b = 20), you always just 76 | say luminance(10, 20). 77 | 78 | if names were optional you maybe could document this like 79 | 80 | --- 81 | 82 | Get the contrast ratio between two relative luminance values 83 | 84 | - Parameters 85 | 1. luminance value 86 | 2. another luminance value 87 | - Returns: contrast ratio 88 | 89 | --- 90 | 91 | what if nesting lists enabled documentation to have multiple signatures? 92 | 93 | 94 | --- 95 | 96 | - Set an attribute in this selection 97 | - Parameters 98 | 1. attribute name (string) 99 | 2. value (any) 100 | - Returns: the selection 101 | - Get an attribute in this selection 102 | - Parameters 103 | 1. attribute name (string) 104 | - Returns: the value of that attribute 105 | 106 | ------------------------------------------------------------------------------- 107 | 108 | Sept 20 109 | 110 | On runtime documentation access 111 | 112 | Runtime documentation access is basically when you can type 113 | and get documentation inline. 114 | 115 | ┌────────────────────────────┐ 116 | │[function] │ 117 | │ │ 118 | │A scale type that smoothly │ 119 | │maps from an input domain │ 120 | │into an output range. │ 121 | └*───────────────────────────┘ 122 | d3.scaleLinear 123 | 124 | This is a sort of holy-grail: from tern.js (http://ternjs.net/) 125 | to languageserver (https://langserver.org/) there are brilliant people 126 | and rich companies trying to implement this sort of thing, and it's 127 | just been hard. Tern didn't take off, and languageserver doesn't really 128 | work well outside of its home court, VSCode. 129 | 130 | my work - Observable - has really, really good autocompletion because 131 | it has direct access to runtime values. whereas other solutions 132 | tend to have to deal with abstract syntax trees and make a lot of inferences. 133 | 134 | so, anyway, can we actually show documentation inline? this would be super 135 | useful for my work - Observable - and I think it'd be pretty clutch. But 136 | it's kind of a tricky one. For example, let's say that we have a function with 137 | documentation like 138 | 139 | // add two numbers 140 | let add = (a, b) => a + b; 141 | 142 | There's no real way that we'd be able to get inline documentation from this 143 | unless the documentation tool 144 | 145 | 1. re-requested the JavaScript source code with CORS enabled 146 | 2. re-parsed it as an AST 147 | 3. and then was able to match the function it's looking at with the AST 148 | 149 | So having access to runtime values in this case doesn't really do anything for you. 150 | 151 | maybe i could write a transformation system that would look at that and transform it into something like 152 | 153 | let add = (a, b) => a + b; 154 | docMap.set(add, {description:'add two numbers'}); 155 | 156 | Could this be cool? Maybe, but then we'd have to think 157 | 158 | - when would someone actually publish this file? it'd be pretty inefficient 159 | so it'd be something they turn off in dists. i don't want to burden people 160 | with publishing modules like this. 161 | 162 | What if it's instead a runtime transform, like shimport ( https://github.com/Rich-Harris/shimport ) 163 | so basically it would eliminate step (3) from above - no need to match the AST with the function at hand. 164 | Which is a good win - that's the scariest step. 165 | 166 | 167 | ------------------------------------------------------------------------------- 168 | 169 | Sept 21 170 | 171 | i got caught up in documentation.js last night, and started on d11n this morning, and 172 | have made great, but early, progress. it feels like the right direction, to me. 173 | 174 | i think d11n should have a hosting component early on, so that it really gets used. 175 | 176 | but that does raise the question of where documentation should begin and end. for example, 177 | are we documenting 178 | 179 | 180 | - a git repository's contents? this is like 181 | circleci or travis - you react to git hooks 182 | 183 | - npm modules 184 | 185 | - something else entirely? 186 | 187 | 188 | and are we producing 189 | 190 | 191 | - readme.md or other markdown output 192 | 193 | - a website? 194 | 195 | 196 | this also brings up the concern of: 197 | 198 | 199 | - should dx be runnable without dependencies? 200 | 201 | - will we hit limits in configurability because of bleeding edge requirements? 202 | 203 | - how does this operate if it needs to basically be bundle.run and a documentation 204 | service, all in one? 205 | 206 | ------------------------------------------------------------------------------- 207 | 208 | i just realized: what about 209 | 210 | class A { 211 | // can foo be documented? 212 | static foo = 1; 213 | } 214 | 215 | Basically, with this approach - the one I've written in d11n so far - it 216 | can't. You can't type A.foo and get foo documentation because of limitations 217 | of the approach. This is also apparently a limitation of docstrings in python. 218 | -------------------------------------------------------------------------------- /journal/2018-08-26.txt: -------------------------------------------------------------------------------- 1 | august 26, 2018 2 | 3 | do parameters need names? 4 | 5 | back to thinking about parameters. back in javascript... 1.0 or whatever, they 6 | were simpler. basically, they all had names. 7 | 8 | now, this is also not that simple. parameter names aren't necessarily informative. 9 | builtins like Math.sin don’t even have them, in the 'native' stringification 10 | of those functions. 11 | 12 | but anyway, back in the day, we almost always had parameter names. but now there 13 | are forms like `foo({ a }) {}` where the first parameter doesn't have a name. 14 | we get 'a' property out of it but the parameter isn't called a. 15 | 16 | documentation.js was kind of awkward about this, always calling those $0 and $1 17 | and so on, for what spot they played in the function. 18 | 19 | also i think in a lot of cases, parameters don't really _need_ a name. a function 20 | like 21 | 22 | export function luminance(a, b) { 23 | const l1 = Math.max(a, b); 24 | const l2 = Math.min(a, b); 25 | return (l1 + 0.05) / (l2 + 0.05); 26 | } 27 | 28 | why would the documentation want to say 'a', other than as a way to permalink 29 | to it? maybe like luminanceValue is better. i just wonder about this because 30 | it's not like you have to call luminance(a = 10, b = 20), you always just 31 | say luminance(10, 20). 32 | 33 | if names were optional you maybe could document this like 34 | 35 | --- 36 | 37 | Get the contrast ratio between two relative luminance values 38 | 39 | - Parameters 40 | 1. luminance value 41 | 2. another luminance value 42 | - Returns: contrast ratio 43 | 44 | --- 45 | 46 | what if nesting lists enabled documentation to have multiple signatures? 47 | 48 | 49 | --- 50 | 51 | - Set an attribute in this selection 52 | - Parameters 53 | 1. attribute name (string) 54 | 2. value (any) 55 | - Returns: the selection 56 | - Get an attribute in this selection 57 | - Parameters 58 | 1. attribute name (string) 59 | - Returns: the value of that attribute 60 | -------------------------------------------------------------------------------- /journal/2018-09-20.txt: -------------------------------------------------------------------------------- 1 | On runtime documentation access 2 | ------------------------------- 3 | 4 | Runtime documentation access is basically when you can type 5 | and get documentation inline. 6 | 7 | ┌────────────────────────────┐ 8 | │[function] │ 9 | │ │ 10 | │A scale type that smoothly │ 11 | │maps from an input domain │ 12 | │into an output range. │ 13 | └*───────────────────────────┘ 14 | d3.scaleLinear 15 | 16 | This is a sort of holy-grail: from tern.js (http://ternjs.net/) 17 | to languageserver (https://langserver.org/) there are brilliant people 18 | and rich companies trying to implement this sort of thing, and it's 19 | just been hard. Tern didn't take off, and languageserver doesn't really 20 | work well outside of its home court, VSCode. 21 | 22 | my work - Observable - has really, really good autocompletion because 23 | it has direct access to runtime values. whereas other solutions 24 | tend to have to deal with abstract syntax trees and make a lot of inferences. 25 | 26 | so, anyway, can we actually show documentation inline? this would be super 27 | useful for my work - Observable - and I think it'd be pretty clutch. But 28 | it's kind of a tricky one. For example, let's say that we have a function with 29 | documentation like 30 | 31 | // add two numbers 32 | let add = (a, b) => a + b; 33 | 34 | There's no real way that we'd be able to get inline documentation from this 35 | unless the documentation tool 36 | 37 | 1. re-requested the JavaScript source code with CORS enabled 38 | 2. re-parsed it as an AST 39 | 3. and then was able to match the function it's looking at with the AST 40 | 41 | So having access to runtime values in this case doesn't really do anything for you. 42 | 43 | maybe i could write a transformation system that would look at that and transform it into something like 44 | 45 | let add = (a, b) => a + b; 46 | docMap.set(add, {description:'add two numbers'}); 47 | 48 | Could this be cool? Maybe, but then we'd have to think 49 | 50 | - when would someone actually publish this file? it'd be pretty inefficient 51 | so it'd be something they turn off in dists. i don't want to burden people 52 | with publishing modules like this. 53 | 54 | What if it's instead a runtime transform, like shimport ( https://github.com/Rich-Harris/shimport ) 55 | so basically it would eliminate step (3) from above - no need to match the AST with the function at hand. 56 | Which is a good win - that's the scariest step. 57 | -------------------------------------------------------------------------------- /journal/2018-09-21.txt: -------------------------------------------------------------------------------- 1 | i got caught up in documentation.js last night, and started on d11n this morning, and 2 | have made great, but early, progress. it feels like the right direction, to me. 3 | 4 | i think d11n should have a hosting component early on, so that it really gets used. 5 | 6 | but that does raise the question of where documentation should begin and end. for example, 7 | are we documenting 8 | 9 | 10 | - a git repository's contents? this is like 11 | circleci or travis - you react to git hooks 12 | 13 | - npm modules 14 | 15 | - something else entirely? 16 | 17 | 18 | and are we producing 19 | 20 | 21 | - readme.md or other markdown output 22 | 23 | - a website? 24 | 25 | 26 | this also brings up the concern of: 27 | 28 | 29 | - should dx be runnable without dependencies? 30 | 31 | - will we hit limits in configurability because of bleeding edge requirements? 32 | 33 | - how does this operate if it needs to basically be bundle.run and a documentation 34 | service, all in one? 35 | -------------------------------------------------------------------------------- /spec.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## What is dx? 4 | 5 | dx is a format for inline code documentation of the ECMAScript family of languages. 6 | It allows for people-oriented descriptions of what software is and what it does 7 | to complement and interact with processing-oriented code. 8 | 9 | dx annotations in code can be extracted to generate API documentation, documentation 10 | integrated into text editors, and more. 11 | 12 | ## Why is a spec needed? 13 | 14 | dx is a new format that intends to spur multiple compatible implementations. It also 15 | will be authored by many people, and needs strict rules to unambiguously set 16 | expectations for what formatted inputs will produce as output. 17 | 18 | # Preliminaries 19 | 20 | ## dx is a CommonMark superset 21 | 22 | Any valid CommonMark text is also valid dx. dx extends CommonMark syntax to add 23 | documentation-related features as well as specific guidance for the positioning 24 | of documentation comments amongst source code. 25 | 26 | ## dx builds on top of JavaScript syntax 27 | 28 | dx exists to describe JavaScript code as it is written, not to invent new 29 | features or overwrite existing syntax. For this reason you won't find 30 | "namespaces" or "public/private". dx will also validate against your code. 31 | For example, you can't have mismatching params in your code and comments. 32 | 33 | ```ts 34 | /* Incrementing cat naps 35 | * 36 | * - param: `catName` `string` The name of the cat. 37 | * - param: `howManyMore` `number` How many naps should the cat take? 38 | * - returns: `number` The total number of naps the cat will take. 39 | */ 40 | function takeMoreNaps(howManyMore) { 41 | // ... 42 | } 43 | ``` 44 | 45 | ``` 46 | Error: `takeMoreNaps` only has 1 param(s), but you described 2. 47 | ``` 48 | 49 | ## dx (optionally) builds on top of Flow/TypeScript syntax 50 | 51 | dx can parse Flow and TypeScript code and will use your types as part of 52 | the generated output. 53 | 54 | ```ts 55 | /* Incrementing cat naps. 56 | * 57 | * - param: `howManyMore` `string` How many naps should the cat take? 58 | * - returns: The total number of naps the cat will take. 59 | */ 60 | function takeMoreNaps(howManyMore: number): number { 61 | // ... 62 | } 63 | ``` 64 | 65 | ``` 66 | Error: Cannot set type of `howManyMore` in comment when using Flow/TypeScript. 67 | ``` 68 | 69 | # Comments 70 | 71 | dx is most commonly written as the content of code comments that spell out 72 | documentation for code. Comments are interpreted as documentation based 73 | on their placement within source code. 74 | 75 | ```js 76 | // crashes the system 77 | function crashTheSystem() {/* … */} 78 | ``` 79 | 80 | dx supports all [JavaScript comment styles]: multi-line comments, single-line comments, 81 | and with or without leading `*` marks in each row. The following are equivalent: 82 | 83 | ```js 84 | // Count wobbles 85 | 86 | /* 87 | * Count wobbles 88 | */ 89 | 90 | /* Count wobbles */ 91 | 92 | /* 93 | Count wobbles 94 | */ 95 | ``` 96 | 97 | **Differences**: Unlike JSDoc, comments do not need to start with `/**` and 98 | can be single-line C-style comments. 99 | 100 | # Structure 101 | 102 | ## Tags 103 | 104 | dx documentation includes structured, tagged content that describes 105 | specific attributes of source code. The tags in a documentation comment are represented 106 | in a backwards-compatible way to CommonMark lists and a format inspired by 107 | [mdconf]. A tag is a list item in which the first word ends with a `:` character. 108 | For example: 109 | 110 | ```md 111 | - param: `teamName` `string` 112 | - returns: `string` the team's name 113 | ``` 114 | 115 | **Diferences**: Unlike JSDoc, tags do not start with `@` and instead follow 116 | Markdown's list syntax. 117 | 118 | ## Examples 119 | 120 | CommonMark code blocks are treated as examples: 121 | 122 | ```js 123 | /* 124 | * Starts the dance party. 125 | * 126 | * ```js 127 | * initDanceParty() 128 | * ``` 129 | */ 130 | ``` 131 | 132 | If you want to add a description to the example, you can use CommonMark 133 | [info strings]. 134 | 135 | ```js 136 | /* 137 | * Starts the dance party. 138 | * 139 | * ```js Turning it up to 11. 140 | * initDanceParty({ turnItUpTo: 11 }) 141 | * ``` 142 | */ 143 | ``` 144 | 145 | ### References 146 | 147 | [mdconf]: https://github.com/tj/mdconf 148 | [info strings]: http://spec.commonmark.org/0.28/#info-string 149 | [JavaScript comment styles]: https://tc39.github.io/ecma262/#sec-comments 150 | --------------------------------------------------------------------------------