UNPKG

lorem-ipsum

Version:

Generates lorem ipsum placeholder text for Node.js, Deno, browsers, and React Native. Developed with Bun.

388 lines (375 loc) 9.47 kB
#!/usr/bin/env node // src/cli.js import { exec } from "node:child_process"; import { readFileSync, realpathSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; // src/constants.js var FORMAT_HTML = "html"; var FORMAT_PLAIN = "plain"; var FORMATS = [FORMAT_HTML, FORMAT_PLAIN]; var UNIT_WORDS = "words"; var UNIT_WORD = "word"; var UNIT_SENTENCES = "sentences"; var UNIT_SENTENCE = "sentence"; var UNIT_PARAGRAPHS = "paragraphs"; var UNIT_PARAGRAPH = "paragraph"; var LINE_ENDINGS = { POSIX: ` `, WIN32: `\r ` }; var PLATFORMS = { DARWIN: "darwin", LINUX: "linux", WIN32: "win32" }; var COPY_COMMANDS = { DARWIN: "pbcopy", LINUX: "xclip -selection clipboard", WIN32: "clip" }; var REGEX = { UNITS: /^(paragraphs|paragraph|sentences|sentence|words|word)$/i }; // src/words.js var WORDS = [ "ad", "adipisicing", "aliqua", "aliquip", "amet", "anim", "aute", "cillum", "commodo", "consectetur", "consequat", "culpa", "cupidatat", "deserunt", "do", "dolor", "dolore", "duis", "ea", "eiusmod", "elit", "enim", "esse", "est", "et", "eu", "ex", "excepteur", "exercitation", "fugiat", "id", "in", "incididunt", "ipsum", "irure", "labore", "laboris", "laborum", "Lorem", "magna", "minim", "mollit", "nisi", "non", "nostrud", "nulla", "occaecat", "officia", "pariatur", "proident", "qui", "quis", "reprehenderit", "sint", "sit", "sunt", "tempor", "ullamco", "ut", "velit", "veniam", "voluptate" ]; // src/generator.js var capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1); var makeArrayOfLength = (length = 0) => Array.from({ length }, (_, index) => index); class Generator { constructor({ sentencesPerParagraph = { max: 7, min: 3 }, wordsPerSentence = { max: 15, min: 5 }, random, words = WORDS } = {}) { if (sentencesPerParagraph.min > sentencesPerParagraph.max) { throw new Error(`Minimum number of sentences per paragraph (${sentencesPerParagraph.min}) cannot exceed maximum (${sentencesPerParagraph.max}).`); } if (wordsPerSentence.min > wordsPerSentence.max) { throw new Error(`Minimum number of words per sentence (${wordsPerSentence.min}) cannot exceed maximum (${wordsPerSentence.max}).`); } this.sentencesPerParagraph = sentencesPerParagraph; this.words = words; this.wordsPerSentence = wordsPerSentence; this.random = random || Math.random; } generateRandomInteger(min, max) { return Math.floor(this.random() * (max - min + 1) + min); } generateRandomWords(num) { const { min, max } = this.wordsPerSentence; const length = num || this.generateRandomInteger(min, max); return makeArrayOfLength(length).reduce((accumulator) => `${this.pluckRandomWord()} ${accumulator}`, "").trim(); } generateRandomSentence(num) { return `${capitalize(this.generateRandomWords(num))}.`; } generateRandomParagraph(num) { const { min, max } = this.sentencesPerParagraph; const length = num || this.generateRandomInteger(min, max); return makeArrayOfLength(length).reduce((accumulator) => `${this.generateRandomSentence()} ${accumulator}`, "").trim(); } pluckRandomWord() { const index = this.generateRandomInteger(0, this.words.length - 1); return this.words[index]; } } var generator_default = Generator; // src/lorem-ipsum.js var isReactNative = () => { try { return navigator.product === "ReactNative"; } catch { return false; } }; var isNodeCompatible = () => typeof process !== "undefined" && typeof process.platform === "string"; var isWindows = () => { try { return process.platform === "win32"; } catch { return false; } }; class LoremIpsum { constructor(options = {}, format = FORMAT_PLAIN, suffix) { if (FORMATS.indexOf(format.toLowerCase()) === -1) { throw new Error(`${format} is an invalid format. Please use ${FORMATS.join(" or ")}.`); } this.format = format; this.generator = new generator_default(options); this.suffix = suffix; } getLineEnding() { if (this.suffix) { return this.suffix; } if (!isReactNative() && isNodeCompatible() && isWindows()) { return LINE_ENDINGS.WIN32; } return LINE_ENDINGS.POSIX; } formatString(value) { if (this.format === FORMAT_HTML) { return `<p>${value}</p>`; } return value; } formatStrings(values) { return values.map((value) => this.formatString(value)); } generateWords(num) { return this.formatString(this.generator.generateRandomWords(num)); } generateSentences(num) { return this.formatString(this.generator.generateRandomParagraph(num)); } generateParagraphs(num) { return this.formatStrings(Array.from({ length: num }, () => this.generator.generateRandomParagraph())).join(this.getLineEnding()); } } var lorem_ipsum_default = LoremIpsum; // src/index.js var loremIpsum = ({ count = 1, format = FORMAT_PLAIN, paragraphLowerBound = 3, paragraphUpperBound = 7, random, sentenceLowerBound = 5, sentenceUpperBound = 15, units = UNIT_SENTENCES, words = WORDS, suffix = "" } = {}) => { const lorem = new lorem_ipsum_default({ random, sentencesPerParagraph: { max: paragraphUpperBound, min: paragraphLowerBound }, words, wordsPerSentence: { max: sentenceUpperBound, min: sentenceLowerBound } }, format, suffix); switch (units) { case UNIT_PARAGRAPHS: case UNIT_PARAGRAPH: return lorem.generateParagraphs(count); case UNIT_SENTENCES: case UNIT_SENTENCE: return lorem.generateSentences(count); case UNIT_WORDS: case UNIT_WORD: return lorem.generateWords(count); default: return ""; } }; // src/cli.js var DESCRIPTION = "Generates one or more words|sentences|paragraphs"; var USAGE = "3 words [options]"; var HELP = `${DESCRIPTION} Usage: lorem-ipsum ${USAGE} Arguments: count The number of units units Words, sentences, or paragraphs Options: -c, --copy Copy output to the clipboard -f, --format Output format: ${FORMATS.join(", ")} -h, --help Display help -v, --version Display version `; var getVersion = () => { const root = dirname(dirname(fileURLToPath(import.meta.url))); return JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version; }; var getCopyCommand = (platform = "") => { switch (platform.toLowerCase()) { case PLATFORMS.DARWIN: return COPY_COMMANDS.DARWIN; case PLATFORMS.WIN32: return COPY_COMMANDS.WIN32; case PLATFORMS.LINUX: default: return COPY_COMMANDS.LINUX; } }; var shellQuote = (value) => `'${value.replace(/'/g, "'\\''")}'`; var copyToClipboard = (text, run = exec) => new Promise((resolve, reject) => { const platform = process.platform; if (Object.values(PLATFORMS).indexOf(platform) === -1) { reject(new Error(`Copy is not supported for ${platform}`)); return; } run(`printf %s ${shellQuote(text)} | ${getCopyCommand(platform)}`, (error, stdout, stderr) => { if (error) { reject(error); return; } if (stderr) { reject(new Error(stderr)); return; } resolve(text); }); }); var parseArgs = (args) => { const options = { copy: false, format: FORMAT_PLAIN, help: false, values: [], version: false }; for (let index = 0;index < args.length; index += 1) { const arg = args[index]; switch (arg) { case "-c": case "--copy": options.copy = true; break; case "-f": case "--format": options.format = args[index + 1]; index += 1; break; case "-h": case "--help": options.help = true; break; case "-v": case "--version": options.version = true; break; default: options.values.push(arg); break; } } return options; }; var run = async (args = process.argv.slice(2)) => { const options = parseArgs(args); if (options.version) { console.log(getVersion()); return; } if (options.help) { console.log(HELP); return; } if (FORMATS.indexOf(options.format) === -1) { console.error(`${options.format} is not valid. Choose from ${FORMATS.join(" or ")}.`); process.exit(1); } const num = options.values[0] || "1"; const units = options.values[1] || "sentence"; if (REGEX.UNITS.test(units) === false) { console.error(`${units} is not valid. Choose from paragraph(s), sentence(s), or word(s).`); process.exit(1); } const count = parseInt(num, 10); if (!count || count < 1) { console.error(`${num} is not valid. Choose a number greater than 0.`); process.exit(1); } const output = loremIpsum({ count, format: options.format, units }); console.log(output); if (options.copy === true) { try { await copyToClipboard(output); console.log(""); console.log("copied"); } catch (error) { console.log(error.message); } } }; var isMain = () => { try { return process.argv[1] && realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]); } catch { return false; } }; if (isMain()) { run().catch((error) => { console.error(error.message); process.exit(1); }); } export { run, parseArgs, copyToClipboard };