-
Notifications
You must be signed in to change notification settings - Fork 1
/
mode.js
225 lines (192 loc) · 5.05 KB
/
mode.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
"use strict";
var utils = require("../lib/utils");
/**
* Eyes and tongue of the cow
*
* The eyes and tongue are hardcoded for some cows and cannot be changed.
*
* @typedef {Object} CowFace
* @property {string} [eyes] Eyes of the cow
* @property {string} [tongue] Tongue of the cow
*/
/**
* Name for known faces
*
* @typedef {Object} CowMode
* @property {string} id The short name of the mode
* @property {string} name The full name of the mode
*/
/**
* Cow mode and face
*
* @typedef {CowMode & CowFace} CowModeData
*/
/**
* All available modes data
*
* The default mode is in the first position.
*
* @type {ReadonlyArray<Readonly<CowModeData>>}
* @constant
* @package
*/
var modes = [
{ id: "u", name: "default" },
{ id: "b", name: "borg", eyes: "==" },
{ id: "d", name: "dead", eyes: "xx", tongue: "U " },
{ id: "g", name: "greedy", eyes: "$$" },
{ id: "p", name: "paranoia", eyes: "@@" },
{ id: "s", name: "stoned", eyes: "**", tongue: "U " },
{ id: "t", name: "tired", eyes: "--" },
{ id: "w", name: "wired", eyes: "OO" },
{ id: "y", name: "youthful", eyes: ".." }
];
/**
* Custom modes data
*
* @type {Readonly<CowModeData>[]}
* @constant
*/
var customModes = [];
/**
* Create a full deep copy of the given cow mode data
*
* @param {CowModeData} modeData Cow mode data to copy
* @returns {CowModeData} A copy of the given cow mode data
*/
function copyModeData(modeData) {
return {
id: modeData.id,
name: modeData.name,
eyes: modeData.eyes,
tongue: modeData.tongue
};
}
/**
* Get the mode for the giving face
*
* If the face is not found, the default mode is returned.
*
* @param {CowFace} face The cow face
* @returns {CowMode} The matching cow mode
*/
function faceMode(face) {
/** @type {CowMode | undefined} */
var mode;
// Find mode
if (typeof face === "object" && face !== null) {
mode = utils.find(modes.concat(customModes), function(mode) {
return mode.eyes === face.eyes && mode.tongue === face.tongue;
});
}
// Get default mode if is not found
if (mode === undefined) {
mode = modes[0];
}
// Return a copy of the mode
return {
id: mode.id,
name: mode.name,
};
}
/**
* Get the face for the giving mode
*
* If the mode is not found, the default face is returned.
*
* @param {string} [id] The id or name of the cow mode
* @returns {CowFace} The matching cow face
*/
function modeFace(id) {
/** @type {CowFace | undefined} */
var face;
// Find face
if (typeof id === "string") {
face = utils.find(modes.concat(customModes), function(mode) {
return mode.id === id || mode.name === id;
});
}
// Get default face if is not found
if (face === undefined) {
face = modes[0];
}
// Return a copy of the face
return {
eyes: face.eyes,
tongue: face.tongue
};
}
/**
* Add a new cow mode data to the custom cow mode data list
*
* Cow mode data id should match with the first name letter (case sensitive) and
* should be different to any existing option.
*
* @param {CowModeData} modeData Cow mode data to add
* @returns {boolean} Whether the cow mode data could be added
*/
function addMode(modeData) {
// Validate type and format
var valid = true;
valid = valid && typeof modeData === "object" && modeData !== null && !Array.isArray(modeData);
valid = valid && typeof modeData.id === "string" && modeData.id.length === 1;
valid = valid && typeof modeData.name === "string" && modeData.id === modeData.name[0];
valid = valid && (typeof modeData.eyes === "undefined" || typeof modeData.eyes === "string");
valid = valid && (typeof modeData.tongue === "undefined" || typeof modeData.tongue === "string");
if (!valid) {
return false;
}
// Check if cow mode data already exists
var ind = modes.concat(customModes).findIndex(function(mode) {
return mode.id === modeData.id;
});
if (ind !== -1) {
return false;
}
// Check reserved id
var options = [ "h", "e", "f", "l", "n", "r", "T", "W" ];
if (options.includes(modeData.id)) {
return false;
}
// Add and sort custom cow mode data list
customModes.push(copyModeData(modeData));
customModes.sort(function(a, b) {
return a.id.localeCompare(b.id);
});
return true;
}
/**
* Remove a cow mode data from the custom cow mode data list
*
* @param {string} id The id or name of the cow mode
* @return {CowModeData | undefined} Removed cow mode data
*/
function removeMode(id) {
// Return undefined for not valid string
if (typeof id !== "string") {
return undefined;
}
// Get cow index
var ind = customModes.findIndex(function(face) {
return face.id === id || face.name === id;
});
// Remove cow mode data from custom mode data list and return it
if (ind !== -1) {
return customModes.splice(ind, 1)[0];
}
// Not found cow mode data
return undefined;
}
/**
* Manage cow modes and faces
*
* @module cowsay/lib/mode
*/
module.exports = {
modes: modes.map(copyModeData),
customModes: customModes,
faceMode: faceMode,
modeFace: modeFace,
addMode: addMode,
removeMode: removeMode
};