refactor to break stateReducer into modules for each property of state

This commit is contained in:
Sorrel Bri 2019-12-11 22:19:54 -08:00
parent 02426fb383
commit c8f6b65302
12 changed files with 351 additions and 913 deletions

View file

@ -11,6 +11,6 @@
[lints]
[options]
; all=true
; all=true
[strict]

View file

@ -1,675 +0,0 @@
{
"header": {
"reportVersion": 1,
"event": "Allocation failed - JavaScript heap out of memory",
"trigger": "FatalError",
"filename": "report.20191129.153032.5120.0.001.json",
"dumpEventTime": "2019-11-29T15:30:32Z",
"dumpEventTimeStamp": "1575070232386",
"processId": 5120,
"cwd": "/Users/sorrel/code/phono-change-applier",
"commandLine": [
"/usr/local/Cellar/node/12.6.0/bin/node",
"/Users/sorrel/code/phono-change-applier/node_modules/jest-worker/build/workers/processChild.js"
],
"nodejsVersion": "v12.6.0",
"wordSize": 64,
"arch": "x64",
"platform": "darwin",
"componentVersions": {
"node": "12.6.0",
"v8": "7.5.288.22-node.14",
"uv": "1.30.1",
"zlib": "1.2.11",
"brotli": "1.0.7",
"ares": "1.15.0",
"modules": "72",
"nghttp2": "1.38.0",
"napi": "4",
"llhttp": "1.1.4",
"http_parser": "2.8.0",
"openssl": "1.1.1c",
"cldr": "35.1",
"icu": "64.2",
"tz": "2019a",
"unicode": "12.1"
},
"release": {
"name": "node",
"headersUrl": "https://nodejs.org/download/release/v12.6.0/node-v12.6.0-headers.tar.gz",
"sourceUrl": "https://nodejs.org/download/release/v12.6.0/node-v12.6.0.tar.gz"
},
"osName": "Darwin",
"osRelease": "17.7.0",
"osVersion": "Darwin Kernel Version 17.7.0: Sun Jun 2 20:31:42 PDT 2019; root:xnu-4570.71.46~1/RELEASE_X86_64",
"osMachine": "x86_64",
"cpus": [
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz",
"speed": 2000,
"user": 2044650,
"nice": 0,
"sys": 1337730,
"idle": 7706670,
"irq": 0
}
],
"host": "SBJ-comp.local"
},
"javascriptStack": {
"message": "No stack.",
"stack": [
"Unavailable."
]
},
"nativeStack": [
{
"pc": "0x0000000100140f5b",
"symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, v8::Local<v8::String>) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x0000000100075aec",
"symbol": "node::OnFatalError(char const*, char const*) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x000000010016900d",
"symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x0000000100168faf",
"symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002c018b",
"symbol": "v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002c1004",
"symbol": "v8::internal::Heap::HasLowYoungGenerationAllocationRate() [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002bf345",
"symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002bdcfa",
"symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002c4d97",
"symbol": "v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002c4de4",
"symbol": "v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001002a41e8",
"symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x00000001004960a2",
"symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/Cellar/node/12.6.0/bin/node]"
},
{
"pc": "0x000000010071bf59",
"symbol": "Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/usr/local/Cellar/node/12.6.0/bin/node]"
}
],
"javascriptHeap": {
"totalMemory": 2153086976,
"totalCommittedMemory": 2151679912,
"usedMemory": 2144297648,
"availableMemory": 48338248,
"memoryLimit": 2197815296,
"heapSpaces": {
"read_only_space": {
"memorySize": 262144,
"committedMemory": 32272,
"capacity": 261832,
"used": 31960,
"available": 229872
},
"new_space": {
"memorySize": 2097152,
"committedMemory": 1359664,
"capacity": 1047328,
"used": 374792,
"available": 672536
},
"old_space": {
"memorySize": 2127966208,
"committedMemory": 2127561520,
"capacity": 2123871224,
"used": 2122211032,
"available": 1660192
},
"code_space": {
"memorySize": 688128,
"committedMemory": 657536,
"capacity": 543776,
"used": 543776,
"available": 0
},
"map_space": {
"memorySize": 2625536,
"committedMemory": 2621112,
"capacity": 1757200,
"used": 1757200,
"available": 0
},
"large_object_space": {
"memorySize": 19398656,
"committedMemory": 19398656,
"capacity": 19375432,
"used": 19375432,
"available": 0
},
"code_large_object_space": {
"memorySize": 49152,
"committedMemory": 49152,
"capacity": 3456,
"used": 3456,
"available": 0
},
"new_large_object_space": {
"memorySize": 0,
"committedMemory": 0,
"capacity": 1047328,
"used": 0,
"available": 1047328
}
}
},
"resourceUsage": {
"userCpuSeconds": 82.9667,
"kernelCpuSeconds": 5.36789,
"cpuConsumptionPercent": 200.76,
"maxRss": 2276429135872,
"pageFaults": {
"IORequired": 28,
"IONotRequired": 955033
},
"fsActivity": {
"reads": 0,
"writes": 0
}
},
"libuv": [
],
"environmentVariables": {
"npm_config_save_dev": "",
"npm_config_legacy_bundling": "",
"npm_config_dry_run": "",
"npm_config_viewer": "man",
"npm_config_only": "",
"npm_config_commit_hooks": "true",
"npm_config_browser": "",
"npm_package_gitHead": "13e04ab20d0f19c2364c2effe91bdb03bb2f2e10",
"npm_config_also": "",
"npm_package_devDependencies_react_test_renderer": "^16.12.0",
"npm_config_sign_git_commit": "",
"npm_config_rollback": "true",
"TERM_PROGRAM": "Apple_Terminal",
"NODE": "/usr/local/Cellar/node/12.6.0/bin/node",
"npm_config_usage": "",
"npm_config_audit": "true",
"INIT_CWD": "/Users/sorrel/code/phono-change-applier",
"npm_config_globalignorefile": "/usr/local/etc/npmignore",
"SHELL": "/bin/bash",
"TERM": "xterm-256color",
"npm_config_shell": "/bin/bash",
"npm_config_maxsockets": "50",
"npm_config_init_author_url": "",
"npm_config_shrinkwrap": "true",
"npm_config_parseable": "",
"npm_config_metrics_registry": "https://registry.npmjs.org/",
"TMPDIR": "/var/folders/61/30m32tnj2_n8vpgq01j3xqb40000gq/T/",
"npm_config_timing": "",
"npm_config_init_license": "ISC",
"Apple_PubSub_Socket_Render": "/private/tmp/com.apple.launchd.J3gGwt1Hbc/Render",
"npm_config_if_present": "",
"TERM_PROGRAM_VERSION": "404.1",
"npm_config_sign_git_tag": "",
"npm_config_init_author_email": "",
"npm_config_cache_max": "Infinity",
"npm_config_preid": "",
"npm_config_long": "",
"npm_config_local_address": "",
"npm_config_git_tag_version": "true",
"npm_config_cert": "",
"TERM_SESSION_ID": "71BD6564-37BE-4A5F-A20D-A1F80094E087",
"npm_config_registry": "https://registry.npmjs.org/",
"npm_config_noproxy": "",
"npm_config_fetch_retries": "2",
"npm_package_private": "true",
"npm_package_dependencies_react_dom": "^16.12.0",
"npm_config_versions": "",
"npm_config_message": "%s",
"npm_config_key": "",
"npm_package_readmeFilename": "README.md",
"npm_package_description": "[Inspired by the Zompist Sound Change Applier 2](https://www.zompist.com/sca2.html)",
"npm_package_devDependencies__testing_library_react": "^9.3.2",
"USER": "sorrel",
"npm_config_globalconfig": "/usr/local/etc/npmrc",
"npm_package_browserslist_development_1": "last 1 firefox version",
"npm_config_prefer_online": "",
"npm_config_logs_max": "10",
"npm_config_always_auth": "",
"npm_package_browserslist_development_0": "last 1 chrome version",
"npm_package_eslintConfig_extends": "react-app",
"SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.Pvi0zgMU0F/Listeners",
"npm_package_browserslist_development_2": "last 1 safari version",
"__CF_USER_TEXT_ENCODING": "0x1F7:0x0:0x0",
"npm_execpath": "/usr/local/lib/node_modules/npm/bin/npm-cli.js",
"npm_config_global_style": "",
"npm_config_cache_lock_retries": "10",
"npm_config_update_notifier": "true",
"npm_config_cafile": "",
"npm_config_heading": "npm",
"npm_config_audit_level": "low",
"npm_config_searchlimit": "20",
"npm_config_read_only": "",
"npm_config_offline": "",
"npm_config_fetch_retry_mintimeout": "10000",
"npm_config_json": "",
"npm_config_access": "",
"npm_config_argv": "{\"remain\":[],\"cooked\":[\"test\"],\"original\":[\"test\"]}",
"PATH": "/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/sorrel/code/phono-change-applier/node_modules/.bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/opt/X11/bin",
"npm_config_allow_same_version": "",
"npm_config_https_proxy": "",
"npm_config_engine_strict": "",
"npm_config_description": "true",
"_": "/Users/sorrel/code/phono-change-applier/node_modules/.bin/react-scripts",
"npm_config_userconfig": "/Users/sorrel/.npmrc",
"npm_config_init_module": "/Users/sorrel/.npm-init.js",
"npm_package_browserslist_production_1": "not dead",
"npm_config_cidr": "",
"npm_package_browserslist_production_0": ">0.2%",
"PWD": "/Users/sorrel/code/phono-change-applier",
"npm_config_user": "",
"npm_config_node_version": "12.6.0",
"npm_package_dependencies_node_sass": "^4.13.0",
"npm_lifecycle_event": "test",
"npm_package_browserslist_production_2": "not op_mini all",
"npm_config_save": "true",
"npm_config_ignore_prepublish": "",
"npm_config_editor": "vi",
"npm_config_auth_type": "legacy",
"npm_package_name": "phono-change-applier",
"LANG": "en_US.UTF-8",
"npm_config_tag": "latest",
"npm_config_script_shell": "",
"npm_config_progress": "true",
"npm_config_global": "",
"npm_config_before": "",
"npm_package_scripts_build": "react-scripts build",
"npm_package_scripts_start": "react-scripts start",
"npm_config_searchstaleness": "900",
"npm_config_optional": "true",
"npm_config_ham_it_up": "",
"XPC_FLAGS": "0x0",
"npm_config_save_prod": "",
"npm_config_force": "",
"npm_config_bin_links": "true",
"npm_config_searchopts": "",
"npm_config_node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
"npm_config_depth": "Infinity",
"npm_config_sso_poll_frequency": "500",
"npm_config_rebuild_bundle": "true",
"npm_package_version": "0.1.0",
"XPC_SERVICE_NAME": "0",
"npm_config_unicode": "true",
"SHLVL": "2",
"HOME": "/Users/sorrel",
"npm_config_fetch_retry_maxtimeout": "60000",
"npm_package_scripts_test": "react-scripts test",
"npm_config_tag_version_prefix": "v",
"npm_config_strict_ssl": "true",
"npm_config_sso_type": "oauth",
"npm_config_scripts_prepend_node_path": "warn-only",
"npm_config_save_prefix": "^",
"npm_config_loglevel": "notice",
"npm_config_ca": "",
"npm_config_save_exact": "",
"npm_config_group": "20",
"npm_config_fetch_retry_factor": "10",
"npm_config_dev": "",
"npm_config_version": "",
"npm_config_prefer_offline": "",
"npm_config_cache_lock_stale": "60000",
"npm_config_otp": "",
"npm_config_cache_min": "10",
"npm_config_searchexclude": "",
"npm_config_cache": "/Users/sorrel/.npm",
"npm_package_dependencies_react_scripts": "3.2.0",
"LOGNAME": "sorrel",
"npm_lifecycle_script": "react-scripts test",
"npm_config_color": "true",
"npm_config_proxy": "",
"npm_config_package_lock": "true",
"npm_config_package_lock_only": "",
"npm_config_fund": "true",
"npm_package_dependencies_react": "^16.12.0",
"npm_config_save_optional": "",
"npm_config_ignore_scripts": "",
"npm_config_user_agent": "npm/6.13.1 node/v12.6.0 darwin x64",
"npm_config_cache_lock_wait": "10000",
"npm_config_production": "",
"DISPLAY": "/private/tmp/com.apple.launchd.x5Pdwz4pIw/org.macosforge.xquartz:0",
"npm_config_send_metrics": "",
"npm_config_save_bundle": "",
"npm_config_umask": "0022",
"npm_config_node_options": "",
"npm_config_init_version": "1.0.0",
"npm_config_init_author_name": "",
"npm_config_git": "git",
"npm_config_scope": "",
"npm_package_scripts_eject": "react-scripts eject",
"SECURITYSESSIONID": "186a7",
"npm_config_unsafe_perm": "true",
"npm_config_tmp": "/var/folders/61/30m32tnj2_n8vpgq01j3xqb40000gq/T",
"npm_config_onload_script": "",
"npm_node_execpath": "/usr/local/Cellar/node/12.6.0/bin/node",
"npm_config_link": "",
"npm_config_format_package_lock": "true",
"npm_config_prefix": "/usr/local",
"npm_package_devDependencies__testing_library_jest_dom": "^4.2.4",
"BABEL_ENV": "test",
"NODE_ENV": "test",
"PUBLIC_URL": "",
"NODE_PATH": "",
"JEST_WORKER_ID": "1",
"FORCE_COLOR": "1"
},
"userLimits": {
"core_file_size_blocks": {
"soft": 0,
"hard": "unlimited"
},
"data_seg_size_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"file_size_blocks": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_locked_memory_bytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_memory_size_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"open_files": {
"soft": 10240,
"hard": "unlimited"
},
"stack_size_bytes": {
"soft": 8388608,
"hard": 67104768
},
"cpu_time_seconds": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_user_processes": {
"soft": 709,
"hard": 1064
},
"virtual_memory_kbytes": {
"soft": "unlimited",
"hard": "unlimited"
}
},
"sharedObjects": [
"/usr/local/Cellar/node/12.6.0/bin/node",
"/usr/local/opt/icu4c/lib/libicui18n.64.dylib",
"/usr/local/opt/icu4c/lib/libicuuc.64.dylib",
"/usr/local/opt/icu4c/lib/libicudata.64.dylib",
"/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation",
"/usr/lib/libSystem.B.dylib",
"/usr/lib/libc++.1.dylib",
"/usr/lib/system/libcache.dylib",
"/usr/lib/system/libcommonCrypto.dylib",
"/usr/lib/system/libcompiler_rt.dylib",
"/usr/lib/system/libcopyfile.dylib",
"/usr/lib/system/libcorecrypto.dylib",
"/usr/lib/system/libdispatch.dylib",
"/usr/lib/system/libdyld.dylib",
"/usr/lib/system/libkeymgr.dylib",
"/usr/lib/system/liblaunch.dylib",
"/usr/lib/system/libmacho.dylib",
"/usr/lib/system/libquarantine.dylib",
"/usr/lib/system/libremovefile.dylib",
"/usr/lib/system/libsystem_asl.dylib",
"/usr/lib/system/libsystem_blocks.dylib",
"/usr/lib/system/libsystem_c.dylib",
"/usr/lib/system/libsystem_configuration.dylib",
"/usr/lib/system/libsystem_coreservices.dylib",
"/usr/lib/system/libsystem_darwin.dylib",
"/usr/lib/system/libsystem_dnssd.dylib",
"/usr/lib/system/libsystem_info.dylib",
"/usr/lib/system/libsystem_m.dylib",
"/usr/lib/system/libsystem_malloc.dylib",
"/usr/lib/system/libsystem_network.dylib",
"/usr/lib/system/libsystem_networkextension.dylib",
"/usr/lib/system/libsystem_notify.dylib",
"/usr/lib/system/libsystem_sandbox.dylib",
"/usr/lib/system/libsystem_secinit.dylib",
"/usr/lib/system/libsystem_kernel.dylib",
"/usr/lib/system/libsystem_platform.dylib",
"/usr/lib/system/libsystem_pthread.dylib",
"/usr/lib/system/libsystem_symptoms.dylib",
"/usr/lib/system/libsystem_trace.dylib",
"/usr/lib/system/libunwind.dylib",
"/usr/lib/system/libxpc.dylib",
"/usr/lib/closure/libclosured.dylib",
"/usr/lib/libobjc.A.dylib",
"/usr/lib/libc++abi.dylib",
"/usr/lib/libDiagnosticMessagesClient.dylib",
"/usr/lib/libicucore.A.dylib",
"/usr/lib/libz.1.dylib",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices",
"/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics",
"/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO",
"/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LangAnalysis.framework/Versions/A/LangAnalysis",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis",
"/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight",
"/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate",
"/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit",
"/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation",
"/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration",
"/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay",
"/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface",
"/System/Library/Frameworks/Metal.framework/Versions/A/Metal",
"/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport",
"/System/Library/Frameworks/Security.framework/Versions/A/Security",
"/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore",
"/usr/lib/libbsm.0.dylib",
"/usr/lib/libauto.dylib",
"/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration",
"/usr/lib/libarchive.2.dylib",
"/usr/lib/libxml2.2.dylib",
"/usr/lib/liblangid.dylib",
"/usr/lib/libCRFSuite.dylib",
"/usr/lib/libenergytrace.dylib",
"/usr/lib/system/libkxld.dylib",
"/usr/lib/libOpenScriptingUtil.dylib",
"/usr/lib/libcoretls.dylib",
"/usr/lib/libcoretls_cfhelpers.dylib",
"/usr/lib/libpam.2.dylib",
"/usr/lib/libsqlite3.dylib",
"/usr/lib/libxar.1.dylib",
"/usr/lib/libbz2.1.0.dylib",
"/usr/lib/liblzma.5.dylib",
"/usr/lib/libnetwork.dylib",
"/usr/lib/libapple_nghttp2.dylib",
"/usr/lib/libpcap.A.dylib",
"/usr/lib/libboringssl.dylib",
"/usr/lib/libusrtcp.dylib",
"/usr/lib/libapple_crypto.dylib",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices",
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList",
"/System/Library/Frameworks/NetFS.framework/Versions/A/NetFS",
"/System/Library/PrivateFrameworks/NetAuth.framework/Versions/A/NetAuth",
"/System/Library/PrivateFrameworks/login.framework/Versions/A/Frameworks/loginsupport.framework/Versions/A/loginsupport",
"/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC",
"/usr/lib/libmecabra.dylib",
"/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData",
"/usr/lib/libmarisa.dylib",
"/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon",
"/usr/lib/libChineseTokenizer.dylib",
"/usr/lib/libcmph.dylib",
"/usr/lib/libiconv.2.dylib",
"/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling",
"/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData",
"/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji",
"/usr/lib/libcompression.dylib",
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory",
"/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS",
"/usr/lib/libutil.dylib",
"/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement",
"/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement",
"/usr/lib/libxslt.1.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib",
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib",
"/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler",
"/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator",
"/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment",
"/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib",
"/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage",
"/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL",
"/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders",
"/usr/lib/libFosl_dynamic.dylib",
"/System/Library/PrivateFrameworks/FaceCore.framework/Versions/A/FaceCore",
"/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontParser.dylib",
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib",
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib",
"/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSCore.framework/Versions/A/MPSCore",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSImage.framework/Versions/A/MPSImage",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork",
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix",
"/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib",
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib",
"/usr/lib/libcups.2.dylib",
"/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos",
"/System/Library/Frameworks/GSS.framework/Versions/A/GSS",
"/usr/lib/libresolv.9.dylib",
"/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal",
"/usr/lib/libheimdal-asn1.dylib",
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory",
"/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth",
"/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation",
"/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio",
"/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox",
"/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce",
"/Users/sorrel/code/phono-change-applier/node_modules/jest-haste-map/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64/fse.node"
]
}

