diff --git a/.gitignore b/.gitignore index 782706d..6708c86 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ coverage/ .npmrc package-lock.json +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d9882e..8f424eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ For easy reference, some examples of formats are kept at the bottom of this file ## [Unreleased] +## [0.2.0] - 2023-07-26 + +### Added + +- An index.js that exports everything from the package +- Compiled javascript in the published package +- Separate type definitions in the published package + +### Changed + +- The middlewares are now functions instead of objects with methods +- The attribution models are now functions instead of objects with methods + ## [0.1.0] - 2023-07-24 The first version! diff --git a/README.md b/README.md index b43e30b..d029461 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,21 @@ This is not meant to be a full replacement of an analytics tool, which usually measures things such as sessions, landing pages, interactions, revenue and more. This just attributes, and it is small enough (around 1kb gzipped) that it can be used alongside such tools if you want to. +## Installation + +This package is on npm: + +```shell +npm install @jeroen.bakker/just-attribute +``` + ## Usage In its most basic form logging interactions (pageviews) is as simple as: ```javascript +import { InteractionLogger } from '@jeroen.bakker/just-attribute'; + const logger = new InteractionLogger(localStorage); logger.pageview(); ``` @@ -39,12 +49,13 @@ When it is time to finalize the list of interactions (i.e. when a user "converts run the log of interactions through one of the included attribution models and clear the log. ```javascript +import { InteractionLogger, firstInteraction } from '@jeroen.bakker/just-attribute'; + const logger = new InteractionLogger(localStorage); -const firstInteraction = new FirstInteraction(); // Do whatever you want with the attribution, such as sync it to your server // it might also be a good idea to sync the logs themselves to learn from them or to debug attribution -const attribution = firstInteraction.attribute(logger.interactionLog()); +const attribution = firstInteraction(logger.interactionLog()); // Clear the log so you don't endlessly collect interactions that have already been attributed logger.clearLog(); @@ -128,12 +139,12 @@ They are simply executed by the logger itself after the initial interaction has Once all middlewares are done it is determined whether attribution has changed, and if so the interaction is logged. A few middlewares have been provided: -* [Google Ads](src/InteractionMiddlewares/GoogleAdsMiddleware.ts) +* [Google Ads](src/InteractionMiddlewares/GoogleAds.ts) This sets a source / medium of google / cpc for any URL containing a `gclid` parameter. Additionally, the parameter is logged as an important parameter, meaning attribution will change if it has a different value in a new interaction. -* [Facebook Ads](src/InteractionMiddlewares/FacebookAdsMiddleware.ts) +* [Facebook Ads](src/InteractionMiddlewares/FacebookAds.ts) Similar to the above middleware, it sets a source / medium of facebook / cpc for any URL containing a `fbclid` parameter. -* [`ref` transformer](src/InteractionMiddlewares/RefMiddleware.ts) +* [`ref` transformer](src/InteractionMiddlewares/Ref.ts) If a URL conains a `ref` parameter this will set its value as the source and sets the medium to referral. Please see the source of these middlewares for further details on their behavior. @@ -162,6 +173,7 @@ Planned: - Add out of the box implementation for running attribution models in BigQuery using javascript UDFs - Describe how to contribute - Add a code style linter/fixer to make contributing easier +- Set up GitHub action to publish to npm Undecided: - Whether to log the page URL as part of the interaction, this would allow users to get information about landing pages and how they perform. diff --git a/debug.ts b/debug.ts deleted file mode 100644 index 7d3e444..0000000 --- a/debug.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InteractionLogger from './src/InteractionLogger'; - -const instance = new InteractionLogger(localStorage); - -globalThis.__jaLogger = instance; - -instance.onAttributionChange((interaction) => { - console.group('just-attribute'); - console.log('Attribution changed:', interaction); - console.groupEnd(); -}); - -instance.pageview(); diff --git a/index.ts b/index.ts deleted file mode 100644 index 338330f..0000000 --- a/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import InteractionLogger from './src/InteractionLogger'; - -const instance = new InteractionLogger(localStorage); -instance.pageview(); diff --git a/jest.config.ts b/jest.config.ts index a621ddb..eb3a7b6 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -12,7 +12,9 @@ export default { // An array of glob patterns indicating a set of files for which coverage information should be collected collectCoverageFrom: [ - 'src/**/*.ts' + 'src/**/*.ts', + '!src/types.ts', + '!src/index.ts', ], // The directory where Jest should output its coverage files diff --git a/package.json b/package.json index 57ffe4e..2ecccbe 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,18 @@ { "name": "@jeroen.bakker/just-attribute", - "version": "0.1.0", + "version": "0.2.0", "description": "Realtime privacy-conscious marketing attribution for the web", "author": "Jeroen Bakker", "license": "MIT", "scripts": { - "debug": "esbuild debug.ts --bundle --minify --outfile=./dist/just-attribute-debug.js", - "build": "esbuild index.ts --bundle --minify --outfile=./dist/just-attribute.js", - "test": "jest" + "build": "esbuild src/*.ts src/*/*.ts --outdir=dist --bundle --format=esm --minify", + "tsc": "tsc", + "test": "jest", + "prepublishOnly": "npm run build && npm run tsc" }, - "main": "src/InteractionLogger.ts", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", "dependencies": {}, "devDependencies": { "@jest/globals": "^29.6.1", @@ -21,7 +24,7 @@ }, "files": [ "src", - "types.ts" + "dist" ], "repository": { "type": "git", diff --git a/src/AttributionModels/FirstInteraction.ts b/src/AttributionModels/FirstInteraction.ts index 475d2ae..ecba719 100644 --- a/src/AttributionModels/FirstInteraction.ts +++ b/src/AttributionModels/FirstInteraction.ts @@ -1,4 +1,4 @@ -import { AttributionModel, Interaction } from '../../types'; +import { AttributionModel, Interaction } from '../types'; /** * This implements the "first interaction" attribution model @@ -6,15 +6,15 @@ import { AttributionModel, Interaction } from '../../types'; * * Since only one interaction is returned, it is not weighted */ -export default class FirstInteraction implements AttributionModel { - public attribute(interactions: Interaction[]): Interaction { - if (interactions.length === 0) { - return null; - } +const firstInteraction: AttributionModel = (interactions: Interaction[]): Interaction => { + if (interactions.length === 0) { + return null; + } - const filteredInteractions = interactions.filter((interaction) => !interaction.excluded); + const filteredInteractions = interactions.filter((interaction) => !interaction.excluded); - // If all we had were excluded interactions we return the first one as it's better than nothing - return filteredInteractions.shift() || interactions.shift(); - } + // If all we had were excluded interactions we return the first one as it's better than nothing + return filteredInteractions.shift() || interactions.shift(); } + +export default firstInteraction; diff --git a/src/AttributionModels/LastInteraction.ts b/src/AttributionModels/LastInteraction.ts index 371a2a0..5a784b1 100644 --- a/src/AttributionModels/LastInteraction.ts +++ b/src/AttributionModels/LastInteraction.ts @@ -1,4 +1,4 @@ -import { AttributionModel, Interaction } from '../../types'; +import { AttributionModel, Interaction } from '../types'; /** * This implements the "last interaction" attribution model @@ -6,11 +6,11 @@ import { AttributionModel, Interaction } from '../../types'; * * Since only one interaction is returned, it is not weighted */ -export default class LastInteraction implements AttributionModel { - public attribute(interactions: Interaction[]): Interaction { - const includedInteractions = interactions.filter((interaction) => !interaction.excluded); +const lastInteraction: AttributionModel = (interactions: Interaction[]): Interaction => { + const includedInteractions = interactions.filter((interaction) => !interaction.excluded); - // Interactions are logged in order of occurrence, so we simply need to return the last one - return includedInteractions.pop() ?? null; - } + // Interactions are logged in order of occurrence, so we simply need to return the last one + return includedInteractions.pop() ?? null; } + +export default lastInteraction; diff --git a/src/AttributionModels/LastNonDirectInteraction.ts b/src/AttributionModels/LastNonDirectInteraction.ts index 8861f61..8cd42d6 100644 --- a/src/AttributionModels/LastNonDirectInteraction.ts +++ b/src/AttributionModels/LastNonDirectInteraction.ts @@ -1,4 +1,4 @@ -import { AttributionModel, Interaction } from '../../types'; +import { AttributionModel, Interaction } from '../types'; /** * This implements the "last non-direct interaction" attribution model @@ -7,20 +7,20 @@ import { AttributionModel, Interaction } from '../../types'; * * Since only one interaction is returned, it is not weighted */ -export default class LastNonDirectInteraction implements AttributionModel { - public attribute(interactions: Interaction[]): Interaction { - if (interactions.length === 0) { - return null; - } +const lastNonDirectInteraction: AttributionModel = (interactions: Interaction[]): Interaction => { + if (interactions.length === 0) { + return null; + } - const nonExcludedInteractions = interactions.filter((interaction) => !interaction.excluded); - const nonExcludedNonDirectInteractions = nonExcludedInteractions.filter((interaction) => !interaction.direct); + const nonExcludedInteractions = interactions.filter((interaction) => !interaction.excluded); + const nonExcludedNonDirectInteractions = nonExcludedInteractions.filter((interaction) => !interaction.direct); - // First, we attempt to return the last non-excluded non-direct interaction - // Then if all we had were excluded and/or direct interactions we attempt to return the last non-excluded direct interaction - // Then if all we had were excluded interactions we return the last one as it's better than nothing - return nonExcludedNonDirectInteractions.pop() - || nonExcludedInteractions.pop() - || interactions.pop(); - } + // First, we attempt to return the last non-excluded non-direct interaction + // Then if all we had were excluded and/or direct interactions we attempt to return the last non-excluded direct interaction + // Then if all we had were excluded interactions we return the last one as it's better than nothing + return nonExcludedNonDirectInteractions.pop() + || nonExcludedInteractions.pop() + || interactions.pop(); } + +export default lastNonDirectInteraction; diff --git a/src/AttributionModels/Linear.ts b/src/AttributionModels/Linear.ts index 8ac9580..9155ad4 100644 --- a/src/AttributionModels/Linear.ts +++ b/src/AttributionModels/Linear.ts @@ -1,27 +1,27 @@ -import { AttributionModel, Interaction, WeightedInteraction } from '../../types'; +import { AttributionModel, Interaction, WeightedInteraction } from '../types'; /** * This implements the "linear" attribution model * which equally distributes the attribution over all interactions */ -export default class Linear implements AttributionModel { - public attribute(interactions: Interaction[]): WeightedInteraction[] { - if (interactions.length === 0) { - return []; - } - - let includedInteractions = interactions.filter((interaction) => !interaction.excluded) +const linear: AttributionModel = (interactions: Interaction[]): WeightedInteraction[] => { + if (interactions.length === 0) { + return []; + } - // If all our interactions are excluded, ignore the exclusions anyway - if (includedInteractions.length === 0) { - includedInteractions = interactions; - } + let includedInteractions = interactions.filter((interaction) => !interaction.excluded) - return includedInteractions.map((interaction) => { - return { - ...interaction, - weight: 1 / includedInteractions.length, - } - }); + // If all our interactions are excluded, ignore the exclusions anyway + if (includedInteractions.length === 0) { + includedInteractions = interactions; } + + return includedInteractions.map((interaction) => { + return { + ...interaction, + weight: 1 / includedInteractions.length, + } + }); } + +export default linear; diff --git a/src/AttributionModels/PositionBased.ts b/src/AttributionModels/PositionBased.ts index 33568ad..9df6416 100644 --- a/src/AttributionModels/PositionBased.ts +++ b/src/AttributionModels/PositionBased.ts @@ -1,4 +1,4 @@ -import { AttributionModel, Interaction, WeightedInteraction } from '../../types'; +import { AttributionModel, Interaction, WeightedInteraction } from '../types'; /** * This implements the "position based" attribution model @@ -7,46 +7,44 @@ import { AttributionModel, Interaction, WeightedInteraction } from '../../types' * If there are 2 interactions the first and last interactions will both get 50% of the attribution, * and if there is only 1 interaction it will of course receive 100% of the attribution. */ -export default class PositionBased implements AttributionModel { - - - public attribute(interactions: Interaction[]): WeightedInteraction[] { - if (interactions.length === 0) { - return []; - } - - let remainingInteractions = interactions.filter((interaction) => ! interaction.excluded); +const positionBased: AttributionModel = (interactions: Interaction[]): WeightedInteraction[] => { + if (interactions.length === 0) { + return []; + } - // If all interactions were excluded, ignore the exclusions - if (remainingInteractions.length === 0) { - remainingInteractions = interactions; - } + let remainingInteractions = interactions.filter((interaction) => !interaction.excluded); - const firstInteraction = remainingInteractions.shift(); - const lastInteraction = remainingInteractions.pop(); + // If all interactions were excluded, ignore the exclusions + if (remainingInteractions.length === 0) { + remainingInteractions = interactions; + } - // If there is only 1 interaction, attribute 100% to it - if (! lastInteraction) { - return [{...firstInteraction, weight: 1}]; - } + const firstInteraction = remainingInteractions.shift(); + const lastInteraction = remainingInteractions.pop(); - // If there are only two interactions, attribute 50% to both - if (remainingInteractions.length === 0) { - return [ - {...firstInteraction, weight: 0.5}, - {...lastInteraction, weight: 0.5}, - ]; - } + // If there is only 1 interaction, attribute 100% to it + if (!lastInteraction) { + return [{...firstInteraction, weight: 1}]; + } + // If there are only two interactions, attribute 50% to both + if (remainingInteractions.length === 0) { return [ - {...firstInteraction, weight: 0.4,}, - ...remainingInteractions.map((interaction): WeightedInteraction => { - return { - ...interaction, - weight: 0.2 / remainingInteractions.length, - }; - }), - {...lastInteraction, weight: 0.4}, + {...firstInteraction, weight: 0.5}, + {...lastInteraction, weight: 0.5}, ]; } + + return [ + {...firstInteraction, weight: 0.4,}, + ...remainingInteractions.map((interaction): WeightedInteraction => { + return { + ...interaction, + weight: 0.2 / remainingInteractions.length, + }; + }), + {...lastInteraction, weight: 0.4}, + ]; } + +export default positionBased; diff --git a/src/InteractionLogger.ts b/src/InteractionLogger.ts index 79b7a40..ef95730 100644 --- a/src/InteractionLogger.ts +++ b/src/InteractionLogger.ts @@ -1,4 +1,4 @@ -import { InteractionMiddleware, Interaction } from '../types'; +import { InteractionMiddleware, Interaction } from './types'; export default class InteractionLogger { private static readonly logStorageKey = 'ja_interaction_log'; diff --git a/src/InteractionMiddlewares/FacebookAdsMiddleware.ts b/src/InteractionMiddlewares/FacebookAds.ts similarity index 76% rename from src/InteractionMiddlewares/FacebookAdsMiddleware.ts rename to src/InteractionMiddlewares/FacebookAds.ts index 07e372d..920f6c6 100644 --- a/src/InteractionMiddlewares/FacebookAdsMiddleware.ts +++ b/src/InteractionMiddlewares/FacebookAds.ts @@ -1,6 +1,6 @@ -import { InteractionMiddleware, Interaction } from '../../types'; +import { InteractionMiddleware, Interaction } from '../types'; -export const FacebookAdsMiddleware: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { +const facebookAds: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { // If it is already attributed to something just return that if (currentInteraction.source && currentInteraction.medium) { return currentInteraction; @@ -24,3 +24,5 @@ export const FacebookAdsMiddleware: InteractionMiddleware = (currentInteraction: return interaction; } + +export default facebookAds; diff --git a/src/InteractionMiddlewares/GoogleAdsMiddleware.ts b/src/InteractionMiddlewares/GoogleAds.ts similarity index 76% rename from src/InteractionMiddlewares/GoogleAdsMiddleware.ts rename to src/InteractionMiddlewares/GoogleAds.ts index 16433c2..a08225a 100644 --- a/src/InteractionMiddlewares/GoogleAdsMiddleware.ts +++ b/src/InteractionMiddlewares/GoogleAds.ts @@ -1,6 +1,6 @@ -import { InteractionMiddleware, Interaction } from '../../types'; +import { InteractionMiddleware, Interaction } from '../types'; -export const GoogleAdsMiddleware: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { +const googleAds: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { // If it is already attributed to something just return that if (currentInteraction.source && currentInteraction.medium) { return currentInteraction; @@ -24,3 +24,5 @@ export const GoogleAdsMiddleware: InteractionMiddleware = (currentInteraction: I return interaction; } + +export default googleAds; diff --git a/src/InteractionMiddlewares/RefMiddleware.ts b/src/InteractionMiddlewares/Ref.ts similarity index 78% rename from src/InteractionMiddlewares/RefMiddleware.ts rename to src/InteractionMiddlewares/Ref.ts index df3ae16..ecf5d00 100644 --- a/src/InteractionMiddlewares/RefMiddleware.ts +++ b/src/InteractionMiddlewares/Ref.ts @@ -1,9 +1,9 @@ -import { InteractionMiddleware, Interaction } from '../../types'; +import { InteractionMiddleware, Interaction } from '../types'; /** * Turns URLs such as example.com?ref=foobar into referrals */ -export const RefMiddleware: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { +const ref: InteractionMiddleware = (currentInteraction: Interaction): Interaction => { // If it is already attributed to something just return that if (currentInteraction.source && currentInteraction.medium) { return currentInteraction; @@ -26,3 +26,5 @@ export const RefMiddleware: InteractionMiddleware = (currentInteraction: Interac return interaction; } + +export default ref; diff --git a/src/distributeValue.ts b/src/distributeValue.ts index 56004db..5eb6653 100644 --- a/src/distributeValue.ts +++ b/src/distributeValue.ts @@ -1,4 +1,4 @@ -import { WeightedInteraction } from '../types'; +import { WeightedInteraction } from './types'; /** * Distributes a value over a list of weighted interactions, will overwrite previous values. diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..70f5b99 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,10 @@ +export { default as InteractionLogger } from './InteractionLogger'; +export { default as distributeValue } from './distributeValue'; +export { default as googleAds } from './InteractionMiddlewares/GoogleAds'; +export { default as facebookAds } from './InteractionMiddlewares/FacebookAds'; +export { default as ref } from './InteractionMiddlewares/Ref'; +export { default as lastInteraction } from './AttributionModels/LastInteraction'; +export { default as firstInteraction } from './AttributionModels/FirstInteraction'; +export { default as lastNonDirectInteraction } from './AttributionModels/LastNonDirectInteraction'; +export { default as linear } from './AttributionModels/Linear'; +export { default as positionBased } from './AttributionModels/PositionBased'; diff --git a/types.ts b/src/types.ts similarity index 94% rename from types.ts rename to src/types.ts index 28e0818..3ba783f 100644 --- a/types.ts +++ b/src/types.ts @@ -41,8 +41,6 @@ export interface WeightedInteraction extends Interaction { value?: number; } -export interface AttributionModel { - attribute(attributionLog: Interaction[]): Interaction|WeightedInteraction[]|null; -} +export type AttributionModel = (attributionLog: Interaction[]) => Interaction|WeightedInteraction[]|null; export type InteractionMiddleware = (currentInteraction: Interaction, url?: URL, referrer?: URL) => Interaction; diff --git a/tests/AttributionModels/FirstInteraction.test.ts b/tests/AttributionModels/FirstInteraction.test.ts index 1680ecb..9396b3d 100644 --- a/tests/AttributionModels/FirstInteraction.test.ts +++ b/tests/AttributionModels/FirstInteraction.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import FirstInteraction from '../../src/AttributionModels/FirstInteraction'; +import { Interaction } from '../../src/types'; +import firstInteraction from '../../src/AttributionModels/FirstInteraction'; test.each([ [ @@ -66,8 +66,7 @@ test.each([ {direct: true, excluded: true}, ], ])('it returns the first non-excluded interaction', (interactions: Interaction[], expectedAttribution: Interaction) => { - const firstInteraction = new FirstInteraction(); - const attribution = firstInteraction.attribute(interactions); + const attribution = firstInteraction(interactions); expect(attribution).toEqual(expectedAttribution); }); diff --git a/tests/AttributionModels/LastInteraction.test.ts b/tests/AttributionModels/LastInteraction.test.ts index 284b098..7892df1 100644 --- a/tests/AttributionModels/LastInteraction.test.ts +++ b/tests/AttributionModels/LastInteraction.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import LastInteraction from '../../src/AttributionModels/LastInteraction'; +import { Interaction } from '../../src/types'; +import lastInteraction from '../../src/AttributionModels/LastInteraction'; test.each([ [ @@ -38,8 +38,7 @@ test.each([ ], // @ts-ignore ])('it returns the last non-excluded interaction', (interactions: Interaction[], expectedAttribution: Interaction) => { - const lastInteraction = new LastInteraction(); - const attribution = lastInteraction.attribute(interactions); + const attribution = lastInteraction(interactions); expect(attribution).toEqual(expectedAttribution); }); diff --git a/tests/AttributionModels/LastNonDirectInteraction.test.ts b/tests/AttributionModels/LastNonDirectInteraction.test.ts index de99c43..f70a0c6 100644 --- a/tests/AttributionModels/LastNonDirectInteraction.test.ts +++ b/tests/AttributionModels/LastNonDirectInteraction.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import LastNonDirectInteraction from '../../src/AttributionModels/LastNonDirectInteraction'; +import { Interaction } from '../../src/types'; +import lastNonDirectInteraction from '../../src/AttributionModels/LastNonDirectInteraction'; test.each([ [ @@ -65,8 +65,7 @@ test.each([ {source: 'test', medium: 'test', excluded: true}, ], ])('it returns the last non-excluded non-direct interaction', (interactions: Interaction[], expectedAttribution: Interaction) => { - const lastNonDirectInteraction = new LastNonDirectInteraction(); - const attribution = lastNonDirectInteraction.attribute(interactions); + const attribution = lastNonDirectInteraction(interactions); expect(attribution).toEqual(expectedAttribution); }); diff --git a/tests/AttributionModels/Linear.test.ts b/tests/AttributionModels/Linear.test.ts index 5a7abe0..5a4d099 100644 --- a/tests/AttributionModels/Linear.test.ts +++ b/tests/AttributionModels/Linear.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction, WeightedInteraction } from '../../types'; -import Linear from '../../src/AttributionModels/Linear'; +import { Interaction, WeightedInteraction } from '../../src/types'; +import linear from '../../src/AttributionModels/Linear'; test.each([ [ @@ -94,8 +94,7 @@ test.each([ ], ], ])('it returns the correct attribution based on non-excluded interactions', (interactions: Interaction[], expectedAttributions: WeightedInteraction[]) => { - const linear = new Linear(); - const attributions = linear.attribute(interactions); + const attributions = linear(interactions); expect(attributions).toEqual(expectedAttributions); }); diff --git a/tests/AttributionModels/PositionBased.test.ts b/tests/AttributionModels/PositionBased.test.ts index b84c8d2..9664be5 100644 --- a/tests/AttributionModels/PositionBased.test.ts +++ b/tests/AttributionModels/PositionBased.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction, WeightedInteraction } from '../../types'; -import PositionBased from '../../src/AttributionModels/PositionBased'; +import { Interaction, WeightedInteraction } from '../../src/types'; +import positionBased from '../../src/AttributionModels/PositionBased'; test.each([ [ @@ -110,8 +110,7 @@ test.each([ ], ], ])('it returns the correct attribution based', (interactions: Interaction[], expectedAttributions: WeightedInteraction[]) => { - const positionBased = new PositionBased(); - const attributions = positionBased.attribute(interactions); + const attributions = positionBased(interactions); expect(attributions).toEqual(expectedAttributions); }); diff --git a/tests/InteractionLogger.test.ts b/tests/InteractionLogger.test.ts index db57a3e..ca60bb9 100644 --- a/tests/InteractionLogger.test.ts +++ b/tests/InteractionLogger.test.ts @@ -1,6 +1,6 @@ import InteractionLogger from '../src/InteractionLogger'; import { expect, jest, test } from '@jest/globals'; -import { Interaction } from '../types'; +import { Interaction } from '../src/types'; import MemoryStorage from './fixtures/MemoryStorage'; import { TestMiddleware } from './fixtures/TestMiddleware'; diff --git a/tests/InteractionMiddlewares/FacebookAdsMiddleware.test.ts b/tests/InteractionMiddlewares/FacebookAdsMiddleware.test.ts index 723d6fe..3066ede 100644 --- a/tests/InteractionMiddlewares/FacebookAdsMiddleware.test.ts +++ b/tests/InteractionMiddlewares/FacebookAdsMiddleware.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import { FacebookAdsMiddleware } from '../../src/InteractionMiddlewares/FacebookAdsMiddleware'; +import { Interaction } from '../../src/types'; +import facebookAdsMiddleware from '../../src/InteractionMiddlewares/FacebookAds'; test.each([ // Parameter should be used to determine facebook / cpc @@ -34,5 +34,5 @@ test.each([ {parameters: {gclid: 'abc123'}}, ], ])('it attributes Facebook Ads', (currentInteraction: Interaction, expectedInteraction: Interaction ) => { - expect(FacebookAdsMiddleware(currentInteraction)).toEqual(expectedInteraction); + expect(facebookAdsMiddleware(currentInteraction)).toEqual(expectedInteraction); }); diff --git a/tests/InteractionMiddlewares/GoogleAdsMiddleware.test.ts b/tests/InteractionMiddlewares/GoogleAdsMiddleware.test.ts index ed27500..bf29d97 100644 --- a/tests/InteractionMiddlewares/GoogleAdsMiddleware.test.ts +++ b/tests/InteractionMiddlewares/GoogleAdsMiddleware.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import { GoogleAdsMiddleware } from '../../src/InteractionMiddlewares/GoogleAdsMiddleware'; +import { Interaction } from '../../src/types'; +import googleAds from '../../src/InteractionMiddlewares/GoogleAds'; test.each([ // Parameter should be used to determine google / cpc @@ -34,5 +34,5 @@ test.each([ {parameters: {fbclid: 'abc123'}}, ], ])('it attributes Google Ads', (currentInteraction: Interaction, expectedInteraction: Interaction ) => { - expect(GoogleAdsMiddleware(currentInteraction)).toEqual(expectedInteraction); + expect(googleAds(currentInteraction)).toEqual(expectedInteraction); }); diff --git a/tests/InteractionMiddlewares/RefMiddleware.test.ts b/tests/InteractionMiddlewares/RefMiddleware.test.ts index 7ee257e..6fea346 100644 --- a/tests/InteractionMiddlewares/RefMiddleware.test.ts +++ b/tests/InteractionMiddlewares/RefMiddleware.test.ts @@ -1,6 +1,6 @@ import { expect, test } from '@jest/globals'; -import { Interaction } from '../../types'; -import { RefMiddleware } from '../../src/InteractionMiddlewares/RefMiddleware'; +import { Interaction } from '../../src/types'; +import ref from '../../src/InteractionMiddlewares/Ref'; test.each([ // Parameter should be used to determine referral @@ -34,5 +34,5 @@ test.each([ {parameters: {gclid: 'abc123'}}, ], ])('it attributes ref referrals', (currentInteraction: Interaction, expectedInteraction: Interaction) => { - expect(RefMiddleware(currentInteraction)).toEqual(expectedInteraction); + expect(ref(currentInteraction)).toEqual(expectedInteraction); }); diff --git a/tests/distributeValue.test.ts b/tests/distributeValue.test.ts index 00f13ba..d60d3d4 100644 --- a/tests/distributeValue.test.ts +++ b/tests/distributeValue.test.ts @@ -1,5 +1,5 @@ import { expect, test } from '@jest/globals'; -import { WeightedInteraction } from '../types'; +import { WeightedInteraction } from '../src/types'; import distributeValue from '../src/distributeValue'; test.each([ diff --git a/tests/fixtures/TestMiddleware.ts b/tests/fixtures/TestMiddleware.ts index b642d16..0497066 100644 --- a/tests/fixtures/TestMiddleware.ts +++ b/tests/fixtures/TestMiddleware.ts @@ -1,4 +1,4 @@ -import { InteractionMiddleware } from '../../types'; +import { InteractionMiddleware } from '../../src/types'; export const TestMiddleware: InteractionMiddleware = (currentInteraction, url, referrer) => { const {test, ...additionalParameters} = currentInteraction.parameters ?? {}; diff --git a/tsconfig.json b/tsconfig.json index 33f5c24..0feed3f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "include": [ - "**/*.ts", + "src/**/*.ts", + "src/index.ts" ], "exclude": [ "node_modules", @@ -11,7 +12,10 @@ "DOM" ], "esModuleInterop": true, - "noEmit": true + "declaration": true, + "emitDeclarationOnly": true, + "declarationMap": true, + "declarationDir": "dist", + "rootDir": "src" } } -