@jdeighan/coffee-utils 15.0.0 → 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": "15.0.0",
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/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('');