lmammino / tall

Promise-based, No-dependency URL unshortner (expander) module for Node.js
https://lmammino.github.io/tall/
MIT License
72 stars 7 forks source link

Implemented plugin system #44

Closed lmammino closed 2 years ago

lmammino commented 2 years ago

This PR proposes a new plugin-based implementations that can allow to make tall easily extensible without breaking the principles on which it is built:

This will enable adding additional interesting behaviours (through dedicated plugins) such as:

Since implementing this behaviours requires parsing HTML (and therefore implies introducing external dependencies), those behaviours can be built as external plugins and be passed to tall.

Once this is finalised and merged #43 could be re-implemented as a plugin

CC: @karlhorky

Usage

By default the original business logic (follow location headers) is now implemented as a plugin which is enabled by default: locationHeaderPlugin.

Plugins are effectively executed like middlewares and they have an opportunity to change the current status and decide to STOP at the current url or FOLLOW the current url to look for new indicators that suggest a redirect (location headers, canonical links, http-equiv meta headers, etc.).

This is how the the locationHeaderPlugin is currently being implemented:

async function locationHeaderPlugin (url: URL, response: IncomingMessage, previous: Follow | Stop): Promise<Follow | Stop> {
  const { protocol, host } = url

  // if there's a location header normalise the URL and follow it
  if (response.headers.location) {
    const followUrl = new URL(response.headers.location.startsWith('http')
      ? response.headers.location
      : `${protocol}//${host}${response.headers.location}`)
    return new Follow(followUrl)
  }

  // otherwise don't change the current result 
  // (which could already have a Stop or a Follow based on the previous iteration)
  return previous
}

Let's say we have implemented a new plugin called httpEquivPlugin we could enable as follows:

import httpEquivPlugin from 'tall-http-equiv',
import {tall, locationHeaderPlugin} from 'tall'

tall('https://example.com', {
  plugins: [locationHeaderPlugin, httpEquivPlugin]
}).then(console.log)

TODO

codecov[bot] commented 2 years ago

Codecov Report

Merging #44 (2301ddc) into master (4055aba) will not change coverage. The diff coverage is 100.00%.

:exclamation: Current head 2301ddc differs from pull request most recent head 0a3fdbd. Consider uploading reports for the commit 0a3fdbd to get more accurate results

Impacted file tree graph

@@            Coverage Diff            @@
##            master       #44   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           54        80   +26     
  Branches        10        11    +1     
=========================================
+ Hits            54        80   +26     
Impacted Files Coverage Δ
src/index.ts 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 4055aba...0a3fdbd. Read the comment docs.