kni 4.0.3 → 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/link.js CHANGED
@@ -1,58 +1,56 @@
1
- 'use strict';
1
+ const link = story => {
2
+ const labels = Object.keys(story.states);
3
+ for (let i = 0; i < labels.length; i++) {
4
+ const label = labels[i];
5
+ const state = story.states[label];
2
6
 
3
- module.exports = link;
7
+ const link = linker(story, label, state);
4
8
 
5
- function link(story) {
6
- var labels = Object.keys(story.states);
7
- for (var i = 0; i < labels.length; i++) {
8
- var label = labels[i];
9
- var state = story.states[label];
9
+ if (state.label != null) {
10
+ state.label = link('label')(state.label);
11
+ }
12
+ if (state.next != null) {
13
+ state.next = link('next')(state.next);
14
+ }
15
+ if (state.branch != null) {
16
+ state.branch = link('branch')(state.branch);
17
+ }
18
+ if (state.question != null) {
19
+ state.question = state.question.map(link('question'));
20
+ }
21
+ if (state.answer != null) {
22
+ state.answer = state.answer.map(link('answer'));
23
+ }
24
+ }
25
+ };
10
26
 
11
- var link = linker(story, label, state);
27
+ export default link;
12
28
 
13
- if (state.label != null) {
14
- state.label = link('label')(state.label);
15
- }
16
- if (state.next != null) {
17
- state.next = link('next')(state.next);
29
+ const linker = (story, context, state) => {
30
+ const parts = context.split('.');
31
+ const ancestry = [];
32
+ while (parts.length > 0) {
33
+ ancestry.push(parts.slice());
34
+ parts.pop();
35
+ }
36
+ ancestry.push([]);
37
+ return role => {
38
+ return label => {
39
+ if (label === 'RET' || label === 'ESC') {
40
+ return label;
41
+ }
42
+ for (let i = 0; i < ancestry.length; i++) {
43
+ let candidate = ancestry[i].slice();
44
+ candidate.push(label);
45
+ candidate = candidate.join('.');
46
+ if (story.states[candidate] != null) {
47
+ return candidate;
18
48
  }
19
- if (state.branch != null) {
20
- state.branch = link('branch')(state.branch);
21
- }
22
- if (state.question != null) {
23
- state.question = state.question.map(link('question'));
24
- }
25
- if (state.answer != null) {
26
- state.answer = state.answer.map(link('answer'));
27
- }
28
- }
29
- }
30
-
31
- function linker(story, context, state) {
32
- var parts = context.split('.');
33
- var ancestry = [];
34
- while (parts.length > 0) {
35
- ancestry.push(parts.slice());
36
- parts.pop();
37
- }
38
- ancestry.push([]);
39
- return function (role) {
40
- return function (label) {
41
- if (label === 'RET' || label === 'ESC') {
42
- return label;
43
- }
44
- for (var i = 0; i < ancestry.length; i++) {
45
- var candidate = ancestry[i].slice();
46
- candidate.push(label);
47
- candidate = candidate.join('.');
48
- if (story.states[candidate] != null) {
49
- return candidate;
50
- }
51
- }
52
- // istanbul ignore next
53
- story.error('Could not link ' + role + ' label ' + JSON.stringify(label) + ' at position ' + state.position);
54
- // istanbul ignore next
55
- return label;
56
- };
49
+ }
50
+ story.error(
51
+ `Could not link ${role} label ${JSON.stringify(label)} at position ${state.position}`
52
+ );
53
+ return label;
57
54
  };
58
- }
55
+ };
56
+ };
package/outline-lexer.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ // @ts-check
2
2
 
3
3
  // Transforms a stream of lines with known indentation levels and leaders like
4
4
  // bullets, and transforms these into a stream of lines with start and stop
@@ -9,59 +9,86 @@
9
9
 
10
10
  // TODO remove the break emission feature
11
11
 
12
- module.exports = OutlineLexer;
12
+ export default class OutlineLexer {
13
+ debug = typeof process === 'object' && process.env.DEBUG_OUTLINE_LEXER;
13
14
 
14
- var debug = typeof process === 'object' && process.env.DEBUG_OUTLINE_LEXER;
15
+ top = 0;
16
+ broken = false;
15
17
 
16
- function OutlineLexer(generator) {
18
+ /** @typedef {import('./scanner')} Scanner */
19
+
20
+ /** Outline lexer state object, which receives typed text tokens, along
21
+ * with the current scanner. It is expected to return a subsequent state
22
+ * object, which will be retained by the lexer, and receive the subsequent
23
+ * token.
24
+ *
25
+ * @typedef {object} State
26
+ * @prop {(type: string, text: string, sc: Scanner) => State} next
27
+ */
28
+
29
+ /**
30
+ * @param {State} generator
31
+ */
32
+ constructor(generator) {
17
33
  this.generator = generator;
18
- this.top = 0;
19
34
  this.stack = [this.top];
20
- this.broken = false;
21
- this.debug = debug;
22
- }
35
+ }
23
36
 
24
- OutlineLexer.prototype.next = function next(line, scanner) {
25
- // istanbul ignore if
37
+ /**
38
+ * @param {string} line
39
+ * @param {Scanner} scanner
40
+ * @returns {OutlineLexer}
41
+ */
42
+ next(line, scanner) {
26
43
  if (this.debug) {
27
- console.error(
28
- 'OLL', scanner.position(),
29
- JSON.stringify(line),
30
- 'indent', scanner.indent,
31
- 'leader', JSON.stringify(scanner.leader),
32
- 'stack', this.stack,
33
- 'top', this.top
34
- );
44
+ console.error(
45
+ 'OLL',
46
+ scanner.position(),
47
+ JSON.stringify(line),
48
+ 'indent',
49
+ scanner.indent,
50
+ 'leader',
51
+ JSON.stringify(scanner.leader),
52
+ 'stack',
53
+ this.stack,
54
+ 'top',
55
+ this.top
56
+ );
35
57
  }
36
58
  while (scanner.indent < this.top) {
37
- this.generator = this.generator.next('stop', '', scanner);
38
- this.stack.pop();
39
- this.top = this.stack[this.stack.length - 1];
59
+ this.generator = this.generator.next('stop', '', scanner);
60
+ this.stack.pop();
61
+ this.top = this.stack[this.stack.length - 1];
40
62
  }
41
63
  if (scanner.leader.length !== 0 && scanner.indent > this.top) {
42
- this.generator = this.generator.next('start', scanner.leader, scanner);
43
- this.stack.push(scanner.indent);
44
- this.top = scanner.indent;
45
- this.broken = false;
64
+ this.generator = this.generator.next('start', scanner.leader, scanner);
65
+ this.stack.push(scanner.indent);
66
+ this.top = scanner.indent;
67
+ this.broken = false;
46
68
  } else if (scanner.leader.length !== 0 && scanner.indent === this.top) {
47
- this.generator = this.generator.next('stop', '', scanner);
48
- this.generator = this.generator.next('start', scanner.leader, scanner);
49
- this.top = scanner.indent;
50
- this.broken = false;
69
+ this.generator = this.generator.next('stop', '', scanner);
70
+ this.generator = this.generator.next('start', scanner.leader, scanner);
71
+ this.top = scanner.indent;
72
+ this.broken = false;
51
73
  }
52
74
  if (line.length) {
53
- this.generator = this.generator.next('text', line, scanner);
75
+ this.generator = this.generator.next('text', line, scanner);
54
76
  } else if (!this.broken) {
55
- this.broken = true;
56
- this.generator = this.generator.next('break', '', scanner);
77
+ this.broken = true;
78
+ this.generator = this.generator.next('break', '', scanner);
57
79
  }
58
80
  return this;
59
- };
81
+ }
60
82
 
61
- OutlineLexer.prototype.return = function _return(scanner) {
62
- for (var i = 0; i < this.stack.length; i++) {
63
- this.generator = this.generator.next('stop', '', scanner);
83
+ /**
84
+ * @param {Scanner} scanner
85
+ * @returns {OutlineLexer}
86
+ */
87
+ return(scanner) {
88
+ for (let i = 0; i < this.stack.length; i++) {
89
+ this.generator = this.generator.next('stop', '', scanner);
64
90
  }
65
91
  this.stack.length = 0;
66
92
  return this;
67
- };
93
+ }
94
+ }
package/package.json CHANGED
@@ -1,56 +1,49 @@
1
1
  {
2
2
  "name": "kni",
3
- "version": "4.0.3",
3
+ "version": "5.0.0",
4
4
  "description": "A text adventure language and runtime inspired by inkle/ink",
5
+ "type": "module",
5
6
  "bin": {
6
7
  "kni": "./kni.js"
7
8
  },
8
9
  "dependencies": {
9
10
  "pop-equals": "^1.0.0",
10
11
  "shon": "^4.0.0",
11
- "system": "^1.0.6",
12
12
  "table": "^3.7.8",
13
13
  "tee": "^0.2.0",
14
14
  "xorshift": "^1.1.1"
15
15
  },
16
16
  "devDependencies": {
17
- "eslint": "^2.7.0",
18
- "istanbul": "^0.4.3",
19
- "json-diff": "^0.3.1",
20
- "opn": "^1.0.1"
17
+ "@babel/core": "^7.13.1",
18
+ "@babel/eslint-parser": "^7.13.4",
19
+ "@babel/plugin-syntax-class-properties": "^7.12.13",
20
+ "@babel/plugin-syntax-import-attributes": "^7.27.1",
21
+ "@rollup/plugin-node-resolve": "^16.0.3",
22
+ "@types/node": "^14.14.31",
23
+ "eslint": "^7.20.0",
24
+ "nyc": "^15.1.0",
25
+ "open": "^7.4.2",
26
+ "prettier": "^3.7.1",
27
+ "rimraf": "^3.0.2",
28
+ "rollup": "^4.53.3",
29
+ "strip-ansi": "^3.0.1",
30
+ "typescript": "^4.2.2"
21
31
  },
22
32
  "files": [
23
- "console.js",
24
- "describe.js",
25
- "document.js",
26
- "engine.js",
27
- "evaluate.js",
28
- "excerpt.js",
29
- "grammar.js",
30
- "html.js",
31
- "inline-lexer.js",
32
- "kni.js",
33
- "kni.json",
34
- "link.js",
35
- "outline-lexer.js",
36
- "parser.js",
37
- "path.js",
38
- "readline.js",
39
- "scanner.js",
40
- "scope.js",
41
- "story.js",
42
- "template.js",
43
- "translate-json.js",
44
- "verify.js",
45
- "wrapper.js"
33
+ "*.js",
34
+ "!*-test.js",
35
+ "*.json",
36
+ "!.*.json"
46
37
  ],
47
38
  "scripts": {
48
- "test": "npm ls -s && npm run lint && npm run cover -s",
39
+ "format": "prettier --write \"**/*.js\"",
40
+ "format:check": "prettier --check \"**/*.js\"",
49
41
  "lint": "eslint .",
50
- "build": "node kni.js examples/archery.kni -j > examples/archery.json && bundle index.js > bundle.js",
51
- "cover": "istanbul cover --report html --print node -- test.js && istanbul report text && npm run check-cover -s",
52
- "check-cover": "istanbul check-coverage",
53
- "view-cover": "opn ./coverage/index.html",
42
+ "lint-fix": "eslint . --fix",
43
+ "test": "node -- test.js",
44
+ "cover": "nyc npm test",
45
+ "check-cover": "nyc check-coverage",
46
+ "view-cover": "npm run cover && open ./coverage/index.html",
54
47
  "usage": "usage2json kni.usage > kni.json"
55
48
  },
56
49
  "translators": {
package/parser.js CHANGED
@@ -1,29 +1,41 @@
1
- 'use strict';
1
+ // @ts-check
2
2
 
3
- module.exports = Parser;
3
+ export default class Parser {
4
+ debug = typeof process === 'object' && process.env.DEBUG_PARSER;
4
5
 
5
- var debug = typeof process === 'object' && process.env.DEBUG_PARSER;
6
+ /** @typedef {import('./scanner')} Scanner */
6
7
 
7
- function Parser(generator) {
8
+ /**
9
+ * @typedef {object} State
10
+ * @prop {(type: string, space: string, text: string, sc: Scanner) => State} next
11
+ */
12
+
13
+ /**
14
+ * @param {State} generator
15
+ */
16
+ constructor(generator) {
8
17
  this.generator = generator;
9
- this.debug = debug;
10
- }
18
+ }
11
19
 
12
- Parser.prototype.next = function next(type, space, text, scanner) {
13
- var prior = this.generator.constructor.name;
20
+ /**
21
+ * @param {string} type
22
+ * @param {string} space
23
+ * @param {string} text
24
+ * @param {Scanner} scanner
25
+ * @returns {Parser}
26
+ */
27
+ next(type, space, text, scanner) {
28
+ const prior = this.generator.constructor.name;
14
29
  this.generator = this.generator.next(type, space, text, scanner);
15
- // istanbul ignore if
16
- if (!this.generator) {
17
- throw new Error(prior + ' returned undefined next state given ' + type + '/' + text + ' at ' + scanner.position());
18
- }
19
- // istanbul ignore if
20
30
  if (this.debug) {
21
- console.error(
22
- 'PAR',
23
- scanner.position(),
24
- type, JSON.stringify(text),
25
- prior + '->' + this.generator.constructor.name
26
- );
31
+ console.error(
32
+ 'PAR',
33
+ scanner.position(),
34
+ type,
35
+ JSON.stringify(text),
36
+ `${prior}->${this.generator.constructor.name}`
37
+ );
27
38
  }
28
39
  return this;
29
- };
40
+ }
41
+ }
package/path.js CHANGED
@@ -1,46 +1,34 @@
1
- 'use strict';
2
-
3
- exports.start = start;
4
-
5
- function start() {
6
- return ['start'];
7
- }
8
-
9
- exports.toName = pathToName;
10
-
11
- function pathToName(path) {
12
- var name = path[0];
13
- var i;
14
- for (i = 1; i < path.length - 1; i++) {
15
- name += '.' + path[i];
16
- }
17
- var last = path[i];
18
- if (path.length > 1 && last !== 0) {
19
- name += '.' + last;
20
- }
21
- return name;
22
- }
23
-
24
- exports.next = nextPath;
25
-
26
- function nextPath(path) {
27
- path = path.slice();
28
- path[path.length - 1]++;
29
- return path;
30
- }
31
-
32
- exports.firstChild = firstChildPath;
33
-
34
- function firstChildPath(path) {
35
- path = path.slice();
36
- path.push(1);
37
- return path;
38
- }
39
-
40
- exports.zerothChild = zerothChildPath;
41
-
42
- function zerothChildPath(path) {
43
- path = path.slice();
44
- path.push(0);
45
- return path;
46
- }
1
+ export const start = () => {
2
+ return ['start'];
3
+ };
4
+
5
+ export const toName = path => {
6
+ let name = path[0];
7
+ let i;
8
+ for (i = 1; i < path.length - 1; i++) {
9
+ name += `.${path[i]}`;
10
+ }
11
+ const last = path[i];
12
+ if (path.length > 1 && last !== 0) {
13
+ name += `.${last}`;
14
+ }
15
+ return name;
16
+ };
17
+
18
+ export const next = path => {
19
+ path = path.slice();
20
+ path[path.length - 1]++;
21
+ return path;
22
+ };
23
+
24
+ export const firstChild = path => {
25
+ path = path.slice();
26
+ path.push(1);
27
+ return path;
28
+ };
29
+
30
+ export const zerothChild = path => {
31
+ path = path.slice();
32
+ path.push(0);
33
+ return path;
34
+ };