diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..899177c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,4 @@
+node_modules/
+packages/**/node_modules
+packages/**/dist
+packages/**/build
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..75a894a
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "semi": false,
+ "singleQuote": true,
+ "printWidth": 100
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ca7777b..e278ff6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -2,5 +2,18 @@
"typescript.tsdk": "./node_modules/typescript/lib",
"editor.tabSize": 2,
"editor.detectIndentation": false,
- "tslint.nodePath": "./node_modules"
+ "tslint.nodePath": "./node_modules",
+ "[typescript]": {
+ "editor.formatOnSave": true
+ },
+ "[typescriptreact]": {
+ "editor.formatOnSave": true
+ },
+ "prettier.printWidth": 100,
+ "prettier.semi": false,
+ "prettier.singleQuote": true,
+ "prettier.typescriptEnable": [
+ "typescript",
+ "typescriptreact"
+ ],
}
diff --git a/package.json b/package.json
index 2a90f52..f1f7368 100644
--- a/package.json
+++ b/package.json
@@ -5,13 +5,16 @@
"build": "yarn workspace @grammarly/focal build",
"package": "yarn workspace @grammarly/focal pack",
"release": "yarn workspace @grammarly/focal release",
- "test": "yarn workspace @grammarly/focal test && yarn workspace focal-todomvc build && yarn workspace focal-examples build && yarn workspace focal-manual-tests build",
- "postinstall": "yarn build"
+ "test": "yarn workspace @grammarly/focal test && yarn workspace focal-todomvc build && yarn workspace focal-examples build && yarn workspace focal-manual-tests build && yarn prettier:check",
+ "postinstall": "yarn build",
+ "prettier:fix": "prettier --write './packages/**/*.ts?(x)'",
+ "prettier:check": "prettier --list-different './packages/**/*.ts?(x)'"
},
"devDependencies": {
"@grammarly/tslint-config": "0.5.1",
"tslint": "5.20.0",
- "typescript": "3.6.4"
+ "typescript": "3.6.4",
+ "prettier": "1.18.2"
},
"workspaces": [
"packages/focal",
@@ -21,4 +24,4 @@
"resolutions": {
"@types/react": "16.9.11"
}
-}
+}
\ No newline at end of file
diff --git a/packages/examples/all/custom_typings/css/index.d.ts b/packages/examples/all/custom_typings/css/index.d.ts
index 74ad49c..f70595d 100644
--- a/packages/examples/all/custom_typings/css/index.d.ts
+++ b/packages/examples/all/custom_typings/css/index.d.ts
@@ -1,4 +1,4 @@
declare module '*.css' {
const e: any
- export = e;
+ export = e
}
diff --git a/packages/examples/all/src/add-input/index.tsx b/packages/examples/all/src/add-input/index.tsx
index ce4ad92..a11daac 100644
--- a/packages/examples/all/src/add-input/index.tsx
+++ b/packages/examples/all/src/add-input/index.tsx
@@ -25,16 +25,13 @@ const App = (props: { state: Atom }) => {
return (
)
diff --git a/packages/examples/all/src/animated-counter/index.tsx b/packages/examples/all/src/animated-counter/index.tsx
index b3d195f..0b3972b 100644
--- a/packages/examples/all/src/animated-counter/index.tsx
+++ b/packages/examples/all/src/animated-counter/index.tsx
@@ -2,9 +2,7 @@ import * as React from 'react'
import { F, Atom } from '@grammarly/focal'
import * as Model from './model'
-const Counter = ({
- counterState = Atom.create(Model.defaultCounterState)
-}) => {
+const Counter = ({ counterState = Atom.create(Model.defaultCounterState) }) => {
const count = counterState.view('count')
const absoluteCount = counterState.view('absoluteCount')
@@ -13,19 +11,13 @@ const Counter = ({
Count: {count}, abs = {absoluteCount}
-
-
+
+
)
}
-const AnimatedDiv = ({
- counterState = Atom.create(Model.defaultCounterState)
-}) => {
+const AnimatedDiv = ({ counterState = Atom.create(Model.defaultCounterState) }) => {
const displayState = counterState.lens('display')
const count = counterState.view('count')
@@ -36,7 +28,7 @@ const AnimatedDiv = ({
style={{
background: '#f00',
position: 'absolute',
- opacity: count.view(x => Model.shouldHideCounter(x) ? 0.3 : 1.0),
+ opacity: count.view(x => (Model.shouldHideCounter(x) ? 0.3 : 1.0)),
left: count.view(x => x * 25),
transition: 'left 0.5s linear, opacity 1.5s linear'
}}
@@ -46,7 +38,7 @@ const AnimatedDiv = ({
}
}}
>
-
+
)
} else {
@@ -54,20 +46,16 @@ const AnimatedDiv = ({
}
})
- return (
- {animDiv}
- )
+ return {animDiv}
}
-const App = ({
- state = Atom.create(Model.defaultAppState)
-}) => {
+const App = ({ state = Atom.create(Model.defaultAppState) }) => {
const counterState = state.lens('counter')
return (
)
}
diff --git a/packages/examples/all/src/animated-counter/model.ts b/packages/examples/all/src/animated-counter/model.ts
index d897609..478dc7a 100644
--- a/packages/examples/all/src/animated-counter/model.ts
+++ b/packages/examples/all/src/animated-counter/model.ts
@@ -34,8 +34,7 @@ export function shouldHideCounter(count: number) {
export function hideAfterFadeOut(counter: Atom) {
// check if we still should hide
- if (shouldHideCounter(counter.get().count))
- counter.lens('display').set(false)
+ if (shouldHideCounter(counter.get().count)) counter.lens('display').set(false)
}
export function resetCounter(counter: Atom) {
diff --git a/packages/examples/all/src/app.tsx b/packages/examples/all/src/app.tsx
index c5b2c4f..3a88d49 100644
--- a/packages/examples/all/src/app.tsx
+++ b/packages/examples/all/src/app.tsx
@@ -8,7 +8,7 @@ interface ExampleComponent {
declare const require: (path: string) => any
-const examples: { name: string, example: ExampleComponent }[] = [
+const examples: { name: string; example: ExampleComponent }[] = [
'counter',
'clock',
'checkbox',
@@ -45,10 +45,7 @@ examples.forEach(ex => {
defaultState[ex.name] = ex.example.defaultState
})
-export const AppComponent = ({
- state = Atom.create(defaultState)
-}) => {
-
+export const AppComponent = ({ state = Atom.create(defaultState) }) => {
return (
Focal examples
diff --git a/packages/examples/all/src/big-table/index.tsx b/packages/examples/all/src/big-table/index.tsx
index 49a5d02..93bce63 100644
--- a/packages/examples/all/src/big-table/index.tsx
+++ b/packages/examples/all/src/big-table/index.tsx
@@ -1,36 +1,36 @@
import { fromEvent } from 'rxjs'
import { startWith, distinctUntilChanged, map } from 'rxjs/operators'
-import {
- F, Atom, ReadOnlyAtom, bindElementProps, reactiveList
-} from '@grammarly/focal'
+import { F, Atom, ReadOnlyAtom, bindElementProps, reactiveList } from '@grammarly/focal'
import * as React from 'react'
const Window = {
- innerWidth:
- fromEvent(window, 'resize').pipe(
- map(() => window.innerWidth),
- distinctUntilChanged(),
- startWith(0))
+ innerWidth: fromEvent(window, 'resize').pipe(
+ map(() => window.innerWidth),
+ distinctUntilChanged(),
+ startWith(0)
+ )
}
const defaultState = {
tableHeight: 250,
rowHeight: 30,
rowCount: 10000,
- columns: [ 'ID', 'ID * 10', 'Random Number' ]
+ columns: ['ID', 'ID * 10', 'Random Number']
}
function getRowContent(id: number) {
- return [ `${id}`, `${id * 10}`, `${Math.floor(Math.random() * 100)}` ]
+ return [`${id}`, `${id * 10}`, `${Math.floor(Math.random() * 100)}`]
}
function cellWidthStyle(columns: string[]) {
- return Window.innerWidth.pipe(map(innerWidth =>
- ({ width: innerWidth / columns.length + 'px' })))
+ return Window.innerWidth.pipe(map(innerWidth => ({ width: innerWidth / columns.length + 'px' })))
}
function getVisibleRows(
- tableHeight: number, rowHeight: number, rowCount: number, scrollTop: number
+ tableHeight: number,
+ rowHeight: number,
+ rowCount: number,
+ scrollTop: number
) {
return {
begin: Math.floor(scrollTop / rowHeight),
@@ -38,24 +38,30 @@ function getVisibleRows(
}
}
-const THead = (props: { columns: ReadOnlyAtom }) =>
+const THead = (props: { columns: ReadOnlyAtom }) => (
{props.columns.view(cols =>
- cols.map((col, i) =>
- {col}))}
+ cols.map((col, i) => (
+
+ {col}
+
+ ))
+ )}
+)
const TBody = (props: {
- state: Atom,
+ state: Atom
visibleRows: ReadOnlyAtom<{ begin: number; end: number }>
-}) =>
+}) => (
{reactiveList(
props.visibleRows.view(({ begin, end }) =>
- Array.from(Array(end - begin), (_, i) => i + begin)),
- i =>
+ Array.from(Array(end - begin), (_, i) => i + begin)
+ ),
+ i => (
{props.state.view(({ columns }) =>
- getRowContent(i).map((column, i) =>
- {column}))}
+ getRowContent(i).map((column, i) => (
+
+ {column}
+
+ ))
+ )}
+ )
)}
+)
const App = ({
state,
scrollTop = Atom.create(0)
}: {
- state: Atom,
+ state: Atom
scrollTop: Atom
-}) =>
+}) => (
getVisibleRows(m.tableHeight, m.rowHeight, m.rowCount, s)
+ visibleRows: Atom.combine(state, scrollTop, (m, s) =>
+ getVisibleRows(m.tableHeight, m.rowHeight, m.rowCount, s)
)
}}
/>
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/bmi/index.tsx b/packages/examples/all/src/bmi/index.tsx
index b799857..991fcaa 100644
--- a/packages/examples/all/src/bmi/index.tsx
+++ b/packages/examples/all/src/bmi/index.tsx
@@ -2,7 +2,7 @@ import * as React from 'react'
import { Atom, F, bind } from '@grammarly/focal'
interface AppState {
- weightKg: number,
+ weightKg: number
heightCm: number
}
@@ -15,7 +15,7 @@ namespace AppState {
function getBmi(weight: number, height: number) {
const heightMeters = height * 0.01
- return Math.round(weight / (heightMeters ** 2))
+ return Math.round(weight / heightMeters ** 2)
}
const App = (props: { state: Atom }) => {
@@ -25,14 +25,12 @@ const App = (props: { state: Atom }) => {
return (
- Weight (kg)
+ Weight (kg)
- Height (cm)
+ Height (cm)
-
- BMI is {Atom.combine(weight, height, getBmi)}
-
+
BMI is {Atom.combine(weight, height, getBmi)}
)
}
diff --git a/packages/examples/all/src/change-color/index.tsx b/packages/examples/all/src/change-color/index.tsx
index f20ca30..4bf92dc 100644
--- a/packages/examples/all/src/change-color/index.tsx
+++ b/packages/examples/all/src/change-color/index.tsx
@@ -12,7 +12,7 @@ const BOLD = 'bold'
interface AppState {
style: {
- color: string,
+ color: string
font: string
}
}
@@ -34,43 +34,31 @@ const App = (props: { state: Atom }) => {
return (
- {
- [GREEN, RED, BLUE].map((x, index) => (
-
- ))
- }
+ {[GREEN, RED, BLUE].map((x, index) => (
+
+ ))}
- {
- [NORMAL, ITALIC, BOLD].map((x, index) => (
-
- ))
- }
+ {[NORMAL, ITALIC, BOLD].map((x, index) => (
+
+ ))}
-
styles[x]),
- font.view(x => styles[x])
- )
- }
- >
+ styles[x]), font.view(x => styles[x]))}>
Some text
diff --git a/packages/examples/all/src/checkbox-undo-redo/index.tsx b/packages/examples/all/src/checkbox-undo-redo/index.tsx
index 1fa7077..240cee2 100644
--- a/packages/examples/all/src/checkbox-undo-redo/index.tsx
+++ b/packages/examples/all/src/checkbox-undo-redo/index.tsx
@@ -3,9 +3,10 @@ import { Atom, F, Lens, reactiveList } from '@grammarly/focal'
import { App as Checkbox, AppState as CheckboxState } from '../checkbox'
import { History, HistoryState } from '../utils/history'
-interface AppState extends HistoryState<{
- checkboxes: CheckboxState[]
-}> { }
+interface AppState
+ extends HistoryState<{
+ checkboxes: CheckboxState[]
+ }> {}
namespace AppState {
export const defaultState: AppState = HistoryState.createDefault({
@@ -21,45 +22,40 @@ const App = (props: { state: Atom }) => {
)
diff --git a/packages/examples/all/src/checkbox/index.tsx b/packages/examples/all/src/checkbox/index.tsx
index 8f6daa7..2134b68 100644
--- a/packages/examples/all/src/checkbox/index.tsx
+++ b/packages/examples/all/src/checkbox/index.tsx
@@ -11,17 +11,18 @@ export namespace AppState {
}
}
-export const App = (props: { state: Atom }) =>
+export const App = (props: { state: Atom }) => (
- {props.state.view(x => x.checked ? 'ON' : 'OFF')}
+ {props.state.view(x => (x.checked ? 'ON' : 'OFF'))}
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/clock/index.tsx b/packages/examples/all/src/clock/index.tsx
index 4e7bd34..e3167c7 100644
--- a/packages/examples/all/src/clock/index.tsx
+++ b/packages/examples/all/src/clock/index.tsx
@@ -3,14 +3,14 @@ import { interval } from 'rxjs'
import { map, startWith } from 'rxjs/operators'
import { F } from '@grammarly/focal'
-const App = () =>
+const App = () => (
- {
- interval(1000).pipe(
- startWith(0),
- map(() => new Date().toString()))
- }
+ {interval(1000).pipe(
+ startWith(0),
+ map(() => new Date().toString())
+ )}
+)
export default {
Component: App
diff --git a/packages/examples/all/src/convert-inputs/index.tsx b/packages/examples/all/src/convert-inputs/index.tsx
index cbf3247..9a0b154 100644
--- a/packages/examples/all/src/convert-inputs/index.tsx
+++ b/packages/examples/all/src/convert-inputs/index.tsx
@@ -1,11 +1,11 @@
import * as React from 'react'
import { Atom, F } from '@grammarly/focal'
-const toFahrenheit = (celsius: number) => celsius * 9 / 5 + 32
-const toCelsius = (fahrenheit: number) => (fahrenheit - 32) * 5 / 9
+const toFahrenheit = (celsius: number) => (celsius * 9) / 5 + 32
+const toCelsius = (fahrenheit: number) => ((fahrenheit - 32) * 5) / 9
interface AppState {
- celsius: number,
+ celsius: number
fahrenheit: number
}
@@ -18,29 +18,36 @@ namespace AppState {
}
}
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
x.celsius.toString())}
- onChange={e => props.state.set({
- celsius: +e.currentTarget.value,
- fahrenheit: toFahrenheit(+e.currentTarget.value)
- })}
- />°C
+ onChange={e =>
+ props.state.set({
+ celsius: +e.currentTarget.value,
+ fahrenheit: toFahrenheit(+e.currentTarget.value)
+ })
+ }
+ />
+ °C
x.fahrenheit.toString())}
- onChange={e => props.state.set({
- fahrenheit: +e.currentTarget.value,
- celsius: toCelsius(+e.currentTarget.value)
- })}
- />°F
+ onChange={e =>
+ props.state.set({
+ fahrenheit: +e.currentTarget.value,
+ celsius: toCelsius(+e.currentTarget.value)
+ })
+ }
+ />
+ °F
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/convert/index.tsx b/packages/examples/all/src/convert/index.tsx
index 68d05e4..0e0eb98 100644
--- a/packages/examples/all/src/convert/index.tsx
+++ b/packages/examples/all/src/convert/index.tsx
@@ -15,8 +15,8 @@ const App = (props: { state: Atom }) => {
const temperature = props.state.lens('temperature')
return (
-
- °C is {temperature.view(x => +x * 9 / 5 + 32 )}°F
+
+ °C is {temperature.view(x => (+x * 9) / 5 + 32)}°F
)
}
diff --git a/packages/examples/all/src/counter/index.tsx b/packages/examples/all/src/counter/index.tsx
index 4516e73..2e9892b 100644
--- a/packages/examples/all/src/counter/index.tsx
+++ b/packages/examples/all/src/counter/index.tsx
@@ -15,20 +15,19 @@ namespace AppState {
}
}
-const Counter = (props: { count: Atom }) =>
+const Counter = (props: { count: Atom }) => (
You have clicked this button {props.count} time(s).
-
-
+
+)
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
Hello, world!
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/hello/index.tsx b/packages/examples/all/src/hello/index.tsx
index 0418088..2c88bd2 100644
--- a/packages/examples/all/src/hello/index.tsx
+++ b/packages/examples/all/src/hello/index.tsx
@@ -2,7 +2,7 @@ import * as React from 'react'
import { Atom, F, bind } from '@grammarly/focal'
interface AppState {
- firstName: string,
+ firstName: string
lastName: string
}
@@ -18,18 +18,16 @@ const App = (props: { state: Atom }) => {
const lastName = props.state.lens('lastName')
return (
- First Name:
+ First Name:
- Last Name:
+ Last Name:
- {
- Atom.combine(
+ {Atom.combine(
firstName,
lastName,
(x, y) => x.length > 0 && y.length > 0 && `Hello, ${x} ${y}`
- )
- }
+ )}
)
diff --git a/packages/examples/all/src/http-search-github/index.tsx b/packages/examples/all/src/http-search-github/index.tsx
index 2d85112..9347152 100644
--- a/packages/examples/all/src/http-search-github/index.tsx
+++ b/packages/examples/all/src/http-search-github/index.tsx
@@ -7,9 +7,17 @@ enum ResultKind {
InProgress
}
-interface Success { kind: ResultKind.Success, value: T }
-interface Failure { kind: ResultKind.Failure, error: any }
-interface InProgress { kind: ResultKind.InProgress }
+interface Success {
+ kind: ResultKind.Success
+ value: T
+}
+interface Failure {
+ kind: ResultKind.Failure
+ error: any
+}
+interface InProgress {
+ kind: ResultKind.InProgress
+}
type Result = Success | Failure | InProgress
@@ -33,7 +41,7 @@ namespace Result {
interface AppState {
searchString: string
- result: undefined | Result<{ url: string, name: string }[]>
+ result: undefined | Result<{ url: string; name: string }[]>
}
namespace AppState {
@@ -48,70 +56,64 @@ function runSearch(result: Atom, query: str
fetch(`https://api.github.com/search/repositories?q=${query}`)
.then(res =>
- res.json()
- .then(json => res.status === 200
- ? Promise.resolve(json)
- : Promise.reject(json.message)))
+ res
+ .json()
+ .then(json => (res.status === 200 ? Promise.resolve(json) : Promise.reject(json.message)))
+ )
.then((json: any) =>
json.items.map((repo: any) => ({
url: repo.html_url,
name: repo.full_name
- })))
+ }))
+ )
.then(r => result.set(Result.success(r)))
.catch(err => result.set(Result.failure(err)))
}
export const App = (props: { state: Atom }) => {
const result = props.state.lens('result')
- const repos = result.view(x => x && x.kind === ResultKind.Success ? x.value : [])
+ const repos = result.view(x => (x && x.kind === ResultKind.Success ? x.value : []))
return (
)
diff --git a/packages/examples/all/src/increment-number/index.tsx b/packages/examples/all/src/increment-number/index.tsx
index 0cddff8..a203ee4 100644
--- a/packages/examples/all/src/increment-number/index.tsx
+++ b/packages/examples/all/src/increment-number/index.tsx
@@ -13,52 +13,56 @@ namespace AppState {
}
}
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
- {
- props.state.view(x =>
- props.state.set({ isRunning: !x.isRunning })}
- />
- )
- }
+ {props.state.view(x => (
+ props.state.set({ isRunning: !x.isRunning })}
+ />
+ ))}
with Observable.combineLatest
- {
- combineLatest(
- interval(1000).pipe(startWith(0), mapTo(1)),
- props.state.view('isRunning')
- ).pipe(
- scan<[number, boolean], number>(
- (acc, [val, shouldIncrement]) => shouldIncrement ? acc + val : acc, 0
- )
+ {combineLatest(
+ interval(1000).pipe(
+ startWith(0),
+ mapTo(1)
+ ),
+ props.state.view('isRunning')
+ ).pipe(
+ scan<[number, boolean], number>(
+ (acc, [val, shouldIncrement]) => (shouldIncrement ? acc + val : acc),
+ 0
)
- }
+ )}
with Observable.switchMap
- {
- interval(1000).pipe(
- startWith(0),
- switchMap(() => props.state.view(x => x.isRunning ? 1 : 0)),
- scan((acc, val) => acc + val, 0)
- )
- }
+ {interval(1000).pipe(
+ startWith(0),
+ switchMap(() => props.state.view(x => (x.isRunning ? 1 : 0))),
+ scan((acc, val) => acc + val, 0)
+ )}
Atom.switchMap Observable
- {
- props.state.pipe(
- switchMap(x => x.isRunning ? interval(1000).pipe(startWith(0), mapTo(1)) : of(0)),
- scan((acc, val) => acc + val, 0)
- )
- }
+ {props.state.pipe(
+ switchMap(x =>
+ x.isRunning
+ ? interval(1000).pipe(
+ startWith(0),
+ mapTo(1)
+ )
+ : of(0)
+ ),
+ scan((acc, val) => acc + val, 0)
+ )}
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/index.tsx b/packages/examples/all/src/index.tsx
index badf8a6..f0fcdcd 100644
--- a/packages/examples/all/src/index.tsx
+++ b/packages/examples/all/src/index.tsx
@@ -16,12 +16,11 @@ appState.subscribe(s => {
})
// inject app state in global for debugging
-; (window as any).appState = appState
+;(window as any).appState = appState
function startApp(C: typeof App.AppComponent) {
const targetEl = document.getElementById('app')
- if (targetEl == null)
- throw new Error('React app target element not found. Wrong HTML file?')
+ if (targetEl == null) throw new Error('React app target element not found. Wrong HTML file?')
ReactDOM.render(, targetEl)
}
diff --git a/packages/examples/all/src/input/index.tsx b/packages/examples/all/src/input/index.tsx
index b36cfa1..bd4aaef 100644
--- a/packages/examples/all/src/input/index.tsx
+++ b/packages/examples/all/src/input/index.tsx
@@ -11,11 +11,12 @@ namespace AppState {
}
}
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
-
+
{props.state.view('entry')}
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/list-search/index.tsx b/packages/examples/all/src/list-search/index.tsx
index 560ade4..da6200c 100644
--- a/packages/examples/all/src/list-search/index.tsx
+++ b/packages/examples/all/src/list-search/index.tsx
@@ -1,5 +1,5 @@
import * as React from 'react'
-import { interval, Subscription } from 'rxjs'
+import { interval, Subscription } from 'rxjs'
import { Atom, F, bind } from '@grammarly/focal'
const defaultSearchList = Object.keys(window)
@@ -11,8 +11,8 @@ function getRandomSearchList() {
}
interface AppState {
- searchString: string,
- searchList: string[],
+ searchString: string
+ searchList: string[]
timer: number
}
@@ -24,20 +24,18 @@ namespace AppState {
}
}
-class App extends React.Component<{ state: Atom }, {}> {
+class App extends React.Component<{ state: Atom }, {}> {
private _subscription: Subscription
componentDidMount() {
const { state } = this.props
const timer = state.lens('timer')
- this._subscription = interval(1000)
- .subscribe(_ => {
- state.lens('timer').modify(x => x === 0 ? 5 : x - 1)
+ this._subscription = interval(1000).subscribe(_ => {
+ state.lens('timer').modify(x => (x === 0 ? 5 : x - 1))
- if (timer.get() === 5)
- state.lens('searchList').set(getRandomSearchList())
- })
+ if (timer.get() === 5) state.lens('searchList').set(getRandomSearchList())
+ })
}
componentWillUnmount() {
@@ -53,17 +51,15 @@ class App extends React.Component<{ state: Atom }, {}> {
Timer: {state.view('timer')}
- {
- Atom.combine(search, state.lens('searchList'), (searchValue, list) => (
-
- {
- list
- .filter(x => x.toLowerCase().includes(searchValue.toLowerCase()))
- .map((x, i) =>
{x})
- }
-
- ))
- }
+ {Atom.combine(search, state.lens('searchList'), (searchValue, list) => (
+
+ {list
+ .filter(x => x.toLowerCase().includes(searchValue.toLowerCase()))
+ .map((x, i) => (
+
{x}
+ ))}
+
+ ))}
)
diff --git a/packages/examples/all/src/player/index.tsx b/packages/examples/all/src/player/index.tsx
index f4195ff..2eba1c7 100644
--- a/packages/examples/all/src/player/index.tsx
+++ b/packages/examples/all/src/player/index.tsx
@@ -5,14 +5,14 @@ import { Status, AudioModel, AppState, audioSrc, defaultState } from './model'
const Volume = ({ volume }: { volume: Atom }) => (
x >= 10)}
onClick={() => volume.modify(x => x + 1)}
/>
x <= 0)}
onClick={() => volume.modify(x => x - 1)}
/>
@@ -22,12 +22,9 @@ const Volume = ({ volume }: { volume: Atom }) => (
const Play = ({ status }: { status: Atom }) => (
(x === Status.playing ? 'Stop' : 'Play'))}
- onClick={() =>
- status.modify(
- x => (x === Status.playing ? Status.pause : Status.playing)
- )}
+ onClick={() => status.modify(x => (x === Status.playing ? Status.pause : Status.playing))}
/>
)
@@ -35,16 +32,11 @@ const TimeLine = ({
currentTime,
maxDuration
}: {
- currentTime: Atom,
+ currentTime: Atom
maxDuration: ReadOnlyAtom
}) => (
-
+
{currentTime}s
)
@@ -64,10 +56,7 @@ class App extends React.Component<{ state: Atom }, {}> {
const { state } = this.props
return (
diff --git a/packages/examples/all/src/player/model.ts b/packages/examples/all/src/player/model.ts
index 952f8e9..6afd1d7 100644
--- a/packages/examples/all/src/player/model.ts
+++ b/packages/examples/all/src/player/model.ts
@@ -34,20 +34,13 @@ export class AudioModel {
constructor(atom: Atom, audioSrc: string) {
this.audio = new Audio(audioSrc)
- this.durationSubscription = fromEvent(this.audio, 'canplaythrough')
- .subscribe(() =>
- atom.lens('maxDuration').set(this.audio.duration)
- )
+ this.durationSubscription = fromEvent(this.audio, 'canplaythrough').subscribe(() =>
+ atom.lens('maxDuration').set(this.audio.duration)
+ )
this.timeSubscription = atom
.view(x => x.status)
- .pipe(
- switchMap(x =>
- x === Status.playing
- ? interval(1000).pipe(mapTo(1))
- : of(0)
- )
- )
+ .pipe(switchMap(x => (x === Status.playing ? interval(1000).pipe(mapTo(1)) : of(0))))
.subscribe(x =>
atom.modify(y => {
const newCurTime = parseInt(y.currentTime, 10) + x
@@ -67,17 +60,13 @@ export class AudioModel {
this.statusSubscription = atom
.view(x => x.status)
- .subscribe(
- x => x === Status.playing ? this.audio.play() : this.audio.pause()
- )
+ .subscribe(x => (x === Status.playing ? this.audio.play() : this.audio.pause()))
- this.volumeSubscription = atom
- .lens('volume')
- .subscribe(x => this.audio.volume = x / 10)
+ this.volumeSubscription = atom.lens('volume').subscribe(x => (this.audio.volume = x / 10))
this.currentTimeSubscription = atom
.lens('currentTime')
- .subscribe(x => this.audio.currentTime = parseInt(x, 10))
+ .subscribe(x => (this.audio.currentTime = parseInt(x, 10)))
}
unsubscribe() {
diff --git a/packages/examples/all/src/scroll/index.tsx b/packages/examples/all/src/scroll/index.tsx
index 473f514..87b6895 100644
--- a/packages/examples/all/src/scroll/index.tsx
+++ b/packages/examples/all/src/scroll/index.tsx
@@ -37,15 +37,13 @@ const pattern = `
. : :.:::::::.: :.
`
-const Scroller = (props: { scrollTop: Atom, scrollLeft: Atom }) =>
+const Scroller = (props: { scrollTop: Atom; scrollLeft: Atom }) => (
, scrollLeft: Atom
})
>
{pattern}
+)
-const ScrollInput = (props: { value: Atom, label: string }) =>
+const ScrollInput = (props: { value: Atom; label: string }) => (
+)
const App = (props: { state: Atom }) => {
const scrollTop = props.state.lens('scrollTop')
@@ -75,8 +75,8 @@ const App = (props: { state: Atom }) => {
-
-
+
+
)
diff --git a/packages/examples/all/src/slider/index.tsx b/packages/examples/all/src/slider/index.tsx
index b06dbbb..a4ff5fa 100644
--- a/packages/examples/all/src/slider/index.tsx
+++ b/packages/examples/all/src/slider/index.tsx
@@ -11,11 +11,12 @@ namespace AppState {
}
}
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
-
+
Value: {props.state.view('range')}
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/timer/index.tsx b/packages/examples/all/src/timer/index.tsx
index e25e3cc..6094499 100644
--- a/packages/examples/all/src/timer/index.tsx
+++ b/packages/examples/all/src/timer/index.tsx
@@ -10,14 +10,14 @@ enum Status {
}
interface Time {
- seconds: number,
- milliseconds: number,
+ seconds: number
+ milliseconds: number
minutes: number
}
interface AppState {
- time: Time,
- laps: Time[],
+ time: Time
+ laps: Time[]
status: Status
}
@@ -59,19 +59,15 @@ function updateTime(time: Time, val: number) {
return { milliseconds, seconds, minutes }
}
-const Laps = ({ laps }: { laps: ReadOnlyAtom
- {
- isStarted.view(x =>
- x
- ? status.set(Status.STOPPED)}
- />
- : status.set(Status.STARTED)}
- />
- )
- }
- {
- status.view(x =>
- x === Status.STOPPED &&
+ {isStarted.view(x =>
+ x ? (
state.set(AppState.defaultState)}
+ key="stop"
+ type="submit"
+ value="Stop"
+ onClick={() => status.set(Status.STOPPED)}
/>
- )
- }
- {
- isStarted.view(x =>
- x &&
+ ) : (
state.modify(x => ({ ...x, laps: [...x.laps, x.time] }))}
+ key="start"
+ type="submit"
+ value="Start"
+ onClick={() => status.set(Status.STARTED)}
/>
)
- }
+ )}
+ {status.view(
+ x =>
+ x === Status.STOPPED && (
+ state.set(AppState.defaultState)}
+ />
+ )
+ )}
+ {isStarted.view(
+ x =>
+ x && (
+ state.modify(x => ({ ...x, laps: [...x.laps, x.time] }))}
+ />
+ )
+ )}
diff --git a/packages/examples/all/src/todos-with-undo/index.tsx b/packages/examples/all/src/todos-with-undo/index.tsx
index b798ec5..02c5d4f 100644
--- a/packages/examples/all/src/todos-with-undo/index.tsx
+++ b/packages/examples/all/src/todos-with-undo/index.tsx
@@ -4,7 +4,7 @@ import { App as TodoApp } from '../todos'
import { History, HistoryState } from '../utils/history'
import * as TodosModel from '../todos/model'
-interface AppState extends HistoryState { }
+interface AppState extends HistoryState {}
const App = (props: { state: Atom }) => {
const history = History.create(props.state)
@@ -13,14 +13,14 @@ const App = (props: { state: Atom }) => {
history.undo()}
/>
history.redo()}
/>
diff --git a/packages/examples/all/src/todos/index.tsx b/packages/examples/all/src/todos/index.tsx
index 076ba27..b049831 100644
--- a/packages/examples/all/src/todos/index.tsx
+++ b/packages/examples/all/src/todos/index.tsx
@@ -1,17 +1,23 @@
import * as React from 'react'
import { Atom, F, Lens, bind, reactiveList } from '@grammarly/focal'
import {
- AppState, TodoState,
- defaultAppState, defaultTodoState,
- addTodo, toggleTodo, filterTodos,
- SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED
+ AppState,
+ TodoState,
+ defaultAppState,
+ defaultTodoState,
+ addTodo,
+ toggleTodo,
+ filterTodos,
+ SHOW_ALL,
+ SHOW_ACTIVE,
+ SHOW_COMPLETED
} from './model'
-const Todo = (props: { id: string, todo: Atom }) => {
+const Todo = (props: { id: string; todo: Atom }) => {
const { todo, id } = props
const todoStyle = {
cursor: 'pointer',
- textDecoration: todo.view(x => x.completed ? 'line-through' : 'none')
+ textDecoration: todo.view(x => (x.completed ? 'line-through' : 'none'))
}
return (
todo.modify(toggleTodo)}>
@@ -24,50 +30,42 @@ const TodoList = (props: { state: Atom }) => {
const todos = props.state.lens('todos')
return (
- {
- reactiveList(
- props.state.view(x => filterTodos(x.todos, x.filter)),
- id => {
- const todo = todos
- .lens(Lens.key(id))
- .lens(Lens.withDefault(defaultTodoState))
- return
- }
- )
- }
+ {reactiveList(props.state.view(x => filterTodos(x.todos, x.filter)), id => {
+ const todo = todos.lens(Lens.key(id)).lens(Lens.withDefault(defaultTodoState))
+ return
+ })}
)
}
const Footer = (props: { filter: Atom }) => (
)
-export const App = (props: { state: Atom }) =>
+export const App = (props: { state: Atom }) => (
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/todos/model.ts b/packages/examples/all/src/todos/model.ts
index 099a5a0..49d0d5c 100644
--- a/packages/examples/all/src/todos/model.ts
+++ b/packages/examples/all/src/todos/model.ts
@@ -1,5 +1,5 @@
export interface TodoState {
- value: string,
+ value: string
completed: boolean
}
@@ -11,14 +11,13 @@ export const SHOW_ALL = 'SHOW_ALL'
export const SHOW_ACTIVE = 'SHOW_ACTIVE'
export const SHOW_COMPLETED = 'SHOW_COMPLETED'
-export type ShowMode =
- typeof SHOW_ALL | typeof SHOW_ACTIVE | typeof SHOW_COMPLETED
+export type ShowMode = typeof SHOW_ALL | typeof SHOW_ACTIVE | typeof SHOW_COMPLETED
export interface AppState {
- todos: TodoListState,
- value: string,
- filter: ShowMode,
- nextTodoId: number
+ todos: TodoListState
+ value: string
+ filter: ShowMode
+ nextTodoId: number
}
export const defaultAppState: AppState = {
diff --git a/packages/examples/all/src/tree/index.tsx b/packages/examples/all/src/tree/index.tsx
index 0cb19fb..f78e3d1 100644
--- a/packages/examples/all/src/tree/index.tsx
+++ b/packages/examples/all/src/tree/index.tsx
@@ -1,61 +1,53 @@
import * as React from 'react'
import { Atom, F, Lens, reactiveList } from '@grammarly/focal'
-import {
- defaultAppState, defaultNodeState,
- AppState, NodeState
-} from './model'
+import { defaultAppState, defaultNodeState, AppState, NodeState } from './model'
-const Counter = (props: { value: Atom }) =>
+const Counter = (props: { value: Atom }) => (
Counter {props.value}
- props.value.modify(x => x + 1)} />
- props.value.modify(x => x - 1)} />
+ props.value.modify(x => x + 1)} />
+ props.value.modify(x => x - 1)} />
+)
-const Node = (props: { state: Atom, removeNode?(): void }): JSX.Element => {
+const Node = (props: { state: Atom; removeNode?(): void }): JSX.Element => {
const children = props.state.lens('children')
return (
- {
- props.removeNode &&
+ {props.removeNode && (
props.removeNode && props.removeNode()}
/>
- }
+ )}
- {
- reactiveList(
- children.view(x => x.map((_, index) => index)),
- index => (
-
- (index))
- .lens(Lens.withDefault(defaultNodeState))
- }
- removeNode={() => children.modify(x => x.filter((_, i) => i !== index))}
- />
-
- )
- )
- }
+ {reactiveList(children.view(x => x.map((_, index) => index)), index => (
+
+ (index))
+ .lens(Lens.withDefault(defaultNodeState))}
+ removeNode={() => children.modify(x => x.filter((_, i) => i !== index))}
+ />
+
+ ))}
props.state.lens('children').modify(x => [...x, defaultNodeState])}
/>
)
}
-const App = (props: { state: Atom }) =>
+const App = (props: { state: Atom }) => (
+)
export default {
Component: App,
diff --git a/packages/examples/all/src/tree/model.ts b/packages/examples/all/src/tree/model.ts
index 4b11013..9835540 100644
--- a/packages/examples/all/src/tree/model.ts
+++ b/packages/examples/all/src/tree/model.ts
@@ -1,10 +1,10 @@
export interface NodeState {
- value: number,
+ value: number
children: NodeState[]
}
export interface AppState {
- tree: NodeState
+ tree: NodeState
}
export const defaultNodeState = {
diff --git a/packages/examples/all/src/update-number/index.tsx b/packages/examples/all/src/update-number/index.tsx
index 436afcf..0c9cc9e 100644
--- a/packages/examples/all/src/update-number/index.tsx
+++ b/packages/examples/all/src/update-number/index.tsx
@@ -13,7 +13,7 @@ import * as React from 'react'
import { Atom, F, bind } from '@grammarly/focal'
interface AppState {
- inputValue: string,
+ inputValue: string
value: number
}
@@ -50,33 +50,29 @@ const App = (props: { state: Atom }) => {
const value = props.state.view('value')
return (
-
+
props.state.modify(x => ({ ...x, value: parseInt(x.inputValue, 10) }))}
/>
Observable.scan
- {
- value.pipe(
- scan(([_, curr], val) => [curr, val], [0, value.get()]),
- switchMap(getUpdateNumberObservable)
- )
- }
+ {value.pipe(
+ scan(([_, curr], val) => [curr, val], [0, value.get()]),
+ switchMap(getUpdateNumberObservable)
+ )}
Observable.bufferCount
- {
- value.pipe(
- bufferCount(2, 1),
- switchMap(getUpdateNumberObservable),
- merge(value.pipe(first()))
- )
- }
+ {value.pipe(
+ bufferCount(2, 1),
+ switchMap(getUpdateNumberObservable),
+ merge(value.pipe(first()))
+ )}
diff --git a/packages/examples/all/src/utils/history.ts b/packages/examples/all/src/utils/history.ts
index 94f9048..f466f75 100644
--- a/packages/examples/all/src/utils/history.ts
+++ b/packages/examples/all/src/utils/history.ts
@@ -39,9 +39,7 @@ export namespace History {
return {
position: newPosition,
- history: s.history
- .slice(0, newPosition)
- .concat([v])
+ history: s.history.slice(0, newPosition).concat([v])
}
}
)
@@ -50,12 +48,10 @@ export namespace History {
canRedo: redoCount.view(x => x === 0),
undo() {
- if (position.get() > 0)
- position.modify(x => x - 1)
+ if (position.get() > 0) position.modify(x => x - 1)
},
redo() {
- if (redoCount.get() > 0)
- position.modify(x => x + 1)
+ if (redoCount.get() > 0) position.modify(x => x + 1)
}
}
}
diff --git a/packages/examples/all/tslint.json b/packages/examples/all/tslint.json
index afb3ca4..447a569 100644
--- a/packages/examples/all/tslint.json
+++ b/packages/examples/all/tslint.json
@@ -1,3 +1,12 @@
{
- "extends": "@grammarly/tslint-config"
+ "extends": "@grammarly/tslint-config",
+ "rules": {
+ "whitespace": [false],
+ "quotemark": [
+ true,
+ "single",
+ "jsx-double",
+ "avoid-escape"
+ ]
+ }
}
\ No newline at end of file
diff --git a/packages/examples/todomvc/src/app.tsx b/packages/examples/todomvc/src/app.tsx
index 8bdd480..43f70d3 100644
--- a/packages/examples/todomvc/src/app.tsx
+++ b/packages/examples/todomvc/src/app.tsx
@@ -28,35 +28,29 @@ interface TodoProps {
remove(): void
}
-const Todo = ({ todo, editing, remove }: TodoProps) =>
+const Todo = ({ todo, editing, remove }: TodoProps) => (
x && x.completed && 'completed'),
- editing.view(x => x && 'editing'))
- }
+ {...classes(todo.view(x => x && x.completed && 'completed'), editing.view(x => x && 'editing'))}
>
-
item)}
- {...bind({ checked:
- todo
- .lens(Lens.create(
+ {...bind({
+ checked: todo.lens(
+ Lens.create(
(x: TodoItem | undefined) => x && x.completed,
(v: boolean, x) => x && { ...x, completed: v }
- ))
+ )
+ )
})}
/>
- editing.set(true)}
- >
+ editing.set(true)}>
{todo.view(x => x && x.title)}
-
+
{editing.view(e => {
if (e) {
@@ -72,10 +66,12 @@ const Todo = ({ todo, editing, remove }: TodoProps) =>
exit()
if (newTitle) {
todo
- .lens(Lens.create(
- (x: TodoItem | undefined) => x && x.title,
- (v: string, x) => x && { ...x, title: v }
- ))
+ .lens(
+ Lens.create(
+ (x: TodoItem | undefined) => x && x.title,
+ (v: string, x) => x && { ...x, title: v }
+ )
+ )
.set(newTitle)
} else {
remove()
@@ -84,16 +80,13 @@ const Todo = ({ todo, editing, remove }: TodoProps) =>
return (
x && focus(x)}
defaultValue={todo.view(x => (x && x.title) || '')}
- onKeyDown={e =>
- e.key === 'Enter' && save(e)
- || e.key === 'Escape' && exit()
- }
+ onKeyDown={e => (e.key === 'Enter' && save(e)) || (e.key === 'Escape' && exit())}
/>
)
} else {
@@ -101,86 +94,88 @@ const Todo = ({ todo, editing, remove }: TodoProps) =>
}
})}
+)
const NewTodo = ({ onEntry }: { onEntry(title: string): void }) => {
const onKeyDown = (e: React.KeyboardEvent) => {
const title = (e.target as HTMLInputElement).value.trim()
if (e.which === 13 && title !== '') {
- onEntry(title);
- (e.target as HTMLInputElement).value = ''
+ onEntry(title)
+ ;(e.target as HTMLInputElement).value = ''
}
}
- return
+ return (
+
+ )
}
-const Filters = () =>
-
- {routes.map(r =>
+const Filters = () => (
+
+ {routes.map(r => (
-
- c.hash === r.hash && 'selected')))}
- href={r.hash}
- >
+ c.hash === r.hash && 'selected')))} href={r.hash}>
{r.title}
- )}
+ ))}
+)
const AppComponent = ({ model }: { model: AppModel }) => {
return (
-
-
+
+
todos
- model.add(title)}/>
+ model.add(title)} />
-
+
!x || Object.keys(x).length === 0)}
{...bind({ checked: model.toggleAll() })}
/>
-
+
{reactiveList(
- route.pipe(combineLatest(
- model.todos,
- (r, xs) => Object.keys(xs).filter(k => r.filter(xs[k]))
- )),
- id => (id))}
- remove={() => model.delete(id)}
- editing={Atom.create(false)}
- />
+ route.pipe(
+ combineLatest(model.todos, (r, xs) => Object.keys(xs).filter(k => r.filter(xs[k])))
+ ),
+ id => (
+ (id))}
+ remove={() => model.delete(id)}
+ editing={Atom.create(false)}
+ />
+ )
)}
!x || Object.keys(x).length === 0)}
>
-
+
{model.todos.view(xs => {
const activeCount = Object.keys(xs).filter(k => !xs[k].completed).length
return `${activeCount} item${activeCount === 1 ? '' : 's'} left`
})}
-
+
model.deleteCompleted()}
hidden={model.todos.view(items => {
const keys = Object.keys(items)
@@ -190,27 +185,22 @@ const AppComponent = ({ model }: { model: AppModel }) => {
Clear completed
-
-
)
}
export class App {
- constructor(
- private _targetElement: HTMLElement,
- private _model: AppModel
- ) {}
+ constructor(private _targetElement: HTMLElement, private _model: AppModel) {}
start() {
- ReactDOM.render(
- ,
- this._targetElement
- )
+ ReactDOM.render(, this._targetElement)
}
}
diff --git a/packages/examples/todomvc/src/index.tsx b/packages/examples/todomvc/src/index.tsx
index 7fb4a17..ae9f685 100644
--- a/packages/examples/todomvc/src/index.tsx
+++ b/packages/examples/todomvc/src/index.tsx
@@ -16,18 +16,14 @@ if (!targetEl)
const LOCALSTORAGE_NAME = 'focal.examples.todomvc'
-const defaultState = (
- JSON.parse(
- localStorage.getItem(LOCALSTORAGE_NAME) || 'null'
- ) as ((typeof Model.defaultState) | null)
-) || Model.defaultState
+const defaultState =
+ (JSON.parse(localStorage.getItem(LOCALSTORAGE_NAME) || 'null') as (
+ | (typeof Model.defaultState)
+ | null)) || Model.defaultState
const model = new Model.AppModel(Atom.create(defaultState))
-let app = new App(
- targetEl,
- model
-)
+let app = new App(targetEl, model)
model.state.pipe(debounceTime(1000)).subscribe(s => {
console.log('App state changed: ' + JSON.stringify(s))
@@ -38,7 +34,7 @@ if (module.hot) {
module.hot.accept('./app', () => {
const newAppModule = require('./app')
- const newApp = (new newAppModule.App(targetEl , model))
+ const newApp = new newAppModule.App(targetEl, model)
app = newApp
app.start()
})
@@ -48,8 +44,12 @@ app.start()
function bench(action: () => void, name: string) {
const now =
- window.performance && window.performance.now ?
- function () { return window.performance.now() } // tslint:disable-line
+ // tslint:disable-next-line: strict-boolean-expressions
+ window.performance && window.performance.now
+ ? // tslint:disable-next-line
+ function() {
+ return window.performance.now()
+ }
: Date.now
const startTime = now()
@@ -70,12 +70,14 @@ function bench(action: () => void, name: string) {
}, 0)
}
-(window as any).benchmark = {
+// tslint:disable-next-line
+;(window as any).benchmark = {
elm: {
run: function(numberOfItems = 200) {
const newTodo = document.getElementsByClassName('new-todo')[0] as HTMLInputElement
- function elmBenchmark1() { // tslint:disable-line
+ // tslint:disable-next-line
+ function elmBenchmark1() {
for (let i = 0; i < numberOfItems; i++) {
const keydownEvent = document.createEvent('Event')
keydownEvent.initEvent('keydown', true, true)
@@ -91,14 +93,12 @@ function bench(action: () => void, name: string) {
function elmBenchmark2() {
const checkboxes = document.querySelectorAll('.toggle')
- for (let i = 0; i < checkboxes.length; i++)
- (checkboxes[i] as any).click()
+ for (let i = 0; i < checkboxes.length; i++) (checkboxes[i] as any).click()
}
function elmBenchmark3() {
const destroyButtons = document.querySelectorAll('.destroy')
- for (let i = 0; i < destroyButtons.length; i++)
- (destroyButtons[i] as any).click()
+ for (let i = 0; i < destroyButtons.length; i++) (destroyButtons[i] as any).click()
}
setTimeout(() => {
diff --git a/packages/examples/todomvc/src/model.ts b/packages/examples/todomvc/src/model.ts
index 3d80344..cfa092b 100644
--- a/packages/examples/todomvc/src/model.ts
+++ b/packages/examples/todomvc/src/model.ts
@@ -31,15 +31,13 @@ export class AppModel {
add(title: string) {
this.state.modify(({ todos, nextId }) => ({
- todos: Object.assign({},
- todos,
- {
- [String(nextId)]: {
- title,
- completed: false,
- id: nextId
- }
- }),
+ todos: Object.assign({}, todos, {
+ [String(nextId)]: {
+ title,
+ completed: false,
+ id: nextId
+ }
+ }),
nextId: nextId + 1
}))
}
@@ -48,20 +46,27 @@ export class AppModel {
this.todos.modify(todos =>
Object.keys(todos)
.filter(k => k !== id)
- .reduce((acc, k) => {
- acc[k] = todos[k]
- return acc
- }, {} as TodoList))
+ .reduce(
+ (acc, k) => {
+ acc[k] = todos[k]
+ return acc
+ },
+ {} as TodoList
+ )
+ )
}
deleteCompleted() {
this.todos.modify(todos => {
return Object.keys(todos)
.filter(k => !todos[k].completed)
- .reduce((acc, k) => {
- acc[k] = todos[k]
- return acc
- }, {} as TodoList)
+ .reduce(
+ (acc, k) => {
+ acc[k] = todos[k]
+ return acc
+ },
+ {} as TodoList
+ )
})
}
@@ -70,11 +75,13 @@ export class AppModel {
Lens.create(
todos => Object.keys(todos).filter(k => !todos[k].completed).length === 0,
(v: boolean, todos: TodoList) =>
- Object.keys(todos)
- .reduce((acc, k) => {
+ Object.keys(todos).reduce(
+ (acc, k) => {
acc[k] = { id: todos[k].id, title: todos[k].title, completed: v }
return acc
- }, {} as TodoList)
+ },
+ {} as TodoList
+ )
)
)
}
diff --git a/packages/examples/todomvc/tslint.json b/packages/examples/todomvc/tslint.json
index afb3ca4..447a569 100644
--- a/packages/examples/todomvc/tslint.json
+++ b/packages/examples/todomvc/tslint.json
@@ -1,3 +1,12 @@
{
- "extends": "@grammarly/tslint-config"
+ "extends": "@grammarly/tslint-config",
+ "rules": {
+ "whitespace": [false],
+ "quotemark": [
+ true,
+ "single",
+ "jsx-double",
+ "avoid-escape"
+ ]
+ }
}
\ No newline at end of file
diff --git a/packages/focal/src/atom/base.ts b/packages/focal/src/atom/base.ts
index 2c40990..1f0f27c 100644
--- a/packages/focal/src/atom/base.ts
+++ b/packages/focal/src/atom/base.ts
@@ -99,19 +99,16 @@ export interface ReadOnlyAtom extends Observable {
/**
* View this atom at a give property path.
*/
- view<
- K1 extends keyof T,
- K2 extends keyof T[K1]
- >(k1: K1, k2: K2): ReadOnlyAtom
+ view(k1: K1, k2: K2): ReadOnlyAtom
/**
* View this atom at a give property path.
*/
- view<
- K1 extends keyof T,
- K2 extends keyof T[K1],
- K3 extends keyof T[K1][K2]
- >(k1: K1, k2: K2, k3: K3): ReadOnlyAtom
+ view(
+ k1: K1,
+ k2: K2,
+ k3: K3
+ ): ReadOnlyAtom
/**
* View this atom at a give property path.
@@ -121,7 +118,12 @@ export interface ReadOnlyAtom extends Observable {
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3]
- >(k1: K1, k2: K2, k3: K3, k4: K4): ReadOnlyAtom
+ >(
+ k1: K1,
+ k2: K2,
+ k3: K3,
+ k4: K4
+ ): ReadOnlyAtom
/**
* View this atom at a give property path.
@@ -132,7 +134,13 @@ export interface ReadOnlyAtom extends Observable {
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3],
K5 extends keyof T[K1][K2][K3][K4]
- >(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): ReadOnlyAtom
+ >(
+ k1: K1,
+ k2: K2,
+ k3: K3,
+ k4: K4,
+ k5: K5
+ ): ReadOnlyAtom
}
/**
@@ -202,19 +210,16 @@ export interface Atom extends ReadOnlyAtom {
/**
* Create a lensed atom that's focused on a given property path.
*/
- lens<
- K1 extends keyof T,
- K2 extends keyof T[K1]
- >(k1: K1, k2: K2): Atom
+ lens(k1: K1, k2: K2): Atom
/**
* Create a lensed atom that's focused on a given property path.
*/
- lens<
- K1 extends keyof T,
- K2 extends keyof T[K1],
- K3 extends keyof T[K1][K2]
- >(k1: K1, k2: K2, k3: K3): Atom
+ lens(
+ k1: K1,
+ k2: K2,
+ k3: K3
+ ): Atom
/**
* Create a lensed atom that's focused on a given property path.
@@ -224,7 +229,12 @@ export interface Atom extends ReadOnlyAtom {
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3]
- >(k1: K1, k2: K2, k3: K3, k4: K4): Atom
+ >(
+ k1: K1,
+ k2: K2,
+ k3: K3,
+ k4: K4
+ ): Atom
/**
* Create a lensed atom that's focused on a given property path.
@@ -235,12 +245,17 @@ export interface Atom extends ReadOnlyAtom {
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3],
K5 extends keyof T[K1][K2][K3][K4]
- >(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): Atom
+ >(
+ k1: K1,
+ k2: K2,
+ k3: K3,
+ k4: K4,
+ k5: K5
+ ): Atom
}
-export abstract class AbstractReadOnlyAtom
- extends BehaviorSubject
- implements ReadOnlyAtom {
+export abstract class AbstractReadOnlyAtom extends BehaviorSubject
+ implements ReadOnlyAtom {
abstract get(): T
view(): ReadOnlyAtom
@@ -252,24 +267,22 @@ export abstract class AbstractReadOnlyAtom
view(...args: any[]): ReadOnlyAtom {
// tslint:disable no-use-before-declare
return args[0] !== undefined
- // view(getter) case
- ? typeof args[0] === 'function'
+ ? // view(getter) case
+ typeof args[0] === 'function'
? new AtomViewImpl(this, args[0] as (x: T) => U)
- // view('key') case
- : typeof args[0] === 'string'
- ? new AtomViewImpl(this, Lens.compose(...args.map(Lens.key())).get)
- // view(lens) and view(prism) cases
+ : // view('key') case
+ typeof args[0] === 'string'
+ ? new AtomViewImpl(this, Lens.compose(...args.map(Lens.key())).get)
+ : // view(lens) and view(prism) cases
// @NOTE single case handles both lens and prism arg
- : new AtomViewImpl(this, x => (args[0] as Lens).get(x))
- // view() case
- : this as ReadOnlyAtom
+ new AtomViewImpl(this, x => (args[0] as Lens).get(x))
+ : // view() case
+ (this as ReadOnlyAtom)
// tslint:enable no-use-before-declare
}
}
-export abstract class AbstractAtom
- extends AbstractReadOnlyAtom
- implements Atom {
+export abstract class AbstractAtom extends AbstractReadOnlyAtom implements Atom {
abstract modify(updateFn: (x: T) => T): void
set(x: T) {
@@ -286,12 +299,18 @@ export abstract class AbstractAtom
// lens(prop expr) case
return typeof arg1 === 'function'
? new LensedAtom(this, Lens.prop(arg1 as (x: T) => U), structEq)
- // lens('key') case
- : typeof arg1 === 'string'
- ? new LensedAtom(
- this, Lens.compose(Lens.key(arg1), ...args.map(k => Lens.key(k))), structEq)
- // lens(lens) case
- : new LensedAtom(this, arg1 as Lens, structEq)
+ : // lens('key') case
+ typeof arg1 === 'string'
+ ? new LensedAtom(
+ this,
+ Lens.compose(
+ Lens.key(arg1),
+ ...args.map(k => Lens.key(k))
+ ),
+ structEq
+ )
+ : // lens(lens) case
+ new LensedAtom(this, arg1 as Lens, structEq)
// tslint:enable no-use-before-declare
}
}
@@ -309,15 +328,13 @@ export class JsonAtom extends AbstractAtom {
const prevValue = this.getValue()
const next = updateFn(prevValue)
- if (!structEq(prevValue, next))
- this.next(next)
+ if (!structEq(prevValue, next)) this.next(next)
}
set(x: T) {
const prevValue = this.getValue()
- if (!structEq(prevValue, x))
- this.next(x)
+ if (!structEq(prevValue, x)) this.next(x)
}
}
@@ -345,9 +362,7 @@ class LensedAtom extends AbstractAtom {
//
// This way we don't need to recalculate the lens value
// every time.
- return this._subscription
- ? this.getValue()
- : this._lens.get(this._source.get())
+ return this._subscription ? this.getValue() : this._lens.get(this._source.get())
}
modify(updateFn: (x: TDest) => TDest) {
@@ -362,15 +377,15 @@ class LensedAtom extends AbstractAtom {
const prevValue = this.getValue()
const next = this._lens.get(x)
- if (!this._eq(prevValue, next))
- this.next(next)
+ if (!this._eq(prevValue, next)) this.next(next)
}
private _subscription: Subscription | null = null
private _refCount = 0
// Rx method overrides
- _subscribe(subscriber: Subscriber) { // tslint:disable-line function-name
+ // tslint:disable-next-line function-name
+ _subscribe(subscriber: Subscriber) {
if (!this._subscription) {
this._subscription = this._source.subscribe(x => this._onSourceValue(x))
}
@@ -422,24 +437,22 @@ class AtomViewImpl extends AbstractReadOnlyAtom {
//
// This way we don't need to recalculate the view value
// every time.
- return this._subscription
- ? this.getValue()
- : this._getter(this._source.get())
+ return this._subscription ? this.getValue() : this._getter(this._source.get())
}
private _onSourceValue(x: TSource) {
const prevValue = this.getValue()
const next = this._getter(x)
- if (!this._eq(prevValue, next))
- this.next(next)
+ if (!this._eq(prevValue, next)) this.next(next)
}
private _subscription: Subscription | null = null
private _refCount = 0
// Rx method overrides
- _subscribe(subscriber: Subscriber) { // tslint:disable-line function-name
+ // tslint:disable-next-line function-name
+ _subscribe(subscriber: Subscriber) {
if (!this._subscription) {
this._subscription = this._source.subscribe(x => this._onSourceValue(x))
}
@@ -492,27 +505,24 @@ export class CombinedAtomViewImpl extends AbstractReadOnlyAtom
//
// This way we don't need to recalculate the view value
// every time.
- return this._subscription
- ? this.getValue()
- : this._combineFn(this._sources.map(x => x.get()))
+ return this._subscription ? this.getValue() : this._combineFn(this._sources.map(x => x.get()))
}
private _onSourceValues(xs: any[]) {
const prevValue = this.getValue()
const next = this._combineFn(xs)
- if (!this._eq(prevValue, next))
- this.next(next)
+ if (!this._eq(prevValue, next)) this.next(next)
}
private _subscription: Subscription | null = null
private _refCount = 0
// Rx method overrides
- _subscribe(subscriber: Subscriber) { // tslint:disable-line function-name
+ // tslint:disable-next-line function-name
+ _subscribe(subscriber: Subscriber) {
if (!this._subscription) {
- this._subscription = combineLatest(this._sources)
- .subscribe(xs => this._onSourceValues(xs))
+ this._subscription = combineLatest(this._sources).subscribe(xs => this._onSourceValues(xs))
}
this._refCount++
diff --git a/packages/focal/src/atom/index.ts b/packages/focal/src/atom/index.ts
index 740ec82..26e74be 100644
--- a/packages/focal/src/atom/index.ts
+++ b/packages/focal/src/atom/index.ts
@@ -1,16 +1,9 @@
import { Observable, BehaviorSubject, Subscription } from 'rxjs'
import { tap, share, filter } from 'rxjs/operators'
-import {
- Atom as _Atom,
- ReadOnlyAtom,
- JsonAtom,
- CombinedAtomViewImpl
-} from './base'
+import { Atom as _Atom, ReadOnlyAtom, JsonAtom, CombinedAtomViewImpl } from './base'
-export {
- ReadOnlyAtom
-} from './base'
+export { ReadOnlyAtom } from './base'
// a hack we need to do so we can merge the Atom type with
// the namespace below and then export it.
@@ -30,20 +23,11 @@ export namespace Atom {
}
// tslint:disable no-unused-vars
- export function log(
- atom: Atom,
- name?: string
- ): Atom
+ export function log(atom: Atom, name?: string): Atom
- export function log(
- atom: ReadOnlyAtom,
- name?: string
- ): ReadOnlyAtom
+ export function log(atom: ReadOnlyAtom, name?: string): ReadOnlyAtom
- export function log(
- atom: Atom,
- logger?: (prevState: T, newState: T) => void
- ): Atom
+ export function log(atom: Atom, logger?: (prevState: T, newState: T) => void): Atom
export function log(
atom: ReadOnlyAtom,
@@ -127,12 +111,9 @@ export namespace Atom {
): ReadOnlyAtom
// tslint:enable no-unused-vars
- export function combine(
- ...args: (ReadOnlyAtom | ((...xs: any[]) => TResult))[]
- ) {
- return new CombinedAtomViewImpl(
- args.slice(undefined, -1) as ReadOnlyAtom[],
- xs => (args[args.length - 1] as ((...xs: any[]) => TResult))(...xs)
+ export function combine(...args: (ReadOnlyAtom | ((...xs: any[]) => TResult))[]) {
+ return new CombinedAtomViewImpl(args.slice(undefined, -1) as ReadOnlyAtom[], xs =>
+ (args[args.length - 1] as ((...xs: any[]) => TResult))(...xs)
)
}
@@ -170,20 +151,18 @@ export namespace Atom {
return new Observable>(o => {
const sub = new Subscription()
+ sub.add(atomSubj.pipe(filter((x): x is Atom => !!x)).subscribe(o))
+
sub.add(
- atomSubj
- .pipe(filter((x): x is Atom => !!x))
- .subscribe(o)
+ initAndUpdateAtom.subscribe(
+ undefined,
+ // propagate errors
+ e => o.error(e),
+ // propagate completion
+ () => o.complete()
+ )
)
- sub.add(initAndUpdateAtom.subscribe(
- undefined,
- // propagate errors
- e => o.error(e),
- // propagate completion
- () => o.complete()
- ))
-
return sub
})
}
diff --git a/packages/focal/src/equals.ts b/packages/focal/src/equals.ts
index ff0a4be..c526612 100644
--- a/packages/focal/src/equals.ts
+++ b/packages/focal/src/equals.ts
@@ -31,7 +31,8 @@
function arrayFromIterator(iter: Iterator) {
const result: T[] = []
let next: IteratorResult
- while (!(next = iter.next()).done) { // tslint:disable-line no-conditional-assignment
+ // tslint:disable-next-line no-conditional-assignment
+ while (!(next = iter.next()).done) {
result.push(next.value)
}
return result
@@ -64,7 +65,8 @@ function has(prop: string, obj: any) {
*/
function identical(a: any, b: any) {
// SameValue algorithm
- if (a === b) { // Steps 1-5, 7-10
+ if (a === b) {
+ // Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return a !== 0 || 1 / a === 1 / b
} else {
@@ -73,13 +75,17 @@ function identical(a: any, b: any) {
}
}
-const _isArguments = ((function () {
+const _isArguments = (function() {
const toString = Object.prototype.toString
return toString.call(arguments) === '[object Arguments]'
- ? function isArguments(x: any) { return toString.call(x) === '[object Arguments]' }
- : function isArguments(x: any) { return has('callee', x) }
-}) ())
+ ? function isArguments(x: any) {
+ return toString.call(x) === '[object Arguments]'
+ }
+ : function isArguments(x: any) {
+ return has('callee', x)
+ }
+})()
/**
* Returns a list containing the names of all the enumerable own properties of
@@ -87,27 +93,32 @@ const _isArguments = ((function () {
* Note that the order of the output array is not guaranteed to be consistent
* across different JS platforms.
*/
-const keys = ((function () {
+const keys = (function() {
// cover IE < 9 keys issues
- const hasEnumBug = !({ toString: null }).propertyIsEnumerable('toString')
+ const hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString')
const nonEnumerableProps = [
- 'constructor', 'valueOf', 'isPrototypeOf', 'toString',
- 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'
+ 'constructor',
+ 'valueOf',
+ 'isPrototypeOf',
+ 'toString',
+ 'propertyIsEnumerable',
+ 'hasOwnProperty',
+ 'toLocaleString'
]
// Safari bug
- const hasArgsEnumBug = ((function () {
+ const hasArgsEnumBug = (function() {
'use strict'
return arguments.propertyIsEnumerable('length')
- }) ())
+ })()
const contains = function contains(list: T[], item: T) {
- var idx = 0 // tslint:disable-line no-var-keyword
+ // tslint:disable-next-line no-var-keyword
+ var idx = 0
while (idx < list.length) {
- if (list[idx] === item)
- return true
+ if (list[idx] === item) return true
idx += 1
}
@@ -117,41 +128,60 @@ const keys = ((function () {
return typeof Object.keys === 'function' && !hasArgsEnumBug
? function keys(obj: any) {
- return Object(obj) !== obj ? [] : Object.keys(obj)
- }
+ return Object(obj) !== obj ? [] : Object.keys(obj)
+ }
: function keys(obj: any) {
- if (Object(obj) !== obj) return []
+ if (Object(obj) !== obj) return []
- let prop: string, nIdx: number
- const ks: string[] = []
- const checkArgsLength = hasArgsEnumBug && _isArguments(obj)
+ let prop: string, nIdx: number
+ const ks: string[] = []
+ const checkArgsLength = hasArgsEnumBug && _isArguments(obj)
- for (prop in obj) {
- if (has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
- ks[ks.length] = prop
+ for (prop in obj) {
+ if (has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
+ ks[ks.length] = prop
+ }
}
- }
- if (hasEnumBug) {
- nIdx = nonEnumerableProps.length - 1
- while (nIdx >= 0) {
- prop = nonEnumerableProps[nIdx]
- if (has(prop, obj) && !contains(ks, prop)) {
- ks[ks.length] = prop
+ if (hasEnumBug) {
+ nIdx = nonEnumerableProps.length - 1
+ while (nIdx >= 0) {
+ prop = nonEnumerableProps[nIdx]
+ if (has(prop, obj) && !contains(ks, prop)) {
+ ks[ks.length] = prop
+ }
+ nIdx -= 1
}
- nIdx -= 1
}
- }
- return ks
- }
-}) ())
+ return ks
+ }
+})()
type TypeDescString =
- 'Object' | 'Number' | 'Boolean' | 'String' | 'Null' | 'Array' | 'RegExp' |
- 'Int8Array' | 'Uint8Array' | 'Uint8ClampedArray' | 'Int16Array' | 'Uint16Array' |
- 'Int32Array' | 'Uint32Array' | 'Float32Array' | 'Float64Array' | 'Arguments' |
- 'Map' | 'Set' | 'Date' | 'Error' | 'ArrayBuffer' | 'Undefined'
+ | 'Object'
+ | 'Number'
+ | 'Boolean'
+ | 'String'
+ | 'Null'
+ | 'Array'
+ | 'RegExp'
+ | 'Int8Array'
+ | 'Uint8Array'
+ | 'Uint8ClampedArray'
+ | 'Int16Array'
+ | 'Uint16Array'
+ | 'Int32Array'
+ | 'Uint32Array'
+ | 'Float32Array'
+ | 'Float64Array'
+ | 'Arguments'
+ | 'Map'
+ | 'Set'
+ | 'Date'
+ | 'Error'
+ | 'ArrayBuffer'
+ | 'Undefined'
/**
* Gives a single-word string description of the (native) type of a value,
@@ -170,9 +200,11 @@ type TypeDescString =
* R.type(/[A-z]/); //=> "RegExp"
*/
function type(val: any) {
- return val === null ? 'Null' as TypeDescString
- : val === undefined ? 'Undefined' as TypeDescString
- : Object.prototype.toString.call(val).slice(8, -1) as TypeDescString
+ return val === null
+ ? ('Null' as TypeDescString)
+ : val === undefined
+ ? ('Undefined' as TypeDescString)
+ : (Object.prototype.toString.call(val).slice(8, -1) as TypeDescString)
}
/**
@@ -198,16 +230,16 @@ export function equals(a: any, b: any, stackA: any[] = [], stackB: any[] = []) {
if (a == null || b == null) return false
if (typeof a.equals === 'function' || typeof b.equals === 'function') {
- return typeof a.equals === 'function' && a.equals(b) &&
- typeof b.equals === 'function' && b.equals(a)
+ return (
+ typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a)
+ )
}
switch (type(a)) {
case 'Arguments':
case 'Array':
case 'Object':
- if (typeof a.constructor === 'function' &&
- functionName(a.constructor) === 'Promise') {
+ if (typeof a.constructor === 'function' && functionName(a.constructor) === 'Promise') {
return a === b
}
break
@@ -215,14 +247,12 @@ export function equals(a: any, b: any, stackA: any[] = [], stackB: any[] = []) {
case 'Boolean':
case 'Number':
case 'String':
- if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf())))
- return false
+ if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf()))) return false
break
case 'Date':
- if (!identical(a.valueOf(), b.valueOf()))
- return false
+ if (!identical(a.valueOf(), b.valueOf())) return false
break
@@ -230,12 +260,16 @@ export function equals(a: any, b: any, stackA: any[] = [], stackB: any[] = []) {
return a.name === b.name && a.message === b.message
case 'RegExp':
- if (!(a.source === b.source &&
- a.global === b.global &&
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky &&
- a.unicode === b.unicode)) {
+ if (
+ !(
+ a.source === b.source &&
+ a.global === b.global &&
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline &&
+ a.sticky === b.sticky &&
+ a.unicode === b.unicode
+ )
+ ) {
return false
}
@@ -268,13 +302,11 @@ export function equals(a: any, b: any, stackA: any[] = [], stackB: any[] = []) {
}
const keysA = keys(a)
- if (keysA.length !== keys(b).length)
- return false
+ if (keysA.length !== keys(b).length) return false
let idx = stackA.length - 1
while (idx >= 0) {
- if (stackA[idx] === a)
- return stackB[idx] === b
+ if (stackA[idx] === a) return stackB[idx] === b
idx -= 1
}
@@ -285,8 +317,7 @@ export function equals(a: any, b: any, stackA: any[] = [], stackB: any[] = []) {
while (idx >= 0) {
const key = keysA[idx]
- if (!(has(key, b) && equals(b[key], a[key], stackA, stackB)))
- return false
+ if (!(has(key, b) && equals(b[key], a[key], stackA, stackB))) return false
idx -= 1
}
diff --git a/packages/focal/src/index.ts b/packages/focal/src/index.ts
index 86d4298..a415b3d 100644
--- a/packages/focal/src/index.ts
+++ b/packages/focal/src/index.ts
@@ -2,11 +2,4 @@ export { Lens, Prism, Optic } from './lens/index'
export { Atom, ReadOnlyAtom } from './atom/index'
export { Option } from './utils'
-export {
- bind,
- lift,
- reactiveList,
- classes,
- bindElementProps,
- F
-} from './react'
+export { bind, lift, reactiveList, classes, bindElementProps, F } from './react'
diff --git a/packages/focal/src/lens/base.ts b/packages/focal/src/lens/base.ts
index c0f847c..d50e57e 100644
--- a/packages/focal/src/lens/base.ts
+++ b/packages/focal/src/lens/base.ts
@@ -3,7 +3,8 @@ import { Option } from './../utils'
export interface Optic {
get(s: TSource): T
set(v: U, s: TSource): TSource
- modify(updateFn: (v: T) => U, s: TSource): TSource // tslint:disable-line no-unused-vars
+ // tslint:disable-next-line no-unused-vars
+ modify(updateFn: (v: T) => U, s: TSource): TSource
// @TODO can't optic compose?
}
@@ -12,7 +13,8 @@ function createModify(
getter: (s: TSource) => T,
setter: (v: U, s: TSource) => TSource
) {
- return function modify(updateFn: (v: T) => U, s: TSource) { // tslint:disable-line
+ // tslint:disable-next-line
+ return function modify(updateFn: (v: T) => U, s: TSource) {
return setter(updateFn(getter(s)), s)
}
}
@@ -68,15 +70,11 @@ export namespace Prism {
return create(
(s: TSource) => {
const x = getter(s)
- return x !== undefined
- ? next.get(x)
- : undefined
+ return x !== undefined ? next.get(x) : undefined
},
(v: U, s: TSource) => {
const x = getter(s)
- return x !== undefined
- ? setter(next.set(v, x), s)
- : s
+ return x !== undefined ? setter(next.set(v, x), s) : s
}
)
}
@@ -129,15 +127,24 @@ export namespace Lens {
export function compose(l1: Lens, l2: Lens): Lens
export function compose(
- l1: Lens, l2: Lens, l3: Lens
+ l1: Lens,
+ l2: Lens,
+ l3: Lens
): Lens
export function compose(
- l1: Lens, l2: Lens, l3: Lens, l4: Lens
+ l1: Lens,
+ l2: Lens,
+ l3: Lens,
+ l4: Lens
): Lens
export function compose(
- l1: Lens, l2: Lens, l3: Lens, l4: Lens, l5: Lens
+ l1: Lens,
+ l2: Lens,
+ l3: Lens,
+ l4: Lens,
+ l5: Lens
): Lens
export function compose(...lenses: Lens[]): Lens
diff --git a/packages/focal/src/lens/index.ts b/packages/focal/src/lens/index.ts
index cb313de..20707d8 100644
--- a/packages/focal/src/lens/index.ts
+++ b/packages/focal/src/lens/index.ts
@@ -9,9 +9,7 @@
*
* @module
*/
-import {
- Lens, Prism, Optic
-} from './base'
+import { Lens, Prism, Optic } from './base'
// This import adds JSON-specific lens functions to the Lens
// namespace, in style of RxJS.
@@ -26,10 +24,6 @@ import {
// But maybe there is a way to avoid this?
import './json'
-export {
- PropExpr
-} from './json'
+export { PropExpr } from './json'
-export {
- Lens, Prism, Optic
-}
+export { Lens, Prism, Optic }
diff --git a/packages/focal/src/lens/json.ts b/packages/focal/src/lens/json.ts
index 1898863..2e4b4fa 100644
--- a/packages/focal/src/lens/json.ts
+++ b/packages/focal/src/lens/json.ts
@@ -4,38 +4,46 @@
* @module
*/
-import {
- structEq,
- setKey,
- conservatively,
- findIndex,
- Option,
- DEV_ENV,
- warning
-} from './../utils'
+import { structEq, setKey, conservatively, findIndex, Option, DEV_ENV, warning } from './../utils'
import { Lens, Prism } from './base'
export type PropExpr = (x: O) => P
// @TODO can we optimize this regexp?
-const PROP_EXPR_RE = new RegExp([
- '^', 'function', '\\(', '[^), ]+', '\\)', '\\{',
+const PROP_EXPR_RE = new RegExp(
+ [
+ '^',
+ 'function',
+ '\\(',
+ '[^), ]+',
+ '\\)',
+ '\\{',
'("use strict";)?',
'return\\s',
- '[^\\.]+\\.(\\S+?);?',
- '\\}', '$'
-].join('\\s*'))
-
-const WALLABY_PROP_EXPR_RE = new RegExp([
- '^', 'function', '\\(', '[^), ]+', '\\)', '\\{',
+ '[^\\.]+\\.(\\S+?);?',
+ '\\}',
+ '$'
+ ].join('\\s*')
+)
+
+const WALLABY_PROP_EXPR_RE = new RegExp(
+ [
+ '^',
+ 'function',
+ '\\(',
+ '[^), ]+',
+ '\\)',
+ '\\{',
'("use strict";)?',
- '(\\$_\\$wf\\(\\d+\\);)?', // wallaby.js code coverage compatability (#36)
+ '(\\$_\\$wf\\(\\d+\\);)?', // wallaby.js code coverage compatability (#36)
'return\\s',
- '(\\$_\\$w\\(\\d+, \\d+\\),\\s)?', // wallaby.js code coverage compatability (#36)
- '[^\\.]+\\.(\\S+?);?',
- '\\}', '$'
-].join('\\s*'))
+ '(\\$_\\$w\\(\\d+, \\d+\\),\\s)?', // wallaby.js code coverage compatability (#36)
+ '[^\\.]+\\.(\\S+?);?',
+ '\\}',
+ '$'
+ ].join('\\s*')
+)
export function parsePropertyPath(getterSource: string): string[] {
const exprRegexp = process.env.NODE_ENV === 'wallaby' ? WALLABY_PROP_EXPR_RE : PROP_EXPR_RE
@@ -140,17 +148,17 @@ export function keyImpl(): KeyImplFor
export function keyImpl(k?: string) {
return k === undefined
- // type-safe key
- ? (k: K): Lens =>
- Lens.create(
- (s: TObject) => s[k],
- (v: TObject[K], s: TObject) => setKey(k, v, s)
+ ? // type-safe key
+ (k: K): Lens =>
+ Lens.create(
+ (s: TObject) => s[k],
+ (v: TObject[K], s: TObject) => setKey(k, v, s)
+ )
+ : // untyped key
+ Lens.create(
+ (s: { [k: string]: any }) => s[k] as Option,
+ (v: any, s: { [k: string]: any }) => setKey(k, v, s)
)
- // untyped key
- : Lens.create(
- (s: { [k: string]: any }) => s[k] as Option,
- (v: any, s: { [k: string]: any }) => setKey(k, v, s)
- )
}
let propExprDeprecatedWarnings = 0
@@ -165,9 +173,9 @@ function warnPropExprDeprecated(path: string[]) {
warning(
`The property expression overload of Atom.lens and Lens.prop are deprecated and ` +
- `will be removed in next versions of Focal. Please use the key name overload for ` +
- `Atom.lens and Lens.key instead. ` +
- `You can convert your code by changing the calls:
+ `will be removed in next versions of Focal. Please use the key name overload for ` +
+ `Atom.lens and Lens.key instead. ` +
+ `You can convert your code by changing the calls:
a.lens(x => ${propExpr}) to a.lens(${keys}),
Lens.prop((x: T) => ${propExpr}) to Lens.key()(${keys}).`
)
@@ -185,8 +193,7 @@ export function propImpl(
}
export function indexImpl(i: number): Prism {
- if (i < 0)
- throw new TypeError(`${i} is not a valid array index, expected >= 0`)
+ if (i < 0) throw new TypeError(`${i} is not a valid array index, expected >= 0`)
return Prism.create(
(xs: TItem[]) => xs[i] as Option,
@@ -208,16 +215,13 @@ export function withDefaultImpl(defaultValue: T): Lens