kni 4.0.2 → 5.0.0

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/readline.js CHANGED
@@ -1,143 +1,153 @@
1
- 'use strict';
1
+ import readline from 'readline';
2
+ import fs from 'fs';
2
3
 
3
- var readline = require('readline');
4
- var fs = require('fs');
5
-
6
- module.exports = Readline;
7
-
8
- function Readline(transcript, filename) {
9
- var self = this;
4
+ export default class Readline {
5
+ constructor(transcript, filename) {
6
+ const self = this;
10
7
  this.readline = readline.createInterface({
11
- input: process.stdin,
12
- output: process.stdout
8
+ input: process.stdin,
9
+ output: process.stdout,
13
10
  });
14
11
  this.engine = null;
15
- this.boundAnswer = answer;
12
+ this.boundAnswer = text => {
13
+ self.answer(text);
14
+ };
16
15
  this.transcript = transcript;
17
16
  this.history = [];
18
17
  this.state = new Play(this, filename);
19
18
  Object.seal(this);
20
- function answer(text) {
21
- self.answer(text);
22
- }
23
- }
19
+ }
20
+
21
+ meterFault() {
22
+ this.readline.question(`Enter any command to continue... `, (answer) => {
23
+ if (answer === 'quit') {
24
+ this.close();
25
+ } else {
26
+ this.engine.clearMeterFault();
27
+ }
28
+ });
29
+ }
24
30
 
25
- Readline.prototype.ask = function ask(cue) {
26
- this.readline.question((cue || '') + '> ', this.boundAnswer);
27
- };
31
+ ask(cue) {
32
+ this.readline.question(`${cue || ''}> `, this.boundAnswer);
33
+ }
28
34
 
29
- Readline.prototype.answer = function answer(text) {
35
+ answer(text) {
30
36
  if (this.transcript) {
31
- this.transcript.write('> ' + text + '\n');
37
+ this.transcript.write(`> ${text}\n`);
32
38
  }
33
39
  this.state = this.state.answer(text);
34
- };
40
+ }
35
41
 
36
- Readline.prototype.close = function close() {
42
+ close() {
37
43
  if (this.transcript) {
38
- this.transcript.write('\n');
44
+ this.transcript.write('\n');
39
45
  }
40
46
  this.readline.close();
41
- };
47
+ }
48
+ }
42
49
 
43
- function Play(readline, filename) {
50
+ class Play {
51
+ constructor(readline, filename) {
44
52
  this.readline = readline;
45
53
  this.filename = filename || 'kni.waypoint';
46
- }
54
+ }
47
55
 
48
- Play.prototype.answer = function answer(text) {
49
- var engine = this.readline.engine;
56
+ answer(text) {
57
+ const engine = this.readline.engine;
50
58
 
51
59
  if (text === 'quit') {
52
- console.log('');
53
- engine.dialog.close();
54
- // istanbul ignore next
60
+ console.log('');
61
+ engine.dialog.close();
55
62
  } else if (text === 'bt' || text === 'trace') {
56
- engine.log();
57
- engine.ask();
58
- // istanbul ignore next
63
+ engine.log();
64
+ engine.ask();
59
65
  } else if (text === 'capture' || text === 'cap') {
60
- console.log(JSON.stringify(engine.waypoint));
61
- console.log('');
62
- engine.ask();
63
- // istanbul ignore next
66
+ console.log(JSON.stringify(engine.waypoint));
67
+ console.log('');
68
+ engine.ask();
64
69
  } else if (text === 'save') {
65
- console.log('');
66
- engine.dialog.ask('file name [' + this.filename + ']> ');
67
- return new Save(this, engine.waypoint, this.filename);
70
+ console.log('');
71
+ engine.dialog.ask(`file name [${this.filename}]> `);
72
+ return new Save(this, engine.waypoint, this.filename);
68
73
  } else if (text === 'load') {
69
- console.log('');
70
- engine.dialog.ask('file name [' + this.filename + ']> ');
71
- return new Load(this, this.filename);
74
+ console.log('');
75
+ engine.dialog.ask(`file name [${this.filename}]> `);
76
+ return new Load(this, this.filename);
72
77
  } else if (text === 'back') {
73
- console.log('');
74
- if (this.readline.transcript) {
75
- this.readline.transcript.write('\n');
76
- }
77
- if (this.readline.history.length <= 1) {
78
- console.log('Meanwhile, at the beginning of recorded history...');
79
- }
80
- engine.waypoint = this.readline.history.pop();
81
- engine.resume(engine.waypoint);
78
+ console.log('');
79
+ if (this.readline.transcript) {
80
+ this.readline.transcript.write('\n');
81
+ }
82
+ if (this.readline.history.length <= 1) {
83
+ console.log('Meanwhile, at the beginning of recorded history...');
84
+ }
85
+ engine.waypoint = this.readline.history.pop();
86
+ engine.resume(engine.waypoint);
82
87
  } else if (text === 'replay') {
83
- console.log('');
84
- if (this.readline.transcript) {
85
- this.readline.transcript.write('\n');
86
- }
87
- engine.resume(engine.waypoint);
88
+ console.log('');
89
+ if (this.readline.transcript) {
90
+ this.readline.transcript.write('\n');
91
+ }
92
+ engine.resume(engine.waypoint);
88
93
  } else {
89
- this.readline.history.push(engine.waypoint);
90
- engine.answer(text);
94
+ this.readline.history.push(engine.waypoint);
95
+ engine.answer(text);
91
96
  }
92
97
  return this;
93
- };
98
+ }
94
99
 
95
- Play.prototype.saved = function saved(filename) {
96
- var engine = this.readline.engine;
100
+ saved(filename) {
101
+ const engine = this.readline.engine;
97
102
 
98
103
  this.filename = filename;
99
104
  engine.ask();
100
105
  return this;
101
- };
106
+ }
102
107
 
103
- Play.prototype.loaded = function loaded(waypoint) {
104
- var engine = this.readline.engine;
108
+ loaded(waypoint) {
109
+ const engine = this.readline.engine;
105
110
 
106
111
  engine.resume(waypoint);
107
112
  return this;
108
- };
113
+ }
114
+ }
109
115
 
