![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
doc-enforcer
Advanced tools
Enforce documentation in github-flavored readme files to eliminate oral tradition & guarantee support for the next dev
This is a way to guarantee plain, human-readable, deep-linkable descriptions exist in github-compatible READMEs for arrays of strings you provide in one of 3 patterns:
Attach these to tests to guarantee documentation, as the check fails until all items are documented.
See examples section below for ideas.
Table of Contents |
---|
require('doc-enforcer')([ //a single function exported
//which you supply an array of objects:
{ // each object often called a "pattern"
name:"" ,// what to title this doc section
markdownPath:"" ,// which md file this doc should go in
// note these sections are <!--delimited-->, so N patterns
// may exist in one file, in any order.
// Just don't add anything except the requested
// descriptions inside the delimiters,
// or they will disappear on rebuild.
verbose:true ,// (default: true)
// true = log out success & fail; false = only fails
optional:false ,// (default: false)
// false = throw on missing doc; true = don't
// extract a string [] 1 of 3 ways:
// 1) either from js files by globbing, ASTing, & selecting:
ast:{
fileGlob:"",// string passed to npmjs.org/glob to fetch js files
selector:"",// string passed to npmjs.com/esquery to target js
// this is how eslint works; plug your code into
// astexplorer.net or estools.github.io/esquery
// to understand how to make these
property:"",// string passed to npmjs.com/lodash-getpath
// to extract string []
// from the AST nodes selected above
// this way you can select a prop
// from all items in an [] (in an [], in an [],...)
},
// 2) or dynamically if what you want to document isn't in js:
customInput({glob,fs}){
// note you're given glob & fs
// since you'll likely be manipulating files
return anArrayOfStrings // or a promise for one
},
// 3) or directly:
customInput:['a','b','c',...],
// if you want to customize how to format the doc
// there are some presets:
customOutput:'ul|ol|table', //default is ul
// or a fully custom option:
customOutput(matchedDescriptions/* = {
[name]:{
name, - plain string of item supplied
formattedName, - .md form for safe anchoring & extraction
description, - plain content of description
formattedDescription, - .md form for safe extraction
slug, - pattern + name for canonical referencing in a file
linkSafeSlug, - formatted slug for github-safe anchoring
isBlank, - whether doc is empty
[ast context if available] - (if you gathered items this way)
}
,...
}
*/){
// in case you prefer the doc to look a very specific way,
// return 1 string here to write to the markdown file.
// Log out the given param to see what you have to work with.
// Some form of given formattedName and formattedDescription
// per item needs to exist in the returned string
// to preserve data across rebuilds.
// It should let you know if it cannot find them.
},
},
//...add as many pattern objects as you'd like
])
In case that wasn't clear, check the examples.
Say you wanted to require readme info for keys on all module.export
ed objects, like:
module.exports = {
something,
somethingElse,
etcetera,
soManyThings,
}
That could look like:
require('doc-enforcer')([{
name:"Module exports",
markdownPath:"./readme.md",
ast:{
fileGlob:`${__dirname}/**/wherever/they/are/**.js`,
selector:"AssignmentExpression[left.object.name='module'][left.property.name='exports'][right.type='ObjectExpression']",
property:"right.properties[].key.name",
},
}])
Say you wanted to guarantee new top level folders had mutually exclusive reasons for existing. That might look like:
require('doc-enforcer')([{
name:"Top Level Folders",
markdownPath:"./readme.md",
customInput:({glob,fs})=>glob.sync(`${__dirname}/../*/`),
}])
Say your codebase makes CSVs for others to use and you wanted to document one's header. Parse the file, extract your points of interest, return an array.
require('doc-enforcer')([{
name:"That CSV",
markdownPath:"./test.md",
customInput:({glob,fs})=>
fs.readFileSync(`${__dirname}/test.md`).toString()
.split('\n').shift().split(/\W/)
}])
Say you wanted a simple text explanation for each column added to the db. That could simply look like this:
require('doc-enforcer')([{
name:"db-schema",
markdownPath:"./readme.md",
async customInput({glob,fs}){
return new Promise((good,bad)=>{
var mysql = require('mysql');
var connection = mysql.createConnection({
user : 'x',
password : 'x',
});
connection.connect();
connection.query(`
SELECT column_name,table_name
from information_schema.columns
where table_schema='test'
`,
function (error, results, fields) {
if (error) throw error;
good(results.map(x=>`${x.table_name}.${x.column_name}`))
connection.end();
});
})
},
customOutput:'table',
}])
If you also wanted each table to have a description, you'd need to alter the query to return a row per table. Or, if you wanted it to look fancier with type info & other things, see below.
If you wanted to customize the output, like grouping columns by table or adding type info,
you might make customInput
& customOutput
functions, and store some info for reuse:
var mysql=require('mysql')
var _=require('lodash')
var remember //store here things from customInput for customOutput
require('doc-enforcer')([{
name:"db-schema",
markdownPath:"./test.md",
async customInput({glob,fs}){
return new Promise((good,bad)=>{
var mysql = require('mysql');
var connection = mysql.createConnection({
user : 'x',
password : 'x',
});
connection.connect();
connection.query(`
select table_name,column_name,column_type
from information_schema.columns
where table_schema='test'
/*
note you'll need the same # of rows returned
as descriptions to keep
*/
union
select table_name,'',''
from information_schema.tables
where table_schema='test'
`,
function (error, results, fields) {
if (error) throw error;
var tokenize=x=>`${x.table_name}.${x.column_name}`
remember=_.keyBy(results,tokenize)//for customOutput
good(results.map(tokenize))
connection.end();
});
})
},
customOutput(matches){
return `<table>${_(matches)
.map(x=>{
var [table_name,column_name]=x.name.split('.')
return {...x
,table_name
,column_name
,...remember[x.name]
}
})
.groupBy('table_name')
.map((items,tableName)=>{
var {tables:[table],columns} = _.groupBy(items,x=>x.column_name?'columns':'tables')
return `<tr alt="item:${table.slug}"><td>
${table.formattedName
.replace(`.<`,'<')
} - ${table.formattedDescription}
<ul>${
columns.map(col=>`
<li alt="item:${col.slug}">${col.formattedName
.replace(`<code>${table.name}`,'<code>')
} <i>[${col.column_type}]</i> - ${col.formattedDescription}</li>`
).join('')
}
</ul>
</td></tr>`
})
.join('\n')}</table>`
},
}])
(Or use something like db-linter!)
.eslint
file
in each folder that has all the files that rule should apply to,
but then your folder structure is bending to a lint rule, which seems backwards,
and that still will not cover cases for things not literally in your codebase.FAQs
Enforce documentation in github-flavored readme files to eliminate oral tradition & guarantee support for the next dev
We found that doc-enforcer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.