# Leafdoc **Repository Path**: mirrors_leaflet/Leafdoc ## Basic Information - **Project Name**: Leafdoc - **Description**: A lightweight NaturalDocs-like LeafletJS-style documentation generator - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: gh-pages - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-09 - **Last Updated**: 2025-06-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Leafdoc Leafdoc (or 🍂doc for short) is a NaturalDocs- and JSdoc-like documentation generator. Leafdoc's goals are to help produce documentation which is: * **Concise**: If you need half a page to describe what a function does, then Leafdoc is probably not for you. * **Non-intrusive**: Allow devs to write the minimum possible amount of documentation lines. A two-line function shouldn't need 15 lines of docs. * **Narrative**: Forget about exhaustive code introspection, and focus into providing freeform human-readable explanations and per-class code examples using Markdown to do the heavy lifting. * **Language-agnostic**: Designed with Javascript in mind (and its dozens of ways of doing class inheritance or defining methods), Leafdoc doesn't parse your source code, just the comments. ## Try See [Leafdoc's own documentation as generated by Leafdoc](https://github.com/Leaflet/Leafdoc/blob/gh-pages/Leafdoc.md), or the [Leaflet documentation as generated by Leafdoc](http://leafletjs.com/reference-1.6.0.html). ### Try it yourself ```sh git clone [...] npm install npm test ``` You will find a `Leafdoc.html` file. Open that file in a web browser, and you'll see Leafdoc's own documentation. ## Command-line usage ```sh npm install leafdoc node_modules/.bin/leafdoc -t node_modules/leafdoc/templates/basic -o documentation.html src ``` See [Leafdoc's own documentation](http://leaflet.github.io/Leafdoc/Leafdoc.html) for a reference of available parameters. ## Write The syntax is pretty much the tried-and-true directives-in-comment-blocks from JSdoc, NaturalDocs and a gazillion others. But instead of an `@` symbol, Leafdoc uses a leaf: ```js /* * 🍂method addDir: this * 🍂param dirname: String * 🍂param extension: String * * Recursively scans a directory, and parses any files that match the given `extension` */ ``` Leafdoc was designed with compactness in mind, so it accepts comment blocks consisting of adjacent `//` comment lines, and a shorthand syntax for function/method parameters. This is equivalent to the example just above: ```js // 🍂method addDir (dirname: String, extension: String): this // Recursively scans a directory, and parses any files that match the given `extension` ``` If you need to be even *more* compact, use a semicolon (`;`) to put several directives in the same line: ```js // 🍂namespace Math; 🍂method sum(a: Int, b: Int): Int ; Returns the sum of two numbers ``` ### Valid directives * `🍂class` and `🍂namespace` should be at the top of your files. They define the context of the rest of the directives. A namespace can be used in more than one file (for example, when plugging more functionality to an existing class). * `🍂example` lets some space to demonstrate how the class / namespace is meant to be used. * `🍂section` allows you to group several functions, events, methods or options together, thematically. You may need to have sections without an explicit name to add stuff to the default section. * Methods, functions, options, etc are a generic thing internally named "documentable": * `🍂method` * `🍂function` * `🍂factory` * `🍂constructor` * `🍂destructor` * `🍂option` * `🍂event` * `🍂example` * `🍂property` * Functions/methods/factories can have parameters, specified with `🍂param (name)`, `🍂param (name): (type)` or inline (see below). * Classes, namespaces and documentables can have `🍂aka (alternative name)`, (short for Also Known As). This allows to create links to the same thing using different names. * Anything can have several `🍂comment`s, explaining the thing. `🍂comment` directives can be implicit, because any (non-empty) line without an explicit directive equals to a comment. * If a function (or any other documentable) has several alternative uses, use the `🍂alternative` directive after to re-defining the documentable, e.g.: ``` /* 🍂method on(type: String, fn: Function): this Adds the function `fn` as an event handler for the `type` event. 🍂alternative 🍂method on(types: [String], fn: Function): this Given an array of event types (strings), attaches `fn` as an event handler to each of them. */ ``` In this example, the two alternatives are `on(type, fn)` and `on(fnMap)`. They will be shown as two different documentables. * `🍂inherits [parent]` means that a class or namespace inherits all documentables from another class or namespace. * `🍂relationship [relationshiptype] [namespace] ()` is specific to thegraphviz * `🍂uninheritable` is applied only to *sections*, and hides them from the * `🍂miniclass [name] [(parentname)]` defines a class/namespace that shall display *inside* the parent namespace (specified between parentheses); most useful for very concide classes/data structs that are useful only within the context of the parent namespace. ### Shorthand syntax Any documentable has the same syntax: name, optional required flag, optional parameters, optional type / return type/value, default value. ``` name[?] [ ( params ) ] [: type] [= default] ``` where `params` is ``` name[?] [ : type ] [ , name[?] [ : type ] [ , name[?] [ : type ] ... ] ] ``` and where `name` is a valid unicode identifier, or an ellipsis (`…`). `type` and `default` are freeform and can have spaces. Which means the following are possible: ``` An option usually has a type and a default value: 🍂option enabled: Boolean = true But we can omit the default value: 🍂option enabled: Boolean Or omit just the data type: 🍂option enabled = true Or even just say there is an option: 🍂option enabled A function with a return type: 🍂function get: String A function with one parameter: 🍂function get(id: Int): String Or two: A function with one parameter: 🍂function sum(a: Int, b: Int): Int The last function can also be written without the parameters shorthand: 🍂function sum: Int 🍂param a: Int 🍂param b: Int Use an interrogation sign to specify a parameter as optional: 🍂function update(force? : Boolean): null Use ellipsis to mark optional parameters: 🍂function update(…): null ``` You can specify everything (name, optional, params, type, default), but no documentable uses them all in the templates. The usual schema is: | | Params | Type | Default | | ----------- | ------ | ---- | ------- | | example | | | | | option | | X | X | | property | | X | X | | event | | X | | | method | X | X | | | function | X | X | | | factory | X | | | | constructor | X | | | | factory | X | | | ### Relationships format Relationships are meaningful for class diagrams. They correspond with the UML class diagram The syntax is: ``` 🍂relationship type namespace [ ,cardinalityFrom [ ,cardinalityTo [ ,label ]]] ``` The following relationship `type`s are implemented for display in the `graphviz-class-diagram` templates: - `associated` - `implements` - `dependsOn` - `aggregationOf` - `compositionOf` Note that class inheritance is a separate directive (`🍂inherits`) . `namespace` must be an identifier; `cardinalityFrom` and `cardinalityTo` must not have commas in them. Some examples of how `🍂relationship` works: ``` 🍂namespace ConcreteClass 🍂relationship implements AbstractClass ``` ``` 🍂namespace Classroom 🍂relationship aggregationOf Student, 0..n, 1..n 🍂relationship aggregationOf Teacher, 1, 0..n ``` ``` 🍂namespace Caller 🍂relationship associated Callee ,, calls ``` ### Output customization The output relies on a set of `handlebars` templates. By default, the ones in `templates/basic` will be used. In order to use another set of templates, pass `the `templateDir` option to the Leafdoc constructor, like so: ```js var l = new Leafdoc({templateDir: 'leaflet'}); ``` I will write no detailed docs on how to modify the templates. If you know some HTML and `handlebars`, just copy them and hack things away :-) ### Custom documentables Your code might have several things of the same kind, which you want to show in the same fashion as documentables. Maybe it's files, or icons, or you have 5 trivial sub-classes which only merit one line. You can define custom documentables by doing so: ```js var l = new Leafdoc(); l.registerDocumentable('icon', 'Available icons'); ``` Whenever you add a custom documentable, you'll need to create its `handlebars` template too! Failure to do so will throw an error when you are building your documentation. Your custom documentable will accept parameters, type, and default as the rest of documentables, and can follow the shorthand syntax. You will have to map parameters, type and default to something that makes sense for that documentable. For example, the template might map an icon's filename to the documentable's default: ``` 🍂icon happy = 'icons/happy.gif' A happy face ``` Also documentables can be inheritable or not. For example you have some entities in namespace which can be inherited. Pass `true` to third argument of [registerDocumentable](./Leafdoc.md#leafdoc-registerdocumentable) to make documentable inheritable: ```js var l = new Leafdoc(); l.registerDocumentable('field', 'Fields', true); ``` And later in your documentation: ``` 🍂field limit? = 5 A limit for query ``` ## Known gotchas * Leafdoc relies on some ugly per-module globals, so having more than one instance in your code (in the same process) might break things up. The use case for Leafdoc is to have just one instance when building docs for your code. ## Legalese Licensed under the GNU General Public License version 3 (or "GPL3"). Check the full text at https://www.gnu.org/licenses/gpl-3.0.html. ## Troubleshooting ### I'm using Debian and I cannot see the leaf character! Run `apt-get install fonts-symbola`. ### I cannot type 🍂 in my keyboard! (Linux only) Write this into a plain text file: ``` keycode 46 = l L l L U1F342 Lstroke lstroke ``` Then run `xmodmap name-of-the-file`. Now 🍂 is mapped to `AltGr+l`. Of course, you can always do `leafdoc.setLeadingCharacter('@');`, but that's boring.