From d86fa73749e492d7fc0d289eb4909d1d7ffcc319 Mon Sep 17 00:00:00 2001 From: Dan Bornstein Date: Thu, 28 Mar 2024 13:18:24 -0700 Subject: [PATCH] New script `reflow-jsdoc`. --- CHANGELOG.md | 3 +- .../lib/bashy-node/node-project/reflow-jsdoc | 193 ++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100755 scripts/lib/bashy-node/node-project/reflow-jsdoc diff --git a/CHANGELOG.md b/CHANGELOG.md index e1d267c..a4257a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ Breaking changes: * None. Other notable changes: -* None. +* `bashy-node`: + * New script `node-project reflow-jsdoc`. ### v2.10 -- 2024-03-14 diff --git a/scripts/lib/bashy-node/node-project/reflow-jsdoc b/scripts/lib/bashy-node/node-project/reflow-jsdoc new file mode 100755 index 0000000..4f43fdd --- /dev/null +++ b/scripts/lib/bashy-node/node-project/reflow-jsdoc @@ -0,0 +1,193 @@ +#!/bin/bash +# +# Copyright 2022-2024 the Lactoserv Authors (Dan Bornstein et alia). +# SPDX-License-Identifier: Apache-2.0 + +. "$(dirname "$(readlink -f "$0")")/_init.sh" || exit "$?" + + +# +# Argument parsing +# + +define-usage --with-help $' + ${name} [ ...] + + Reflows all JSDoc comments in the source, in a way that is imperfect yet + sufficiently decent to be reasonably human-vetted. +' + +process-args "$@" || exit "$?" + + +# +# Helper functions +# + +# Awk script which performs reflowing on a single file. +REFLOW_SCRIPT=' +# Start of doc comment block. +/^ *\/[*][*]$/ { + inDoc = 1; + count = 0; + indent = ""; + firstIndent = ""; + print; + next; +} + +# Code quote block: Suppress! +inDoc && /^ *[*] ```/ { + if (inCodeQuote) { + inCodeQuote = 0; + print; + next; + } else { + autoflowLines(); + inCodeQuote = 1; + } +} +inCodeQuote { + print; + next; +} + +# Paragraph separator. +inDoc && /^ *[*]$/ { + autoflowLines(); + print; + next; +} + +# Start of a tag. (Should be handled, but not yet implemented.) +inDoc && /^ *[*] *@/ { + autoflowLines(); + inDoc = 0; +} + +# End of doc comment block. +inDoc && /^ *[*]\/$/ { + autoflowLines(); + inDoc = 0; +} + +# Additional line in current paragraph, or possibly start of new paragraph (if +# indentation changes; not perfect but good enough for a follow-on human pass). +inDoc { + if (indent == "") { + indent = $0; + match(indent, /^[ *]* /); + firstIndent = substr(indent, RSTART, RLENGTH); + indent = calcIndent(firstIndent); + } else { + newIndent = $0; + match(newIndent, /^[ *]* /); + newIndent = substr(newIndent, RSTART, RLENGTH); + if (indent != newIndent) { + autoflowLines(); + firstIndent = newIndent; + indent = calcIndent(firstIndent); + } + } + lines[count] = $0; + count++; + next; +} + +{ print; } + +# Convert a first-indent into a the-rest-indent. +function calcIndent(firstIndent, _locals_, result) { + result = firstIndent; + match(result, /^ *[*] /); + result = substr(result, RSTART, RLENGTH); + while (length(result) < length(firstIndent)) result = result " "; + #print "FIRST <" firstIndent "> REST <" result ">"; + return result; +} + +# Emit one paragraph of comment. +function autoflowLines(_locals_, i, line, text) { + if (count == 0) return; + + #print "INDENTS: <" firstIndent "> <" indent ">"; + + text = ""; + for (i = 0; i < count; i++) { + line = lines[i]; + sub(/^[ *]* /, "", line); + if (i == 0) text = line; + else text = text " " line; + } + + while (text != "") { + if (length(text) + length(indent) <= 80) { + i = length(text); + } else { + for (i = 81 - length(indent); i > 0; i--) { + if (substr(text, i, 1) == " ") break; + } + if (i == 0) { + # Very long word. Just emit it on its own line. + match(text, /^[^ ]+/); + i = RLENGTH; + } + } + + line = substr(text, 1, i); + sub(/^ */, "", line); + sub(/ *$/, "", line); + if (firstIndent != "") { + print firstIndent line; + firstIndent = ""; + } else { + print indent line; + } + + text = substr(text, i + 1); + } + + count = 0; + indent = ""; +} +' + +# Processes a single file. +function process-file { + local path="$1" + + local origText && origText="$(cat "${path}")" \ + || return "$?" + + local fixedText && fixedText="$(awk <<<"${origText}" "${REFLOW_SCRIPT}")" \ + || return "$?" + + cat <<<"${fixedText}" >"${path}" \ + || return "$?" +} + + +# +# Main script +# + +baseDir="$(base-dir)" + +sourceArray="$( + lib buildy ls-files --output=array --full-paths --include='\.(js|mjs|cjs)' +)" \ +|| exit "$?" + +jset-array --raw sources "${sourceArray}" \ +|| exit "$?" + +for file in "${sources[@]}"; do + progress-msg "${file}..." + process-file "${file}" \ + || { + error-msg "Trouble processing file: ${file}" + exit 1 + } +done + +progress-msg 'Done!'