View file

@ -9,7 +9,8 @@ import Epochs from './components/Epochs';
import Options from './components/Options';
import Output from './components/Output';
import {initState, stateReducer} from './reducers/stateReducer';
import {stateReducer} from './reducers/stateReducer';
import {initState} from './reducers/stateReducer.init';
const PhonoChangeApplier = () => {
const [ state, dispatch ] = useReducer(

View file

@ -0,0 +1,30 @@
// @flow
import type { stateType } from './stateReducer';
export type epochAction = {
type: "ADD_EPOCH" | "SET_EPOCH",
value: {
index?: number,
name: string,
changes?: Array<string>
}
}
export const addEpoch = (state: stateType, action: epochAction): stateType => {
const newEpoch = { ...action.value, changes: ['']};
return {...state, epochs: [...state.epochs, newEpoch]}
}
export const setEpoch = (state: stateType, action: epochAction): stateType => {
let mutatedEpochs = state.epochs;
const index = action.value.index
if (!index) return state;
mutatedEpochs[index].name = action.value.name
? action.value.name
: mutatedEpochs[index].name;
mutatedEpochs[index].changes = action.value.changes
? action.value.changes
: mutatedEpochs[index].changes;
return {...state, epochs: [...mutatedEpochs]}
}

View file

@ -6,7 +6,7 @@ describe('Epochs', () => {
state.epochs = [
{
name: 'epoch 1',
changes: []
changes: ['']
}
]
})
@ -17,33 +17,33 @@ describe('Epochs', () => {
});
it('epochs addition returns new epochs list', () => {
const action = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: []}};
const action = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: ['']}};
expect(stateReducer(state, action)).toEqual({...state, epochs: [...state.epochs, action.value]})
})
it('epoch name mutation returns new epochs list with mutation', () => {
const firstAction = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: []}};
const firstAction = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: ['']}};
const secondAction = {type: 'SET_EPOCH', value: { index: 0, name: 'proto-lang'}};
const secondState = stateReducer(state, firstAction);
expect(stateReducer(secondState, secondAction)).toEqual(
{...state,
epochs: [
{name: 'proto-lang', changes: []},
{name: 'epoch 2', changes: []}
{name: 'proto-lang', changes: ['']},
{name: 'epoch 2', changes: ['']}
]
}
);
});
it('epoch changes mutation returns new epochs list with mutation', () => {
const firstAction = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: []}};
const firstAction = {type: 'ADD_EPOCH', value: { name: 'epoch 2', changes: ['']}};
const secondAction = {type: 'SET_EPOCH', value: { index: 0, changes: ['n>t/_#', '[+plosive]>[+nasal -plosive]/_n']}};
const secondState = stateReducer(state, firstAction);
expect(stateReducer(secondState, secondAction)).toEqual(
{...state,
epochs: [
{name: 'epoch 1', changes: ['n>t/_#', '[+plosive]>[+nasal -plosive]/_n']},
{name: 'epoch 2', changes: []}
{name: 'epoch 2', changes: ['']}
]
}
);

