Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dinky.js

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dinky.js - npm Package Compare versions

Comparing version 0.8.1 to 1.0.0

lib/Comments.js

54

lib/Dinky.js

@@ -6,5 +6,7 @@ const NetworkError = require("./util/NetworkError")

const Lists = require("./Lists")
const Comments = require("./Comments")
const Images = require("./Images")
const Search = require("./Search")
const Lists = require("./Lists")
const Tags = require("./Tags")

@@ -16,3 +18,3 @@ /**

/**
* A JavaScript client for Derpibooru API
* JavaScript bindings for Derpibooru API
*

@@ -35,34 +37,56 @@ * @param {object} [options = {}] – client options

/**
* Creates a request handler for /images.json
* Creates a request handler for /api/v1/json/search
*
* @return {Images}
* @param {string | string[]} [query = []] – query params
*
* @return {Search}
*
* @public
*/
images() {
return new Images({link: this.__link, dinky: this})
search(...query) {
return new Search({link: this.__link, dinky: this, query})
}
/**
* Creates a request handler for /search.json
* Creates a request handler for /api/v1/json/comments
*
* @param {string | string[]} [tags = []] – a tag or a list of tags
* @return {Comments}
*
* @return {Search}
* @public
*/
comments() {
return new Comments({link: this.__link, dinky: this})
}
/**
* Creates a request handler for /api/v1/json/tags
*
* @return {Tags}
*
* @public
*/
search(...tags) {
return new Search({link: this.__link, dinky: this, tags})
tags() {
return new Tags({link: this.__link, dinky: this})
}
/**
* Creates a new Lists instance to give you ability
* to send requests to `/lists.json` and bunch of shortcuts
* to search for specific images categories on `/search.json`
* Creates a request handler for /api/v1/json/images
*
* @return {Images}
*
* @public
*/
images() {
return new Images({link: this.__link, dinky: this})
}
/**
* Creates a List class that contains a bunch of shortcuts for Search.
*
* @return {Lists}
*
* @public
*/
lists() {
return new Lists({link: this.__link, dinky: this})
return new Lists({dinky: this})
}

@@ -69,0 +93,0 @@ }

@@ -1,2 +0,2 @@

const Request = require("./Request")
const Entities = require("./Entities")

@@ -6,3 +6,3 @@ /**

*/
class Images extends Request {
class Images extends Entities {
/**

@@ -18,14 +18,25 @@ * @param {object} options

/**
* Takes an image by given ID.
* Creates a new Search request that to /api/v1/json/search/images
*
* @param {number} id – image ID on Derpibooru
* @param {string | string[]} [query = []] – query params
*
* @return {Promise<object>}
* @return {Search}
*
* @public
*/
async id(id) {
this._path.push(id)
search(...args) {
return super.search(...args).images()
}
return this.exec()
/**
* Get a featured image
*
* @params {object} options
*
* @return {Promise<object>}
*/
featured(options) {
this._path.push("featured")
return this.exec(options)
}

@@ -32,0 +43,0 @@ }

@@ -1,26 +0,16 @@

const Request = require("./Request")
class Lists extends Request {
constructor({dinky, link}) {
super({dinky, link, path: "lists"})
/**
* @api private
*/
class Lists {
constructor({dinky}) {
this._dinky = dinky
}
/*
* Creates a request that gets 3 images lists (top scoring,
* all time top scoring, top commented) for given period.
*
* @param {string} period – Sampling period, specified in weeks,
* days, or hours
*
* @return {Lists}
*/
last(period) {
this._query.set("last", period)
return this
}
/**
* Creates a Search request that gets top scoring images of last 3 days.
* The most rated images will be at the top of the list.
*
* @return {Search}
*
* @public
*/

@@ -39,2 +29,4 @@ topScoring() {

* @return {Search}
*
* @public
*/

@@ -50,2 +42,4 @@ topScoringAllTime() {

* @return {Search}
*
* @public
*/

@@ -52,0 +46,0 @@ topCommented() {

@@ -15,5 +15,19 @@ const {URLSearchParams} = require("url")

/**
* Query params storage.
* Unlike URLSearchParams this class keeps every entry as is,
* so you would be able to read them from the store.
*
* @api private
*/
class Query extends Map {
/**
* Adds a new antry to the store
*
* @param {string} key
* @param {any} value
*
* @return {Query}
*
* @public
*/
set(key, value) {

@@ -25,2 +39,11 @@ assertKey(key)

/**
* Returns an antry by its name if so exists.
*
* @param {string} name
*
* @return {any}
*
* @public
*/
get(key) {

@@ -32,2 +55,11 @@ assertKey(key)

/**
* Checks if an entry associated key exists
*
* @param {string} key
*
* @return {boolean}
*
* @public
*/
has(key) {

@@ -39,2 +71,11 @@ assertKey(key)

/**
* Removes an entry associated with given key
*
* @param {string} key
*
* @return {void}
*
* @public
*/
delete(key) {

@@ -46,2 +87,9 @@ assertKey(key)

/**
* Casts query params to a string
*
* @return {string}
*
* @public
*/
toString() {

@@ -51,3 +99,3 @@ const entries = []

for (const [key, value] of this) {
// Omit all nullish keys because they're not necessary
// Omit all nullish and falsy keys as of they aren't necessary
if (value || value === 0) {

@@ -58,7 +106,3 @@ entries.push([key, value])

// Use URLSearchParams with Query class here because looks like
// it casts all given data types to string, but we need to save them
// as we need more flexibility for query search parameters
// For example: having an access to arrays as-is allows us to pass
// more data into it. See Search#tags() method as an example
// Use URLSearchParams to stringify entries
return new URLSearchParams(entries).toString()

@@ -65,0 +109,0 @@ }

const Query = require("./Query")
const {isArray} = Array
/**

@@ -42,3 +44,3 @@ * @api private

*/
this._path = [path]
this._path = isArray(path) ? path : [path]

@@ -45,0 +47,0 @@ this.exec = this.exec.bind(this)

@@ -1,2 +0,1 @@

const waterfall = require("./util/waterfall")
const flat = require("./util/flat")

@@ -6,3 +5,3 @@

const isArray = Array.isArray
const {isArray} = Array

@@ -17,13 +16,85 @@ /**

* @param {Function} options.link
* @param {string[] | string} [options.tags = []]
* @param {string[] | string} [options.query = []]
*/
constructor({dinky, link, tags = []}) {
constructor({dinky, link, query = []}) {
super({dinky, link, path: "search"})
if (tags.length > 0) {
this.tags(...tags)
if (query.length > 0) {
this.query(...query)
}
this.__type = "images"
}
/**
* Sets the search type to given value
*
* @param {string} searchType
*
* @return {Search}
*
* @private
*/
__setType(searchType) {
this.__type = searchType
return this
}
/**
* Sets Search type to "comments"
*
* @return {Search}
*
* @public
*/
comments() {
return this.__setType("comments")
}
/**
* Sets Search type to "galleries"
*
* @return {Search}
*
* @public
*/
galleries() {
return this.__setType("galleries")
}
/**
* Sets Search type to "posts"
*
* @return {Search}
*
* @public
*/
posts() {
return this.__setType("posts")
}
/**
* Sets Search type to "tags"
*
* @return {Search}
*
* @public
*/
tags() {
return this.__setType("tags")
}
/**
* Sets Search type to "images"
*
* @return {Search}
*
* @public
*/
images() {
return this.__setType("images")
}
/**
* Appends a tag or a list of tags to the current search request

@@ -36,3 +107,3 @@ *

*/
tags(...list) {
query(...list) {
list = flat(list)

@@ -64,5 +135,7 @@

* @return {Search}
*
* @public
*/
faves() {
return this.tags("my:faves")
return this.query("my:faves")
}

@@ -76,5 +149,7 @@

* @return {Search}
*
* @public
*/
watched() {
return this.tags("my:watched")
return this.query("my:watched")
}

@@ -88,5 +163,7 @@

* @return {Search}
*
* @public
*/
upvotes() {
return this.tags("my:upvotes")
return this.query("my:upvotes")
}

@@ -100,5 +177,7 @@

* @return {Search}
*
* @public
*/
downvotes() {
return this.tags("my:downvotes")
return this.query("my:downvotes")
}

@@ -112,5 +191,7 @@

* @return {Search}
*
* @public
*/
uploads() {
return this.tags("my:uploads")
return this.query("my:uploads")
}

@@ -124,5 +205,7 @@

* @return {Search}
*
* @public
*/
favedBy(user) {
return this.tags(`faved_by:${user}`)
return this.query(`faved_by:${user}`)
}

@@ -136,5 +219,7 @@

* @return {Search}
*
* @public
*/
uploadedBy(user) {
return this.tags(`uploader:${user}`)
return this.query(`uploader:${user}`)
}

@@ -153,3 +238,3 @@

limit(value) {
this._query.set("perpage", value)
this._query.set("per_page", value)

@@ -192,3 +277,3 @@ return this

*
* @return {Request}
* @return {Search}
*

@@ -206,3 +291,3 @@ * @public

*
* @return {Request}
* @return {Search}
*

@@ -218,3 +303,3 @@ * @public

/**
* Adds a param to surt result by given field.
* Adds a param to sort result by given field.
*

@@ -224,2 +309,4 @@ * @param {string} field

* @return {Search}
*
* @public
*/

@@ -235,18 +322,8 @@ sortBy(field) {

*
* @return {Promise<object | undefined>}
* @return {Search}
*
* @public
*/
async random() {
this._query.set("random_image", true)
const resolve = image => {
if (image && image.id != null) {
return this._dinky.images().id(image.id)
}
return undefined
}
return waterfall([this.exec, resolve])
random() {
return this.sortBy("random")
}

@@ -265,3 +342,3 @@

this._query.set("q", params.join(","))
} else if (this._query.has("random_image")) {
} else if (this._query.get("sf") === "random") {
// Add wildcard when searching for random image,

@@ -272,27 +349,4 @@ // but no tags has been set

const limit = this._query.get("perpage")
if (limit != null) {
// Turn off the rule because we need to check value of any type
// eslint-disable-next-line no-restricted-globals
if (isNaN(limit)) {
throw new TypeError("You must specify the limit amount as number.")
}
this._path.push(this.__type)
if (limit <= 1 || limit >= 50) {
throw new RangeError("Limit must be a value in range between 1 and 50.")
}
}
const min = this._query.get("min_score")
// eslint-disable-next-line no-restricted-globals
if (min != null && isNaN(min)) {
throw new TypeError("You must specify minimal score as a number.")
}
const max = this._query.get("max_score")
// eslint-disable-next-line no-restricted-globals
if (max != null && isNaN(max)) {
throw new TypeError("You must specify maximal score as a number.")
}
return super.exec(options)

@@ -299,0 +353,0 @@ }

@@ -1,11 +0,14 @@

const isArray = Array.isArray
const {isArray} = Array
/**
* @api private
*/
function flat(array, depth = 1) {
const walk = (prev, next) => (
const step = (prev, next) => (
prev.concat(isArray(next) && depth > 0 ? flat(next, depth - 1) : [next])
)
return array.reduce(walk, [])
return array.reduce(step, [])
}
module.exports = flat

@@ -0,3 +1,6 @@

/**
* @api private
*/
const isFunction = value => typeof value === "function"
module.exports = isFunction

@@ -0,3 +1,6 @@

/**
* @api private
*/
const isNumber = value => typeof value === "number"
module.exports = isNumber

@@ -0,1 +1,4 @@

/**
* @api private
*/
const getType = val => (

@@ -5,2 +8,5 @@ Object.prototype.toString.call(val).slice(8, -1).toLowerCase()

/**
* @api private
*/
function isPlainObject(val) {

@@ -7,0 +13,0 @@ if (getType(val) !== "object") {

@@ -0,3 +1,6 @@

/**
* @api private
*/
const isString = value => typeof value === "string"
module.exports = isString

@@ -6,2 +6,3 @@ const {parse, format} = require("url")

const cast = require("./castDates")
const partial = require("./partial")

@@ -12,4 +13,6 @@ const right = require("./partialRight")

// TODO: Make version configurable
const base = parse("https://derpibooru.org/api/v1/json")
const toCamelCase = right(camelCase, {deep: true})
const base = parse("https://derpibooru.org")
const defaults = {

@@ -20,3 +23,6 @@ key: undefined,

async function receiveData(response) {
/**
* @api private
*/
function receiveData(response) {
if (response.ok === false) {

@@ -56,2 +62,3 @@ throw new NetworkError(`Network error: ${response.status}`, response)

return async function link(path, search, params = {}) {
path = [base.pathname, ...path].filter(Boolean)
params = {...options, ...params}

@@ -67,7 +74,7 @@

const pathname = `${path.join("/").replace(/\/{2,}/g, "/")}.json`
const pathname = path.join("/").replace(/\/{2,}/g, "/")
const url = format({...base, pathname, search: search.toString()})
const sendRequest = partial(fetch, url, {method: "get"})
return waterfall([sendRequest, receiveData, toCamelCase])
return waterfall([sendRequest, receiveData, toCamelCase, cast])
}

@@ -74,0 +81,0 @@ }

@@ -0,1 +1,4 @@

/**
* @api public
*/
class NetworkError extends Error {

@@ -2,0 +5,0 @@ constructor(message, response) {

{
"name": "dinky.js",
"version": "0.8.1",
"version": "1.0.0",
"description": "JavaScript bindings for Derpibooru API",
"main": "lib/Dinky",
"repository": "https://github.com/octet-stream/dinky",
"repository": "octet-stream/dinky",
"author": "Nick K. <io@octetstream.me>",
"license": "MIT",
"engines": {
"node": ">=8 < 9 || >= 10 < 11 || >= 12"
"node": ">= 10 < 11 || >= 12"
},

@@ -26,26 +26,20 @@ "keywords": [

},
"ava": {
"files": [
"test/**/*.js",
"!test/helper/**"
]
},
"devDependencies": {
"@octetstream/eslint-config": "4.0.0",
"ava": "2.4.0",
"codecov": "3.6.1",
"eslint": "6.6.0",
"eslint-plugin-ava": "9.0.0",
"eslint-plugin-markdown": "1.0.1",
"fetch-mock": "8.0.0-alpha.14",
"husky": "3.0.9",
"lint-staged": "9.4.2",
"nyc": "14.1.1",
"ava": "3.5.1",
"codecov": "3.6.5",
"eslint": "6.8.0",
"eslint-plugin-ava": "10.2.0",
"eslint-plugin-markdown": "1.0.2",
"fetch-mock": "9.3.1",
"husky": "4.2.3",
"lint-staged": "10.0.9",
"nyc": "15.0.0",
"proxyquire": "2.1.3",
"sinon": "7.5.0"
"sinon": "9.0.1"
},
"dependencies": {
"camelcase-keys": "6.1.0",
"camelcase-keys": "6.2.1",
"node-fetch": "2.6.0"
}
}

@@ -39,4 +39,4 @@ # dinky.js

// The following request will return the 1th uploaded image from Derpibooru.
// Equivalent to https://derpibooru.org/images/0.json request
dinky().images().id(0).then(console.log)
// Equivalent to https://derpibooru.org/api/v1/json/images/0 request
dinky().images().getById(0).then(console.log)
```

@@ -50,6 +50,5 @@

// You can specify tags right in the .search() method
// The following example is equivalent of these requests:
// https://derpibooru.org/search.json?q=artist:rainbow,safe&random_image=true
// ...and then this one:
// https://derpibooru.org/images/<received image id>.json
// The following example is equivalent of this requests:
// https://derpibooru.org/api/v1/json/search/images
// ?q=artist:rainbow,safe&sf=random
dinky().search(["artist:rainbow", "safe"]).random()

@@ -66,11 +65,13 @@ .then(console.log)

(async function() {
const search = dinky()
const random = dinky()
.search(["scootaloo", "princess luna", "safe", "sleepless in ponyville"])
.minScore(200)
.random()
.limit(1)
// Will search for random image with parameters from above
await search.random()
await random
// ...and once more
await search.random()
await random
}()).catch(console.error)

@@ -138,22 +139,62 @@ ```

Creates a request handler for `/images.json`
Creates a request handler for `/api/v1/json/images`
##### `search([tags]) -> {Search}`
##### `search([query]) -> {Search}`
Creates a request handler for `/search.json`. This method takes a list of tags
Creates a request handler for `/api/v1/json/search/images`. This method takes a list of query params
- **{string | string[]}** [tags = []] – a tag or a list of tags and returns Search instance
- **{string | string[]}** [query = []] – a tag or a list of query params and returns Search instance
### `class Images > Request`
### `class Images > Entities`
##### `constructor() -> {Images}`
Creates a request handler for `/images.json`
Creates a request handler for `/api/v1/json/images`
#### Instance methods
##### `id(id) -> {Promise<object>}`
##### `search([query]) -> {Search}`
Creates a new Search request that points to `/api/v1/json/search/images`.
##### `getById(id) -> {Promise<object>}`
Returns an image with given ID
##### `featured() -> {Promise<object>}`
Returns featured image
### `class Comments > Entities`
##### `constructor() -> {Comments}`
Creates a request handler for `/api/v1/json/comments`.
#### Instance methods
##### `search([query]) -> {Search}`
Creates a new Search request that points to `/api/v1/json/search/comments`.
##### `getById(id) -> {Promise<object>}`
Returns a comment with given ID
### `class Tags > Entities`
##### `constructor() -> {Tags}`
Creates a request handler for `/api/v1/json/tags`.
#### Instance methods
##### `search([query]) -> {Search}`
Creates a new Search request that points to `/api/v1/json/search/tags`.
##### `getById(id) -> {Promise<object>}`
Returns a tag with given ID
### `class Search > Request`

@@ -163,15 +204,35 @@

Creates a request handler for `/search.json`.
Creates a request handler for `/api/v1/json/search`.
#### Instance methods
##### `tags([list]) -> {Search}`
##### `comments() -> {Search}`
Appends a tag or a list of tags to the current search request.
This method will not apply the `q=` parameter to the request for query when no tags has been set.
Sets Search type to "comments"
- **{string | string[]}** [list = []] – a tag or a list of tags you want to append
##### `galleries() -> {Search}`
##### `faves() -> {Seatch}`
Sets Search type to "galleries"
##### `posts() -> {Search}`
Sets Search type to "posts"
##### `tags() -> {Search}`
Sets Search type to "tags"
##### `images() -> {Search}`
Sets Search type to "images"
##### `query([list]) -> {Search}`
Appends list of query params to the current search request.
This method will not apply the `q=` parameter to if called without arguments.
- **{string | string[]}** [list = []] – list of query params you want to append
##### `faves() -> {Search}`
Sets my:faves param to the search request.

@@ -236,3 +297,3 @@

##### `random() -> {Promise<object>}`
##### `random() -> {Search}`

@@ -245,12 +306,4 @@ If been called, the API will return random image

Creates a new Lists instance to give you ability to send requests to `/lists.json`
and bunch of shortcuts to search for specific images categories on `/search.json`
Provides a bunch of shortcuts for `Search` request
##### `last(period) -> {Lists}`
Creates a request that gets 3 images lists (top scoring, all time top scoring, top commented)
for given period.
- **{string}** period – Sampling period, specified in weeks, days, or hours
##### `topScoring() -> {Search}`

@@ -271,2 +324,18 @@

### `class Entities > Request`
##### `constructor() -> {Entities}`
Creates an Entity providing a few common methods for `Images`, `Comments` and `Tags`
#### Instance methods
##### `search([query]) -> {Search}`
Creates a new Search request that points to `/api/v1/json/search`.
##### `getById(id) -> {Promise<object>}`
Finds an entity by given ID
### `class Request`

@@ -273,0 +342,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc