Skip to content

Commit 8ef93ff

Browse files
committed
Initial commit
0 parents  commit 8ef93ff

File tree

8 files changed

+597
-0
lines changed

8 files changed

+597
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
*.log
3+
.nyc_output/
4+
coverage/
5+
node_modules/
6+
hast-util-find-and-replace.js
7+
hast-util-find-and-replace.min.js

.travis.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
language: node_js
2+
node_js:
3+
- '4.0'
4+
- '7.0'
5+
after_script: bash <(curl -s https://codecov.io/bash)
6+
deploy:
7+
- provider: npm
8+
email: tituswormer@gmail.com
9+
api_key:
10+
secure: q8F6+Xa/dKMyt1WywHSNG+OlT1hzzxLm3JY1sRtfyIXaZj9aJO4iSxQ5p94Y2Ub6NHILBpyNCXmLzptVuAwI4VdEoqZkDZfVF/daGwfdWAzvdVyYaOKlCcdNZ7IadA4/gLVrvjnuvbP8iigmnMQKB4NXoXlFEeCqUIJT538jVr2HZo24HxT1YUUjqQsj3S0CBm4w1l0bIO3rLtm8u5mb+nHu4Y1V70Ug9oC2lHpeCUTiiGnleqeHVa7MbToPkYKwtCPI/t8AyB0ITrjYuRWSHNIcXn8pI55HAW04VkbxxUpgvFmUxXii1iPRO44j1l/rpBUlpq3lS1zzwP4zXzRGkjaY0KZ7P82+SatQSr9eMGrAbUmPHZsxRWV3wd8kCXHjrbPgzhgzmHzC8TfXOkK/hKS0ypiqfFJwgH/WE74909x1Jt61c1kRkTfvnDCEDwMw6npYcyqLN/UoyUOVnQxDVybcqU/OtcC63YvEmQ12ovsPhzoGqNqcfY8kLwXRQyqNe0b3IrTynOrOUy9AmiGx+3M/ESgFQK1TfJ8lCykUt1etcOyU1tdjsP6m7Xc/vvqjn8pTdcEK5sM/eO6zyzAuLshPbUfij58uzm1nzVHBQUxD20a5xIVIapgTbXiHyo1GMPJIXBAPrsUDcN+RUUloGToQhYTWwcCk9iS4WW0HSoY=
11+
on:
12+
tags: true
13+
node: '4.0'
14+
- provider: releases
15+
api_key:
16+
secure: Qx6vu32wBkdSt2r/w0C5mXvkzVJlS2XQnxZ9Gl+tzijBtIHb8Az4JC3Vhf5Z8pvHu2gC7AmjsfiFYH1fDa66g9eLVfpnSIg6q8Xw295z4jQFiJYVWE70yb1c8eVEu20yTYbFgNx30Yqs1uwbXu+7/7Mzlvqcmiw0v5yYF8VwHx+wbead64Ev9wXvQAsBnVXb7R+Iql75At7jpZvQ28rx0fLwNpKli3R7Wss1atgdRa2uwdbeIWpgNzVKgOPhlkFohZNQynjAPpCm8RKD24Mqv1BXXUXgJjMS0fSz8T85Vg5eElBogsx/ywT1cih4n+/XtE1bWRysDeBw6PpYh5lTrEeJmJjkkzjKGfQlG6c0Pi80Edda0Pz8ZDS3q+8kKrS/0ejszvl3HSfyBb+0xDeIkDOQHIV/LoDdIlHhpX0asPNMtjjsIpPye0X8gDsI3mmQEYPGMDjP2Xo/QWaO/ypFmiTPXC2QLQG8RuWF2jL7rjT7tdNnSqj/fTx+WPyhVFNxenxJLHsmM/Gax9IqIbIWZf4q+gasFoWY4t83hbw5iA5rPHeJY6veRM4Ilby7I8Y4Btci2SFm4WrbW5VvJ14t046lVvCme3sBgusB0SCdZgFK12MGvAwPrHZHxJRhUIykV3M2iCMGik6FHEEvaZpzfYFLRM1zEhTKR1d8bfm2zFM=
17+
file:
18+
- "hast-util-find-and-replace.js"
19+
- "hast-util-find-and-replace.min.js"
20+
on:
21+
tags: true
22+
node: '7.0'

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

index.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
'use strict';
2+
3+
var array = require('isarray');
4+
var visit = require('unist-util-visit-parents');
5+
var is = require('hast-util-is-element');
6+
var escape = require('escape-string-regexp');
7+
8+
var IGNORE = ['title', 'script', 'style', 'svg', 'math'];
9+
10+
module.exports = findAndReplace;
11+
12+
findAndReplace.ignore = IGNORE;
13+
14+
function findAndReplace(tree, find, replace, options) {
15+
var settings;
16+
var schema;
17+
18+
if (typeof find === 'string' || (typeof find === 'object' && 'flags' in find)) {
19+
schema = [[find, replace]];
20+
} else {
21+
schema = find;
22+
options = replace;
23+
}
24+
25+
settings = options || {};
26+
27+
search(tree, settings, handlerFactory(toPairs(schema)));
28+
29+
return tree;
30+
31+
function handlerFactory(pairs) {
32+
var pair = pairs[0];
33+
34+
return handler;
35+
36+
function handler(node, pos, parent) {
37+
var siblings = parent.children;
38+
var value = node.value;
39+
var find = pair[0];
40+
var replace = pair[1];
41+
var lastIndex = 0;
42+
var nodes = [];
43+
var subvalue;
44+
var index;
45+
var length;
46+
var match;
47+
var subhandler;
48+
49+
find.lastIndex = 0;
50+
51+
match = find.exec(value);
52+
53+
while (match) {
54+
index = match.index;
55+
subvalue = value.slice(lastIndex, index);
56+
57+
if (subvalue) {
58+
nodes.push({type: 'text', value: subvalue});
59+
}
60+
61+
subvalue = replace.apply(null, match);
62+
63+
if (subvalue) {
64+
if (typeof subvalue === 'string') {
65+
subvalue = {type: 'text', value: subvalue};
66+
}
67+
68+
nodes.push(subvalue);
69+
}
70+
71+
lastIndex = index + match[0].length;
72+
73+
if (!find.global) {
74+
break;
75+
}
76+
77+
match = find.exec(value);
78+
}
79+
80+
if (index === undefined) {
81+
nodes = [node];
82+
} else {
83+
subvalue = value.slice(lastIndex);
84+
85+
if (subvalue) {
86+
nodes.push({type: 'text', value: subvalue});
87+
}
88+
89+
parent.children = siblings.slice(0, pos).concat(nodes).concat(siblings.slice(pos + 1));
90+
}
91+
92+
if (pairs.length <= 1) {
93+
return;
94+
}
95+
96+
length = nodes.length;
97+
index = -1;
98+
subhandler = handlerFactory(pairs.slice(1));
99+
100+
while (++index < length) {
101+
node = nodes[index];
102+
103+
if (node.type === 'text') {
104+
subhandler(node, pos, parent);
105+
} else {
106+
search(node, settings, subhandler);
107+
}
108+
109+
pos++;
110+
}
111+
}
112+
}
113+
}
114+
115+
function search(tree, options, handler) {
116+
var ignore = options.ignore || IGNORE;
117+
var result = [];
118+
119+
visit(tree, 'text', visitor);
120+
121+
return result;
122+
123+
function visitor(node, parents) {
124+
var length = parents.length;
125+
var index = length;
126+
var parent;
127+
128+
while (index--) {
129+
if (is(parents[index], ignore)) {
130+
return;
131+
}
132+
}
133+
134+
parent = parents[length - 1];
135+
handler(node, parent.children.indexOf(node), parent);
136+
}
137+
}
138+
139+
function toPairs(schema) {
140+
var result = [];
141+
var key;
142+
var length;
143+
var index;
144+
145+
if (typeof schema !== 'object') {
146+
throw new Error('Expected array or object as schema');
147+
}
148+
149+
if (array(schema)) {
150+
length = schema.length;
151+
index = -1;
152+
153+
while (++index < length) {
154+
result.push([toExpression(schema[index][0]), toFunction(schema[index][1])]);
155+
}
156+
} else {
157+
for (key in schema) {
158+
result.push([toExpression(key), toFunction(schema[key])]);
159+
}
160+
}
161+
162+
return result;
163+
}
164+
165+
function toExpression(find) {
166+
return typeof find === 'string' ? RegExp(escape(find), 'g') : find;
167+
}
168+
169+
function toFunction(replace) {
170+
return typeof replace === 'function' ? replace : returner;
171+
172+
function returner() {
173+
return replace;
174+
}
175+
}

package.json

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"name": "hast-util-find-and-replace",
3+
"version": "0.0.0",
4+
"description": "Find and replace text in a HAST tree",
5+
"license": "MIT",
6+
"keywords": [
7+
"hast",
8+
"html",
9+
"find",
10+
"replace",
11+
"util",
12+
"utility"
13+
],
14+
"repository": "https://github.com/wooorm/hast-util-find-and-replace",
15+
"bugs": "https://github.com/wooorm/hast-util-find-and-replace/issues",
16+
"author": "Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)",
17+
"contributors": [
18+
"Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)"
19+
],
20+
"files": [
21+
"index.js"
22+
],
23+
"dependencies": {
24+
"escape-string-regexp": "^1.0.5",
25+
"hast-util-is-element": "^1.0.0",
26+
"isarray": "^2.0.1",
27+
"unist-util-visit-parents": "^1.1.0"
28+
},
29+
"devDependencies": {
30+
"browserify": "^13.0.0",
31+
"esmangle": "^1.0.1",
32+
"hastscript": "^3.0.1",
33+
"nyc": "^10.0.0",
34+
"remark-cli": "^2.1.0",
35+
"remark-preset-wooorm": "^1.0.0",
36+
"tape": "^4.4.0",
37+
"xo": "^0.17.0"
38+
},
39+
"scripts": {
40+
"build-md": "remark . --quiet --frail --output",
41+
"build-bundle": "browserify index.js --bare -s hastUtilFindAndReplace > hast-util-find-and-replace.js",
42+
"build-mangle": "esmangle hast-util-find-and-replace.js > hast-util-find-and-replace.min.js",
43+
"build": "npm run build-md && npm run build-bundle && npm run build-mangle",
44+
"lint": "xo",
45+
"test-api": "node test",
46+
"test-coverage": "nyc --reporter lcov tape test.js",
47+
"test": "npm run build && npm run lint && npm run test-coverage"
48+
},
49+
"xo": {
50+
"space": true,
51+
"rules": {
52+
"guard-for-in": "off"
53+
},
54+
"ignores": [
55+
"hast-util-find-and-replace.js"
56+
]
57+
},
58+
"nyc": {
59+
"check-coverage": true,
60+
"lines": 100,
61+
"functions": 100,
62+
"branches": 100
63+
},
64+
"remarkConfig": {
65+
"presets": "wooorm"
66+
}
67+
}

0 commit comments

Comments
 (0)