View file

@ -0,0 +1,75 @@
// @flow
import type { stateType } from './stateReducer';
export type featureAction = {
type: "ADD_FEATURE",
value: {
positivePhones: Array<string>,
negativePhones: Array<string>,
feature: string
}
}
const addPhones = (phones: {}, phone: string): {} => {
let node = {};
phone.split('').forEach((graph, index) => {
if (index) node[graph] = {}
if (!index && !phones[graph]) phones[graph] = {}
node = index === 0 ? phones[graph] : node[graph];
if (index === phone.length - 1) node.grapheme = phone;
})
return phones;
}
const findPhone = (phones: {}, phone: string): {} => {
let node = {};
phone.split('').forEach((graph, index) => {
node = index === 0 ? phones[graph] : node[graph];
});
return node;
}
const addFeatureToPhone = (
phones: {}, phone: string, featureKey: string, featureValue: boolean
): {} =>
{
let node = {}
phone.split('').forEach((graph, index) => {
node = index === 0 ? phones[graph] : node[graph];
if (index === phone.split('').length - 1) node.features = {...node.features, [featureKey]: featureValue}
})
return phones;
}
export const addFeature = (state: stateType, action: featureAction): stateType => {
let positivePhones = action.value.positivePhones || [];
let negativePhones = action.value.negativePhones || [];
let newFeatureName = action.value.feature;
let newPhoneObject = [
...positivePhones, ...negativePhones
].reduce((phoneObject, phone) => addPhones(phoneObject, phone), state.phones)
if (positivePhones) {
positivePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, true)
, newPhoneObject
);
positivePhones = positivePhones.map( positivePhone => findPhone(newPhoneObject, positivePhone) )
}
if (negativePhones) {
negativePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, false)
, newPhoneObject
);
negativePhones = negativePhones.map( negativePhone => findPhone(newPhoneObject, negativePhone) )
}
let newFeature = {[action.value.feature]: {positive: positivePhones, negative: negativePhones}};
return {...state, features:{...state.features, ...newFeature}, phones: newPhoneObject}
}

