From c8f6b653025b2976f14b1d0ad2304c2f56c3e8b7 Mon Sep 17 00:00:00 2001 From: Sorrel Bri Date: Wed, 11 Dec 2019 22:19:54 -0800 Subject: [PATCH] refactor to break stateReducer into modules for each property of state --- .flowconfig | 2 +- report.20191129.153032.5120.0.001.json | 675 ---------------------- src/PhonoChangeApplier.js | 3 +- src/reducers/stateReducer.epochs.js | 30 + src/reducers/stateReducer.epochs.test.js | 14 +- src/reducers/stateReducer.features.js | 75 +++ src/reducers/stateReducer.init.js | 84 +++ src/reducers/stateReducer.js | 237 +------- src/reducers/stateReducer.lexicon.js | 41 ++ src/reducers/stateReducer.lexicon.test.js | 43 +- src/reducers/stateReducer.results.js | 57 ++ src/reducers/stateReducer.results.test.js | 3 +- 12 files changed, 351 insertions(+), 913 deletions(-) delete mode 100644 report.20191129.153032.5120.0.001.json create mode 100644 src/reducers/stateReducer.epochs.js create mode 100644 src/reducers/stateReducer.features.js create mode 100644 src/reducers/stateReducer.init.js create mode 100644 src/reducers/stateReducer.lexicon.js create mode 100644 src/reducers/stateReducer.results.js diff --git a/.flowconfig b/.flowconfig index ce05603..d988226 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,6 +11,6 @@ [lints] [options] -; all=true +; all=true [strict] diff --git a/report.20191129.153032.5120.0.001.json b/report.20191129.153032.5120.0.001.json deleted file mode 100644 index 8702aca..0000000 --- a/report.20191129.153032.5120.0.001.json +++ /dev/null @@ -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, std::__1::allocator > const&, v8::Local) [/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" - ] -} \ No newline at end of file diff --git a/src/PhonoChangeApplier.js b/src/PhonoChangeApplier.js index 532c298..66db158 100644 --- a/src/PhonoChangeApplier.js +++ b/src/PhonoChangeApplier.js @@ -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( diff --git a/src/reducers/stateReducer.epochs.js b/src/reducers/stateReducer.epochs.js new file mode 100644 index 0000000..324d57c --- /dev/null +++ b/src/reducers/stateReducer.epochs.js @@ -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 + } +} + +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]} +} \ No newline at end of file diff --git a/src/reducers/stateReducer.epochs.test.js b/src/reducers/stateReducer.epochs.test.js index ef3d463..c79682a 100644 --- a/src/reducers/stateReducer.epochs.test.js +++ b/src/reducers/stateReducer.epochs.test.js @@ -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: ['']} ] } ); diff --git a/src/reducers/stateReducer.features.js b/src/reducers/stateReducer.features.js new file mode 100644 index 0000000..d4239d5 --- /dev/null +++ b/src/reducers/stateReducer.features.js @@ -0,0 +1,75 @@ +// @flow +import type { stateType } from './stateReducer'; + +export type featureAction = { + type: "ADD_FEATURE", + value: { + positivePhones: Array, + negativePhones: Array, + 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} +} \ No newline at end of file diff --git a/src/reducers/stateReducer.init.js b/src/reducers/stateReducer.init.js new file mode 100644 index 0000000..7fd4aa5 --- /dev/null +++ b/src/reducers/stateReducer.init.js @@ -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; +} \ No newline at end of file diff --git a/src/reducers/stateReducer.js b/src/reducers/stateReducer.js index e03273b..aca0046 100644 --- a/src/reducers/stateReducer.js +++ b/src/reducers/stateReducer.js @@ -1,7 +1,18 @@ // @flow -type stateType = { - lexicon: Array, - epochs: Array}>, +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, phones: {[key: string]: phoneType}, options: {}, results: {}, @@ -9,6 +20,10 @@ type stateType = { features: featureType } +type epochType = { + name: string, changes: Array +} + type phoneType = { grapheme: string, features: {[key: string]: boolean} @@ -18,239 +33,39 @@ type featureType = { [key: string]: {[key: string]: Array} } -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; -} \ No newline at end of file diff --git a/src/reducers/stateReducer.lexicon.js b/src/reducers/stateReducer.lexicon.js new file mode 100644 index 0000000..2d71efa --- /dev/null +++ b/src/reducers/stateReducer.lexicon.js @@ -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 +} + +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} +} \ No newline at end of file diff --git a/src/reducers/stateReducer.lexicon.test.js b/src/reducers/stateReducer.lexicon.test.js index 75da307..5b2f83e 100644 --- a/src/reducers/stateReducer.lexicon.test.js +++ b/src/reducers/stateReducer.lexicon.test.js @@ -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'}, diff --git a/src/reducers/stateReducer.results.js b/src/reducers/stateReducer.results.js new file mode 100644 index 0000000..76df8b5 --- /dev/null +++ b/src/reducers/stateReducer.results.js @@ -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 } } +} \ No newline at end of file diff --git a/src/reducers/stateReducer.results.test.js b/src/reducers/stateReducer.results.test.js index 6aee4a7..7bdab9b 100644 --- a/src/reducers/stateReducer.results.test.js +++ b/src/reducers/stateReducer.results.test.js @@ -1,4 +1,5 @@ -import {stateReducer, initState} from './stateReducer'; +import {stateReducer} from './stateReducer'; +import {initState} from './stateReducer.init'; describe('Results', () => { let state = {};