Skip to content

Commit

Permalink
Merge pull request #6 from woocommerce/add/jsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
tomalec authored Jun 2, 2022
2 parents 0770268 + d6b87a2 commit fecfad5
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The packages here are too experimental or too Grow-specific to be shared Woo-wid

- [`/packages/js/generator-grow`](packages/js/generator-grow/README.md) - Yeoman Generator for extension repository boilerplate.
- [`/packages/js/storybook`](packages/js/storybook/README.md) - Storybook dependencies and basic scripts
- [`/packages/js/tracking-jsdoc`](packages/js/tracking-jsdoc/README.md) - `jsdoc` plugin to document Tracking Events in markdown

<p align="center">
<br/><br/>
Expand Down
84 changes: 84 additions & 0 deletions packages/js/tracking-jsdoc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# woocommerce-grow-tracking-jsdoc

JSDoc template to report Tracking events to markdown file.

## Usage

0. `npm i jsdoc` and configure jsdoc according to your source code, so the `npx jsdoc ./your/source/` runs successfully.
1. Install or link this package via npm
2. Add your `/TRACKING.md` template

```md
# Usage Tracking

Some nice general description.

<woocommerce-grow-tracking-jsdoc></woocommerce-grow-tracking-jsdoc>
```
3. Generate the docs
```sh
jsdoc -r your/source/files/ -t ./node_modules/woocommerce-grow-tracking-jsdoc
```



## Config

You may add any of the following properties to your JSDoc config (`.jsdocrc.json`) to change those default values:
```js
{
"templates": {
"woocommerce-grow-tracking-jsdoc": {
// Path to the markdown file to which the tracking events' docs should be added
"path": "TRACKING.md",
// Pattern to be used to match the content to be replaced. The groups are respectively: start marker, replaceable content, end marker.
"replacement": "(<woocommerce-grow-tracking-jsdoc(?:\\s[^>]*)?>)([\\s\\S]*)(<\\/woocommerce-grow-tracking-jsdoc.*>)"
}
}
```
Then make sure `jsdoc` uses it, by `jsdoc -r your/source/files/ -c .jsdocrc.json`.

## Emitters
If you would like to add some descriptions to `@fires` or `@emmits` tags, for example to specify what data is attached to the event, add `fires-description` to your plugins list:

```json
{
"plugins": [
// To be able to add descriptions to `@fires` & `@emmits`
"woocommerce-grow-tracking-jsdoc/fires-description"
],
// …
```


## Imported types

If your codebase uses TS-style of importing types `{import('foo').bar}`, you will most probably get an error, like:
```
ERROR: Unable to parse a tag's type expression for source file … Invalid type expression "import('foo').bar"
```
To mitigate that use a `jsdoc-plugin-typescript` plugin to skip those. `npm install --save-dev jsdoc-plugin-typescript` and add this to your config:
```js
{
"plugins": [
"jsdoc-plugin-typescript"
],
"typescript": {
"moduleRoot": "assets/source" // Path to your module's root directory.
}
// …
```

## `~` Alias

If your codebase uses a `.~` or `~` alias for the root directory, you may use `tilde-alias`.

```js
{
"plugins": [
"woocommerce-grow-tracking-jsdoc/tilde-alias",
"jsdoc-plugin-typescript"
],
//
```
21 changes: 21 additions & 0 deletions packages/js/tracking-jsdoc/fires-description.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* JSDoc plugin that allows to use descriptions for built-in `@fires` & `@emmits` tags.
*
* Overwrites the standard definition with `canHaveName: true` option,
* and tweaks `applyNamespace` to apply it only to `value.name`.
*/
const { applyNamespace } = require( 'jsdoc/name' );

exports.defineTags = function ( dictionary ) {
dictionary
.defineTag( 'fires', {
mustHaveValue: true,
canHaveName: true,
onTagged( doclet, tag ) {
doclet.fires = doclet.fires || [];
tag.value.name = applyNamespace( tag.value.name, 'event' );
doclet.fires.push( tag.value );
},
} )
.synonym( ' emmits' );
};
18 changes: 18 additions & 0 deletions packages/js/tracking-jsdoc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "woocommerce-grow-tracking-jsdoc",
"version": "0.0.1",
"description": "JSDoc template to report Tracking events to markdown file",
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/woocommerce/grow.git"
},
"author": "WooCommerce",
"license": "GPL-3.0-or-later",
"bugs": {
"url": "https://github.com/woocommerce/grow/issues"
},
"homepage": "https://github.com/woocommerce/grow#readme",
"peerDependencies": {
"jsdoc": "^3.6.10"
}
}
132 changes: 132 additions & 0 deletions packages/js/tracking-jsdoc/publish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
const fs = require( 'jsdoc/fs' );
const env = require( 'jsdoc/env' );
const path = require( 'jsdoc/path' );

