Comparing version 2.0.2 to 3.0.0
34
cli.js
#!/usr/bin/env node | ||
'use strict'; | ||
const pkg = require('./package.json'); | ||
const yosay = require('.'); | ||
import meow from 'meow'; | ||
import yosay from './index.js'; | ||
require('taketalk')({ | ||
init(input, options) { | ||
console.log(yosay(input, options)); | ||
}, | ||
help() { | ||
console.log(` | ||
${pkg.description} | ||
const cli = meow(` | ||
Usage | ||
$ yosay <string> | ||
$ yosay <string> --maxLength 8 | ||
$ echo <string> | yosay | ||
Usage | ||
$ yosay <string> | ||
$ yosay <string> --maxLength 8 | ||
$ echo <string> | yosay | ||
Example | ||
$ yosay 'Sindre is a horse' | ||
${yosay('Sindre is a horse')} | ||
`, { | ||
importMeta: import.meta, | ||
}); | ||
Example | ||
$ yosay 'Sindre is a horse' | ||
${yosay('Sindre is a horse')}`); | ||
}, | ||
version: pkg.version | ||
}); | ||
console.log(yosay(cli.input[0], cli.flags)); |
314
index.js
@@ -1,193 +0,197 @@ | ||
'use strict'; | ||
const chalk = require('chalk'); | ||
const pad = require('pad-component'); | ||
const wrap = require('wrap-ansi'); | ||
const stringWidth = require('string-width'); | ||
const stripAnsi = require('strip-ansi'); | ||
const ansiStyles = require('ansi-styles'); | ||
const ansiRegex = require('ansi-regex')(); | ||
const cliBoxes = require('cli-boxes'); | ||
import chalk from 'chalk'; | ||
import pad from 'pad-component'; | ||
import wrapAnsi from 'wrap-ansi'; | ||
import stringWidth from 'string-width'; | ||
import stripAnsi from 'strip-ansi'; | ||
import ansiStyles from 'ansi-styles'; | ||
import ansiRegex from 'ansi-regex'; | ||
import cliBoxes from 'cli-boxes'; | ||
const border = cliBoxes.round; | ||
const leftOffset = 17; | ||
const defaultGreeting = | ||
'\n _-----_ ' + | ||
'\n | | ' + | ||
'\n |' + chalk.red('--(o)--') + '| ' + | ||
'\n `---------ยด ' + | ||
'\n ' + chalk.yellow('(') + ' _' + chalk.yellow('ยดU`') + '_ ' + chalk.yellow(')') + ' ' + | ||
'\n /___A___\\ /' + | ||
'\n ' + chalk.yellow('| ~ |') + ' ' + | ||
'\n __' + chalk.yellow('\'.___.\'') + '__ ' + | ||
'\n ยด ' + chalk.red('` |') + 'ยฐ ' + chalk.red('ยด Y') + ' ` '; | ||
module.exports = (message, options) => { | ||
message = (message || 'Welcome to Yeoman, ladies and gentlemen!').trim(); | ||
options = options || {}; | ||
const defaultGreeting | ||
= '\n _-----_ ' | ||
+ '\n | | ' | ||
+ '\n |' + chalk.red('--(o)--') + '| ' | ||
+ '\n `---------ยด ' | ||
+ '\n ' + chalk.yellow('(') + ' _' + chalk.yellow('ยดU`') + '_ ' + chalk.yellow(')') + ' ' | ||
+ '\n /___A___\\ /' | ||
+ '\n ' + chalk.yellow('| ~ |') + ' ' | ||
+ '\n __' + chalk.yellow('\'.___.\'') + '__ ' | ||
+ '\n ยด ' + chalk.red('` |') + 'ยฐ ' + chalk.red('ยด Y') + ' ` '; | ||
/* | ||
* What you're about to see may confuse you. And rightfully so. Here's an | ||
* explanation. | ||
* | ||
* When yosay is given a string, we create a duplicate with the ansi styling | ||
* sucked out. This way, the true length of the string is read by `pad` and | ||
* `wrap`, so they can correctly do their job without getting tripped up by | ||
* the "invisible" ansi. Along with the duplicated, non-ansi string, we store | ||
* the character position of where the ansi was, so that when we go back over | ||
* each line that will be printed out in the message box, we check the | ||
* character position to see if it needs any styling, then re-insert it if | ||
* necessary. | ||
* | ||
* Better implementations welcome :) | ||
*/ | ||
export default function yosay(message, options = {}) { | ||
message = (message ?? 'Welcome to Yeoman, ladies and gentlemen!').trim(); | ||
let maxLength = 24; | ||
const styledIndexes = {}; | ||
let completedString = ''; | ||
let topOffset = 4; | ||
/* | ||
What you're about to see may confuse you. And rightfully so. Here's an explanation. | ||
// Amount of characters of the yeoman character ยปcolumnยซ โ ` /___A___\ /` | ||
const YEOMAN_CHARACTER_WIDTH = 17; | ||
When yosay is given a string, we create a duplicate with the ansi styling | ||
sucked out. This way, the true length of the string is read by `pad` and | ||
`wrap`, so they can correctly do their job without getting tripped up by | ||
the "invisible" ansi. Along with the duplicated, non-ansi string, we store | ||
the character position of where the ansi was, so that when we go back over | ||
each line that will be printed out in the message box, we check the | ||
character position to see if it needs any styling, then re-insert it if | ||
necessary. | ||
// Amount of characters of the default top frame of the speech bubble โ `โญโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ` | ||
const DEFAULT_TOP_FRAME_WIDTH = 28; | ||
Better implementations welcome :) | ||
*/ | ||
// Amount of characters of a total line | ||
let TOTAL_CHARACTERS_PER_LINE = YEOMAN_CHARACTER_WIDTH + DEFAULT_TOP_FRAME_WIDTH; | ||
const styledIndexes = {}; | ||
let maxLength = 24; | ||
let topOffset = 4; | ||
let completedString = ''; | ||
// The speech bubble will overflow the Yeoman character if the message is too long. | ||
const MAX_MESSAGE_LINES_BEFORE_OVERFLOW = 7; | ||
// Amount of characters of the yeoman character ยปcolumnยซ โ ` /___A___\ /` | ||
const YEOMAN_CHARACTER_WIDTH = 17; | ||
if (options.maxLength) { | ||
maxLength = stripAnsi(message).toLowerCase().split(' ').sort()[0].length; | ||
// Amount of characters of the default top frame of the speech bubble โ `โญโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ` | ||
const DEFAULT_TOP_FRAME_WIDTH = 28; | ||
if (maxLength < options.maxLength) { | ||
maxLength = options.maxLength; | ||
TOTAL_CHARACTERS_PER_LINE = maxLength + YEOMAN_CHARACTER_WIDTH + topOffset; | ||
} | ||
} | ||
// The speech bubble will overflow the Yeoman character if the message is too long. | ||
const MAX_MESSAGE_LINES_BEFORE_OVERFLOW = 7; | ||
const regExNewLine = new RegExp(`\\s{${maxLength}}`); | ||
const borderHorizontal = border.horizontal.repeat(maxLength + 2); | ||
// Amount of characters of a total line | ||
let TOTAL_CHARACTERS_PER_LINE = YEOMAN_CHARACTER_WIDTH + DEFAULT_TOP_FRAME_WIDTH; | ||
const frame = { | ||
top: border.topLeft + borderHorizontal + border.topRight, | ||
side: ansiStyles.reset.open + border.vertical + ansiStyles.reset.open, | ||
bottom: ansiStyles.reset.open + border.bottomLeft + borderHorizontal + border.bottomRight | ||
}; | ||
if (options.maxLength) { | ||
maxLength = stripAnsi(message).toLowerCase().split(' ').sort()[0].length; | ||
message.replace(ansiRegex, (match, offset) => { | ||
Object.keys(styledIndexes).forEach(key => { | ||
offset -= styledIndexes[key].length; | ||
}); | ||
if (maxLength < options.maxLength) { | ||
maxLength = options.maxLength; | ||
TOTAL_CHARACTERS_PER_LINE = maxLength + YEOMAN_CHARACTER_WIDTH + topOffset; | ||
} | ||
} | ||
styledIndexes[offset] = styledIndexes[offset] ? styledIndexes[offset] + match : match; | ||
}); | ||
const regexNewline = new RegExp(`\\s{${maxLength}}`); | ||
const borderHorizontal = border.top.repeat(maxLength + 2); | ||
const strippedMessage = stripAnsi(message); | ||
const spacesIndex = []; | ||
const frame = { | ||
top: border.topLeft + borderHorizontal + border.topRight, | ||
side: ansiStyles.reset.open + border.left + ansiStyles.reset.open, | ||
bottom: ansiStyles.reset.open + border.bottomLeft + borderHorizontal + border.bottomRight, | ||
}; | ||
strippedMessage.split(' ').reduce((accu, cur) => { | ||
spacesIndex.push(accu + cur.length); | ||
return spacesIndex[spacesIndex.length - 1] + 1; | ||
}, 0); | ||
message.replace(ansiRegex(), (match, offset) => { | ||
for (const value of Object.values(styledIndexes)) { | ||
offset -= value.length; | ||
} | ||
return wrap(strippedMessage, maxLength, {hard: true}) | ||
.split(/\n/) | ||
.reduce((greeting, str, index, array) => { | ||
if (!regExNewLine.test(str)) { | ||
str = str.trim(); | ||
} | ||
styledIndexes[offset] = styledIndexes[offset] ? styledIndexes[offset] + match : match; | ||
}); | ||
completedString += str; | ||
const strippedMessage = stripAnsi(message); | ||
const spacesIndex = []; | ||
let offset = 0; | ||
// TODO: Remove `.reduce`. | ||
// eslint-disable-next-line unicorn/no-array-reduce | ||
strippedMessage.split(' ').reduce((accumulator, currentValue) => { | ||
spacesIndex.push(accumulator + currentValue.length); | ||
return spacesIndex.at(-1) + 1; | ||
}, 0); | ||
for (let i = 0; i < spacesIndex.length; i++) { | ||
let char = completedString[spacesIndex[i] - offset]; | ||
if (char) { | ||
if (char !== ' ') { | ||
offset += 1; | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
return wrapAnsi(strippedMessage, maxLength, {hard: true}) | ||
.split(/\n/) | ||
// TODO: Remove `.reduce`. | ||
// eslint-disable-next-line unicorn/no-array-reduce | ||
.reduce((greeting, string_, index, array) => { | ||
if (!regexNewline.test(string_)) { | ||
string_ = string_.trim(); | ||
} | ||
str = completedString | ||
.substr(completedString.length - str.length) | ||
.replace(/./g, (char, charIndex) => { | ||
charIndex += completedString.length - str.length + offset; | ||
completedString += string_; | ||
let hasContinuedStyle = 0; | ||
let continuedStyle; | ||
let offset = 0; | ||
Object.keys(styledIndexes).forEach(offset => { | ||
if (charIndex > offset) { | ||
hasContinuedStyle++; | ||
continuedStyle = styledIndexes[offset]; | ||
} | ||
for (const element of spacesIndex) { | ||
const character = completedString[element - offset]; | ||
if (character) { | ||
if (character !== ' ') { | ||
offset += 1; | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
if (hasContinuedStyle === 1 && charIndex < offset) { | ||
hasContinuedStyle++; | ||
} | ||
}); | ||
string_ = completedString | ||
.slice(completedString.length - string_.length) | ||
.replaceAll(/./g, (character, characterIndex) => { | ||
characterIndex += completedString.length - string_.length + offset; | ||
if (styledIndexes[charIndex]) { | ||
return styledIndexes[charIndex] + char; | ||
} else if (hasContinuedStyle >= 2) { | ||
return continuedStyle + char; | ||
} | ||
let hasContinuedStyle = 0; | ||
let continuedStyle; | ||
return char; | ||
}) | ||
.trim(); | ||
for (const offset of Object.keys(styledIndexes)) { | ||
if (characterIndex > offset) { | ||
hasContinuedStyle++; | ||
continuedStyle = styledIndexes[offset]; | ||
} | ||
const paddedString = pad({ | ||
length: stringWidth(str), | ||
valueOf() { | ||
return ansiStyles.reset.open + str + ansiStyles.reset.open; | ||
} | ||
}, maxLength); | ||
if (hasContinuedStyle === 1 && characterIndex < offset) { | ||
hasContinuedStyle++; | ||
} | ||
} | ||
if (index === 0) { | ||
// Need to adjust the top position of the speech bubble depending on the | ||
// amount of lines of the message. | ||
if (array.length === 2) { | ||
topOffset -= 1; | ||
} | ||
if (styledIndexes[characterIndex]) { | ||
return styledIndexes[characterIndex] + character; | ||
} | ||
if (array.length >= 3) { | ||
topOffset -= 2; | ||
} | ||
if (hasContinuedStyle >= 2) { | ||
return continuedStyle + character; | ||
} | ||
// The speech bubble will overflow the Yeoman character if the message | ||
// is too long. So we vertically center the bubble by adding empty lines | ||
// on top of the greeting. | ||
if (array.length > MAX_MESSAGE_LINES_BEFORE_OVERFLOW) { | ||
const emptyLines = Math.ceil((array.length - MAX_MESSAGE_LINES_BEFORE_OVERFLOW) / 2); | ||
return character; | ||
}) | ||
.trim(); | ||
for (let i = 0; i < emptyLines; i++) { | ||
greeting.unshift(''); | ||
} | ||
const paddedString = pad({ | ||
length: stringWidth(string_), | ||
valueOf() { | ||
return ansiStyles.reset.open + string_ + ansiStyles.reset.open; | ||
}, | ||
}, maxLength); | ||
frame.top = pad.left(frame.top, TOTAL_CHARACTERS_PER_LINE); | ||
} | ||
if (index === 0) { | ||
// Need to adjust the top position of the speech bubble depending on the | ||
// amount of lines of the message. | ||
if (array.length === 2) { | ||
topOffset -= 1; | ||
} | ||
greeting[topOffset - 1] += frame.top; | ||
} | ||
if (array.length >= 3) { | ||
topOffset -= 2; | ||
} | ||
greeting[index + topOffset] = | ||
(greeting[index + topOffset] || pad.left('', leftOffset)) + | ||
frame.side + ' ' + paddedString + ' ' + frame.side; | ||
// The speech bubble will overflow the Yeoman character if the message | ||
// is too long. So we vertically center the bubble by adding empty lines | ||
// on top of the greeting. | ||
if (array.length > MAX_MESSAGE_LINES_BEFORE_OVERFLOW) { | ||
const emptyLines = Math.ceil((array.length - MAX_MESSAGE_LINES_BEFORE_OVERFLOW) / 2); | ||
if (array.length === index + 1) { | ||
greeting[index + topOffset + 1] = | ||
(greeting[index + topOffset + 1] || pad.left('', leftOffset)) + | ||
frame.bottom; | ||
} | ||
for (let i = 0; i < emptyLines; i++) { | ||
greeting.unshift(''); | ||
} | ||
return greeting; | ||
}, defaultGreeting.split(/\n/)) | ||
.join('\n') + '\n'; | ||
}; | ||
frame.top = pad.left(frame.top, TOTAL_CHARACTERS_PER_LINE); | ||
} | ||
greeting[topOffset - 1] += frame.top; | ||
} | ||
greeting[index + topOffset] | ||
= (greeting[index + topOffset] || pad.left('', leftOffset)) | ||
+ frame.side + ' ' + paddedString + ' ' + frame.side; | ||
if (array.length === index + 1) { | ||
greeting[index + topOffset + 1] | ||
= (greeting[index + topOffset + 1] || pad.left('', leftOffset)) | ||
+ frame.bottom; | ||
} | ||
return greeting; | ||
}, defaultGreeting.split(/\n/)) | ||
.join('\n') + '\n'; | ||
} |
{ | ||
"name": "yosay", | ||
"version": "2.0.2", | ||
"description": "Tell Yeoman what to say", | ||
"license": "BSD-2-Clause", | ||
"repository": "yeoman/yosay", | ||
"homepage": "yeoman.io", | ||
"author": "Yeoman", | ||
"bin": "cli.js", | ||
"engines": { | ||
"node": ">=4" | ||
}, | ||
"scripts": { | ||
"test": "xo && mocha" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"cli.js" | ||
], | ||
"keywords": [ | ||
"cli-app", | ||
"cli", | ||
"yeoman", | ||
"yo", | ||
"cowsay", | ||
"say", | ||
"box", | ||
"message", | ||
"ansi" | ||
], | ||
"dependencies": { | ||
"ansi-regex": "^2.0.0", | ||
"ansi-styles": "^3.0.0", | ||
"chalk": "^1.0.0", | ||
"cli-boxes": "^1.0.0", | ||
"pad-component": "0.0.1", | ||
"string-width": "^2.0.0", | ||
"strip-ansi": "^3.0.0", | ||
"taketalk": "^1.0.0", | ||
"wrap-ansi": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^3.2.0", | ||
"xo": "^0.17.0" | ||
}, | ||
"xo": { | ||
"space": true | ||
} | ||
"name": "yosay", | ||
"version": "3.0.0", | ||
"description": "Tell Yeoman what to say", | ||
"license": "BSD-2-Clause", | ||
"repository": "yeoman/yosay", | ||
"type": "module", | ||
"bin": "./cli.js", | ||
"exports": "./index.js", | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"scripts": { | ||
"test": "xo && FORCE_COLOR=1 mocha", | ||
"manual-test": "node test/manual-test.js && node cli.js" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"cli.js" | ||
], | ||
"keywords": [ | ||
"cli-app", | ||
"cli", | ||
"yeoman", | ||
"yo", | ||
"cowsay", | ||
"say", | ||
"box", | ||
"message", | ||
"ansi" | ||
], | ||
"dependencies": { | ||
"ansi-regex": "^6.0.1", | ||
"ansi-styles": "^6.2.1", | ||
"chalk": "^5.3.0", | ||
"cli-boxes": "^3.0.0", | ||
"meow": "^12.1.1", | ||
"pad-component": "0.0.1", | ||
"string-width": "^6.1.0", | ||
"strip-ansi": "^7.1.0", | ||
"wrap-ansi": "^8.1.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^10.2.0", | ||
"xo": "^0.56.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Yes
9967
172
2
1
64
1
+ Addedmeow@^12.1.1
+ Addedansi-regex@6.1.0(transitive)
+ Addedansi-styles@6.2.1(transitive)
+ Addedchalk@5.4.1(transitive)
+ Addedcli-boxes@3.0.0(transitive)
+ Addedeastasianwidth@0.2.0(transitive)
+ Addedemoji-regex@10.4.09.2.2(transitive)
+ Addedmeow@12.1.1(transitive)
+ Addedstring-width@5.1.26.1.0(transitive)
+ Addedstrip-ansi@7.1.0(transitive)
+ Addedwrap-ansi@8.1.0(transitive)
- Removedtaketalk@^1.0.0
- Removedansi-regex@2.1.13.0.1(transitive)
- Removedansi-styles@2.2.13.2.1(transitive)
- Removedchalk@1.1.3(transitive)
- Removedcli-boxes@1.0.0(transitive)
- Removedcode-point-at@1.1.0(transitive)
- Removedcolor-convert@1.9.3(transitive)
- Removedcolor-name@1.1.3(transitive)
- Removedescape-string-regexp@1.0.5(transitive)
- Removedget-stdin@4.0.1(transitive)
- Removedhas-ansi@2.0.0(transitive)
- Removedis-fullwidth-code-point@1.0.02.0.0(transitive)
- Removedminimist@1.2.8(transitive)
- Removednumber-is-nan@1.0.1(transitive)
- Removedstring-width@1.0.22.1.1(transitive)
- Removedstrip-ansi@3.0.14.0.0(transitive)
- Removedsupports-color@2.0.0(transitive)
- Removedtaketalk@1.0.0(transitive)
- Removedwrap-ansi@2.1.0(transitive)
Updatedansi-regex@^6.0.1
Updatedansi-styles@^6.2.1
Updatedchalk@^5.3.0
Updatedcli-boxes@^3.0.0
Updatedstring-width@^6.1.0
Updatedstrip-ansi@^7.1.0
Updatedwrap-ansi@^8.1.0