Skip to content

Commit d86fa73

Browse files
committed
New script reflow-jsdoc.
1 parent c64ec02 commit d86fa73

File tree

2 files changed

+195
-1
lines changed

2 files changed

+195
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Breaking changes:
1010
* None.
1111

1212
Other notable changes:
13-
* None.
13+
* `bashy-node`:
14+
* New script `node-project reflow-jsdoc`.
1415

1516
### v2.10 -- 2024-03-14
1617

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#!/bin/bash
2+
#
3+
# Copyright 2022-2024 the Lactoserv Authors (Dan Bornstein et alia).
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
. "$(dirname "$(readlink -f "$0")")/_init.sh" || exit "$?"
7+
8+
9+
#
10+
# Argument parsing
11+
#
12+
13+
define-usage --with-help $'
14+
${name} [<opt> ...] <version>
15+
16+
Reflows all JSDoc comments in the source, in a way that is imperfect yet
17+
sufficiently decent to be reasonably human-vetted.
18+
'
19+
20+
process-args "$@" || exit "$?"
21+
22+
23+
#
24+
# Helper functions
25+
#
26+
27+
# Awk script which performs reflowing on a single file.
28+
REFLOW_SCRIPT='
29+
# Start of doc comment block.
30+
/^ *\/[*][*]$/ {
31+
inDoc = 1;
32+
count = 0;
33+
indent = "";
34+
firstIndent = "";
35+
print;
36+
next;
37+
}
38+
39+
# Code quote block: Suppress!
40+
inDoc && /^ *[*] ```/ {
41+
if (inCodeQuote) {
42+
inCodeQuote = 0;
43+
print;
44+
next;
45+
} else {
46+
autoflowLines();
47+
inCodeQuote = 1;
48+
}
49+
}
50+
inCodeQuote {
51+
print;
52+
next;
53+
}
54+
55+
# Paragraph separator.
56+
inDoc && /^ *[*]$/ {
57+
autoflowLines();
58+
print;
59+
next;
60+
}
61+
62+
# Start of a tag. (Should be handled, but not yet implemented.)
63+
inDoc && /^ *[*] *@/ {
64+
autoflowLines();
65+
inDoc = 0;
66+
}
67+
68+
# End of doc comment block.
69+
inDoc && /^ *[*]\/$/ {
70+
autoflowLines();
71+
inDoc = 0;
72+
}
73+
74+
# Additional line in current paragraph, or possibly start of new paragraph (if
75+
# indentation changes; not perfect but good enough for a follow-on human pass).
76+
inDoc {
77+
if (indent == "") {
78+
indent = $0;
79+
match(indent, /^[ *]* /);
80+
firstIndent = substr(indent, RSTART, RLENGTH);
81+
indent = calcIndent(firstIndent);
82+
} else {
83+
newIndent = $0;
84+
match(newIndent, /^[ *]* /);
85+
newIndent = substr(newIndent, RSTART, RLENGTH);
86+
if (indent != newIndent) {
87+
autoflowLines();
88+
firstIndent = newIndent;
89+
indent = calcIndent(firstIndent);
90+
}
91+
}
92+
lines[count] = $0;
93+
count++;
94+
next;
95+
}
96+
97+
{ print; }
98+
99+
# Convert a first-indent into a the-rest-indent.
100+
function calcIndent(firstIndent, _locals_, result) {
101+
result = firstIndent;
102+
match(result, /^ *[*] /);
103+
result = substr(result, RSTART, RLENGTH);
104+
while (length(result) < length(firstIndent)) result = result " ";
105+
#print "FIRST <" firstIndent "> REST <" result ">";
106+
return result;
107+
}
108+
109+
# Emit one paragraph of comment.
110+
function autoflowLines(_locals_, i, line, text) {
111+
if (count == 0) return;
112+
113+
#print "INDENTS: <" firstIndent "> <" indent ">";
114+
115+
text = "";
116+
for (i = 0; i < count; i++) {
117+
line = lines[i];
118+
sub(/^[ *]* /, "", line);
119+
if (i == 0) text = line;
120+
else text = text " " line;
121+
}
122+
123+
while (text != "") {
124+
if (length(text) + length(indent) <= 80) {
125+
i = length(text);
126+
} else {
127+
for (i = 81 - length(indent); i > 0; i--) {
128+
if (substr(text, i, 1) == " ") break;
129+
}
130+
if (i == 0) {
131+
# Very long word. Just emit it on its own line.
132+
match(text, /^[^ ]+/);
133+
i = RLENGTH;
134+
}
135+
}
136+
137+
line = substr(text, 1, i);
138+
sub(/^ */, "", line);
139+
sub(/ *$/, "", line);
140+
if (firstIndent != "") {
141+
print firstIndent line;
142+
firstIndent = "";
143+
} else {
144+
print indent line;
145+
}
146+
147+
text = substr(text, i + 1);
148+
}
149+
150+
count = 0;
151+
indent = "";
152+
}
153+
'
154+
155+
# Processes a single file.
156+
function process-file {
157+
local path="$1"
158+
159+
local origText && origText="$(cat "${path}")" \
160+
|| return "$?"
161+
162+
local fixedText && fixedText="$(awk <<<"${origText}" "${REFLOW_SCRIPT}")" \
163+
|| return "$?"
164+
165+
cat <<<"${fixedText}" >"${path}" \
166+
|| return "$?"
167+
}
168+
169+
170+
#
171+
# Main script
172+
#
173+
174+
baseDir="$(base-dir)"
175+
176+
sourceArray="$(
177+
lib buildy ls-files --output=array --full-paths --include='\.(js|mjs|cjs)'
178+
)" \
179+
|| exit "$?"
180+
181+
jset-array --raw sources "${sourceArray}" \
182+
|| exit "$?"
183+
184+
for file in "${sources[@]}"; do
185+
progress-msg "${file}..."
186+
process-file "${file}" \
187+
|| {
188+
error-msg "Trouble processing file: ${file}"
189+
exit 1
190+
}
191+
done
192+
193+
progress-msg 'Done!'

0 commit comments

Comments
 (0)