Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

abstract-state-router

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

abstract-state-router - npm Package Compare versions

Comparing version 5.17.0 to 6.0.0

bundle.js

5

changelog.md

@@ -0,1 +1,6 @@

# [6.0.0](https://github.com/TehShrike/abstract-state-router/releases/tag/v6.0.0)
- `Promise` and `Object.assign` polyfills are now required for older browsers
- refactor: updated all the source code to ES2015 (though the published version is still compiled down to ES5)
# [5.17.0](https://github.com/TehShrike/abstract-state-router/releases/tag/v5.17.0)

@@ -2,0 +7,0 @@

451

index.js

@@ -1,64 +0,62 @@

var StateState = require('./lib/state-state')
var StateComparison = require('./lib/state-comparison')
var CurrentState = require('./lib/current-state')
var stateChangeLogic = require('./lib/state-change-logic')
var parse = require('./lib/state-string-parser')
var StateTransitionManager = require('./lib/state-transition-manager')
var defaultRouterOptions = require('./default-router-options.js')
const StateState = require('./lib/state-state')
const StateComparison = require('./lib/state-comparison')
const CurrentState = require('./lib/current-state')
const stateChangeLogic = require('./lib/state-change-logic')
const parse = require('./lib/state-string-parser')
const StateTransitionManager = require('./lib/state-transition-manager')
const defaultRouterOptions = require('./default-router-options.js')
var series = require('./lib/promise-map-series')
var denodeify = require('then-denodeify')
const series = require('./lib/promise-map-series')
const extend = require('./lib/extend.js')
var EventEmitter = require('eventemitter3')
var extend = require('xtend')
var newHashBrownRouter = require('hash-brown-router')
var combine = require('combine-arrays')
var buildPath = require('page-path-builder')
var nextTick = require('iso-next-tick')
const denodeify = require('then-denodeify')
const EventEmitter = require('eventemitter3')
const newHashBrownRouter = require('hash-brown-router')
const combine = require('combine-arrays')
const buildPath = require('page-path-builder')
const nextTick = require('iso-next-tick')
require('native-promise-only/npo')
const getProperty = name => obj => obj[name]
const reverse = ary => ary.slice().reverse()
const isFunction = property => obj => typeof obj[property] === 'function'
const isThenable = object => object && (typeof object === 'object' || typeof object === 'function') && typeof object.then === 'function'
const promiseMe = (fn, ...args) => new Promise(resolve => resolve(fn(...args)))
var expectedPropertiesOfAddState = [ 'name', 'route', 'defaultChild', 'data', 'template', 'resolve', 'activate', 'querystringParameters', 'defaultQuerystringParameters', 'defaultParameters' ]
const expectedPropertiesOfAddState = [ 'name', 'route', 'defaultChild', 'data', 'template', 'resolve', 'activate', 'querystringParameters', 'defaultQuerystringParameters', 'defaultParameters' ]
module.exports = function StateProvider(makeRenderer, rootElement, stateRouterOptions) {
var prototypalStateHolder = StateState()
var lastCompletelyLoadedState = CurrentState()
var lastStateStartedActivating = CurrentState()
var stateProviderEmitter = new EventEmitter()
var compareStartAndEndStates = StateComparison(prototypalStateHolder)
const prototypalStateHolder = StateState()
const lastCompletelyLoadedState = CurrentState()
const lastStateStartedActivating = CurrentState()
const stateProviderEmitter = new EventEmitter()
const compareStartAndEndStates = StateComparison(prototypalStateHolder)
function stateNameToArrayofStates(stateName) {
return parse(stateName).map(function(name) {
return prototypalStateHolder.get(name)
})
}
const stateNameToArrayofStates = stateName => parse(stateName).map(prototypalStateHolder.get)
StateTransitionManager(stateProviderEmitter)
stateRouterOptions = extend({
const { throwOnError, pathPrefix } = extend({
throwOnError: true,
pathPrefix: '#'
pathPrefix: '#',
}, stateRouterOptions)
if (!stateRouterOptions.router) {
stateRouterOptions.router = newHashBrownRouter(defaultRouterOptions)
}
const router = stateRouterOptions.router || newHashBrownRouter(defaultRouterOptions)
stateRouterOptions.router.on('not found', function(route, parameters) {
router.on('not found', (route, parameters) => {
stateProviderEmitter.emit('routeNotFound', route, parameters)
})
var destroyDom = null
var getDomChild = null
var renderDom = null
var resetDom = null
let destroyDom = null
let getDomChild = null
let renderDom = null
let resetDom = null
var activeDomApis = {}
var activeStateResolveContent = {}
var activeEmitters = {}
let activeStateResolveContent = {}
const activeDomApis = {}
const activeEmitters = {}
function handleError(event, err) {
nextTick(function() {
nextTick(() => {
stateProviderEmitter.emit(event, err)
console.error(event + ' - ' + err.message)
if (stateRouterOptions.throwOnError) {
console.error(`${event} - ${err.message}`)
if (throwOnError) {
throw err

@@ -70,6 +68,6 @@ }

function destroyStateName(stateName) {
var state = prototypalStateHolder.get(stateName)
const state = prototypalStateHolder.get(stateName)
stateProviderEmitter.emit('beforeDestroyState', {
state: state,
domApi: activeDomApis[stateName]
domApi: activeDomApis[stateName],
})

@@ -82,6 +80,6 @@

return destroyDom(activeDomApis[stateName]).then(function() {
return destroyDom(activeDomApis[stateName]).then(() => {
delete activeDomApis[stateName]
stateProviderEmitter.emit('afterDestroyState', {
state: state
state,
})

@@ -92,11 +90,11 @@ })

function resetStateName(parameters, stateName) {
var domApi = activeDomApis[stateName]
var content = getContentObject(activeStateResolveContent, stateName)
var state = prototypalStateHolder.get(stateName)
const domApi = activeDomApis[stateName]
const content = getContentObject(activeStateResolveContent, stateName)
const state = prototypalStateHolder.get(stateName)
stateProviderEmitter.emit('beforeResetState', {
domApi: domApi,
content: content,
state: state,
parameters: parameters
domApi,
content,
state,
parameters,
})

@@ -108,7 +106,7 @@

return resetDom({
domApi: domApi,
content: content,
domApi,
content,
template: state.template,
parameters: parameters
}).then(function(newDomApi) {
parameters,
}).then(newDomApi => {
if (newDomApi) {

@@ -120,5 +118,5 @@ activeDomApis[stateName] = newDomApi

domApi: activeDomApis[stateName],
content: content,
state: state,
parameters: parameters
content,
state,
parameters,
})

@@ -129,6 +127,6 @@ })

function getChildElementForStateName(stateName) {
return new Promise(function(resolve) {
var parent = prototypalStateHolder.getParent(stateName)
return new Promise(resolve => {
const parent = prototypalStateHolder.getParent(stateName)
if (parent) {
var parentDomApi = activeDomApis[parent.name]
const parentDomApi = activeDomApis[parent.name]
resolve(getDomChild(parentDomApi))

@@ -142,24 +140,24 @@ } else {

function renderStateName(parameters, stateName) {
return getChildElementForStateName(stateName).then(function(childElement) {
var state = prototypalStateHolder.get(stateName)
var content = getContentObject(activeStateResolveContent, stateName)
return getChildElementForStateName(stateName).then(element => {
const state = prototypalStateHolder.get(stateName)
const content = getContentObject(activeStateResolveContent, stateName)
stateProviderEmitter.emit('beforeCreateState', {
state: state,
content: content,
parameters: parameters
state,
content,
parameters,
})
return renderDom({
element: childElement,
template: state.template,
content: content,
parameters: parameters
}).then(function(domApi) {
element,
content,
parameters,
}).then(domApi => {
activeDomApis[stateName] = domApi
stateProviderEmitter.emit('afterCreateState', {
state: state,
domApi: domApi,
content: content,
parameters: parameters
state,
domApi,
content,
parameters,
})

@@ -172,3 +170,3 @@ return domApi

function renderAll(stateNames, parameters) {
return series(stateNames, renderStateName.bind(null, parameters))
return series(stateNames, stateName => renderStateName(parameters, stateName))
}

@@ -178,3 +176,3 @@

try {
var finalDestinationStateName = prototypalStateHolder.applyDefaultChildStates(state.name)
const finalDestinationStateName = prototypalStateHolder.applyDefaultChildStates(state.name)

@@ -186,4 +184,4 @@ if (finalDestinationStateName === state.name) {

var theRouteWeNeedToEndUpAt = makePath(finalDestinationStateName, parameters)
var currentRoute = stateRouterOptions.router.location.get()
const theRouteWeNeedToEndUpAt = makePath(finalDestinationStateName, parameters)
const currentRoute = router.location.get()

@@ -205,11 +203,11 @@ if (theRouteWeNeedToEndUpAt === currentRoute) {

if (typeof state === 'undefined') {
throw new Error('Expected \'state\' to be passed in.')
throw new Error(`Expected 'state' to be passed in.`)
} else if (typeof state.name === 'undefined') {
throw new Error('Expected the \'name\' option to be passed in.')
throw new Error(`Expected the 'name' option to be passed in.`)
} else if (typeof state.template === 'undefined') {
throw new Error('Expected the \'template\' option to be passed in.')
throw new Error(`Expected the 'template' option to be passed in.`)
}
Object.keys(state).filter(function(key) {
Object.keys(state).filter(key => {
return expectedPropertiesOfAddState.indexOf(key) === -1
}).forEach(function(key) {
}).forEach(key => {
console.warn('Unexpected property passed to addState:', key)

@@ -220,5 +218,5 @@ })

var route = prototypalStateHolder.buildFullStateRoute(state.name)
const route = prototypalStateHolder.buildFullStateRoute(state.name)
stateRouterOptions.router.add(route, onRouteChange.bind(null, state))
router.add(route, parameters => onRouteChange(state, parameters))
}

@@ -238,9 +236,9 @@

function ifNotCancelled(fn) {
return function() {
return (...args) => {
if (transition.cancelled) {
var err = new Error('The transition to ' + newStateName + 'was cancelled')
const err = new Error(`The transition to ${newStateName} was cancelled`)
err.wasCancelledBySomeoneElse = true
throw err
} else {
return fn.apply(null, arguments)
return fn(...args)
}

@@ -251,81 +249,88 @@ }

return promiseMe(prototypalStateHolder.guaranteeAllStatesExist, newStateName)
.then(function applyDefaultParameters() {
var state = prototypalStateHolder.get(newStateName)
var defaultParams = state.defaultParameters || state.defaultQuerystringParameters || {}
var needToApplyDefaults = Object.keys(defaultParams).some(function missingParameterValue(param) {
return typeof parameters[param] === 'undefined'
})
.then(function applyDefaultParameters() {
const state = prototypalStateHolder.get(newStateName)
const defaultParams = state.defaultParameters || state.defaultQuerystringParameters || {}
const needToApplyDefaults = Object.keys(defaultParams).some(function missingParameterValue(param) {
return typeof parameters[param] === 'undefined'
})
if (needToApplyDefaults) {
throw redirector(newStateName, extend(defaultParams, parameters))
}
return state
}).then(ifNotCancelled(function(state) {
stateProviderEmitter.emit('stateChangeStart', state, parameters, stateNameToArrayofStates(state.name))
lastStateStartedActivating.set(state.name, parameters)
})).then(function getStateChanges() {
var stateComparisonResults = compareStartAndEndStates(lastCompletelyLoadedState.get().name, lastCompletelyLoadedState.get().parameters, newStateName, parameters)
return stateChangeLogic(stateComparisonResults) // { destroy, change, create }
}).then(ifNotCancelled(function resolveDestroyAndActivateStates(stateChanges) {
return resolveStates(getStatesToResolve(stateChanges), extend(parameters)).catch(function onResolveError(e) {
e.stateChangeError = true
throw e
}).then(ifNotCancelled(function destroyAndActivate(stateResolveResultsObject) {
transition.cancellable = false
if (needToApplyDefaults) {
throw redirector(newStateName, extend(defaultParams, parameters))
}
return state
}).then(ifNotCancelled(state => {
stateProviderEmitter.emit('stateChangeStart', state, parameters, stateNameToArrayofStates(state.name))
lastStateStartedActivating.set(state.name, parameters)
})).then(function getStateChanges() {
const stateComparisonResults = compareStartAndEndStates({
original: lastCompletelyLoadedState.get(),
destination: {
name: newStateName,
parameters,
},
})
return stateChangeLogic(stateComparisonResults) // { destroy, change, create }
}).then(ifNotCancelled(function resolveDestroyAndActivateStates(stateChanges) {
return resolveStates(getStatesToResolve(stateChanges), extend(parameters)).catch(function onResolveError(e) {
e.stateChangeError = true
throw e
}).then(ifNotCancelled(function destroyAndActivate(stateResolveResultsObject) {
transition.cancellable = false
function activateAll() {
var statesToActivate = stateChanges.change.concat(stateChanges.create)
const activateAll = () => activateStates(
stateChanges.change.concat(stateChanges.create)
)
return activateStates(statesToActivate)
}
activeStateResolveContent = extend(activeStateResolveContent, stateResolveResultsObject)
activeStateResolveContent = extend(activeStateResolveContent, stateResolveResultsObject)
return series(reverse(stateChanges.destroy), destroyStateName).then(() => {
return series(
reverse(stateChanges.change),
stateName => resetStateName(extend(parameters), stateName)
)
}).then(
() => renderAll(stateChanges.create, extend(parameters)).then(activateAll)
)
}))
return series(reverse(stateChanges.destroy), destroyStateName).then(function() {
return series(reverse(stateChanges.change), resetStateName.bind(null, extend(parameters)))
}).then(function() {
return renderAll(stateChanges.create, extend(parameters)).then(activateAll)
})
}))
function activateStates(stateNames) {
return stateNames.map(prototypalStateHolder.get).forEach(state => {
const emitter = new EventEmitter()
const context = Object.create(emitter)
context.domApi = activeDomApis[state.name]
context.data = state.data
context.parameters = parameters
context.content = getContentObject(activeStateResolveContent, state.name)
activeEmitters[state.name] = emitter
function activateStates(stateNames) {
return stateNames.map(prototypalStateHolder.get).forEach(function(state) {
var emitter = new EventEmitter()
var context = Object.create(emitter)
context.domApi = activeDomApis[state.name]
context.data = state.data
context.parameters = parameters
context.content = getContentObject(activeStateResolveContent, state.name)
activeEmitters[state.name] = emitter
try {
state.activate && state.activate(context)
} catch (e) {
nextTick(function() {
throw e
})
}
})
}
})).then(function stateChangeComplete() {
lastCompletelyLoadedState.set(newStateName, parameters)
try {
stateProviderEmitter.emit('stateChangeEnd', prototypalStateHolder.get(newStateName), parameters, stateNameToArrayofStates(newStateName))
} catch (e) {
handleError('stateError', e)
}
}).catch(ifNotCancelled(function handleStateChangeError(err) {
if (err && err.redirectTo) {
stateProviderEmitter.emit('stateChangeCancelled', err)
return stateProviderEmitter.go(err.redirectTo.name, err.redirectTo.params, { replace: true })
} else if (err) {
handleError('stateChangeError', err)
}
})).catch(function handleCancellation(err) {
if (err && err.wasCancelledBySomeoneElse) {
// we don't care, the state transition manager has already emitted the stateChangeCancelled for us
} else {
throw new Error("This probably shouldn't happen, maybe file an issue or something " + err)
}
})
try {
state.activate && state.activate(context)
} catch (e) {
nextTick(() => {
throw e
})
}
})
}
})).then(function stateChangeComplete() {
lastCompletelyLoadedState.set(newStateName, parameters)
try {
stateProviderEmitter.emit('stateChangeEnd', prototypalStateHolder.get(newStateName), parameters, stateNameToArrayofStates(newStateName))
} catch (e) {
handleError('stateError', e)
}
}).catch(ifNotCancelled(function handleStateChangeError(err) {
if (err && err.redirectTo) {
stateProviderEmitter.emit('stateChangeCancelled', err)
return stateProviderEmitter.go(err.redirectTo.name, err.redirectTo.params, { replace: true })
} else if (err) {
handleError('stateChangeError', err)
}
})).catch(function handleCancellation(err) {
if (err && err.wasCancelledBySomeoneElse) {
// we don't care, the state transition manager has already emitted the stateChangeCancelled for us
} else {
throw new Error(`This probably shouldn't happen, maybe file an issue or something ${err}`)
}
})
}

@@ -344,6 +349,6 @@

var destinationStateName = stateName === null ? getGuaranteedPreviousState().name : stateName
const destinationStateName = stateName === null ? getGuaranteedPreviousState().name : stateName
var destinationState = prototypalStateHolder.get(destinationStateName) || {}
var defaultParams = destinationState.defaultParameters || destinationState.defaultQuerystringParameters
const destinationState = prototypalStateHolder.get(destinationStateName) || {}
const defaultParams = destinationState.defaultParameters || destinationState.defaultQuerystringParameters

@@ -353,35 +358,36 @@ parameters = extend(defaultParams, parameters)

prototypalStateHolder.guaranteeAllStatesExist(destinationStateName)
var route = prototypalStateHolder.buildFullStateRoute(destinationStateName)
const route = prototypalStateHolder.buildFullStateRoute(destinationStateName)
return buildPath(route, parameters || {})
}
var defaultOptions = {
replace: false
const defaultOptions = {
replace: false,
}
stateProviderEmitter.addState = addState
stateProviderEmitter.go = function go(newStateName, parameters, options) {
stateProviderEmitter.go = (newStateName, parameters, options) => {
options = extend(defaultOptions, options)
var goFunction = options.replace ? stateRouterOptions.router.replace : stateRouterOptions.router.go
const goFunction = options.replace ? router.replace : router.go
return promiseMe(makePath, newStateName, parameters, options).then(goFunction, handleError.bind(null, 'stateChangeError'))
return promiseMe(makePath, newStateName, parameters, options)
.then(goFunction, err => handleError('stateChangeError', err))
}
stateProviderEmitter.evaluateCurrentRoute = function evaluateCurrentRoute(defaultState, defaultParams) {
return promiseMe(makePath, defaultState, defaultParams).then(function(defaultPath) {
stateRouterOptions.router.evaluateCurrent(defaultPath)
}).catch(function(err) {
handleError('stateError', err)
})
stateProviderEmitter.evaluateCurrentRoute = (defaultState, defaultParams) => {
return promiseMe(makePath, defaultState, defaultParams).then(defaultPath => {
router.evaluateCurrent(defaultPath)
}).catch(err => handleError('stateError', err))
}
stateProviderEmitter.makePath = function makePathAndPrependHash(stateName, parameters, options) {
return stateRouterOptions.pathPrefix + makePath(stateName, parameters, options)
stateProviderEmitter.makePath = (stateName, parameters, options) => {
return pathPrefix + makePath(stateName, parameters, options)
}
stateProviderEmitter.stateIsActive = function stateIsActive(stateName, opts) {
var currentState = lastCompletelyLoadedState.get()
return (currentState.name === stateName || currentState.name.indexOf(stateName + '.') === 0) && (typeof opts === 'undefined' || Object.keys(opts).every(function matches(key) {
return opts[key] === currentState.parameters[key]
}))
stateProviderEmitter.stateIsActive = (stateName, parameters = null) => {
const currentState = lastCompletelyLoadedState.get()
const stateNameMatches = currentState.name === stateName || currentState.name.indexOf(stateName + '.') === 0
const parametersWereNotPassedIn = !parameters
return stateNameMatches
&& (parametersWereNotPassedIn || Object.keys(parameters).every(key => parameters[key] === currentState.parameters[key]))
}
var renderer = makeRenderer(stateProviderEmitter)
const renderer = makeRenderer(stateProviderEmitter)

@@ -397,9 +403,9 @@ destroyDom = denodeify(renderer.destroy)

function getContentObject(stateResolveResultsObject, stateName) {
var allPossibleResolvedStateNames = parse(stateName)
const allPossibleResolvedStateNames = parse(stateName)
return allPossibleResolvedStateNames.filter(function(stateName) {
return stateResolveResultsObject[stateName]
}).reduce(function(obj, stateName) {
return extend(obj, stateResolveResultsObject[stateName])
}, {})
return allPossibleResolvedStateNames
.filter(stateName => stateResolveResultsObject[stateName])
.reduce((obj, stateName) => {
return extend(obj, stateResolveResultsObject[stateName])
}, {})
}

@@ -411,4 +417,4 @@

name: newStateName,
params: parameters
}
params: parameters,
},
}

@@ -419,16 +425,15 @@ }

function resolveStates(states, parameters) {
var statesWithResolveFunctions = states.filter(isFunction('resolve'))
var stateNamesWithResolveFunctions = statesWithResolveFunctions.map(property('name'))
var resolves = Promise.all(statesWithResolveFunctions.map(function(state) {
return new Promise(function(resolve, reject) {
function resolveCb(err, content) {
err ? reject(err) : resolve(content)
}
const statesWithResolveFunctions = states.filter(isFunction('resolve'))
const stateNamesWithResolveFunctions = statesWithResolveFunctions.map(getProperty('name'))
resolveCb.redirect = function redirect(newStateName, parameters) {
const resolves = Promise.all(statesWithResolveFunctions.map(state => {
return new Promise((resolve, reject) => {
const resolveCb = (err, content) => err ? reject(err) : resolve(content)
resolveCb.redirect = (newStateName, parameters) => {
reject(redirector(newStateName, parameters))
}
var res = state.resolve(state.data, parameters, resolveCb)
if (res && (typeof res === 'object' || typeof res === 'function') && typeof res.then === 'function') {
const res = state.resolve(state.data, parameters, resolveCb)
if (isThenable(res)) {
resolve(res)

@@ -439,35 +444,11 @@ }

return resolves.then(function(resolveResults) {
return combine({
return resolves.then(resolveResults =>
combine({
stateName: stateNamesWithResolveFunctions,
resolveResult: resolveResults
}).reduce(function(obj, result) {
resolveResult: resolveResults,
}).reduce((obj, result) => {
obj[result.stateName] = result.resolveResult
return obj
}, {})
})
)
}
function property(name) {
return function(obj) {
return obj[name]
}
}
function reverse(ary) {
return ary.slice().reverse()
}
function isFunction(property) {
return function(obj) {
return typeof obj[property] === 'function'
}
}
function promiseMe() {
var fn = Array.prototype.shift.apply(arguments)
var args = arguments
return new Promise(function(resolve) {
resolve(fn.apply(null, args))
})
}
module.exports = function CurrentState() {
var current = {
let current = {
name: '',
parameters: {}
parameters: {},
}
return {
get: function() {
get() {
return current
},
set: function(name, parameters) {
set(name, parameters) {
current = {
name: name,
parameters: parameters
name,
parameters,
}
}
},
}
}
// Pulled from https://github.com/joliss/promise-map-series and prettied up a bit
var Promise = require('native-promise-only/npo')
module.exports = function sequence(array, iterator, thisArg) {
var current = Promise.resolve()
var cb = arguments.length > 2 ? iterator.bind(thisArg) : iterator
var results = array.map(function(value, i) {
return current = current.then(function(j) {
return cb(value, j, array)
}.bind(null, i))
})
return Promise.all(results)
module.exports = function sequence(array, iterator) {
let currentPromise = Promise.resolve()
return Promise.all(
array.map((value, i) => {
return currentPromise = currentPromise.then(() => iterator(value, i, array))
})
)
}
module.exports = function stateChangeLogic(stateComparisonResults) {
var hitChangingState = false
var hitDestroyedState = false
let hitChangingState = false
let hitDestroyedState = false
var output = {
const output = {
destroy: [],
change: [],
create: []
create: [],
}
stateComparisonResults.forEach(function(state) {
stateComparisonResults.forEach(state => {
hitChangingState = hitChangingState || state.stateParametersChanged

@@ -13,0 +13,0 @@ hitDestroyedState = hitDestroyedState || state.stateNameChanged

@@ -1,17 +0,19 @@

var stateStringParser = require('./state-string-parser')
var combine = require('combine-arrays')
var pathToRegexp = require('path-to-regexp-with-reversible-keys')
const stateStringParser = require('./state-string-parser')
const extend = require('./extend.js')
const combine = require('combine-arrays')
const pathToRegexp = require('path-to-regexp-with-reversible-keys')
module.exports = function StateComparison(stateState) {
var getPathParameters = pathParameters()
const getPathParameters = pathParameters()
var parametersChanged = parametersThatMatterWereChanged.bind(null, stateState, getPathParameters)
const parametersChanged = args => parametersThatMatterWereChanged(extend(args, { stateState, getPathParameters }))
return stateComparison.bind(null, parametersChanged)
return args => stateComparison(extend(args, { parametersChanged }))
}
function pathParameters() {
var parameters = {}
const parameters = {}
return function getPathParameters(path) {
return path => {
if (!path) {

@@ -31,26 +33,28 @@ return []

function parametersThatMatterWereChanged(stateState, getPathParameters, stateName, fromParameters, toParameters) {
var state = stateState.get(stateName)
var querystringParameters = state.querystringParameters || []
var parameters = getPathParameters(state.route).concat(querystringParameters)
function parametersThatMatterWereChanged({ stateState, getPathParameters, stateName, fromParameters, toParameters }) {
const state = stateState.get(stateName)
const querystringParameters = state.querystringParameters || []
const parameters = getPathParameters(state.route).concat(querystringParameters)
return Array.isArray(parameters) && parameters.some(function(key) {
return fromParameters[key] !== toParameters[key]
})
return Array.isArray(parameters) && parameters.some(
key => fromParameters[key] !== toParameters[key]
)
}
function stateComparison(parametersChanged, originalState, originalParameters, newState, newParameters) {
var states = combine({
start: stateStringParser(originalState),
end: stateStringParser(newState)
function stateComparison({ parametersChanged, original, destination }) {
const states = combine({
start: stateStringParser(original.name),
end: stateStringParser(destination.name),
})
return states.map(function(states) {
return {
nameBefore: states.start,
nameAfter: states.end,
stateNameChanged: states.start !== states.end,
stateParametersChanged: states.start === states.end && parametersChanged(states.start, originalParameters, newParameters)
}
})
return states.map(({ start, end }) => ({
nameBefore: start,
nameAfter: end,
stateNameChanged: start !== end,
stateParametersChanged: start === end && parametersChanged({
stateName: start,
fromParameters: original.parameters,
toParameters: destination.parameters,
}),
}))
}

@@ -1,12 +0,12 @@

var stateStringParser = require('./state-string-parser')
const stateStringParser = require('./state-string-parser')
module.exports = function StateState() {
var states = {}
const states = {}
function getHierarchy(name) {
var names = stateStringParser(name)
const names = stateStringParser(name)
return names.map(function(name) {
return names.map(name => {
if (!states[name]) {
throw new Error('State ' + name + ' not found')
throw new Error(`State ${name} not found`)
}

@@ -18,3 +18,3 @@ return states[name]

function getParent(name) {
var parentName = getParentName(name)
const parentName = getParentName(name)

@@ -25,6 +25,6 @@ return parentName && states[parentName]

function getParentName(name) {
var names = stateStringParser(name)
const names = stateStringParser(name)
if (names.length > 1) {
var secondToLast = names.length - 2
const secondToLast = names.length - 2

@@ -38,9 +38,7 @@ return names[secondToLast]

function guaranteeAllStatesExist(newStateName) {
var stateNames = stateStringParser(newStateName)
var statesThatDontExist = stateNames.filter(function(name) {
return !states[name]
})
const stateNames = stateStringParser(newStateName)
const statesThatDontExist = stateNames.filter(name => !states[name])
if (statesThatDontExist.length > 0) {
throw new Error('State ' + statesThatDontExist[statesThatDontExist.length - 1] + ' does not exist')
throw new Error(`State ${statesThatDontExist[statesThatDontExist.length - 1]} does not exist`)
}

@@ -50,18 +48,16 @@ }

function buildFullStateRoute(stateName) {
return getHierarchy(stateName).map(function(state) {
return '/' + (state.route || '')
}).join('').replace(/\/{2,}/g, '/')
return getHierarchy(stateName).map(state => `/${state.route || ''}`)
.join('')
.replace(/\/{2,}/g, '/')
}
function applyDefaultChildStates(stateName) {
var state = states[stateName]
const state = states[stateName]
function getDefaultChildStateName() {
return state && (typeof state.defaultChild === 'function'
const defaultChildStateName = state && (
typeof state.defaultChild === 'function'
? state.defaultChild()
: state.defaultChild)
}
: state.defaultChild
)
var defaultChildStateName = getDefaultChildStateName()
if (!defaultChildStateName) {

@@ -71,3 +67,3 @@ return stateName

var fullStateName = stateName + '.' + defaultChildStateName
const fullStateName = `${stateName}.${defaultChildStateName}`

@@ -79,15 +75,15 @@ return applyDefaultChildStates(fullStateName)

return {
add: function(name, state) {
add(name, state) {
states[name] = state
},
get: function(name) {
get(name) {
return name && states[name]
},
getHierarchy: getHierarchy,
getParent: getParent,
getParentName: getParentName,
guaranteeAllStatesExist: guaranteeAllStatesExist,
buildFullStateRoute: buildFullStateRoute,
applyDefaultChildStates: applyDefaultChildStates
getHierarchy,
getParent,
getParentName,
guaranteeAllStatesExist,
buildFullStateRoute,
applyDefaultChildStates,
}
}

@@ -1,9 +0,11 @@

module.exports = function(stateString) {
return stateString.split('.').reduce(function(stateNames, latestNameChunk) {
if (stateNames.length) {
latestNameChunk = stateNames[stateNames.length - 1] + '.' + latestNameChunk
}
stateNames.push(latestNameChunk)
module.exports = stateString => {
return stateString.split('.').reduce((stateNames, latestNameChunk) => {
stateNames.push(
stateNames.length
? stateNames[stateNames.length - 1] + '.' + latestNameChunk
: latestNameChunk
)
return stateNames
}, [])
}

@@ -1,4 +0,4 @@

module.exports = function (emitter) {
var currentTransitionAttempt = null
var nextTransition = null
module.exports = emitter => {
let currentTransitionAttempt = null
let nextTransition = null

@@ -12,5 +12,3 @@ function doneTransitioning() {

function isTransitioning() {
return !!currentTransitionAttempt
}
const isTransitioning = () => !!currentTransitionAttempt

@@ -25,3 +23,3 @@ function beginNextTransitionAttempt() {

currentTransitionAttempt.transition.cancelled = true
var err = new Error('State transition cancelled by the state transition manager')
const err = new Error('State transition cancelled by the state transition manager')
err.wasCancelledBySomeoneElse = true

@@ -31,3 +29,3 @@ emitter.emit('stateChangeCancelled', err)

emitter.on('stateChangeAttempt', function(beginStateChange) {
emitter.on('stateChangeAttempt', beginStateChange => {
nextTransition = createStateTransitionAttempt(beginStateChange)

@@ -47,11 +45,11 @@

function createStateTransitionAttempt(beginStateChange) {
var transition = {
const transition = {
cancelled: false,
cancellable: true
cancellable: true,
}
return {
transition: transition,
beginStateChange: beginStateChange.bind(null, transition)
transition,
beginStateChange: (...args) => beginStateChange(transition, ...args),
}
}
}
{
"name": "abstract-state-router",
"version": "5.17.0",
"version": "6.0.0",
"description": "Like ui-router, but without all the Angular. The best way to structure a single-page webapp.",
"main": "index.js",
"scripts": {
"test": "tape test/*.js | faucet",
"build": "rollup -c",
"test": "npm run build && tape test/*.js | faucet",
"coverage": "covert test/*.js",
"browserwatch": "watchify test-browser/add-color.js test/*.js -o test-browser/build.js -d",
"browserstackbuild": "browserify test-browser/add-color.js test/*.js node_modules/browserstack-tape-reporter/index.js -o test-browser/build.js",
"browserstack": "npm run browserstackbuild && browserstack-runner"
"browserwatch": "sh -c 'rollup -c -w --dev & npm run watchtests'",
"watchtests": "watchify test-browser/add-color.js test/*.js -o test-browser/build.js -d"
},

@@ -33,20 +33,24 @@ "repository": {

"iso-next-tick": "1.0.0",
"native-promise-only": "0.8.1",
"page-path-builder": "~1.0.3",
"path-to-regexp-with-reversible-keys": "~1.0.3",
"then-denodeify": "1.0.1",
"xtend": "^4.0.0"
"then-denodeify": "1.0.1"
},
"devDependencies": {
"babel-core": "6.26.0",
"babel-plugin-external-helpers": "6.22.0",
"babel-preset-es2015": "6.24.1",
"browserify": "14.0.0",
"browserstack-runner": "TehShrike/browserstack-runner#fixing-json-borking",
"browserstack-tape-reporter": "~1.1.0",
"covert": "^1.1.0",
"faucet": "0.0.1",
"rollup": "0.50.0",
"rollup-plugin-babel": "3.0.2",
"rollup-plugin-commonjs": "8.2.1",
"rollup-plugin-node-resolve": "3.0.0",
"rollup-plugin-visualizer": "0.3.1",
"rollup-watch": "4.3.1",
"tap-browser-color": "0.1.2",
"tape": "^4.1.0",
"tape-catch": "1.0.6",
"watchify": "3.9.0",
"webpack": "^1.12.14"
"watchify": "3.9.0"
}
}

@@ -13,2 +13,8 @@ abstract-state-router lets you build single-page webapps using nested routes/states. Your code doesn't reference routes directly, like `/app/users/josh`, but by name and properties, like `app.user` + `{ name: 'josh' }`.

# 2017-10: major version bump, 6.0!
The first major version bump in two and a half years! Don't worry though, it's entirely backwards compatible, except that the Promise polyfill has been dropped, so the library size should be a bit smaller.
If you're supporting old browsers, you'll need polyfills for `Promise` and `Object.assign`. Check out [polyfill.io](https://polyfill.io/), it makes life super-easy.
**[Read the changelog](./changelog.md)**

@@ -285,9 +291,2 @@

Automated browser testing provided by [Browserstack](https://www.browserstack.com/).
Tested in Chrome, Firefox, Safari, and IE10+ (IE9 doesn't support [replace](https://developer.mozilla.org/en-US/docs/Web/API/Location/replace)).
[![Build Status](https://travis-ci.org/TehShrike/abstract-state-router.svg?branch=master)](https://travis-ci.org/TehShrike/abstract-state-router)
# State change flow

@@ -294,0 +293,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc