diff --git a/README.md b/README.md
index 9a28c58..64204a3 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ My Swiss knife
## Getting Started
-Flowing features;
+Folowing features:
- Wrap [async-airtable](https://github.com/GV14982/async-airtable) to access AirTable API easily.
diff --git a/package-lock.json b/package-lock.json
index b6ad228..ec637ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
- "name": "stools",
- "version": "0.1.0",
+ "name": "@thomascsd/stools",
+ "version": "1.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1767,6 +1767,16 @@
}
}
},
+ "@mrmlnc/readdir-enhanced": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
+ "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
+ "dev": true,
+ "requires": {
+ "call-me-maybe": "^1.0.1",
+ "glob-to-regexp": "^0.3.0"
+ }
+ },
"@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -1968,6 +1978,16 @@
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true
},
+ "@types/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
"@types/graceful-fs": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -2024,6 +2044,18 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
+ "@types/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
+ "dev": true
+ },
+ "@types/minimist": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz",
+ "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==",
+ "dev": true
+ },
"@types/node": {
"version": "14.14.37",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
@@ -2393,6 +2425,16 @@
"integrity": "sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A==",
"dev": true
},
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -2539,6 +2581,12 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "dev": true
+ },
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -2568,6 +2616,12 @@
"function-bind": "^1.1.1"
}
},
+ "arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "dev": true
+ },
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -3460,6 +3514,12 @@
"get-intrinsic": "^1.0.2"
}
},
+ "call-me-maybe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
+ "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
+ "dev": true
+ },
"caller-callsite": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
@@ -3490,6 +3550,25 @@
"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
"dev": true
},
+ "camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ }
+ }
+ },
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@@ -3665,6 +3744,12 @@
}
}
},
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
"cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -3937,6 +4022,168 @@
"parse-json": "^4.0.0"
}
},
+ "cp-file": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
+ "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^3.0.0",
+ "nested-error-stacks": "^2.0.0",
+ "p-event": "^4.1.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "cpy": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz",
+ "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==",
+ "dev": true,
+ "requires": {
+ "arrify": "^2.0.1",
+ "cp-file": "^7.0.0",
+ "globby": "^9.2.0",
+ "has-glob": "^1.0.0",
+ "junk": "^3.1.0",
+ "nested-error-stacks": "^2.1.0",
+ "p-all": "^2.1.0",
+ "p-filter": "^2.1.0",
+ "p-map": "^3.0.0"
+ },
+ "dependencies": {
+ "@nodelib/fs.stat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
+ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dev": true,
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "dir-glob": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+ "dev": true,
+ "requires": {
+ "path-type": "^3.0.0"
+ }
+ },
+ "fast-glob": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
+ "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==",
+ "dev": true,
+ "requires": {
+ "@mrmlnc/readdir-enhanced": "^2.2.1",
+ "@nodelib/fs.stat": "^1.1.2",
+ "glob-parent": "^3.1.0",
+ "is-glob": "^4.0.0",
+ "merge2": "^1.2.3",
+ "micromatch": "^3.1.10"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "globby": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+ "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "array-union": "^1.0.2",
+ "dir-glob": "^2.2.2",
+ "fast-glob": "^2.2.6",
+ "glob": "^7.1.3",
+ "ignore": "^4.0.3",
+ "pify": "^4.0.1",
+ "slash": "^2.0.0"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true
+ }
+ }
+ },
+ "cpy-cli": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-3.1.1.tgz",
+ "integrity": "sha512-HCpNdBkQy3rw+uARLuIf0YurqsMXYzBa9ihhSAuxYJcNIrqrSq3BstPfr0cQN38AdMrQiO9Dp4hYy7GtGJsLPg==",
+ "dev": true,
+ "requires": {
+ "cpy": "^8.0.0",
+ "meow": "^6.1.1"
+ }
+ },
"create-ecdh": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
@@ -4324,6 +4571,24 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
+ "decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "dependencies": {
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ }
+ }
+ },
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@@ -5939,6 +6204,12 @@
"is-glob": "^4.0.1"
}
},
+ "glob-to-regexp": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
+ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
+ "dev": true
+ },
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -6009,6 +6280,12 @@
"har-schema": "^2.0.0"
}
},
+ "hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true
+ },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -6030,6 +6307,26 @@
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
+ "has-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz",
+ "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
@@ -6297,6 +6594,12 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
@@ -6661,6 +6964,12 @@
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true
},
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true
+ },
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -8494,6 +8803,12 @@
"object.assign": "^4.1.2"
}
},
+ "junk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
+ "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
+ "dev": true
+ },
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -8890,6 +9205,12 @@
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
"dev": true
},
+ "map-obj": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz",
+ "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==",
+ "dev": true
+ },
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -8926,6 +9247,33 @@
"readable-stream": "^2.0.1"
}
},
+ "meow": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz",
+ "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==",
+ "dev": true,
+ "requires": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "^4.0.2",
+ "normalize-package-data": "^2.5.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.13.1",
+ "yargs-parser": "^18.1.3"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+ "dev": true
+ }
+ }
+ },
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -9004,6 +9352,12 @@
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
+ "min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true
+ },
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -9031,6 +9385,25 @@
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
+ "minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ },
+ "dependencies": {
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true
+ }
+ }
+ },
"mississippi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@@ -9165,6 +9538,12 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
+ "nested-error-stacks": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
+ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==",
+ "dev": true
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -9600,12 +9979,55 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
+ "p-all": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz",
+ "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==",
+ "dev": true,
+ "requires": {
+ "p-map": "^2.0.0"
+ },
+ "dependencies": {
+ "p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+ "dev": true
+ }
+ }
+ },
"p-each-series": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
"integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==",
"dev": true
},
+ "p-event": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
+ "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
+ "dev": true,
+ "requires": {
+ "p-timeout": "^3.1.0"
+ }
+ },
+ "p-filter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
+ "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
+ "dev": true,
+ "requires": {
+ "p-map": "^2.0.0"
+ },
+ "dependencies": {
+ "p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+ "dev": true
+ }
+ }
+ },
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@@ -9630,6 +10052,24 @@
"p-limit": "^2.0.0"
}
},
+ "p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "p-timeout": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
+ "dev": true,
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -9725,8 +10165,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
- "dev": true,
- "optional": true
+ "dev": true
},
"path-exists": {
"version": "3.0.0",
@@ -9829,14 +10268,22 @@
"dev": true
},
"postcss": {
- "version": "8.2.9",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.9.tgz",
- "integrity": "sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q==",
+ "version": "8.2.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
+ "integrity": "sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==",
"dev": true,
"requires": {
"colorette": "^1.2.2",
- "nanoid": "^3.1.22",
+ "nanoid": "^3.1.23",
"source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "nanoid": {
+ "version": "3.1.23",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
+ "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
+ "dev": true
+ }
}
},
"postcss-calc": {
@@ -10894,6 +11341,12 @@
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true
},
+ "quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -11037,6 +11490,16 @@
"resolve": "^1.1.6"
}
},
+ "redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "requires": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ }
+ },
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
@@ -12336,6 +12799,15 @@
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true
},
+ "strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "requires": {
+ "min-indent": "^1.0.0"
+ }
+ },
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -12729,6 +13201,12 @@
"punycode": "^2.1.0"
}
},
+ "trim-newlines": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz",
+ "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==",
+ "dev": true
+ },
"ts-jest": {
"version": "25.5.1",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-25.5.1.tgz",
diff --git a/package.json b/package.json
index e87c627..d8c1525 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@thomascsd/stools",
- "version": "1.0.4",
+ "version": "1.1.0",
"license": "MIT",
"repository": {
"url": "https://github.com/thomascsd/stools"
@@ -17,7 +17,8 @@
"lint": "tsdx lint",
"size": "size-limit",
"analyze": "size-limit --why",
- "deploy": "npm publish --access public"
+ "deploy:cpy": "cpy ./package.json ./dist/ & cpy ./README.md ./dist/",
+ "deploy": "deploy:cpy & cd dist & npm publish --access public --dry-run"
},
"peerDependencies": {},
"husky": {
@@ -45,6 +46,7 @@
],
"devDependencies": {
"@size-limit/preset-small-lib": "^4.10.2",
+ "cpy-cli": "^3.1.1",
"dotenv": "^8.2.0",
"husky": "^6.0.0",
"size-limit": "^4.10.2",
diff --git a/src/index.ts b/src/index.ts
index e795ed2..c9460cd 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,4 @@
import 'reflect-metadata';
export * from './services/DataService';
+export * from './services/DataFunctionService';
export * from './models/BaseModel';
diff --git a/src/services/BaseService.ts b/src/services/BaseService.ts
index 1f6c3a6..582d21a 100644
--- a/src/services/BaseService.ts
+++ b/src/services/BaseService.ts
@@ -5,7 +5,7 @@ import { BaseModel } from '../models/BaseModel';
export class BaseService {
constructor(public apiKey: string) {}
- async getDatas(
+ async get(
baseId: string,
tableName: string,
options?: SelectOptions
@@ -27,13 +27,13 @@ export class BaseService {
return body;
}
- async saveData(baseId: string, tableName: string, model: T) {
+ async save(baseId: string, tableName: string, model: T) {
const airtable = this.getAirTableClient(baseId);
const body = await airtable.createRecord(tableName, model);
return body;
}
- async updateData(baseId: string, tableName: string, model: T) {
+ async update(baseId: string, tableName: string, model: T) {
const airtable = this.getAirTableClient(baseId);
const tmpModel = { ...model };
const id = tmpModel.id;
@@ -46,7 +46,7 @@ export class BaseService {
return body;
}
- async deleteData(
+ async delete(
baseId: string,
tableName: string,
model: T
diff --git a/src/services/DataFunctionService.ts b/src/services/DataFunctionService.ts
index 307aa45..51db4ca 100644
--- a/src/services/DataFunctionService.ts
+++ b/src/services/DataFunctionService.ts
@@ -1,7 +1,28 @@
+import { SelectOptions, AirtableRecord, DeleteResponse } from 'asyncairtable/lib/@types';
+import { BaseModel } from '../models/BaseModel';
import { BaseService } from './BaseService';
+/**
+ * Define service that access AirTable's data
+ */
export class DataFunctionService extends BaseService {
- constructor(public apiKey: string) {
+ constructor(public apiKey: string, public baseId: string) {
super(apiKey);
}
+
+ async getDatas(tableName: string, options?: SelectOptions): Promise {
+ return await super.get(this.baseId, tableName, options);
+ }
+
+ async saveData(tableName: string, model: T): Promise {
+ return await super.save(this.baseId, tableName, model);
+ }
+
+ async updateData(tableName: string, model: T): Promise {
+ return await super.update(this.baseId, tableName, model);
+ }
+
+ async deleteData(tableName: string, model: T): Promise {
+ return await super.delete(this.baseId, tableName, model);
+ }
}
diff --git a/src/services/DataService.ts b/src/services/DataService.ts
index 5cbf098..e834c4d 100644
--- a/src/services/DataService.ts
+++ b/src/services/DataService.ts
@@ -1,14 +1,19 @@
-import AsyncAirtable from 'asyncairtable';
-import { AirtableRecord, SelectOptions } from 'asyncairtable/lib/@types';
+import { AirtableRecord, DeleteResponse, SelectOptions } from 'asyncairtable/lib/@types';
import { Service, Inject, Token } from 'typedi';
import { BaseModel } from '../models/BaseModel';
+import { BaseService } from './BaseService';
const AIRTABLE_APIKEY_TOKEN = 'stools_AIRTABLE_APIKEY_TOKEN';
export const API_KEY_TOKEN = new Token(AIRTABLE_APIKEY_TOKEN);
+/**
+ * Define service that access AirTable's data, and use DI with typedi.
+ */
@Service()
-export class DataService {
+export class DataService extends BaseService {
constructor(@Inject(API_KEY_TOKEN) public apiKey: string) {
+ super(apiKey);
+
if (!this.apiKey) {
this.apiKey = process.env.AIRTABLE_API ?? '';
}
@@ -19,53 +24,30 @@ export class DataService {
tableName: string,
options?: SelectOptions
): Promise {
- const airtable = this.getAirTableClient(baseId);
- const records: AirtableRecord[] = await airtable.select(tableName, options);
-
- const body = records
- .map((o: AirtableRecord) => {
- const fields = o.fields;
- fields.id = o.id;
- return fields;
- })
- .map(fields => {
- const obj: Record = { ...fields };
- return obj;
- }) as T[];
-
- return body;
- }
-
- async saveData(baseId: string, tableName: string, model: T) {
- const airtable = this.getAirTableClient(baseId);
- const body = await airtable.createRecord(tableName, model);
-
- return body;
+ return await super.get(baseId, tableName, options);
}
- async updateData(baseId: string, tableName: string, model: T) {
- const airtable = this.getAirTableClient(baseId);
- const tmpModel = { ...model };
- const id = tmpModel.id;
- delete tmpModel.id;
- const body = await airtable.updateRecord(tableName, {
- id: id as string,
- fields: tmpModel,
- });
-
- return body;
+ async saveData(
+ baseId: string,
+ tableName: string,
+ model: T
+ ): Promise {
+ return await super.save(baseId, tableName, model);
}
- async deleteData(baseId: string, tableName: string, model: T) {
- const airtable = this.getAirTableClient(baseId);
-
- const res = await airtable.deleteRecord(tableName, model.id as string);
- return res;
+ async updateData(
+ baseId: string,
+ tableName: string,
+ model: T
+ ): Promise {
+ return await super.update(baseId, tableName, model);
}
- private getAirTableClient(baseId: string) {
- const airtable = new AsyncAirtable(this.apiKey, baseId);
-
- return airtable;
+ async deleteData(
+ baseId: string,
+ tableName: string,
+ model: T
+ ): Promise {
+ return await super.delete(baseId, tableName, model);
}
}
diff --git a/test/DataFunctionService.test.ts b/test/DataFunctionService.test.ts
new file mode 100644
index 0000000..7e27923
--- /dev/null
+++ b/test/DataFunctionService.test.ts
@@ -0,0 +1,76 @@
+import { config } from 'dotenv';
+import { DataFunctionService, BaseModel } from '../src';
+import { AirtableRecord } from 'asyncairtable/lib/@types';
+
+config();
+
+const apiKey = process.env.AIRTABLE_API ?? '';
+const baseId = process.env.AIRTABLE_BASE_ID ?? '';
+
+describe('DataService', () => {
+ let service: DataFunctionService;
+ let data: AirtableRecord;
+
+ beforeEach(() => {
+ service = new DataFunctionService(apiKey, baseId);
+ });
+
+ it('apikey by env', () => {
+ expect(service.apiKey).toEqual(apiKey);
+ });
+
+ it('baseId by env', () => {
+ expect(service.baseId).toEqual(baseId);
+ });
+
+ it('get datas', async () => {
+ const datas = await service.getDatas('contact');
+
+ expect(datas.length).not.toEqual(0);
+ });
+
+ it('add data', async () => {
+ const model: BaseModel = {
+ name: 'thomas',
+ email: 't123@sample.com',
+ mobile: '0999123456',
+ };
+
+ data = await service.saveData('contact', model);
+
+ expect(data).not.toBeUndefined();
+ expect(data.fields.name).toEqual('thomas');
+
+ console.dir(data);
+ });
+
+ it('update data', async () => {
+ const model: BaseModel = {
+ id: data.id,
+ name: 'thomas789',
+ email: 't123@sample.com',
+ mobile: '0999123456',
+ };
+
+ data = await service.updateData('contact', model);
+
+ expect(data).not.toBeUndefined();
+ expect(data.fields.name).toEqual('thomas789');
+
+ console.dir(data);
+ });
+
+ it('delete data', async () => {
+ const model: BaseModel = {
+ id: data.id,
+ };
+
+ const res = await service.deleteData('contact', model);
+
+ console.dir(res);
+
+ expect(res).not.toBeUndefined();
+ expect(res.id).toEqual(data.id);
+ expect(res.deleted).toBeTruthy();
+ });
+});