scrabble-solver 2.9.3 → 2.10.1

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 (226) hide show
  1. package/.prettierignore +2 -0
  2. package/README.md +3 -1
  3. package/lerna.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/configs/build/literaki/literaki.d.ts +1 -0
  6. package/packages/configs/build/literaki/literaki.js +1 -0
  7. package/packages/configs/build/literaki/tiles/index.d.ts +1 -0
  8. package/packages/configs/build/literaki/tiles/index.js +3 -1
  9. package/packages/configs/build/literaki/tiles/tilesFa.d.ts +6 -0
  10. package/packages/configs/build/literaki/tiles/tilesFa.js +37 -0
  11. package/packages/configs/build/scrabble/scrabble.d.ts +1 -0
  12. package/packages/configs/build/scrabble/scrabble.js +1 -0
  13. package/packages/configs/build/scrabble/tiles/index.d.ts +1 -0
  14. package/packages/configs/build/scrabble/tiles/index.js +3 -1
  15. package/packages/configs/build/scrabble/tiles/tilesFa.d.ts +6 -0
  16. package/packages/configs/build/scrabble/tiles/tilesFa.js +37 -0
  17. package/packages/configs/package.json +3 -3
  18. package/packages/configs/src/literaki/literaki.ts +2 -1
  19. package/packages/configs/src/literaki/tiles/index.ts +1 -0
  20. package/packages/configs/src/literaki/tiles/tilesFa.ts +36 -0
  21. package/packages/configs/src/scrabble/scrabble.ts +2 -1
  22. package/packages/configs/src/scrabble/tiles/index.ts +1 -0
  23. package/packages/configs/src/scrabble/tiles/tilesFa.ts +36 -0
  24. package/packages/constants/build/index.js +1 -0
  25. package/packages/constants/package.json +1 -1
  26. package/packages/constants/src/index.ts +1 -0
  27. package/packages/dictionaries/package-lock.json +2 -2
  28. package/packages/dictionaries/package.json +4 -4
  29. package/packages/logger/package-lock.json +2 -2
  30. package/packages/logger/package.json +1 -1
  31. package/packages/logger/scripts/stats.js +1 -1
  32. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  33. package/packages/scrabble-solver/.next/build-manifest.json +11 -11
  34. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  35. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  36. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  37. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  38. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  39. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  40. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  41. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  42. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  43. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  44. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  45. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  46. package/packages/scrabble-solver/.next/server/chunks/{429.js → 131.js} +2 -3652
  47. package/packages/scrabble-solver/.next/server/chunks/413.js +399 -199
  48. package/packages/scrabble-solver/.next/server/chunks/44.js +71 -45
  49. package/packages/scrabble-solver/.next/server/chunks/515.js +1114 -542
  50. package/packages/scrabble-solver/.next/server/chunks/911.js +96 -2
  51. package/packages/scrabble-solver/.next/server/chunks/939.js +1 -0
  52. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  53. package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
  54. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  55. package/packages/scrabble-solver/.next/server/pages/500.html +2 -2
  56. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  57. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +49 -11
  58. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  59. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +1 -8
  60. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  61. package/packages/scrabble-solver/.next/server/pages/api/solve.js +67 -57
  62. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  63. package/packages/scrabble-solver/.next/server/pages/api/verify.js +2 -9
  64. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  65. package/packages/scrabble-solver/.next/server/pages/index.html +9 -1
  66. package/packages/scrabble-solver/.next/server/pages/index.js +43 -36
  67. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  68. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  69. package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
  70. package/packages/scrabble-solver/.next/static/chunks/368-8b386c3106556f62.js +1 -0
  71. package/packages/scrabble-solver/.next/static/chunks/pages/{404-8650986dc56dab75.js → 404-932294135c3206dd.js} +1 -1
  72. package/packages/scrabble-solver/.next/static/chunks/pages/_app-8f0df20f771045ed.js +1 -0
  73. package/packages/scrabble-solver/.next/static/chunks/pages/index-8af7a9d7a2cd98a7.js +1 -0
  74. package/packages/scrabble-solver/.next/static/css/6b1833fd19d3a74a.css +1 -0
  75. package/packages/scrabble-solver/.next/static/css/a6154e4ca046ca13.css +1 -0
  76. package/packages/scrabble-solver/.next/static/css/bad53af6f8616677.css +1 -0
  77. package/packages/scrabble-solver/.next/static/hf94cues-LcXZRCpAzQ6w/_buildManifest.js +1 -0
  78. package/packages/scrabble-solver/.next/static/{s5pE_3C3ebZuSfaqE7xat → hf94cues-LcXZRCpAzQ6w}/_ssgManifest.js +0 -0
  79. package/packages/scrabble-solver/.next/trace +52 -52
  80. package/packages/scrabble-solver/package-lock.json +2 -2
  81. package/packages/scrabble-solver/package.json +8 -8
  82. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +45 -9
  83. package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +6 -4
  84. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +8 -1
  85. package/packages/scrabble-solver/src/components/EmptyState/EmptyState.tsx +6 -2
  86. package/packages/scrabble-solver/src/components/Loading/Loading.tsx +13 -2
  87. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.module.scss +8 -7
  88. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +35 -28
  89. package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.tsx +7 -1
  90. package/packages/scrabble-solver/src/components/PlainTiles/Tile.tsx +4 -3
  91. package/packages/scrabble-solver/src/components/Rack/Rack.tsx +18 -4
  92. package/packages/scrabble-solver/src/components/Radio/Radio.module.scss +1 -1
  93. package/packages/scrabble-solver/src/components/RemainingTiles/Character.tsx +7 -2
  94. package/packages/scrabble-solver/src/components/RemainingTiles/RemainingTiles.tsx +28 -20
  95. package/packages/scrabble-solver/src/components/Results/Cell.tsx +5 -3
  96. package/packages/scrabble-solver/src/components/Results/Result.tsx +8 -3
  97. package/packages/scrabble-solver/src/components/Results/Results.module.scss +31 -9
  98. package/packages/scrabble-solver/src/components/Results/Results.tsx +8 -4
  99. package/packages/scrabble-solver/src/components/Results/getColumns.ts +58 -0
  100. package/packages/scrabble-solver/src/components/Settings/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
  101. package/packages/scrabble-solver/src/components/Settings/components/ConfigSetting/ConfigSetting.module.scss +1 -0
  102. package/packages/scrabble-solver/src/components/Settings/components/LocaleSetting/LocaleSetting.module.scss +12 -1
  103. package/packages/scrabble-solver/src/components/Settings/components/LocaleSetting/LocaleSetting.tsx +1 -1
  104. package/packages/scrabble-solver/src/components/Settings/components/LocaleSetting/options.ts +16 -2
  105. package/packages/scrabble-solver/src/components/Sidebar/Sidebar.module.scss +42 -8
  106. package/packages/scrabble-solver/src/components/SvgFontCss/SvgFontCss.tsx +8 -7
  107. package/packages/scrabble-solver/src/components/SvgFontCss/createCss.ts +11 -0
  108. package/packages/scrabble-solver/src/components/SvgFontCss/createStyle.ts +9 -0
  109. package/packages/scrabble-solver/src/components/SvgFontCss/createSvg.ts +10 -0
  110. package/packages/scrabble-solver/src/components/SvgFontFix/SvgFontFix.module.scss +5 -0
  111. package/packages/scrabble-solver/src/components/SvgFontFix/SvgFontFix.tsx +21 -0
  112. package/packages/scrabble-solver/src/components/SvgFontFix/index.ts +1 -0
  113. package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +10 -2
  114. package/packages/scrabble-solver/src/components/Tile/Tile.tsx +4 -0
  115. package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +3 -1
  116. package/packages/scrabble-solver/src/components/Words/Words.tsx +4 -3
  117. package/packages/scrabble-solver/src/components/index.ts +1 -0
  118. package/packages/scrabble-solver/src/hooks/index.ts +2 -0
  119. package/packages/scrabble-solver/src/hooks/useDirection.ts +22 -0
  120. package/packages/scrabble-solver/src/hooks/useLanguage.ts +22 -0
  121. package/packages/scrabble-solver/src/i18n/constants.ts +53 -0
  122. package/packages/scrabble-solver/src/i18n/fa.json +56 -0
  123. package/packages/scrabble-solver/src/i18n/fr.json +1 -1
  124. package/packages/scrabble-solver/src/i18n/i18n.ts +22 -0
  125. package/packages/scrabble-solver/src/i18n/index.ts +2 -20
  126. package/packages/scrabble-solver/src/icons/FlagFa.svg +95 -0
  127. package/packages/scrabble-solver/src/icons/index.ts +1 -0
  128. package/packages/scrabble-solver/src/lib/createComparator.ts +22 -0
  129. package/packages/scrabble-solver/src/lib/createKeyComparator.ts +4 -2
  130. package/packages/scrabble-solver/src/lib/createStringComparator.ts +5 -0
  131. package/packages/scrabble-solver/src/lib/detectLocale.ts +4 -0
  132. package/packages/scrabble-solver/src/lib/getRemainingTiles.ts +4 -2
  133. package/packages/scrabble-solver/src/lib/getRemainingTilesGroups.ts +54 -31
  134. package/packages/scrabble-solver/src/lib/index.ts +2 -2
  135. package/packages/scrabble-solver/src/lib/sortResults.ts +11 -9
  136. package/packages/scrabble-solver/src/lib/unorderedArraysEqual.ts +3 -2
  137. package/packages/scrabble-solver/src/pages/api/verify.ts +1 -1
  138. package/packages/scrabble-solver/src/pages/index.module.scss +7 -18
  139. package/packages/scrabble-solver/src/pages/index.tsx +10 -2
  140. package/packages/scrabble-solver/src/sdk/findWordDefinitions.ts +1 -1
  141. package/packages/scrabble-solver/src/service-worker/routeVerifyRequests.ts +1 -1
  142. package/packages/scrabble-solver/src/state/sagas.ts +19 -5
  143. package/packages/scrabble-solver/src/state/selectors.ts +15 -7
  144. package/packages/scrabble-solver/src/styles/global.scss +6 -1
  145. package/packages/solver/package-lock.json +2 -2
  146. package/packages/solver/package.json +5 -5
  147. package/packages/types/build/Locale.d.ts +1 -0
  148. package/packages/types/build/Locale.js +1 -0
  149. package/packages/types/build/Result.d.ts +0 -1
  150. package/packages/types/build/Result.js +0 -5
  151. package/packages/types/package.json +2 -2
  152. package/packages/types/src/Locale.ts +1 -0
  153. package/packages/types/src/Result.ts +0 -11
  154. package/packages/word-definitions/build/crawl/crawl.js +2 -0
  155. package/packages/word-definitions/build/crawl/crawlFarsi.d.ts +2 -0
  156. package/packages/word-definitions/build/crawl/crawlFarsi.js +11 -0
  157. package/packages/word-definitions/build/lib/normalizeDefinition.js +2 -1
  158. package/packages/word-definitions/build/parse/index.d.ts +1 -0
  159. package/packages/word-definitions/build/parse/index.js +3 -1
  160. package/packages/word-definitions/build/parse/parse.js +2 -0
  161. package/packages/word-definitions/build/parse/parseEnglish.js +1 -1
  162. package/packages/word-definitions/build/parse/parseFarsi.d.ts +3 -0
  163. package/packages/word-definitions/build/parse/parseFarsi.js +13 -0
  164. package/packages/word-definitions/package-lock.json +2 -2
  165. package/packages/word-definitions/package.json +2 -2
  166. package/packages/word-definitions/src/crawl/crawl.ts +2 -0
  167. package/packages/word-definitions/src/crawl/crawlFarsi.ts +11 -0
  168. package/packages/word-definitions/src/lib/normalizeDefinition.ts +2 -1
  169. package/packages/word-definitions/src/parse/__tests__/input/en-US.awe.html +2170 -323
  170. package/packages/word-definitions/src/parse/__tests__/input/en-US.pawn.html +2405 -349
  171. package/packages/word-definitions/src/parse/__tests__/input/en-US.pawnee.html +1326 -222
  172. package/packages/word-definitions/src/parse/__tests__/input/en-US.pean.html +1490 -201
  173. package/packages/word-definitions/src/parse/__tests__/input/en-US.wiz.html +1526 -272
  174. package/packages/word-definitions/src/parse/index.ts +1 -0
  175. package/packages/word-definitions/src/parse/parse.ts +2 -0
  176. package/packages/word-definitions/src/parse/parseEnglish.ts +2 -1
  177. package/packages/word-definitions/src/parse/parseFarsi.ts +17 -0
  178. package/packages/word-lists/build/getDeDeWordList.js +2 -1
  179. package/packages/word-lists/build/getEnGbWordList.js +2 -1
  180. package/packages/word-lists/build/getEnUsWordList.js +2 -1
  181. package/packages/word-lists/build/getEsEsWordList.js +2 -1
  182. package/packages/word-lists/build/getFaIrWordList.d.ts +2 -0
  183. package/packages/word-lists/build/getFaIrWordList.js +9 -0
  184. package/packages/word-lists/build/getFrFrWordList.js +2 -1
  185. package/packages/word-lists/build/getPlPlWordList.js +9 -9
  186. package/packages/word-lists/build/getWordList.js +2 -0
  187. package/packages/word-lists/build/lib/downloadFile.js +5 -5
  188. package/packages/word-lists/build/lib/extractWords.d.ts +1 -1
  189. package/packages/word-lists/build/lib/extractWords.js +10 -7
  190. package/packages/word-lists/build/lib/findFirstWordIndex.d.ts +1 -1
  191. package/packages/word-lists/build/lib/findFirstWordIndex.js +2 -2
  192. package/packages/word-lists/build/lib/getTempFilepath.d.ts +2 -0
  193. package/packages/word-lists/build/lib/getTempFilepath.js +14 -0
  194. package/packages/word-lists/build/lib/getTxtWordList.d.ts +1 -1
  195. package/packages/word-lists/build/lib/getTxtWordList.js +5 -5
  196. package/packages/word-lists/build/lib/index.d.ts +1 -1
  197. package/packages/word-lists/build/lib/index.js +3 -3
  198. package/packages/word-lists/package-lock.json +2 -32
  199. package/packages/word-lists/package.json +2 -3
  200. package/packages/word-lists/src/getDeDeWordList.ts +3 -1
  201. package/packages/word-lists/src/getEnGbWordList.ts +3 -1
  202. package/packages/word-lists/src/getEnUsWordList.ts +3 -1
  203. package/packages/word-lists/src/getEsEsWordList.ts +3 -1
  204. package/packages/word-lists/src/getFaIrWordList.ts +11 -0
  205. package/packages/word-lists/src/getFrFrWordList.ts +3 -1
  206. package/packages/word-lists/src/getPlPlWordList.ts +7 -7
  207. package/packages/word-lists/src/getWordList.ts +2 -0
  208. package/packages/word-lists/src/lib/downloadFile.ts +5 -5
  209. package/packages/word-lists/src/lib/extractWords.ts +13 -7
  210. package/packages/word-lists/src/lib/findFirstWordIndex.ts +2 -2
  211. package/packages/word-lists/src/lib/getTempFilepath.ts +13 -0
  212. package/packages/word-lists/src/lib/getTxtWordList.ts +3 -3
  213. package/packages/word-lists/src/lib/index.ts +1 -1
  214. package/packages/scrabble-solver/.next/static/chunks/880-18e3aea6915aebe7.js +0 -1
  215. package/packages/scrabble-solver/.next/static/chunks/pages/_app-183f598b1d4d480b.js +0 -1
  216. package/packages/scrabble-solver/.next/static/chunks/pages/index-f1cef1e67e14d022.js +0 -1
  217. package/packages/scrabble-solver/.next/static/css/751e8a14776d05d8.css +0 -1
  218. package/packages/scrabble-solver/.next/static/css/ad2a08918868cad8.css +0 -1
  219. package/packages/scrabble-solver/.next/static/css/e8de67ad5ea35427.css +0 -1
  220. package/packages/scrabble-solver/.next/static/s5pE_3C3ebZuSfaqE7xat/_buildManifest.js +0 -1
  221. package/packages/scrabble-solver/src/components/Results/constants.ts +0 -42
  222. package/packages/scrabble-solver/src/lib/comparator.ts +0 -16
  223. package/packages/scrabble-solver/src/lib/stringComparator.ts +0 -5
  224. package/packages/word-lists/build/lib/getTempFilename.d.ts +0 -2
  225. package/packages/word-lists/build/lib/getTempFilename.js +0 -10
  226. package/packages/word-lists/src/lib/getTempFilename.ts +0 -7
