@jdeighan/coffee-utils 10.0.1 → 10.0.4

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": "10.0.1",
4
+ "version": "10.0.4",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -12,6 +12,7 @@
12
12
  "./log": "./src/log_utils.js",
13
13
  "./block": "./src/block_utils.js",
14
14
  "./indent": "./src/indent_utils.js",
15
+ "./html": "./src/html_utils.js",
15
16
  "./stack": "./src/call_stack.js",
16
17
  "./debug": "./src/debug_utils.js",
17
18
  "./arrow": "./src/arrow.js",
@@ -97,33 +97,41 @@ export class SectionMap
97
97
  hReplacers = desc
98
98
  desc = @lSectionTree
99
99
  else if notdefined(desc)
100
+ debug "desc is entire tree"
100
101
  desc = @lSectionTree
101
102
 
102
103
  if isArray(desc)
104
+ debug "item is an array"
103
105
  lBlocks = []
104
106
  setName = undef
105
107
  for item in desc
106
108
  subBlock = undef
107
- if isArray(item)
108
- subBlock = @getBlock(item, hReplacers)
109
- else if isSectionName(item)
110
- subBlock = @getBlock(item, hReplacers)
111
- else if isSetName(item)
109
+ if isSetName(item)
110
+ debug "set name is #{item}"
112
111
  setName = item
113
- else if isString(item)
114
- subBlock = item # a literal string
112
+ else if isSectionName(item) || isArray(item)
113
+ subBlock = @getBlock(item, hReplacers)
114
+ if defined(subBlock)
115
+ debug "add subBlock", subBlock
116
+ lBlocks.push subBlock
117
+ else
118
+ debug "subBlock is undef"
119
+ else if isString(item) && nonEmpty(item)
120
+ debug "add string", item
121
+ lBlocks.push item
115
122
  else
116
123
  croak "Bad item: #{OL(item)}"
117
- if defined(subBlock)
118
- lBlocks.push subBlock
124
+
119
125
  block = arrayToBlock(lBlocks)
126
+ debug "block is", block
120
127
  if defined(setName)
121
128
  if defined(proc = hReplacers[setName])
122
- debug "REPLACE #{setName}"
123
129
  block = proc(block)
130
+ debug "REPLACE #{setName} with", block
124
131
  else
125
132
  debug "NO REPLACER for #{setName}"
126
133
  else if isSectionName(desc)
134
+ debug "item is a section name"
127
135
  block = @section(desc).getBlock()
128
136
  if defined(proc = hReplacers[desc])
129
137
  debug "REPLACE #{desc}"
@@ -131,7 +139,7 @@ export class SectionMap
131
139
  else
132
140
  debug "NO REPLACER for #{desc}"
133
141
  else if isSetName(desc)
134
- # --- pass array to getBlock()
142
+ debug "item is a set name"
135
143
  block = @getBlock(@hSets[desc], hReplacers)
136
144
  else
137
145
  croak "Bad 1st arg: #{OL(desc)}"
package/src/SectionMap.js CHANGED
@@ -126,39 +126,46 @@ export var SectionMap = class SectionMap {
126
126
  hReplacers = desc;
127
127
  desc = this.lSectionTree;
128
128
  } else if (notdefined(desc)) {
129
+ debug("desc is entire tree");
129
130
  desc = this.lSectionTree;
130
131
  }