/** @module publish */

// RegExp used to match the replacement. The groups are respectively: start marker, replacable content, end marker.
const defaultReplacementRegex = /(<woocommerce-grow-tracking-jsdoc(?:\s[^>]*)?>)([\s\S]*)(<\/woocommerce-grow-tracking-jsdoc.*>)/;

const disclaimerStart = `<!---
Everything below will be automatically generated by \`woocommerce-grow-tracking-jsdoc\`.
Do not edit it manually!
-->`;
const disclaimerEnd = `<!---
End of \`woocommerce-grow-tracking-jsdoc\`-generated content.
-->
`;

/**
* Creates MD link to the line of code, where the symbol was defined.
*
* @param {Object} symbol JSDoc symbol object.
* @param {string} readmeDir The absolute path to the directory of README file.
*/
function getLineLink( symbol, readmeDir ) {
const localLocation =
path.relative(
readmeDir,
path.join( symbol.meta.path, symbol.meta.filename )
) +
'#L' +
symbol.meta.lineno;
return `[\`${ symbol.name }\`](${ localLocation })`;
}

/**
* Generate documentation output.
*
* @param {Object} data - A TaffyDB collection representing
* all the symbols documented in your code.
*/
exports.publish = function ( data ) {
const {
conf: {
templates: {
'woocommerce-grow-tracking-jsdoc': {
path: readmePath = 'TRACKING.md',
replacement,
} = {},
} = {},
} = {},
pwd,
} = env;

const readmeDir = path.join( pwd, path.dirname( readmePath ) );
const replacementRegex = replacement
? new RegExp( replacement )
: defaultReplacementRegex;

let mdResult = '';

data( { kind: 'event' } )
.order( 'name' )
.each( ( symbol ) => {
// Build the event title with the link to its source.
mdResult += `\n### ${ getLineLink( symbol, readmeDir ) }\n`;
// description
mdResult += ( symbol.description || '' ) + '\n';
// Build properites table.
if ( symbol.properties ) {
mdResult += `#### Properties
| name | type | description |
| ---- | ---- | ----------- |\n`;
symbol.properties.forEach( ( property ) => {
// Escape `|` for markdown table.
const type = property.type.parsedType.typeExpression.replace(
/\|/g,
'\\|'
);
const description = property.description.replace(
/\|/g,
'\\|'
);
mdResult += `\`${
property.name
}\` | \`${ type }\` | ${ description.replace(
/\s*\n\s*/g,
' <br> '
) }\n`;
} );
}

// Find all places that fires the event.
const emitters = new Map();
// TaffyDB#has is buggy https://github.com/typicaljoe/taffydb/issues/19, so let's filter it manually.
data( { fires: { isArray: true } } ).each( ( emitter ) => {
const firesCurrent = emitter.fires.filter(
( fires ) => fires.name === 'event:' + symbol.name
);
if ( firesCurrent.length ) {
emitters.set( emitter, firesCurrent );
}
} );
if ( emitters.size ) {
mdResult += `#### Emitters\n`;
emitters.forEach( ( fires, emitter ) => {
mdResult += '- ' + getLineLink( emitter, readmeDir );
if ( fires.length > 1 ) {
mdResult +=
`\n` +
fires
.map(
( evt ) => ` - ${ evt.description || '' }`
)
.join( '\n' );
} else if ( fires[ 0 ] && fires[ 0 ].description ) {
mdResult += ' ' + fires[ 0 ].description;
}
mdResult += '\n';
} );
}
} );

let readme = fs.readFileSync( readmePath, 'utf8' );
// Replace the marker with generated content.
readme = readme.replace(
replacementRegex,
`$1\n${ disclaimerStart }\n${ mdResult }\n${ disclaimerEnd }$3`
);
fs.writeFileSync( readmePath, readme, 'utf8' );
return mdResult;
};
5 changes: 5 additions & 0 deletions packages/js/tracking-jsdoc/tilde-alias.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.handlers = {
beforeParse( e ) {
e.source = e.source.replace( /(import\(["'])\.?~\//g, `$1` );
},
};

0 comments on commit fecfad5

Please sign in to comment.