@@ -18,14 +18,16 @@ import {
18
18
  Results,
19
19
  Settings,
20
20
  Splash,
21
+ SvgFontFix,
21
22
  Well,
22
23
  Words,
23
24
  } from 'components';
24
- import { useIsTablet, useLocalStorage } from 'hooks';
25
+ import { useDirection, useIsTablet, useLanguage, useLocalStorage } from 'hooks';
26
+ import { LOCALE_FEATURES } from 'i18n';
25
27
  import { getCellSize } from 'lib';
26
28
  import { COMPONENTS_SPACING, COMPONENTS_SPACING_MOBILE, DICTIONARY_HEIGHT } from 'parameters';
27
29
  import { registerServiceWorker } from 'serviceWorkerManager';
28
- import { initialize, localStorage, reset, selectConfig, solveSlice, useTypedSelector } from 'state';
30
+ import { initialize, localStorage, reset, selectConfig, selectLocale, solveSlice, useTypedSelector } from 'state';
29
31
 
30
32
  import styles from './index.module.scss';
31
33
 
@@ -37,6 +39,7 @@ interface Props {
37
39
 
38
40
  const Index: FunctionComponent<Props> = ({ version }) => {
39
41
  const dispatch = useDispatch();
42
+ const locale = useTypedSelector(selectLocale);
40
43
  const isTablet = useIsTablet();
41
44
  const [showKeyMap, setShowKeyMap] = useState(false);
42
45
  const [showRemainingTiles, setShowRemainingTiles] = useState(false);
@@ -68,6 +71,9 @@ const Index: FunctionComponent<Props> = ({ version }) => {
68
71
  }
69
72
  };
70
73
 
74
+ const { direction } = LOCALE_FEATURES[locale];
75
+ useDirection(direction);
76
+ useLanguage(locale);
71
77
  useLocalStorage();
72
78
 
73
79
  useEffectOnce(() => {
@@ -86,6 +92,8 @@ const Index: FunctionComponent<Props> = ({ version }) => {
86
92
 
87
93
  return (
88
94
  <>
95
+ <SvgFontFix />
96
+
89
97
  <div className={classNames(styles.index, { [styles.initialized]: isInitialized })}>
90
98
  <div className={styles.nav}>
91
99
  <div className={styles.navLogo}>
@@ -3,7 +3,7 @@ import { Locale, WordDefinition, WordDefinitionJson } from '@scrabble-solver/typ
3
3
  import fetchJson from './fetchJson';
4
4
 
5
5
  const findWordDefinitions = async (locale: Locale, word: string): Promise<WordDefinition[]> => {
6
- const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${word}`);
6
+ const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${encodeURIComponent(word)}`);
7
7
  return json.map(WordDefinition.fromJson);
8
8
  };
9
9
 
@@ -22,7 +22,7 @@ const routeVerifyRequests = () => {
22
22
  }
23
23
 
24
24
  const board = Board.fromJson(boardJson);
25
- const words = board.getWords().sort((a, b) => a.localeCompare(b));
25
+ const words = board.getWords().sort((a, b) => a.localeCompare(b, locale));
26
26
  const invalidWords = words.filter((word) => !trie.has(word));
27
27
  const validWords = words.filter((word) => trie.has(word));
28
28
  const json = JSON.stringify({ invalidWords, validWords });
@@ -7,13 +7,13 @@ import { findWordDefinitions, solve, verify, visit } from 'sdk';
7
7
 
8
8
  import { initialize, reset } from './actions';
9
9
  import {
10
- selectAutoGroupTiles,
11
10
  selectBoard,
12
11
  selectCellIsFiltered,
13
12
  selectCharacters,
14
13
  selectConfig,
15
14
  selectDictionary,
16
15
  selectLocale,
16
+ selectLocaleAutoGroupTiles,
17
17
  } from './selectors';
18
18
  import {
19
19
  boardSlice,
@@ -65,7 +65,7 @@ function* onRackValueChange(): AnyGenerator {
65
65
  }
66
66
 
67
67
  function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerator {
68
- const autoGroupTiles = yield select(selectAutoGroupTiles);
68
+ const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
69
69
  yield put(boardSlice.actions.applyResult(result));
70
70
  yield put(cellFilterSlice.actions.reset());
71
71
  yield put(rackSlice.actions.removeTiles(result.tiles));
@@ -74,8 +74,15 @@ function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerato
74
74
  }
75
75
 
76
76
  function* onConfigIdChange(): AnyGenerator {
77
+ const characters = yield select(selectCharacters);
78
+
79
+ if (characters.length > 0) {
80
+ yield put(solveSlice.actions.submit());
81
+ } else {
82
+ yield put(resultsSlice.actions.reset());
83
+ }
84
+
77
85
  yield put(resultsSlice.actions.reset());
78
- yield put(solveSlice.actions.submit());
79
86
  yield put(verifySlice.actions.submit());
80
87
  yield* ensureProperTilesCount();
81
88
  }
@@ -112,9 +119,16 @@ function* onReset(): AnyGenerator {
112
119
  }
113
120
 
114
121
  function* onLocaleChange(): AnyGenerator {
122
+ const characters = yield select(selectCharacters);
123
+
124
+ if (characters.length > 0) {
125
+ yield put(solveSlice.actions.submit());
126
+ } else {
127
+ yield put(resultsSlice.actions.reset());
128
+ }
129
+
115
130
  yield put(dictionarySlice.actions.reset());
116
131
  yield put(resultsSlice.actions.changeResultCandidate(null));
117
- yield put(solveSlice.actions.submit());
118
132
  yield put(verifySlice.actions.submit());
119
133
  }
120
134
 
@@ -181,7 +195,7 @@ function* ensureProperTilesCount(): AnyGenerator {
181
195
  } else if (config.maximumCharactersCount < characters.length) {
182
196
  const nonNulls = characters.filter(Boolean).slice(0, config.maximumCharactersCount);
183
197
  const differenceCount = Math.abs(config.maximumCharactersCount - nonNulls.length);
184
- const autoGroupTiles = yield select(selectAutoGroupTiles);
198
+ const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
185
199
  yield put(rackSlice.actions.init([...nonNulls, ...Array(differenceCount).fill(null)]));
186
200
  yield put(rackSlice.actions.groupTiles(autoGroupTiles));
187
201
  }
@@ -2,7 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
2
2
  import { getLocaleConfig } from '@scrabble-solver/configs';
3
3
  import { Cell, Config, isError, Result, Tile } from '@scrabble-solver/types';
4
4
 
5
- import i18n from 'i18n';
5
+ import i18n, { LOCALE_FEATURES } from 'i18n';
6
6
  import { findCell, getRemainingTiles, getRemainingTilesGroups, sortResults, unorderedArraysEqual } from 'lib';
7
7
  import { Translations } from 'types';
8
8
 
@@ -38,9 +38,17 @@ export const selectDictionaryError = createSelector([selectDictionaryRoot], (dic
38
38
  return isError(dictionary.error) ? dictionary.error : undefined;
39
39
  });
40
40
 
41
+ export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
42
+
41
43
  export const selectAutoGroupTiles = createSelector([selectSettingsRoot], (settings) => settings.autoGroupTiles);
42
44
 
43
- export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
45
+ export const selectLocaleAutoGroupTiles = createSelector([selectLocale, selectSettingsRoot], (locale, settings) => {
46
+ if (LOCALE_FEATURES[locale].direction === 'ltr' || settings.autoGroupTiles === null) {
47
+ return settings.autoGroupTiles;
48
+ }
49
+
50
+ return settings.autoGroupTiles === 'left' ? 'right' : 'left';
51
+ });
44
52
 
45
53
  export const selectBoard = selectBoardRoot;
46
54
 
@@ -63,7 +71,7 @@ export const selectResultsSortColumn = createSelector([selectResultsRoot], (resu
63
71
  export const selectResultsSortDirection = createSelector([selectResultsRoot], (results) => results.sort.direction);
64
72
 
65
73
  export const selectSortedResults = createSelector(
66
- [selectResults, selectResultsSortColumn, selectResultsSortDirection],
74
+ [selectResults, selectResultsSortColumn, selectResultsSortDirection, selectLocale],
67
75
  sortResults,
68
76
  );
69
77
 
@@ -167,9 +175,9 @@ export const selectSolveError = createSelector([selectSolveRoot], (solve) => {
167
175
  });
168
176
 
169
177
  export const selectHaveCharactersChanged = createSelector(
170
- [selectLastSolvedParameters, selectCharacters],
171
- (lastSolvedParameters, characters) => {
172
- return !unorderedArraysEqual(lastSolvedParameters.characters, characters);
178
+ [selectLastSolvedParameters, selectCharacters, selectLocale],
179
+ (lastSolvedParameters, characters, locale) => {
180
+ return !unorderedArraysEqual(lastSolvedParameters.characters, characters, locale);
173
181
  },
174
182
  );
175
183
 
@@ -184,7 +192,7 @@ export const selectAreResultsOutdated = createSelector(
184
192
  );
185
193
 
186
194
  export const selectRemainingTiles = createSelector(
187
- [selectConfig, selectBoardRoot, selectCharacters],
195
+ [selectConfig, selectBoardRoot, selectCharacters, selectLocale],
188
196
  getRemainingTiles,
189
197
  );
190
198
 
@@ -1,4 +1,4 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&family=Open+Sans:wght@400;700&family=Roboto+Mono&display=swap');
1
+ @import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&family=Open+Sans:wght@400;700&family=Vazirmatn:wght@300;400;700&family=Roboto+Mono&display=swap');
2
2
 
3
3
  @import '~normalize.css';
4
4
 
@@ -51,3 +51,8 @@ h4 {
51
51
  -webkit-margin-after: 0;
52
52
  margin: 0;
53
53
  }
54
+
55
+ [lang='fa-IR'] {
56
+ --font--family: 'Vazirmatn', 'Open Sans', sans-serif;
57
+ --font--family--title: 'Vazirmatn', 'Lato', sans-serif;
58
+ }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/solver",
3
- "version": "2.9.3",
3
+ "version": "2.10.1",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/solver",
9
- "version": "2.9.3",
9
+ "version": "2.10.1",
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.3",
3
+ "version": "2.10.1",
4
4
  "description": "Scrabble Solver 2 - Solver",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -25,12 +25,12 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@kamilmielnik/trie": "^2.0.1",
28
- "@scrabble-solver/types": "^2.9.3"
28
+ "@scrabble-solver/types": "^2.10.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@scrabble-solver/configs": "^2.9.3",
32
- "@scrabble-solver/constants": "^2.9.3",
33
- "@scrabble-solver/dictionaries": "^2.9.3"
31
+ "@scrabble-solver/configs": "^2.10.1",
32
+ "@scrabble-solver/constants": "^2.10.1",
33
+ "@scrabble-solver/dictionaries": "^2.10.1"
34
34
  },
35
35
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
36
36
  }
@@ -3,6 +3,7 @@ declare enum Locale {
3
3
  EN_GB = "en-GB",
4
4
  EN_US = "en-US",
5
5
  ES_ES = "es-ES",
6
+ FA_IR = "fa-IR",
6
7
  FR_FR = "fr-FR",
7
8
  PL_PL = "pl-PL"
8
9
  }
@@ -8,6 +8,7 @@ var Locale;
8
8
  Locale["EN_GB"] = "en-GB";
9
9
  Locale["EN_US"] = "en-US";
10
10
  Locale["ES_ES"] = "es-ES";
11
+ Locale["FA_IR"] = "fa-IR";
11
12
  Locale["FR_FR"] = "fr-FR";
12
13
  Locale["PL_PL"] = "pl-PL";
13
14
  })(Locale || (Locale = {}));
@@ -13,7 +13,6 @@ declare class Result {
13
13
  readonly points: number;
14
14
  readonly pointsRatio: number;
15
15
  readonly tiles: Tile[];
16
- readonly tilesCharacters: string;
17
16
  readonly tilesCount: number;
18
17
  readonly vowelsCount: number;
19
18
  readonly word: string;
@@ -17,7 +17,6 @@ class Result {
17
17
  this.points = points;
18
18
  this.pointsRatio = getPointsRatio(tiles, points);
19
19
  this.tiles = tiles;
20
- this.tilesCharacters = getTilesCharacters(tiles);
21
20
  this.tilesCount = tiles.length;
22
21
  this.vowelsCount = getVowels(tiles).length;
23
22
  this.word = getWord(cells);
@@ -41,15 +40,11 @@ class Result {
41
40
  };
42
41
  }
43
42
  }
44
- const charactersComparator = (a, b) => a.localeCompare(b);
45
43
  const getBlanks = (tiles) => tiles.filter(({ isBlank }) => isBlank);
46
44
  const getConsonants = (tiles) => tiles.filter(isConsonant);
47
45
  const getVowels = (tiles) => tiles.filter(isVowel);
48
- const getNonBlankCharacters = (tiles) => getNonBlanks(tiles).map(({ character }) => character);
49
- const getNonBlanks = (tiles) => tiles.filter(({ isBlank }) => !isBlank);
50
46
  const getPointsRatio = (tiles, points) => points / tiles.length;
51
47
  const getTiles = (cells) => cells.filter(({ isEmpty }) => isEmpty).map(({ tile }) => tile);
52
- const getTilesCharacters = (tiles) => getNonBlankCharacters(tiles).sort(charactersComparator).join('');
53
48
  // eslint-disable-next-line prefer-template
54
49
  const getWord = (cells) => cells.reduce((word, cell) => word + cell.toString(), '');
55
50
  const getWords = (cells, collisions) => [cells, ...collisions].map(getWord);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/types",
3
- "version": "2.9.3",
3
+ "version": "2.10.1",
4
4
  "description": "Scrabble Solver 2 - Types",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -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.3"
27
+ "@scrabble-solver/constants": "^2.10.1"
28
28
  },
29
29
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
30
30
  }
@@ -4,6 +4,7 @@ enum Locale {
4
4
  EN_GB = 'en-GB',
5
5
  EN_US = 'en-US',
6
6
  ES_ES = 'es-ES',
7
+ FA_IR = 'fa-IR',
7
8
  FR_FR = 'fr-FR',
8
9
  PL_PL = 'pl-PL',
9
10
  }
@@ -34,8 +34,6 @@ class Result {
34
34
 
35
35
  public readonly tiles: Tile[];
36
36
 
37
- public readonly tilesCharacters: string;
38
-
39
37
  public readonly tilesCount: number;
40
38
 
41
39
  public readonly vowelsCount: number;
@@ -67,7 +65,6 @@ class Result {
67
65
  this.points = points;
68
66
  this.pointsRatio = getPointsRatio(tiles, points);
69
67
  this.tiles = tiles;
70
- this.tilesCharacters = getTilesCharacters(tiles);
71
68
  this.tilesCount = tiles.length;
72
69
  this.vowelsCount = getVowels(tiles).length;
73
70
  this.word = getWord(cells);
@@ -85,24 +82,16 @@ class Result {
85
82
  }
86
83
  }
87
84
 
88
- const charactersComparator = (a: string, b: string): number => a.localeCompare(b);
89
-
90
85
  const getBlanks = (tiles: Tile[]): Tile[] => tiles.filter(({ isBlank }) => isBlank);
91
86
 
92
87
  const getConsonants = (tiles: Tile[]): Tile[] => tiles.filter(isConsonant);
93
88
 
94
89
  const getVowels = (tiles: Tile[]): Tile[] => tiles.filter(isVowel);
95
90
 
96
- const getNonBlankCharacters = (tiles: Tile[]): string[] => getNonBlanks(tiles).map(({ character }) => character);
97
-
98
- const getNonBlanks = (tiles: Tile[]): Tile[] => tiles.filter(({ isBlank }) => !isBlank);
99
-
100
91
  const getPointsRatio = (tiles: Tile[], points: number): number => points / tiles.length;
101
92
 
102
93
  const getTiles = (cells: Cell[]): Tile[] => cells.filter(({ isEmpty }) => isEmpty).map(({ tile }) => tile);
103
94
 
104
- const getTilesCharacters = (tiles: Tile[]): string => getNonBlankCharacters(tiles).sort(charactersComparator).join('');
105
-
106
95
  // eslint-disable-next-line prefer-template
107
96
  const getWord = (cells: Cell[]): string => cells.reduce((word, cell) => word + cell.toString(), '');
108
97
 
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const types_1 = require("@scrabble-solver/types");
7
7
  const crawlEnglish_1 = __importDefault(require("./crawlEnglish"));
8
+ const crawlFarsi_1 = __importDefault(require("./crawlFarsi"));
8
9
  const crawlFrench_1 = __importDefault(require("./crawlFrench"));
9
10
  const crawlGerman_1 = __importDefault(require("./crawlGerman"));
10
11
  const crawlPolish_1 = __importDefault(require("./crawlPolish"));
@@ -14,6 +15,7 @@ const crawlPerLocale = {
14
15
  [types_1.Locale.EN_GB]: crawlEnglish_1.default,
15
16
  [types_1.Locale.EN_US]: crawlEnglish_1.default,
16
17
  [types_1.Locale.ES_ES]: crawlSpanish_1.default,
18
+ [types_1.Locale.FA_IR]: crawlFarsi_1.default,
17
19
  [types_1.Locale.FR_FR]: crawlFrench_1.default,
18
20
  [types_1.Locale.PL_PL]: crawlPolish_1.default,
19
21
  };
@@ -0,0 +1,2 @@
1
+ declare const crawlFarsi: (word: string) => Promise<string>;
2
+ export default crawlFarsi;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lib_1 = require("../lib");
4
+ const crawlFarsi = (word) => {
5
+ return (0, lib_1.request)({
6
+ protocol: 'https',
7
+ hostname: 'www.vajehyab.com',
8
+ path: `/moein/${encodeURIComponent(word)}`,
9
+ });
10
+ };
11
+ exports.default = crawlFarsi;
@@ -15,7 +15,8 @@ const normalizeQuotes = (definition) => definition.replace(/\."/g, '".');
15
15
  const normalizeMarkers = (definition) => definition.replace(/^\(\d+\.\d+\)\s+/g, '');
16
16
  const normalizeTrailingSymbols = (definition) => definition.trim().replace(/:$/, '');
17
17
  const normalizeLeadingSymbols = (definition) => definition.trim().replace(/^:/, '');
18
- const normalizeNonWords = (definition) => (/\w/.test(definition) ? definition : '');
18
+ // https://stackoverflow.com/a/40732368
19
+ const normalizeNonWords = (definition) => (/[\w\u0621-\u064A]+/.test(definition) ? definition : '');
19
20
  const normalizeCommas = (definition) => {
20
21
  return definition
21
22
  .replace(/\s+,\s+/g, ', ')
@@ -1,5 +1,6 @@
1
1
  export { default as parse } from './parse';
2
2
  export { default as parseEnglish } from './parseEnglish';
3
+ export { default as parseFarsi } from './parseFarsi';
3
4
  export { default as parseFrench } from './parseFrench';
4
5
  export { default as parseGerman } from './parseGerman';
5
6
  export { default as parsePolish } from './parsePolish';
@@ -3,11 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parseSpanish = exports.parsePolish = exports.parseGerman = exports.parseFrench = exports.parseEnglish = exports.parse = void 0;
6
+ exports.parseSpanish = exports.parsePolish = exports.parseGerman = exports.parseFrench = exports.parseFarsi = exports.parseEnglish = exports.parse = void 0;
7
7
  var parse_1 = require("./parse");
8
8
  Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return __importDefault(parse_1).default; } });
9
9
  var parseEnglish_1 = require("./parseEnglish");
10
10
  Object.defineProperty(exports, "parseEnglish", { enumerable: true, get: function () { return __importDefault(parseEnglish_1).default; } });
11
+ var parseFarsi_1 = require("./parseFarsi");
12
+ Object.defineProperty(exports, "parseFarsi", { enumerable: true, get: function () { return __importDefault(parseFarsi_1).default; } });
11
13
  var parseFrench_1 = require("./parseFrench");
12
14
  Object.defineProperty(exports, "parseFrench", { enumerable: true, get: function () { return __importDefault(parseFrench_1).default; } });
13
15
  var parseGerman_1 = require("./parseGerman");
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const types_1 = require("@scrabble-solver/types");
7
7
  const lib_1 = require("../lib");
8
8
  const parseEnglish_1 = __importDefault(require("./parseEnglish"));
9
+ const parseFarsi_1 = __importDefault(require("./parseFarsi"));
9
10
  const parseFrench_1 = __importDefault(require("./parseFrench"));
10
11
  const parseGerman_1 = __importDefault(require("./parseGerman"));
11
12
  const parsePolish_1 = __importDefault(require("./parsePolish"));
@@ -15,6 +16,7 @@ const parsePerLocale = {
15
16
  [types_1.Locale.EN_GB]: parseEnglish_1.default,
16
17
  [types_1.Locale.EN_US]: parseEnglish_1.default,
17
18
  [types_1.Locale.ES_ES]: parseSpanish_1.default,
19
+ [types_1.Locale.FA_IR]: parseFarsi_1.default,
18
20
  [types_1.Locale.FR_FR]: parseFrench_1.default,
19
21
  [types_1.Locale.PL_PL]: parsePolish_1.default,
20
22
  };
@@ -8,7 +8,7 @@ const parseEnglish = (html) => {
8
8
  const $ = (0, cheerio_1.load)(html);
9
9
  $('strong.mw_t_bc').replaceWith(', ');
10
10
  $('.text-lowercase').remove();
11
- $('[id^=dictionary-entry]').find('.dtText > *:not(a)').remove();
11
+ $('.sub-content-thread').remove();
12
12
  const $definitions = $('[id^=dictionary-entry]').find('.dtText, .cxl-ref');
13
13
  return {
14
14
  definitions: Array.from($definitions).map((definition) => $(definition).text().replace(/\n/g, '')),
@@ -0,0 +1,3 @@
1
+ import { ParseResult } from '../types';
2
+ declare const parseFarsi: (html: string) => ParseResult;
3
+ export default parseFarsi;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const cheerio_1 = require("cheerio");
4
+ const DOES_NOT_EXIST_MESSAGE = '404 Page Not Found';
5
+ const parseFarsi = (html) => {
6
+ const $ = (0, cheerio_1.load)(html);
7
+ const $definitions = $('[itemprop=articleBody]');
8
+ return {
9
+ definitions: Array.from($definitions).map((definition) => $(definition).text()),
10
+ exists: $('#container h1').text() !== DOES_NOT_EXIST_MESSAGE,
11
+ };
12
+ };
13
+ exports.default = parseFarsi;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/word-definitions",
3
- "version": "2.9.3",
3
+ "version": "2.10.1",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/word-definitions",
9
- "version": "2.9.3",
9
+ "version": "2.10.1",
10
10
  "license": "CC-BY-NC-ND-4.0",
11
11
  "dependencies": {
12
12
  "cheerio": "^1.0.0-rc.12",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/word-definitions",
3
- "version": "2.9.3",
3
+ "version": "2.10.1",
4
4
  "description": "Scrabble Solver 2 - Word definitions",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "clean": "rimraf build/ node_modules/ package-lock.json"
24
24
  },
25
25
  "dependencies": {
26
- "@scrabble-solver/types": "^2.9.3",
26
+ "@scrabble-solver/types": "^2.10.1",
27
27
  "cheerio": "^1.0.0-rc.12",
28
28
  "follow-redirects": "^1.15.2",
29
29
  "striptags": "^3.2.0"
@@ -1,6 +1,7 @@
1
1
  import { Locale } from '@scrabble-solver/types';
2
2
 
3
3
  import crawlEnglish from './crawlEnglish';
4
+ import crawlFarsi from './crawlFarsi';
4
5
  import crawlFrench from './crawlFrench';
5
6
  import crawlGerman from './crawlGerman';
6
7
  import crawlPolish from './crawlPolish';
@@ -11,6 +12,7 @@ const crawlPerLocale: Record<Locale, (word: string) => Promise<string>> = {
11
12
  [Locale.EN_GB]: crawlEnglish,
12
13
  [Locale.EN_US]: crawlEnglish,
13
14
  [Locale.ES_ES]: crawlSpanish,
15
+ [Locale.FA_IR]: crawlFarsi,
14
16
  [Locale.FR_FR]: crawlFrench,
15
17
  [Locale.PL_PL]: crawlPolish,
16
18
  };
@@ -0,0 +1,11 @@
1
+ import { request } from '../lib';
2
+
3
+ const crawlFarsi = (word: string): Promise<string> => {
4
+ return request({
5
+ protocol: 'https',
6
+ hostname: 'www.vajehyab.com',
7
+ path: `/moein/${encodeURIComponent(word)}`,
8
+ });
9
+ };
10
+
11
+ export default crawlFarsi;
@@ -21,7 +21,8 @@ const normalizeTrailingSymbols: Normalize = (definition) => definition.trim().re
21
21
 
22
22
  const normalizeLeadingSymbols: Normalize = (definition) => definition.trim().replace(/^:/, '');
23
23
 
24
- const normalizeNonWords: Normalize = (definition) => (/\w/.test(definition) ? definition : '');
24
+ // https://stackoverflow.com/a/40732368
25
+ const normalizeNonWords: Normalize = (definition) => (/[\w\u0621-\u064A]+/.test(definition) ? definition : '');
25
26
 
26
27
  const normalizeCommas: Normalize = (definition) => {
27
28
  return definition