110
- function Save(parent, waypoint, filename) {
116
+ class Save {
117
+ constructor(parent, waypoint, filename) {
111
118
  this.parent = parent;
112
119
  this.waypoint = waypoint;
113
120
  this.filename = filename;
114
- }
121
+ }
115
122
 
116
- Save.prototype.answer = function answer(filename) {
117
- var waypoint = JSON.stringify(this.waypoint);
123
+ answer(filename) {
124
+ const waypoint = JSON.stringify(this.waypoint);
118
125
  filename = filename || this.filename;
119
126
  fs.writeFileSync(filename, waypoint, 'utf8');
120
127
 
121
128
  console.log('');
122
- console.log('Waypoint written to ' + filename);
129
+ console.log(`Waypoint written to ${filename}`);
123
130
  console.log(waypoint);
124
131
  console.log('');
125
132
  return this.parent.saved(filename);
126
- };
133
+ }
134
+ }
127
135
 
128
- function Load(parent, filename) {
136
+ class Load {
137
+ constructor(parent, filename) {
129
138
  this.parent = parent;
130
139
  this.filename = filename;
131
- }
140
+ }
132
141
 
133
- Load.prototype.answer = function answer(filename) {
142
+ answer(filename) {
134
143
  filename = filename || this.filename;
135
144
 
136
- var waypoint = fs.readFileSync(filename, 'utf8');
145
+ const waypoint = fs.readFileSync(filename, 'utf8');
137
146
  console.log('');
138
- console.log('Loaded from ' + filename);
147
+ console.log(`Loaded from ${filename}`);
139
148
  console.log(waypoint);
140
149
  console.log('');
141
150
 
142
151
  return this.parent.loaded(JSON.parse(waypoint));
143
- };
152
+ }
153
+ }
package/scanner.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ // @ts-check
2
2
 
3
3
  // Transforms a stream of text into a sequence of 'lines', tracking each line's
4
4
  // level of indentation.
@@ -7,86 +7,111 @@
7
7
  //
8
8
  // The scanner feeds into an outline lexer.
9
9
 
10
- var tabWidth = 4;
11
- var leaders = '-+*!>';
12
- var debug = typeof process === 'object' && process.env.DEBUG_SCANNER;
10
+ const tabWidth = 4;
13
11
 
