1 line
No EOL
62 KiB
Text
1 line
No EOL
62 KiB
Text
{"version":3,"sources":["components/ProtoLang.js","components/Features.js","components/SoundChangeSuite.js","components/Epochs.js","components/Options.js","components/Output.js","reducers/reducer.lexicon.js","reducers/reducer.features.js","reducers/reducer.results.js","reducers/reducer.init.js","reducers/reducer.js","reducers/reducer.epochs.js","reducers/reducer.options.js","PhonoChangeApplier.js","App.js","serviceWorker.js","index.js"],"names":["ProtoLang","lexicon","dispatch","className","data-testid","name","cols","rows","value","map","property","object","join","renderLexicon","onChange","e","console","log","target","split","line","lexeme","trim","epoch","type","parseNewPhones","somePhones","phone","buildAddFeatureAction","newPositivePhones","newNegativePhones","feature","positivePhones","negativePhones","Features","phones","features","useState","setFeature","setNewPositivePhones","setNewNegativePhones","featureObject","getProperty","featureMap","index","featureName","Object","keys","plus","minus","key","getFeatureMapJSX","plusPhones","positive","minusPhones","negative","getFeatureMap","parsePhonesFromFeatureObject","htmlFor","id","onClick","dispatchFunction","actionBuilder","actionParameters","preventDefault","handleClickDispatch","SoundChangeSuite","props","changes","setEpoch","changeHandler","cb","updateEpoch","epochIndex","useEffect","change","onSubmit","removeEpoch","Epochs","epochs","epochName","dispatchValue","renderAddEpochButton","length","addEpoch","renderEpochs","Options","options","load","setLoad","handleRadioChange","option","setValue","handleFormSubmit","checked","output","localStorage","phonoChange","ls","get","priorRun","Output","results","renderDefault","i","pass","renderResults","makeLexeme","state","newLexeme","findIndex","findPhone","reduce","node","graph","addFeatureToPhone","featureKey","featureValue","forEach","errorMessage","location","err","prefix","separator","decomposeRule","rule","match","lintRule","position","newFeatures","environment","pre","post","isUnknownFeatureToken","token","getFeatures","phoneme","featureBoolean","featureMatch","unknownTokens","filter","doesFeatureRuleContainUnknownToken","bool","mapToPositiveAndNegativeFeatures","mapStringToFeatures","ruleString","ruleBrackets","v","featureBundle","lastIndex","push","findFeaturesFromGrapheme","decomposeRules","ruleBundle","mapRuleBundleToFeatureBundle","isEnvironmentBoundByRule","phonemeFeatures","ruleFeatures","ruleFeature","entries","hasOwnProperty","isPhonemeBoundByRule","getEntries","reduceFeatureValues","newPhoneme","newFeature","newValue","transformPhoneme","newPhonemeFeatures","newPhonemeCandidates","transformFeatureValues","candidates","candidatesSubset","array","candidate","includes","isObjectWithPropertyInArray","transformLexeme","lexemeBundle","find","val","slice","grapheme","transformLexemeInitial","transformLexemeCoda","formBundleFromLexicon","findFeaturesFromLexeme","stringifyLexeme","stringifyResults","passResults","run","action","_","lexiconBundle","parent","result","transformLexicon","errors","initState","changesArgument","a","sonorant","back","low","high","rounded","u","ɯ","ə","t","occlusive","coronal","obstruent","nasal","ʰ","aspirated","n","save","splice","stateReducer","addLexeme","newLexicon","setLexicon","newEpoch","mutatedEpochs","newFeatureName","newPhoneObject","phoneObject","addPhones","positivePhone","negativePhone","addFeature","mutatedState","setOptions","PhonoChangeApplier","useReducer","phonemes","App","Boolean","window","hostname","ReactDOM","render","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.00d4b63c.chunk.js","sourcesContent":["import React from 'react';\nimport './ProtoLang.scss';\n\nconst ProtoLang = ({ lexicon, dispatch }) => {\n const getProperty = property => object => object[property];\n const renderLexicon = () => {\n if (!lexicon) return '';\n // Code for optionally rendering epoch name with lexeme\n // `\\t#${lexeme.epoch.name}`\n return lexicon.map(getProperty('lexeme')).join('\\n');\n }\n\n return (\n <div className=\"ProtoLang\" data-testid=\"ProtoLang\">\n <h3>Proto Language Lexicon</h3>\n <br />\n <form data-testid=\"ProtoLang-Lexicon\">\n <textarea\n name=\"lexicon\" \n cols=\"30\"\n rows=\"10\"\n data-testid=\"ProtoLang-Lexicon__textarea\"\n value={renderLexicon()}\n onChange={e=> {\n console.log(e.target.value.split(/\\n/).map(line => {\n const lexeme = line.split('#')[0].trim();\n const epoch = line.split('#')[1] || '';\n return { lexeme, epoch }\n }))\n dispatch({\n type: 'SET_LEXICON', \n value: e.target.value.split(/\\n/).map(line => {\n const lexeme = line.split('#')[0].trim();\n const epoch = line.split('#')[1] || '';\n return { lexeme, epoch }\n })\n })\n }\n }>\n </textarea>\n </form>\n </div>\n );\n}\n\nexport default ProtoLang;","// @flow\nimport React, {useState} from 'react';\nimport './Features.scss';\n\nimport type { featureAction } from '../reducers/reducer.features';\n\nconst parsePhonesFromFeatureObject = featureObject => {\n const getProperty = property => object => object[property]\n \n const getFeatureMap = (featureObject) => {\n return Object.keys(featureObject).map(feature => {\n const plusPhones = featureObject[feature].positive.map(getProperty('grapheme')).join(' / ');\n const minusPhones = featureObject[feature].negative.map(getProperty('grapheme')).join(' / ');\n return {[feature]: {plus: plusPhones, minus: minusPhones}}\n })\n }\n\n const getFeatureMapJSX = (featureMap) => {\n return featureMap.map((feature, index) => {\n const featureName = Object.keys(feature);\n const { plus, minus } = feature[featureName];\n return (\n <li key={`feature__${featureName}`}>\n <span className=\"feature--names-and-phones\">\n <span className=\"feature--feature-name\"> \n {`[+ ${featureName}]`}\n </span>\n <span className=\"feature--feature-phones\">\n {plus}\n </span>\n </span>\n <span className=\"feature--names-and-phones\">\n <span className=\"feature--feature-name\"> \n {`[- ${featureName}]`}\n </span>\n <span className=\"feature--feature-phones\">\n {minus}\n </span>\n </span>\n </li>\n )\n })\n }\n\n const featureMap = getFeatureMap(featureObject);\n const featureMapJSX = getFeatureMapJSX(featureMap);\n return featureMapJSX;\n}\n\nconst parseNewPhones = somePhones => {\n if (somePhones === '') return [''];\n return somePhones.split('/').map(phone => phone.trim());\n}\n\nconst handleClickDispatch = e => dispatchFunction => actionBuilder => actionParameters => {\n e.preventDefault();\n return dispatchFunction(actionBuilder(actionParameters));\n}\n\nconst buildAddFeatureAction = ([newPositivePhones, newNegativePhones, feature]): featureAction => (\n {\n type: \"ADD_FEATURE\",\n value: {\n positivePhones: parseNewPhones(newPositivePhones),\n negativePhones: parseNewPhones(newNegativePhones),\n feature\n }\n }\n)\n\nconst Features = ({ phones, features, dispatch }) => {\n const [feature, setFeature] = useState('aspirated')\n const [ newPositivePhones, setNewPositivePhones ] = useState('tʰ / pʰ / kʰ');\n const [ newNegativePhones, setNewNegativePhones ] = useState('t / p / k');\n \n const newFeaturesSubmit = e => {\n e.preventDefault();\n setFeature('');\n setNewPositivePhones('');\n setNewNegativePhones('');\n }\n\n return (\n <div className=\"Features\" data-testid=\"Features\">\n \n <h3>Phonetic Features</h3>\n \n <ul className=\"Features__list\" data-testid=\"Features-list\">\n {phones ? <>{parsePhonesFromFeatureObject(features)}</> : <></>}\n </ul>\n\n <form className=\"Features__form\" data-testid=\"Features-form\">\n <input \n type=\"text\" name=\"feature\" \n value={feature} onChange={e=> setFeature(e.target.value)}\n ></input>\n\n {/* ! Positive Phones */}\n <label htmlFor=\"positive-phones\">+\n <input \n id=\"positive-phones\"\n type=\"text\" name=\"phonemes\" \n value={newPositivePhones} onChange={e=> setNewPositivePhones(e.target.value)}\n ></input>\n </label>\n \n {/* ! Negative Phones */}\n <label htmlFor=\"negative-phones\">-\n <input \n id=\"negative-phones\"\n type=\"text\" name=\"phonemes\" \n value={newNegativePhones} onChange={e=> setNewNegativePhones(e.target.value)}\n ></input>\n </label>\n\n <input \n type=\"submit\" \n onClick={e => handleClickDispatch(e)(dispatch)(buildAddFeatureAction)([newPositivePhones, newNegativePhones, feature])} \n value=\"Add feature\"\n ></input>\n </form>\n\n </div>\n );\n}\n\nexport default Features;","import React, { useState, useEffect } from 'react';\nimport './SoundChangeSuite.scss';\n\nconst SoundChangeSuite = props => {\n const [ epoch, setEpoch ] = useState(props.epoch ? props.epoch : {name:'', changes:['']});\n \n const changeHandler = (e,cb) => {\n cb(e);\n props.updateEpoch(epoch, props.epochIndex);\n }\n \n useEffect(() => {\n props.updateEpoch(epoch, props.epochIndex);\n }, [epoch])\n\n return (\n <>\n <h4>{epoch.name}</h4>\n <form className=\"SoundChangeSuite__form\" data-testid={`${epoch.name}_SoundChangeSuite_changes`}>\n \n <textarea \n name=\"epoch\" \n id=\"\" cols=\"30\" rows=\"1\" \n value={epoch.name} \n onChange={e=>changeHandler(\n e, () => {\n setEpoch({...epoch, name:e.target.value})\n }\n )} \n ></textarea>\n \n <textarea \n name=\"changes\" \n id=\"\" cols=\"30\" rows=\"10\" \n value={epoch.changes.join('\\n')} \n onChange={e=> changeHandler(\n e, ()=>setEpoch(\n {...epoch, changes:e.target.value.split(/\\n/).map(change=>change === ' ' \n ? '[+ feature]>[- feature]/_#' \n : change\n )}\n )\n )}\n ></textarea>\n </form>\n <form onSubmit={e=>props.removeEpoch(e, epoch.name)}>\n <input type=\"submit\" name=\"remove-epoch\" value={`remove ${epoch.name}`}></input>\n </form>\n </>\n );\n}\n\nexport default SoundChangeSuite;","import React from 'react';\nimport './Epochs.scss';\n\nimport SoundChangeSuite from './SoundChangeSuite';\nimport { render } from 'react-dom';\n\n\n\nconst Epochs = ({epochs, dispatch}) => {\n \n const addEpoch = e => {\n e.preventDefault()\n let index = epochs.length + 1;\n dispatch({\n type: 'ADD_EPOCH',\n value: {name: `Epoch ${index}`}\n })\n }\n\n const removeEpoch = (e, epochName) => {\n e.preventDefault()\n dispatch({\n type: 'REMOVE_EPOCH',\n value: {name: epochName}\n });\n }\n\n const updateEpoch = (epoch, epochIndex) => {\n const dispatchValue = {\n name: epoch.name,\n index: epochIndex,\n changes: epoch.changes\n }\n dispatch({\n type: \"SET_EPOCH\",\n value: dispatchValue\n })\n }\n \n const renderAddEpochButton = index => {\n if (index === epochs.length - 1 ) return (\n <form onSubmit={e=>addEpoch(e)}>\n <input type=\"submit\" name=\"add-epoch\" value=\"Add Epoch\" ></input>\n </form>\n )\n return <></>\n }\n\n const renderEpochs = () => {\n if (epochs) return epochs.map((epoch, index) => (\n <div \n className=\"SoundChangeSuite\" \n data-testid={`${epoch.name}_SoundChangeSuite`}\n key={`epoch-${index}`}\n >\n <SoundChangeSuite \n epochIndex={index} epoch={epoch} \n updateEpoch={updateEpoch} removeEpoch={removeEpoch}\n // error={errors[epoch.name]}\n />\n {renderAddEpochButton(index)}\n </div>\n ));\n }\n\n return (\n <>\n { renderEpochs() }\n </>\n );\n}\n\nexport default Epochs;","import React, { useState } from 'react';\nimport './Options.scss';\nimport ls from 'local-storage';\n\nconst Options = ({ options, dispatch }) => {\n const [ load, setLoad ] = useState('');\n\n const handleRadioChange = e => {\n const { name, id } = e.target;\n dispatch({\n type: 'SET_OPTIONS',\n value: {\n option: name,\n setValue: id\n }\n });\n }\n \n const handleFormSubmit = (e, options) => {\n e.preventDefault();\n dispatch({\n type: 'RUN',\n value: options\n });\n }\n\n return (\n <div className=\"Options\" data-testid=\"Options\">\n <h3>Modeling Options</h3>\n\n <form onSubmit={e=>handleFormSubmit(e, options)} data-testid=\"Options-form\">\n \n {/* <h5>Output</h5> */}\n\n <input \n type=\"radio\" name=\"output\" id=\"default\" \n checked={options ? options.output === 'default' : true}\n onChange={e=>handleRadioChange(e)}\n />\n <label htmlFor=\"default\">Default \n <span className=\"Options__output-example\"> output</span>\n </label>\n \n <input \n type=\"radio\" name=\"output\" id=\"proto\" \n checked={options ? options.output === 'proto' : false}\n onChange={e=>handleRadioChange(e)}\n />\n <label htmlFor=\"proto\">Proto \n <span className=\"Options__output-example\"> output [proto]</span>\n </label>\n \n <input \n type=\"radio\" name=\"output\" id=\"diachronic\" \n checked={options ? options.output === 'diachronic' : false}\n onChange={e=>handleRadioChange(e)}\n />\n <label htmlFor=\"diachronic\">Diachronic \n <span className=\"Options__output-example\"> *proto > *epoch > output</span>\n </label>\n \n <input type=\"submit\" value=\"Run Changes\"></input>\n </form>\n\n\n <form onSubmit={()=>{}}>\n <label>\n Load from a prior run:\n <select value={load} onChange={e=>setLoad(e.target.value)}>\n {localStorage.phonoChange \n ? ls.get('phonoChange').map(priorRun => {\n return <option key={priorRun.name} value={priorRun.name}>{priorRun.name}</option>\n }\n ) : <></>}\n </select>\n </label>\n <input type=\"submit\" value=\"Submit\" />\n </form>\n </div>\n );\n}\n\nexport default Options;","import React from 'react';\nimport './Output.scss';\n\nconst Output = props => {\n const { results, options } = props;\n const renderResults = () => {\n switch(options.output) {\n case 'default':\n return renderDefault();\n default:\n return <></>\n }\n }\n\n const renderDefault = () => {\n return results.map((epoch, i) => {\n const lexicon = epoch.lexicon.map((lexeme, i) => <span key={`${epoch.pass}-${i}`}>{lexeme}</span>);\n return (\n <div key={`epoch-${i}`} className=\"Output-epoch\">\n <h5>{epoch.pass}</h5>\n <p className=\"lexicon\">{lexicon}</p>\n </div>\n )\n })\n }\n return (\n <div className=\"Output\" data-testid=\"Output\">\n <h3>Results of Run</h3>\n\n <div data-testid=\"Output-lexicon\" className=\"Output__container\">\n {results && results.length ? renderResults() : <></>}\n </div>\n </div>\n );\n}\n\nexport default Output;","// @flow\nimport type { stateType } from './reducer';\n\ntype lexemeType = {\n lexeme: string,\n epoch?: string\n}\n\ntype addLexemeAction = {\n type: 'ADD_LEXEME',\n value: lexemeType\n}\n\ntype setLexiconAction = {\n type: 'SET_LEXICON',\n value: Array<lexemeType>\n}\n\nconst makeLexeme = (lexeme: string, epochName: ?string, state: stateType) => {\n const newLexeme = {lexeme: lexeme, epoch: state.epochs[0]};\n if (epochName) {\n const epochIndex = state.epochs.findIndex(epoch => epoch.name === epochName);\n if (epochIndex > 0) {\n newLexeme.epoch = state.epochs[epochIndex];\n };\n }\n return newLexeme;\n}\n\nexport type lexiconAction = addLexemeAction | setLexiconAction\n\nexport const addLexeme = (state: stateType, action: addLexemeAction): stateType => {\n const newLexeme = makeLexeme(action.value.lexeme, action.value.epoch, state);\n return {...state, lexicon:[...state.lexicon, newLexeme]}\n}\n\nexport const setLexicon = (state: stateType, action: setLexiconAction): stateType => {\n let newLexicon = action.value;\n newLexicon = newLexicon.map(lexeme => makeLexeme(lexeme.lexeme, lexeme.epoch, state));\n return {...state, lexicon: newLexicon}\n}","// @flow\nimport type { stateType } from './reducer';\n\nexport type featureAction = {\n type: \"ADD_FEATURE\",\n value: {\n positivePhones: Array<string>,\n negativePhones: Array<string>,\n feature: string\n }\n}\n\nconst addPhones = (phones: {}, phone: string): {} => {\n let node = {};\n\n phone.split('').forEach((graph, index) => {\n if (index) node[graph] = {}\n if (!index && !phones[graph]) phones[graph] = {} \n node = index === 0 ? phones[graph] : node[graph];\n if (index === phone.length - 1) node.grapheme = phone;\n })\n\n return phones;\n}\n\nconst findPhone = (phones: {}, phone: string): {} => {\n return phone\n .split('')\n .reduce((node, graph, index) => {\n node = index === 0 ? phones[graph] : node[graph];\n return node;\n }, {});\n}\n\nconst addFeatureToPhone = (\n phones: {}, phone: string, featureKey: string, featureValue: boolean\n): {} => {\n let node = {}\n phone.split('').forEach((graph, index) => {\n node = index === 0 ? phones[graph] : node[graph];\n \n if (index === phone.split('').length - 1) {\n node.features = {...node.features, [featureKey]: featureValue}\n }\n });\n return phones;\n}\n\nexport const addFeature = (state: stateType, action: featureAction): stateType => {\n let positivePhones = action.value.positivePhones || [];\n let negativePhones = action.value.negativePhones || [];\n let newFeatureName = action.value.feature;\n let newPhoneObject = [\n ...positivePhones, ...negativePhones\n ]\n .reduce((phoneObject, phone) => addPhones(phoneObject, phone), state.phones)\n \n if (positivePhones) {\n\n positivePhones.reduce(\n (phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, true)\n , newPhoneObject\n );\n\n positivePhones = positivePhones.map( positivePhone => findPhone(newPhoneObject, positivePhone) )\n }\n \n if (negativePhones) {\n \n negativePhones.reduce(\n (phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, false)\n , newPhoneObject\n );\n \n negativePhones = negativePhones.map( negativePhone => findPhone(newPhoneObject, negativePhone) )\n }\n \n let newFeature = {[action.value.feature]: {positive: positivePhones, negative: negativePhones}};\n return {...state, features:{...state.features, ...newFeature}, phones: newPhoneObject}\n}","// @flow\nimport type { stateType, epochType, phoneType } from './reducer';\n\nexport type resultsAction = {\n type: 'RUN'\n}\n\nexport type decomposedRulesType = [\n {\n environment: {\n pre: [{[key: string]: boolean}],\n position: [{[key: string]: boolean}],\n post: [{[key: string]: boolean}]\n },\n newFeatures: [{[key: string]: boolean}]\n }\n]\n\ntype ruleBundle = {\n environment: {\n pre: string,\n position: string,\n post: string\n },\n newFeatures: string\n}\n\nconst getProperty = property => object => object[property]\n\nconst findFeaturesFromLexeme = (phones: {}, lexeme:string): [] => {\n let featureBundle = []\n let lastIndex = lexeme.length - 1;\n let node = {};\n [...lexeme].forEach((graph, index) => {\n if (!index) return node = phones[graph]\n if (index === lastIndex) return node[graph] \n ? featureBundle.push(node[graph])\n : featureBundle.push(node, phones[graph])\n if (!node[graph] && node.features) {\n featureBundle.push(node)\n return node = phones[graph]\n }\n if (!node[graph])\n return node = node[graph]\n })\n return featureBundle;\n}\n\nconst findFeaturesFromGrapheme = (phones: {}, lexeme:string): [] => {\n let featureBundle = []\n let lastIndex = lexeme.length - 1;\n let node = {};\n [...lexeme].forEach((graph, index) => {\n if (!index && !lastIndex) featureBundle.push(phones[graph].features)\n if (!index) return node = phones[graph]\n if (index === lastIndex) return node[graph] \n ? featureBundle.push(node[graph])\n : featureBundle.push(node, phones[graph])\n if (!node[graph] && node.features) {\n featureBundle.push(node)\n return node = phones[graph]\n }\n if (!node[graph])\n return node = node[graph]\n })\n return featureBundle;\n}\n\nconst errorMessage = ([prefix, separator], location, err) => `${prefix}${location}${separator}${err}`\n\nconst lintRule = (rule) => {\n if (!rule.match(/>/g)) throw `Insert '>' operator between target and result`\n if (!rule.match(/\\//g)) throw `Insert '/' operator between change and environment`\n if (!rule.match(/_/g)) throw `Insert '_' operator in environment`\n if (rule.match(/>/g).length > 1) throw `Too many '>' operators`\n if (rule.match(/\\//g).length > 1) throw `Too many '/' operators`\n if (rule.match(/_/g).length > 1) throw `Too many '_' operators`\n return rule.split(/>|\\/|_/g);\n}\n\nconst decomposeRule = (rule: string, index: number): ruleBundle => {\n try {\n // splits rule at '>' '/' and '_' substrings resulting in array of length 4\n const [position, newFeatures, pre, post] = lintRule(rule); \n return { environment: { pre, position, post }, newFeatures }\n } catch (err) {\n throw errorMessage`Error in line ${index + 1}: ${err}`;\n }\n}\n\nconst isUnknownFeatureToken = token => token !== '-' && token !== '+' && token !== ']' && token !== '[' && token !== ' ';\n\nconst doesFeatureRuleContainUnknownToken = features => {\n const unknownTokens = features\n .match(/\\W/g)\n .filter(isUnknownFeatureToken)\n if (unknownTokens.length) throw `Unknown token '${unknownTokens[0]}'`;\n return true\n}\n\nconst reduceFeaturesToBoolean = bool => (map, feature) => ({...map, [feature]: bool})\n\nconst getFeatures = (phoneme: string, featureBoolean): {} => {\n try {\n const featureMatch = featureBoolean\n // regEx to pull positive features\n ? /(?=\\+.).*(?<=\\-)|(?=\\+.).*(?!\\-).*(?<=\\])/g \n // regEx to pull negative features\n : /(?=\\-.).*(?<=\\+)|(?=\\-.).*(?!\\+).*(?<=\\])/g\n const [ features ] = phoneme.match(featureMatch) || [ null ];\n if (features) {\n doesFeatureRuleContainUnknownToken(features)\n return features\n .trim()\n .match(/\\w+/g)\n .reduce(reduceFeaturesToBoolean(featureBoolean), {})\n }\n return {}\n } catch (err) {\n throw err;\n }\n}\n\nconst mapToPositiveAndNegativeFeatures = phoneme => (\n { ...getFeatures(phoneme, true), ...getFeatures(phoneme, false) } )\n\nconst mapStringToFeatures = (ruleString, phones) => {\n if (ruleString) {\n if (ruleString === '.') return [];\n if (ruleString === '#') return ['#']\n if (ruleString === '0') return [];\n const ruleBrackets = ruleString.match(/\\[.*\\]/)\n try {\n if (ruleBrackets) {\n return ruleString\n .split('[')\n // filter out empty strings\n .filter(v => v)\n .map(mapToPositiveAndNegativeFeatures)\n }\n return findFeaturesFromGrapheme(phones, ruleString);\n } catch (err) {\n throw err;\n }\n }\n return {};\n}\n\nconst mapRuleBundleToFeatureBundle = phones => ( ruleBundle, index ) => {\n // for each object in ruleBundle, map values to array of objects with feature-boolean key-value pairs\n try {\n const { newFeatures, environment:{ pre, position, post } } = ruleBundle;\n return {\n environment: {\n pre: mapStringToFeatures(pre, phones),\n position: mapStringToFeatures(position, phones),\n post: mapStringToFeatures(post, phones),\n },\n newFeatures: mapStringToFeatures(newFeatures, phones)\n }\n } catch (err) {\n throw errorMessage`Error in line ${index + 1}: ${err}`;\n }\n}\n\nexport const decomposeRules = (epoch: epochType, phones: {[key: string]: phoneType}): decomposedRulesType => {\n const { changes } = epoch\n try {\n return changes\n .map(decomposeRule)\n .map(mapRuleBundleToFeatureBundle(phones));\n } catch (err) {\n return err;\n }\n}\n\nconst isPhonemeBoundByRule = phonemeFeatures => (ruleFeature, index) => {\n const phoneme = phonemeFeatures[index].features;\n return Object.entries(ruleFeature).reduce((bool, [feature, value]) => {\n if (!bool) return false;\n if (!phoneme.hasOwnProperty(feature)) return false;\n if (!phoneme[feature] && !value) return true;\n if (phoneme[feature] !== value) return false;\n return true;\n }, true);\n} \n\nconst isEnvironmentBoundByRule = (phonemeFeatures, ruleFeatures) => {\n if (!ruleFeatures) return true;\n return ruleFeatures.filter(isPhonemeBoundByRule(phonemeFeatures)).length === ruleFeatures.length;\n}\n\nconst getEntries = object => Object.entries(object);\nconst isObjectWithPropertyInArray = (array, property) => candidate => array.map(getProperty(property)).includes(candidate[property]);\nconst transformFeatureValues = features => ([newFeature, newValue]) => features[newFeature][newValue ? 'positive': 'negative'];\nconst reduceFeatureValues = (newPhoneme, [newFeature, newValue]) => ({ ...newPhoneme, [newFeature]: newValue })\n\nconst transformPhoneme = (phoneme, newFeatures, features) => {\n if (!newFeatures) return {}\n const newPhonemeFeatures = getEntries(newFeatures).reduce(reduceFeatureValues, {...phoneme.features});\n const newPhonemeCandidates = getEntries(newPhonemeFeatures).map(transformFeatureValues(features));\n return newPhonemeCandidates\n .reduce((candidates, candidatesSubset, index, array) => candidates.filter(isObjectWithPropertyInArray(candidatesSubset, 'grapheme'))\n , newPhonemeCandidates[newPhonemeCandidates.length - 1])[0];\n}\n\nconst transformLexemeInitial = (newLexeme, pre, post, position, phoneme, index, lexemeBundle, newFeatures, features) => {\n if (index !== pre.length - 1) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule(lexemeBundle.slice(index + position.length, index + post.length + position.length), post)) return [...newLexeme, phoneme];\n const newPhoneme = transformPhoneme(phoneme, newFeatures[0], features);\n // if deletion occurs\n if (!newPhoneme.grapheme) return [ ...newLexeme] ;\n return [...newLexeme, newPhoneme];\n}\n\nconst transformLexemeCoda = (newLexeme, pre, post, position, phoneme, index, lexemeBundle, newFeatures, features) => {\n if (index + post.length !== lexemeBundle.length) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];\n const newPhoneme = transformPhoneme(phoneme, newFeatures[0], features);\n // if deletion occurs\n if (!newPhoneme.grapheme) return [ ...newLexeme] ;\n return [...newLexeme, newPhoneme];\n}\n\nexport const transformLexeme = (lexemeBundle, rule, features) => {\n const {pre, post, position} = rule.environment;\n const newLexeme = lexemeBundle.reduce((newLexeme, phoneme, index) => {\n if (pre.find(val => val === '#')) return transformLexemeInitial(newLexeme, pre, post, position, phoneme, index, lexemeBundle, rule.newFeatures, features);\n if (post.find(val => val === '#')) return transformLexemeCoda(newLexeme, pre, post, position, phoneme, index, lexemeBundle, rule.newFeatures, features);\n if ( index < pre.length || index >= lexemeBundle.length - post.length ) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];\n if (!isEnvironmentBoundByRule(lexemeBundle.slice(index, index + post.length), post)) return [...newLexeme, phoneme];\n const newPhoneme = transformPhoneme(phoneme, rule.newFeatures[0], features);\n // if deletion occurs\n if (!newPhoneme || !newPhoneme.grapheme) return [ ...newLexeme] ;\n return [...newLexeme, newPhoneme];\n }, [])\n return newLexeme;\n}\n\nconst formBundleFromLexicon = lexicon => phones => lexicon.map(({lexeme}) => findFeaturesFromLexeme(phones, lexeme))\n\nconst transformLexicon = lexiconBundle => \n ruleBundle => \n features => \n lexiconBundle.map(lexemeBundle => ruleBundle.reduce(\n (lexeme, rule, i) => transformLexeme(lexeme, rule, features)\n , lexemeBundle\n ))\n\nconst getGraphemeFromEntry = ([_, phoneme]) => phoneme.grapheme\nconst stringifyLexeme = (lexeme) => lexeme.map(getProperty('grapheme')).join('')\nconst stringifyResults = ({lexicon, ...passResults}) => ({...passResults, lexicon: lexicon.map(stringifyLexeme)})\n\nexport const run = (state: stateType, action: resultsAction): stateType => {\n\n // TODO iterate through each epoch\n try {\n const passResults = state.epochs.reduce((results, epoch, _) => {\n const { phones, features, lexicon } = state;\n let lexiconBundle;\n if ( epoch.parent ) {\n lexiconBundle = results.find(result => result.pass === epoch.parent).lexicon\n }\n if (!epoch.parent) {\n lexiconBundle = formBundleFromLexicon(lexicon)(phones); \n }\n const ruleBundle = decomposeRules(epoch, phones);\n const passResults = transformLexicon(lexiconBundle)(ruleBundle)(features)\n const pass = { pass: epoch.name, lexicon: passResults }\n if ( epoch.parent ) pass.parent = epoch.parent;\n return [...results, pass];\n }, []);\n \n const results = passResults.map(stringifyResults);\n console.log(results)\n return {...state, results }\n } catch (err) {\n console.log(err)\n return {...state, errors: err };\n }\n}","// @flow\nimport type { stateType } from './reducer';\n\nexport type initAction = {\n type: \"INIT\"\n}\n\nexport const initState = (changesArgument: number): stateType => {\n const state = {\n epochs: [\n {\n name: 'epoch 1',\n changes: [\n '[+ occlusive - nasal]>[+ occlusive + nasal]/n_.',\n 'a>ɯ/._#',\n '[+ sonorant - low rounded high back]>0/._.',\n '[+ obstruent]>[+ obstruent aspirated ]/#_.',\n '[+ sonorant - rounded]>[+ sonorant + rounded]/._#',\n // 'at>ta/._#'\n ]\n }\n ],\n phones: {\n a: {\n grapheme: 'a', features: {\n sonorant: true, back: true, low: true, high: false, rounded: false\n }\n },\n u: {\n grapheme: 'u', features: {\n sonorant: true, back: true, low: false, high: true, rounded: true, \n }\n },\n ɯ: {\n grapheme: 'ɯ', features: {\n sonorant: true, back: true, low: false, high: true, rounded: false,\n }\n },\n ə: {\n grapheme: 'ə', features: {\n sonorant: true, low: false, rounded: false, high: false, back: false\n }\n },\n t: {\n grapheme: 't', features: {\n occlusive: true, coronal: true, obstruent: true, nasal: false\n },\n ʰ: {\n grapheme: 'tʰ', features: {\n occlusive: true, coronal: true, obstruent: true, aspirated: true\n }\n }\n },\n n: {\n grapheme: 'n', features: {\n sonorant: true, nasal: true, occlusive: true, coronal: true\n }\n }\n },\n options: {\n output: 'default', save: false\n },\n results: [],\n errors: {},\n features: {},\n lexicon: []\n };\n state.features = {\n sonorant: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ, state.phones.ə, state.phones.n], negative: [] },\n back: { positive:[ state.phones.a, state.phones.u, state.phones.ɯ ], negative: [ state.phones.ə ] },\n low: { positive:[ state.phones.a ], negative: [ state.phones.u, state.phones.ɯ, state.phones.ə ] },\n high: { positive:[ state.phones.u, state.phones.ɯ ], negative: [ state.phones.a, state.phones.ə ] },\n rounded: { positive:[ state.phones.u ], negative: [ state.phones.a, state.phones.ɯ, state.phones.ə ] },\n occlusive: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },\n coronal: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },\n obstruent: { positive:[ state.phones.t, state.phones.n, state.phones.t.ʰ ], negative: [] },\n nasal: { positive:[ state.phones.n ], negative: [state.phones.t, state.phones.t.ʰ] },\n aspirated: { positive:[ state.phones.t.ʰ ], negative: [ state.phones.t ] },\n }\n state.lexicon = [\n {lexeme: 'anta', epoch: state.epochs[0]}, \n {lexeme: 'anat', epoch: state.epochs[0]},\n {lexeme: 'anət', epoch: state.epochs[0]},\n {lexeme: 'anna', epoch: state.epochs[0]}, \n {lexeme: 'tan', epoch: state.epochs[0]},\n {lexeme: 'ənta', epoch: state.epochs[0]}\n ]\n\n if(changesArgument > -1) state.epochs[0].changes = state.epochs[0].changes.splice(0, changesArgument)\n\n return state;\n}","// @flow\nimport { addLexeme, setLexicon } from './reducer.lexicon';\nimport type { lexiconAction } from './reducer.lexicon';\nimport { addEpoch, setEpoch, removeEpoch } from './reducer.epochs';\nimport type { epochAction } from './reducer.epochs';\nimport { addFeature } from './reducer.features';\nimport type { featureAction } from './reducer.features';\nimport type { optionsAction } from './reducer.options';\nimport { setOptions } from './reducer.options';\nimport { run } from './reducer.results';\nimport type { resultsAction } from './reducer.results'\nimport { initState } from './reducer.init';\nimport type { initAction } from './reducer.init';\n\nexport type stateType = {\n lexicon: Array<{lexeme: string, epoch: epochType}>,\n epochs: Array<epochType>,\n phones: {[key: string]: phoneType},\n options: {output: string, save: boolean},\n results: [],\n errors: {},\n features: featureType\n}\n\ntype epochType = {\n name: string, changes: Array<string>\n}\n\ntype phoneType = {\n grapheme: string,\n features: {[key: string]: boolean}\n}\n\ntype featureType = {\n [key: string]: {[key: string]: Array<phoneType>}\n}\n\ntype actionType = featureAction | epochAction | initAction | resultsAction | lexiconAction\n\nexport const stateReducer = (state: stateType, action: actionType): stateType => {\n switch (action.type) {\n case 'INIT': {\n return initState();\n }\n \n case 'ADD_LEXEME': return addLexeme(state, action);\n \n case 'SET_LEXICON': return setLexicon(state, action);\n\n case 'ADD_EPOCH': return addEpoch(state, action);\n\n case 'SET_EPOCH': return setEpoch(state, action);\n\n case 'REMOVE_EPOCH': return removeEpoch(state, action);\n\n case 'ADD_FEATURE': return addFeature(state, action);\n\n case 'SET_OPTIONS': return setOptions(state, action);\n\n case 'RUN': return run(state, action);\n\n default: return state;\n }\n}\n","// @flow\nimport type { stateType } from './reducer';\n\nexport type epochAction = {\n type: \"ADD_EPOCH\" | \"SET_EPOCH\" | \"REMOVE_EPOCH\",\n value: {\n index?: number,\n name: string,\n changes?: Array<string>\n }\n}\n\nexport const addEpoch = (state: stateType, action: epochAction): stateType => {\n const newEpoch = { name: action.value.name, changes: action.value.changes || [''] };\n return {...state, epochs: [...state.epochs, newEpoch]}\n}\n\nexport const setEpoch = (state: stateType, action: epochAction): stateType => {\n const index = action.value.index;\n if (typeof index !== 'number') return state;\n \n const mutatedEpochs = state.epochs;\n mutatedEpochs[index].name = action.value.name \n ? action.value.name \n : mutatedEpochs[index].name;\n\n mutatedEpochs[index].changes = action.value.changes \n ? action.value.changes \n : mutatedEpochs[index].changes;\n return {...state, epochs: [...mutatedEpochs]}\n}\n\nexport const removeEpoch = (state: stateType, action: epochAction): stateType => {\n const mutatedEpochs = state.epochs.filter(epoch => epoch.name !== action.value.name )\n return {...state, epochs: [...mutatedEpochs]}\n}","// @flow\nimport type { stateType } from './reducer';\n\nexport type optionAction = {\n type: 'SET_OPTIONS',\n value: {\n option: string,\n setValue: string\n }\n};\n\nexport const setOptions = (state: stateType, action: optionAction): stateType => {\n const option = action.value.option;\n let value = action.value.setValue;\n if (value === 'true') value = true;\n if (value === 'false') value = false;\n const mutatedState = {...state};\n mutatedState.options[option] = value;\n return mutatedState;\n}","import React, { useState, useReducer } from 'react';\nimport './PhonoChangeApplier.scss';\n\nimport ProtoLang from './components/ProtoLang';\nimport Features from './components/Features';\nimport Epochs from './components/Epochs';\nimport Options from './components/Options';\nimport Output from './components/Output';\n\nimport { stateReducer } from './reducers/reducer';\nimport { initState } from './reducers/reducer.init';\n\nconst PhonoChangeApplier = () => {\n const [ state, dispatch ] = useReducer(\n stateReducer,\n {},\n initState\n )\n const { lexicon, phones, phonemes, epochs, options, features, results } = state;\n\n return (\n <div className=\"PhonoChangeApplier\" data-testid=\"PhonoChangeApplier\">\n <ProtoLang lexicon={lexicon} dispatch={dispatch}/>\n <Features phones={phones} features={features} dispatch={dispatch}/>\n <Epochs epochs={epochs} dispatch={dispatch} />\n <Options options={options} dispatch={dispatch}/>\n <Output results={results} options={options} dispatch={dispatch}/>\n </div>\n );\n}\n\nexport default PhonoChangeApplier;","import React from 'react';\nimport './App.css';\nimport PhonoChangeApplier from './PhonoChangeApplier';\n\nfunction App() {\n return (\n <div className=\"App\" data-testid=\"App\">\n <h1>Phono Change Applier</h1>\n <PhonoChangeApplier />\n </div>\n );\n}\n\nexport default App;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.scss';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render(<App />, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""} |