View file

@ -0,0 +1,84 @@
// @flow
import type { stateType } from './stateReducer';
export type initAction = {
type: "INIT"
}
export const initState = (changesArgument: number = -1): stateType => {
const state = {
lexicon: [
{lexeme: 'anta', epoch: 'epoch 1'}, 'anat', 'anət', 'anna', 'tan', 'ənta'
],
epochs: [
{
name: 'epoch 1',
changes: [
'[+ occlusive - nasal]>[+ occlusive nasal]/n_',
'at>ta/_#',
'[+ sonorant - low rounded high back]>_/_',
'nn>nun/_',
'[+ nasal][+ obstruent]>[+ nasal obstruent aspirated ]/#_',
'[+ sonorant rounded]>[+ sonorant - rounded]/_#'
]
}
],
phones: {
a: {
grapheme: 'a', features: {
sonorant: true, back: true, low: true, high: false, rounded: false
}
},
u: {
grapheme: 'u', features: {
sonorant: true, back: true, low: false, high: true, rounded: true,
}
},
ɯ: {
grapheme: 'ɯ', features: {
sonorant: true, back: true, low: false, high: true, rounded: false,
}
},
ə: {
grapheme: 'ə', features: {
sonorant: true, low: false, rounded: false, high: false, back: false
}
},
t: {
grapheme: 't', features: {
occlusive: true, coronal: true, obstruent: true
},
ʰ: {
grapheme: 'tʰ', features: {
occlusive: true, coronal: true, obstruent: true, aspirated: true
}
}
},
n: {
grapheme: 'n', features: {
sonorant: true, nasal: true, occlusive: true, coronal: true
}
}
},
options: {},
results: {},
errors: {},
features: {}
};
state.features = {
sonorant: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ, state.phones.ə, state.phones.n], negative: [] },
back: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ ], negative: [ state.phones.ə ] },
low: { positive:[ state.phones.a ], negative: [ state.phones.u, state.phones.ɯ, state.phones.ə ] },
high: { positive:[ state.phones.u, state.phones.ɯ ], negative: [ state.phones.a, state.phones.ə ] },
rounded: { positive:[ state.phones.u ], negative: [ state.phones.a, state.phones.ɯ, state.phones.ə ] },
occlusive: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
coronal: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
obstruent: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
nasal: { positive:[ state.phones.n ], negative: [] },
aspirated: { positive:[ state.phones.t.ʰ ], negative: [] },
}
if(changesArgument > -1) state.epochs[0].changes = state.epochs[0].changes.splice(changesArgument, 1)
return state;
}