14
- module.exports = Scanner;
12
+ /**
13
+ * @param {number} columnNo -- screen column number (logical X coord)
14
+ * @returns {number} -- column number where the next tab stop starts
15
+ */
16
+ const nextTabStop = columnNo => {
17
+ // TODO simplify with modulo arithmetic
18
+ return Math.floor((columnNo + tabWidth) / tabWidth) * tabWidth;
19
+ };
20
+
21
+ const leaders = '-+*!>';
22
+
23
+ export default class Scanner {
24
+ debug = typeof process === 'object' && process.env.DEBUG_SCANNER;
25
+
26
+ indent = 0;
27
+ lineStart = 0;
28
+ indentStart = 0;
29
+ itemStart = 0;
30
+ lineNo = 0;
31
+ columnNo = 0;
32
+ columnStart = 0;
33
+ leading = true;
34
+ leader = '';
35
+
36
+ /** An Iterator-like object that has text pushed into it by a Scanner.
37
+ *
38
+ * Its biggest difference from an Iterator<string> is that the Scanner
39
+ * object itself is passed along as an additional next agument
40
+ *
41
+ * @typedef {object} ScanIt
42
+ * @prop {(text: string, sc: Scanner) => void} next
43
+ * @prop {(sc: Scanner) => void} return
44
+ */
15
45
 
16
- function Scanner(generator, fileName) {
46
+ /**
47
+ * @param {ScanIt} generator
48
+ * @param {string} fileName
49
+ */
50
+ constructor(generator, fileName) {
17
51
  this.generator = generator;
18
52
  this.fileName = fileName || '-';
19
- this.indent = 0;
20
- this.lineStart = 0;
21
- this.indentStart = 0;
22
- this.itemStart = 0;
23
- this.lineNo = 0;
24
- this.columnNo = 0;
25
- this.columnStart = 0;
26
- this.leading = true;
27
- this.leader = '';
28
- this.debug = debug;
29
- Object.seal(this);
30
- }
53
+ }
31
54
 
32
- Scanner.prototype.next = function next(text) {
33
- for (var i = 0; i < text.length; i++) {
34
- var c = text[i];
35
- var d = text[i + 1];
36
- // istanbul ignore if
37
- if (this.debug) {
38
- console.error('SCN', this.position() + ':' + i, JSON.stringify(c + (d || '')));
39
- }
40
- if (
41
- ((c === '\t' || c === ' ') && d === '#') ||
42
- (this.columnNo === 0 && c === '#')
43
- ) {
44
- this.newLine(text, i);
45
- for (i++; i < text.length; i++) {
46
- c = text[i];
47
- if (c === '\n') {
48
- break;
49
- }
50
- }
51
- } else if (c === '\t') {
52
- this.columnNo = nextTabStop(this.columnNo);
53
- } else if (c === '\n') {
54
- this.newLine(text, i);
55
- } else if (c === ' ') {
56
- this.columnNo++;
57
- } else if (
58
- this.leading && leaders.indexOf(c) >= 0 &&
59
- (d === ' ' || d === '\t')
60
- ) {
61
- this.leader += c;
62
- this.columnNo++;
63
- } else if (this.leading && leaders.indexOf(c) >= 0 && d === '\n') {
64
- this.leader += c;
65
- this.indentStart = i;
66
- this.columnStart = this.columnNo;
67
- this.lineStart = this.lineNo;
68
- this.indent = this.columnNo + 2;
69
- } else if (this.leading) {
70
- this.indent = this.columnNo;
71
- this.indentStart = i;
72
- this.columnStart = this.columnNo;
73
- this.lineStart = this.lineNo;
74
- this.columnNo++;
75
- this.leading = false;
55
+ /**
56
+ * @param {string} text
57
+ * @returns {void}
58
+ */
59
+ next(text) {
60
+ let i = 0;
61
+ for (; i < text.length; i++) {
62
+ let c = text[i];
63
+ const d = text[i + 1];
64
+ if (this.debug) {
65
+ console.error('SCN', `${this.position()}:${i}`, JSON.stringify(c + (d || '')));
66
+ }
67
+ if (((c === '\t' || c === ' ') && d === '#') || (this.columnNo === 0 && c === '#')) {
68
+ this.newLine(text, i);
69
+ for (i++; i < text.length; i++) {
70
+ c = text[i];
71
+ if (c === '\n') {
72
+ break;
73
+ }
76
74
  }
75
+ } else if (c === '\t') {
76
+ this.columnNo = nextTabStop(this.columnNo);
77
+ } else if (c === '\n') {
78
+ this.newLine(text, i);
79
+ } else if (c === ' ') {
80
+ this.columnNo++;
81
+ } else if (this.leading && leaders.indexOf(c) >= 0 && (d === ' ' || d === '\t')) {
82
+ this.leader += c;
83
+ this.columnNo++;
84
+ } else if (this.leading && leaders.indexOf(c) >= 0 && d === '\n') {
85
+ this.leader += c;
86
+ this.indentStart = i;
87
+ this.columnStart = this.columnNo;
88
+ this.lineStart = this.lineNo;
89
+ this.indent = this.columnNo + 2;
90
+ } else if (this.leading) {
91
+ this.indent = this.columnNo;
92
+ this.indentStart = i;
93
+ this.columnStart = this.columnNo;
94
+ this.lineStart = this.lineNo;
95
+ this.columnNo++;
96
+ this.leading = false;
97
+ }
77
98
  }
78
99
 
79
100
  // TODO To exercise the following block, you need a file with no final
80
101
  // newline.
81
- // istanbul ignore if
82
102
  if (!this.leading) {
83
- this.generator.next(text.slice(this.indentStart, i), this);
103
+ this.generator.next(text.slice(this.indentStart, i), this);
84
104
  }
85
- };
105
+ }
86
106
 
87
- Scanner.prototype.newLine = function newLine(text, i) {
107
+ /**
108
+ * @param {string} text
109
+ * @param {number} i
110
+ * @returns {void}
111
+ */
112
+ newLine(text, i) {
88
113
  if (this.leading) {
89
- this.indentStart = i;
114
+ this.indentStart = i;
90
115
  }
91
116
  this.leading = true;
92
117
  this.generator.next(text.slice(this.indentStart, i), this);
@@ -94,18 +119,16 @@ Scanner.prototype.newLine = function newLine(text, i) {
94
119
  this.lineNo++;
95
120
  this.lineStart = i + 1;
96
121
  this.leader = '';
97
- };
122
+ }
98
123
 
99
- Scanner.prototype.return = function _return() {
124
+ /**
125
+ * @returns {void}
126
+ */
127
+ return() {
100
128
  this.generator.return(this);
101
- };
102
-
103
- // istanbul ignore next
104
- Scanner.prototype.position = function position() {
105
- return this.fileName + ':' + (this.lineNo + 1) + ':' + (this.columnStart + 1);
106
- };
129
+ }
107
130
 
108
- function nextTabStop(columnNo) {
109
- // TODO simplify with modulo arithmetic
110
- return Math.floor((columnNo + tabWidth) / tabWidth) * tabWidth;
131
+ position() {
132
+ return `${this.fileName}:${this.lineNo + 1}:${this.columnStart + 1}`;
133
+ }
111
134
  }
package/scope.js CHANGED
@@ -1,57 +1,53 @@
1
- 'use strict';
2
-
3
- var Path = require('./path');
4
-
5
- module.exports = Scope;
1
+ import * as Path from './path.js';
2
+
3
+ export default class Scope {
4
+ static tie(ends, name) {
5
+ for (let i = 0; i < ends.length; i++) {
6
+ const end = ends[i];
7
+ if (end.type === 'branch') {
8
+ end.node.branch = name;
9
+ } else {
10
+ end.next = name;
11
+ }
12
+ }
13
+ }
6
14
 
7
- function Scope(story, path, base) {
15
+ constructor(story, path, base) {
8
16
  this.story = story;
9
17
  this.path = path;
10
18
  this.base = base;
11
19
  Object.seal(this);
12
- }
20
+ }
13
21
 
14
- Scope.prototype.name = function name() {
22
+ name() {
15
23
  return Path.toName(this.path);
16
- };
24
+ }
17
25
 
18
- Scope.prototype.create = function create(type, arg, position) {
26
+ create(type, arg, position) {
19
27
  return this.story.create(this.path, type, arg, position);
20
- };
28
+ }
21
29
 
22
- Scope.prototype.next = function next() {
30
+ next() {
23
31
  return new Scope(this.story, Path.next(this.path), this.base);
24
- };
32
+ }
25
33
 
26
- Scope.prototype.zerothChild = function zerothChild() {
34
+ zerothChild() {
27
35
  return new Scope(this.story, Path.zerothChild(this.path), this.base);
28
- };
36
+ }
29
37
 
30
- Scope.prototype.firstChild = function firstChild() {
38
+ firstChild() {
31
39
  return new Scope(this.story, Path.firstChild(this.path), this.base);
32
- };
40
+ }
33
41
 
34
- Scope.prototype.label = function label(label) {
42
+ label(label) {
35
43
  return new Scope(this.story, this.base.concat([label, 0]), this.base);
36
- };
44
+ }
37
45
 
38
- Scope.prototype.tie = function _tie(nodes) {
39
- tie(nodes, this.name());
40
- };
46
+ tie(nodes) {
47
+ Scope.tie(nodes, this.name());
48
+ }
41
49
 
42
- // istanbul ignore next
43
- Scope.prototype.error = function (message) {
50
+ error(message) {
44
51
  this.story.error(message);
45
- };
46
-
47
- Scope.tie = tie;
48
- function tie(ends, name) {
49
- for (var i = 0; i < ends.length; i++) {
50
- var end = ends[i];
51
- if (end.type === 'branch') {
52
- end.node.branch = name;
53
- } else {
54
- end.next = name;
55
- }
56
- }
52
+ }
57
53
  }