scrabble-solver 2.9.0 → 2.9.2

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.
Files changed (132) hide show
  1. package/.eslintignore +4 -2
  2. package/.eslintrc.js +8 -1
  3. package/LICENSE +1 -1
  4. package/README.md +50 -30
  5. package/img/logo.svg +76 -0
  6. package/lerna.json +1 -1
  7. package/package.json +3 -3
  8. package/packages/configs/package.json +5 -5
  9. package/packages/constants/package.json +3 -3
  10. package/packages/dictionaries/build/constants/index.js +1 -1
  11. package/packages/dictionaries/package-lock.json +2 -2
  12. package/packages/dictionaries/package.json +6 -6
  13. package/packages/dictionaries/src/constants/index.ts +1 -1
  14. package/packages/logger/package-lock.json +2 -2
  15. package/packages/logger/package.json +5 -4
  16. package/packages/logger/scripts/stats.js +52 -0
  17. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  18. package/packages/scrabble-solver/.next/build-manifest.json +8 -8
  19. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  20. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  21. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  22. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  23. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  24. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  25. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  26. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  27. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  28. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  29. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  30. package/packages/scrabble-solver/.next/required-server-files.json +1 -1
  31. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  32. package/packages/scrabble-solver/.next/server/chunks/413.js +7 -3
  33. package/packages/scrabble-solver/.next/server/chunks/44.js +895 -4
  34. package/packages/scrabble-solver/.next/server/chunks/515.js +15 -6
  35. package/packages/scrabble-solver/.next/server/chunks/865.js +230 -116
  36. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  37. package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
  38. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  39. package/packages/scrabble-solver/.next/server/pages/500.html +2 -2
  40. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  41. package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
  42. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +121 -65
  43. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  44. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +1 -1
  45. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  46. package/packages/scrabble-solver/.next/server/pages/api/solve.js +1 -1
  47. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  48. package/packages/scrabble-solver/.next/server/pages/api/verify.js +1 -1
  49. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  50. package/packages/scrabble-solver/.next/server/pages/index.html +2 -2
  51. package/packages/scrabble-solver/.next/server/pages/index.js +5 -1
  52. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  53. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  54. package/packages/scrabble-solver/.next/static/{BiJ0RS1mh1CdONVQg_p20 → Ntg-ilwD7GqTIFwRpSaTQ}/_buildManifest.js +1 -1
  55. package/packages/scrabble-solver/.next/static/{BiJ0RS1mh1CdONVQg_p20 → Ntg-ilwD7GqTIFwRpSaTQ}/_ssgManifest.js +0 -0
  56. package/packages/scrabble-solver/.next/static/chunks/317-5e5334962dd7c681.js +1 -0
  57. package/packages/scrabble-solver/.next/static/chunks/pages/{_app-1878e12521f2d115.js → _app-183f598b1d4d480b.js} +1 -1
  58. package/packages/scrabble-solver/.next/static/chunks/pages/{index-14d33636a0746c22.js → index-b1ffeaddd9fb64b5.js} +1 -1
  59. package/packages/scrabble-solver/.next/static/css/e8de67ad5ea35427.css +1 -0
  60. package/packages/scrabble-solver/.next/trace +52 -52
  61. package/packages/scrabble-solver/package-lock.json +2 -2
  62. package/packages/scrabble-solver/package.json +10 -10
  63. package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +2 -7
  64. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +1 -1
  65. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +4 -1
  66. package/packages/scrabble-solver/src/components/Board/components/Cell/CellPure.tsx +12 -1
  67. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +1 -0
  68. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +7 -2
  69. package/packages/scrabble-solver/src/components/Splash/Splash.module.scss +1 -1
  70. package/packages/scrabble-solver/src/i18n/en.json +2 -2
  71. package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/[word].ts +3 -1
  72. package/packages/scrabble-solver/src/pages/index.tsx +6 -1
  73. package/packages/scrabble-solver/src/service-worker/dictionaries/constants.ts +3 -1
  74. package/packages/solver/package-lock.json +2 -2
  75. package/packages/solver/package.json +7 -7
  76. package/packages/types/build/Locale.d.ts +2 -2
  77. package/packages/types/build/Locale.js +1 -1
  78. package/packages/types/build/WordDefinition.d.ts +8 -5
  79. package/packages/types/build/WordDefinition.js +5 -1
  80. package/packages/types/build/WordDefinitionJson.d.ts +7 -0
  81. package/packages/types/package.json +4 -4
  82. package/packages/types/src/Locale.ts +1 -1
  83. package/packages/types/src/WordDefinition.ts +13 -1
  84. package/packages/types/src/WordDefinitionJson.ts +7 -0
  85. package/packages/word-definitions/build/getWordDefinition.d.ts +1 -1
  86. package/packages/word-definitions/build/getWordDefinition.js +3 -3
  87. package/packages/word-definitions/build/lib/normalizeDefinition.js +3 -1
  88. package/packages/word-definitions/build/parse/parse.js +2 -2
  89. package/packages/word-definitions/build/parse/parseEnglish.js +7 -7
  90. package/packages/word-definitions/build/parse/parseFrench.js +3 -6
  91. package/packages/word-definitions/build/parse/parseGerman.js +54 -16
  92. package/packages/word-definitions/build/parse/parsePolish.js +3 -6
  93. package/packages/word-definitions/build/parse/parseSpanish.js +3 -6
  94. package/packages/word-definitions/build/types.d.ts +1 -1
  95. package/packages/word-definitions/package-lock.json +14 -14
  96. package/packages/word-definitions/package.json +4 -4
  97. package/packages/word-definitions/src/getWordDefinition.ts +3 -3
  98. package/packages/word-definitions/src/lib/normalizeDefinition.ts +4 -1
  99. package/packages/word-definitions/src/parse/__tests__/expected/de-DE.hm.json +4 -0
  100. package/packages/word-definitions/src/parse/__tests__/expected/de-DE.ho.json +9 -0
  101. package/packages/word-definitions/src/parse/__tests__/expected/de-DE.kolla.json +4 -0
  102. package/packages/word-definitions/src/parse/__tests__/expected/de-DE.vom.json +16 -0
  103. package/packages/word-definitions/src/parse/__tests__/expected/en-US.awe.json +1 -1
  104. package/packages/word-definitions/src/parse/__tests__/expected/en-US.pawn.json +1 -1
  105. package/packages/word-definitions/src/parse/__tests__/expected/en-US.pawnee.json +1 -1
  106. package/packages/word-definitions/src/parse/__tests__/expected/en-US.pean.json +1 -1
  107. package/packages/word-definitions/src/parse/__tests__/expected/en-US.wiz.json +1 -1
  108. package/packages/word-definitions/src/parse/__tests__/expected/es-ES.corma.json +1 -1
  109. package/packages/word-definitions/src/parse/__tests__/expected/es-ES.portero.json +1 -1
  110. package/packages/word-definitions/src/parse/__tests__/input/de-DE.hm.html +873 -0
  111. package/packages/word-definitions/src/parse/__tests__/input/de-DE.ho.html +1144 -0
  112. package/packages/word-definitions/src/parse/__tests__/input/de-DE.kolla.html +980 -0
  113. package/packages/word-definitions/src/parse/__tests__/input/de-DE.vom.html +738 -0
  114. package/packages/word-definitions/src/parse/parse.test.ts +4 -0
  115. package/packages/word-definitions/src/parse/parse.ts +2 -2
  116. package/packages/word-definitions/src/parse/parseEnglish.ts +8 -4
  117. package/packages/word-definitions/src/parse/parseFrench.ts +3 -3
  118. package/packages/word-definitions/src/parse/parseGerman.ts +71 -12
  119. package/packages/word-definitions/src/parse/parsePolish.ts +3 -3
  120. package/packages/word-definitions/src/parse/parseSpanish.ts +3 -3
  121. package/packages/word-definitions/src/types.ts +1 -1
  122. package/packages/word-lists/build/getDeDeWordList.js +1 -1
  123. package/packages/word-lists/build/getPlPlWordList.js +2 -2
  124. package/packages/word-lists/package-lock.json +2 -2
  125. package/packages/word-lists/package.json +4 -4
  126. package/packages/word-lists/src/getDeDeWordList.ts +1 -1
  127. package/packages/word-lists/src/getPlPlWordList.ts +2 -2
  128. package/img/logo.png +0 -0
  129. package/packages/scrabble-solver/.next/server/chunks/452.js +0 -894
  130. package/packages/scrabble-solver/.next/static/chunks/317-c5d262202c17d519.js +0 -1
  131. package/packages/scrabble-solver/.next/static/css/9ac903004135f4b1.css +0 -1
  132. package/packages/scrabble-solver/public/robots.txt +0 -4
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/scrabble-solver",
9
- "version": "2.9.0",
9
+ "version": "2.9.2",
10
10
  "license": "CC BY-NC-ND 4.0",
