{"id":21515555,"url":"https://github.com/dxrcy/phonet","last_synced_at":"2025-03-17T16:17:07.793Z","repository":{"id":69458481,"uuid":"603586593","full_name":"dxrcy/phonet","owner":"dxrcy","description":"A CLI tool and library to validate phonotactic patterns for constructed languages ","archived":false,"fork":false,"pushed_at":"2024-02-02T03:53:57.000Z","size":349,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-15T08:37:17.220Z","etag":null,"topics":["conlang","language","phonetics"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dxrcy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-02-19T00:36:44.000Z","updated_at":"2023-12-02T02:23:06.000Z","dependencies_parsed_at":"2024-03-02T03:43:00.072Z","dependency_job_id":"74b1e69e-60d9-470a-85c2-14aca15619e7","html_url":"https://github.com/dxrcy/phonet","commit_stats":{"total_commits":87,"total_committers":2,"mean_commits":43.5,"dds":"0.011494252873563204","last_synced_commit":"83dd19d27f47ae39553b39f2d2994e65cda06160"},"previous_names":["dxrcy/phonet","darccyy/phonet"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dxrcy%2Fphonet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dxrcy%2Fphonet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dxrcy%2Fphonet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dxrcy%2Fphonet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dxrcy","download_url":"https://codeload.github.com/dxrcy/phonet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244066190,"owners_count":20392407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conlang","language","phonetics"],"created_at":"2024-11-23T23:55:52.370Z","updated_at":"2025-03-17T16:17:07.763Z","avatar_url":"https://github.com/dxrcy.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phonet\n\n_Phonet_ is a CLI tool and library to validate phonotactic patterns for constructed languages.\nIt is compatible with either romanization and phonetic transcription.\nWords can be randomly generated (see [Argument Syntax](#argument-syntax)).\n\n# Usage\n\nThis project may be used as a rust library crate, or as a binary executable.\n\n## Binary use\n\n[Download latest version here](https://github.com/dxrcy/phonet/releases/latest)\n\n### Argument Syntax\n\nGenerated by [Clap](https://crates.io/crates/clap)\n\n```\nUsage: phonet.exe [OPTIONS] [TESTS]...\n\nArguments:\n  [TESTS]...\n          Custom tests (optional)\n\n          This overrides all tests in the file\n\nOptions:\n  -f, --file \u003cFILE\u003e\n          Name and path of file to run and test\n\n          If name ends with a period, the 'phonet' extension is implied\n\n          Eg. `phonet -f myfile.phonet` or `phonet -f myfile.` (same result)\n\n          If name ends with a slash, the '/phonet' file name is implied\n\n          Eg. `phonet -f folder/phonet` or `phonet -f folder/` (same result)\n\n          [default: phonet]\n\n  -q, --quiet\n          Don't display passes and notes, only fails\n\n  -m, --minify\n          Minify file and save\n\n  -w, --with-tests\n          Include tests in minified file\n\n  -g, --generate [\u003cGENERATE\u003e]\n          Generate random words\n\n          Default count 1, specify with number\n\n      --gmin \u003cGENERATE_MIN_LEN\u003e\n          Set minimum length (inclusive) for generated words\n\n          Use with the `--generate` or `-g` flag\n\n          Note: This increases generation time exponentially\n\n          [default: 3]\n\n      --gmax \u003cGENERATE_MAX_LEN\u003e\n          Set maximum length (inclusive) for generated words\n\n          Use with the `--generate` or `-g` flag\n\n          [default: 20]\n\n  -n, --no-color\n          Display output in default color\n\n          Use for piping standard output to a file\n\n  -h, --help\n          Print help (see a summary with '-h')\n\n  -V, --version\n          Print version\n```\n\n### Example\n\n```bash\n# Runs ./phonet\nphonet\n\n# Runs ./phonet, with tests: 'some', 'tests' (overrides the tests in file)\nphonet some tests\n\n# Runs ./myfile.phonet\nphonet -f myfile.phonet\nphonet -f myfile.phonet some tests\n\n# 'phonet' extension implied\nphonet -f myfile.\n\n# 'phonet' filename implied\nphonet -f src/phonet\nphonet -f src/\n\n# Runs ./phonet, only showing fails\nphonet -q\n\n# Runs ./phonet, and minifies to ./min.phonet without tests\nphonet -m\n\n# Runs ./myfile.phonet, only displaying fails, and minifies to ./myfile.min.phonet with tests\nphonet -f myfile. -q -mw\n\n# Runs ./phonet, and generates 1 random word\nphonet -g\n\n# Runs ./myfile.phonet, and generates 10 random words\nphonet -g10 -f myfile.phonet\n\n# Runs ./phonet, with no color, and writes output to ./phonet.txt\nphonet -n \u003e phonet.txt\n\n# Runs ./myfile.phonet, only displaying fails, and generates 3 random words with length 6-8, writes output to ./phonet.txt (with no color)\nphonet -f myfile. -qn -g 3 --gmin 6 --gmax 8 \u003e ./phonet.txt\n```\n\n### Create Alias / Path\n\nReplace `\u003cpath_to_file\u003e` with the directory of the downloaded binary.\n\n#### Bash\n\nAdd alias in `.bashrc` in user directory\n\n```bash\n# ~/.bashrc\nalias phonet=\"\u003cpath_to_file\u003e/phonet.exe\"\n```\n\n#### Powershell\n\nAdd to `$env:PATH`\n\n```ps1\n$env:Path = \"$env:Path;\u003cpath_to_file\u003e\\phonet.exe\"\n```\n\n## Library use\n\nAdd `phonet = \"1.0.2\"` to your `Crates.toml` file\n\n- [Docs.rs](https://docs.rs/phonet/latest/phonet)\n- [Crates.io](https://crates.io/crates/phonet)\n\n### Short Example\n\n```rust\nuse phonet::Draft;\n\nfn main() {\n    let file = std::fs::read_to_string(\"phonet\").unwrap();\n\n    // Parse draft\n    Draft::from(\u0026file).unwrap()\n        // Run tests\n        .run()\n        // Display results\n        .display(Default::default(), true)\n}\n```\n\n### Long Example\n\n```rust\nuse std::fs;\n\nuse phonet::{\n    draft::{Message::Test, TestDraft},\n    get_min_filename, DisplayLevel, Draft,\n};\n\nfn main() {\n    let filename = \"myfile.phonet\";\n\n    // Read file\n    let file = fs::read_to_string(filename).expect(\"Could not read phonet file\");\n\n    // Parse file\n    let mut draft = Draft::from(\u0026file).expect(\"Failed to parse file\");\n\n    // Add a custom test\n    draft.messages.push(Test(TestDraft {\n        intent: true,\n        word: \"taso\".to_string(),\n    }));\n\n    // Minify file\n    fs::write(\n        get_min_filename(filename),\n        draft.minify(false).expect(\"Failed to minify\"),\n    )\n    .expect(\"Could not write minified file\");\n\n    // Run tests and display only failed tests\n    draft.run().display(DisplayLevel::OnlyFails, true);\n\n    // Create a generator for random words\n    // Each with a length between 5 and 8 (inclusive)\n    // Generation is done lazily, similar to an iterator\n    println!(\"Randomly generated words:\");\n    let mut words = draft\n        .generator(5..=8)\n        .expect(\"Failed to create word generator\");\n\n    // Generate 10 random words\n    for _ in 0..10 {\n        println!(\" - {}\", words.next());\n    }\n}\n```\n\n# File syntax\n\nA _Phonet_ file is used to define the rules, classes, and tests for the program.\n\nThe file should either be called `phonet`, or end in `.phonet`\n\n## Syntax Highlighting\n\n- [TreeSitter Parser](https://github.com/dxrcy/tree-sitter-phonet)\n- [VSCode Extension](https://github.com/dxrcy/phonet-syntax) (unmaintained)\n\n## Statements\n\nThe syntax is a statements, each separated by a semicolon `;` or a linebreak.\n\nUse a _Ampersand_ `\u0026` to denote a multi-line statement.\nThis may only be ended with a semicolon `;`\nNote that comments cannot be multiline.\n\nComments will end with a linebreak or a semicolon `;`\n\nAll whitespace is ignored, except to separate words in [_tests_](#tests).\n\n\u003e Note! This will replace spaces in Regex as well! Use `\\s` if you need a space\n\nEach statement must begin with an operator:\n\n- `#` **Hashtag**: A whole line comment. A linebreak (not a semicolon) ends the comment\n- `$` **Dollar**: Define a [_class_](#classes)\n- `+` **_Plus_** or `!` **_Bang_**: Define a [_rule_](#rule)\n- `*` **Star**: Create a test [_note_](#notes), and define a _reason_ if a test fails\n- `?` **Question mark**: Create a [_test_](#tests)\n- `~` **Tilde**: Define the [_mode_](#mode) of the file\n\n## Classes\n\nClasses are used as shorthand Regular Expressions, substituted into [_rules_](#rules) at runtime.\n\n\u003e **Note:** Angle brackets will not parse as class names directly after:\n\u003e\n\u003e - An opening round bracket and a question mark: `(?`\n\u003e - An opening round bracket, question mark, and letter 'P': `(?P`\n\u003e - A backslash and letter 'k': `\\k`\n\u003e\n\u003e This is the syntax used for look-behinds and named groups\n\n_Syntax:_\n\n- `$` **Dollar**\n- Name - Must be only characters from [a-zA-Z0-9_]\n- `=` **Equals**\n- Value - Regular Expression, may contain other _classes_ in angle brackets `\u003c\u003e` or `⟨⟩` (as with [_rules_](#rules))\n\nThe _'any'_ class, defined with `$_ = ...`, is used for random word generation.\n\n_Example:_\n\n```phonet\n# Some consonants\n$C = [ptksmn]\n\n# Some vowels\n$V = [iueoa]\n\n# Only sibilant consonants\n$C_s = [sz]\n\n# Every letter\n$_ = ⟨C⟩ | \u003cV\u003e\n```\n\n## Rules\n\nRules are Regular Expressions used to test if a word is valid.\n\nRules are defined with an _intent_, either `+` for _positive_, or `!` for _negative_.\n\n- A _positive_ rule must be followed for a word to be valid\n- A _negative_ rule must **not** be followed for a word to be valid\n\nTo use a [_class_](#classes), use the class name, surrounded by angle brackets `\u003c\u003e` or `⟨⟩`\n\n_Syntax:_\n\n- `+` **_Plus_** or `!` **_Bang_** - Plus for _positive_ rule, Bang for _negative_ rule\n- Pattern - Regular Expression, may contain [_classes_](#classes) in angle brackets `\u003c\u003e` or `⟨⟩`\n\n_Example (with predefined [*classes*](#classes)):_\n\n```phonet\n# Must be (C)V syllable structure\n+ ^ (\u003cC\u003e? ⟨V⟩)+ $\n\n# Must not have two vowels in a row\n! \u003cV\u003e{2}\n```\n\n## Tests\n\nTests are checked against all rules, and the result is displayed in the output.\n\nTests are ran in the order of definition.\n\nLike [_rules_](#rules), tests must have a defined _intent_, either `+` for _positive_, or `!` for _negative_.\n\n- A _positive_ test will pass if it is valid\n- A _negative_ test will **fail** if it is valid\n\n_Syntax:_\n\n- `?` **Question mark**\n- `+` **_Plus_** or `!` **_Bang_** - Plus for _positive_ test, Bang for _negative_ test\n- Tests - A word, or multiple words separated by a space\n\n_Example (with predefined [*rules*](#rules)):_\n\n```phonet\n# This should match, to pass\n?+ taso\n# This test should NOT match, to pass\n?! tax\n# Each word is a test, all should match to pass\n?+ taso sato tasa\n```\n\n## Notes\n\nNotes are printed to the terminal output, alongside tests.\n\nThey are used as a _reason_ for any proceeding rules, as an explanation if a test fails.\n\n_Syntax:_\n\n- `*` **Star**\n- `:` **Colon** (_Optional_) - Define a 'quiet' note\n- Text to print, and define reason as\n\n_Example:_\n\n```phonet\n* Syllable structure\n+ ^ (\u003cC\u003e? \u003cV\u003e)+ $\n\n# This test will NOT match, however it SHOULD (due to the Plus), so it will FAIL, with the above note as the reason\n?+ tasto\n\n# This is a 'quiet' note, it will not display, but it will be used as the reason for the following rule\n*: Must not have two vowels in a row\n! \u003cV\u003e{2}\n\n?+ taso\n```\n\n## Mode\n\nThe mode of a _Phonet_ file may be one of these:\n\n- _Romanized_: Using `\u003c\u003e` (not `⟨⟩`)\n- _Broad transcription_: Using `//`\n- _Narrow transcription_: Using `[]`\n\nThis may optionally be specified in a file, although it does not add any functionality.\n\n_Syntax:_\n\n- `~` **Tilde**\n- `\u003c.\u003e`, `/./`, or `[.]` - Mode identifier, with `.` being any string for, or blank\n\n_Examples:_\n\n```phonet\n# Specify romanized mode (fish icon)\n~\u003c\u003e\n```\n\n```phonet\n# Specify broad transcription, with a given name\n~ / My Language /\n```\n\n## Examples\n\nSee the [examples](./examples/) folder for _Phonet_ file examples.\n\n- [Good Syntax Example](./examples/example.phonet)\n- [Toki Pona](./examples/tokipona.phonet)\n\u003c!-- - [Ivalingo](./examples/ivalingo.phonet) --\u003e\n\n## Recommended Syntax Patterns\n\nThese formatting tips are not required, but recommended to make the file easier to read.\n\n1. Specify the mode at the very top of the file\n2. Define all classes at the top of the file\n   - Also define an [_'any'_ class](#classes) first, for word generation\n3. Group related rules and tests, using a note\n   - Define rules first, then positive tests, then negative tests\n4. Indent rules and tests under note\n   - Rules should use 1 intent, tests use 2\n\n### Example File\n\n_Example (this is from [example.phonet](./examples/example.phonet)):_\n\n```phonet\n~\u003c\u003e ;# Mode (optional) - This file uses romanized letters\n\n# Class definitions\n$_ = ⟨C⟩ | ⟨V⟩        ;# Any / all letters (required for generating words)\n$C = [ptkmnswjl]      ;# Consonants\n$V = [aeiou]          ;# Vowels\n\n* Invalid letters     ;# Note - Prints to standard output, and used as reason if test fails\n  + ^ ⟨_⟩+ $          ;# Check that every letter is in the 'any' class\n    ?+ taso\n    ?! tyxo\n\n* Examples of failing tests\n    ?+ tyxo           ;# This test will fail - with the reason 'Invalid Letters' (above)\n    ?! taso           ;# This test will fail, as a false positive\n\n* Syllable structure\n  + ^ ⟨V⟩? ( ⟨C⟩ ⟨V⟩ )+ $  ;# Check that word is Consonant + Vowel, repeating at least once\n    ?+ taso kili ano atoso\n    ?! taaso an\n\n* Some more tests\n    ?+ silo tila\n    ?! akka axe\n\n# This is a 'quiet' note - It will not display, unless any following rules fail\n*: No repeated letters\n  ! (.)\\1             ;# This is an unnamed back-reference\n  ! (?\u003cx\u003e .) \\k\u003cx\u003e    ;# (Alternative) This is a named back-reference (NOT a class)\n    ?+ taso           ;# An example of multi-line statements on next line (comments cannot be on same line)\n    ?! \u0026\n      taaso\n      ttaso\n    ;\n\n# Comments cannot be multiline, even using '\u0026'\n\n* 2 tests *should* have failed!\n```\n\n![Phonet Icon](./icon.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdxrcy%2Fphonet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdxrcy%2Fphonet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdxrcy%2Fphonet/lists"}