scrabble-cheater 3.6.5 → 3.7.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/README.md CHANGED
@@ -11,7 +11,7 @@ Of course you shouldn't be using this and I'm not responsible if people call you
11
11
 
12
12
  ## Setup
13
13
 
14
- ℹ️ This is a hybrid [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules) / [ESM](https://nodejs.org/api/esm.html#introduction) module.
14
+ ℹ️ This is a pure [ESM](https://nodejs.org/api/esm.html#introduction) module.
15
15
 
16
16
  ```
17
17
  yarn
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
2
5
  import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
6
  import { ScrabbleCheater } from './index.js';
6
- const { bin, description, version } = require('../package.json');
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const packageJsonPath = path.join(__dirname, '../package.json');
10
+ const { bin, description, version } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
7
11
  commander
8
12
  .name(Object.keys(bin)[0])
9
13
  .version(version)
@@ -1,8 +1,6 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import readline from 'node:readline';
1
3
  import clipboard from 'clipboardy';
2
- import fs from 'fs';
3
- import readline from 'readline';
4
- import { promisify } from 'util';
5
- const readFileAsync = promisify(fs.readFile);
6
4
  const defaultOptions = {
7
5
  letters: '',
8
6
  maximum: 0,
@@ -48,7 +46,7 @@ export class ScrabbleCheater {
48
46
  }
49
47
  async loadWords() {
50
48
  const regex = new RegExp('^[A-Za-z]+$');
51
- const wordList = await readFileAsync(this.wordListPath, 'utf-8');
49
+ const wordList = await fs.readFile(this.wordListPath, 'utf-8');
52
50
  this.dictionary = wordList.split('\n').filter(value => regex.test(value));
53
51
  return this.dictionary.length;
54
52
  }
@@ -1,6 +1,6 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
1
3
  import { assert, expect, describe, test } from 'vitest';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
4
  import { ScrabbleCheater } from './index.js';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
package/package.json CHANGED
@@ -1,25 +1,20 @@
1
1
  {
2
2
  "author": "Florian Imdahl <git@ffflorian.de>",
3
- "bin": "dist/cjs/cli.js",
3
+ "bin": "dist/cli.js",
4
4
  "dependencies": {
5
5
  "clipboardy": "4.0.0",
6
6
  "commander": "12.1.0"
7
7
  },
8
8
  "description": "A simple Scrabble cheating tool.",
9
9
  "devDependencies": {
10
- "rimraf": "5.0.7",
11
- "typescript": "5.5.2",
12
- "vitest": "1.6.0"
10
+ "rimraf": "6.0.1",
11
+ "typescript": "5.5.4",
12
+ "vitest": "2.0.5"
13
13
  },
14
14
  "engines": {
15
15
  "node": ">= 18.0"
16
16
  },
17
- "exports": {
18
- ".": {
19
- "import": "./dist/esm/index.js",
20
- "require": "./dist/cjs/index.js"
21
- }
22
- },
17
+ "exports": "./dist/index.js",
23
18
  "files": [
24
19
  "dist"
25
20
  ],
@@ -30,21 +25,17 @@
30
25
  "typescript"
31
26
  ],
32
27
  "license": "GPL-3.0",
33
- "main": "dist/cjs/index.js",
34
- "module": "dist/esm/index.js",
28
+ "module": "dist/index.js",
35
29
  "name": "scrabble-cheater",
36
30
  "repository": "https://github.com/ffflorian/node-packages/tree/main/packages/scrabble-cheater",
37
31
  "scripts": {
38
- "build": "yarn build:cjs && yarn build:esm && yarn generate:packagejson",
39
- "build:cjs": "tsc -p tsconfig.cjs.json",
40
- "build:esm": "tsc -p tsconfig.json",
32
+ "build": "tsc -p tsconfig.json",
41
33
  "clean": "rimraf dist",
42
34
  "dist": "yarn clean && yarn build",
43
- "generate:packagejson": "../../bin/generate-hybrid-package-json.sh",
44
35
  "start": "node --loader ts-node/esm src/cli.ts -d",
45
36
  "test": "vitest run"
46
37
  },
47
38
  "type": "module",
48
- "version": "3.6.5",
49
- "gitHead": "f7a6a79286e4eb85392b5f2d33942ab166142109"
39
+ "version": "3.7.0",
40
+ "gitHead": "f1a74d8ec9721d5b52a00e41b2ec73278e048290"
50
41
  }
package/dist/cjs/index.js DELETED
@@ -1,102 +0,0 @@
1
- import clipboard from 'clipboardy';
2
- import fs from 'fs';
3
- import readline from 'readline';
4
- import { promisify } from 'util';
5
- const readFileAsync = promisify(fs.readFile);
6
- const defaultOptions = {
7
- letters: '',
8
- maximum: 0,
9
- quietMode: false,
10
- singleMode: false,
11
- };
12
- export class ScrabbleCheater {
13
- constructor(wordListPath, options) {
14
- this.dictionary = [];
15
- this.wordListPath = wordListPath;
16
- this.options = { ...defaultOptions, ...options };
17
- }
18
- setLetters(letters) {
19
- this.options.letters = letters;
20
- return this;
21
- }
22
- async start() {
23
- const length = await this.loadWords();
24
- if (!length) {
25
- throw new Error('No words loaded. Wordlist file corrupt?');
26
- }
27
- this.log(`${length} word${length > 1 ? 's' : ''} loaded.`);
28
- const letters = this.options.letters ? this.formatLetters(this.options.letters) : await this.readLineAsync();
29
- let matches = this.findMatches(letters);
30
- this.log(`ScrabbleCheater: ${matches.length} matches found`, true);
31
- if (this.options.maximum) {
32
- this.log(`, ${this.options.singleMode ? 'sending' : 'displaying'} the first ${this.options.maximum}`, true);
33
- matches = matches.slice(0, this.options.maximum);
34
- }
35
- this.log('.\n\n', true);
36
- if (this.options.singleMode) {
37
- this.singleOutput(matches);
38
- }
39
- return matches;
40
- }
41
- findMatches(letters) {
42
- const regex = new RegExp(`^[${letters}]+$`);
43
- return this.dictionary.filter(word => regex.test(word)).sort((wordA, wordB) => wordB.length - wordA.length);
44
- }
45
- formatLetters(letters) {
46
- const regex = new RegExp('[^A-Za-z]');
47
- return letters.replace(regex, '').toLowerCase();
48
- }
49
- async loadWords() {
50
- const regex = new RegExp('^[A-Za-z]+$');
51
- const wordList = await readFileAsync(this.wordListPath, 'utf-8');
52
- this.dictionary = wordList.split('\n').filter(value => regex.test(value));
53
- return this.dictionary.length;
54
- }
55
- log(message, raw = false) {
56
- if (!this.options.quietMode) {
57
- if (!raw) {
58
- console.info(`ScrabbleCheater: ${message}`);
59
- }
60
- else {
61
- process.stdout.write(message);
62
- }
63
- }
64
- }
65
- readLineAsync() {
66
- return new Promise((resolve, reject) => {
67
- const rl = readline.createInterface({
68
- input: process.stdin,
69
- output: process.stdout,
70
- });
71
- rl.question('Letters? ', input => {
72
- const letters = this.formatLetters(input);
73
- if (letters) {
74
- resolve(letters);
75
- }
76
- else {
77
- reject(new Error('No letters entered.'));
78
- }
79
- rl.close();
80
- });
81
- });
82
- }
83
- singleOutput(matches) {
84
- const rl = readline.createInterface({
85
- input: process.stdin,
86
- output: process.stdout,
87
- });
88
- let counter = 0;
89
- const next = () => {
90
- clipboard.writeSync(matches[counter]);
91
- if (counter < matches.length - 1) {
92
- this.log('Press Enter to copy the next word...');
93
- counter++;
94
- }
95
- else {
96
- return rl.close();
97
- }
98
- };
99
- rl.on('line', next);
100
- next();
101
- }
102
- }
@@ -1,3 +0,0 @@
1
- {
2
- "type": "commonjs"
3
- }
package/dist/esm/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/esm/cli.js DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
- import { ScrabbleCheater } from './index.js';
6
- const { bin, description, version } = require('../package.json');
7
- commander
8
- .name(Object.keys(bin)[0])
9
- .version(version)
10
- .description(description)
11
- .option('-w, --wordlist <file>', 'Specify a wordlist file (mandatory)')
12
- .option('-l, --letters <letters>', 'Specify letters')
13
- .option('-q, --quiet', 'Quiet mode: displays only the letters')
14
- .option('-m, --maximum <number>', 'Specify a maximum of results')
15
- .option('-s, --single', 'Single word mode: displays each word and copies it to the clipboard')
16
- .parse(process.argv);
17
- const commanderOptions = commander.opts();
18
- if (!commanderOptions.wordlist) {
19
- console.error(' Error: no wordlist file specified.');
20
- commander.help();
21
- }
22
- if (commanderOptions.maximum && !parseInt(commanderOptions.maximum, 10)) {
23
- console.error(' Error: invalid maximum number specified.');
24
- commander.help();
25
- }
26
- const options = {
27
- ...(commanderOptions.letters && { letters: commanderOptions.letters }),
28
- ...(commanderOptions.maximum && { maximum: commanderOptions.maximum }),
29
- ...(commanderOptions.quiet && { quiet: commanderOptions.quiet }),
30
- ...(commanderOptions.single && { single: commanderOptions.single }),
31
- };
32
- void (async () => {
33
- try {
34
- const matches = await new ScrabbleCheater(commanderOptions.wordlist, options).start();
35
- if (matches.length && !commanderOptions.single) {
36
- console.info(matches.join('\n'));
37
- }
38
- process.exit();
39
- }
40
- catch (error) {
41
- console.error(error);
42
- process.exit(1);
43
- }
44
- })();
@@ -1,20 +0,0 @@
1
- export interface Options {
2
- letters?: string;
3
- maximum?: number;
4
- quietMode?: boolean;
5
- singleMode?: boolean;
6
- }
7
- export declare class ScrabbleCheater {
8
- private dictionary;
9
- private readonly options;
10
- private readonly wordListPath;
11
- constructor(wordListPath: string, options?: Options);
12
- setLetters(letters: string): ScrabbleCheater;
13
- start(): Promise<string[]>;
14
- private findMatches;
15
- private formatLetters;
16
- private loadWords;
17
- private log;
18
- private readLineAsync;
19
- private singleOutput;
20
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,27 +0,0 @@
1
- import { assert, expect, describe, test } from 'vitest';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { ScrabbleCheater } from './index.js';
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
- const wordList = path.resolve(__dirname, '../fixtures/wordlist.txt');
8
- const emptyList = path.resolve(__dirname, '../fixtures/empty.txt');
9
- describe('ScrabbleCheater', () => {
10
- test('finds all words', async () => {
11
- const sc = new ScrabbleCheater(wordList, { letters: 'her', quietMode: true });
12
- const matches = await sc.start();
13
- expect(matches.includes('here')).toBe(true);
14
- expect(matches.includes('her')).toBe(true);
15
- expect(matches.includes('he')).toBe(true);
16
- });
17
- test(`Doesn't accept an empty file`, async () => {
18
- const sc = new ScrabbleCheater(emptyList);
19
- try {
20
- await sc.start();
21
- assert.fail();
22
- }
23
- catch (error) {
24
- // nothing to do
25
- }
26
- });
27
- });
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
File without changes
File without changes
File without changes