View file

@ -1,7 +1,18 @@
// @flow
type stateType = {
lexicon: Array<?string>,
epochs: Array<?{name: string, changes: Array<string>}>,
import { addLexeme, setLexicon } from './stateReducer.lexicon';
import type { lexiconAction } from './stateReducer.lexicon';
import { addEpoch, setEpoch } from './stateReducer.epochs';
import type { epochAction } from './stateReducer.epochs';
import { addFeature } from './stateReducer.features';
import type { featureAction } from './stateReducer.features';
import { run } from './stateReducer.results';
import type { resultsAction } from './stateReducer.results'
import { initState } from './stateReducer.init';
import type { initAction } from './stateReducer.init';
export type stateType = {
lexicon: Array<{lexeme: string, epoch: epochType}>,
epochs: Array<epochType>,
phones: {[key: string]: phoneType},
options: {},
results: {},
@ -9,6 +20,10 @@ type stateType = {
features: featureType
}
type epochType = {
name: string, changes: Array<string>
}
type phoneType = {
grapheme: string,
features: {[key: string]: boolean}
@ -18,239 +33,39 @@ type featureType = {
[key: string]: {[key: string]: Array<phoneType>}
}
const addPhones = (phones: {}, phone: string): {} => {
let node = {};
phone.split('').forEach((graph, index) => {
if (index) node[graph] = {}
if (!index && !phones[graph]) phones[graph] = {}
node = index === 0 ? phones[graph] : node[graph];
if (index === phone.length - 1) node.grapheme = phone;
})
return phones;
}
type actionType = featureAction | epochAction | initAction | resultsAction | lexiconAction
const findPhone = (phones: {}, phone: string): {} => {
let node = {};
phone.split('').forEach((graph, index) => {
node = index === 0 ? phones[graph] : node[graph];
});
return node;
}
const addFeatureToPhone = (
phones: {}, phone: string, featureKey: string, featureValue: boolean
): {} =>
{
let node = {}
phone.split('').forEach((graph, index) => {
node = index === 0 ? phones[graph] : node[graph];
if (index === phone.split('').length - 1) node.features = {...node.features, [featureKey]: featureValue}
})
return phones;
}
const findFeatures = (phones: {}, lexeme:string): [] => {
let featureBundle = []
let lastIndex = lexeme.length - 1;
let node = {};
[...lexeme].forEach((graph, index) => {
if (!index) return node = phones[graph]
if (index === lastIndex) return node[graph]
? featureBundle.push(node[graph])
: featureBundle.push(node, phones[graph])
if (!node[graph] && node.features) {
featureBundle.push(node)
return node = phones[graph]
}
if (!node[graph])
return node = node[graph]
})
return featureBundle;
}
const decomposeRule = (rule: string): string[] => {
let decomposedChange = rule.split('>');
decomposedChange = [decomposedChange[0], ...decomposedChange[1].split('/')]
decomposedChange = [decomposedChange[0], decomposedChange[1], ...decomposedChange[2].split('_')];
return [...decomposedChange];
}
export const stateReducer = (state: stateType, action: {type: string, value: {}}) => {
export const stateReducer = (state: stateType, action: actionType): stateType => {
switch (action.type) {
case 'INIT': {
return initState();
}
case 'ADD_LEXEME': {
let newLexeme = action.value;
if (!newLexeme.epoch) newLexeme.epoch = state.epochs[0].name;
return {...state, lexicon:[...state.lexicon, newLexeme]}
return addLexeme(state, action);
}
case 'SET_LEXICON': {
let newLexicon = action.value;
newLexicon = newLexicon.map(lexeme => lexeme.epoch
? lexeme
: {...lexeme, epoch: state.epochs[0].name});
return {...state, lexicon: newLexicon}
return setLexicon(state, action);
}
case 'ADD_EPOCH': {
let newEpoch = action.value;
return {...state, epochs: [...state.epochs, newEpoch]}
return addEpoch(state, action);
}
case 'SET_EPOCH': {
let mutatedEpochs = state.epochs;
let index = [action.value.index]
mutatedEpochs[index].name = action.value.name
? action.value.name
: mutatedEpochs[index].name;
mutatedEpochs[index].changes = action.value.changes
? action.value.changes
: mutatedEpochs[index].changes;
return {...state, epochs: [...mutatedEpochs]}
return setEpoch(state, action);
}
case 'ADD_FEATURE': {
let positivePhones = action.value.positivePhones || [];
let negativePhones = action.value.negativePhones || [];
let newFeatureName = action.value.feature;
let newPhoneObject = [
...positivePhones, ...negativePhones
].reduce((phoneObject, phone) => addPhones(phoneObject, phone), state.phones)
if (positivePhones) {
positivePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, true)
, newPhoneObject
);
positivePhones = positivePhones.map( positivePhone => findPhone(newPhoneObject, positivePhone) )
}
if (negativePhones) {
negativePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, false)
, newPhoneObject
);
negativePhones = negativePhones.map( negativePhone => findPhone(newPhoneObject, negativePhone) )
}
let newFeature = {[action.value.feature]: {positive: positivePhones, negative: negativePhones}};
return {...state, features:{...state.features, ...newFeature}, phones: newPhoneObject}
return addFeature(state, action);
}
case 'RUN': {
// ! one epoch only
// rule 0 '[+ occlusive - nasal]>[+ occlusive nasal]/n_'
let ruleBundle = state.epochs[0].changes;
ruleBundle = ruleBundle.map(rule => decomposeRule(rule))
ruleBundle.map(rule => {
rule.forEach(position => {
console.log(position)
})
})
let featurePhoneBundle = state.lexicon.map(lexeme => findFeatures(state.phones, lexeme))
console.log(featurePhoneBundle)
ruleBundle.forEach(rule => {
featurePhoneBundle.map(featurePhone => {
// if (findRules(featurePhone, )
})
})
let results = [];
return {...state, results: { pass: state.epochs[0].name, results } }
return run(state, action);
}
default:
return state;
}
}
export const initState = (changesArgument: number = -1): stateType => {
const state = {
lexicon: [
'anta', 'anat', 'anət', 'anna', 'tan', 'ənta'
],
epochs: [
{
name: 'epoch 1',
changes: [
'[+ occlusive - nasal]>[+ occlusive nasal]/n_',
'at>ta/_#',
'[+ sonorant - low rounded high back]>_/_',
'nn>nun/_',
'[+ nasal][+ obstruent]>[+ nasal obstruent aspirated ]/#_',
'[+ sonorant rounded]>[+ sonorant - rounded]/_#'
]
}
],
phones: {
a: {
grapheme: 'a', features: {
sonorant: true, back: true, low: true, high: false, rounded: false
}
},
u: {
grapheme: 'u', features: {
sonorant: true, back: true, low: false, high: true, rounded: true,
}
},
ɯ: {
grapheme: 'ɯ', features: {
sonorant: true, back: true, low: false, high: true, rounded: false,
}
},
ə: {
grapheme: 'ə', features: {
sonorant: true, low: false, rounded: false, high: false, back: false
}
},
t: {
grapheme: 't', features: {
occlusive: true, coronal: true, obstruent: true
},
ʰ: {
grapheme: 'tʰ', features: {
occlusive: true, coronal: true, obstruent: true, aspirated: true
}
}
},
n: {
grapheme: 'n', features: {
sonorant: true, nasal: true, occlusive: true, coronal: true
}
}
},
options: {},
results: {},
errors: {},
features: {}
};
state.features = {
sonorant: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ, state.phones.ə, state.phones.n], negative: [] },
back: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ ], negative: [ state.phones.ə ] },
low: { positive:[ state.phones.a ], negative: [ state.phones.u, state.phones.ɯ, state.phones.ə ] },
high: { positive:[ state.phones.u, state.phones.ɯ ], negative: [ state.phones.a, state.phones.ə ] },
rounded: { positive:[ state.phones.u ], negative: [ state.phones.a, state.phones.ɯ, state.phones.ə ] },
occlusive: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
coronal: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
obstruent: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },
nasal: { positive:[ state.phones.n ], negative: [] },
aspirated: { positive:[ state.phones.t.ʰ ], negative: [] },
}
if(changesArgument > -1) state.epochs[0].changes = state.epochs[0].changes.splice(changesArgument, 1)
return state;
}

