diff --git a/src/params/param.ts b/src/params/param.ts index 6f9ca6d6..7b42758e 100644 --- a/src/params/param.ts +++ b/src/params/param.ts @@ -2,14 +2,14 @@ * @internalapi * @module params */ /** for typedoc */ -import {extend, filter, map, applyPairs, allTrueR} from "../common/common"; -import {prop, propEq} from "../common/hof"; -import {isInjectable, isDefined, isString, isArray} from "../common/predicates"; -import {RawParams, ParamDeclaration} from "../params/interface"; -import {services} from "../common/coreservices"; -import {matcherConfig} from "../url/urlMatcherConfig"; -import {ParamType} from "./type"; -import {ParamTypes} from "./paramTypes"; +import { extend, filter, map, applyPairs, allTrueR } from "../common/common"; +import { prop, propEq } from "../common/hof"; +import { isInjectable, isDefined, isString, isArray } from "../common/predicates"; +import { RawParams, ParamDeclaration } from "../params/interface"; +import { services } from "../common/coreservices"; +import { ParamType } from "./type"; +import { ParamTypes } from "./paramTypes"; +import { UrlMatcherFactory } from "../url/urlMatcherFactory"; let hasOwn = Object.prototype.hasOwnProperty; let isShorthand = (cfg: ParamDeclaration) => @@ -43,10 +43,10 @@ function getType(cfg: ParamDeclaration, urlType: ParamType, location: DefType, i /** * returns false, true, or the squash value to indicate the "default parameter url squash policy". */ -function getSquashPolicy(config: ParamDeclaration, isOptional: boolean) { +function getSquashPolicy(config: ParamDeclaration, isOptional: boolean, defaultPolicy: (boolean|string)) { let squash = config.squash; if (!isOptional || squash === false) return false; - if (!isDefined(squash) || squash == null) return matcherConfig.defaultSquashPolicy(); + if (!isDefined(squash) || squash == null) return defaultPolicy; if (squash === true || isString(squash)) return squash; throw new Error(`Invalid squash policy: '${squash}'. Valid policies: false, true, or arbitrary string`); } @@ -75,15 +75,15 @@ export class Param { raw: boolean; config: any; - constructor(id: string, type: ParamType, config: ParamDeclaration, location: DefType, paramTypes: ParamTypes) { + constructor(id: string, type: ParamType, config: ParamDeclaration, location: DefType, urlMatcherFactory: UrlMatcherFactory) { config = unwrapShorthand(config); - type = getType(config, type, location, id, paramTypes); + type = getType(config, type, location, id, urlMatcherFactory.paramTypes); let arrayMode = getArrayMode(); type = arrayMode ? type.$asArray(arrayMode, location === DefType.SEARCH) : type; let isOptional = config.value !== undefined; let dynamic = isDefined(config.dynamic) ? !!config.dynamic : !!type.dynamic; let raw = isDefined(config.raw) ? !!config.raw : !!type.raw; - let squash = getSquashPolicy(config, isOptional); + let squash = getSquashPolicy(config, isOptional, urlMatcherFactory.defaultSquashPolicy()); let replace = getReplace(config, arrayMode, isOptional, squash); // array config: param name (param[]) overrides default settings. explicit config overrides param name. @@ -146,21 +146,6 @@ export class Param { return `{Param:${this.id} ${this.type} squash: '${this.squash}' optional: ${this.isOptional}}`; } - /** Creates a new [[Param]] from a CONFIG block */ - static fromConfig(id: string, type: ParamType, config: any, paramTypes: ParamTypes): Param { - return new Param(id, type, config, DefType.CONFIG, paramTypes); - } - - /** Creates a new [[Param]] from a url PATH */ - static fromPath(id: string, type: ParamType, config: any, paramTypes: ParamTypes): Param { - return new Param(id, type, config, DefType.PATH, paramTypes); - } - - /** Creates a new [[Param]] from a url SEARCH */ - static fromSearch(id: string, type: ParamType, config: any, paramTypes: ParamTypes): Param { - return new Param(id, type, config, DefType.SEARCH, paramTypes); - } - static values(params: Param[], values: RawParams = {}): RawParams { return params.map(param => [param.id, param.value(values[param.id])]).reduce(applyPairs, {}); } diff --git a/src/state/stateBuilder.ts b/src/state/stateBuilder.ts index bd6c2ec1..7a8a7ff8 100644 --- a/src/state/stateBuilder.ts +++ b/src/state/stateBuilder.ts @@ -13,7 +13,7 @@ import {UrlMatcher} from "../url/urlMatcher"; import {Resolvable} from "../resolve/resolvable"; import {services} from "../common/coreservices"; import {ResolvePolicy} from "../resolve/interface"; -import {ParamTypes} from "../params/paramTypes"; +import { ParamFactory } from "../url/interface"; const parseUrl = (url: string): any => { if (!isString(url)) return false; @@ -84,9 +84,9 @@ function navigableBuilder(state: State) { return !isRoot(state) && state.url ? state : (state.parent ? state.parent.navigable : null); }; -const getParamsBuilder = (paramTypes: ParamTypes) => +const getParamsBuilder = (paramFactory: ParamFactory) => function paramsBuilder(state: State): { [key: string]: Param } { - const makeConfigParam = (config: any, id: string) => Param.fromConfig(id, null, config, paramTypes); + const makeConfigParam = (config: any, id: string) => paramFactory.fromConfig(id, null, config); let urlParams: Param[] = (state.url && state.url.parameters({inherit: false})) || []; let nonUrlParams: Param[] = values(mapObj(omit(state.params || {}, urlParams.map(prop('id'))), makeConfigParam)); return urlParams.concat(nonUrlParams).map(p => [p.id, p]).reduce(applyPairs, {}); @@ -212,7 +212,7 @@ export class StateBuilder { /** An object that contains all the BuilderFunctions registered, key'd by the name of the State property they build */ private builders: Builders; - constructor(private matcher: StateMatcher, $urlMatcherFactoryProvider: UrlMatcherFactory) { + constructor(private matcher: StateMatcher, urlMatcherFactory: UrlMatcherFactory) { let self = this; const root = () => matcher.find(""); @@ -229,10 +229,10 @@ export class StateBuilder { parent: [ parentBuilder ], data: [ dataBuilder ], // Build a URLMatcher if necessary, either via a relative or absolute URL - url: [ getUrlBuilder($urlMatcherFactoryProvider, root) ], + url: [ getUrlBuilder(urlMatcherFactory, root) ], // Keep track of the closest ancestor state that has a URL (i.e. is navigable) navigable: [ getNavigableBuilder(isRoot) ], - params: [ getParamsBuilder($urlMatcherFactoryProvider.paramTypes) ], + params: [ getParamsBuilder(urlMatcherFactory.paramFactory) ], // Each framework-specific ui-router implementation should define its own `views` builder // e.g., src/ng1/statebuilders/views.ts views: [], diff --git a/src/url/index.ts b/src/url/index.ts index be00327c..0f185e9b 100644 --- a/src/url/index.ts +++ b/src/url/index.ts @@ -3,7 +3,6 @@ * @module url */ /** for typedoc */ export * from "./urlMatcher"; -export * from "./urlMatcherConfig"; export * from "./urlMatcherFactory"; export * from "./urlRouter"; export * from "./urlRule"; diff --git a/src/url/interface.ts b/src/url/interface.ts new file mode 100644 index 00000000..930c68ed --- /dev/null +++ b/src/url/interface.ts @@ -0,0 +1,25 @@ +import { LocationServices, $InjectorLike, LocationConfig } from "../common/coreservices"; +import { UrlRule } from "./urlRule"; +import { UrlMatcher } from "./urlMatcher"; +import { IInjectable } from "../common/common"; +import { ParamType } from "../params/type"; +import { Param } from "../params/param"; + +export interface ParamFactory { + /** Creates a new [[Param]] from a CONFIG block */ + fromConfig(id: string, type: ParamType, config: any): Param; + /** Creates a new [[Param]] from a url PATH */ + fromPath(id: string, type: ParamType, config: any): Param; + /** Creates a new [[Param]] from a url SEARCH */ + fromSearch(id: string, type: ParamType, config: any): Param; +} + +export interface UrlConfig extends LocationConfig, UrlMatcherConfig {}; + +export interface UrlMatcherConfig { + caseInsensitive(value?: boolean): boolean; + strictMode(value?: boolean): boolean; + defaultSquashPolicy(value?: (boolean|string)): (boolean|string); + paramType(name, type?) +} + diff --git a/src/url/urlMatcher.ts b/src/url/urlMatcher.ts index ec09bdb1..4e83e2c8 100644 --- a/src/url/urlMatcher.ts +++ b/src/url/urlMatcher.ts @@ -15,6 +15,7 @@ import {DefType} from "../params/param"; import {unnestR} from "../common/common"; import {arrayTuples} from "../common/common"; import {RawParams} from "../params/interface"; +import { ParamFactory } from "./interface"; /** @hidden */ function quoteRegExp(string: any, param?: any) { @@ -114,7 +115,7 @@ export class UrlMatcher { * - `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`. * - `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`. */ - constructor(pattern: string, paramTypes: ParamTypes, public config?: any) { + constructor(pattern: string, paramTypes: ParamTypes, paramFactory: ParamFactory, public config?: any) { this.pattern = pattern; this.config = defaults(this.config, { params: {}, @@ -172,7 +173,7 @@ export class UrlMatcher { if (p.segment.indexOf('?') >= 0) break; // we're into the search part checkParamErrors(p.id); - this._params.push(Param.fromPath(p.id, p.type, this.config.paramMap(p.cfg, false), paramTypes)); + this._params.push(paramFactory.fromPath(p.id, p.type, this.config.paramMap(p.cfg, false))); this._segments.push(p.segment); patterns.push([p.segment, tail(this._params)]); last = placeholder.lastIndex; @@ -192,7 +193,7 @@ export class UrlMatcher { while ((m = searchPlaceholder.exec(search))) { p = matchDetails(m, true); checkParamErrors(p.id); - this._params.push(Param.fromSearch(p.id, p.type, this.config.paramMap(p.cfg, true), paramTypes)); + this._params.push(paramFactory.fromSearch(p.id, p.type, this.config.paramMap(p.cfg, true))); last = placeholder.lastIndex; // check if ?& } diff --git a/src/url/urlMatcherConfig.ts b/src/url/urlMatcherConfig.ts deleted file mode 100644 index d6dec34c..00000000 --- a/src/url/urlMatcherConfig.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** @module url */ /** for typedoc */ -import {isDefined, isString} from "../common/predicates"; - -export class MatcherConfig { - _isCaseInsensitive: boolean = false; - _isStrictMode: boolean = true; - _defaultSquashPolicy: (boolean|string) = false; - - caseInsensitive(value?: boolean): boolean { - return this._isCaseInsensitive = isDefined(value) ? value : this._isCaseInsensitive; - } - - strictMode(value?: boolean): boolean { - return this._isStrictMode = isDefined(value) ? value : this._isStrictMode; - } - - defaultSquashPolicy(value?: (boolean|string)): (boolean|string) { - if (isDefined(value) && value !== true && value !== false && !isString(value)) - throw new Error(`Invalid squash policy: ${value}. Valid policies: false, true, arbitrary-string`); - return this._defaultSquashPolicy = isDefined(value) ? value : this._defaultSquashPolicy; - } -} - -// TODO: Do not export global instance; create one in UIRouter() constructor -export let matcherConfig = new MatcherConfig(); diff --git a/src/url/urlMatcherFactory.ts b/src/url/urlMatcherFactory.ts index c98b519b..4ae62d9b 100644 --- a/src/url/urlMatcherFactory.ts +++ b/src/url/urlMatcherFactory.ts @@ -2,23 +2,15 @@ * @coreapi * @module url */ /** for typedoc */ -import {forEach, extend} from "../common/common"; -import {isObject, isDefined, isFunction} from "../common/predicates"; - -import {UrlMatcher} from "./urlMatcher"; -import {matcherConfig} from "./urlMatcherConfig"; -import {Param} from "../params/param"; -import {ParamTypes} from "../params/paramTypes"; -import {ParamTypeDefinition} from "../params/interface"; +import { forEach, extend } from "../common/common"; +import { isObject, isDefined, isFunction, isString } from "../common/predicates"; +import { UrlMatcher } from "./urlMatcher"; +import { Param, DefType } from "../params/param"; +import { ParamTypes } from "../params/paramTypes"; +import { ParamTypeDefinition } from "../params/interface"; import { Disposable } from "../interface"; - -/** @hidden */ -function getDefaultConfig() { - return { - strict: matcherConfig.strictMode(), - caseInsensitive: matcherConfig.caseInsensitive() - }; -} +import { ParamType } from "../params/type"; +import { ParamFactory } from "./interface"; /** * Factory for [[UrlMatcher]] instances. @@ -27,7 +19,10 @@ function getDefaultConfig() { * `$urlMatcherFactor` or ng1 providers as `$urlMatcherFactoryProvider`. */ export class UrlMatcherFactory implements Disposable { - paramTypes = new ParamTypes(); + /** @hidden */ paramTypes = new ParamTypes(); + /** @hidden */ _isCaseInsensitive: boolean = false; + /** @hidden */ _isStrictMode: boolean = true; + /** @hidden */ _defaultSquashPolicy: (boolean|string) = false; constructor() { extend(this, { UrlMatcher, Param }); @@ -39,8 +34,8 @@ export class UrlMatcherFactory implements Disposable { * @param value `false` to match URL in a case sensitive manner; otherwise `true`; * @returns the current value of caseInsensitive */ - caseInsensitive(value: boolean) { - return matcherConfig.caseInsensitive(value); + caseInsensitive(value?: boolean): boolean { + return this._isCaseInsensitive = isDefined(value) ? value : this._isCaseInsensitive; } /** @@ -49,8 +44,8 @@ export class UrlMatcherFactory implements Disposable { * @param value `false` to match trailing slashes in URLs, otherwise `true`. * @returns the current value of strictMode */ - strictMode(value: boolean) { - return matcherConfig.strictMode(value); + strictMode(value?: boolean): boolean { + return this._isStrictMode = isDefined(value) ? value : this._isStrictMode; } /** @@ -64,10 +59,16 @@ export class UrlMatcherFactory implements Disposable { * the parameter value from the URL and replace it with this string. * @returns the current value of defaultSquashPolicy */ - defaultSquashPolicy(value: string) { - return matcherConfig.defaultSquashPolicy(value); + defaultSquashPolicy(value?: (boolean|string)) { + if (isDefined(value) && value !== true && value !== false && !isString(value)) + throw new Error(`Invalid squash policy: ${value}. Valid policies: false, true, arbitrary-string`); + return this._defaultSquashPolicy = isDefined(value) ? value : this._defaultSquashPolicy; } + /** @hidden */ + private _getConfig = (config) => + extend({ strict: this._isStrictMode, caseInsensitive: this._isCaseInsensitive }, config); + /** * Creates a [[UrlMatcher]] for the specified pattern. * @@ -76,7 +77,7 @@ export class UrlMatcherFactory implements Disposable { * @returns The UrlMatcher. */ compile(pattern: string, config?: { [key: string]: any }) { - return new UrlMatcher(pattern, this.paramTypes, extend(getDefaultConfig(), config)); + return new UrlMatcher(pattern, this.paramTypes, this.paramFactory, this._getConfig(config)); } /** @@ -86,7 +87,7 @@ export class UrlMatcherFactory implements Disposable { * @returns `true` if the object matches the `UrlMatcher` interface, by * implementing all the same methods. */ - isMatcher(object: any) { + isMatcher(object: any): boolean { // TODO: typeof? if (!isObject(object)) return false; let result = true; @@ -128,6 +129,21 @@ export class UrlMatcherFactory implements Disposable { return this; }; + /** @internalapi Creates a new [[Param]] for a given location (DefType) */ + paramFactory: ParamFactory = { + /** Creates a new [[Param]] from a CONFIG block */ + fromConfig: (id: string, type: ParamType, config: any) => + new Param(id, type, config, DefType.CONFIG, this), + + /** Creates a new [[Param]] from a url PATH */ + fromPath: (id: string, type: ParamType, config: any) => + new Param(id, type, config, DefType.PATH, this), + + /** Creates a new [[Param]] from a url SEARCH */ + fromSearch: (id: string, type: ParamType, config: any) => + new Param(id, type, config, DefType.SEARCH, this), + }; + /** @internalapi */ dispose() { this.paramTypes.dispose(); diff --git a/src/url/urlRouter.ts b/src/url/urlRouter.ts index afeb06ed..528b2da9 100644 --- a/src/url/urlRouter.ts +++ b/src/url/urlRouter.ts @@ -141,9 +141,9 @@ export class UrlRouter implements Disposable { * * #### Example: * ```js - * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), { - * person: "bob" - * }); + * matcher = $umf.compile("/about/:person"); + * params = { person: "bob" }; + * $bob = $urlRouter.href(matcher, params); * // $bob == "/about/bob"; * ``` * diff --git a/src/url/urlService.ts b/src/url/urlService.ts index f80944eb..faa0fc60 100644 --- a/src/url/urlService.ts +++ b/src/url/urlService.ts @@ -3,6 +3,7 @@ import { UIRouter } from "../router"; import { LocationServices, notImplemented, LocationConfig } from "../common/coreservices"; import { noop, createProxyFunctions } from "../common/common"; +import { UrlConfig } from "./interface"; /** @hidden */ const makeStub = (keys: string[]): any => @@ -49,7 +50,7 @@ export class UrlService implements LocationServices { * This information can be used to build absolute URLs, such as * `https://example.com:443/basepath/state/substate?param1=a#hashvalue`; */ - config: LocationConfig; + config: UrlConfig; constructor(private router: UIRouter) { this.config = {} as any; diff --git a/test/stateHelperSpec.ts b/test/stateHelperSpec.ts index d126ea29..95b4f608 100644 --- a/test/stateHelperSpec.ts +++ b/test/stateHelperSpec.ts @@ -130,7 +130,7 @@ describe('state helpers', function() { }); it('should compile a UrlMatcher for ^ URLs', function() { - var url = new UrlMatcher('/', paramTypes); + var url = new UrlMatcher('/', paramTypes, null); spyOn(urlMatcherFactoryProvider, 'compile').and.returnValue(url); spyOn(urlMatcherFactoryProvider, 'isMatcher').and.returnValue(true); @@ -158,7 +158,7 @@ describe('state helpers', function() { it('should pass through custom UrlMatchers', function() { var root = states[''] = { url: { append: function() {} } }; - var url = new UrlMatcher("/", paramTypes); + var url = new UrlMatcher("/", paramTypes, null); spyOn(urlMatcherFactoryProvider, 'isMatcher').and.returnValue(true); spyOn(root.url, 'append').and.returnValue(url); expect(builder.builder('url')({ url: url })).toBe(url); diff --git a/test/urlMatcherFactorySpec.ts b/test/urlMatcherFactorySpec.ts index 40bd5bb8..60667007 100644 --- a/test/urlMatcherFactorySpec.ts +++ b/test/urlMatcherFactorySpec.ts @@ -4,17 +4,13 @@ import { TestingPlugin } from "./_testingPlugin"; import { LocationPlugin } from "../src/vanilla/interface"; var router: UIRouter; -var $urlMatcherFactory: UrlMatcherFactory; +var $umf: UrlMatcherFactory; var $location: LocationServices; -function makeMatcher(url, config?) { - return new UrlMatcher(url, $urlMatcherFactory.paramTypes, config); -} - beforeEach(function() { router = new UIRouter(); router.plugin(TestingPlugin); - $urlMatcherFactory = router.urlMatcherFactory; + $umf = router.urlMatcherFactory; let locationPlugin = router.getPlugin('vanilla.memoryLocation') as LocationPlugin; $location = locationPlugin.service; }); @@ -24,71 +20,71 @@ describe("UrlMatcher", function () { describe("provider", function () { it("should factory matchers with correct configuration", function () { - $urlMatcherFactory.caseInsensitive(false); - expect($urlMatcherFactory.compile('/hello').exec('/HELLO')).toBeNull(); + $umf.caseInsensitive(false); + expect($umf.compile('/hello').exec('/HELLO')).toBeNull(); - $urlMatcherFactory.caseInsensitive(true); - expect($urlMatcherFactory.compile('/hello').exec('/HELLO')).toEqual({}); + $umf.caseInsensitive(true); + expect($umf.compile('/hello').exec('/HELLO')).toEqual({}); - $urlMatcherFactory.strictMode(true); - expect($urlMatcherFactory.compile('/hello').exec('/hello/')).toBeNull(); + $umf.strictMode(true); + expect($umf.compile('/hello').exec('/hello/')).toBeNull(); - $urlMatcherFactory.strictMode(false); - expect($urlMatcherFactory.compile('/hello').exec('/hello/')).toEqual({}); + $umf.strictMode(false); + expect($umf.compile('/hello').exec('/hello/')).toEqual({}); }); it("should correctly validate UrlMatcher interface", function () { - var m = makeMatcher("/"); - expect($urlMatcherFactory.isMatcher(m)).toBe(true); + var m = $umf.compile("/"); + expect($umf.isMatcher(m)).toBe(true); m = extend({}, m, { validates: null }); - expect($urlMatcherFactory.isMatcher(m)).toBe(false); + expect($umf.isMatcher(m)).toBe(false); }); }); it("should match static URLs", function () { - expect(makeMatcher('/hello/world').exec('/hello/world')).toEqual({}); + expect($umf.compile('/hello/world').exec('/hello/world')).toEqual({}); }); it("should match static case insensitive URLs", function () { - expect(makeMatcher('/hello/world', { caseInsensitive: true }).exec('/heLLo/World')).toEqual({}); + expect($umf.compile('/hello/world', { caseInsensitive: true }).exec('/heLLo/World')).toEqual({}); }); it("should match against the entire path", function () { - var matcher = makeMatcher('/hello/world', { strict: true }); + var matcher = $umf.compile('/hello/world', { strict: true }); expect(matcher.exec('/hello/world/')).toBeNull(); expect(matcher.exec('/hello/world/suffix')).toBeNull(); }); it("should parse parameter placeholders", function () { - var matcher = makeMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from&to'); + var matcher = $umf.compile('/users/:id/details/{type}/{repeat:[0-9]+}?from&to'); expect(matcher.parameters().map(prop('id'))).toEqual(['id', 'type', 'repeat', 'from', 'to']); }); it("should encode and decode duplicate query string values as array", function () { - var matcher = makeMatcher('/?foo'), array = { foo: ["bar", "baz"] }; + var matcher = $umf.compile('/?foo'), array = { foo: ["bar", "baz"] }; expect(matcher.exec('/', array)).toEqual(array); expect(matcher.format(array)).toBe('/?foo=bar&foo=baz'); }); describe("snake-case parameters", function() { it("should match if properly formatted", function() { - var matcher = makeMatcher('/users/?from&to&snake-case&snake-case-triple'); + var matcher = $umf.compile('/users/?from&to&snake-case&snake-case-triple'); expect(matcher.parameters().map(prop('id'))).toEqual(['from', 'to', 'snake-case', 'snake-case-triple']); }); it("should not match if invalid", function() { var err = "Invalid parameter name '-snake' in pattern '/users/?from&to&-snake'"; - expect(function() { makeMatcher('/users/?from&to&-snake'); }).toThrowError(err); + expect(function() { $umf.compile('/users/?from&to&-snake'); }).toThrowError(err); err = "Invalid parameter name 'snake-' in pattern '/users/?from&to&snake-'"; - expect(function() { makeMatcher('/users/?from&to&snake-'); }).toThrowError(err); + expect(function() { $umf.compile('/users/?from&to&snake-'); }).toThrowError(err); }); }); describe("parameters containing periods", function() { it("should match if properly formatted", function() { - var matcher = makeMatcher('/users/?from&to&with.periods&with.periods.also'); + var matcher = $umf.compile('/users/?from&to&with.periods&with.periods.also'); var params = matcher.parameters().map(function(p) { return p.id; }); expect(params.sort()).toEqual(['from','to','with.periods','with.periods.also']); @@ -96,47 +92,47 @@ describe("UrlMatcher", function () { it("should not match if invalid", function() { var err = new Error("Invalid parameter name '.periods' in pattern '/users/?from&to&.periods'"); - expect(function() { makeMatcher('/users/?from&to&.periods'); }).toThrow(err); + expect(function() { $umf.compile('/users/?from&to&.periods'); }).toThrow(err); err = new Error("Invalid parameter name 'periods.' in pattern '/users/?from&to&periods.'"); - expect(function() { makeMatcher('/users/?from&to&periods.'); }).toThrow(err); + expect(function() { $umf.compile('/users/?from&to&periods.'); }).toThrow(err); }); }); describe(".exec()", function() { it("should capture parameter values", function () { - var m = makeMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from&to', { strict: false }); + var m = $umf.compile('/users/:id/details/{type}/{repeat:[0-9]+}?from&to', { strict: false }); expect(m.exec('/users/123/details//0', {})).toEqualData({ id:'123', type:'', repeat:'0'}); }); it("should capture catch-all parameters", function () { - var m = makeMatcher('/document/*path'); + var m = $umf.compile('/document/*path'); expect(m.exec('/document/a/b/c', {})).toEqual({ path: 'a/b/c' }); expect(m.exec('/document/', {})).toEqual({ path: '' }); }); it("should use the optional regexp with curly brace placeholders", function () { - var m = makeMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from&to'); + var m = $umf.compile('/users/:id/details/{type}/{repeat:[0-9]+}?from&to'); expect(m.exec('/users/123/details/what/thisShouldBeDigits', {})).toBeNull(); }); it("should not use optional regexp for '/'", function () { - var m = makeMatcher('/{language:(?:fr|en|de)}'); + var m = $umf.compile('/{language:(?:fr|en|de)}'); expect(m.exec('/', {})).toBeNull(); }); it("should work with empty default value", function () { - var m = makeMatcher('/foo/:str', { params: { str: { value: "" } } }); + var m = $umf.compile('/foo/:str', { params: { str: { value: "" } } }); expect(m.exec('/foo/', {})).toEqual({ str: "" }); }); it("should work with empty default value for regex", function () { - var m = makeMatcher('/foo/{param:(?:foo|bar|)}', { params: { param: { value: "" } } }); + var m = $umf.compile('/foo/{param:(?:foo|bar|)}', { params: { param: { value: "" } } }); expect(m.exec('/foo/', {})).toEqual({ param: "" }); }); it("should treat the URL as already decoded and does not decode it further", function () { - expect(makeMatcher('/users/:id').exec('/users/100%25', {})).toEqual({ id: '100%25'}); + expect($umf.compile('/users/:id').exec('/users/100%25', {})).toEqual({ id: '100%25'}); }); xit('should allow embedded capture groups', function () { @@ -146,7 +142,7 @@ describe("UrlMatcher", function () { }; forEach(shouldPass, function(url, route) { - expect(makeMatcher(route).exec(url, {})).toEqual({ + expect($umf.compile(route).exec(url, {})).toEqual({ childParam: "childParam", matchedParam: "someword" }); @@ -160,7 +156,7 @@ describe("UrlMatcher", function () { }; forEach(shouldThrow, function(url, route) { - expect(function() { makeMatcher(route).exec(url, {}); }).toThrowError( + expect(function() { $umf.compile(route).exec(url, {}); }).toThrowError( "Unbalanced capture group in route '" + route + "'" ); }); @@ -171,40 +167,40 @@ describe("UrlMatcher", function () { }; forEach(shouldPass, function(url, route) { - expect(function() { makeMatcher(route).exec(url, {}); }).not.toThrow(); + expect(function() { $umf.compile(route).exec(url, {}); }).not.toThrow(); }); }); }); describe(".format()", function() { it("should reconstitute the URL", function () { - var m = makeMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from'), + var m = $umf.compile('/users/:id/details/{type}/{repeat:[0-9]+}?from'), params = { id:'123', type:'default', repeat:444, ignored:'value', from:'1970' }; expect(m.format(params)).toEqual('/users/123/details/default/444?from=1970'); }); it("should encode URL parameters", function () { - expect(makeMatcher('/users/:id').format({ id:'100%'})).toEqual('/users/100%25'); + expect($umf.compile('/users/:id').format({ id:'100%'})).toEqual('/users/100%25'); }); it("encodes URL parameters with hashes", function () { - var m = makeMatcher('/users/:id#:section'); + var m = $umf.compile('/users/:id#:section'); expect(m.format({ id: 'bob', section: 'contact-details' })).toEqual('/users/bob#contact-details'); }); it("should trim trailing slashes when the terminal value is optional", function () { var config = { params: { id: { squash: true, value: '123' } } }, - m = makeMatcher('/users/:id', config), + m = $umf.compile('/users/:id', config), params = { id: '123' }; expect(m.format(params)).toEqual('/users'); }); it("should format query parameters from parent, child, grandchild matchers", function() { - var m = makeMatcher('/parent?qParent'); - var m2 = m.append(makeMatcher('/child?qChild')); - var m3 = m2.append(makeMatcher('/grandchild?qGrandchild')); + var m = $umf.compile('/parent?qParent'); + var m2 = m.append($umf.compile('/child?qChild')); + var m3 = m2.append($umf.compile('/grandchild?qGrandchild')); var params = { qParent: 'parent', qChild: 'child', qGrandchild: 'grandchild' }; var url = '/parent/child/grandchild?qParent=parent&qChild=child&qGrandchild=grandchild'; @@ -217,43 +213,43 @@ describe("UrlMatcher", function () { describe(".append()", function() { it("should append matchers", function () { - var matcher = makeMatcher('/users/:id/details/{type}?from').append(makeMatcher('/{repeat:[0-9]+}?to')); + var matcher = $umf.compile('/users/:id/details/{type}?from').append($umf.compile('/{repeat:[0-9]+}?to')); var params = matcher.parameters(); expect(params.map(prop('id'))).toEqual(['id', 'type', 'from', 'repeat', 'to']); }); it("should return a new matcher", function () { - var base = makeMatcher('/users/:id/details/{type}?from'); - var matcher = base.append(makeMatcher('/{repeat:[0-9]+}?to')); + var base = $umf.compile('/users/:id/details/{type}?from'); + var matcher = base.append($umf.compile('/{repeat:[0-9]+}?to')); expect(matcher).not.toBe(base); }); it("should respect $urlMatcherFactoryProvider.strictMode", function() { - var m = makeMatcher('/'); - $urlMatcherFactory.strictMode(false); - m = m.append($urlMatcherFactory.compile("foo")); + var m = $umf.compile('/'); + $umf.strictMode(false); + m = m.append($umf.compile("foo")); expect(m.exec("/foo")).toEqual({}); expect(m.exec("/foo/")).toEqual({}) }); it("should respect $urlMatcherFactoryProvider.caseInsensitive", function() { - var m = makeMatcher('/'); - $urlMatcherFactory.caseInsensitive(true); - m = m.append($urlMatcherFactory.compile("foo")); + var m = $umf.compile('/'); + $umf.caseInsensitive(true); + m = m.append($umf.compile("foo")); expect(m.exec("/foo")).toEqual({}); expect(m.exec("/FOO")).toEqual({}); }); it("should respect $urlMatcherFactoryProvider.caseInsensitive when validating regex params", function() { - var m = makeMatcher('/'); - $urlMatcherFactory.caseInsensitive(true); - m = m.append($urlMatcherFactory.compile("foo/{param:bar}")); + var m = $umf.compile('/'); + $umf.caseInsensitive(true); + m = m.append($umf.compile("foo/{param:bar}")); expect(m.validates({ param: 'BAR' })).toEqual(true); }); it("should generate/match params in the proper order", function() { - var m = makeMatcher('/foo?queryparam'); - m = m.append(makeMatcher("/bar/:pathparam")); + var m = $umf.compile('/foo?queryparam'); + m = m.append($umf.compile("/bar/:pathparam")); expect(m.exec("/foo/bar/pathval", { queryparam: "queryval" })).toEqual({ pathparam: "pathval", queryparam: "queryval" @@ -264,13 +260,13 @@ describe("UrlMatcher", function () { describe("multivalue-query-parameters", function() { it("should handle .is() for an array of values", function () { - var m = makeMatcher('/foo?{param1:int}'), param = m.parameter('param1'); + var m = $umf.compile('/foo?{param1:int}'), param = m.parameter('param1'); expect(param.type.is([1, 2, 3])).toBe(true); expect(param.type.is([1, "2", 3])).toBe(false); }); it("should handle .equals() for two arrays of values", function () { - var m = makeMatcher('/foo?{param1:int}&{param2:date}'), + var m = $umf.compile('/foo?{param1:int}&{param2:date}'), param1 = m.parameter('param1'), param2 = m.parameter('param2'); @@ -287,7 +283,7 @@ describe("UrlMatcher", function () { }); it("should conditionally be wrapped in an array by default", function () { - var m = makeMatcher('/foo?param1'); + var m = $umf.compile('/foo?param1'); // empty array [] is treated like "undefined" expect(m.format({ param1: undefined })).toBe("/foo"); @@ -322,7 +318,7 @@ describe("UrlMatcher", function () { }); it("should be wrapped in an array if array: true", function () { - var m = makeMatcher('/foo?param1', { params: { param1: { array: true } } }); + var m = $umf.compile('/foo?param1', { params: { param1: { array: true } } }); // empty array [] is treated like "undefined" expect(m.format({ param1: undefined })).toBe("/foo"); @@ -356,7 +352,7 @@ describe("UrlMatcher", function () { }); it("should be wrapped in an array if paramname looks like param[]", function () { - var m = makeMatcher('/foo?param1[]'); + var m = $umf.compile('/foo?param1[]'); expect(m.exec("/foo")).toEqualData({}); @@ -372,7 +368,7 @@ describe("UrlMatcher", function () { // Test for issue #2222 it("should return default value, if query param is missing.", function() { - var m = makeMatcher('/state?param1¶m2¶m3¶m5', { + var m = $umf.compile('/state?param1¶m2¶m3¶m5', { params: { param1 : 'value1', param2 : {array: true, value: ['value2']}, @@ -401,7 +397,7 @@ describe("UrlMatcher", function () { }); it("should not be wrapped by ui-router into an array if array: false", (function() { - var m = makeMatcher('/foo?param1', { params: { param1: { array: false } } }); + var m = $umf.compile('/foo?param1', { params: { param1: { array: false } } }); expect(m.exec("/foo")).toEqualData({}); @@ -418,7 +414,7 @@ describe("UrlMatcher", function () { describe("multivalue-path-parameters", function() { it("should behave as a single-value by default", (function() { - var m = makeMatcher('/foo/:param1'); + var m = $umf.compile('/foo/:param1'); expect(m.exec("/foo/")).toEqual({ param1: ""}); @@ -428,7 +424,7 @@ describe("UrlMatcher", function () { })); it("should be split on - in url and wrapped in an array if array: true", (function() { - var m = makeMatcher('/foo/:param1', { params: { param1: { array: true } } }); + var m = $umf.compile('/foo/:param1', { params: { param1: { array: true } } }); expect(m.exec("/foo/")).toEqual({ param1: undefined }); expect(m.exec("/foo/bar")).toEqual({ param1: [ "bar" ] }); @@ -441,7 +437,7 @@ describe("UrlMatcher", function () { })); it("should behave similar to multi-value query params", (function() { - var m = makeMatcher('/foo/:param1[]'); + var m = $umf.compile('/foo/:param1[]'); // empty array [] is treated like "undefined" expect(m.format({ "param1[]": undefined })).toBe("/foo/"); @@ -471,7 +467,7 @@ describe("UrlMatcher", function () { })); it("should be split on - in url and wrapped in an array if paramname looks like param[]", (function() { - var m = makeMatcher('/foo/:param1[]'); + var m = $umf.compile('/foo/:param1[]'); expect(m.exec("/foo/")).toEqual({ "param1[]": undefined }); expect(m.exec("/foo/bar")).toEqual({ "param1[]": [ "bar" ] }); @@ -483,7 +479,7 @@ describe("UrlMatcher", function () { })); it("should allow path param arrays with '-' in the values", (function() { - var m = makeMatcher('/foo/:param1[]'); + var m = $umf.compile('/foo/:param1[]'); expect(m.exec("/foo/")).toEqual({ "param1[]": undefined }); expect(m.exec("/foo/bar\\-")).toEqual({ "param1[]": [ "bar-" ] }); @@ -497,7 +493,7 @@ describe("UrlMatcher", function () { })); // xit("should handle angular 1 $location.url encode/decodes correctly", (function() { - // var m = makeMatcher('/foo/:param1[]'); + // var m = $umf.compile('/foo/:param1[]'); // // $location.setUrl(m.format({ "param1[]": [ 'bar-', '-baz' ] })); // expect(m.exec($location.path(), $location.search())).toEqual({ "param1[]": [ 'bar-', '-baz' ] }); @@ -517,13 +513,13 @@ describe("urlMatcherFactoryProvider", function () { describe(".type()", function () { var m; beforeEach(function() { - $urlMatcherFactory.type("myType", {} as any, function() { + $umf.type("myType", {} as any, function() { return { decode: function() { return { status: 'decoded' }; }, is: isObject } as any; }); - m = makeMatcher("/test?{foo:myType}"); + m = $umf.compile("/test?{foo:myType}"); }); it("should handle arrays properly with config-time custom type definitions", function () { @@ -534,19 +530,19 @@ describe("urlMatcherFactoryProvider", function () { // TODO: Fix object pollution between tests for urlMatcherConfig afterEach(function () { - $urlMatcherFactory.caseInsensitive(false); + $umf.caseInsensitive(false); }); }); describe("urlMatcherFactory", function () { it("compiles patterns", function () { - var matcher = $urlMatcherFactory.compile('/hello/world'); + var matcher = $umf.compile('/hello/world'); expect(matcher instanceof UrlMatcher).toBe(true); }); it("recognizes matchers", function () { - expect($urlMatcherFactory.isMatcher(makeMatcher('/'))).toBe(true); + expect($umf.isMatcher($umf.compile('/'))).toBe(true); var custom = { format: noop, @@ -557,28 +553,28 @@ describe("urlMatcherFactory", function () { parameters: noop, parameter: noop }; - expect($urlMatcherFactory.isMatcher(custom)).toBe(true); + expect($umf.isMatcher(custom)).toBe(true); }); it("should handle case sensitive URL by default", function () { - expect($urlMatcherFactory.compile('/hello/world').exec('/heLLo/WORLD')).toBeNull(); + expect($umf.compile('/hello/world').exec('/heLLo/WORLD')).toBeNull(); }); it("should handle case insensitive URL", function () { - $urlMatcherFactory.caseInsensitive(true); - expect($urlMatcherFactory.compile('/hello/world').exec('/heLLo/WORLD')).toEqual({}); + $umf.caseInsensitive(true); + expect($umf.compile('/hello/world').exec('/heLLo/WORLD')).toEqual({}); }); describe("typed parameters", function() { it("should accept object definitions", function () { var type = { encode: function() {}, decode: function() {} }; - $urlMatcherFactory.type("myType1", type as any); - expect($urlMatcherFactory.type("myType1").encode).toBe(type.encode); + $umf.type("myType1", type as any); + expect($umf.type("myType1").encode).toBe(type.encode); }); it("should reject duplicate definitions", function () { - $urlMatcherFactory.type("myType2", { encode: function () {}, decode: function () {} } as any); - expect(function() { $urlMatcherFactory.type("myType2", {} as any); }).toThrowError("A type named 'myType2' has already been defined."); + $umf.type("myType2", { encode: function () {}, decode: function () {} } as any); + expect(function() { $umf.type("myType2", {} as any); }).toThrowError("A type named 'myType2' has already been defined."); }); // consider if this feature should remain or be removed @@ -606,7 +602,7 @@ describe("urlMatcherFactory", function () { // })); it("should match built-in types", function () { - var m = makeMatcher("/{foo:int}/{flag:bool}"); + var m = $umf.compile("/{foo:int}/{flag:bool}"); expect(m.exec("/1138/1")).toEqual({ foo: 1138, flag: true }); expect(m.format({ foo: 5, flag: true })).toBe("/5/1"); @@ -615,22 +611,22 @@ describe("urlMatcherFactory", function () { }); it("should match built-in types with spaces", function () { - var m = makeMatcher("/{foo: int}/{flag: bool}"); + var m = $umf.compile("/{foo: int}/{flag: bool}"); expect(m.exec("/1138/1")).toEqual({ foo: 1138, flag: true }); expect(m.format({ foo: 5, flag: true })).toBe("/5/1"); }); it("should not throw on null value", function () { - var m = makeMatcher("/{foo:int}"); + var m = $umf.compile("/{foo:int}"); expect(m.exec("/1138")).toEqual({ foo: 1138 }); expect(m.format({ foo: null })).toBe(null); - m = makeMatcher("/{foo:int}", { params: { foo: { value: 1 } } }); + m = $umf.compile("/{foo:int}", { params: { foo: { value: 1 } } }); expect(m.format({ foo: null })).toBe("/1"); }); it("should match types named only in params", function () { - var m = makeMatcher("/{foo}/{flag}", { + var m = $umf.compile("/{foo}/{flag}", { params: { foo: { type: 'int'}, flag: { type: 'bool'} @@ -642,7 +638,7 @@ describe("urlMatcherFactory", function () { it("should throw an error if a param type is declared twice", function () { expect(function() { - makeMatcher("/{foo:int}", { + $umf.compile("/{foo:int}", { params: { foo: { type: 'int' } } @@ -651,7 +647,7 @@ describe("urlMatcherFactory", function () { }); it("should encode/decode dates", function () { - var m = makeMatcher("/calendar/{date:date}"), + var m = $umf.compile("/calendar/{date:date}"), result = m.exec("/calendar/2014-03-26"); var date = new Date(2014, 2, 26); @@ -661,7 +657,7 @@ describe("urlMatcherFactory", function () { }); it("should encode/decode arbitrary objects to json", function () { - var m = makeMatcher("/state/{param1:json}/{param2:json}"); + var m = $umf.compile("/state/{param1:json}/{param2:json}"); var params = { param1: { foo: 'huh', count: 3 }, @@ -676,7 +672,7 @@ describe("urlMatcherFactory", function () { }); it("should not match invalid typed parameter values", function() { - var m = makeMatcher('/users/{id:int}'); + var m = $umf.compile('/users/{id:int}'); expect(m.exec('/users/1138')['id']).toBe(1138); expect(m.exec('/users/alpha')).toBeNull(); @@ -686,7 +682,7 @@ describe("urlMatcherFactory", function () { }); it("should automatically handle multiple search param values", (function() { - var m = makeMatcher("/foo/{fooid:int}?{bar:int}"); + var m = $umf.compile("/foo/{fooid:int}?{bar:int}"); $location.setUrl("/foo/5?bar=1"); expect(m.exec($location.path(), $location.search())).toEqual( { fooid: 5, bar: 1 } ); @@ -700,14 +696,14 @@ describe("urlMatcherFactory", function () { })); it("should allow custom types to handle multiple search param values manually", (function() { - $urlMatcherFactory.type("custArray", { + $umf.type("custArray", { encode: function(array) { return array.join("-"); }, decode: function(val) { return isArray(val) ? val : val.split(/-/); }, equals: equals, is: isArray } as any); - var m = makeMatcher("/foo?{bar:custArray}", { params: { bar: { array: false } } } ); + var m = $umf.compile("/foo?{bar:custArray}", { params: { bar: { array: false } } } ); $location.setUrl("/foo?bar=fox"); expect(m.exec($location.path(), $location.search())).toEqual( { bar: [ 'fox' ] } ); @@ -721,7 +717,7 @@ describe("urlMatcherFactory", function () { describe("optional parameters", function() { it("should match with or without values", function () { - var m = makeMatcher('/users/{id:int}', { + var m = $umf.compile('/users/{id:int}', { params: { id: { value: null, squash: true } } }); expect(m.exec('/users/1138')).toEqual({ id: 1138 }); @@ -731,7 +727,7 @@ describe("urlMatcherFactory", function () { }); it("should correctly match multiple", function() { - var m = makeMatcher('/users/{id:int}/{state:[A-Z]+}', { + var m = $umf.compile('/users/{id:int}/{state:[A-Z]+}', { params: { id: { value: null, squash: true }, state: { value: null, squash: true } } }); expect(m.exec('/users/1138')).toEqual({ id: 1138, state: null }); @@ -748,7 +744,7 @@ describe("urlMatcherFactory", function () { }); it("should correctly format with or without values", function() { - var m = makeMatcher('/users/{id:int}', { + var m = $umf.compile('/users/{id:int}', { params: { id: { value: null } } }); expect(m.format()).toBe('/users/'); @@ -756,7 +752,7 @@ describe("urlMatcherFactory", function () { }); it("should correctly format multiple", function() { - var m = makeMatcher('/users/{id:int}/{state:[A-Z]+}', { + var m = $umf.compile('/users/{id:int}/{state:[A-Z]+}', { params: { id: { value: null, squash: true }, state: { value: null, squash: true } } }); @@ -767,7 +763,7 @@ describe("urlMatcherFactory", function () { }); it("should match in between static segments", function() { - var m = makeMatcher('/users/{user:int}/photos', { + var m = $umf.compile('/users/{user:int}/photos', { params: { user: { value: 5, squash: true } } }); expect(m.exec('/users/photos')['user']).toBe(5); @@ -777,7 +773,7 @@ describe("urlMatcherFactory", function () { }); it("should correctly format with an optional followed by a required parameter", function() { - var m = makeMatcher('/home/:user/gallery/photos/:photo', { + var m = $umf.compile('/home/:user/gallery/photos/:photo', { params: { user: {value: null, squash: true}, photo: undefined @@ -789,7 +785,7 @@ describe("urlMatcherFactory", function () { describe("default values", function() { it("should populate if not supplied in URL", function() { - var m = makeMatcher('/users/{id:int}/{test}', { + var m = $umf.compile('/users/{id:int}/{test}', { params: { id: { value: 0, squash: true }, test: { value: "foo", squash: true } } }); expect(m.exec('/users')).toEqual({ id: 0, test: "foo" }); @@ -800,7 +796,7 @@ describe("urlMatcherFactory", function () { }); it("should populate even if the regexp requires 1 or more chars", function() { - var m = makeMatcher('/record/{appId}/{recordId:[0-9a-fA-F]{10,24}}', { + var m = $umf.compile('/record/{appId}/{recordId:[0-9a-fA-F]{10,24}}', { params: { appId: null, recordId: null } }); expect(m.exec("/record/546a3e4dd273c60780e35df3/")) @@ -808,7 +804,7 @@ describe("urlMatcherFactory", function () { }); it("should allow shorthand definitions", function() { - var m = makeMatcher('/foo/:foo', { + var m = $umf.compile('/foo/:foo', { params: { foo: "bar" } }); expect(m.exec("/foo/")).toEqual({ foo: "bar" }); @@ -816,7 +812,7 @@ describe("urlMatcherFactory", function () { it("should populate query params", function() { var defaults = { order: "name", limit: 25, page: 1 }; - var m = makeMatcher('/foo?order&{limit:int}&{page:int}', { + var m = $umf.compile('/foo?order&{limit:int}&{page:int}', { params: defaults }); expect(m.exec("/foo")).toEqual(defaults); @@ -824,17 +820,17 @@ describe("urlMatcherFactory", function () { it("should allow function-calculated values", function() { function barFn() { return "Value from bar()"; } - var m = makeMatcher('/foo/:bar', { + var m = $umf.compile('/foo/:bar', { params: { bar: barFn } }); expect(m.exec('/foo/')['bar']).toBe("Value from bar()"); - m = makeMatcher('/foo/:bar', { + m = $umf.compile('/foo/:bar', { params: { bar: { value: barFn, squash: true } } }); expect(m.exec('/foo')['bar']).toBe("Value from bar()"); - m = makeMatcher('/foo?bar', { + m = $umf.compile('/foo?bar', { params: { bar: barFn } }); expect(m.exec('/foo')['bar']).toBe("Value from bar()"); @@ -842,7 +838,7 @@ describe("urlMatcherFactory", function () { // consider if this feature should remain or be removed // it("should allow injectable functions", inject(function($stateParams) { - // var m = makeMatcher('/users/{user:json}', { + // var m = $umf.compile('/users/{user:json}', { // params: { // user: function($stateParams) { // return $stateParams.user; @@ -856,7 +852,7 @@ describe("urlMatcherFactory", function () { // })); xit("should match when used as prefix", function() { - var m = makeMatcher('/{lang:[a-z]{2}}/foo', { + var m = $umf.compile('/{lang:[a-z]{2}}/foo', { params: { lang: "de" } }); expect(m.exec('/de/foo')).toEqual({ lang: "de" }); @@ -866,7 +862,7 @@ describe("urlMatcherFactory", function () { describe("squash policy", function() { var Session = { username: "loggedinuser" }; function getMatcher(squash) { - return makeMatcher('/user/:userid/gallery/:galleryid/photo/:photoid', { + return $umf.compile('/user/:userid/gallery/:galleryid/photo/:photoid', { params: { userid: { squash: squash, value: function () { return Session.username; } }, galleryid: { squash: squash, value: "favorites" } @@ -929,18 +925,18 @@ describe("urlMatcherFactory", function () { describe("strict matching", function() { it("should match with or without trailing slash", function() { - var m = makeMatcher('/users', { strict: false }); + var m = $umf.compile('/users', { strict: false }); expect(m.exec('/users')).toEqual({}); expect(m.exec('/users/')).toEqual({}); }); it("should not match multiple trailing slashes", function() { - var m = makeMatcher('/users', { strict: false }); + var m = $umf.compile('/users', { strict: false }); expect(m.exec('/users//')).toBeNull(); }); it("should match when defined with parameters", function() { - var m = makeMatcher('/users/{name}', { strict: false, params: { + var m = $umf.compile('/users/{name}', { strict: false, params: { name: { value: null } }}); expect(m.exec('/users/')).toEqual({ name: null }); @@ -953,23 +949,23 @@ describe("urlMatcherFactory", function () { // This feature never made it into 1.0 // xdescribe("parameter isolation", function() { // it("should allow parameters of the same name in different segments", function() { - // var m = makeMatcher('/users/:id').append(makeMatcher('/photos/:id')); + // var m = $umf.compile('/users/:id').append($umf.compile('/photos/:id')); // expect(m.exec('/users/11/photos/38', {}, { isolate: true })).toEqual([{ id: '11' }, { id: '38' }]); // }); // // it("should prioritize the last child when non-isolated", function() { - // var m = makeMatcher('/users/:id').append(makeMatcher('/photos/:id')); + // var m = $umf.compile('/users/:id').append($umf.compile('/photos/:id')); // expect(m.exec('/users/11/photos/38')).toEqual({ id: '38' }); // }); // // it("should copy search parameter values to all matching segments", function() { - // var m = makeMatcher('/users/:id?from').append(makeMatcher('/photos/:id?from')); + // var m = $umf.compile('/users/:id?from').append($umf.compile('/photos/:id?from')); // var result = m.exec('/users/11/photos/38', { from: "bob" }, { isolate: true }); // expect(result).toEqual([{ from: "bob", id: "11" }, { from: "bob", id: "38" }]); // }); // // it("should pair empty objects with static segments", function() { - // var m = makeMatcher('/users/:id').append(makeMatcher('/foo')).append(makeMatcher('/photos/:id')); + // var m = $umf.compile('/users/:id').append($umf.compile('/foo')).append($umf.compile('/photos/:id')); // var result = m.exec('/users/11/foo/photos/38', {}, { isolate: true }); // expect(result).toEqual([{ id: '11' }, {}, { id: '38' }]); // }); diff --git a/test/urlRouterSpec.ts b/test/urlRouterSpec.ts index 117e1947..3efc07ef 100644 --- a/test/urlRouterSpec.ts +++ b/test/urlRouterSpec.ts @@ -15,10 +15,6 @@ describe("UrlRouter", function () { location: LocationServices, match; - function makeMatcher(url, config?) { - return new UrlMatcher(url, $umf.paramTypes, config); - } - beforeEach(function() { router = new UIRouter(); router.plugin(TestingPlugin); @@ -126,25 +122,25 @@ describe("UrlRouter", function () { describe("location updates", function() { it('can push location changes', function () { spyOn(router.locationService, "setUrl"); - $ur.push(makeMatcher("/hello/:name"), { name: "world" }); + $ur.push($umf.compile("/hello/:name"), { name: "world" }); expect(router.locationService.setUrl).toHaveBeenCalledWith("/hello/world", undefined); }); it('can push a replacement location', function () { spyOn(router.locationService, "setUrl"); - $ur.push(makeMatcher("/hello/:name"), { name: "world" }, { replace: true }); + $ur.push($umf.compile("/hello/:name"), { name: "world" }, { replace: true }); expect(router.locationService.setUrl).toHaveBeenCalledWith("/hello/world", true); }); it('can push location changes with no parameters', function () { spyOn(router.locationService, "setUrl"); - $ur.push(makeMatcher("/hello/:name", { params: { name: "" } })); + $ur.push($umf.compile("/hello/:name", { params: { name: "" } })); expect(router.locationService.setUrl).toHaveBeenCalledWith("/hello/", undefined); }); it('can push location changes that include a #fragment', function () { // html5mode disabled - $ur.push(makeMatcher('/hello/:name'), { name: 'world', '#': 'frag' }); + $ur.push($umf.compile('/hello/:name'), { name: 'world', '#': 'frag' }); expect($url.path()).toBe('/hello/world'); expect($url.hash()).toBe('frag'); }); @@ -166,14 +162,14 @@ describe("UrlRouter", function () { describe("URL generation", function() { it("should return null when UrlMatcher rejects parameters", function () { $umf.type("custom", { is: val => val === 1138 }); - var matcher = makeMatcher("/foo/{param:custom}"); + var matcher = $umf.compile("/foo/{param:custom}"); expect($ur.href(matcher, { param: 1138 })).toBe('#/foo/1138'); expect($ur.href(matcher, { param: 5 })).toBeNull(); }); it('should return URLs with #fragments', function () { - expect($ur.href(makeMatcher('/hello/:name'), { name: 'world', '#': 'frag' })).toBe('#/hello/world#frag'); + expect($ur.href($umf.compile('/hello/:name'), { name: 'world', '#': 'frag' })).toBe('#/hello/world#frag'); }); }); }); diff --git a/test/vanilla.browserHistorySpec.ts b/test/vanilla.browserHistorySpec.ts index 3d1a1048..1c358e7d 100644 --- a/test/vanilla.browserHistorySpec.ts +++ b/test/vanilla.browserHistorySpec.ts @@ -2,12 +2,13 @@ import { UrlMatcher } from "../src/index"; import { UIRouter } from "../src/router"; import { UrlService } from "../src/url/urlService"; import * as vanilla from "../src/vanilla"; +import { UrlMatcherFactory } from "../src/url/urlMatcherFactory"; describe('browserHistory implementation', () => { let router: UIRouter; - let urlService: UrlService; - let makeMatcher; + let $url: UrlService; + let $umf: UrlMatcherFactory; let mockHistory, mockLocation; @@ -45,10 +46,8 @@ describe('browserHistory implementation', () => { router = new UIRouter(); router.plugin(vanilla.servicesPlugin); router.plugin(vanilla.pushStateLocationPlugin); - urlService = router.urlService; - makeMatcher = (url, config?) => { - return new UrlMatcher(url, router.urlMatcherFactory.paramTypes, config) - }; + $umf = router.urlMatcherFactory; + $url = router.urlService; router.stateRegistry.register({ url: '/path/:urlParam?queryParam', @@ -60,14 +59,14 @@ describe('browserHistory implementation', () => { let service = mockPushState(router); expect(router.urlService.config.html5Mode()).toBe(true); let stub = spyOn(service._history, 'pushState'); - router.urlRouter.push(makeMatcher('/hello/:name'), { name: 'world' }, {}); + router.urlRouter.push($umf.compile('/hello/:name'), { name: 'world' }, {}); expect(stub.calls.first().args[2]).toBe('/hello/world'); }); it('uses history.replaceState when setting a url with replace', () => { let service = mockPushState(router); let stub = spyOn(service._history, 'replaceState'); - router.urlRouter.push(makeMatcher('/hello/:name'), { name: 'world' }, { replace: true }); + router.urlRouter.push($umf.compile('/hello/:name'), { name: 'world' }, { replace: true }); expect(stub.calls.first().args[2]).toBe('/hello/world'); }); @@ -80,16 +79,16 @@ describe('browserHistory implementation', () => { expect(mockLocation.href.includes('/path/bar')).toBe(true); expect(mockLocation.href.includes('#')).toBe(false); - expect(urlService.path()).toBe('/path/bar'); - expect(urlService.search()).toEqual({}); + expect($url.path()).toBe('/path/bar'); + expect($url.search()).toEqual({}); await router.stateService.go('path', { urlParam: 'bar', queryParam: 'query' }); expect(mockLocation.href.includes('/path/bar?queryParam=query')).toBe(true); expect(mockLocation.href.includes('#')).toBe(false); - expect(urlService.path()).toBe('/path/bar'); - expect(urlService.search()).toEqual({ queryParam: 'query' }); + expect($url.path()).toBe('/path/bar'); + expect($url.search()).toEqual({ queryParam: 'query' }); done(); }); diff --git a/test/vanilla.hashHistorySpec.ts b/test/vanilla.hashHistorySpec.ts index 3f04ecd6..5e642b44 100644 --- a/test/vanilla.hashHistorySpec.ts +++ b/test/vanilla.hashHistorySpec.ts @@ -1,23 +1,23 @@ import { UIRouter, UrlMatcher } from "../src/index"; import * as vanilla from "../src/vanilla"; +import { UrlMatcherFactory } from "../src/url/urlMatcherFactory"; +import { StateService } from "../src/state/stateService"; +import { UrlService } from "../src/url/urlService"; describe('hashHistory implementation', () => { - let router; - let $state; - let locationProvider; - let makeMatcher; + let router: UIRouter; + let $state: StateService; + let $umf: UrlMatcherFactory; + let $url: UrlService; beforeEach(() => { router = new UIRouter(); router.plugin(vanilla.servicesPlugin); router.plugin(vanilla.hashLocationPlugin); $state = router.stateService; - locationProvider = router.urlService; - - makeMatcher = (url, config?) => { - return new UrlMatcher(url, router.urlMatcherFactory.paramTypes, config) - }; + $umf = router.urlMatcherFactory; + $url = router.urlService; router.stateRegistry.register({ url: '/path/:urlParam?queryParam', @@ -33,14 +33,14 @@ describe('hashHistory implementation', () => { await $state.go('path', { urlParam: 'bar' }); expect(window.location.toString().includes('#/path/bar')).toBe(true); - expect(locationProvider.path()).toBe('/path/bar'); - expect(locationProvider.search()).toEqual({}); + expect($url.path()).toBe('/path/bar'); + expect($url.search()).toEqual({}); await $state.go('path', { urlParam: 'bar', queryParam: 'query' }); expect(window.location.toString().includes('#/path/bar?queryParam=query')).toBe(true); - expect(locationProvider.path()).toBe('/path/bar'); - expect(locationProvider.search()).toEqual({ queryParam: 'query' }); + expect($url.path()).toBe('/path/bar'); + expect($url.search()).toEqual({ queryParam: 'query' }); done(); });