Skip to content

Commit

Permalink
fix(RejectFactory): stringify rejections with circular dependency-awa…
Browse files Browse the repository at this point in the history
…re stringify

refactor(common): Move string functions to common/string.ts
closes #2538
  • Loading branch information
christopherthielen committed Mar 27, 2016
1 parent 7a68ade commit 199db79
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 83 deletions.
49 changes: 3 additions & 46 deletions src/common/common.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/** @module common */ /** for typedoc */

import {isFunction, isString, isArray, isRegExp, isDate} from "./predicates";
import { all, pattern, any, not, prop, curry, val } from "./hof";
import { all, any, not, prop, curry } from "./hof";

let angular = (<any> window).angular || {};
export const fromJson = angular.fromJson || _fromJson;
export const toJson = angular.toJson || _toJson;
export const fromJson = angular.fromJson || JSON.parse.bind(JSON);
export const toJson = angular.toJson || JSON.stringify.bind(JSON);
export const copy = angular.copy || _copy;
export const forEach = angular.forEach || _forEach;
export const extend = angular.extend || _extend;
Expand Down Expand Up @@ -467,54 +467,11 @@ export function applyPairs(memo: TypedMap<any>, keyValTuple: any[]) {
return memo;
}

export function fnToString(fn: IInjectable) {
let _fn = isArray(fn) ? fn.slice(-1)[0] : fn;
return _fn && _fn.toString() || "undefined";
}

/**
* Returns a string shortened to a maximum length
*
* If the string is already less than the `max` length, return the string.
* Else return the string, shortened to `max - 3` and append three dots ("...").
*
* @param max the maximum length of the string to return
* @param str the input string
*/
export function maxLength(max: number, str: string) {
if (str.length <= max) return str;
return str.substr(0, max - 3) + "...";
}

/**
* Returns a string, with spaces added to the end, up to a desired str length
*
* If the string is already longer than the desired length, return the string.
* Else returns the string, with extra spaces on the end, such that it reaches `length` characters.
*
* @param length the desired length of the string to return
* @param str the input string
*/
export function padString(length: number, str: string) {
while (str.length < length) str += " ";
return str;
}

/** Get the last element of an array */
export function tail<T>(arr: T[]): T {
return arr.length && arr[arr.length - 1] || undefined;
}

export const kebobString = (camelCase: string) => camelCase.replace(/([A-Z])/g, $1 => "-"+$1.toLowerCase());

function _toJson(obj) {
return JSON.stringify(obj);
}

function _fromJson(json) {
return isString(json) ? JSON.parse(json) : json;
}

/**
* shallow copy from src to dest
*
Expand Down
1 change: 1 addition & 0 deletions src/common/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from "./glob";
export * from "./hof";
export * from "./predicates";
export * from "./queue";
export * from "./strings";
export * from "./trace";
89 changes: 89 additions & 0 deletions src/common/strings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/** @module common */ /** */

import {isString, isArray, isDefined, isNull, isPromise, isInjectable, isObject} from "./predicates";
import {TransitionRejection} from "../transition/rejectFactory";
import {IInjectable, identity} from "./common";
import {pattern, is, not, val, invoke} from "./hof";
import {Transition} from "../transition/transition";
import {Resolvable} from "../resolve/resolvable";

/**
* Returns a string shortened to a maximum length
*
* If the string is already less than the `max` length, return the string.
* Else return the string, shortened to `max - 3` and append three dots ("...").
*
* @param max the maximum length of the string to return
* @param str the input string
*/
export function maxLength(max: number, str: string) {
if (str.length <= max) return str;
return str.substr(0, max - 3) + "...";
}

/**
* Returns a string, with spaces added to the end, up to a desired str length
*
* If the string is already longer than the desired length, return the string.
* Else returns the string, with extra spaces on the end, such that it reaches `length` characters.
*
* @param length the desired length of the string to return
* @param str the input string
*/
export function padString(length: number, str: string) {
while (str.length < length) str += " ";
return str;
}

export const kebobString = (camelCase: string) => camelCase.replace(/([A-Z])/g, $1 => "-"+$1.toLowerCase());

function _toJson(obj) {
return JSON.stringify(obj);
}

function _fromJson(json) {
return isString(json) ? JSON.parse(json) : json;
}


function promiseToString(p) {
if (is(TransitionRejection)(p.reason)) return p.reason.toString();
return `Promise(${JSON.stringify(p)})`;
}

export function functionToString(fn) {
let fnStr = fnToString(fn);
let namedFunctionMatch = fnStr.match(/^(function [^ ]+\([^)]*\))/);
return namedFunctionMatch ? namedFunctionMatch[1] : fnStr;
}

export function fnToString(fn: IInjectable) {
let _fn = isArray(fn) ? fn.slice(-1)[0] : fn;
return _fn && _fn.toString() || "undefined";
}


let stringifyPattern = pattern([
[not(isDefined), val("undefined")],
[isNull, val("null")],
[isPromise, promiseToString],
[is(Transition), invoke("toString")],
[is(Resolvable), invoke("toString")],
[isInjectable, functionToString],
[val(true), identity]
]);

export function stringify(o) {
var seen = [];

function format(val) {
if (isObject(val)) {
if (seen.indexOf(val) !== -1) return '[circular ref]';
seen.push(val);
}
return stringifyPattern(val);
}

return JSON.stringify(o, (key, val) => format(val)).replace(/\\"/g, '"');
}

32 changes: 3 additions & 29 deletions src/common/trace.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
/** @module common */ /** for typedoc */
import {fnToString, maxLength, padString, identity} from "../common/common";
import {is, invoke, not, val, pattern, parse} from "../common/hof";
import {isNull, isPromise, isNumber, isInjectable, isDefined} from "../common/predicates";
import {Resolvable} from "../resolve/resolvable";
import {parse} from "../common/hof";
import {isNumber} from "../common/predicates";
import {Transition} from "../transition/transition";
import {TransitionRejection} from "../transition/rejectFactory";
import {ActiveUIView, ViewConfig} from "../view/interface";

function promiseToString(p) {
if (is(TransitionRejection)(p.reason)) return p.reason.toString();
return `Promise(${JSON.stringify(p)})`;
}

function functionToString(fn) {
let fnStr = fnToString(fn);
let namedFunctionMatch = fnStr.match(/^(function [^ ]+\([^)]*\))/);
return namedFunctionMatch ? namedFunctionMatch[1] : fnStr;
}
import {stringify, functionToString, maxLength, padString} from "./strings";

function uiViewString (viewData) {
if (!viewData) return 'ui-view (defunct)';
Expand All @@ -30,19 +17,6 @@ function normalizedCat(input: Category): string {
return isNumber(input) ? Category[input] : Category[Category[input]];
}

function stringify(o) {
let format = pattern([
[not(isDefined), val("undefined")],
[isNull, val("null")],
[isPromise, promiseToString],
[is(Transition), invoke("toString")],
[is(Resolvable), invoke("toString")],
[isInjectable, functionToString],
[val(true), identity]
]);

return JSON.stringify(o, (key, val) => format(val)).replace(/\\"/g, '"');
}

export enum Category {
RESOLVE, TRANSITION, HOOK, INVOKE, UIVIEW, VIEWCONFIG
Expand Down
3 changes: 2 additions & 1 deletion src/ng1/viewDirective.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @module view */ /** for typedoc */
"use strict";
import {extend, map, unnestR, filter, kebobString} from "../common/common";
import {extend, map, unnestR, filter} from "../common/common";
import {isDefined, isFunction} from "../common/predicates";
import {trace} from "../common/trace";
import {ActiveUIView} from "../view/interface";
Expand All @@ -12,6 +12,7 @@ import {ResolveContext} from "../resolve/resolveContext";
import {Transition} from "../transition/transition";
import {Node} from "../path/node";
import {Param} from "../params/param";
import {kebobString} from "../common/strings";

export type UIViewData = {
$cfg: Ng1ViewConfig;
Expand Down
3 changes: 2 additions & 1 deletion src/ng1/viewsBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @module ng1 */ /** */
import {State} from "../state/stateObject";
import {pick, forEach, anyTrueR, unnestR, kebobString} from "../common/common";
import {pick, forEach, anyTrueR, unnestR} from "../common/common";
import {kebobString} from "../common/strings";
import {ViewConfig, ViewContext} from "../view/interface";
import {Ng1ViewDeclaration} from "./interface";
import {ViewService} from "../view/view";
Expand Down
2 changes: 1 addition & 1 deletion src/resolve/module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @module path */ /** for typedoc */
/** @module resolve */ /** for typedoc */
export * from "./interface";
export * from "./resolvable";
export * from "./resolveContext";
Expand Down
2 changes: 1 addition & 1 deletion src/resolve/resolvable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @module path */ /** for typedoc */
/** @module resolve */ /** for typedoc */
import {extend, pick, map, filter} from "../common/common";
import {not} from "../common/hof";
import {isInjectable} from "../common/predicates";
Expand Down
2 changes: 1 addition & 1 deletion src/resolve/resolveContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @module path */ /** for typedoc */
/** @module resolve */ /** for typedoc */
import {IInjectable, find, filter, map, tail, defaults, extend, pick, omit} from "../common/common";
import {prop, propEq} from "../common/hof";
import {isString, isObject} from "../common/predicates";
Expand Down
2 changes: 1 addition & 1 deletion src/resolve/resolveInjector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @module path */ /** for typedoc */
/** @module resolve */ /** for typedoc */
import {map} from "../common/common";

import {Resolvable} from "./resolvable";
Expand Down
3 changes: 2 additions & 1 deletion src/transition/rejectFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"use strict";
import {extend} from "../common/common";
import {services} from "../common/coreservices";
import {stringify} from "../common/strings";

export enum RejectType {
SUPERSEDED = 2, ABORTED = 3, INVALID = 4, IGNORED = 5
Expand All @@ -22,7 +23,7 @@ export class TransitionRejection {
}

toString() {
const detailString = d => d && d.toString !== Object.prototype.toString ? d.toString() : JSON.stringify(d);
const detailString = d => d && d.toString !== Object.prototype.toString ? d.toString() : stringify(d);
let type = this.type, message = this.message, detail = detailString(this.detail);
return `TransitionRejection(type: ${type}, message: ${message}, detail: ${detail})`;
}
Expand Down
3 changes: 2 additions & 1 deletion src/transition/transitionHook.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @module transition */ /** for typedoc */
import {TransitionHookOptions} from "./interface";
import {IInjectable, defaults, extend, noop, fnToString, maxLength, Predicate} from "../common/common";
import {IInjectable, defaults, extend, noop, Predicate} from "../common/common";
import {fnToString, maxLength} from "../common/strings";
import {isDefined, isPromise } from "../common/predicates";
import {not, pattern, val, eq, is, parse } from "../common/hof";
import {trace} from "../common/trace";
Expand Down

0 comments on commit 199db79

Please sign in to comment.