View file

@ -0,0 +1,41 @@
// @flow
import type { stateType } from './stateReducer';
type lexemeType = {
lexeme: string,
epoch?: string
}
type addLexemeAction = {
type: 'ADD_LEXEME',
value: lexemeType
}
type setLexiconAction = {
type: 'SET_LEXICON',
value: Array<lexemeType>
}
const makeLexeme = (lexeme: string, epochName: ?string, state: stateType) => {
const newLexeme = {lexeme: lexeme, epoch: state.epochs[0]};
if (epochName) {
const epochIndex = state.epochs.findIndex(epoch => epoch.name === epochName);
if (epochIndex > 0) {
newLexeme.epoch = state.epochs[epochIndex];
};
}
return newLexeme;
}
export type lexiconAction = addLexemeAction | setLexiconAction
export const addLexeme = (state: stateType, action: addLexemeAction): stateType => {
const newLexeme = makeLexeme(action.value.lexeme, action.value.epoch, state);
return {...state, lexicon:[...state.lexicon, newLexeme]}
}
export const setLexicon = (state: stateType, action: setLexiconAction): stateType => {
let newLexicon = action.value;
newLexicon = newLexicon.map(lexeme => makeLexeme(lexeme.lexeme, lexeme.epoch, state));
return {...state, lexicon: newLexicon}
}

View file

@ -2,16 +2,20 @@ import {stateReducer} from './stateReducer';
describe('Lexicon', () => {
const state = {
lexicon: [
{lexeme:'anta', epoch:'epoch 1'},
{lexeme:'anat', epoch:'epoch 1'},
{lexeme:'anət', epoch:'epoch 1'},
{lexeme:'anna', epoch:'epoch 1'},
{lexeme:'tan', epoch:'epoch 1'},
{lexeme:'ənta', epoch:'epoch 1'}
],
epochs: [{name: 'epoch 1'}]
};
epochs: [
{ name: 'epoch 1', changes:[''] },
{ name: 'epoch 2', changes:[''] }
]
}
state.lexicon = [
{lexeme:'anta', epoch:state.epochs[0]},
{lexeme:'anat', epoch:state.epochs[0]},
{lexeme:'anət', epoch:state.epochs[0]},
{lexeme:'anna', epoch:state.epochs[0]},
{lexeme:'tan', epoch:state.epochs[0]},
{lexeme:'ənta', epoch:state.epochs[0]}
]
;
it('lexicon returned unaltered', () => {
const action = {type: ''};
@ -20,12 +24,12 @@ describe('Lexicon', () => {
it('lexicon addition without epoch returns updated lexicon with default epoch', () => {
const action = {type: 'ADD_LEXEME', value: {lexeme:'ntʰa'}}
expect(stateReducer(state, action)).toEqual({...state, lexicon:[...state.lexicon, {lexeme:'ntʰa', epoch:'epoch 1'}]});
expect(stateReducer(state, action)).toEqual({...state, lexicon:[...state.lexicon, {lexeme:'ntʰa', epoch:state.epochs[0]}]});
});
it('lexicon addition with epoch returns updated lexicon with correct epoch', () => {
const action = {type: 'ADD_LEXEME', value: {lexeme:'ntʰa', epoch: 'epoch 2'}}
expect(stateReducer(state, action)).toEqual({...state, lexicon:[...state.lexicon, action.value]});
expect(stateReducer(state, action)).toEqual({...state, lexicon:[...state.lexicon, {lexeme:'ntʰa', epoch:state.epochs[1]}]});
});
it('lexicon set returns updated lexicon with correct epoch', () => {
@ -36,15 +40,20 @@ describe('Lexicon', () => {
{lexeme:'anna', epoch:'epoch 1'}
]
const action = {type: 'SET_LEXICON', value: newLexicon}
expect(stateReducer(state, action)).toEqual({...state, lexicon:newLexicon});
expect(stateReducer(state, action)).toEqual({...state, lexicon:[
{lexeme:'anta', epoch:state.epochs[0]},
{lexeme:'anat', epoch:state.epochs[0]},
{lexeme:'anət', epoch:state.epochs[0]},
{lexeme:'anna', epoch:state.epochs[0]}
]});
});
it('lexicon set with no epoch returns updated lexicon with defaul epoch', () => {
const newLexicon = [
{lexeme:'anta', epoch:'epoch 1'},
{lexeme:'anat', epoch:'epoch 1'},
{lexeme:'anət', epoch:'epoch 2'},
{lexeme:'anna', epoch:'epoch 1'}
{lexeme:'anta', epoch:state.epochs[0]},
{lexeme:'anat', epoch:state.epochs[0]},
{lexeme:'anət', epoch:state.epochs[1]},
{lexeme:'anna', epoch:state.epochs[0]}
]
const inputLexicon = [
{lexeme:'anta'},

View file

@ -0,0 +1,57 @@
// @flow
import type { stateType } from './stateReducer';
export type resultsAction = {
type: 'RUN'
}
const findFeatures = (phones: {}, lexeme:string): [] => {
let featureBundle = []
let lastIndex = lexeme.length - 1;
let node = {};
[...lexeme].forEach((graph, index) => {
if (!index) return node = phones[graph]
if (index === lastIndex) return node[graph]
? featureBundle.push(node[graph])
: featureBundle.push(node, phones[graph])
if (!node[graph] && node.features) {
featureBundle.push(node)
return node = phones[graph]
}
if (!node[graph])
return node = node[graph]
})
return featureBundle;
}
const decomposeRule = (rule: string): string[] => {
let decomposedChange = rule.split('>');
decomposedChange = [decomposedChange[0], ...decomposedChange[1].split('/')]
decomposedChange = [decomposedChange[0], decomposedChange[1], ...decomposedChange[2].split('_')];
return [...decomposedChange];
}
export const run = (state: stateType, action: resultsAction): stateType => {
// ! one epoch only
// rule 0 '[+ occlusive - nasal]>[+ occlusive nasal]/n_'
let ruleBundle = state.epochs[0].changes;
ruleBundle = ruleBundle.map(rule => decomposeRule(rule))
ruleBundle.map(rule => {
rule.forEach(position => {
console.log(position)
})
})
let featurePhoneBundle = state.lexicon.map(lexeme => findFeatures(state.phones, lexeme))
console.log(featurePhoneBundle)
ruleBundle.forEach(rule => {
featurePhoneBundle.map(featurePhone => {
// if (findRules(featurePhone, )
})
})
let results = [];
return {...state, results: { pass: state.epochs[0].name, results } }
}

View file

@ -1,4 +1,5 @@
import {stateReducer, initState} from './stateReducer';
import {stateReducer} from './stateReducer';
import {initState} from './stateReducer.init';
describe('Results', () => {
let state = {};