@jdeighan/coffee-utils 14.0.38 → 15.0.1

Sign up to get free protection for your applications and to get access to all the features.
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('');