@jdeighan/coffee-utils 14.0.38 → 15.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "14.0.38",
4
+ "version": "15.0.1",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
package/src/fs.coffee CHANGED
@@ -5,7 +5,7 @@ import pathlib from 'path'
5
5
  import urllib from 'url'
6
6
  import fs from 'fs'
7
7
  import {
8
- readFile, writeFile, rm,
8
+ readFile, writeFile, rm, rmdir, # rmSync, rmdirSync,
9
9
  } from 'node:fs/promises'
10
10
  import {execSync} from 'node:child_process'
11
11
  import readline from 'readline'
@@ -21,6 +21,15 @@ import {LOG, LOGVALUE} from '@jdeighan/base-utils/log'
21
21
  import {dbg, dbgEnter, dbgReturn} from '@jdeighan/base-utils/debug'
22
22
  import {fromTAML} from '@jdeighan/base-utils/taml'
23
23
 
24
+ fix = true
25
+
26
+ # ---------------------------------------------------------------------------
27
+
28
+ export doFixOutput = (flag=true) =>
29
+
30
+ fix = flag
31
+ return
32
+
24
33
  # ---------------------------------------------------------------------------
25
34
 
26
35
  export mkpath = (lParts...) =>
@@ -40,7 +49,7 @@ export mkpath = (lParts...) =>
40
49
 
41
50
  # ---------------------------------------------------------------------------
42
51
 
43
- export mkdir = (dirpath) =>
52
+ export mkdirSync = (dirpath) =>
44
53
 
45
54
  try
46
55
  fs.mkdirSync dirpath
@@ -54,21 +63,88 @@ export mkdir = (dirpath) =>
54
63
 
55
64
  # ---------------------------------------------------------------------------
56
65
 
57
- export rmdir = (dirpath) =>
66
+ export rmDir = (dirpath) =>
67
+
68
+ await rmdir dirpath, {recursive: true}
69
+ return
70
+
71
+ # ---------------------------------------------------------------------------
72
+
73
+ export rmDirSync = (dirpath) =>
58
74
 
59
- await rm dirpath, {recursive: true}
75
+ fs.rmdirSync dirpath, {recursive: true}
60
76
  return
61
77
 
62
78
  # ---------------------------------------------------------------------------
63
79
 
64
- export rmfile = (filepath) =>
80
+ export rmFile = (filepath) =>
65
81
 
66
82
  await rm filepath
67
83
  return
68
84
 
85
+ # ---------------------------------------------------------------------------
86
+
87
+ export rmFileSync = (filepath) =>
88
+
89
+ fs.rmSync filepath
90
+ return
91
+
92
+ # --------------------------------------------------------------------------
93
+
94
+ export fixOutput = (contents) =>
95
+
96
+ if fix
97
+ return rtrim(contents) + "\n"
98
+ else
99
+ return contents
100
+
101
+ # --------------------------------------------------------------------------
102
+
103
+ export fixFile = (filepath, func) =>
104
+
105
+ contents = await readFile(filepath, {encoding: 'utf8'})
106
+ output = func(contents) # returns modified contents
107
+ output = fixOutput(output)
108
+ await writeFile(filepath, output, {encoding: 'utf8'})
109
+ return
110
+
111
+ # --------------------------------------------------------------------------
112
+
113
+ export fixJson = (filepath, func) =>
114
+
115
+ contents = await readFile(filepath, {encoding: 'utf8'})
116
+ hJson = JSON.parse(contents)
117
+ func(hJson) # modify in place
118
+ output = JSON.stringify(hJson, null, 3)
119
+ output = fixOutput(output)
120
+ await writeFile(filepath, output, {encoding: 'utf8'})
121
+ return
122
+
123
+ # --------------------------------------------------------------------------
124
+
125
+ export fixFileSync = (filepath, func) =>
126
+
127
+ contents = fs.readFileSync(filepath, {encoding: 'utf8'})
128
+ output = func(contents) # returns modified contents
129
+ output = fixOutput(output)
130
+ fs.writeFileSync(filepath, output, {encoding: 'utf8'})
131
+ return
132
+
133
+ # --------------------------------------------------------------------------
134
+
135
+ export fixJsonSync = (filepath, func) =>
136
+
137
+ contents = fs.readFileSync(filepath, {encoding: 'utf8'})
138
+ hJson = JSON.parse(contents)
139
+ func(hJson) # modify in place
140
+ output = JSON.stringify(hJson, null, 3)
141
+ output = fixOutput(output)
142
+ fs.writeFileSync(filepath, output, {encoding: 'utf8'})
143
+ return
144
+
69
145
  # --------------------------------------------------------------------------
