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/html.js CHANGED
@@ -1,168 +1,175 @@
1
- "use strict";
2
-
3
- var fs = require("fs");
4
- var System = require("system");
5
- var bundleSystemId = require("system/bundle").bundleSystemId;
6
- var Location = require("system/location");
7
- var Identifier = require("system/identifier");
8
-
9
- module.exports = makeHtml;
10
- function makeHtml(story, output, templateArgs) {
11
- var location = Location.fromDirectory(__dirname);
12
- var id = "./template";
13
-
14
- return System.load(location, {
15
- node: true
16
- }).then(function (buildSystem) {
17
- return System.load(location, {
18
- browser: true,
19
- buildSystem: buildSystem,
20
- }).then(function (system) {
21
-
22
- // Preempt the loader with a the prepared story:
23
- var module = system.lookup("./story.json");
24
- module.text = 'module.exports = ' + JSON.stringify(story, null, 4);
25
- module.factory = function () {};
26
-
27
- return bundleSystemId(system, id);
28
- });
29
- })
30
- .then(function (script) {
31
- return template(script, templateArgs);
32
- })
33
- .then(function (bundle) {
34
- output.end(bundle);
35
- })
36
- .catch(function (error) {
37
- console.error(error);
38
- process.exit(-1);
1
+ import {rollup} from 'rollup';
2
+ import {nodeResolve} from '@rollup/plugin-node-resolve';
3
+ import {fileURLToPath} from 'url';
4
+ import {dirname, join} from 'path';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ const makeHtml = async (story, output, templateArgs) => {
10
+ try {
11
+ // Create a virtual story module plugin
12
+ const virtualStoryPlugin = {
13
+ name: 'virtual-story',
14
+ resolveId(id) {
15
+ if (id === 'virtual:story') {
16
+ return id;
17
+ }
18
+ return null;
19
+ },
20
+ load(id) {
21
+ if (id === 'virtual:story') {
22
+ return `export default ${JSON.stringify(story, null, 2)};`;
23
+ }
24
+ return null;
25
+ },
26
+ };
27
+
28
+ // Bundle with Rollup
29
+ const bundle = await rollup({
30
+ input: join(__dirname, 'entry.js'),
31
+ plugins: [
32
+ virtualStoryPlugin,
33
+ nodeResolve({
34
+ rootDir: __dirname,
35
+ }),
36
+ ],
37
+ external: [],
39
38
  });
40
- }
41
-
42
- function template(bundle, args) {
43
- var title = '';
44
- if (args.title != null) {
45
- title = '<title>' + title + '</title>';
46
- }
47
- var bgcolor = 'hsla(60, 42.00%, 66.00%, 1)';
48
- if (args.backgroundColor != null) {
49
- bgcolor = args.backgroundColor;
50
- }
51
- var color = 'hsla(240, 42.00%, 25.00%, 1)';
52
- if (args.color != null) {
53
- color = args.color;
54
- }
55
- return [
56
- '<!doctype html>',
57
- '<html>',
58
- ' <head>',
59
- ' <meta charset="utf8">',
60
- ' <meta name="viewport" content="width=device-width, initial-scale=0.75">',
61
- title,
62
- ' <style>',
63
- ' @media handheld {',
64
- ' body {',
65
- ' font-size: 150%;',
66
- ' }',
67
- ' }',
68
- '',
69
- ' body {',
70
- ' font-size: 200%;',
71
- ' background-color: ', bgcolor, ';',
72
- ' color: ', color, ';',
73
- ' overflow: none;',
74
- ' }',
75
- '',
76
- ' .body {',
77
- ' position: absolute;',
78
- ' top: 0;',
79
- ' bottom: 1.5em;',
80
- ' left: 0;',
81
- ' right: 0;',
82
- ' }',
83
- '',
84
- ' .kni-frame {',
85
- ' position: absolute;',
86
- ' height: 100%;',
87
- ' width: 100%;',
88
- ' overflow-y: scroll;',
89
- ' transition: transform 1s ease, opacity 1s ease-out;',
90
- ' }',
91
- '',
92
- ' .kni-frame-a {',
93
- ' display: table;',
94
- ' height: 100%;',
95
- ' width: 100%;',
96
- ' }',
97
- '',
98
- ' .kni-frame-b {',
99
- ' display: table-cell;',
100
- ' vertical-align: middle;',
101
- ' padding: 1em;',
102
- ' width: 40ex;',
103
- ' }',
104
- '',
105
- ' .kni-frame-c {',
106
- ' display: flex;',
107
- ' flex-direction: row;',
108
- ' flex-wrap: nowrap;',
109
- ' justify-content: center;',
110
- ' align-items: flex-start;',
111
- ' }',
112
- '',
113
- ' .kni-body {',
114
- ' display: flex-item;',
115
- ' flex: 0 1 auto;',
116
- ' max-width: 40ex;',
117
- ' text-align: justify;',
118
- ' }',
119
- '',
120
- ' th {',
121
- ' vertical-align: top;',
122
- ' padding-right: 1ex;',
123
- ' }',
124
- '',
125
- ' td {',
126
- ' vertical-align: top;',
127
- ' cursor: pointer;',
128
- ' }',
129
- '',
130
- ' li {',
131
- ' list-style-type: decimal;',
132
- ' }',
133
- '',
134
- ' a {',
135
- ' color: inherit;',
136
- ' font-family: 200%;',
137
- ' }',
138
- '',
139
- ' a:link {',
140
- ' color: inherit;',
141
- ' }',
142
- '',
143
- ' a:hover {',
144
- ' color: inherit;',
145
- ' }',
146
- '',
147
- ' a:visited {',
148
- ' color: inherit;',
149
- ' }',
150
- '',
151
- ' .reset {',
152
- ' position: absolute;',
153
- ' height: 1em;',
154
- ' bottom: 0;',
155
- ' left: 0;',
156
- ' margin: 10px;',
157
- ' }',
158
- ' </style>',
159
- ' </head>',
160
- ' <body>',
161
- ' <div class="reset"><a href="#">reset</a></div>',
162
- ' <script><!--',
163
- bundle,
164
- ' --></script>',
165
- ' </body>',
166
- '</html>',
167
- ].join('\n');
168
- }
39
+
40
+ // Generate output
41
+ const {output: outputs} = await bundle.generate({
42
+ format: 'iife',
43
+ name: 'kni',
44
+ });
45
+
46
+ const script = outputs[0].code;
47
+
48
+ // Generate HTML
49
+ const html = template(script, templateArgs);
50
+ output.end(html);
51
+ } catch (error) {
52
+ console.error(error);
53
+ process.exit(-1);
54
+ }
55
+ };
56
+
57
+ export default makeHtml;
58
+
59
+ const template = (bundle, args) => {
60
+ const title = args.title != null ? `<title>${args.title}</title>` : '';
61
+ const bgcolor = args.backgroundColor ?? 'hsla(60, 42.00%, 66.00%, 1)';
62
+ const color = args.color ?? 'hsla(240, 42.00%, 25.00%, 1)';
63
+
64
+ return `<!doctype html>
65
+ <html>
66
+ <head>
67
+ <meta charset="utf8">
68
+ <meta name="viewport" content="width=device-width, initial-scale=0.75">
69
+ ${title}
70
+ <style>
71
+ @media handheld {
72
+ body {
73
+ font-size: 150%;
74
+ }
75
+ }
76
+
77
+ body {
78
+ font-size: 200%;
79
+ background-color: ${bgcolor};
80
+ color: ${color};
81
+ overflow: none;
82
+ }
83
+
84
+ .body {
85
+ position: absolute;
86
+ top: 0;
87
+ bottom: 1.5em;
88
+ left: 0;
89
+ right: 0;
90
+ }
91
+
92
+ .kni-frame {
93
+ position: absolute;
94
+ height: 100%;
95
+ width: 100%;
96
+ overflow-y: scroll;
97
+ transition: transform 1s ease, opacity 1s ease-out;
98
+ }
99
+
100
+ .kni-frame-a {
101
+ display: table;
102
+ height: 100%;
103
+ width: 100%;
104
+ }
105
+
106
+ .kni-frame-b {
107
+ display: table-cell;
108
+ vertical-align: middle;
109
+ padding: 1em;
110
+ width: 40ex;
111
+ }
112
+
113
+ .kni-frame-c {
114
+ display: flex;
115
+ flex-direction: row;
116
+ flex-wrap: nowrap;
117
+ justify-content: center;
118
+ align-items: flex-start;
119
+ }
120
+
121
+ .kni-body {
122
+ display: flex-item;
123
+ flex: 0 1 auto;
124
+ max-width: 40ex;
125
+ text-align: justify;
126
+ }
127
+
128
+ th {
129
+ vertical-align: top;
130
+ padding-right: 1ex;
131
+ }
132
+
133
+ td {
134
+ vertical-align: top;
135
+ cursor: pointer;
136
+ }
137
+
138
+ li {
139
+ list-style-type: decimal;
140
+ }
141
+
142
+ a {
143
+ color: inherit;
144
+ font-family: 200%;
145
+ }
146
+
147
+ a:link {
148
+ color: inherit;
149
+ }
150
+
151
+ a:hover {
152
+ color: inherit;
153
+ }
154
+
155
+ a:visited {
156
+ color: inherit;
157
+ }
158
+
159
+ .reset {
160
+ position: absolute;
161
+ height: 1em;
162
+ bottom: 0;
163
+ left: 0;
164
+ margin: 10px;
165
+ }
166
+ </style>
167
+ </head>
168
+ <body>
169
+ <div class="reset"><a href="#">reset</a></div>
170
+ <script><!--
171
+ ${bundle}
172
+ --></script>
173
+ </body>
174
+ </html>`;
175
+ };
package/inline-lexer.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ // @ts-check
2
2
 
3
3
  // Receives a stream of start, stop, and text tokens from an outline lexer and
4
4
  // produces a more comprehensive stream of tokens by breaking text tokens into
@@ -11,152 +11,182 @@
11
11
  // states.
12
12
  // The final parse state captures the entire syntax tree.
13
13
 
14
- module.exports = InlineLexer;
14
+ const L1 = '@[]{}|/<>';
15
+ const L2 = ['->', '<-', '==', '<>', '>=', '<=', '{"', '"}', "{'", "'}", '//', '**'];
16
+ const num = /\d/;
15
17
 
16
- var debug = typeof process === 'object' && process.env.DEBUG_INLINE_LEXER;
17
-
18
- var L1 = '@[]{}|/<>';
19
- var L2 = ['->', '<-', '==', '<>', '>=', '<=', '{"', '"}', '{\'', '\'}', '//', '**'];
20
- var num = /\d/;
21
- var space = /\s/;
22
18
  // alphanumerics including non-english
23
- var alpha = /[\w\u00C0-\u1FFF\u2C00-\uD7FF\d_]/;
19
+ const alpha = /[\w\u00C0-\u1FFF\u2C00-\uD7FF\d_]/;
20
+
21
+ /** Receives outline tokens, passing through inter-line structure tokens, and
22
+ * decomposing line tokens along with interstitial space tracking.
23
+ */
24
+ export default class InlineLexer {
25
+ debug = typeof process === 'object' && process.env.DEBUG_INLINE_LEXER;
26
+
27
+ space = '';
28
+ accumulator = '';
29
+ type = 'symbol';
30
+
31
+ /** @typedef {import('./scanner')} Scanner */
24
32
 
25
- function InlineLexer(generator) {
33
+ /** Inline lexer state object, which receives typed text tokens along with
34
+ * any preceding collapsed space, and the current scanner.
35
+ *
36
+ * NOTE: unlike the upstream OutlineLexer.State monad, which
37
+ * InlineLexer.next implements, this is not quite a state monad, as it does
38
+ * not support subsequent state chaining; in practice, that is implemented
39
+ * by Parser. This curious decoupling stands in interesting contrast to the
40
+ * outline layer having coupled together the iterator callback interface
41
+ * with state retention and chaining.
42
+ *
43
+ * @typedef {object} State
44
+ * @prop {(type: string, space: string, text: string, sc: Scanner) => void} next
45
+ */
46
+
47
+ /**
48
+ * @param {State} generator
49
+ */
50
+ constructor(generator) {
26
51
  this.generator = generator;
27
- this.space = '';
28
- this.accumulator = '';
29
- this.type = 'symbol';
30
- this.debug = debug;
31
- Object.seal(this);
32
- }
52
+ }
33
53
 
34
- InlineLexer.prototype.next = function next(type, text, scanner) {
35
- // istanbul ignore if
54
+ /**
55
+ * @param {string} type
56
+ * @param {string} text
57
+ * @param {Scanner} scanner
58
+ */
59
+ next(type, text, scanner) {
36
60
  if (this.debug) {
37
- console.log('ILL', type, JSON.stringify(text));
61
+ console.log('ILL', type, JSON.stringify(text));
38
62
  }
39
63
 
40
64
  if (type !== 'text') {
41
- this.flush();
42
- this.generator.next(type, ' ', text, scanner);
43
- this.space = '';
44
- return this;
65
+ this.flush(scanner);
66
+ this.generator.next(type, ' ', text, scanner);
67
+ this.space = '';
68
+ return this;
45
69
  }
46
70
 
47
- var wrap = false;
48
- for (var i = 0; i < text.length - 1; i++) {
49
- var c = text[i];
50
- var d = text[i + 1];
51
- var cd = c + d;
52
- var numeric = num.test(c);
53
- var alphanum = alpha.test(c);
54
- if (c === ' ' || c === '\t') {
55
- this.flush(scanner);
56
- this.space = ' ';
57
- } else if (cd === '\\ ') {
58
- // Scan forward to end of line until encountering a non-space
59
- // character.
60
- for (i = i + 2; i < text.length; i++) {
61
- c = text[i];
62
- if (c !== ' ' && c !== '\t') {
63
- i--;
64
- break;
65
- }
66
- }
67
- if (i === text.length) {
68
- // If everything after \ is whitespace, then treat it as if
69
- // there is no whitespace, meaning that the \ means continue
70
- // through next line.
71
- wrap = true;
72
- } else {
73
- // Otherwise, treat all following space as a single space.
74
- this.flush(scanner);
75
- this.generator.next('literal', '', ' ', scanner);
76
- this.space = '';
77
- }
78
- } else if (c === '\\') {
79
- // TODO account for escaped space through to the end of line
80
- this.flush(scanner);
81
- this.generator.next('literal', this.space, d, scanner);
82
- this.space = '';
83
- i++;
84
- } else if (L2.indexOf(cd) >= 0) {
85
- this.flush(scanner);
86
- this.generator.next('token', this.space, cd, scanner);
87
- this.space = '';
88
- i++;
89
- } else if (L1.indexOf(c) >= 0) {
90
- this.flush(scanner);
91
- this.generator.next('token', this.space, c, scanner);
92
- this.space = '';
93
- } else if (cd === '--') {
94
- this.flush(scanner);
95
- for (var j = i + 2; j < text.length; j++) {
96
- c = text[j];
97
- if (c !== '-') {
98
- break;
99
- }
100
- }
101
- this.generator.next('dash', this.space, text.slice(i, j), scanner);
102
- i = j - 1;
103
- } else if (this.type !== 'alphanum' && numeric) {
104
- if (this.type != 'number') {
105
- this.flush(scanner);
106
- }
107
- this.accumulator += c;
108
- this.type = 'number';
109
- } else if (alphanum) {
110
- if (this.type != 'alphanum') {
111
- this.flush(scanner);
112
- }
113
- this.accumulator += c;
114
- this.type = 'alphanum';
71
+ let wrap = false;
72
+ let i = 0;
73
+ for (; i < text.length - 1; i++) {
74
+ let c = text[i];
75
+ const d = text[i + 1];
76
+ const cd = c + d;
77
+ const numeric = num.test(c);
78
+ const alphanum = alpha.test(c);
79
+ if (c === ' ' || c === '\t') {
80
+ this.flush(scanner);
81
+ this.space = ' ';
82
+ } else if (cd === '\\ ') {
83
+ // Scan forward to end of line until encountering a non-space
84
+ // character.
85
+ for (i = i + 2; i < text.length; i++) {
86
+ c = text[i];
87
+ if (c !== ' ' && c !== '\t') {
88
+ i--;
89
+ break;
90
+ }
91
+ }
92
+ if (i === text.length) {
93
+ // If everything after \ is whitespace, then treat it as if
94
+ // there is no whitespace, meaning that the \ means continue
95
+ // through next line.
96
+ wrap = true;
115
97
  } else {
116
- this.flush(scanner);
117
- this.generator.next(this.type, this.space, c, scanner);
118
- this.space = '';
98
+ // Otherwise, treat all following space as a single space.
99
+ this.flush(scanner);
100
+ this.generator.next('literal', '', ' ', scanner);
101
+ this.space = '';
119
102
  }
103
+ } else if (c === '\\') {
104
+ // TODO account for escaped space through to the end of line
105
+ this.flush(scanner);
106
+ this.generator.next('literal', this.space, d, scanner);
107
+ this.space = '';
108
+ i++;
109
+ } else if (L2.indexOf(cd) >= 0) {
110
+ this.flush(scanner);
111
+ this.generator.next('token', this.space, cd, scanner);
112
+ this.space = '';
113
+ i++;
114
+ } else if (L1.indexOf(c) >= 0) {
115
+ this.flush(scanner);
116
+ this.generator.next('token', this.space, c, scanner);
117
+ this.space = '';
118
+ } else if (cd === '--') {
119
+ this.flush(scanner);
120
+ let j = i + 2;
121
+ for (; j < text.length; j++) {
122
+ c = text[j];
123
+ if (c !== '-') {
124
+ break;
125
+ }
126
+ }
127
+ this.generator.next('dash', this.space, text.slice(i, j), scanner);
128
+ i = j - 1;
129
+ } else if (this.type !== 'alphanum' && numeric) {
130
+ if (this.type != 'number') {
131
+ this.flush(scanner);
132
+ }
133
+ this.accumulator += c;
134
+ this.type = 'number';
135
+ } else if (alphanum) {
136
+ if (this.type != 'alphanum') {
137
+ this.flush(scanner);
138
+ }
139
+ this.accumulator += c;
140
+ this.type = 'alphanum';
141
+ } else {
142
+ this.flush(scanner);
143
+ this.generator.next(this.type, this.space, c, scanner);
144
+ this.space = '';
145
+ }
120
146
  }
121
147
 
122
148
  if (i < text.length) {
123
- var c = text[i];
124
- var numeric = num.test(c);
125
- var alphanum = alpha.test(c);
126
- if (c === '\\') {
127
- wrap = true;
128
- } else if (c === ' ' || c === '\t') {
129
- // noop
130
- } else if (L1.indexOf(c) >= 0) {
131
- this.flush(scanner);
132
- this.generator.next('token', this.space, c, scanner);
133
- } else if (this.type !== 'alphanum' && numeric) {
134
- if (this.type !== 'number') {
135
- this.flush(scanner);
136
- }
137
- this.accumulator += c;
138
- this.type = 'number';
139
- } else if (!alphanum) {
140
- this.flush(scanner);
141
- this.generator.next(this.type, this.space, c, scanner);
142
- } else {
143
- this.type = 'alphanum';
144
- this.accumulator += c;
149
+ const c = text[i];
150
+ const numeric = num.test(c);
151
+ const alphanum = alpha.test(c);
152
+ if (c === '\\') {
153
+ wrap = true;
154
+ } else if (c === ' ' || c === '\t') {
155
+ // noop
156
+ } else if (L1.indexOf(c) >= 0) {
157
+ this.flush(scanner);
158
+ this.generator.next('token', this.space, c, scanner);
159
+ } else if (this.type !== 'alphanum' && numeric) {
160
+ if (this.type !== 'number') {
161
+ this.flush(scanner);
145
162
  }
163
+ this.accumulator += c;
164
+ this.type = 'number';
165
+ } else if (!alphanum) {
166
+ this.flush(scanner);
167
+ this.generator.next(this.type, this.space, c, scanner);
168
+ } else {
169
+ this.type = 'alphanum';
170
+ this.accumulator += c;
171
+ }
146
172
  }
147
173
 
148
174
  if (!wrap) {
149
- this.flush(scanner);
150
- this.space = ' ';
175
+ this.flush(scanner);
176
+ this.space = ' ';
151
177
  }
152
178
  return this;
153
- };
179
+ }
154
180
 
155
- InlineLexer.prototype.flush = function flush(scanner) {
181
+ /**
182
+ * @param {Scanner} scanner
183
+ */
184
+ flush(scanner) {
156
185
  if (this.accumulator) {
157
- this.generator.next(this.type, this.space, this.accumulator, scanner);
158
- this.accumulator = '';
159
- this.space = '';
160
- this.type = 'symbol';
186
+ this.generator.next(this.type, this.space, this.accumulator, scanner);
187
+ this.accumulator = '';
188
+ this.space = '';
189
+ this.type = 'symbol';
161
190
  }
162
- };
191
+ }
192
+ }