diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index 3d99fddd..997b1fba 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -27,7 +27,7 @@ jobs: - name: Setup Deno uses: denoland/setup-deno@v2 with: - deno-version: v2.x + deno-version: v2.4.x - name: Install Dependencies run: deno install --frozen - name: Build diff --git a/CHANGELOG.md b/CHANGELOG.md index 310606b3..faace1ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,22 +2,54 @@ +## 0.7.0 + +Released 25 September 2025 + +ilo Token can now translate preverbs! Currently this only works when the +predicate is translated as a verb unless the preverb is translated as a linking +verb. This will be expanded soon. + +ilo Token will now recognize "taso" as sentence starting particle along with +other particle with similar function such as "kin" and "anu". ilo Token will +also recognize "anu la" treating it similarly like "anu" as sentence starting +particle. + +ilo Token now performs proper verb negation: "mi toki ala" will translate to "I +do not communicate" instead of the grammatically awkward "I not communicate". + +- Implement preverb translation. +- Implement translation of "taso", "kin", and "anu" as sentence starting + particle. +- Implement translation of "anu la". +- Implement proper verb negation. +- Implement modal verb translation e.g. "mi ken" into "I can". +- Implement pagination. This also prevents browser crashes due to numerous + translation output. +- Number as english words e.g. "ten" instead of "10" are now used for small + numbers (≤ 20). Thanks soweli Eweke for the suggestion! +- Remove telo misikeke. ilo Token's own error messages still needs more work. +- Remove "allow separate repeated modifiers". It'll be hardcoded to be turned + on. + ## 0.6.0 Released 22 April 2025 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2066d65a..21be3db8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,7 +58,7 @@ More things to remember: - Keep the source code as runtime agnostic as possible. We target the browser and Deno. This is necessary because we use `deno test`. If a module is exclusive to one runtime, add a note above the code: - `// This code is browser/Deno only`. + `// this code is browser/Deno only`. (The following aren't strict rules. It's perfectly fine to not follow any of these for any reason e.g. you just want to fix typo.) @@ -87,16 +87,16 @@ themselves serves as a space for broader topics, not just ilo Token. - [ma pona pi toki pona Discord Server](https://discord.gg/Byqn5z9) ([Thread for ilo Token](https://discord.com/channels/301377942062366741/1053538532993548320)): A Discord server for Toki Pona. - --> - -- [Conlangs from Space](https://conlangsfrom.space/) - ([Forum page for ilo Token](https://conlangsfrom.space/t/ilo-token-a-wip-rule-based-toki-pona-to-english-translator/452)): - A forum site dedicated for all conlangs, not just Toki Pona. - [r/ProgrammingLanguages Discord Server](https://discord.gg/4Kjt3ZE) ([Channel for ilo Token](https://discord.com/channels/530598289813536771/1224854915214737522)): A Discord server for programming language development. While ilo Token isn't a programming language, it uses similar techniques found in programming language development e.g. parsing. + --> + +- [Conlangs from Space](https://conlangsfrom.space/) + ([Forum page for ilo Token](https://conlangsfrom.space/t/ilo-token-a-wip-rule-based-toki-pona-to-english-translator/452)): + A forum site dedicated for all conlangs, not just Toki Pona. These are unofficial spaces and are not subject to the [Contributor Covenant Code of Conduct](https://github.com/ilo-token/ilo-token.github.io/blob/master/CODE_OF_CONDUCT.md). diff --git a/LICENSE b/LICENSE index f3dc888c..a612ad98 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,373 @@ -MIT License - -Copyright (c) 2025 neverRare - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index afb9e823..feb62696 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ After using `git clone`, you'll need [Deno](https://deno.com/) for this project. Then you'll need to install the dependencies before running any command: `deno install --frozen`. -After this, you can start away by running `deno task start` then open the link -provided by the stdout to open a local copy of ilo Token. The server will -auto-reload the webpage whenever there are changes on the code. +After this, you can start away by running `deno task start` then open +`./dist/index.html` using your favorite browser. The server will automatically +rebuild the project. However, you need to manually refresh the page. Run `deno task` to see more useful command lines. diff --git a/build/build.ts b/build/build.ts deleted file mode 100644 index 52e92110..00000000 --- a/build/build.ts +++ /dev/null @@ -1,22 +0,0 @@ -// This code is Deno only - -import * as ESBuild from "esbuild"; -import * as Dictionary from "../dictionary/build.ts"; -import { OPTIONS } from "./config.ts"; - -const BUILD_OPTIONS: ESBuild.BuildOptions = { - ...OPTIONS, - minify: true, - define: { LIVE_RELOAD: "false" }, -}; -if (import.meta.main) { - const start = performance.now(); - if (await Dictionary.build()) { - await ESBuild.build(BUILD_OPTIONS); - const end = performance.now(); - // deno-lint-ignore no-console - console.log(`Total time took: ${Math.floor(end - start)}ms`); - } else { - Deno.exitCode = 1; - } -} diff --git a/build/config.ts b/build/config.ts deleted file mode 100644 index d615e328..00000000 --- a/build/config.ts +++ /dev/null @@ -1,14 +0,0 @@ -// This code is Deno only - -import { denoPlugins } from "@luca/esbuild-deno-loader"; -import { BuildOptions } from "esbuild"; - -export const OPTIONS: BuildOptions = { - entryPoints: ["./src/main.ts"], - outfile: "./dist/main.js", - bundle: true, - sourcemap: "linked", - target: [`es${new Date().getFullYear() - 3}`], - plugins: [...denoPlugins()], - logLevel: "info", -}; diff --git a/build/dev.ts b/build/dev.ts deleted file mode 100644 index 00596955..00000000 --- a/build/dev.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This code is Deno only - -import { assert } from "@std/assert/assert"; -import { exists } from "@std/fs/exists"; -import { BuildOptions, context } from "esbuild"; -import { OPTIONS } from "./config.ts"; - -const DICTIONARY = new URL("../dictionary/dictionary.ts", import.meta.url); - -const BUILD_OPTIONS: BuildOptions = { - ...OPTIONS, - minify: false, - define: { LIVE_RELOAD: "true" }, -}; -async function watchMain(): Promise { - await using stack = new AsyncDisposableStack(); - const buildContext = stack.use({ - context: await context(BUILD_OPTIONS), - async [Symbol.asyncDispose](): Promise { - await this.context.dispose(); - }, - }); - buildContext.context.watch(); - buildContext.context.serve({ servedir: "./dist/" }); - stack.move(); - return buildContext; -} -async function watchDictionary(): Promise { - const command = new Deno.Command(Deno.execPath(), { - args: [ - "run", - "-E=NO_COLOR", - "-R=./dictionary/dictionary", - "-W=./dictionary/dictionary.ts", - "--no-prompt", - "--frozen", - "--cached-only", - "--watch", - "--no-clear-screen", - "./dictionary/watch.ts", - ], - cwd: new URL("../", import.meta.url), - stdout: "inherit", - stderr: "inherit", - stdin: "null", - }); - const process = command.spawn(); - const status = await process.status; - assert(!status.success); - return status.code; -} -if (import.meta.main) { - if (!await exists(DICTIONARY)) { - const Dictionary = await import("../dictionary/build.ts"); - if (!await Dictionary.build()) { - await Dictionary.buildWithDictionary(new Map()); - // deno-lint-ignore no-console - console.error( - "Dictionary failed to build. Empty dictionary is used instead. Please fix it.", - ); - } - } - const statusCodePromise = watchDictionary(); - await using _ = await watchMain(); - Deno.exitCode = await statusCodePromise; -} diff --git a/deno.json b/deno.json index 6789a5d3..a482c3ba 100644 --- a/deno.json +++ b/deno.json @@ -2,50 +2,58 @@ "compilerOptions": { "lib": ["dom", "deno.ns"] }, + "permissions": { + "build-dictionary": { + "env": ["NO_COLOR", "DEBUG_TAGS", "DEBUG_CHUNKS"], + "read": ["./dictionary/dictionary"], + "write": ["./dictionary/dictionary.ts"] + }, + "soft-build-dictionary": { + "env": ["NO_COLOR", "DEBUG_TAGS", "DEBUG_CHUNKS"], + "read": ["./dictionary/dictionary", "./dictionary/dictionary.ts"], + "write": ["./dictionary/dictionary.ts"] + } + }, "tasks": { "build": { "description": "Builds every static files needed for GitHub pages. This builds the dictionary first at `./dictionary/dictionary.ts` then the distribution code `./dist/main.js`.", - "command": "deno run -E -R -W -N=jsr.io --allow-run --no-prompt --frozen --cached-only ./build/build.ts" + "command": "deno bundle --output=./dist/main.js --minify --sourcemap=linked --platform=browser --format=iife ./src/main.ts", + "dependencies": ["build-dictionary"] }, "start": { - "description": "Starts a development server. The provided page will auto-reload whenever there are changes to the code.", - "command": "deno run -E -R -W -N=jsr.io --allow-run --no-prompt --frozen --cached-only ./build/dev.ts" + "description": "Starts a development server which automatically rebuilds the project whenever there are changes to the code. However, there is no server that serves frontend and you have to manually refresh the page.", + "command": "(trap 'kill 0' SIGINT; deno run --permission-set=build-dictionary --no-prompt --frozen --cached-only --watch --no-clear-screen ./dictionary/watch.ts & deno bundle --output=./dist/main.js --sourcemap=linked --platform=browser --format=iife --watch ./src/main.ts)", + "dependencies": ["soft-build-dictionary"] }, "repl": { "description": "Starts a REPL", "command": "deno run --no-prompt --frozen --cached-only ./src/repl.ts", "dependencies": ["build-dictionary"] }, - "update": { - "description": "Updates dependencies and telo misikeke", - "command": "deno outdated --update && deno run -N=gitlab.com -W=./telo_misikeke/linku_data.json,./telo_misikeke/Parser.js,./telo_misikeke/rules.js --no-prompt --frozen --cached-only ./telo_misikeke/update.ts" - }, "build-dictionary": { "description": "Builds the dictionary at `./dictionary/dictionary.ts`", - "command": "deno run -E=NO_COLOR -R=./dictionary/dictionary -W=./dictionary/dictionary.ts --no-prompt --frozen --cached-only ./dictionary/build.ts" + "command": "deno run --permission-set=build-dictionary --no-prompt --frozen --cached-only ./dictionary/build.ts" + }, + "soft-build-dictionary": { + "description": "Only builds the dictionary at `./dictionary/dictionary.ts` when it doesn't exists. When an error occurs, an empty dictionary is provided.", + "command": "deno run --permission-set=soft-build-dictionary --no-prompt --frozen --cached-only ./dictionary/soft-build.ts" } }, "fmt": { "exclude": [ "./dictionary/dictionary.ts", - "./dist/main.js", - "./telo_misikeke/linku_data.json", - "./telo_misikeke/rules.js", - "./telo_misikeke/Parser.js" + "./dist/main.js" ] }, "lint": { "exclude": [ "./dictionary/dictionary.ts", - "./dist/main.js", - "./telo_misikeke/rules.js", - "./telo_misikeke/Parser.js" + "./dist/main.js" ], "rules": { "tags": ["recommended"], "include": [ "camelcase", - "explicit-function-return-type", "explicit-module-boundary-types", "no-console", "no-boolean-literal-for-arguments", @@ -63,17 +71,16 @@ } }, "imports": { - "@luca/esbuild-deno-loader": "jsr:@luca/esbuild-deno-loader@^0.11.1", - "@std/assert": "jsr:@std/assert@^1.0.12", - "@std/async": "jsr:@std/async@^1.0.12", + "@std/assert": "jsr:@std/assert@^1.0.14", + "@std/async": "jsr:@std/async@^1.0.14", "@std/cache": "jsr:@std/cache@^0.2.0", - "@std/collections": "jsr:@std/collections@^1.0.10", - "@std/fs": "jsr:@std/fs@^1.0.16", - "@std/html": "jsr:@std/html@^1.0.3", - "@std/random": "jsr:@std/random@^0.1.0", + "@std/collections": "jsr:@std/collections@^1.1.3", + "@std/fs": "jsr:@std/fs@^1.0.19", + "@std/html": "jsr:@std/html@^1.0.4", + "@std/random": "jsr:@std/random@^0.1.2", "@std/regexp": "jsr:@std/regexp@^1.0.1", - "@std/text": "jsr:@std/text@^1.0.12", - "compromise": "npm:compromise@^14.14.3", - "esbuild": "npm:esbuild@^0.25.2" + "@std/text": "jsr:@std/text@^1.0.16", + "browser-dtector": "npm:browser-dtector@^4.1.0", + "compromise": "npm:compromise@^14.14.4" } } diff --git a/deno.lock b/deno.lock index 3e5878e1..15d0c96a 100644 --- a/deno.lock +++ b/deno.lock @@ -1,51 +1,40 @@ { - "version": "4", + "version": "5", "specifiers": { - "jsr:@luca/esbuild-deno-loader@~0.11.1": "0.11.1", - "jsr:@std/assert@^1.0.12": "1.0.12", - "jsr:@std/async@^1.0.12": "1.0.12", - "jsr:@std/bytes@^1.0.2": "1.0.5", + "jsr:@std/assert@^1.0.14": "1.0.14", + "jsr:@std/async@^1.0.14": "1.0.14", "jsr:@std/cache@0.2": "0.2.0", - "jsr:@std/collections@^1.0.10": "1.0.10", - "jsr:@std/encoding@^1.0.5": "1.0.8", + "jsr:@std/collections@^1.1.3": "1.1.3", "jsr:@std/encoding@^1.0.7": "1.0.8", - "jsr:@std/fs@^1.0.16": "1.0.16", - "jsr:@std/html@^1.0.3": "1.0.3", - "jsr:@std/internal@^1.0.6": "1.0.6", - "jsr:@std/path@^1.0.6": "1.0.8", + "jsr:@std/fs@^1.0.19": "1.0.19", + "jsr:@std/html@^1.0.4": "1.0.4", + "jsr:@std/internal@^1.0.10": "1.0.10", + "jsr:@std/internal@^1.0.9": "1.0.10", "jsr:@std/path@^1.0.8": "1.0.8", - "jsr:@std/random@0.1": "0.1.0", + "jsr:@std/path@^1.0.9": "1.0.9", + "jsr:@std/path@^1.1.1": "1.1.2", + "jsr:@std/random@~0.1.2": "0.1.2", "jsr:@std/regexp@^1.0.1": "1.0.1", - "jsr:@std/text@^1.0.12": "1.0.12", - "npm:compromise@^14.14.3": "14.14.4", - "npm:esbuild@~0.25.2": "0.25.2" + "jsr:@std/text@^1.0.16": "1.0.16", + "npm:@types/node@*": "22.15.15", + "npm:browser-dtector@^4.1.0": "4.1.0", + "npm:compromise@^14.14.4": "14.14.4" }, "jsr": { - "@luca/esbuild-deno-loader@0.11.1": { - "integrity": "dc020d16d75b591f679f6b9288b10f38bdb4f24345edb2f5732affa1d9885267", + "@std/assert@1.0.14": { + "integrity": "68d0d4a43b365abc927f45a9b85c639ea18a9fab96ad92281e493e4ed84abaa4", "dependencies": [ - "jsr:@std/bytes", - "jsr:@std/encoding@^1.0.5", - "jsr:@std/path@^1.0.6" + "jsr:@std/internal@^1.0.10" ] }, - "@std/assert@1.0.12": { - "integrity": "08009f0926dda9cbd8bef3a35d3b6a4b964b0ab5c3e140a4e0351fbf34af5b9a", - "dependencies": [ - "jsr:@std/internal" - ] - }, - "@std/async@1.0.12": { - "integrity": "d1bfcec459e8012846fe4e38dfc4241ab23240ecda3d8d6dfcf6d81a632e803d" - }, - "@std/bytes@1.0.5": { - "integrity": "4465dd739d7963d964c809202ebea6d5c6b8e3829ef25c6a224290fbb8a1021e" + "@std/async@1.0.14": { + "integrity": "62e954a418652c704d37563a3e54a37d4cf0268a9dcaeac1660cc652880b5326" }, "@std/cache@0.2.0": { "integrity": "63a2ccd5a9e7c03e430f7d34dfcfd0d0cfc90731a1eaf8208f4c66e418fc3035" }, - "@std/collections@1.0.10": { - "integrity": "903af106a3d92970d74e20f7ebff77d9658af9bef4403f1dc42a7801c0575899" + "@std/collections@1.1.3": { + "integrity": "bf8b0818886df6a32b64c7d3b037a425111f28278d69fd0995aeb62777c986b0" }, "@std/encoding@1.0.7": { "integrity": "f631247c1698fef289f2de9e2a33d571e46133b38d042905e3eac3715030a82d" @@ -53,106 +42,303 @@ "@std/encoding@1.0.8": { "integrity": "a6c8f3f933ab1bed66244f435d1dc0fd23a888e07195532122ddc3d5f8f0e6b4" }, - "@std/fs@1.0.16": { - "integrity": "81878f62b6eeda0bf546197fc3daa5327c132fee1273f6113f940784a468b036", + "@std/fs@1.0.19": { + "integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06", "dependencies": [ - "jsr:@std/path@^1.0.8" + "jsr:@std/internal@^1.0.9", + "jsr:@std/path@^1.1.1" ] }, - "@std/html@1.0.3": { - "integrity": "7a0ac35e050431fb49d44e61c8b8aac1ebd55937e0dc9ec6409aa4bab39a7988" + "@std/html@1.0.4": { + "integrity": "eff3497c08164e6ada49b7f81a28b5108087033823153d065e3f89467dd3d50e" }, - "@std/internal@1.0.6": { - "integrity": "9533b128f230f73bd209408bb07a4b12f8d4255ab2a4d22a1fd6d87304aca9a4" + "@std/internal@1.0.10": { + "integrity": "e3be62ce42cab0e177c27698e5d9800122f67b766a0bea6ca4867886cbde8cf7" }, "@std/path@1.0.8": { "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" }, - "@std/random@0.1.0": { - "integrity": "70a006be0ffb77d036bab54aa8ae6bd0119ba77ace0f2f56f63273d4262a5667" + "@std/path@1.0.9": { + "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" + }, + "@std/path@1.1.2": { + "integrity": "c0b13b97dfe06546d5e16bf3966b1cadf92e1cc83e56ba5476ad8b498d9e3038", + "dependencies": [ + "jsr:@std/internal@^1.0.10" + ] + }, + "@std/random@0.1.2": { + "integrity": "21e28f39dcc72d522bb0d2bc13586567d6044c86ee77a0056fcde0e13758c3ee" }, "@std/regexp@1.0.1": { "integrity": "5179d823465085c5480dafb44438466e83c424fadc61ba31f744050ecc0f596d" }, - "@std/text@1.0.12": { - "integrity": "921132a41e03a2363f76ee5afe83c90a6271596aa95c137494edcb3404a564a5" + "@std/text@1.0.16": { + "integrity": "ddb9853b75119a2473857d691cf1ec02ad90793a2e8b4a4ac49d7354281a0cf8", + "dependencies": [ + "jsr:@std/regexp" + ] } }, "npm": { - "@esbuild/aix-ppc64@0.25.2": { - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==" - }, - "@esbuild/android-arm64@0.25.2": { - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==" - }, - "@esbuild/android-arm@0.25.2": { - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==" - }, - "@esbuild/android-x64@0.25.2": { - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==" - }, - "@esbuild/darwin-arm64@0.25.2": { - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==" - }, - "@esbuild/darwin-x64@0.25.2": { - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==" - }, - "@esbuild/freebsd-arm64@0.25.2": { - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==" - }, - "@esbuild/freebsd-x64@0.25.2": { - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==" - }, - "@esbuild/linux-arm64@0.25.2": { - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==" - }, - "@esbuild/linux-arm@0.25.2": { - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==" - }, - "@esbuild/linux-ia32@0.25.2": { - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==" - }, - "@esbuild/linux-loong64@0.25.2": { - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==" - }, - "@esbuild/linux-mips64el@0.25.2": { - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==" - }, - "@esbuild/linux-ppc64@0.25.2": { - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==" - }, - "@esbuild/linux-riscv64@0.25.2": { - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==" - }, - "@esbuild/linux-s390x@0.25.2": { - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==" - }, - "@esbuild/linux-x64@0.25.2": { - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==" - }, - "@esbuild/netbsd-arm64@0.25.2": { - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==" - }, - "@esbuild/netbsd-x64@0.25.2": { - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==" - }, - "@esbuild/openbsd-arm64@0.25.2": { - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==" - }, - "@esbuild/openbsd-x64@0.25.2": { - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==" - }, - "@esbuild/sunos-x64@0.25.2": { - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==" - }, - "@esbuild/win32-arm64@0.25.2": { - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==" - }, - "@esbuild/win32-ia32@0.25.2": { - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==" + "@esbuild/aix-ppc64@0.25.3": { + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/aix-ppc64@0.25.4": { + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/android-arm64@0.25.3": { + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm64@0.25.4": { + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm@0.25.3": { + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-arm@0.25.4": { + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-x64@0.25.3": { + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/android-x64@0.25.4": { + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/darwin-arm64@0.25.3": { + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-arm64@0.25.4": { + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-x64@0.25.3": { + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/darwin-x64@0.25.4": { + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-arm64@0.25.3": { + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-arm64@0.25.4": { + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-x64@0.25.3": { + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-x64@0.25.4": { + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/linux-arm64@0.25.3": { + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm64@0.25.4": { + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm@0.25.3": { + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-arm@0.25.4": { + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-ia32@0.25.3": { + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-ia32@0.25.4": { + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-loong64@0.25.3": { + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-loong64@0.25.4": { + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-mips64el@0.25.3": { + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-mips64el@0.25.4": { + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-ppc64@0.25.3": { + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-ppc64@0.25.4": { + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-riscv64@0.25.3": { + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-riscv64@0.25.4": { + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-s390x@0.25.3": { + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-s390x@0.25.4": { + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-x64@0.25.3": { + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/linux-x64@0.25.4": { + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.25.3": { + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-arm64@0.25.4": { + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-x64@0.25.3": { + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-x64@0.25.4": { + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.25.3": { + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-arm64@0.25.4": { + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-x64@0.25.3": { + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-x64@0.25.4": { + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/sunos-x64@0.25.3": { + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/sunos-x64@0.25.4": { + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/win32-arm64@0.25.3": { + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-arm64@0.25.4": { + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-ia32@0.25.3": { + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-ia32@0.25.4": { + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-x64@0.25.3": { + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@esbuild/win32-x64@0.25.4": { + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@types/node@22.15.15": { + "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", + "dependencies": [ + "undici-types" + ] }, - "@esbuild/win32-x64@0.25.2": { - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==" + "browser-dtector@4.1.0": { + "integrity": "sha512-ZnLAE4aknz8f7UWJ9/QJ9rNlHjBi59aVu6a73WGnUUAIXak6+2AbY/I1fnRPJhuqn94Lce63u9ecKNP+D9f71w==" }, "compromise@14.14.4": { "integrity": "sha512-QdbJwronwxeqb7a5KFK/+Y5YieZ4PE1f7ai0vU58Pp4jih+soDCBMuKVbhDEPQ+6+vI3vSiG4UAAjTAXLJw1Qw==", @@ -165,57 +351,29 @@ "efrt@2.7.0": { "integrity": "sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==" }, - "esbuild@0.25.2": { - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "dependencies": [ - "@esbuild/aix-ppc64", - "@esbuild/android-arm", - "@esbuild/android-arm64", - "@esbuild/android-x64", - "@esbuild/darwin-arm64", - "@esbuild/darwin-x64", - "@esbuild/freebsd-arm64", - "@esbuild/freebsd-x64", - "@esbuild/linux-arm", - "@esbuild/linux-arm64", - "@esbuild/linux-ia32", - "@esbuild/linux-loong64", - "@esbuild/linux-mips64el", - "@esbuild/linux-ppc64", - "@esbuild/linux-riscv64", - "@esbuild/linux-s390x", - "@esbuild/linux-x64", - "@esbuild/netbsd-arm64", - "@esbuild/netbsd-x64", - "@esbuild/openbsd-arm64", - "@esbuild/openbsd-x64", - "@esbuild/sunos-x64", - "@esbuild/win32-arm64", - "@esbuild/win32-ia32", - "@esbuild/win32-x64" - ] - }, "grad-school@0.0.5": { "integrity": "sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==" }, "suffix-thumb@5.0.2": { "integrity": "sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==" + }, + "undici-types@6.21.0": { + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" } }, "workspace": { "dependencies": [ - "jsr:@luca/esbuild-deno-loader@~0.11.1", - "jsr:@std/assert@^1.0.12", - "jsr:@std/async@^1.0.12", + "jsr:@std/assert@^1.0.14", + "jsr:@std/async@^1.0.14", "jsr:@std/cache@0.2", - "jsr:@std/collections@^1.0.10", - "jsr:@std/fs@^1.0.16", - "jsr:@std/html@^1.0.3", - "jsr:@std/random@0.1", + "jsr:@std/collections@^1.1.3", + "jsr:@std/fs@^1.0.19", + "jsr:@std/html@^1.0.4", + "jsr:@std/random@~0.1.2", "jsr:@std/regexp@^1.0.1", - "jsr:@std/text@^1.0.12", - "npm:compromise@^14.14.3", - "npm:esbuild@~0.25.2" + "jsr:@std/text@^1.0.16", + "npm:browser-dtector@^4.1.0", + "npm:compromise@^14.14.4" ] } } diff --git a/dictionary/build.ts b/dictionary/build.ts index 22e9ce4b..13c117aa 100644 --- a/dictionary/build.ts +++ b/dictionary/build.ts @@ -1,8 +1,8 @@ -// This code is Deno only +// this code is Deno only // deno-lint-ignore-file no-console -import { ArrayResultError } from "../src/array_result.ts"; +import { ResultError } from "../src/compound.ts"; import { PositionedError } from "../src/parser/parser_lib.ts"; import { dictionaryParser } from "./parser.ts"; import { Dictionary } from "./type.ts"; @@ -19,11 +19,13 @@ export async function buildWithDictionary( 2, ); const code = `\ -// This code is autogenerated +// this code is autogenerated -import { Dictionary } from "./type.ts"; +import { Dictionary, Entry } from "./type.ts"; + +const json: Record = ${json}; -export const dictionary: Dictionary = new Map(Object.entries(${json})); +export const dictionary: Dictionary = new Map(Object.entries(json)); `; await Deno.writeTextFile(DESTINATION, code); } @@ -36,7 +38,7 @@ export async function build(): Promise { const endDictionary = performance.now(); let dictionary: Dictionary; if (!result.isError()) { - dictionary = result.array[0]; + dictionary = result.unwrap()[0]; } else { displayError(text, result.errors); return false; @@ -50,13 +52,11 @@ export async function build(): Promise { ); return true; } -function displayError( - source: string, - errors: ReadonlyArray, -): void { +function displayError(source: string, errors: ReadonlyArray) { let color: boolean; try { - color = Deno.env.get("NO_COLOR") !== "1"; + const noColor = Deno.env.get("NO_COLOR"); + color = noColor == null || noColor === ""; } catch (error) { if (error instanceof Deno.errors.NotCapable) { color = true; @@ -69,9 +69,9 @@ function displayError( for (const error of errors) { console.error(`%cError%c: ${error.message}`, red, ""); if (error instanceof PositionedError && error.position != null) { - const { position, length } = error.position; + const { position: { position, length } } = error; const end = position + length; - // The only instance returning -1 is useful + // the only instance returning -1 is useful const startLine = source.lastIndexOf("\n", position) + 1; let currentLine = startLine; let currentPosition = position; diff --git a/dictionary/dictionary b/dictionary/dictionary index 5494703d..5b0a3c6b 100644 --- a/dictionary/dictionary +++ b/dictionary/dictionary @@ -1,5 +1,17 @@ +# Read the guidelines for editing: # https://github.com/ilo-token/ilo-token.github.io/wiki/Guidelines-for-editing-dictionary +# The dictionary is licensed under: +# Creative Commons Attribution-ShareAlike 4.0 International +# https://creativecommons.org/licenses/by-sa/4.0/ + +# Many definitions are adapted from Linku (https://linku.la). +# sona Linku is dual-licensed under: +# - Creative Commons Attribution-ShareAlike 3.0 Unported +# https://github.com/lipu-linku/sona/blob/main/LICENSE.CC-BY-SA-3.0 +# - Creative Commons Attribution-ShareAlike 4.0 International +# https://github.com/lipu-linku/sona/blob/main/LICENSE.CC-BY-SA-4.0 + a: ah/aah/aaah(f); # oh/ohh/ohhh(f); @@ -21,14 +33,19 @@ akesi: ala: not(d negative); - not(adv); + not(adv negative); nothing(n plural); + none(n plural); no(d quantifier plural); `[`negates a word or phrase`]`(particle def); `[`forms a yes-no question`]`(particle def); - 0(num); + # 0(num); + # While technically true, this just floods the output. ilo Token + # prioritizes numerals at the moment which is bad because normal + # negation are more interesting. Thanks soweli Eweke for pointing this + # out! alasa: # hunt(v) [object]; @@ -83,13 +100,6 @@ anu: (particle def); or(particle def); - # # These are no longer in Linku - # choose(v) [object]; - # decide(v); - - # choosing(n gerund); - # deciding(n gerund); - awen: # stay(v); remain(v linking) [predicate]; @@ -120,6 +130,11 @@ awen: e: `[`marks the start of a direct object`]`(particle def); +eliki: + trial(n); + adversity(n); + bittersweet(adj opinion); + en: `[`separates multiple subjects`]`(particle def); @@ -330,6 +345,8 @@ ken: enable(v) [object]; kepeken: + use(v) [object]; + using(prep) [indirect object]; by means of(prep) [indirect object]; @@ -371,12 +388,16 @@ kipisi: cut(v) [object]; # slice(v) [object]; - piece(n) of(prep) [headword]; - part(n) of(prep) [headword]; + piece(n); + part(n); sharp(adj physical quality); pointy(adj physical quality); + # splitting(n gerund); + cutting(n gerund); + # slicing(n gerund); + kiwen: hard(adj material) object(n); # metal(n); @@ -1237,6 +1258,7 @@ pona: positive(adj opinion) quality(n); nicely(adv); + # TODO: well(adv); # Implement this when ilo Token can add adverbs after the verbs or adjectives pu: interact(v) with(prep) the(d article) book(n singular) titled(adj) @@ -1588,6 +1610,14 @@ tu: divide(v) [object]; split(v) [object]; + separating(n gerund); + dividing(n gerund); + splitting(n gerund); + + separated(adj opinion); + divided(adj opinion); + split(adj opinion); + unpa: sexual(adj qualifier) activity(n); have(v) sex(n singular) with(prep) [object]; diff --git a/dictionary/parser.ts b/dictionary/parser.ts index 10e13ee9..9263d0b4 100644 --- a/dictionary/parser.ts +++ b/dictionary/parser.ts @@ -24,7 +24,19 @@ import { withPosition, withSource, } from "../src/parser/parser_lib.ts"; -import { Definition, Noun, PartialVerb } from "./type.ts"; +import { + Adjective, + AdjectiveName, + Adverb, + Definition, + Determiner, + Dictionary, + Entry, + IndirectObject, + Noun, + NounForms, + VerbAccessory, +} from "./type.ts"; const RESERVED_SYMBOLS = "#()*+/:;<=>@[\\]^`{|}~"; @@ -51,7 +63,7 @@ const ignore = allWithCheck( choiceWithCheck(spaces, comment), ), ); -function lex(parser: Parser): Parser { +function lex(parser: Parser) { return parser.skip(ignore); } const wordWithPosition = lex( @@ -100,10 +112,10 @@ const perspective = choiceOnlyOne( keyword("second"), keyword("third"), ); -function tag(parser: Parser): Parser { +function tag(parser: Parser) { return openParenthesis.with(parser).skip(closeParenthesis); } -function template(parser: Parser): Parser { +function template(parser: Parser) { return openBracket.with(parser).skip(closeBracket); } const simpleUnit = memoize((kind: string) => word.skip(tag(keyword(kind)))); @@ -120,60 +132,64 @@ const nounOnly = checkedSequence( sequence(optionalAll(keyword("gerund")), optionalNumber) .skip(closeParenthesis), ) - .mapWithPositionedError(([[noun, plural], [gerund, number]]) => { - if (plural == null) { - if (number == null) { - const sentence = nlp(noun); - sentence.tag("Noun"); - const singular = sentence - .nouns() - .toSingular() - .text(); - const plural = sentence - .nouns() - .toPlural() - .text(); - if (singular === "" || plural === "") { - throw `no singular or plural form found for "${noun}". consider ` + - "providing both singular and plural forms instead"; + .mapWithPositionedError( + ( + [[noun, plural], [gerund, number]], + ): NounForms & Readonly<{ gerund: boolean }> => { + if (plural == null) { + if (number == null) { + const sentence = nlp(noun); + sentence.tag("Noun"); + const singular = sentence + .nouns() + .toSingular() + .text(); + const plural = sentence + .nouns() + .toPlural() + .text(); + if (singular === "" || plural === "") { + throw `no singular or plural form found for "${noun}". consider ` + + "providing both singular and plural forms instead"; + } + if (noun !== singular) { + throw `declension error: "${noun}" is not "${singular}". ` + + "consider providing both singular and plural forms instead"; + } + return { + singular: escapeHtml(singular), + plural: escapeHtml(plural), + gerund: gerund != null, + }; + } else { + const escaped = escapeHtml(noun); + let singular: null | string; + let plural: null | string; + switch (number) { + case "singular": + singular = escaped; + plural = null; + break; + case "plural": + singular = null; + plural = escaped; + break; + } + return { singular, plural, gerund: gerund != null }; } - if (noun !== singular) { - throw `conjugation error: "${noun}" is not "${singular}". ` + - "consider providing both singular and plural forms instead"; + } else { + if (number != null) { + throw "plural or singular keyword within tag " + + "must not be provided when singular and plural forms are defined"; } return { - singular: escapeHtml(singular), - plural: escapeHtml(plural), + singular: escapeHtml(noun), + plural, gerund: gerund != null, }; - } else { - const escaped = escapeHtml(noun); - let singular: null | string; - let plural: null | string; - switch (number) { - case "singular": - singular = escaped; - plural = null; - break; - case "plural": - singular = null; - plural = escaped; - break; - } - return { singular, plural, gerund: gerund != null }; } - } else { - if (number != null) { - throw "plural or singular keyword within tag " + - "must not be provided when singular and plural forms are defined"; - } - return { - singular: escapeHtml(noun), - plural, - gerund: gerund != null, - }; - } - }); + }, + ); const determinerType = choiceOnlyOne( keyword("article"), keyword("demonstrative"), @@ -193,14 +209,12 @@ const determiner = checkedSequence( ), sequence(determinerType, optionalNumber.skip(closeParenthesis)), ) - .map(([[determiner, plural], [kind, quantity]]) => - ({ - determiner, - plural, - kind, - quantity: quantity ?? "both", - }) as const - ); + .map(([[determiner, plural], [kind, quantity]]): Determiner => ({ + determiner, + plural, + kind, + quantity: quantity ?? "both", + })); const adjectiveKind = choiceWithCheck( checkedSequence(keyword("physical"), keyword("quality")) .map(() => "physical quality" as const), @@ -216,9 +230,17 @@ const adjectiveKind = choiceWithCheck( ), ), ); +const adverb = checkedSequence( + word.skip(openParenthesis).skip(keyword("adv")), + optionalAll(keyword("negative")).skip(closeParenthesis), +) + .map(([adverb, negative]): Adverb => ({ + adverb, + negative: negative != null, + })); const adjective = checkedSequence( sequence( - all(simpleUnit("adv")), + allWithCheck(adverb), word.skip(openParenthesis).skip(keyword("adj")), ), sequence( @@ -226,8 +248,8 @@ const adjective = checkedSequence( optionalAll(keyword("gerund-like")).skip(closeParenthesis), ), ) - .map(([[adverb, adjective], [kind, gerundLike]]) => ({ - adverb, + .map(([[adverbs, adjective], [kind, gerundLike]]): Adjective => ({ + adverbs, adjective, kind, gerundLike: gerundLike != null, @@ -241,17 +263,15 @@ const noun = sequence( simpleUnit("adj"), word.skip(tag(sequence(keyword("n"), keyword("proper")))), ) - .map(([adjective, name]) => ({ adjective, name })), + .map(([adjective, name]): AdjectiveName => ({ adjective, name })), ), ) - .map(([determiner, adjective, noun, postAdjective]) => - ({ - ...noun, - determiner, - adjective, - postAdjective, - }) as const - ); + .map(([determiners, adjectives, noun, adjectiveName]): Noun => ({ + ...noun, + determiners, + adjectives, + adjectiveName, + })); const checkedNoun = new CheckedParser( choiceOnlyOne( determiner.check, @@ -260,48 +280,44 @@ const checkedNoun = new CheckedParser( ), noun, ); -function checkedSimpleUnitWith( - tag: string, - after: Parser, -): CheckedParser { +function checkedSimpleUnitWith(tag: string, after: Parser) { return checkedSequence( word.skip(openParenthesis).skip(keyword(tag)), closeParenthesis.with(after), ); } -function checkedSimpleUnit(tag: string): CheckedParser { +function checkedSimpleUnit(tag: string) { return checkedSimpleUnitWith(tag, nothing).map(([word]) => word); } function checkedSimpleUnitWithTemplate( tag: string, templateInside: Parser, -): CheckedParser { +) { return checkedSimpleUnitWith(tag, template(templateInside)) .map(([word]) => word); } const interjectionDefinition = checkedSimpleUnit("i") - .map((interjection) => ({ type: "interjection", interjection }) as const); + .map((interjection): Definition => ({ type: "interjection", interjection })); const particleDefinition = checkedSequence( word.skip(openParenthesis).skip(keyword("particle")), sequence(keyword("def"), closeParenthesis), ) - .map(([definition]) => - ({ type: "particle definition", definition }) as const - ); -const adverbDefinition = checkedSimpleUnit("adv") - .map((adverb) => ({ type: "adverb", adverb }) as const); + .map(([definition]): Definition => ({ + type: "particle definition", + definition, + })); const prepositionDefinition = checkedSimpleUnitWithTemplate( "prep", sequence(keyword("indirect"), keyword("object")), ) - .map((preposition) => ({ type: "preposition", preposition }) as const); + .map((preposition): Definition => ({ type: "preposition", preposition })); const numeralDefinition = checkedSimpleUnit("num") - .mapWithPositionedError((num) => { + .mapWithPositionedError((num): Definition => { const numeral = +num; - if (!Number.isInteger(numeral)) { - throw `"${num}" is not a number`; + if (!Number.isInteger(numeral) || numeral < 0) { + throw `"${num}" is not a non-negative integer`; } else { - return { type: "numeral", numeral } as const; + return { type: "numeral", numeral }; } }); const fillerDefinition = checkedSequence( @@ -316,14 +332,14 @@ const fillerDefinition = checkedSequence( .map(([first, rest]) => [first, ...rest]), closeParenthesis, ) - .mapWithPositionedError(([forms]) => { + .mapWithPositionedError(([forms]): Definition => { if (forms.length === 1) { return { type: "filler", before: forms[0], repeat: "", after: "", - } as const; + }; } const [first, ...rest] = forms; for (let i = 0; i < first.length; i++) { @@ -335,7 +351,7 @@ const fillerDefinition = checkedSequence( test === `${before}${repeatString.repeat(i + 2)}${after}` ); if (passed) { - return { type: "filler", before, repeat: repeatString, after } as const; + return { type: "filler", before, repeat: repeatString, after }; } } throw `"${forms.join("/")}" has no repetition pattern found`; @@ -352,14 +368,12 @@ const fourFormPersonalPronounDefinition = checkedSequence( .map(([ [singularSubject, singularObject, pluralSubject, pluralObject], perspective, - ]) => - ({ - type: "personal pronoun", - singular: { subject: singularSubject, object: singularObject }, - plural: { subject: pluralSubject, object: pluralObject }, - perspective, - }) as const - ); + ]): Definition => ({ + type: "personal pronoun", + singular: { subject: singularSubject, object: singularObject }, + plural: { subject: pluralSubject, object: pluralObject }, + perspective, + })); const twoFormPersonalPronounDefinition = checkedSequence( sequence( word.skip(slash), @@ -370,15 +384,13 @@ const twoFormPersonalPronounDefinition = checkedSequence( number.skip(closeParenthesis), ), ) - .map(([[subject, object], [perspective, number]]) => - ({ - type: "personal pronoun", - singular: null, - plural: null, - [number]: { subject, object }, - perspective, - }) as const - ); + .map(([[subject, object], [perspective, number]]): Definition => ({ + type: "personal pronoun", + singular: null, + plural: null, + [number]: { subject, object }, + perspective, + })); const nounDefinition = new CheckedParser( choiceWithCheck( new CheckedParser( @@ -404,10 +416,10 @@ const nounDefinition = new CheckedParser( ), ), ) - .map(([noun, preposition]) => + .map(([noun, preposition]): Definition => preposition == null - ? { ...noun, type: "noun" } as const - : { type: "noun preposition", noun, preposition } as const + ? { ...noun, type: "noun" } + : { type: "noun preposition", noun, preposition } ); const compoundAdjectiveDefinition = checkedSequence( adjective @@ -417,10 +429,13 @@ const compoundAdjectiveDefinition = checkedSequence( .skip(keyword("c")), closeParenthesis.with(adjective.parser), ) - .map((adjective) => ({ type: "compound adjective", adjective }) as const) - .filterWithPositionedError(({ adjective }) => - adjective.every((adjective) => adjective.adverb.length === 0) || - throwError("compound adjective cannot have adverb") + .map((adjectives): Definition & { type: "compound adjective" } => ({ + type: "compound adjective", + adjectives, + })) + .filterWithPositionedError(({ adjectives }) => + adjectives.every(({ adverbs: { length } }) => length === 0) || + throwError("compound adjective cannot have adverbs") ); const verbDefinition = checkedSequence( sequence( @@ -431,19 +446,22 @@ const verbDefinition = checkedSequence( ) .skip(sequence(openParenthesis, keyword("v"))), ), - choiceWithCheck( + choiceWithCheck( checkedSequence( sequence(closeParenthesis, openBracket, keyword("object")), closeBracket .with(optionalWithCheck( checkedSimpleUnitWith("prep", noun) - .map(([preposition, object]) => ({ preposition, object }) as const), + .map(([preposition, object]): IndirectObject => ({ + preposition, + object, + })), )) .map(nullableAsArray), ) - .map(([_, indirectObject]) => ({ + .map(([_, indirectObjects]): null | VerbAccessory => ({ directObject: null, - indirectObject, + indirectObjects, forObject: true, predicateType: null, })), @@ -451,9 +469,9 @@ const verbDefinition = checkedSequence( sequence(closeParenthesis, openBracket, keyword("predicate")), closeBracket, ) - .map(() => ({ + .map((): null | VerbAccessory => ({ directObject: null, - indirectObject: [], + indirectObjects: [], forObject: false, predicateType: "verb", })), @@ -461,14 +479,14 @@ const verbDefinition = checkedSequence( keyword("modal"), sequence(closeParenthesis, template(keyword("predicate"))), ) - .map(() => null), + .map((): null | VerbAccessory => null), checkedSequence( keyword("linking"), sequence(closeParenthesis, template(keyword("predicate"))), ) - .map(() => ({ + .map((): null | VerbAccessory => ({ directObject: null, - indirectObject: [], + indirectObjects: [], forObject: false, predicateType: "noun adjective", })), @@ -484,18 +502,18 @@ const verbDefinition = checkedSequence( openBracket, sequence(keyword("object"), closeBracket), ) - .map(() => "template" as const), + .map(() => "template"), checkedNoun, ), ), ), ), ) - .map(([_, [directObject, rawIndirectObject]]) => { + .map(([_, [directObject, rawIndirectObject]]): VerbAccessory => { if (rawIndirectObject == null) { return { directObject, - indirectObject: [], + indirectObjects: [], forObject: false, predicateType: null, }; @@ -504,14 +522,14 @@ const verbDefinition = checkedSequence( if (indirectObject === "template") { return { directObject, - indirectObject: [], + indirectObjects: [], forObject: preposition, predicateType: null, }; } else { return { directObject, - indirectObject: [{ + indirectObjects: [{ preposition, object: indirectObject, }], @@ -523,7 +541,7 @@ const verbDefinition = checkedSequence( }), ), ) - .mapWithPositionedError(([[verb, forms], rest]) => { + .mapWithPositionedError(([[verb, forms], rest]): Definition => { if (rest == null) { if (forms != null) { throw "modal verbs shouldn't be conjugated"; @@ -562,18 +580,24 @@ const verbDefinition = checkedSequence( return { ...rest, type: "verb", presentPlural, presentSingular, past }; } }); -const definition = choiceWithCheck( +const definition = choiceWithCheck( // noun parser must come before adjective, compound adjective, and determiner parsers nounDefinition, // compound adjective parser must come before adjective parser compoundAdjectiveDefinition, // adjective parser must come before adverb parser - adjective.map((adjective) => ({ ...adjective, type: "adjective" })), + adjective.map((adjective): Definition => ({ + ...adjective, + type: "adjective", + })), verbDefinition, - adverbDefinition, + adverb.map((adverb): Definition => ({ ...adverb, type: "adverb" })), interjectionDefinition, particleDefinition, - determiner.map((determiner) => ({ ...determiner, type: "determiner" })), + determiner.map((determiner): Definition => ({ + ...determiner, + type: "determiner", + })), prepositionDefinition, numeralDefinition, fillerDefinition, @@ -596,8 +620,11 @@ const entry = withSource( ), ), ) - .map(([definitions, source]) => ({ definitions, source: source.trimEnd() })); -export const dictionaryParser = ignore + .map(([definitions, source]): Entry => ({ + definitions, + source: source.trimEnd(), + })); +export const dictionaryParser: Parser = ignore .with( allWithCheck(new CheckedParser(notEnd, sequence(positionedHead, entry))), ) diff --git a/dictionary/soft-build.ts b/dictionary/soft-build.ts new file mode 100644 index 00000000..8f2e0c55 --- /dev/null +++ b/dictionary/soft-build.ts @@ -0,0 +1,16 @@ +// this code is Deno only + +import { exists } from "@std/fs/exists"; + +if (import.meta.main) { + if (!await exists(new URL("./dictionary.ts", import.meta.url))) { + const Dictionary = await import("../dictionary/build.ts"); + if (!await Dictionary.build()) { + await Dictionary.buildWithDictionary(new Map()); + // deno-lint-ignore no-console + console.error( + "Dictionary failed to build. Empty dictionary is used instead. Please fix it.", + ); + } + } +} diff --git a/dictionary/test.ts b/dictionary/test.ts index aa62624c..8931a71d 100644 --- a/dictionary/test.ts +++ b/dictionary/test.ts @@ -1,4 +1,4 @@ -// This code is Deno only +// this code is Deno only import { assertMatch } from "@std/assert/match"; import { dictionary } from "./dictionary.ts"; diff --git a/dictionary/type.ts b/dictionary/type.ts index e9be88e1..7b13ca3f 100644 --- a/dictionary/type.ts +++ b/dictionary/type.ts @@ -2,18 +2,17 @@ export type NounForms = Readonly<{ singular: null | string; plural: null | string; }>; +export type AdjectiveName = Readonly<{ + adjective: string; + name: string; +}>; export type Noun = & NounForms & Readonly<{ - determiner: ReadonlyArray; - adjective: ReadonlyArray; + determiners: ReadonlyArray; + adjectives: ReadonlyArray; gerund: boolean; - postAdjective: - | null - | Readonly<{ - adjective: string; - name: string; - }>; + adjectiveName: null | AdjectiveName; }>; export type PronounForms = Readonly<{ singular: null | Readonly<{ subject: string; object: string }>; @@ -46,8 +45,12 @@ export type AdjectiveType = | "origin" | "material" | "qualifier"; +export type Adverb = Readonly<{ + adverb: string; + negative: boolean; +}>; export type Adjective = Readonly<{ - adverb: ReadonlyArray; + adverbs: ReadonlyArray; adjective: string; kind: AdjectiveType; gerundLike: boolean; @@ -57,18 +60,17 @@ export type VerbForms = Readonly<{ presentSingular: string; past: string; }>; -export type PartialVerb = Readonly<{ +export type IndirectObject = Readonly<{ + preposition: string; + object: Noun; +}>; +export type VerbAccessory = Readonly<{ directObject: null | Noun; - indirectObject: ReadonlyArray< - Readonly<{ - preposition: string; - object: Noun; - }> - >; + indirectObjects: ReadonlyArray; forObject: boolean | string; predicateType: null | "verb" | "noun adjective"; }>; -export type Verb = VerbForms & PartialVerb; +export type Verb = VerbForms & VerbAccessory; export type Definition = | Readonly<{ type: "filler"; before: string; repeat: string; after: string }> | Readonly<{ type: "particle definition"; definition: string }> @@ -84,9 +86,9 @@ export type Definition = | (Readonly<{ type: "adjective" }> & Adjective) | Readonly<{ type: "compound adjective"; - adjective: ReadonlyArray; + adjectives: ReadonlyArray; }> - | Readonly<{ type: "adverb"; adverb: string }> + | (Readonly<{ type: "adverb" }> & Adverb) | (Readonly<{ type: "verb" }> & Verb) | Readonly<{ type: "modal verb"; verb: string }> | Readonly<{ type: "preposition"; preposition: string }> diff --git a/dictionary/watch.ts b/dictionary/watch.ts index ab5f633b..4abdef02 100644 --- a/dictionary/watch.ts +++ b/dictionary/watch.ts @@ -1,4 +1,4 @@ -// This code is Deno only +// this code is Deno only import { unreachable } from "@std/assert/unreachable"; import { debounce } from "@std/async/debounce"; diff --git a/dist/index.html b/dist/index.html index 82176283..b6770b65 100644 --- a/dist/index.html +++ b/dist/index.html @@ -29,62 +29,70 @@ -

ilo Token

-

- ⚠ WARNING: Work in progress; Some things may not work - properly. -

-

- An open-source rule-based Toki Pona to English translator. - Limitations. -

-

- - -

- -
- -
- -
    -

    -
      -
      - Provide feedback - -
      +
      +

      ilo Token

      +
      +
      +

      + ⚠ WARNING: Work in progress; Some things may not work + properly. +

      +

      + An open-source rule-based Toki Pona to English translator. + Limitations. +

      +

      + + +

      + +
      + +
      + +
        +

        +
          +

          + +

          +