131
132
  if (isArray(desc)) {
133
+ debug("item is an array");
132
134
  lBlocks = [];
133
135
  setName = undef;
134
136
  for (i = 0, len = desc.length; i < len; i++) {
135
137
  item = desc[i];
136
138
  subBlock = undef;
137
- if (isArray(item)) {
138
- subBlock = this.getBlock(item, hReplacers);
139
- } else if (isSectionName(item)) {
140
- subBlock = this.getBlock(item, hReplacers);
141
- } else if (isSetName(item)) {
139
+ if (isSetName(item)) {
140
+ debug(`set name is ${item}`);
142
141
  setName = item;
143
- } else if (isString(item)) {
144
- subBlock = item; // a literal string
142
+ } else if (isSectionName(item) || isArray(item)) {
143
+ subBlock = this.getBlock(item, hReplacers);
144
+ if (defined(subBlock)) {
145
+ debug("add subBlock", subBlock);
146
+ lBlocks.push(subBlock);
147
+ } else {
148
+ debug("subBlock is undef");
149
+ }
150
+ } else if (isString(item) && nonEmpty(item)) {
151
+ debug("add string", item);
152
+ lBlocks.push(item);
145
153
  } else {
146
154
  croak(`Bad item: ${OL(item)}`);
147
155
  }
148
- if (defined(subBlock)) {
149
- lBlocks.push(subBlock);
150
- }
151
156
  }
152
157
  block = arrayToBlock(lBlocks);
158
+ debug("block is", block);
153
159
  if (defined(setName)) {
154
160
  if (defined(proc = hReplacers[setName])) {
155
- debug(`REPLACE ${setName}`);
156
161
  block = proc(block);
162
+ debug(`REPLACE ${setName} with`, block);
157
163
  } else {
158
164
  debug(`NO REPLACER for ${setName}`);
159
165
  }
160
166
  }
161
167
  } else if (isSectionName(desc)) {
168
+ debug("item is a section name");
162
169
  block = this.section(desc).getBlock();
163
170
  if (defined(proc = hReplacers[desc])) {
164
171
  debug(`REPLACE ${desc}`);
@@ -167,7 +174,7 @@ export var SectionMap = class SectionMap {
167
174
  debug(`NO REPLACER for ${desc}`);
168
175
  }
169
176
  } else if (isSetName(desc)) {
170
- // --- pass array to getBlock()
177
+ debug("item is a set name");
171
178
  block = this.getBlock(this.hSets[desc], hReplacers);
172
179
  } else {
173
180
  croak(`Bad 1st arg: ${OL(desc)}`);
@@ -3,7 +3,7 @@
3
3
  import fs from 'fs'
4
4
  import readline from 'readline'
5
5
 
6
- import {assert, error} from '@jdeighan/unit-tester/utils'
6
+ import {assert, error, croak} from '@jdeighan/unit-tester/utils'
7
7
  import {
8
8
  undef, defined, isEmpty, isString, isArray, nonEmpty, rtrim,
9
9
  } from '@jdeighan/coffee-utils'
@@ -6,7 +6,8 @@ import readline from 'readline';
6
6
 
7
7
  import {
8
8
  assert,
9
- error
9
+ error,
10
+ croak
10
11
  } from '@jdeighan/unit-tester/utils';
11
12
 
12
13
  import {
@@ -0,0 +1,217 @@
1
+ # html_utils.coffee
2
+
3
+ import {assert, croak} from '@jdeighan/unit-tester/utils'
4
+ import {
5
+ undef, pass, words, isEmpty, nonEmpty,
6
+ } from '@jdeighan/coffee-utils'
7
+ import {indented, enclose} from '@jdeighan/coffee-utils/indent'
8
+ import {arrayToBlock} from '@jdeighan/coffee-utils/block'
9
+ import {debug} from '@jdeighan/coffee-utils/debug'
10
+
11
+ hNoEnd = {}
12
+ for tagName in words('area base br col command embed hr img input' \
13
+ + ' keygen link meta param source track wbr')
14
+ hNoEnd[tagName] = true
15
+
16
+ # ---------------------------------------------------------------------------
17
+
18
+ export parsetag = (line) ->
19
+
20
+ if lMatches = line.match(///^
21
+ (?:
22
+ ([A-Za-z][A-Za-z0-9_]*) # variable name
23
+ \s*
24
+ =
25
+ \s*
26
+ )? # variable is optional
27
+ ([A-Za-z][A-Za-z0-9_]*) # tag name
28
+ (?:
29
+ \:
30
+ ( [a-z]+ )
31
+ )?
32
+ (\S*) # modifiers (class names, etc.)
33
+ \s*
34
+ (.*) # attributes & enclosed text
35
+ $///)
36
+ [_, varName, tagName, subtype, modifiers, rest] = lMatches
37
+ else
38
+ croak "parsetag(): Invalid HTML: '#{line}'"
39
+
40
+ # --- Handle classes - subtypes and added via .<class>
41
+ lClasses = []
42
+ if nonEmpty(subtype) && (tagName != 'svelte')
43
+ lClasses.push subtype
44
+
45
+ if modifiers
46
+ # --- currently, these are only class names
47
+ while lMatches = modifiers.match(///^
48
+ \. ([A-Za-z][A-Za-z0-9_]*)
49
+ ///)
50
+ [all, className] = lMatches
51
+ lClasses.push className
52
+ modifiers = modifiers.substring(all.length)
53
+ if modifiers
54
+ croak "parsetag(): Invalid modifiers in '#{line}'"
55
+
56
+ # --- Handle attributes
57
+ hAttr = {} # { name: { value: <value>, quote: <quote> }, ... }
58
+
59
+ if varName
60
+ hAttr['bind:this'] = {value: varName, quote: '{'}
61
+
62
+ if (tagName == 'script') && (subtype == 'startup')
63
+ hAttr['context'] = {value: 'module', quote: '"'}
64
+
65
+ if rest
66
+ while lMatches = rest.match(///^
67
+ (?:
68
+ (?:
69
+ (?:
70
+ ( bind | on ) # prefix
71
+ :
72
+ )?
73
+ ([A-Za-z][A-Za-z0-9_]*) # attribute name
74
+ )
75
+ =
76
+ (?:
77
+ \{ ([^}]*) \} # attribute value
78
+ | " ([^"]*) "
79
+ | ' ([^']*) '
80
+ | ([^"'\s]+)
81
+ )
82
+ |
83
+ \{
84
+ ([A-Za-z][A-Za-z0-9_]*)
85
+ \}
86
+ ) \s*
87
+ ///)
88
+ [all, prefix, attrName, br_val, dq_val, sq_val, uq_val, ident] = lMatches
89
+ if ident
90
+ hAttr[ident] = { value: ident, shorthand: true }
91
+ else
92
+ if br_val
93
+ value = br_val
94
+ quote = '{'
95
+ else
96
+ assert ! prefix?, "prefix requires use of {...}"
97
+ if dq_val
98
+ value = dq_val
99
+ quote = '"'
100
+ else if sq_val
101
+ value = sq_val
102
+ quote = "'"
103
+ else
104
+ value = uq_val
105
+ quote = ''
106
+
107
+ if prefix
108
+ attrName = "#{prefix}:#{attrName}"
109
+
110
+ if attrName == 'class'
111
+ for className in value.split(/\s+/)
112
+ lClasses.push className
113
+ else
114
+ if hAttr.attrName?
115
+ croak "parsetag(): Multiple attributes named '#{attrName}'"
116
+ hAttr[attrName] = { value, quote }
117
+
118
+ rest = rest.substring(all.length)
119
+
120
+ # --- The rest is contained text
121
+ rest = rest.trim()
122
+ if lMatches = rest.match(///^
123
+ ['"]
124
+ (.*)
125
+ ['"]
126
+ $///)
127
+ rest = lMatches[1]
128
+
129
+ # --- Add class attribute to hAttr if there are classes
130
+ if (lClasses.length > 0)
131
+ hAttr.class = {
132
+ value: lClasses.join(' '),
133
+ quote: '"',
134
+ }
135
+
136
+ # --- Build the return value
137
+ hToken = {
138
+ type: 'tag'
139
+ tagName
140
+ }
141
+
142
+ if subtype
143
+ hToken.subtype = subtype
144
+ hToken.orgtag = "#{tagName}:#{subtype}"
145
+ else
146
+ hToken.orgtag = tagName
147
+
148
+ # --- if tagName == 'svelte', set hToken.tagName to hToken.orgtag
149
+ if (tagName == 'svelte')
150
+ hToken.tagName = hToken.orgtag
151
+
152
+ if nonEmpty(hAttr)
153
+ hToken.hAttr = hAttr
154
+
155
+ # --- Is there contained text?
156
+ if rest
157
+ hToken.text = rest
158
+
159
+ return hToken
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # --- export only for unit testing
163
+
164
+ export attrStr = (hAttr) ->
165
+
166
+ if ! hAttr
167
+ return ''
168
+ str = ''
169
+ for attrName in Object.getOwnPropertyNames(hAttr)
170
+ {value, quote, shorthand} = hAttr[attrName]
171
+ if shorthand
172
+ str += " {#{value}}"
173
+ else
174
+ if quote == '{'
175
+ bquote = '{'
176
+ equote = '}'
177
+ else
178
+ bquote = equote = quote
179
+ str += " #{attrName}=#{bquote}#{value}#{equote}"
180
+ return str
181
+
182
+ # ---------------------------------------------------------------------------
183
+
184
+ export tag2str = (hToken, type='begin') ->
185
+
186
+ {tagName, hAttr} = hToken
187
+ if (type == 'begin')
188
+ str = "<#{tagName}" # build the string bit by bit
189
+ if nonEmpty(hAttr)
190
+ str += attrStr(hAttr)
191
+ str += '>'
192
+ return str
193
+ else if (type == 'end')
194
+ if hNoEnd[tagName]
195
+ return undef
196
+ else
197
+ return "</#{tagName}>"
198
+ else
199
+ croak "type must be 'begin' or 'end'"
200
+
201
+ # ---------------------------------------------------------------------------
202
+ # elem - indent text, surround with HTML tags
203
+
204
+ export elem = (tagName, hAttr=undef, text=undef, oneIndent="\t") ->
205
+
206
+ if isEmpty(text)
207
+ return undef
208
+ hToken = {
209
+ tagName
210
+ hAttr
211
+ text
212
+ }
213
+ return arrayToBlock([
214
+ tag2str(hToken, 'begin')
215
+ indented(text, 1, oneIndent)
216
+ tag2str(hToken, 'end')
217
+ ])
@@ -0,0 +1,222 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ // html_utils.coffee
3
+ var hNoEnd, i, len, ref, tagName;
4
+
5
+ import {
6
+ assert,
7
+ croak
8
+ } from '@jdeighan/unit-tester/utils';
9
+
10
+ import {
11
+ undef,
12
+ pass,
13
+ words,
14
+ isEmpty,
15
+ nonEmpty
16
+ } from '@jdeighan/coffee-utils';
17
+
18
+ import {
19
+ indented,
20
+ enclose
21
+ } from '@jdeighan/coffee-utils/indent';
22
+
23
+ import {
24
+ arrayToBlock
25
+ } from '@jdeighan/coffee-utils/block';
26
+
27
+ import {
28
+ debug
29
+ } from '@jdeighan/coffee-utils/debug';
30
+
31
+ hNoEnd = {};
32
+
33
+ ref = words('area base br col command embed hr img input' + ' keygen link meta param source track wbr');
34
+ for (i = 0, len = ref.length; i < len; i++) {
35
+ tagName = ref[i];
36
+ hNoEnd[tagName] = true;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ export var parsetag = function(line) {
41
+ var _, all, attrName, br_val, className, dq_val, hAttr, hToken, ident, j, lClasses, lMatches, len1, modifiers, prefix, quote, ref1, rest, sq_val, subtype, uq_val, value, varName;
42
+ if (lMatches = line.match(/^(?:([A-Za-z][A-Za-z0-9_]*)\s*=\s*)?([A-Za-z][A-Za-z0-9_]*)(?:\:([a-z]+))?(\S*)\s*(.*)$/)) { // variable name
43
+ // variable is optional
44
+ // tag name
45
+ // modifiers (class names, etc.)
46
+ // attributes & enclosed text
47
+ [_, varName, tagName, subtype, modifiers, rest] = lMatches;
48
+ } else {
49
+ croak(`parsetag(): Invalid HTML: '${line}'`);
50
+ }
51
+ // --- Handle classes - subtypes and added via .<class>
52
+ lClasses = [];
53
+ if (nonEmpty(subtype) && (tagName !== 'svelte')) {
54
+ lClasses.push(subtype);
55
+ }
56
+ if (modifiers) {
57
+ // --- currently, these are only class names
58
+ while (lMatches = modifiers.match(/^\.([A-Za-z][A-Za-z0-9_]*)/)) {
59
+ [all, className] = lMatches;
60
+ lClasses.push(className);
61
+ modifiers = modifiers.substring(all.length);
62
+ }
63
+ if (modifiers) {
64
+ croak(`parsetag(): Invalid modifiers in '${line}'`);
65
+ }
66
+ }
67
+ // --- Handle attributes
68
+ hAttr = {}; // { name: { value: <value>, quote: <quote> }, ... }
69
+ if (varName) {
70
+ hAttr['bind:this'] = {
71
+ value: varName,
72
+ quote: '{'
73
+ };
74
+ }
75
+ if ((tagName === 'script') && (subtype === 'startup')) {
76
+ hAttr['context'] = {
77
+ value: 'module',
78
+ quote: '"'
79
+ };
80
+ }
81
+ if (rest) {
82
+ while (lMatches = rest.match(/^(?:(?:(?:(bind|on):)?([A-Za-z][A-Za-z0-9_]*))=(?:\{([^}]*)\}|"([^"]*)"|'([^']*)'|([^"'\s]+))|\{([A-Za-z][A-Za-z0-9_]*)\})\s*/)) { // prefix
83
+ // attribute name
84
+ // attribute value
85
+ [all, prefix, attrName, br_val, dq_val, sq_val, uq_val, ident] = lMatches;
86
+ if (ident) {
87
+ hAttr[ident] = {
88
+ value: ident,
89
+ shorthand: true
90
+ };
91
+ } else {
92
+ if (br_val) {
93
+ value = br_val;
94
+ quote = '{';
95
+ } else {
96
+ assert(prefix == null, "prefix requires use of {...}");
97
+ if (dq_val) {
98
+ value = dq_val;
99
+ quote = '"';
100
+ } else if (sq_val) {
101
+ value = sq_val;
102
+ quote = "'";
103
+ } else {
104
+ value = uq_val;
105
+ quote = '';
106
+ }
107
+ }
108
+ if (prefix) {
109
+ attrName = `${prefix}:${attrName}`;
110
+ }
111
+ if (attrName === 'class') {
112
+ ref1 = value.split(/\s+/);
113
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
114
+ className = ref1[j];
115
+ lClasses.push(className);
116
+ }
117
+ } else {
118
+ if (hAttr.attrName != null) {
119
+ croak(`parsetag(): Multiple attributes named '${attrName}'`);
120
+ }
121
+ hAttr[attrName] = {value, quote};
122
+ }
123
+ }
124
+ rest = rest.substring(all.length);
125
+ }
126
+ }
127
+ // --- The rest is contained text
128
+ rest = rest.trim();
129
+ if (lMatches = rest.match(/^['"](.*)['"]$/)) {
130
+ rest = lMatches[1];
131
+ }
132
+ // --- Add class attribute to hAttr if there are classes
133
+ if (lClasses.length > 0) {
134
+ hAttr.class = {
135
+ value: lClasses.join(' '),
136
+ quote: '"'
137
+ };
138
+ }
139
+ // --- Build the return value
140
+ hToken = {
141
+ type: 'tag',
142
+ tagName
143
+ };
144
+ if (subtype) {
145
+ hToken.subtype = subtype;
146
+ hToken.orgtag = `${tagName}:${subtype}`;
147
+ } else {
148
+ hToken.orgtag = tagName;
149
+ }
150
+ // --- if tagName == 'svelte', set hToken.tagName to hToken.orgtag
151
+ if (tagName === 'svelte') {
152
+ hToken.tagName = hToken.orgtag;
153
+ }
154
+ if (nonEmpty(hAttr)) {
155
+ hToken.hAttr = hAttr;
156
+ }
157
+ // --- Is there contained text?
158
+ if (rest) {
159
+ hToken.text = rest;
160
+ }
161
+ return hToken;
162
+ };
163
+
164
+ // ---------------------------------------------------------------------------
165
+ // --- export only for unit testing
166
+ export var attrStr = function(hAttr) {
167
+ var attrName, bquote, equote, j, len1, quote, ref1, shorthand, str, value;
168
+ if (!hAttr) {
169
+ return '';
170
+ }
171
+ str = '';
172
+ ref1 = Object.getOwnPropertyNames(hAttr);
173
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
174
+ attrName = ref1[j];
175
+ ({value, quote, shorthand} = hAttr[attrName]);
176
+ if (shorthand) {
177
+ str += ` {${value}}`;
178
+ } else {
179
+ if (quote === '{') {
180
+ bquote = '{';
181
+ equote = '}';
182
+ } else {
183
+ bquote = equote = quote;
184
+ }
185
+ str += ` ${attrName}=${bquote}${value}${equote}`;
186
+ }
187
+ }
188
+ return str;
189
+ };
190
+
191
+ // ---------------------------------------------------------------------------
192
+ export var tag2str = function(hToken, type = 'begin') {
193
+ var hAttr, str;
194
+ ({tagName, hAttr} = hToken);
195
+ if (type === 'begin') {
196
+ str = `<${tagName}`;
197
+ if (nonEmpty(hAttr)) {
198
+ str += attrStr(hAttr);
199
+ }
200
+ str += '>';
201
+ return str;
202
+ } else if (type === 'end') {
203
+ if (hNoEnd[tagName]) {
204
+ return undef;
205
+ } else {
206
+ return `</${tagName}>`;
207
+ }
208
+ } else {
209
+ return croak("type must be 'begin' or 'end'");
210
+ }
211
+ };
212
+
213
+ // ---------------------------------------------------------------------------
214
+ // elem - indent text, surround with HTML tags
215
+ export var elem = function(tagName, hAttr = undef, text = undef, oneIndent = "\t") {
216
+ var hToken;
217
+ if (isEmpty(text)) {
218
+ return undef;
219
+ }
220
+ hToken = {tagName, hAttr, text};
221
+ return arrayToBlock([tag2str(hToken, 'begin'), indented(text, 1, oneIndent), tag2str(hToken, 'end')]);
222
+ };
@@ -164,14 +164,3 @@ export enclose = (text, pre, post, oneIndent="\t") ->
164
164
  indented(text, 1, oneIndent)
165
165
  post
166
166
  ])
167
-
168
- # ---------------------------------------------------------------------------
169
- # elem - indent text, surround with HTML tags
170
-
171
- export elem = (text, tag, oneIndent="\t") ->
172
-
173
- return arrayToBlock([
174
- "<#{tag}>"
175
- indented(text, 1, oneIndent)
176
- "</#{tag}>"
177
- ])
@@ -187,9 +187,3 @@ export var untabify = function(str, numSpaces = 3) {
187
187
  export var enclose = function(text, pre, post, oneIndent = "\t") {
188
188
  return arrayToBlock([pre, indented(text, 1, oneIndent), post]);
189
189
  };
190
-
191
- // ---------------------------------------------------------------------------
192
- // elem - indent text, surround with HTML tags
193
- export var elem = function(text, tag, oneIndent = "\t") {
194
- return arrayToBlock([`<${tag}>`, indented(text, 1, oneIndent), `</${tag}>`]);
195
- };
@@ -183,7 +183,12 @@ export logItem = (label, item, pre='', itemPre=undef) ->
183
183
  putstr "#{pre}#{labelStr}#{item}"
184
184
  else if isString(item)
185
185
  if (item.length <= maxOneLine)
186
- putstr "#{pre}#{labelStr}'#{escapeStr(item)}'"
186
+ result = escapeStr(item)
187
+ hasApos = (result.indexOf("'") >= 0)
188
+ if hasApos
189
+ putstr "#{pre}#{labelStr}\"#{result}\""
190
+ else
191
+ putstr "#{pre}#{labelStr}'#{result}'"
187
192
  else
188
193
  if label
189
194
  putstr "#{pre}#{label}:"
package/src/log_utils.js CHANGED
@@ -184,7 +184,7 @@ export var logBareItem = function(item, pre = '') {
184
184
 
185
185
  // ---------------------------------------------------------------------------
186
186
  export var logItem = function(label, item, pre = '', itemPre = undef) {
187
- var i, labelStr, len, ref, str;
187
+ var hasApos, i, labelStr, len, ref, result, str;
188
188
  assert(isString(pre), `not a string: ${OL(pre)}`);
189
189
  assert(isFunction(putstr), "putstr not properly set");
190
190
  assert(!label || isString(label), "label a non-string");
@@ -207,7 +207,13 @@ export var logItem = function(label, item, pre = '', itemPre = undef) {
207
207
  putstr(`${pre}${labelStr}${item}`);
208
208
  } else if (isString(item)) {
209
209
  if (item.length <= maxOneLine) {
210
- putstr(`${pre}${labelStr}'${escapeStr(item)}'`);
210
+ result = escapeStr(item);
211
+ hasApos = result.indexOf("'") >= 0;
212
+ if (hasApos) {
213
+ putstr(`${pre}${labelStr}\"${result}\"`);
214
+ } else {
215
+ putstr(`${pre}${labelStr}'${result}'`);
216
+ }
211
217
  } else {
212
218
  if (label) {
213
219
  putstr(`${pre}${label}:`);