@slugbugblue/trax-cli 0.12.1 → 0.14.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/.claude/settings.local.json +8 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/eslint.config.js +24 -0
- package/package.json +7 -18
- package/src/cli.js +246 -106
- package/src/cmds/analyze.js +72 -66
- package/src/cmds/delete.js +35 -43
- package/src/cmds/help.js +54 -57
- package/src/cmds/import-export.js +200 -146
- package/src/cmds/index.js +40 -0
- package/src/cmds/list.js +100 -87
- package/src/cmds/new.js +56 -55
- package/src/cmds/notes.js +20 -18
- package/src/cmds/play-try.js +157 -106
- package/src/cmds/puzzles.js +53 -39
- package/src/cmds/select.js +22 -31
- package/src/cmds/suggest.js +28 -37
- package/src/cmds/undo.js +31 -26
- package/src/cmds/view.js +42 -51
- package/src/utils.js +1 -1
- package/src/version.js +1 -1
- package/xo.config.js +10 -0
- package/src/types.d.ts +0 -33
package/src/cmds/list.js
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* You may obtain a copy of the License at
|
|
6
|
-
*
|
|
7
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
*
|
|
9
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
* See the License for the specific language governing permissions and
|
|
13
|
-
* limitations under the License.
|
|
1
|
+
/** CLI list command
|
|
2
|
+
* @copyright 2022-2026
|
|
3
|
+
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
|
+
* @license Apache-2.0
|
|
14
5
|
*/
|
|
15
6
|
|
|
16
|
-
|
|
7
|
+
/** @typedef {import('../cli.js').CLIContext} CLIContext */
|
|
17
8
|
|
|
18
9
|
import process from 'node:process'
|
|
19
10
|
import { Trax } from '@slugbugblue/trax'
|
|
@@ -39,8 +30,83 @@ export const listCmd = {
|
|
|
39
30
|
" <other text>: match a player's name or the latest game note",
|
|
40
31
|
'Add the "reverse" option to reverse the sort order.',
|
|
41
32
|
],
|
|
33
|
+
/** @param {CLIContext} CLI @param {...string} filters */
|
|
34
|
+
fn(CLI, ...filters) {
|
|
35
|
+
if (Object.keys(CLI.GAMES).length === 0) {
|
|
36
|
+
return CLI.error('No games. Type "new" to start a new game.')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const puzzle = filters.find((f) => f.length > 1 && 'puzzles'.startsWith(f))
|
|
40
|
+
if (puzzle) return CLI.do('puzzles', ...filters.filter((f) => f !== puzzle))
|
|
41
|
+
|
|
42
|
+
/** @type {Array<Record<string, string | number | boolean | undefined>>} */
|
|
43
|
+
let list = []
|
|
44
|
+
const size = {
|
|
45
|
+
spacing: 13, // Amount of space taken up by fixed-length and between columns
|
|
46
|
+
id: 1,
|
|
47
|
+
name: 1,
|
|
48
|
+
moves: 1,
|
|
49
|
+
p1: 1,
|
|
50
|
+
p2: 1,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const game of Object.values(CLI.GAMES)) {
|
|
54
|
+
const moves = game.moves.length === 0 ? 0 : game.moves.split(' ').length
|
|
55
|
+
list.push({
|
|
56
|
+
sid: String(game.id).padStart(9, '0'),
|
|
57
|
+
id: (game.id === CLI.GAME.id ? '* #' : '#') + String(game.id),
|
|
58
|
+
name: game.name?.length || 0,
|
|
59
|
+
rules: game.rules,
|
|
60
|
+
moves: game.over ? 'game over' : CLI.plural(moves, 'move'),
|
|
61
|
+
smoves: game.over ? '9999' : String(moves).padStart(9, '0'),
|
|
62
|
+
sturn: String(game.turn),
|
|
63
|
+
p1: game.players?.[0] || 'white',
|
|
64
|
+
p2: game.players?.[1] || 'black',
|
|
65
|
+
turn: game.turn,
|
|
66
|
+
over: game.over,
|
|
67
|
+
note: game.notes?.at(-1)?.note || '',
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
list = listSort(list, filters)
|
|
72
|
+
renderList(CLI, list, size)
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {CLIContext} CLI - the CLI object
|
|
78
|
+
* @param {Array<Record<string, string | number | boolean | undefined>>} list - sorted game list
|
|
79
|
+
* @param {Record<string, number>} size - initial column width minimums
|
|
80
|
+
*/
|
|
81
|
+
const renderList = (CLI, list, size) => {
|
|
82
|
+
let noteSize = Number.POSITIVE_INFINITY
|
|
83
|
+
for (const game of list) {
|
|
84
|
+
size.id = Math.max(size.id, String(game.id).length)
|
|
85
|
+
size.name = Math.max(size.name, Number(game.name))
|
|
86
|
+
size.moves = Math.max(size.moves, String(game.moves).length)
|
|
87
|
+
size.p1 = Math.max(size.p1, String(game.p1).length)
|
|
88
|
+
size.p2 = Math.max(size.p2, String(game.p2).length)
|
|
89
|
+
noteSize = Math.min(noteSize, leftover(size))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for (const game of list) {
|
|
93
|
+
CLI.out(
|
|
94
|
+
CLI.color(String(game.id).padStart(size.id) + ' ') +
|
|
95
|
+
Trax.names[
|
|
96
|
+
/** @type {import('../cli.js').TraxVariant} */ (String(game.rules))
|
|
97
|
+
] +
|
|
98
|
+
' '.repeat(size.name - Number(game.name) + 1) +
|
|
99
|
+
CLI.bubble(game.turn === 1 ? 'wh' : 'w', String(game.p1)) +
|
|
100
|
+
CLI.color('vs '.padStart(size.p1 - String(game.p1).length + 4)) +
|
|
101
|
+
CLI.bubble(game.turn === 2 ? 'bh' : 'b', String(game.p2)) +
|
|
102
|
+
CLI.color(' '.padStart(size.p2 - String(game.p2).length + 1)) +
|
|
103
|
+
CLI.color(String(game.moves).padEnd(size.moves)) +
|
|
104
|
+
CLI.color.help(' ' + String(game.note).slice(0, noteSize)),
|
|
105
|
+
)
|
|
106
|
+
}
|
|
42
107
|
}
|
|
43
108
|
|
|
109
|
+
/** @param {string} a @param {string} b @returns {number} */
|
|
44
110
|
const alphaSort = (a, b) => {
|
|
45
111
|
a = String(a).toLowerCase()
|
|
46
112
|
b = String(b).toLowerCase()
|
|
@@ -49,6 +115,7 @@ const alphaSort = (a, b) => {
|
|
|
49
115
|
return 0
|
|
50
116
|
}
|
|
51
117
|
|
|
118
|
+
/** @param {string | undefined} sort @returns {string} */
|
|
52
119
|
const sortBy = (sort) => {
|
|
53
120
|
if (!sort) return 'id'
|
|
54
121
|
sort = sort.toLowerCase()
|
|
@@ -67,6 +134,11 @@ const sortBy = (sort) => {
|
|
|
67
134
|
return sort
|
|
68
135
|
}
|
|
69
136
|
|
|
137
|
+
/**
|
|
138
|
+
* @param {Array<Record<string, string | number | boolean | undefined>>} list
|
|
139
|
+
* @param {string[]} filters
|
|
140
|
+
* @returns {Array<Record<string, string | number | boolean | undefined>>}
|
|
141
|
+
*/
|
|
70
142
|
const listSort = (list, filters) => {
|
|
71
143
|
if (list.length === 0) return list
|
|
72
144
|
let reverse = false
|
|
@@ -75,7 +147,7 @@ const listSort = (list, filters) => {
|
|
|
75
147
|
if (by === 'reverse') {
|
|
76
148
|
reverse = true
|
|
77
149
|
} else if (list[0]?.[by]) {
|
|
78
|
-
list.sort((a, b) => alphaSort(a[by], b[by]))
|
|
150
|
+
list.sort((a, b) => alphaSort(String(a[by]), String(b[by])))
|
|
79
151
|
} else if (by === 'trax') {
|
|
80
152
|
list = list.filter((g) => g.rules === by)
|
|
81
153
|
} else if (['over', 'active'].includes(by)) {
|
|
@@ -83,12 +155,16 @@ const listSort = (list, filters) => {
|
|
|
83
155
|
} else {
|
|
84
156
|
list = list.filter((g) => {
|
|
85
157
|
return (
|
|
86
|
-
g.id.endsWith(by) ||
|
|
87
|
-
Trax.names[
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
158
|
+
String(g.id).endsWith(by) ||
|
|
159
|
+
Trax.names[
|
|
160
|
+
/** @type {import('../cli.js').TraxVariant} */ (String(g.rules))
|
|
161
|
+
]
|
|
162
|
+
.toLowerCase()
|
|
163
|
+
.includes(by) ||
|
|
164
|
+
String(g.p1).toLowerCase().includes(by) ||
|
|
165
|
+
String(g.p2).toLowerCase().includes(by) ||
|
|
166
|
+
String(g.moves).startsWith(by + ' ') ||
|
|
167
|
+
String(g.note).includes(by)
|
|
92
168
|
)
|
|
93
169
|
})
|
|
94
170
|
}
|
|
@@ -99,9 +175,9 @@ const listSort = (list, filters) => {
|
|
|
99
175
|
return list
|
|
100
176
|
}
|
|
101
177
|
|
|
102
|
-
/** Find how many columns are left over after all the other columns
|
|
103
|
-
* @
|
|
104
|
-
* @returns {number}
|
|
178
|
+
/** Find how many columns are left over after all the other columns are filled.
|
|
179
|
+
* @param {Record<string, number>} sizes
|
|
180
|
+
* @returns {number}
|
|
105
181
|
*/
|
|
106
182
|
const leftover = (sizes) => {
|
|
107
183
|
let left = process.stdout.columns
|
|
@@ -111,66 +187,3 @@ const leftover = (sizes) => {
|
|
|
111
187
|
|
|
112
188
|
return left
|
|
113
189
|
}
|
|
114
|
-
|
|
115
|
-
listCmd.fn = (CLI, ...filters) => {
|
|
116
|
-
if (Object.keys(CLI.GAMES).length === 0) {
|
|
117
|
-
return CLI.error('No games. Type "new" to start a new game.')
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const puzzle = filters.find((f) => f.length > 1 && 'puzzles'.startsWith(f))
|
|
121
|
-
if (puzzle) return CLI.do('puzzles', ...filters.filter((f) => f !== puzzle))
|
|
122
|
-
|
|
123
|
-
let list = []
|
|
124
|
-
const size = {
|
|
125
|
-
spacing: 13, // Amount of space taken up by fixed-length and between columns
|
|
126
|
-
id: 1,
|
|
127
|
-
name: 1,
|
|
128
|
-
moves: 1,
|
|
129
|
-
p1: 1,
|
|
130
|
-
p2: 1,
|
|
131
|
-
}
|
|
132
|
-
let noteSize = Number.POSITIVE_INFINITY
|
|
133
|
-
|
|
134
|
-
for (const game of Object.values(CLI.GAMES)) {
|
|
135
|
-
const moves = game.moves.length === 0 ? 0 : game.moves.split(' ').length
|
|
136
|
-
list.push({
|
|
137
|
-
sid: String(game.id).padStart(9, '0'),
|
|
138
|
-
id: (game.id === CLI.GAME.id ? '* #' : '#') + String(game.id),
|
|
139
|
-
name: game.name?.length || 0,
|
|
140
|
-
rules: game.rules,
|
|
141
|
-
moves: game.over ? 'game over' : CLI.plural(moves, 'move'),
|
|
142
|
-
smoves: game.over ? '9999' : String(moves).padStart(9, '0'),
|
|
143
|
-
sturn: String(game.turn),
|
|
144
|
-
p1: game.players?.[0] || 'white',
|
|
145
|
-
p2: game.players?.[1] || 'black',
|
|
146
|
-
turn: game.turn,
|
|
147
|
-
over: game.over,
|
|
148
|
-
note: game.notes?.[game.notes.length - 1]?.note || '',
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
list = listSort(list, filters)
|
|
153
|
-
|
|
154
|
-
for (const game of list) {
|
|
155
|
-
size.id = Math.max(size.id, game.id.length)
|
|
156
|
-
size.name = Math.max(size.name, game.name)
|
|
157
|
-
size.moves = Math.max(size.moves, game.moves.length)
|
|
158
|
-
size.p1 = Math.max(size.p1, game.p1.length)
|
|
159
|
-
size.p2 = Math.max(size.p2, game.p2.length)
|
|
160
|
-
noteSize = Math.min(noteSize, leftover(size))
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
for (const game of list) {
|
|
164
|
-
CLI.out(
|
|
165
|
-
CLI.color(game.id.padStart(size.id) + ' ') +
|
|
166
|
-
Trax.names[game.rules] +
|
|
167
|
-
' '.repeat(size.name - game.name + 1) +
|
|
168
|
-
CLI.bubble(game.turn === 1 ? 'wh' : 'w', game.p1) +
|
|
169
|
-
CLI.color('vs '.padStart(size.p1 - game.p1.length + 4)) +
|
|
170
|
-
CLI.bubble(game.turn === 2 ? 'bh' : 'b', game.p2) +
|
|
171
|
-
CLI.color(' '.padStart(size.p2 - game.p2.length + 1)) +
|
|
172
|
-
CLI.color(game.moves.padEnd(size.moves)) +
|
|
173
|
-
CLI.color.help(' ' + game.note.slice(0, noteSize)),
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
}
|
package/src/cmds/new.js
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* You may obtain a copy of the License at
|
|
6
|
-
*
|
|
7
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
*
|
|
9
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
* See the License for the specific language governing permissions and
|
|
13
|
-
* limitations under the License.
|
|
1
|
+
/** CLI new command
|
|
2
|
+
* @copyright 2022-2026
|
|
3
|
+
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
|
+
* @license Apache-2.0
|
|
14
5
|
*/
|
|
15
6
|
|
|
16
|
-
|
|
7
|
+
/** @typedef {import('../cli.js').CLIContext} CLIContext */
|
|
17
8
|
|
|
18
9
|
export const newCmd = {
|
|
19
10
|
name: 'new',
|
|
@@ -25,6 +16,51 @@ export const newCmd = {
|
|
|
25
16
|
'Valid variants are "trax", "loop", and "8x8". Defaults to "trax" if not',
|
|
26
17
|
'specified. Use the "vs" keyword to use specific names for the players.',
|
|
27
18
|
],
|
|
19
|
+
/** @param {CLIContext} CLI @param {string} [variant] @param {...string} names */
|
|
20
|
+
fn(CLI, variant, ...names) {
|
|
21
|
+
let rules = ''
|
|
22
|
+
if (variant) {
|
|
23
|
+
variant = variant.toLowerCase()
|
|
24
|
+
if (variant.length > 1 && 'puzzles'.startsWith(variant)) {
|
|
25
|
+
return CLI.do('puzzles', 'new', ...names)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (['8x8', '8', 'trax8x8', '8trax', '8x8trax'].includes(variant)) {
|
|
29
|
+
rules = 'trax8'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (['loop', 'l', 'looptrax'].includes(variant)) rules = 'traxloop'
|
|
33
|
+
if (variant === 't') rules = 'trax'
|
|
34
|
+
if (['trax', 'traxloop', 'trax8'].includes(variant)) rules = variant
|
|
35
|
+
|
|
36
|
+
if (!rules) {
|
|
37
|
+
if (names.includes('vs') || names.includes('VS')) {
|
|
38
|
+
// We don't have a variant, we have player names
|
|
39
|
+
names.unshift(variant)
|
|
40
|
+
} else {
|
|
41
|
+
CLI.error('Unknown Trax variant.')
|
|
42
|
+
return CLI.do('help', 'new')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const players = pairUp()
|
|
48
|
+
if (names.length > 0) {
|
|
49
|
+
let vs = names.indexOf('vs')
|
|
50
|
+
if (vs === -1) vs = names.indexOf('VS')
|
|
51
|
+
if (vs >= 0) {
|
|
52
|
+
players[0] = names.slice(0, vs).join(' ') || 'white'
|
|
53
|
+
players[1] = names.slice(vs + 1).join(' ') || 'black'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const id = CLI.newGame(
|
|
58
|
+
/** @type {import('../cli.js').TraxVariant} */ (rules || 'trax'),
|
|
59
|
+
players,
|
|
60
|
+
'',
|
|
61
|
+
)
|
|
62
|
+
CLI.out(CLI.color('Started new game #' + id))
|
|
63
|
+
},
|
|
28
64
|
}
|
|
29
65
|
|
|
30
66
|
// Okay, yes, this is silly
|
|
@@ -32,6 +68,7 @@ const pairs = [
|
|
|
32
68
|
['Aang', 'Katara'],
|
|
33
69
|
['Abbott', 'Costello'],
|
|
34
70
|
['Adam', 'Eve'],
|
|
71
|
+
['Ali', 'Frazier'],
|
|
35
72
|
['Anne Boleyn', 'Henry VIII'],
|
|
36
73
|
['Ash', 'Pikachu'],
|
|
37
74
|
['Barbie', 'Ken'],
|
|
@@ -44,12 +81,15 @@ const pairs = [
|
|
|
44
81
|
['Chip', 'Dale'],
|
|
45
82
|
['Donald', 'Daisy'],
|
|
46
83
|
['Depp', 'Heard'],
|
|
84
|
+
['Dorothy', 'Toto'],
|
|
47
85
|
['Fred', 'Barney'],
|
|
48
86
|
['Fred', 'George'],
|
|
87
|
+
['Frida', 'Diego'],
|
|
49
88
|
['Frodo', 'Samwise'],
|
|
50
89
|
['Hamilton', 'Burr'],
|
|
51
90
|
['Han', 'Chewie'],
|
|
52
91
|
['Harry', 'Ron'],
|
|
92
|
+
['Hatfield', 'McCoy'],
|
|
53
93
|
['Holmes', 'Moriarty'],
|
|
54
94
|
['Holmes', 'Watson'],
|
|
55
95
|
['Iñigo', 'Fezzik'],
|
|
@@ -73,6 +113,7 @@ const pairs = [
|
|
|
73
113
|
['Pan', 'Hook'],
|
|
74
114
|
['Phineas', 'Ferb'],
|
|
75
115
|
['player 1', 'player 2'],
|
|
116
|
+
['p1', 'p2'],
|
|
76
117
|
['Potter', 'Voldemort'],
|
|
77
118
|
['R2-D2', 'C-3PO'],
|
|
78
119
|
['Ren', 'Stimpy'],
|
|
@@ -85,6 +126,7 @@ const pairs = [
|
|
|
85
126
|
['Snoopy', 'Woodstock'],
|
|
86
127
|
['Sonny', 'Cher'],
|
|
87
128
|
['Spongebob', 'Patrick'],
|
|
129
|
+
['Sully', 'Neytiri'],
|
|
88
130
|
['Tarzan', 'Jane'],
|
|
89
131
|
['Thelma', 'Louise'],
|
|
90
132
|
['Thing 1', 'Thing 2'],
|
|
@@ -103,44 +145,3 @@ const pairUp = () => {
|
|
|
103
145
|
if (duo[0].toLowerCase() !== duo[0] && Math.random() < 0.5) duo.reverse()
|
|
104
146
|
return duo
|
|
105
147
|
}
|
|
106
|
-
|
|
107
|
-
newCmd.fn = (CLI, variant, ...names) => {
|
|
108
|
-
let rules = ''
|
|
109
|
-
if (variant) {
|
|
110
|
-
variant = variant.toLowerCase()
|
|
111
|
-
if (variant.length > 1 && 'puzzles'.startsWith(variant)) {
|
|
112
|
-
return CLI.do('puzzles', 'new', ...names)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (['8x8', '8', 'trax8x8', '8trax', '8x8trax'].includes(variant)) {
|
|
116
|
-
rules = 'trax8'
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (['loop', 'l', 'looptrax'].includes(variant)) rules = 'traxloop'
|
|
120
|
-
if (variant === 't') rules = 'trax'
|
|
121
|
-
if (['trax', 'traxloop', 'trax8'].includes(variant)) rules = variant
|
|
122
|
-
|
|
123
|
-
if (!rules) {
|
|
124
|
-
if (names.includes('vs') || names.includes('VS')) {
|
|
125
|
-
// We don't have a variant, we have player names
|
|
126
|
-
names.unshift(variant)
|
|
127
|
-
} else {
|
|
128
|
-
CLI.error('Unknown Trax variant.')
|
|
129
|
-
return CLI.do('help', 'new')
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const players = pairUp()
|
|
135
|
-
if (names.length > 0) {
|
|
136
|
-
let vs = names.indexOf('vs')
|
|
137
|
-
if (vs === -1) vs = names.indexOf('VS')
|
|
138
|
-
if (vs >= 0) {
|
|
139
|
-
players[0] = names.slice(0, vs).join(' ') || 'white'
|
|
140
|
-
players[1] = names.slice(vs + 1).join(' ') || 'black'
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const id = CLI.newGame(rules, players, '')
|
|
145
|
-
CLI.out(CLI.color('Started new game #' + id))
|
|
146
|
-
}
|
package/src/cmds/notes.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/** Notes CLI command.
|
|
2
|
-
* @copyright 2022
|
|
2
|
+
* @copyright 2022-2026
|
|
3
3
|
* @author Chad Transtrum <chad@transtrum.net>
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/** @typedef {import('../cli.js').CLIContext} CLIContext */
|
|
8
|
+
|
|
7
9
|
export const notesCmd = {
|
|
8
10
|
name: 'notes',
|
|
9
11
|
args: '[#id] <text>',
|
|
@@ -12,26 +14,26 @@ export const notesCmd = {
|
|
|
12
14
|
'Add a short note to a game that will be shown when the game is',
|
|
13
15
|
'displayed, listed, or exported.',
|
|
14
16
|
],
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
17
|
+
/** @param {CLIContext} CLI @param {string} [id] @param {...string} note */
|
|
18
|
+
fn(CLI, id, ...note) {
|
|
19
|
+
const current = String(CLI.GAME.id)
|
|
20
|
+
id ||= current
|
|
21
|
+
if (!/^#?\d+$/v.test(id)) {
|
|
22
|
+
note.unshift(id)
|
|
23
|
+
id = current
|
|
24
|
+
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
if (id.startsWith('#')) id = id.slice(1)
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
const game = CLI.GAMES[id]
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
if (!game) return CLI.error('Game not found.')
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const notes = game.notes || []
|
|
33
|
+
const move = game.moves.length > 0 ? game.moves.split(' ').length : 0
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
notes.push({ move, note: note.join(' ') })
|
|
36
|
+
game.notes = notes
|
|
37
|
+
CLI.save()
|
|
38
|
+
},
|
|
37
39
|
}
|