11
11
  "dependencies": {
12
12
  "@kamilmielnik/trie": "^2.0.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "author": {
13
13
  "name": "Kamil Mielnik",
14
- "email": "kamil.adam.mielnik@gmail.com",
15
- "url": "https://kamilmielnik.com/"
14
+ "email": "kamil@kamilmielnik.com",
15
+ "url": "https://kamilmielnik.com"
16
16
  },
17
17
  "license": "CC BY-NC-ND 4.0",
18
18
  "bugs": {
@@ -31,13 +31,13 @@
31
31
  "@kamilmielnik/trie": "^2.0.1",
32
32
  "@popperjs/core": "^2.11.6",
33
33
  "@reduxjs/toolkit": "^1.8.6",
34
- "@scrabble-solver/configs": "^2.9.0",
35
- "@scrabble-solver/constants": "^2.9.0",
36
- "@scrabble-solver/dictionaries": "^2.9.0",
37
- "@scrabble-solver/logger": "^2.9.0",
38
- "@scrabble-solver/solver": "^2.9.0",
39
- "@scrabble-solver/types": "^2.9.0",
40
- "@scrabble-solver/word-definitions": "^2.9.0",
34
+ "@scrabble-solver/configs": "^2.9.2",
35
+ "@scrabble-solver/constants": "^2.9.2",
36
+ "@scrabble-solver/dictionaries": "^2.9.2",
37
+ "@scrabble-solver/logger": "^2.9.2",
38
+ "@scrabble-solver/solver": "^2.9.2",
39
+ "@scrabble-solver/types": "^2.9.2",
40
+ "@scrabble-solver/word-definitions": "^2.9.2",
41
41
  "classnames": "^2.3.2",
42
42
  "next": "^12.3.1",
43
43
  "normalize.css": "^8.0.1",
@@ -44,13 +44,7 @@ const BoardPure: FunctionComponent<Props> = ({
44
44
  onKeyDown,
45
45
  onPaste,
46
46
  }) => (
47
- <div
48
- className={classNames(styles.board, className)}
49
- ref={innerRef}
50
- onChange={onChange}
51
- onKeyDown={onKeyDown}
52
- onPaste={onPaste}
53
- >
47
+ <div className={classNames(styles.board, className)} ref={innerRef} onKeyDown={onKeyDown} onPaste={onPaste}>
54
48
  {rows.map((cells, y) => (
55
49
  <div className={styles.row} key={y}>
56
50
  {cells.map((cell, x) => (
@@ -62,6 +56,7 @@ const BoardPure: FunctionComponent<Props> = ({
62
56
  isCenter={center.x === x && center.y === y}
63
57
  key={x}
64
58
  size={cellSize}
59
+ onChange={onChange}
65
60
  onDirectionToggle={onDirectionToggle}
66
61
  onFocus={onFocus}
67
62
  />
@@ -213,7 +213,7 @@ $icon-size: 16px;
213
213
 
214
214
  .flag,
215
215
  .star {
216
- $size: 24px;
216
+ $size: 50%;
217
217
 
218
218
  width: $size;
219
219
  height: $size;
@@ -1,6 +1,6 @@
1
1
  import { EMPTY_CELL } from '@scrabble-solver/constants';
2
2
  import { Cell as CellModel } from '@scrabble-solver/types';
3
- import { FunctionComponent, RefObject, useCallback, useMemo } from 'react';
3
+ import { ChangeEventHandler, FunctionComponent, RefObject, useCallback, useMemo } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
6
  import { getTileSizes } from 'lib';
@@ -23,6 +23,7 @@ interface Props {
23
23
  inputRef: RefObject<HTMLInputElement>;
24
24
  isCenter: boolean;
25
25
  size: number;
26
+ onChange: ChangeEventHandler<HTMLInputElement>;
26
27
  onDirectionToggle: () => void;
27
28
  onFocus: (x: number, y: number) => void;
28
29
  }
@@ -34,6 +35,7 @@ const Cell: FunctionComponent<Props> = ({
34
35
  inputRef,
35
36
  isCenter,
36
37
  size,
38
+ onChange,
37
39
  onDirectionToggle,
38
40
  onFocus,
39
41
  }) => {
@@ -88,6 +90,7 @@ const Cell: FunctionComponent<Props> = ({
88
90
  style={style}
89
91
  tile={tile}
90
92
  translate={translate}
93
+ onChange={onChange}
91
94
  onDirectionToggleClick={handleDirectionToggleClick}
92
95
  onFocus={handleFocus}
93
96
  onToggleBlankClick={handleToggleBlankClick}
@@ -1,6 +1,14 @@
1
1
  import { Bonus, Cell, Tile as TileModel } from '@scrabble-solver/types';
2
2
  import classNames from 'classnames';
3
- import { CSSProperties, FocusEventHandler, FunctionComponent, memo, MouseEventHandler, RefObject } from 'react';
3
+ import {
4
+ ChangeEventHandler,
5
+ CSSProperties,
6
+ FocusEventHandler,
7
+ FunctionComponent,
8
+ memo,
9
+ MouseEventHandler,
10
+ RefObject,
11
+ } from 'react';
4
12
 
5
13
  import { ArrowDown, Flag, Star } from 'icons';
6
14
  import { Translate } from 'types';
@@ -25,6 +33,7 @@ interface Props {
25
33
  style?: CSSProperties;
26
34
  tile: TileModel;
27
35
  translate: Translate;
36
+ onChange: ChangeEventHandler<HTMLInputElement>;
28
37
  onDirectionToggleClick: MouseEventHandler<HTMLButtonElement>;
29
38
  onFocus: FocusEventHandler<HTMLInputElement>;
30
39
  onToggleBlankClick: MouseEventHandler<HTMLButtonElement>;
@@ -45,6 +54,7 @@ const CellPure: FunctionComponent<Props> = ({
45
54
  style,
46
55
  tile,
47
56
  translate,
57
+ onChange,
48
58
  onDirectionToggleClick,
49
59
  onFocus,
50
60
  onToggleBlankClick,
@@ -78,6 +88,7 @@ const CellPure: FunctionComponent<Props> = ({
78
88
  raised={!isEmpty}
79
89
  size={size}
80
90
  tabIndex={cell.x === 0 && cell.y === 0 ? undefined : -1}
91
+ onChange={onChange}
81
92
  onFocus={onFocus}
82
93
  />
83
94
 
@@ -53,6 +53,7 @@
53
53
 
54
54
  .definition {
55
55
  margin-bottom: var(--spacing--s);
56
+ white-space: pre-wrap;
56
57
 
57
58
  &:last-child {
58
59
  margin-bottom: 0;
@@ -31,7 +31,7 @@ const Dictionary: FunctionComponent<Props> = ({ className }) => {
31
31
  </EmptyState>
32
32
  )}
33
33
 
34
- {results.map(({ definitions, isAllowed, word }) => (
34
+ {results.map(({ definitions, exists, isAllowed, word }) => (
35
35
  <div
36
36
  className={classNames(styles.result, {
37
37
  [styles.isAllowed]: isAllowed === true,
@@ -51,7 +51,12 @@ const Dictionary: FunctionComponent<Props> = ({ className }) => {
51
51
 
52
52
  {isAllowed === true && (
53
53
  <>
54
- {definitions.length === 0 && <div>{translate('dictionary.empty-state.no-definitions')}</div>}
54
+ {definitions.length === 0 && (
55
+ <>
56
+ {exists && <div>{translate('dictionary.empty-state.no-definitions')}</div>}
57
+ {!exists && <div>{translate('dictionary.empty-state.no-results')}</div>}
58
+ </>
59
+ )}
55
60
 
56
61
  {definitions.length > 0 && (
57
62
  <ul className={styles.definitions}>
@@ -1,6 +1,6 @@
1
1
  @import 'styles/animations';
2
2
 
3
- $loading-duration: 450ms;
3
+ $loading-duration: 250ms;
4
4
  $loaded-duration: 100ms;
5
5
  $hiding-duration: 200ms;
6
6
 
@@ -15,9 +15,9 @@
15
15
  "common.word": "Word",
16
16
  "common.words": "Words",
17
17
  "dictionary.empty-state.no-definitions": "Word exists in the dictionary but it does not have a definition.",
18
- "dictionary.empty-state.no-results": "Unable to find word definition in dictionary.",
18
+ "dictionary.empty-state.no-results": "Unable to find word definition in the dictionary.",
19
19
  "dictionary.empty-state.not-allowed": "This word is not allowed.",
20
- "dictionary.empty-state.uninitialized": "Dictionary definition of the last highlighted word will be shown here.",
20
+ "dictionary.empty-state.uninitialized": "Dictionary definition of the most recently highlighted word will be shown here.",
21
21
  "dictionary.input.placeholder": "Search dictionary...",
22
22
  "empty-state.error": "Error",
23
23
  "empty-state.info": "Info",
@@ -1,4 +1,5 @@
1
1
  import { scrabble } from '@scrabble-solver/configs';
2
+ import { dictionaries } from '@scrabble-solver/dictionaries';
2
3
  import logger from '@scrabble-solver/logger';
3
4
  import { isLocale, Locale } from '@scrabble-solver/types';
4
5
  import { getWordDefinition } from '@scrabble-solver/word-definitions';
@@ -27,7 +28,8 @@ const dictionary = async (request: NextApiRequest, response: NextApiResponse): P
27
28
  },
28
29
  });
29
30
 
30
- const results = await Promise.all(words.map((word) => getWordDefinition(locale, word)));
31
+ const trie = await dictionaries.get(locale);
32
+ const results = await Promise.all(words.map((word) => getWordDefinition(locale, word, trie.has(word))));
31
33
  response.status(200).send(results.map((result) => result.toJson()));
32
34
  } catch (error) {
33
35
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -48,7 +48,8 @@ const Index: FunctionComponent<Props> = ({ version }) => {
48
48
  useMeasure<HTMLDivElement>();
49
49
  const config = useTypedSelector(selectConfig);
50
50
  const cellSize = getCellSize(config, contentWidth - resultsContainerWidth, contentHeight);
51
- const isInitialized = contentWidth > 0 && boardHeight > 0 && resultsContainerWidth > 0;
51
+ const isInitializedInitial = contentWidth > 0 && boardHeight > 0 && resultsContainerWidth > 0;
52
+ const [isInitialized, setIsInitialized] = useState(isInitializedInitial);
52
53
  const resultsHeight = boardHeight - DICTIONARY_HEIGHT - (isTablet ? COMPONENTS_SPACING_MOBILE : COMPONENTS_SPACING);
53
54
 
54
55
  const handleClear = () => {
@@ -71,6 +72,10 @@ const Index: FunctionComponent<Props> = ({ version }) => {
71
72
 
72
73
  useEffectOnce(() => {
73
74
  dispatch(initialize());
75
+
76
+ setTimeout(() => {
77
+ setIsInitialized(true);
78
+ }, 100);
74
79
  });
75
80
 
76
81
  useEffect(() => {
@@ -1,3 +1,5 @@
1
1
  export const DICTIONARY_CACHE = 'dictionary-api-cache';
2
2
 
3
- export const DICTIONARY_CACHE_MAX_AGE = 30 * 24 * 60 * 60 * 1000;
3
+ export const DAY = 24 * 60 * 60 * 1000;
4
+
5
+ export const DICTIONARY_CACHE_MAX_AGE = 1 * DAY; // eslint-disable-line no-implicit-coercion
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/solver",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/solver",
9
- "version": "2.9.0",
9
+ "version": "2.9.2",
10
10
  "license": "CC-BY-NC-ND-4.0",
11
11
  "dependencies": {
12
12
  "@kamilmielnik/trie": "^2.0.1"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/solver",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "description": "Scrabble Solver 2 - Solver",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -10,8 +10,8 @@
10
10
  },
11
11
  "author": {
12
12
  "name": "Kamil Mielnik",
13
- "email": "kamil.adam.mielnik@gmail.com",
14
- "url": "https://kamilmielnik.com/"
13
+ "email": "kamil@kamilmielnik.com",
14
+ "url": "https://kamilmielnik.com"
15
15
  },
16
16
  "license": "CC-BY-NC-ND-4.0",
17
17
  "bugs": {
@@ -25,12 +25,12 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@kamilmielnik/trie": "^2.0.1",
28
- "@scrabble-solver/types": "^2.9.0"
28
+ "@scrabble-solver/types": "^2.9.2"
29
29
  },
30
30
  "devDependencies": {
31
- "@scrabble-solver/configs": "^2.9.0",
32
- "@scrabble-solver/constants": "^2.9.0",
33
- "@scrabble-solver/dictionaries": "^2.9.0"
31
+ "@scrabble-solver/configs": "^2.9.2",
32
+ "@scrabble-solver/constants": "^2.9.2",
33
+ "@scrabble-solver/dictionaries": "^2.9.2"
34
34
  },
35
35
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
36
36
  }
@@ -1,10 +1,10 @@
1
1
  declare enum Locale {
2
+ DE_DE = "de-DE",
2
3
  EN_GB = "en-GB",
3
4
  EN_US = "en-US",
4
5
  ES_ES = "es-ES",
5
6
  FR_FR = "fr-FR",
6
- PL_PL = "pl-PL",
7
- DE_DE = "de-DE"
7
+ PL_PL = "pl-PL"
8
8
  }
9
9
  export declare const isLocale: (locale: unknown) => locale is Locale;
10
10
  export default Locale;
@@ -4,12 +4,12 @@ exports.isLocale = void 0;
4
4
  // eslint-disable-next-line no-shadow
5
5
  var Locale;
6
6
  (function (Locale) {
7
+ Locale["DE_DE"] = "de-DE";
7
8
  Locale["EN_GB"] = "en-GB";
8
9
  Locale["EN_US"] = "en-US";
9
10
  Locale["ES_ES"] = "es-ES";
10
11
  Locale["FR_FR"] = "fr-FR";
11
12
  Locale["PL_PL"] = "pl-PL";
12
- Locale["DE_DE"] = "de-DE";
13
13
  })(Locale || (Locale = {}));
14
14
  const locales = Object.values(Locale);
15
15
  const isLocale = (locale) => locales.includes(locale);
@@ -3,13 +3,16 @@ declare class WordDefinition {
3
3
  static fromJson(json: WordDefinitionJson | null): WordDefinition;
4
4
  static readonly Null: WordDefinition;
5
5
  readonly definitions: string[];
6
+ /**
7
+ * Does the word have an entry in a corresponding online dictionary?
8
+ */
9
+ readonly exists: boolean;
10
+ /**
11
+ * Can the word be legally used in the game?
12
+ */
6
13
  readonly isAllowed: boolean;
7
14
  readonly word: string;
8
- constructor({ definitions, isAllowed, word }: {
9
- definitions: string[];
10
- isAllowed: boolean;
11
- word: string;
12
- });
15
+ constructor({ definitions, exists, isAllowed, word }: WordDefinitionJson);
13
16
  toJson(): WordDefinitionJson | null;
14
17
  }
15
18
  export default WordDefinition;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class WordDefinition {
4
- constructor({ definitions, isAllowed, word }) {
4
+ constructor({ definitions, exists, isAllowed, word }) {
5
5
  this.definitions = definitions;
6
+ this.exists = exists;
6
7
  this.isAllowed = isAllowed;
7
8
  this.word = word;
8
9
  }
@@ -12,6 +13,7 @@ class WordDefinition {
12
13
  }
13
14
  return new WordDefinition({
14
15
  definitions: json.definitions,
16
+ exists: json.exists,
15
17
  isAllowed: json.isAllowed,
16
18
  word: json.word,
17
19
  });
@@ -19,6 +21,7 @@ class WordDefinition {
19
21
  toJson() {
20
22
  return {
21
23
  definitions: this.definitions,
24
+ exists: this.exists,
22
25
  isAllowed: this.isAllowed,
23
26
  word: this.word,
24
27
  };
@@ -26,6 +29,7 @@ class WordDefinition {
26
29
  }
27
30
  WordDefinition.Null = Object.freeze({
28
31
  definitions: [],
32
+ exists: false,
29
33
  isAllowed: false,
30
34
  word: '',
31
35
  toJson: () => null,
@@ -1,5 +1,12 @@
1
1
  interface WordDefinitionJson {
2
2
  definitions: string[];
3
+ /**
4
+ * Does the word have an entry in a corresponding online dictionary?
5
+ */
6
+ exists: boolean;
7
+ /**
8
+ * Can the word be legally used in the game?
9
+ */
3
10
  isAllowed: boolean;
4
11
  word: string;
5
12
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/types",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "description": "Scrabble Solver 2 - Types",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -10,8 +10,8 @@
10
10
  },
11
11
  "author": {
12
12
  "name": "Kamil Mielnik",
13
- "email": "kamil.adam.mielnik@gmail.com",
14
- "url": "https://kamilmielnik.com/"
13
+ "email": "kamil@kamilmielnik.com",
14
+ "url": "https://kamilmielnik.com"
15
15
  },
16
16
  "license": "CC-BY-NC-ND-4.0",
17
17
  "bugs": {
@@ -24,7 +24,7 @@
24
24
  "clean:force": "npm run clean && rimraf package-lock.json"
25
25
  },
26
26
  "dependencies": {
27
- "@scrabble-solver/constants": "^2.9.0"
27
+ "@scrabble-solver/constants": "^2.9.2"
28
28
  },
29
29
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
30
30
  }
@@ -1,11 +1,11 @@
1
1
  // eslint-disable-next-line no-shadow
2
2
  enum Locale {
3
+ DE_DE = 'de-DE',
3
4
  EN_GB = 'en-GB',
4
5
  EN_US = 'en-US',
5
6
  ES_ES = 'es-ES',
6
7
  FR_FR = 'fr-FR',
7
8
  PL_PL = 'pl-PL',
8
- DE_DE = 'de-DE',
9
9
  }
10
10
 
11
11
  const locales = Object.values(Locale);
@@ -8,6 +8,7 @@ class WordDefinition {
8
8
 
9
9
  return new WordDefinition({
10
10
  definitions: json.definitions,
11
+ exists: json.exists,
11
12
  isAllowed: json.isAllowed,
12
13
  word: json.word,
13
14
  });
@@ -15,6 +16,7 @@ class WordDefinition {
15
16
 
16
17
  public static readonly Null: WordDefinition = Object.freeze({
17
18
  definitions: [],
19
+ exists: false,
18
20
  isAllowed: false,
19
21
  word: '',
20
22
  toJson: () => null,
@@ -22,12 +24,21 @@ class WordDefinition {
22
24
 
23
25
  public readonly definitions: string[];
24
26
 
27
+ /**
28
+ * Does the word have an entry in a corresponding online dictionary?
29
+ */
30
+ public readonly exists: boolean;
31
+
32
+ /**
33
+ * Can the word be legally used in the game?
34
+ */
25
35
  public readonly isAllowed: boolean;
26
36
 
27
37
  public readonly word: string;
28
38
 
29
- constructor({ definitions, isAllowed, word }: { definitions: string[]; isAllowed: boolean; word: string }) {
39
+ constructor({ definitions, exists, isAllowed, word }: WordDefinitionJson) {
30
40
  this.definitions = definitions;
41
+ this.exists = exists;
31
42
  this.isAllowed = isAllowed;
32
43
  this.word = word;
33
44
  }
@@ -35,6 +46,7 @@ class WordDefinition {
35
46
  public toJson(): WordDefinitionJson | null {
36
47
  return {
37
48
  definitions: this.definitions,
49
+ exists: this.exists,
38
50
  isAllowed: this.isAllowed,
39
51
  word: this.word,
40
52
  };
@@ -1,5 +1,12 @@
1
1
  interface WordDefinitionJson {
2
2
  definitions: string[];
3
+ /**
4
+ * Does the word have an entry in a corresponding online dictionary?
5
+ */
6
+ exists: boolean;
7
+ /**
8
+ * Can the word be legally used in the game?
9
+ */
3
10
  isAllowed: boolean;
4
11
  word: string;
5
12
  }
@@ -1,3 +1,3 @@
1
1
  import { Locale, WordDefinition } from '@scrabble-solver/types';
2
- declare const getWordDefinition: (locale: Locale, word: string) => Promise<WordDefinition>;
2
+ declare const getWordDefinition: (locale: Locale, word: string, isAllowed: boolean) => Promise<WordDefinition>;
3
3
  export default getWordDefinition;
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const types_1 = require("@scrabble-solver/types");
4
4
  const crawl_1 = require("./crawl");
5
5
  const parse_1 = require("./parse");
6
- const getWordDefinition = async (locale, word) => {
6
+ const getWordDefinition = async (locale, word, isAllowed) => {
7
7
  const html = await (0, crawl_1.crawl)(locale, word);
8
- const { definitions, isAllowed } = (0, parse_1.parse)(locale, html);
9
- const wordDefinition = new types_1.WordDefinition({ definitions, isAllowed, word });
8
+ const { definitions, exists } = (0, parse_1.parse)(locale, html);
9
+ const wordDefinition = new types_1.WordDefinition({ definitions, exists, isAllowed, word });
10
10
  return wordDefinition;
11
11
  };
12
12
  exports.default = getWordDefinition;
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const striptags_1 = __importDefault(require("striptags"));
7
7
  const EMPHASIS_TAGS = ['a', 'b', 'em', 'internalXref'];
8
8
  const normalizeHtmlTags = (definition) => (0, striptags_1.default)((0, striptags_1.default)(definition, EMPHASIS_TAGS), undefined, '"');
9
- const normalizeLineBreaks = (definition) => definition.replace(/[\r\n]/g, '');
9
+ const normalizeLineBreaks = (definition) => definition.replace(/\r\n/g, '\n');
10
+ const normalizeWhitespace = (definition) => definition.replace(/[ ]+/g, ' ');
10
11
  const normalizeQuotes = (definition) => definition.replace(/\."/g, '".');
11
12
  /**
12
13
  * `(1.2) definition` -> `definition`
@@ -26,6 +27,7 @@ const normalizers = [
26
27
  normalizeMarkers,
27
28
  normalizeQuotes,
28
29
  normalizeLineBreaks,
30
+ normalizeWhitespace,
29
31
  normalizeTrailingSymbols,
30
32
  normalizeLeadingSymbols,
31
33
  normalizeNonWords,
@@ -19,10 +19,10 @@ const parsePerLocale = {
19
19
  [types_1.Locale.PL_PL]: parsePolish_1.default,
20
20
  };
21
21
  const parse = (locale, html) => {
22
- const { definitions, isAllowed } = parsePerLocale[locale](html);
22
+ const { definitions, exists } = parsePerLocale[locale](html);
23
23
  return {
24
24
  definitions: (0, lib_1.unique)(definitions.map(lib_1.normalizeDefinition).filter(Boolean)),
25
- isAllowed,
25
+ exists,
26
26
  };
27
27
  };
28
28
  exports.default = parse;
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const cheerio_1 = __importDefault(require("cheerio"));
3
+ const cheerio_1 = require("cheerio");
4
+ const DOES_NOT_EXIST_MESSAGE =
5
+ // eslint-disable-next-line max-len
6
+ "The word you've entered isn't in the dictionary. Click on a spelling suggestion below or try again using the search bar above.";
7
7
  const parseEnglish = (html) => {
8
- const $ = cheerio_1.default.load(html);
8
+ const $ = (0, cheerio_1.load)(html);
9
9
  $('strong.mw_t_bc').replaceWith(', ');
10
10
  $('.text-lowercase').remove();
11
11
  $('[id^=dictionary-entry]').find('.dtText > *:not(a)').remove();
12
12
  const $definitions = $('[id^=dictionary-entry]').find('.dtText, .cxl-ref');
13
13
  return {
14
- definitions: Array.from($definitions).map((definition) => $(definition).text()),
15
- isAllowed: $definitions.length > 0,
14
+ definitions: Array.from($definitions).map((definition) => $(definition).text().replace(/\n/g, '')),
15
+ exists: $('.spelling-suggestion-text').text().trim() !== DOES_NOT_EXIST_MESSAGE,
16
16
  };
17
17
  };
18
18
  exports.default = parseEnglish;
@@ -1,15 +1,12 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const cheerio_1 = __importDefault(require("cheerio"));
3
+ const cheerio_1 = require("cheerio");
7
4
  const parseFrench = (html) => {
8
- const $ = cheerio_1.default.load(html);
5
+ const $ = (0, cheerio_1.load)(html);
9
6
  const $definitions = $('.tlf_cdefinition');
10
7
  return {
11
8
  definitions: Array.from($definitions).map((definition) => $(definition).text()),
12
- isAllowed: $('#vitemselected span').length > 0,
9
+ exists: $('#vitemselected span').length > 0,
13
10
  };
14
11
  };
15
12
  exports.default = parseFrench;