diff --git a/xmlpoke/xmlpoke-tests.ts b/xmlpoke/xmlpoke-tests.ts
new file mode 100644
index 0000000000..b77463f164
--- /dev/null
+++ b/xmlpoke/xmlpoke-tests.ts
@@ -0,0 +1,83 @@
+///
+///
+
+// tsc xmlpoke-tests.ts && node xmlpoke-tests.js
+
+import * as xmlpoke from 'xmlpoke';
+import * as assert from 'assert';
+
+let result: string;
+
+// add with xpath, value
+result = xmlpoke('', xml => xml.add('/a/b', 'c'));
+assert.equal(result, 'c');
+
+// add with xpath, Transform
+const addfn: XmlPoke.Transform = (node, value) => 'c';
+result = xmlpoke('', xml => xml.add('/a/b', addfn));
+assert.equal(result, 'c');
+
+// add with xpath, CDataValue
+const cdataval: XmlPoke.CDataValue = new xmlpoke.CDataValue('c');
+result = xmlpoke('', xml => xml.add('/a/b', cdataval));
+assert.equal(result, '');
+
+// add with xpath, XMLVal
+const xmlval = new xmlpoke.XmlString('');
+result = xmlpoke('', xml => xml.add('/a/b', xmlval));
+assert.equal(result, '');
+
+// add with map
+result = xmlpoke('', xml => xml.add({
+ '/a/b': 'c'
+}));
+assert.equal(result, 'c');
+
+// set with xpath, value
+result = xmlpoke('b', xml => xml.set('/a', 'c'));
+assert.equal(result, 'c');
+
+// set with map
+result = xmlpoke('b', xml => xml.set({
+ '/a': 'c'
+}));
+assert.equal(result, 'c');
+
+// set with xpath that doesn't exist (no-op)
+result = xmlpoke('bval', xml => xml.set('/a/c', 'cval'));
+assert.equal(result, 'bval');
+
+// setOrAdd with xpath, value
+result = xmlpoke('', xml => xml.setOrAdd('/a/b', 'c'));
+assert.equal(result, 'c');
+
+// setOrAdd with map
+result = xmlpoke('', xml => xml.setOrAdd({
+ '/a/b': 'c'
+}));
+assert.equal(result, 'c');
+
+// setOrAdd with xpath that doesn't exist: add
+result = xmlpoke('bval', xml => xml.setOrAdd('/a/c', 'cval'));
+assert.equal(result, 'bvalcval');
+
+// remove
+result = xmlpoke('', xml => xml.remove('//b'));
+assert.equal(result, '');
+
+// clear
+result = xmlpoke('', xml => xml.clear('/a'));
+assert.equal(result, '');
+
+// withBasePath, addNamespace, errorOnNoMatches
+result = xmlpoke('', xml =>
+ xml.withBasePath('/test')
+ .addNamespace('x', 'http://example.com/x')
+ .errorOnNoMatches()
+ .set('/x', (node, value) => {
+ assert.equal(typeof node, 'object');
+ assert.equal((node.constructor as any).name, 'Element');
+ assert.equal(value, 'hello');
+ return 'y';
+ }));
+assert.equal(result, 'y');
diff --git a/xmlpoke/xmlpoke.d.ts b/xmlpoke/xmlpoke.d.ts
new file mode 100644
index 0000000000..4b8868be98
--- /dev/null
+++ b/xmlpoke/xmlpoke.d.ts
@@ -0,0 +1,45 @@
+// Type definitions for xmlpoke 0.1.12
+// Project: https://github.com/mikeobrien/node-xmlpoke
+// Definitions by: Garth Kidd
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+///
+
+declare module XmlPoke { // ghost module
+ interface Transform {
+ (node: Node, value: string): Value;
+ }
+ type Value = string | boolean | number | XmlValue | CDataValue | PathToValueMap | Transform;
+ type PathToValueMap = {
+ [xpath: string]: Value;
+ }
+ interface API {
+ add(xpath: string, value: Value): API;
+ add(map: PathToValueMap): API;
+ set(xpath: string, value: Value): API;
+ set(map: PathToValueMap): API;
+ setOrAdd(xpath: string, value: Value): API;
+ setOrAdd(map: PathToValueMap): API;
+ remove(xpath: string): API;
+ clear(xpath: string): API;
+ withBasePath(xpath: string): API;
+ addNamespace(prefix: string, uri: string): API;
+ errorOnNoMatches(): API;
+ }
+ interface CDataValue {
+ value: string;
+ }
+ interface XmlValue {
+ value: string;
+ }
+}
+
+declare module 'xmlpoke' {
+ const xmlpoke: {
+ (xml: string, modify: (api: XmlPoke.API) => void): string;
+ CDataValue: new (value: string) => XmlPoke.CDataValue;
+ XmlString: new (value: string) => XmlPoke.XmlValue;
+ };
+ namespace xmlpoke {}
+ export = xmlpoke;
+}