70
146
 
71
- export execCmd = (cmdLine) =>
147
+ export execCmdSync = (cmdLine) =>
72
148
 
73
149
  execSync cmdLine, {}, (error, stdout, stderr) =>
74
150
  if (error)
@@ -326,7 +402,7 @@ export barf = (filepath, contents='', hOptions={}) =>
326
402
  contents = toBlock(contents)
327
403
  else if ! isString(contents)
328
404
  croak "barf(): Invalid contents"
329
- contents = rtrim(contents) + "\n"
405
+ contents = fixOutput(contents)
330
406
  fs.writeFileSync(filepath, contents, {encoding: 'utf8'})
331
407
  return
332
408
 
package/src/fs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  // fs.coffee
3
- var isSystemDir;
3
+ var fix, isSystemDir;
4
4
 
5
5
  import os from 'os';
6
6
 
@@ -13,7 +13,8 @@ import fs from 'fs';
13
13
  import {
14
14
  readFile,
15
15
  writeFile,
16
- rm
16
+ rm,
17
+ rmdir // rmSync, rmdirSync,
17
18
  } from 'node:fs/promises';
18
19
 
19
20
  import {
@@ -63,6 +64,13 @@ import {
63
64
  fromTAML
64
65
  } from '@jdeighan/base-utils/taml';
65
66
 
67
+ fix = true;
68
+
69
+ // ---------------------------------------------------------------------------
70
+ export var doFixOutput = (flag = true) => {
71
+ fix = flag;
72
+ };
73
+
66
74
  // ---------------------------------------------------------------------------
67
75
  export var mkpath = (...lParts) => {
68
76
  var _, drive, i, lMatches, lNewParts, len, newPath, part, rest;
@@ -84,7 +92,7 @@ export var mkpath = (...lParts) => {
84
92
  };
85
93
 
86
94
  // ---------------------------------------------------------------------------
87
- export var mkdir = (dirpath) => {
95
+ export var mkdirSync = (dirpath) => {
88
96
  var err;
89
97
  try {
90
98
  fs.mkdirSync(dirpath);
@@ -100,19 +108,96 @@ export var mkdir = (dirpath) => {
100
108
  };
101
109
 
102
110
  // ---------------------------------------------------------------------------
103
- export var rmdir = async(dirpath) => {
104
- await rm(dirpath, {
111
+ export var rmDir = async(dirpath) => {
112
+ await rmdir(dirpath, {
113
+ recursive: true
114
+ });
115
+ };
116
+
117
+ // ---------------------------------------------------------------------------
118
+ export var rmDirSync = (dirpath) => {
119
+ fs.rmdirSync(dirpath, {
105
120
  recursive: true
106
121
  });
107
122
  };
108
123
 
109
124
  // ---------------------------------------------------------------------------
110
- export var rmfile = async(filepath) => {
125
+ export var rmFile = async(filepath) => {
111
126
  await rm(filepath);
112
127
  };
113
128
 
129
+ // ---------------------------------------------------------------------------
130
+ export var rmFileSync = (filepath) => {
131
+ fs.rmSync(filepath);
132
+ };
133
+
134
+ // --------------------------------------------------------------------------
135
+ export var fixOutput = (contents) => {
136
+ if (fix) {
137
+ return rtrim(contents) + "\n";
138
+ } else {
139
+ return contents;
140
+ }
141
+ };
142
+
143
+ // --------------------------------------------------------------------------
144
+ export var fixFile = async(filepath, func) => {
145
+ var contents, output;
146
+ contents = (await readFile(filepath, {
147
+ encoding: 'utf8'
148
+ }));
149
+ output = func(contents); // returns modified contents
150
+ output = fixOutput(output);
151
+ await writeFile(filepath, output, {
152
+ encoding: 'utf8'
153
+ });
154
+ };
155
+
156
+ // --------------------------------------------------------------------------
157
+ export var fixJson = async(filepath, func) => {
158
+ var contents, hJson, output;
159
+ contents = (await readFile(filepath, {
160
+ encoding: 'utf8'
161
+ }));
162
+ hJson = JSON.parse(contents);
163
+ func(hJson); // modify in place
164
+ output = JSON.stringify(hJson, null, 3);
165
+ output = fixOutput(output);
166
+ await writeFile(filepath, output, {
167
+ encoding: 'utf8'
168
+ });
169
+ };
170
+
171
+ // --------------------------------------------------------------------------
172
+ export var fixFileSync = (filepath, func) => {
173
+ var contents, output;
174
+ contents = fs.readFileSync(filepath, {
175
+ encoding: 'utf8'
176
+ });
177
+ output = func(contents); // returns modified contents
178
+ output = fixOutput(output);
179
+ fs.writeFileSync(filepath, output, {
180
+ encoding: 'utf8'
181
+ });
182
+ };
183
+
184
+ // --------------------------------------------------------------------------
185
+ export var fixJsonSync = (filepath, func) => {
186
+ var contents, hJson, output;
187
+ contents = fs.readFileSync(filepath, {
188
+ encoding: 'utf8'
189
+ });
190
+ hJson = JSON.parse(contents);
191
+ func(hJson); // modify in place
192
+ output = JSON.stringify(hJson, null, 3);
193
+ output = fixOutput(output);
194
+ fs.writeFileSync(filepath, output, {
195
+ encoding: 'utf8'
196
+ });
197
+ };
198
+
114
199
  // --------------------------------------------------------------------------
115
- export var execCmd = (cmdLine) => {
200
+ export var execCmdSync = (cmdLine) => {
116
201
  execSync(cmdLine, {}, (error, stdout, stderr) => {
117
202
  if (error) {
118
203
  LOG(`ERROR in ${cmdLine}: ${error.code}`);
@@ -381,7 +466,7 @@ export var barf = (filepath, contents = '', hOptions = {}) => {
381
466
  } else if (!isString(contents)) {
382
467
  croak("barf(): Invalid contents");
383
468
  }
384
- contents = rtrim(contents) + "\n";
469
+ contents = fixOutput(contents);
385
470
  }
386
471
  fs.writeFileSync(filepath, contents, {
387
472
  encoding: 'utf8'
package/src/indent.coffee CHANGED
@@ -34,15 +34,6 @@ export splitLine = (line, oneIndent=undef) =>
34
34
  [prefix, str] = splitPrefix(line)
35
35
  return [indentLevel(prefix, oneIndent), str]
36
36
 
37
- # ---------------------------------------------------------------------------
38
- # indentation - return appropriate indentation string for given level
39
- # export only to allow unit testing
40
-
41
- export indentation = (level, oneIndent="\t") =>
42
-
43
- assert (level >= 0), "indentation(): negative level"
44
- return oneIndent.repeat(level)
45
-
46
37
  # ---------------------------------------------------------------------------
47
38
  # indentLevel - determine indent level of a string
48
39
  # it's OK if the string is ONLY indentation
@@ -59,28 +50,56 @@ export indentLevel = (line, oneIndent=undef) =>
59
50
  if (prefixLen == 0)
60
51
  return 0
61
52
 
62
- if defined(oneIndent)
63
- # --- prefix must be some multiple of oneIndent
64
- len = oneIndent.length
65
- assert (prefixLen % len == 0),
66
- "prefix #{OL(prefix)} not a mult of #{OL(oneIndent)}"
67
-
68
- level = prefixLen / len
53
+ # --- Match \t* followed by \x20* (error if no match)
54
+ if lMatches = prefix.match(/(\t*)(\x20*)/)
55
+ nTabs = lMatches[1].length
56
+ nSpaces = lMatches[2].length
69
57
  else
70
- ch = prefix.substring(0, 1)
71
- if (ch == "\t")
72
- oneIndent = "\t"
73
- level = prefixLen
74
- else if (ch == ' ')
75
- oneIndent = ' '.repeat(prefixLen)
76
- level = 1
58
+ croak "Invalid mix of TABs and spaces"
59
+
60
+ # --- oneIndent must be one of:
61
+ # undef
62
+ # a single TAB character
63
+ # some number of space characters
64
+
65
+ switch oneIndent
66
+ when undef
67
+ if (nTabs > 0)
68
+ level = nTabs # there may also be spaces, but we ignore them
69
+ oneIndent = "\t" # may be used at end
70
+ else
71
+ assert (nSpaces > 0), "There must be TABS or spaces"
72
+ level = 1
73
+ oneIndent = ' '.repeat(nSpaces) # may be used at end
74
+ when "\t"
75
+ assert (nTabs > 0), "Expecting TAB indentation, found spaces"
76
+ # --- NOTE: there may be spaces, but they're not indentation
77
+ level = nTabs
77
78
  else
78
- croak "Bad Indentation in #{OL(line)}"
79
-
80
- assert (prefix == oneIndent.repeat(level)),
81
- "prefix #{OL(prefix)} not a mult of #{OL(oneIndent)}"
79
+ # --- oneIndent must be all space chars
80
+ assert (nTabs == 0),
81
+ "Indentation has TABs but oneIndent = #{OL(oneIndent)}"
82
+ assert (nSpaces % oneIndent.length == 0),
83
+ "prefix #{OL(prefix)} not a mult of #{OL(oneIndent)}"
84
+ level = nSpaces / oneIndent.length
85
+
86
+ # --- If a block, i.e. multi-line string, then all lines must be
87
+ # at least at this level
88
+ if (line.indexOf("\n") >= 0)
89
+ for str in toArray(line)
90
+ assert (indentLevel(str, oneIndent) >= level),
91
+ "indentLevel of #{OL(line)} can't be found"
82
92
  return level
83
93
 
94
+ # ---------------------------------------------------------------------------
95
+ # indentation - return appropriate indentation string for given level
96
+ # export only to allow unit testing
97
+
98
+ export indentation = (level, oneIndent="\t") =>
99
+
100
+ assert (level >= 0), "indentation(): negative level"
101
+ return oneIndent.repeat(level)
102
+
84
103
  # ---------------------------------------------------------------------------
85
104
  # isUndented - true iff indentLevel(line) == 0
86
105
 
package/src/indent.js CHANGED
@@ -48,19 +48,11 @@ export var splitLine = (line, oneIndent = undef) => {
48
48
  return [indentLevel(prefix, oneIndent), str];
49
49
  };
50
50
 
51
- // ---------------------------------------------------------------------------
52
- // indentation - return appropriate indentation string for given level
53
- // export only to allow unit testing
54
- export var indentation = (level, oneIndent = "\t") => {
55
- assert(level >= 0, "indentation(): negative level");
56
- return oneIndent.repeat(level);
57
- };
58
-
59
51
  // ---------------------------------------------------------------------------
60
52
  // indentLevel - determine indent level of a string
61
53
  // it's OK if the string is ONLY indentation
62
54
  export var indentLevel = (line, oneIndent = undef) => {
63
- var ch, lMatches, len, level, prefix, prefixLen;
55
+ var i, lMatches, len, level, nSpaces, nTabs, prefix, prefixLen, ref, str;
64
56
  assert(isString(line), "not a string");
65
57
  // --- This will always match, and it's greedy
66
58
  if (lMatches = line.match(/^\s*/)) {
@@ -70,27 +62,59 @@ export var indentLevel = (line, oneIndent = undef) => {
70
62
  if (prefixLen === 0) {
71
63
  return 0;
72
64
  }
73
- if (defined(oneIndent)) {
74
- // --- prefix must be some multiple of oneIndent
75
- len = oneIndent.length;
76
- assert(prefixLen % len === 0, `prefix ${OL(prefix)} not a mult of ${OL(oneIndent)}`);
77
- level = prefixLen / len;
65
+ // --- Match \t* followed by \x20* (error if no match)
66
+ if (lMatches = prefix.match(/(\t*)(\x20*)/)) {
67
+ nTabs = lMatches[1].length;
68
+ nSpaces = lMatches[2].length;
78
69
  } else {
79
- ch = prefix.substring(0, 1);
80
- if (ch === "\t") {
81
- oneIndent = "\t";
82
- level = prefixLen;
83
- } else if (ch === ' ') {
84
- oneIndent = ' '.repeat(prefixLen);
85
- level = 1;
86
- } else {
87
- croak(`Bad Indentation in ${OL(line)}`);
70
+ croak("Invalid mix of TABs and spaces");
71
+ }
72
+ // --- oneIndent must be one of:
73
+ // undef
74
+ // a single TAB character
75
+ // some number of space characters
76
+ switch (oneIndent) {
77
+ case undef:
78
+ if (nTabs > 0) {
79
+ level = nTabs; // there may also be spaces, but we ignore them
80
+ oneIndent = "\t"; // may be used at end
81
+ } else {
82
+ assert(nSpaces > 0, "There must be TABS or spaces");
83
+ level = 1;
84
+ oneIndent = ' '.repeat(nSpaces); // may be used at end
85
+ }
86
+ break;
87
+ case "\t":
88
+ assert(nTabs > 0, "Expecting TAB indentation, found spaces");
89
+ // --- NOTE: there may be spaces, but they're not indentation
90
+ level = nTabs;
91
+ break;
92
+ default:
93
+ // --- oneIndent must be all space chars
94
+ assert(nTabs === 0, `Indentation has TABs but oneIndent = ${OL(oneIndent)}`);
95
+ assert(nSpaces % oneIndent.length === 0, `prefix ${OL(prefix)} not a mult of ${OL(oneIndent)}`);
96
+ level = nSpaces / oneIndent.length;
97
+ }
98
+ // --- If a block, i.e. multi-line string, then all lines must be
99
+ // at least at this level
100
+ if (line.indexOf("\n") >= 0) {
101
+ ref = toArray(line);
102
+ for (i = 0, len = ref.length; i < len; i++) {
103
+ str = ref[i];
104
+ assert(indentLevel(str, oneIndent) >= level, `indentLevel of ${OL(line)} can't be found`);
88
105
  }
89
106
  }
90
- assert(prefix === oneIndent.repeat(level), `prefix ${OL(prefix)} not a mult of ${OL(oneIndent)}`);
91
107
  return level;
92
108
  };
93
109
 
110
+ // ---------------------------------------------------------------------------
111
+ // indentation - return appropriate indentation string for given level
112
+ // export only to allow unit testing
113
+ export var indentation = (level, oneIndent = "\t") => {
114
+ assert(level >= 0, "indentation(): negative level");
115
+ return oneIndent.repeat(level);
116
+ };
117
+
94
118
  // ---------------------------------------------------------------------------
95
119
  // isUndented - true iff indentLevel(line) == 0
96
120
  export var isUndented = (line) => {
@@ -102,7 +126,7 @@ export var isUndented = (line) => {
102
126
  // indented - add indentation to each string in a block or array
103
127
  // - returns the same type as input, i.e. array or string
104
128
  export var indented = (input, level = 1, oneIndent = "\t") => {
105
- var i, lLines, len1, line, ref, toAdd;
129
+ var i, lLines, len, line, ref, toAdd;
106
130
  // --- level can be a string, in which case it is
107
131
  // pre-pended to each line of input
108
132
  if (isString(level)) {
@@ -123,7 +147,7 @@ export var indented = (input, level = 1, oneIndent = "\t") => {
123
147
  // else it splits the string into an array of lines
124
148
  lLines = [];
125
149
  ref = toArray(input);
126
- for (i = 0, len1 = ref.length; i < len1; i++) {
150
+ for (i = 0, len = ref.length; i < len; i++) {
127
151
  line = ref[i];
128
152
  if (isEmpty(line)) {
129
153
  lLines.push('');
@@ -146,7 +170,7 @@ export var indented = (input, level = 1, oneIndent = "\t") => {
146
170
  // indentation is removed
147
171
  // - returns same type as text, i.e. either string or array
148
172
  export var undented = (input, level = undef, oneIndent = "\t") => {
149
- var i, lLines, lMatches, lNewLines, len1, line, nToRemove, toRemove;
173
+ var i, lLines, lMatches, lNewLines, len, line, nToRemove, toRemove;
150
174
  if (defined(level) && (level === 0)) {
151
175
  return input;
152
176
  }
@@ -181,7 +205,7 @@ export var undented = (input, level = undef, oneIndent = "\t") => {
181
205
  }
182
206
  nToRemove = indentLevel(toRemove);
183
207
  lNewLines = [];
184
- for (i = 0, len1 = lLines.length; i < len1; i++) {
208
+ for (i = 0, len = lLines.length; i < len; i++) {
185
209
  line = lLines[i];
186
210
  if (isEmpty(line)) {
187
211
  lNewLines.push('');