Skip to content

Commit

Permalink
Update leafmodule preventing module duplication
Browse files Browse the repository at this point in the history
Update leafmodule tag to prevent current behaviour of module
duplication due to creating multiple module tage with the same
name.

Update leafmodule tag to instead add memberof tags to all relevant
jsdoc comments in a given file, thus adding all documented symbols
to the desired module without duplication.

Resolves following issues discussed in jsdoc:
    - jsdoc/jsdoc#515
    - jsdoc/jsdoc#1002
  • Loading branch information
jimbob3806 committed Jun 28, 2023
1 parent b57985a commit 307c12d
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 14 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<p align="center">
<img width="605" src="https://img.shields.io/badge/submodule-changelog-inactive?style=for-the-badge&labelColor=BAC99C&color=779966&logo=data:image/png;base64,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">
</p>

# Change Log

All notable changes to this project will be documented in this file.

## [1.2.0] - 2017-03-15

Here we would have the update steps for 1.2.4 for people to follow.

Add link to browse at this commit and view tag on github

### Added

### Changed

- [PROJECTNAME-ZZZZ](http://tickets.projectname.com/browse/PROJECTNAME-ZZZZ) PATCH Drupal.org is now used for composer.

### Fixed

- [PROJECTNAME-TTTT](http://tickets.projectname.com/browse/PROJECTNAME-TTTT) PATCH Add logic to runsheet teaser delete to delete corresponding schedule cards.
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Submodule

A jsdoc plugin for quickly creating nested modules without explicitly having to write a module name such as `path/to/file` reflective of the location of the module in the src directory.
A jsdoc plugin for quickly creating nested modules or modules declared over many files without explicitly having to write a module name such as `path/to/file` reflective of the location of the module in the src directory, and without causing duplicate doclets as a result of having multiple files tagged with the same module name.

![](https://img.shields.io/github/license/blameitonyourisp/submodule?style=for-the-badge&labelColor=181b1a&color=779966) ![](https://img.shields.io/github/package-json/v/blameitonyourisp/submodule/master?style=for-the-badge&labelColor=181b1a&color=779966)

Expand Down Expand Up @@ -101,17 +101,32 @@ If a name is provided, then the `@submodule` behaviour of calculating a module p

### Leafmodule Tag

The `@leafmodule` tag can be used in exactly the same manner as the standard `@submodule` tag, however when calculating the module name for the file, the plugin will ignore the basename of the file. This may be useful if you wish to create modules that are declared over multiple files with less nesting. The `@submodule` tag is equivalent to the `@leafmodule` tag in files whose name is listed in the ignore array of the [submodule configuration](#configuration).
The `@leafmodule` tag offers a way to split modules over multiple files with reduced nesting by adding `@memberof` tags to all jsdoc comments in a file based on the module name calculated by submodule. The `@leafmodule` tag will ignore single line jsdoc comments such as type annotations, and jsdoc comments with an existing memberof tag, allowing you to use override module membership with an explicit comment `@memberof` tag as is already possible with the vanilla jsdoc `@module` tag. The `@leafmodule` tag can be used in exactly the same manner as the standard `@submodule` tag; the tag may be used with or without a custom name, however when using `@leafmodule` without a name, the calculated module name will ignore the basename of the file. This may be useful if you wish to create modules that are declared over multiple files with less nesting, and with no duplication of methods in the generated documentation due to using the same `@module` tag at the top of two or more files as discussed in [jsdoc issue #515](https://github.com/jsdoc/jsdoc/issues/515) and [jsdoc issue #1002](https://github.com/jsdoc/jsdoc/issues/1002).

```javascript
/**
* The leafmodule tag causes submodule to ignore the basename of the file when
* calculating the module name. For example, the following two tags may be
* considered equivalent in a file with path "src/path/to/file.js" where the
* jsdoc config takes "src" as an include directory.
* calculating the module name. Calculated module name is then added as jsdoc
* memberof tag to every jsdoc comment in the file, excluding single line jsdoc
* comments such as type annotations, and jsdoc comments with an existing
* memberof tag (i.e. as with the vanilla jsdoc module tag, it is possible to
* override the set module with a memberof tag on the desired comment). For
* example, in a file with path "src/path/to/file.js" where the jsdoc config
* takes "src" as an include directory, the leafmodule tag would be equivalent
* to adding the following memberof tag to all jsdoc comments in that file.
*
* @leafmodule
* @module path/to
* @memberof module:path/to
*/

/**
* Or, the name field of the leafmodule tag allows you to specify which module
* name is used to tag each doclet with the memberof tag, therefore the following
* leafmodule tag is equivalent to adding the following memberof tag to every
* jsdoc comment in a given file.
*
* @leafmodule custom/name
* @memberof module:custom/name
*/
```

Expand Down
2 changes: 1 addition & 1 deletion dist/bundle.min.cjs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"use strict";var e=require("jsdoc/env"),a=require("path");function n(e,n){this.conf.submodule??={};const{pwd:t,conf:{submodule:{roots:s,ignore:o},source:i}}=this,c=Object.entries(s||{}).sort(((e,a)=>a[1].split("/").length-e[1].split("/").length));for(const e of i.include)c.push(["",e]);let l=a.relative(t,e.meta.path);for(const e of c){const[a,n]=e;if(l.includes(n)){l=""!=a?l.replace(n,a):l.replace(new RegExp(`${n}/?`),a);break}}const u=e.meta.filename.match(/^.+(?=\..+$)/)[0],d=n?.value?.name||(""===l?u:(o||["index"]).includes(u)||this.leaf?l:`${l}/${u}`);Object.assign(e,{kind:"module",name:d})}exports.defineTags=a=>{const t={canHaveType:!0,canHaveName:!0,isNamespace:!1,mustHaveValue:!1,mustNotHaveDescription:!0,mustNotHaveValue:!1};a.defineTag("submodule",{...t,onTagged:n.bind(e)}),a.defineTag("leafmodule",{...t,onTagged:n.bind({...e,leaf:!0})})};
"use strict";var e=require("jsdoc/env"),n=require("path");function s(e,s){this.conf.submodule??={};const{pwd:o,conf:{submodule:{roots:t,ignore:a},source:c}}=this,m=Object.entries(t||{}).sort(((e,n)=>n[1].split("/").length-e[1].split("/").length));for(const e of c.include)m.push(["",e]);let i=n.relative(o,e.meta.path);for(const e of m){const[n,s]=e;if(i.includes(s)){i=""!=n?i.replace(s,n):i.replace(new RegExp(`${s}/?`),n);break}}const l=e.meta.filename.match(/^.+(?=\..+$)/)[0],r=s?.value?.name||(""===i?l:(a||["index"]).includes(l)||this.leaf?i:`${i}/${l}`);this.leaf?process.env.SUBMODULE=r:Object.assign(e,{kind:"module",name:r})}const o={fileBegin:()=>{process.env.SUBMODULE=""},fileComplete:()=>{process.env.SUBMODULE=""},jsdocCommentFound:e=>{if(!e.comment.match(/@memberof/)&&!e.comment.match(/\/\*\*.*\*\//)&&""!=process.env.SUBMODULE){const n=` * @memberof module:${process.env.SUBMODULE}`;e.comment=e.comment.replace(/\s*\*\/$/,`\n${n}\n */`)}}};exports.defineTags=n=>{const o={canHaveType:!0,canHaveName:!0,isNamespace:!1,mustHaveValue:!1,mustNotHaveDescription:!0,mustNotHaveValue:!1};n.defineTag("submodule",{...o,onTagged:s.bind(e)}),n.defineTag("leafmodule",{...o,onTagged:s.bind({...e,leaf:!0})})},exports.handlers=o;
2 changes: 1 addition & 1 deletion dist/tokei.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"schemaVersion":1,"label":"lines written","message":"2.1k","style":"for-the-badge","labelColor":"181b1a","color":"779966"}
{"schemaVersion":1,"label":"lines written","message":"2.2k","style":"for-the-badge","labelColor":"181b1a","color":"779966"}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@13ms/submodule",
"version": "1.1.1",
"version": "1.2.0",
"description": "A jsdoc plugin for automatically creating nested submodules according to file path",
"type": "module",
"main": "dist/bundle.min.cjs",
Expand Down
23 changes: 23 additions & 0 deletions sample/includeA/leafmodule/feature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @leafmodule
*/

/**
* Leafmodule feature function with private access and inner scope
*
* @function
* @private
* @inner
*/
const leafmoduleFeature = () => {}

/**
* ModuleC feature function with public access and static scope, declared in
* leafmodule file with an explicit `@memberof` tag
*
* @function
* @memberof module:moduleC/feature
* @public
* @static
*/
const externalModuleFunction = () => {}
7 changes: 7 additions & 0 deletions sample/includeA/leafmodule/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Leafmodule index file method(s) in this module should not be duplicated like
* they would be if multiple files in jsdoc had the same `@module` tag at the
* top - path leafmodule/index.js
*
* @submodule
*/
27 changes: 26 additions & 1 deletion src/plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ import env from "jsdoc/env"
import { onTagged } from "./onTagged.js"

// @body
// jsdoc plugin handlers, see <https://jsdoc.app/about-plugins.html> for more
// details
const handlers = {
// set empty string environment variable at start and end of file parse
fileBegin: () => { process.env.SUBMODULE = "" },
fileComplete: () => { process.env.SUBMODULE = "" },
// if "SUBMODULE" environment variable is set, add memberof tag to all jsdoc
// comments in file according to value stored in environment variable (note
// that it is not possible to add memberof tag to doclet on the "newDoclet"
// event since comment scope value may be overridden given that without
// a memberof value, the doclet will be considered in global scope, and
// therefore tags such as @inner will be ignored)
jsdocCommentFound: (event) => {
// ignore comments with existing memberof tags or single line comments
if (event.comment.match(/@memberof/)) { return }
if (event.comment.match(/\/\*\*.*\*\//)) { return }
if (process.env.SUBMODULE != "") {
// generate tagline and replace all trailing whitespace and end of
// comment characters with the generated tag
const tag = ` * @memberof module:${process.env.SUBMODULE}`
event.comment = event.comment.replace(/\s*\*\/$/, `\n${tag}\n */`)
}
}
}

// standard tag definition for custom jsdoc plugin, see
// <https://jsdoc.app/about-plugins.html> for more details
const defineTags = dictionary => {
Expand All @@ -45,4 +70,4 @@ const defineTags = dictionary => {
}

// @exports
export { defineTags }
export { handlers, defineTags }
7 changes: 6 additions & 1 deletion src/plugin/onTagged.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ function onTagged(doclet, tag) {
: (ignore || ["index"]).includes(basename) ? dirname
: this.leaf ? dirname // use only dirname if leafmodule
: `${dirname}/${basename}`) // attach basename if submodule
Object.assign(doclet, { kind: "module", name })

// if file is leafmodule tagged, set environment variable in order to tag
// rest of file doclets with correct doclet.memberof tag, otherwise mark
// doclet (file) as module file
if (this.leaf) { process.env.SUBMODULE = name }
else { Object.assign(doclet, { kind: "module", name }) }
}

// @exports
Expand Down
12 changes: 9 additions & 3 deletions src/plugin/onTagged.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,21 @@ describe("onTagged", () => {
})

// test file marked as a leafmodule file which should be documented under
// the namespace module of the directory
test("leaf file", () => {
// the namespace module of the directory, and should set the "SUBMODULE"
// environment variable
test("leafmodule", () => {
const env = { ...defaultEnv, leaf: true }
const doclet = { meta: {
path: "src/path/to",
filename: "file.js"
}}
// case A testing leafmodule in standard configuration
const name = "path/to"
onTagged.call(env, doclet, getTag())
expect(doclet).toEqual(getDoclet(doclet, name))
expect(process.env.SUBMODULE).toBe(name)
// case B testing leafmodule with a custom module nam
const customName = "custom/leafmodule/name"
onTagged.call(env, doclet, getTag(customName))
expect(process.env.SUBMODULE).toBe(customName)
})
})

0 comments on commit 307c12d

Please sign in to comment.