hokey-cokey
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -11,7 +11,7 @@ // RegExp to find named variables in several formats e.g. `:a`, `${b}`, `{{c}}` or `{d}` | ||
/** | ||
* Split up a template into an array of separator / param / separator / param / separator | ||
* Split up a template into an array of separator → param → separator → param → separator | ||
* i.e. odd numbers are separators (possibly zero length) and even numbers are params. | ||
* | ||
* @param {string} template The template including template parameters, e.g. `:name-${country}/{city}` | ||
* @returns {string[]} Array of strings like separator / param / separator / param / separator | ||
* @returns {string[]} Array of strings alternating separator and param. | ||
*/ | ||
@@ -62,2 +62,21 @@ function split(template) { | ||
/** | ||
* Get list of params named in a template string. | ||
* | ||
* @param {string} template The template including template parameters, e.g. `:name-${country}/{city}` | ||
* @returns {string[]} Array of clean string names of found params, e.g. `["name", "country", "city"]` | ||
*/ | ||
function params(template) { | ||
// Checks. | ||
if (typeof template !== "string") throw new TypeError("params(): template must be string"); | ||
// Get chunks, filter out separators (zero-index even numbers), and map to clean names. | ||
const names = split(template) | ||
.filter((c, i) => i % 2) | ||
.map(cleanParam); | ||
// Return names (frozen). | ||
return Object.freeze(names); | ||
} | ||
/** | ||
* Turn ":year-:month" and "2016-06..." etc ing `{ year: "2016"... }` etc. | ||
@@ -118,4 +137,4 @@ * | ||
* @param {string} template The template including template parameters, e.g. `:name-${country}/{city}` | ||
* @param {string} values An object containing values, e.g. `{ name: "Dave", country: "UK", city: "Manchester" }` | ||
* @return {Object} The rendered string, e.g. `Dave-UK/Manchester` | ||
* @param {Object|string|Function} values An object containing values, e.g. `{ name: "Dave", country: "UK", city: "Manchester" }` (functions are called, everything else converted to string), or a function or string to use for all parameters. | ||
* @return {string} The rendered string, e.g. `Dave-UK/Manchester` | ||
* | ||
@@ -127,3 +146,3 @@ * @throws {ReferenceError} If a param in the template string is not specified in values. | ||
if (typeof template !== "string") throw new TypeError("render(): template must be string"); | ||
if (typeof values !== "object" || values === null) throw new TypeError("render(): values must be object"); | ||
if (typeof values === "undefined") throw new TypeError("render(): values must be defined"); | ||
@@ -140,8 +159,20 @@ // Vars. | ||
const name = cleanParam(param); | ||
let value; | ||
// Missing in params? | ||
if (!values.hasOwnProperty(name)) throw new Error(`render(): values.${name} must be set`); | ||
// Switch on values type. | ||
if (typeof values === "function") { | ||
// Functions are called. | ||
value = values(name); | ||
} else if (typeof values === "object" && values !== null) { | ||
// Object use named key. | ||
if (!values.hasOwnProperty(name)) throw new Error(`render(): values.${name} must be set`); | ||
const v = values[name]; | ||
value = typeof v === "function" ? v() : v; | ||
} else { | ||
// Strings are used directly. | ||
value = "" + values; | ||
} | ||
// Update output. | ||
output = output.replace(param, values[name]); | ||
output = output.replace(param, value); | ||
} | ||
@@ -155,3 +186,4 @@ | ||
module.exports.split = split; | ||
module.exports.params = params; | ||
module.exports.extract = extract; | ||
module.exports.render = render; |
{ | ||
"name": "hokey-cokey", | ||
"description": "Render values into templates OR extract values out of templates. That's what it's all about.", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"license": "0BSD", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -12,8 +12,8 @@ # Hokey Cokey! Simple string template rendering and parameter value extracting | ||
**Extract:** | ||
- Match a string (e.g. `places/france/paris`) against a template (e.g. `places/:country/{city}`) | ||
- Return found values (e.g. `{ country: "france", city: "paris" }`) | ||
- Match a target string against a template e.g. `places/france/paris` and `places/:country/{city}` | ||
- Return an object listing found values e.g. `{ country: "france", city: "paris" }` | ||
**Render:** | ||
- With a template string (e.g. `places/${country}/:city`) and an object of values (e.g. `{ country: "france", city: "paris" }`) | ||
- Return the rendered output string after variables have been rendered in (e.g. `places/france/paris`). | ||
- Take a template string and merge in some values e.g. `places/${country}/:city` and `{ country: "france", city: "paris" }` | ||
- Return the rendered string after variables have been inserted e.g. `places/france/paris` | ||
@@ -37,20 +37,51 @@ **Things to know:** | ||
### `extract()`: Get values out of a template | ||
### `extract(template: string, target: string)` Extract values from a string | ||
Extracts a set of values out of a target string based on a template string. | ||
- `template` must be a string containing one or more parameters in any allowed format | ||
- Returns an object in `parameter: value` format | ||
```js | ||
const { extract } = require('hokey-cokey'); | ||
const values = extract("places/{country}/{city}", "places/france/paris"); | ||
// { country: "france", city: "paris" } | ||
console.log(values); | ||
// Extract the values. | ||
extract("places/{country}/{city}", "places/france/paris"); // { country: "france", city: "paris" } | ||
extract("places/:country/:city", "places/france/paris"); // { country: "france", city: "paris" } | ||
``` | ||
### `render()`: Inject values into a template | ||
### `render(template, values)` Inject values into a template | ||
Render a set of values into a template string. | ||
- `template` must be a string containing one or more parameters in any allowed format | ||
- `values` can be: | ||
- An object containing string or function keys (keys must correspond to parameters in the template or render will fail) | ||
- A function called for each parameter (receives the parameter name) | ||
- A single string used for all parameters | ||
- Returns the rendered string | ||
```js | ||
const { render } = require("hokey-cokey"); | ||
const output = render("blogs-:category-:slug", { category: "cheeses", slug: "stilton" }); | ||
// "blogs-cheeses-stilton" | ||
console.log(output); | ||
``` | ||
// Render the template with an object. | ||
render("blogs-:category-:slug", { category: "cheeses", slug: "stilton" }); // blogs-cheeses-stilton | ||
render("blogs-:category-:slug", "Arrrrgh"); // blogs-Arrrrgh-Arrrrgh | ||
render("blogs-:category-:slug", (p) => p.toUpperCase()); // blogs-CATEGORY-SLUG | ||
``` | ||
### `params(template)` Get parameter names from template string | ||
Parse a template string and return an array of found variables that were found. | ||
- `template` must be a string containing one or more parameters in any allowed format | ||
- Returns an array of string parameter names that were found in the template | ||
```js | ||
const { params } = require("hokey-cokey"); | ||
// Extract the parameter names. | ||
params("{username}@{domain}"); // ["username", "domain"] | ||
params(":name // ${age}"); // ["name", "age"] | ||
``` |
@@ -5,3 +5,13 @@ const { render } = require("../"); | ||
describe("render()", () => { | ||
test("Returns correct path", () => { | ||
test("String values", () => { | ||
expect(render("/a", "123")).toBe("/a"); | ||
expect(render("/:a", "123")).toBe("/123"); | ||
expect(render("/:a/:b", "123")).toBe("/123/123"); | ||
}); | ||
test("Function values", () => { | ||
expect(render("/a", p => p)).toBe("/a"); | ||
expect(render("/:a", p => p)).toBe("/a"); | ||
expect(render("/:a/:b", p => p)).toBe("/a/b"); | ||
}); | ||
test("Object values with string properties", () => { | ||
expect(render("/a", {})).toBe("/a"); | ||
@@ -11,2 +21,10 @@ expect(render("/:a", { a: "1" })).toBe("/1"); | ||
}); | ||
test("Object values with non-string properties", () => { | ||
expect(render("/:a/:b", { a: 1, b: 2 })).toBe("/1/2"); | ||
expect(render("/:a/:b", { a: true, b: false })).toBe("/true/false"); | ||
expect(render("/:a/:b", { a: null, b: undefined })).toBe("/null/undefined"); | ||
}); | ||
test("Object values with function properties", () => { | ||
expect(render("/:a/:b", { a: () => "1", b: () => "2" })).toBe("/1/2"); | ||
}); | ||
test("TypeError for wrong input", () => { | ||
@@ -17,6 +35,3 @@ expect(() => render(123, {})).toThrow("render(): template must be string"); | ||
expect(() => render(String, {})).toThrow(TypeError); | ||
expect(() => render("/a", null)).toThrow("render(): values must be object"); | ||
expect(() => render("/a", null)).toThrow(TypeError); | ||
expect(() => render("/a", false)).toThrow(TypeError); | ||
expect(() => render("/a", 123)).toThrow(TypeError); | ||
expect(() => render("/a", undefined)).toThrow("render(): values must be defined"); | ||
}); | ||
@@ -23,0 +38,0 @@ test("TypeError for missing parameters", () => { |
@@ -16,6 +16,6 @@ const { split } = require("../"); | ||
test("Returned array is frozen", () => { | ||
const breakdown = split(""); | ||
expect(Object.isFrozen(breakdown)).toBe(true); | ||
expect(() => breakdown.push("aaaa")).toThrow(TypeError); | ||
expect(() => breakdown.push("aaaa")).toThrow("not extensible"); | ||
const chunks = split(""); | ||
expect(Object.isFrozen(chunks)).toBe(true); | ||
expect(() => chunks.push("aaaa")).toThrow(TypeError); | ||
expect(() => chunks.push("aaaa")).toThrow("not extensible"); | ||
}); | ||
@@ -22,0 +22,0 @@ test("TypeError if input is not string", () => { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
289511
11
293
86