Created
June 28, 2018 03:42
-
-
Save chenyong/8607355463b5f20cd660d242a02e490a to your computer and use it in GitHub Desktop.
An url parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let pageRules = [ | |
{ | |
name: "a", | |
path: "reports/:reportId/edit", | |
router: [], | |
}, | |
{ | |
name: "b", | |
path: "reports/:reportId", | |
router: [], | |
}, | |
{ | |
path: "reports", | |
router: [ | |
{ | |
name: "analysisId", | |
path: ":analysisId", | |
router: [], | |
}, | |
{ | |
name: "home", | |
path: "", | |
router: [], | |
}, | |
], | |
}, | |
]; | |
let router: IRouteParseResult = parseRoutePath(this.props.location.pathname, pageRules); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from "lodash"; | |
import produce from "immer"; | |
export interface IRouteRule { | |
path: string; | |
name?: string; | |
router: IRouteRule[]; | |
} | |
export interface IRouteParseResult { | |
matches: boolean; | |
name: string; | |
data: any; | |
restPath: string[]; | |
basePath: string[]; | |
next?: IRouteParseResult; | |
} | |
let parseRuleIterate = (data: any, segments: string[], ruleSteps: string[], ruleName: string, basePath: string[]): IRouteParseResult => { | |
if (_.isEmpty(ruleSteps)) { | |
return { name: ruleName, matches: true, restPath: segments, basePath: basePath, data: data }; | |
} | |
let s0 = _.first(segments); | |
let r0 = _.first(ruleSteps); | |
if (r0[0] === ":") { | |
let newData = produce(data, (draft) => { | |
draft[r0.slice(1)] = s0; | |
}); | |
return parseRuleIterate(newData, segments.slice(1), ruleSteps.slice(1), ruleName, basePath.concat([s0])); | |
} else if (s0 === r0) { | |
return parseRuleIterate(data, segments.slice(1), ruleSteps.slice(1), ruleName, basePath.concat([s0])); | |
} else { | |
return { | |
name: ruleName, | |
matches: false, | |
restPath: segments, | |
basePath: basePath, | |
data: null, | |
}; | |
} | |
}; | |
let parseWithRule = (rule: IRouteRule, segments: string[], basePath: string[]): IRouteParseResult => { | |
let ruleName = rule.name || _.first(rule.path.split("/")); | |
if (rule.path === "") { | |
return { | |
name: ruleName, | |
matches: true, | |
restPath: segments, | |
basePath: basePath, | |
data: null, | |
}; | |
} | |
let ruleSteps = rule.path.split("/"); | |
if (segments.length < ruleSteps.length) { | |
return { name: ruleName, matches: false, restPath: segments, basePath: basePath, data: null }; | |
} | |
return parseRuleIterate({}, segments, ruleSteps, ruleName, basePath); | |
}; | |
var segmentsParsingCaches = {}; | |
let parseSegments = (segments: string[], rules: IRouteRule[], basePath: string[]): IRouteParseResult => { | |
let cacheKey = segments.join("/"); | |
if (segmentsParsingCaches[cacheKey] != null) { | |
// console.log("Parser: reusing cache", cacheKey); | |
return segmentsParsingCaches[cacheKey]; | |
} | |
if (_.isEmpty(rules)) { | |
if (_.isEmpty(segments)) { | |
return null; | |
} else { | |
return { | |
matches: false, | |
name: "404", | |
data: null, | |
restPath: segments, | |
basePath: basePath, | |
}; | |
} | |
} else { | |
let rule0 = _.first(rules); | |
let parseResult = parseWithRule(rule0, segments, basePath); | |
if (parseResult.matches) { | |
let toReturn = produce(parseResult, (draft: IRouteParseResult) => { | |
draft.next = parseSegments(parseResult.restPath, rule0.router, basePath); | |
draft.restPath = null; | |
}); | |
// console.log("To return", toReturn); | |
let cacheKey = segments.join("/"); | |
segmentsParsingCaches[cacheKey] = toReturn; | |
return toReturn; | |
} else { | |
return parseSegments(segments, rules.slice(1), basePath); | |
} | |
} | |
}; | |
export let parseRoutePath = (pathString: string, rules: IRouteRule[]): IRouteParseResult => { | |
let segments = pathString.split("/").filter((x) => x !== ""); | |
return parseSegments(segments, rules, []); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment