{"id":13671657,"url":"https://github.com/hexojs/hexo-util","last_synced_at":"2025-05-13T13:24:03.500Z","repository":{"id":24842435,"uuid":"28257313","full_name":"hexojs/hexo-util","owner":"hexojs","description":"Utilities for Hexo.","archived":false,"fork":false,"pushed_at":"2025-05-01T12:28:33.000Z","size":556,"stargazers_count":96,"open_issues_count":10,"forks_count":61,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-05T06:05:07.979Z","etag":null,"topics":["hexo","javascript","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hexojs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-12-20T04:59:20.000Z","updated_at":"2025-04-17T15:32:23.000Z","dependencies_parsed_at":"2023-10-22T09:49:37.357Z","dependency_job_id":"465ce204-bd93-4a94-a57b-a4a47e6cf4fc","html_url":"https://github.com/hexojs/hexo-util","commit_stats":{"total_commits":385,"total_committers":34,"mean_commits":"11.323529411764707","dds":0.6285714285714286,"last_synced_commit":"1cf5b21ceeb0d2f9456f9003b9f956c43903d4ff"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexojs%2Fhexo-util","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexojs%2Fhexo-util/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexojs%2Fhexo-util/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexojs%2Fhexo-util/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hexojs","download_url":"https://codeload.github.com/hexojs/hexo-util/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253347040,"owners_count":21894280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hexo","javascript","typescript"],"created_at":"2024-08-02T09:01:15.641Z","updated_at":"2025-05-13T13:24:03.470Z","avatar_url":"https://github.com/hexojs.png","language":"TypeScript","readme":"# hexo-util\n\n[![Build Status](https://github.com/hexojs/hexo-util/workflows/Tester/badge.svg?branch=master)](https://github.com/hexojs/hexo-util/actions?query=workflow%3ATester)\n[![NPM version](https://badge.fury.io/js/hexo-util.svg)](https://www.npmjs.com/package/hexo-util)\n[![Coverage Status](https://coveralls.io/repos/hexojs/hexo-util/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/hexojs/hexo-util?branch=master)\n\nUtilities for [Hexo].\n\n## Table of contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Cache](#cache)\n- [CacheStream](#cachestream)\n- [camelCaseKeys](#camelcasekeysobj-options)\n- [createSha1Hash](#createsha1hash)\n- [decodeURL](#decodeurlstr)\n- [deepMerge](#deepmergetarget-source)\n- [encodeURL](#encodeurlstr)\n- [escapeDiacritic](#escapediacriticstr)\n- [escapeHTML](#escapehtmlstr)\n- [escapeRegex](#escaperegexstr)\n- [full_url_for](#full_url_forpath)\n- [gravatar](#gravatarstr-options)\n- [hash](#hashstr)\n- [highlight](#highlightstr-options)\n- [htmlTag](#htmltagtag-attrs-text-escape)\n- [isExternalLink](#isexternallinkurl-sitehost-exclude)\n- [Pattern](#patternrule)\n- [Permalink](#permalinkrule-options)\n- [prettyUrls](#prettyurlsurl-options)\n- [prismHighlight](#prismhighlightstr-options)\n- [relative_url](#relative_urlfrom-to)\n- [slugize](#slugizestr-options)\n- [spawn](#spawncommand-args-options)\n- [stripHTML](#striphtmlstr)\n- [wordWrap](#wordwrapstr-options)\n- [tocObj](#tocobjstr-options)\n- [truncate](#truncatestr-options)\n- [unescapeHTML](#unescapehtmlstr)\n- [url_for](#url_forpath-option)\n- [bind(hexo)](#bindhexo)\n\n## Installation\n\n``` bash\n$ npm install hexo-util --save\n```\n\n## Usage\n\n``` js\nvar util = require('hexo-util');\n```\n\n### Cache()\n\nA simple plain object cache\n\n``` js\nconst cache = new Cache();\n\n// set(key, value)\ncache.set('foo', 'bar');\n\n// get(key) =\u003e value\ncache.get('foo');\n// 'bar'\n\n// has(key) =\u003e Boolean\ncache.has('foo');\n// true\ncache.has('bar');\n// false\n\n// apply(key. value)\ncache.apply('baz', () =\u003e 123);\n// 123\ncache.apply('baz', () =\u003e 456);\n// 123\ncache.apply('qux', 456);\n// 456\ncache.apply('qux', '789');\n// 456\n\n// size()\ncache.size();\n// 3\n\n// dump()\ncache.dump();\n/*\n{\n  foo: 'bar',\n  baz: 123,\n  qux: 456\n}\n*/\n\n// del(key)\ncache.del('baz');\ncache.has('baz');\n// false\n\n// flush()\ncache.flush();\ncache.has('foo');\n// false\ncache.size();\n// 0\n```\n\n### CacheStream()\n\nCaches contents piped to the stream.\n\n``` js\nvar stream = new CacheStream();\n\nfs.createReadStream('/path/to/file').pipe(stream);\n\nstream.on('finish', function(){\n  // Read cache piped to the stream\n  console.log(stream.getCache());\n\n  // Destroy cache\n  stream.destroy();\n});\n```\n\n### camelCaseKeys(obj, options)\n\nConvert object keys to camelCase. Original keys will be converted to getter/setter and sync to the camelCase keys.\n\n``` js\ncamelCaseKeys({\n  foo_bar: 'test'\n});\n// { fooBar: 'test', foo_bar: 'test' }\n```\n\n### createSha1Hash()\nreturn SHA1 hash object.\n This is the same as calling `createHash('utf8')` in the node.js native module crypto.\n ``` js\nconst sha1 = createSha1Hash();\n fs.createReadStream('/path/to/file')\n  .pipe(sha1)\n  .on('finish', () =\u003e {\n    console.log(sha1.read());\n  });\n```\n\n### decodeURL(str)\n\nDecode [encoded](https://en.wikipedia.org/wiki/Percent-encoding) URL or path. An alternative to the native [`decodeURI()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURI) function, with added ability to decode [punycoded](https://en.wikipedia.org/wiki/Punycode) domain.\n\n``` js\ndecodeURL('http://foo.com/b%C3%A1r')\n// http://foo.com/bár\n\ndecodeURL('http://xn--br-mia.com/baz')\n// http://bár.com/baz\n\ndecodeURL('/foo/b%C3%A1r/')\n// /foo/bár/\n\n/* Alternatively, Node 10+ offers native API to decode punycoded domain */\nconst {format} = require('url')\ndecodeURI(format(new URL('http://xn--br-mia.com.com/b%C3%A1r'), {unicode: true}))\n// http://bár.com/báz\n```\n\n### deepMerge(target, source)\n\nMerges the enumerable properties of two objects deeply. `target` and `source` remain untouched.\n\n``` js\n// Merge deeply\nconst obj1 = {a: {b: 1, c: 1, d: {e: 1, f: 1}}};\nconst obj2 = {a: {b: 2, d: {f: 'f'} }};\n\ndeepMerge(obj1, obj2);\n// {a: {b: 2, c: 1, d: {e: 1, f: 'f'} }}\n```\n\n``` js\n// Arrays will be combined in the same property, similar to lodash.merge\nconst obj1 = { 'a': [{ 'b': 2 }, { 'd': 4 }] };\nconst obj2 = { 'a': [{ 'c': 3 }, { 'e': 5 }] };\n\ndeepMerge(obj1, obj2);\n// { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] };\n```\n\n### encodeURL(str)\n\nEncode URL or path into a [safe format](https://en.wikipedia.org/wiki/Percent-encoding).\n\n``` js\nencodeURL('http://foo.com/bár')\n// http://foo.com/b%C3%A1r\n\nencodeURL('/foo/bár/')\n// /foo/b%C3%A1r/\n```\n\n### escapeDiacritic(str)\n\nEscapes diacritic characters in a string.\n\n### escapeHTML(str)\n\nEscapes HTML entities in a string.\n\n``` js\nescapeHTML('\u003cp\u003eHello \"world\".\u003c/p\u003e')\n// \u0026lt;p\u0026gt;Hello \u0026quot;world\u0026quot;.\u0026lt;\u0026#x2F;p\u0026gt;\n\n/* support escaped characters */\nescapeHTML('\u0026lt;foo\u003ebar\u003c/foo\u0026gt;')\n// \u0026lt;foo\u0026gt;bar\u0026lt;\u0026#x2F;foo\u0026gt;\n```\n\n### escapeRegex(str)\n\nEscapes special characters in a regular expression.\n\n### full_url_for(path)\n\nReturns a url with the config.url prefixed. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).\n\n``` yml\n_config.yml\nurl: https://example.com/blog # example\n```\n\n``` js\nfull_url_for('/a/path')\n// https://example.com/blog/a/path\n```\n\n### gravatar(str, [options])\n\nReturns the gravatar image url from an email.\n\nIf you didn't specify the [options] parameter, the default options will apply. Otherwise, you can set it to a number which will then be passed on as the size parameter to Gravatar. Finally, if you set it to an object, it will be converted into a query string of parameters for Gravatar.\n\nOption | Description | Default\n--- | --- | ---\n`s` | Output image size | 80\n`d` | Default image |\n`f` | Force default |\n`r` | Rating |\n\nMore info: [Gravatar](https://en.gravatar.com/site/implement/images/)\n\n``` js\ngravatar('a@abc.com')\n// https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787\ngravatar('a@abc.com', 40)\n// https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40\ngravatar('a@abc.com' {s: 40, d: 'https://via.placeholder.com/150'})\n// https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40\u0026d=https%3A%2F%2Fvia.placeholder.com%2F150\n```\n\n### hash(str)\n\nGenerates SHA1 hash.\n\n``` js\nhash('123456');\n// \u003cBuffer 7c 4a 8d 09 ca 37 62 af 61 e5 95 20 94 3d c2 64 94 f8 94 1b\u003e\n```\n\n### highlight(str, [options])\n\nSyntax highlighting for a code block.\n\nOption | Description | Default\n--- | --- | ---\n`gutter` | Whether to show line numbers | true\n`wrap` | Whether to wrap the code block in [`\u003ctable\u003e`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table) | true\n`firstLine` | First line number | 1\n`hljs` | Whether to use the `hljs-*` prefix for CSS classes | false\n`lang` | Language |\n`caption` | Caption |\n`tab`| Replace tabs |\n`autoDetect` | Detect language automatically (warning: slow)\u003cbr\u003e_Sublanguage highlight requires `autoDetect` to be enabled and `lang` to be unset_  | false\n`mark` | Line highlight specific line(s) |\n`languageAttr` | Output code language into `data-language` attr | false\n`stripIndent`| Whether to strip leading whitespace via [strip-indent](https://www.npmjs.com/package/strip-indent) | true\n\n### htmlTag(tag, attrs, text, escape)\n\nCreates a html tag.\n\nOption | Description | Default\n--- | --- | ---\n`tag` | Tag / element name |\n`attrs` | Attribute(s) and its value.\u003cbr\u003eValue is always [escaped](#escapehtmlstr), URL is always [encoded](#encodeurlstr). |\n`text` | Text, the value is always escaped\u003cbr\u003e_(except for `\u003cstyle\u003e` tag)_ |\n`escape` | Whether to escape the text | true\n\n``` js\nhtmlTag('img', {src: 'example.png'})\n// \u003cimg src=\"example.png\"\u003e\n\nhtmlTag('a', {href: 'http://hexo.io/'}, 'Hexo')\n// \u003ca href=\"http://hexo.io/\"\u003eHexo\u003c/a\u003e\n\nhtmlTag('link', {href: 'http://foo.com/'}, '\u003ca\u003ebar\u003c/a\u003e')\n// \u003ca href=\"http://foo.com/\"\u003e\u0026lt;bar\u0026gt;\u003c/a\u003e\n\nhtmlTag('a', {href: 'http://foo.com/'}, '\u003cb\u003ebold\u003c/b\u003e', false)\n// \u003ca href=\"http://foo.com/\"\u003e\u003cb\u003ebold\u003c/b\u003e\u003c/a\u003e\n\n/* text value of \u003cstyle\u003e won't be escaped, url is still encoded */\nhtmlTag('style', {}, 'p { content: \"\u003c\"; background: url(\"bár.jpg\"); }')\n// \u003cstyle\u003ep { content: \"\u003c\"; background: url(\"b%C3%A1r.jpg\"); }\u003c/style\u003e\n\n/* support script tag with async/defer */\nhtmlTag('script', {src: '/foo.js', async: true}, '')\n// \u003cscript src=\"/foo.js\" async\u003e\u003c/script\u003e\n```\n\n### isExternalLink(url, sitehost, [exclude])\n\nOption | Description | Default\n--- | --- | ---\n`url` | The input URL. |\n`sitehost` | The hostname / url of website. You can also pass `hexo.config.url`. |\n`exclude` | Exclude hostnames. Specific subdomain is required when applicable, including www. | `[]`\n\nReturns if a given url is external link relative to given `sitehost` and `[exclude]`.\n\n``` js\n// 'sitehost' can be a domain or url\nisExternalLink('https://example.com', 'example.com');\n// false\nisExternalLink('https://example.com', 'https://example.com');\n// false\nisExternalLink('https://example.com', '//example.com/blog/');\n// false\n```\n\n``` js\nisExternalLink('/archives/foo.html', 'example.com');\n// false\nisExternalLink('https://foo.com/', 'example.com');\n// true\n```\n\n``` js\nisExternalLink('https://foo.com', 'example.com', ['foo.com', 'bar.com']);\n// false\nisExternalLink('https://bar.com', 'example.com', ['foo.com', 'bar.com']);\n// false\nisExternalLink('https://baz.com/', 'example.com', ['foo.com', 'bar.com']);\n// true\n```\n\n\n### Pattern(rule)\n\nParses the string and tests if the string matches the rule. `rule` can be a string, a regular expression or a function.\n\n``` js\nvar pattern = new Pattern('posts/:id');\n\npattern.match('posts/89');\n// {0: 'posts/89', 1: '89', id: '89'}\n```\n\n``` js\nvar pattern = new Pattern('posts/*path');\n\npattern.match('posts/2013/hello-world');\n// {0: 'posts/2013/hello-world', 1: '2013/hello-world', path: '2013/hello-world'}\n```\n\n### Permalink(rule, [options])\n\nParses a permalink.\n\nOption | Description\n--- | ---\n`segments` | Customize the rule of a segment in the permalink\n\n``` js\nvar permalink = new Permalink(':year/:month/:day/:title', {\n  segments: {\n    year: /(\\d{4})/,\n    month: /(\\d{2})/,\n    day: /(\\d{2})/\n  }\n});\n\npermalink.parse('2014/01/31/test');\n// {year: '2014', month: '01', day: '31', title: 'test'}\n\npermalink.test('2014/01/31/test');\n// true\n\npermalink.stringify({year: '2014', month: '01', day: '31', title: 'test'})\n// 2014/01/31/test\n```\n\n### prettyUrls(url, [options])\n\nRewrite urls to pretty URLs.\n\nOption | Description | Default\n--- | --- | ---\n`trailing_index` | `/about/index.html -\u003e /about/` when `false` | `true`\n`trailing_html` | `/about.html -\u003e /about` when `false` | `true`\n\nNote: `trailing_html` ignores any link with a trailing `index.html`. (will not be rewritten to `index`).\n\n``` js\nprettyUrls('/foo/bar.html');\n// /foo/bar.html\nprettyUrls('/foo/bar/index.html');\n// /foo/bar/index.html\n\nprettyUrls('/foo/bar.html', { trailing_index: false });\n// /foo/bar.html\nprettyUrls('/foo/bar/index.html', { trailing_index: false });\n// /foo/bar/\n\nprettyUrls('/foo/bar.html', { trailing_html: false });\n// /foo/bar\nprettyUrls('/foo/bar/index.html', { trailing_html: false });\n// /foo/bar/index.html\n\nprettyUrls('/foo/bar.html', { trailing_index: false, trailing_html: false });\n// /foo/bar\nprettyUrls('/foo/bar/index.html', { trailing_index: false, trailing_html: false });\n// /foo/bar/\n```\n\n### prismHighlight(str, [options])\n\nSyntax highlighting for a code block using PrismJS.\n\nOption | Description | Default\n--- | --- | ---\n`lineNumber` | Whether to show line numbers | true\n`lang` | Language | `'none'`\n`tab`| Replace tabs |\n`isPreprocess` | Enable preprocess or not | true\n`mark` | Highlight specific line |\n`firstLine` | First line number |\n`caption` | Caption |\n`stripIndent`| Whether to strip leading whitespace via [strip-indent](https://www.npmjs.com/package/strip-indent) | true\n\n\nWhen `isPreprocess` is enabled, `prismHighlight()` will return PrismJS processed HTML snippet. Otherwise `str` will only be escaped and `prismHighlight()` will return the HTML snippet that is suitable for `prism.js` working in the Browser.\n\n`mark` and `firstLine` options will have effect only when `isPreprocess` is disabled.\n\n### relative_url(from, to)\n\nReturns the relative URL from `from` to `to`. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).\n\n``` js\nrelative_url('foo/bar/', 'css/style.css')\n// ../../css/style.css\n```\n\n### slugize(str, [options])\n\nTransforms a string into a clean URL-friendly string.\n\nOption | Description | Default\n--- | --- | ---\n`separator` | Separator | -\n`transform` | Transform the string into lower case (`1`) or upper case (`2`) |\n\n``` js\nslugize('Hello World') = 'Hello-World'\nslugize('Hellô Wòrld') = 'Hello-World'\nslugize('Hello World', {separator: '_'}) = 'Hello_World'\nslugize('Hello World', {transform: 1}) = 'hello-world'\nslugize('Hello World', {transform: 2}) = 'HELLO-WORLD'\n```\n\n### spawn(command, [args], [options])\n\nLaunches a new process with the given `command`. This method returns a promise.\n\nOption | Description | Default\n--- | --- | ---\n`cwd` | Current working directory of the child process |\n`env` | Environment key-value pairs |\n`stdio` | Child's stdio configuration | `pipe`\n`detached` | The child will be a process group leader |\n`uid` | Sets the user identity of the process |\n`gid` | Sets the group identity of the process |\n`verbose` | Display messages on the console | `false`\n`encoding` | Sets the encoding of the output string | `utf8`\n\nMore info: [`child_process.spawn()`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options)\n\n``` js\nspawn('cat', 'test.txt').then((content) =\u003e {\n  console.log(content);\n});\n\n// $ cd \"/target/folder\"\n// $ cat \"foo.txt\" \"bar.txt\"\nspawn('cat', ['foo.txt', 'bar.txt'], { cwd: '/target/folder' }).then((content) =\u003e {\n  console.log(content);\n});\n```\n\n### stripHTML(str)\n\nRemoves HTML tags in a string.\n\n### stripIndent(str)\n\nStrip leading whitespace from each line in a string. The line with the least number of leading whitespace, ignoring empty lines, determines the number to remove. Useful for removing redundant indentation.\n\n### wordWrap(str, [options])\n\nWraps the string no longer than line width. This method breaks on the first whitespace character that does not exceed line width.\n\nOption | Description | Default\n--- | --- | ---\n`width` | Line width | 80\n\n``` js\nwordWrap('Once upon a time')\n// Once upon a time\n\nwordWrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')\n// Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\\na successor to the throne turned out to be more trouble than anyone could have\\nimagined...\n\nwordWrap('Once upon a time', {width: 8})\n// Once\\nupon a\\ntime\n\nwordWrap('Once upon a time', {width: 1})\n// Once\\nupon\\na\\ntime\n```\n\n### tocObj(str, [options])\n\nGenerate a table of contents in JSON format based on the given html string. Headings with attribute `data-toc-unnumbered=\"true\"` will be marked as unnumbered.\n\nOption | Description | Default\n--- | --- | ---\n`min_depth` | The minimum level of TOC | 1\n`max_depth` | The maximum level of TOC | 6\n\n\n``` js\nconst html = [\n  '\u003ch1 id=\"title_1\"\u003eTitle 1\u003c/h1\u003e',\n  '\u003cdiv id=\"title_1_1\"\u003e\u003ch2\u003eTitle 1.1\u003c/h2\u003e\u003c/div\u003e',\n  '\u003ch3 id=\"title_1_1_1\"\u003eTitle 1.1.1\u003c/h3\u003e',\n  '\u003ch2 id=\"title_1_2\"\u003eTitle 1.2\u003c/h2\u003e',\n  '\u003ch2 id=\"title_1_3\"\u003eTitle 1.3\u003c/h2\u003e',\n  '\u003ch3 id=\"title_1_3_1\"\u003eTitle 1.3.1\u003c/h3\u003e',\n  '\u003ch1 id=\"title_2\"\u003eTitle 2\u003c/h1\u003e',\n  '\u003ch2 id=\"title_2_1\"\u003eTitle 2.1\u003c/h2\u003e'\n].join('\\n');\n\ntocObj(html);\n/*\n[\n  { text: 'Title 1', id: 'title_1', level: 1 },\n  { text: 'Title 1.1', id: 'title_1_1', level: 2 },\n  { text: 'Title 1.1.1', id: 'title_1_1_1', level: 3 },\n  { text: 'Title 1.2', id: 'title_1_2', level: 2 },\n  { text: 'Title 1.3', id: 'title_1_3', level: 2 },\n  { text: 'Title 1.3.1', id: 'title_1_3_1', level: 3 },\n  { text: 'Title 2', id: 'title_2', level: 1 },\n  { text: 'Title 2.1', id: 'title_2_1', level: 2 },\n]\n*/\n\ntocObj(html, { min_depth: 2 });\n/*\n[\n  { text: 'Title 1.1', id: 'title_1_1', level: 2 },\n  { text: 'Title 1.1.1', id: 'title_1_1_1', level: 3 },\n  { text: 'Title 1.2', id: 'title_1_2', level: 2 },\n  { text: 'Title 1.3', id: 'title_1_3', level: 2 },\n  { text: 'Title 1.3.1', id: 'title_1_3_1', level: 3 },\n  { text: 'Title 2.1', id: 'title_2_1', level: 2 },\n]\n*/\n\ntocObj(html, { max_depth: 2 });\n/*\n[\n  { text: 'Title 1', id: 'title_1', level: 1 },\n  { text: 'Title 1.1', id: 'title_1_1', level: 2 },\n  { text: 'Title 1.2', id: 'title_1_2', level: 2 },\n  { text: 'Title 1.3', id: 'title_1_3', level: 2 },\n  { text: 'Title 2', id: 'title_2', level: 1 },\n  { text: 'Title 2.1', id: 'title_2_1', level: 2 },\n]\n*/\n\ntocObj('\u003ch1 id=\"reference\" data-toc-unnumbered=\"true\"\u003eReference\u003c/h1\u003e')\n/*\n[\n  { text: 'Reference', id: 'reference', level: 1, unnumbered: true }\n]\n*/\n```\n\n### truncate(str, [options])\n\nTruncates a given text after a given `length` if text is longer than `length`. The last characters will be replaced with the `omission` option for a total length not exceeding `length`.\n\nOption | Description | Default\n--- | --- | ---\n`length` | Max length of the string | 30\n`omission` | Omission text | ...\n`separator` | truncate text at a natural break |\n\n``` js\ntruncate('Once upon a time in a world far far away')\n// \"Once upon a time in a world...\"\n\ntruncate('Once upon a time in a world far far away', {length: 17})\n// \"Once upon a ti...\"\n\ntruncate('Once upon a time in a world far far away', {length: 17, separator: ' '})\n// \"Once upon a...\"\n\ntruncate('And they found that many people were sleeping better.', {length: 25, omission: '... (continued)'})\n// \"And they f... (continued)\"\n```\n\n### unescapeHTML(str)\n\nUnescapes HTML entities in a string.\n\n``` js\nunescapeHTML('\u0026lt;p\u0026gt;Hello \u0026quot;world\u0026quot;.\u0026lt;\u0026#x2F;p\u0026gt;')\n// \u003cp\u003eHello \"world\".\u003c/p\u003e\n```\n\n### url_for(path, [option])\n\nReturns a url with the root path prefixed. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).\n\nOption | Description | Default\n--- | --- | ---\n`relative` | Output relative link | Value of `config.relative_link`\n\n``` yml\n_config.yml\nroot: /blog/ # example\n```\n\n``` js\nurl_for('/a/path')\n// /blog/a/path\n```\n\nRelative link, follows `relative_link` option by default\ne.g. post/page path is '/foo/bar/index.html'\n\n``` yml\n_config.yml\nrelative_link: true\n```\n\n``` js\nurl_for('/css/style.css')\n// ../../css/style.css\n\n/* Override option\n * you could also disable it to output a non-relative link,\n * even when `relative_link` is enabled and vice versa.\n */\nurl_for('/css/style.css', {relative: false})\n// /css/style.css\n```\n\n## bind(hexo)\n\nFollowing utilities require `bind(hexo)` / `bind(this)` / `call(hexo, input)` / `call(this, input)` to parse the user config when initializing:\n- [`full_url_for()`](#full_url_forpath)\n- [`url_for()`](#url_forpath)\n- [`relative_url()`](#relative_urlfrom-to)\n\nBelow examples demonstrate different approaches to creating a [helper](https://hexo.io/api/helper) (each example is separated by `/******/`),\n\n``` js\n// Single function\nconst url_for = require('hexo-util').url_for.bind(hexo);\n\nhexo.extend.helper.register('test_url', (str) =\u003e {\n  return url_for(str);\n})\n\n\n/******/\n// Multiple functions\nconst url_for = require('hexo-util').url_for.bind(hexo)\n\nfunction testurlHelper(str) {\n  return url_for(str);\n}\n\nhexo.extend.helper.register('test_url', testurlHelper);\n\n\n/******/\n// Functions separated into different files.\n// test_url.js\nmodule.exports = function(str) {\n  const url_for = require('hexo-util').url_for.bind(this);\n  return url_for(str);\n}\n\n// index.js\nhexo.extend.helper.register('test_url', require('./test_url'));\n\n\n/******/\n// Function.call() approach also works\nconst {url_for} = require('hexo-util');\nmodule.exports = function(str) {\n  return url_for.call(this, str);\n}\n\nhexo.extend.helper.register('test_url', require('./test_url'));\n\n\n/******/\n// Separating functions into individual files\n// Each file has multiple functions\n// test_url.js\nfunction testurlHelper(str) {\n  const url_for = require('hexo-util').url_for.bind(this);\n  return url_for(str);\n}\n\nmodule.exports =  {\n  testurlHelper: testurlHelper\n}\n\n// index.js\nhexo.extend.helper.register('test_url', require('./test_url').testurlHelper);\n```\n\n## License\n\nMIT\n\n[Hexo]: http://hexo.io/\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexojs%2Fhexo-util","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhexojs%2Fhexo-util","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexojs%2Fhexo-util/lists"}