Skip to content

Commit

Permalink
feat(core): introduce metadata (#774)
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahdayan authored Oct 19, 2021
1 parent 798547f commit 79212d6
Show file tree
Hide file tree
Showing 10 changed files with 373 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module.exports = {
'@typescript-eslint/camelcase': [
ERROR,
{
allow: ['__autocomplete_'],
allow: ['__autocomplete_', 'aa_core', 'aa_js'],
},
],
// Useful to call functions like `nodeItem?.scrollIntoView()`.
Expand Down
4 changes: 2 additions & 2 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"files": [
{
"path": "packages/autocomplete-core/dist/umd/index.production.js",
"maxSize": "5.5 kB"
"maxSize": "5.75 kB"
},
{
"path": "packages/autocomplete-js/dist/umd/index.production.js",
"maxSize": "16 kB"
"maxSize": "16.25 kB"
},
{
"path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js",
Expand Down
169 changes: 169 additions & 0 deletions packages/autocomplete-core/src/__tests__/metadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { createAlgoliaInsightsPlugin } from '@algolia/autocomplete-plugin-algolia-insights';
import { noop, version } from '@algolia/autocomplete-shared';
import insightsClient from 'search-insights';

import { createPlayground, defer } from '../../../../test/utils';
import { createAutocomplete } from '../createAutocomplete';

beforeEach(() => {
document.head.innerHTML = '';
});

const algoliaCrawlerEnvironment = createEnvironmentWithUserAgent(
'Algolia Crawler 2.303.5'
);

describe('metadata', () => {
test('does not enable metadata with regular user agents', async () => {
createPlayground(createAutocomplete, {
environment: createEnvironmentWithUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0'
),
});

await defer(noop, 0);

expect(document.head).toMatchInlineSnapshot(`<head />`);
});

test('does not enable metadata with no window', async () => {
createPlayground(createAutocomplete, {
environment: {},
});

await defer(noop, 0);

expect(document.head).toMatchInlineSnapshot(`<head />`);
});

test('enables metadata with Algolia Crawler user agents', async () => {
createPlayground(createAutocomplete, {
environment: algoliaCrawlerEnvironment,
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
)
).toEqual({
options: { 'autocomplete-core': ['environment'] },
plugins: [],
ua: [{ segment: 'autocomplete-core', version }],
});
});

test('exposes user agents', async () => {
createPlayground(createAutocomplete, {
environment: algoliaCrawlerEnvironment,
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
).ua
).toEqual([{ segment: 'autocomplete-core', version }]);
});

test('exposes passed options', async () => {
createPlayground(createAutocomplete, {
openOnFocus: true,
placeholder: 'Start searching',
environment: algoliaCrawlerEnvironment,
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
).options
).toEqual({
'autocomplete-core': ['openOnFocus', 'placeholder', 'environment'],
});
});

test('exposes passed plugins and their passed options', async () => {
const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({
insightsClient,
onItemsChange: noop,
});

createPlayground(createAutocomplete, {
environment: algoliaCrawlerEnvironment,
plugins: [algoliaInsightsPlugin],
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
).plugins
).toEqual([
{
name: 'aa.algoliaInsightsPlugin',
options: ['insightsClient', 'onItemsChange'],
},
]);
});

test('exposes custom plugins', async () => {
createPlayground(createAutocomplete, {
environment: algoliaCrawlerEnvironment,
plugins: [
{
name: 'customPlugin',
},
],
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
).plugins
).toEqual([{ name: 'customPlugin', options: [] }]);
});

test('does not set a fallback name for unnamed custom plugins', async () => {
createPlayground(createAutocomplete, {
environment: algoliaCrawlerEnvironment,
plugins: [{}],
});

await defer(noop, 0);

expect(
JSON.parse(
document.head.querySelector<HTMLMetaElement>(
'meta[name="algolia:metadata"]'
).content
).plugins
).toEqual([{ options: [] }]);
});
});

function createEnvironmentWithUserAgent(userAgent: string) {
return {
...global,
navigator: {
...global.navigator,
userAgent,
},
};
}
10 changes: 8 additions & 2 deletions packages/autocomplete-core/src/createAutocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createStore } from './createStore';
import { getAutocompleteSetters } from './getAutocompleteSetters';
import { getDefaultProps } from './getDefaultProps';
import { getPropGetters } from './getPropGetters';
import { getMetadata, injectMetadata } from './metadata';
import { onInput } from './onInput';
import { stateReducer } from './stateReducer';
import {
Expand All @@ -12,7 +13,7 @@ import {
AutocompleteSubscribers,
} from './types';

interface AutocompleteOptions<TItem extends BaseItem>
export interface AutocompleteOptionsWithMetadata<TItem extends BaseItem>
extends AutocompleteCoreOptions<TItem> {
/**
* @internal
Expand All @@ -26,7 +27,7 @@ export function createAutocomplete<
TMouseEvent = MouseEvent,
TKeyboardEvent = KeyboardEvent
>(
options: AutocompleteOptions<TItem>
options: AutocompleteOptionsWithMetadata<TItem>
): AutocompleteApi<TItem, TEvent, TMouseEvent, TKeyboardEvent> {
checkOptions(options);

Expand Down Expand Up @@ -71,6 +72,11 @@ export function createAutocomplete<
})
);

injectMetadata({
metadata: getMetadata({ plugins: props.plugins, options }),
environment: props.environment,
});

return {
refresh,
...propGetters,
Expand Down
80 changes: 80 additions & 0 deletions packages/autocomplete-core/src/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { UserAgent, userAgents } from '@algolia/autocomplete-shared';

import {
AutocompleteEnvironment,
AutocompleteOptions,
AutocompleteOptionsWithMetadata,
AutocompletePlugin,
BaseItem,
} from '.';

type AutocompleteMetadata = {
plugins: Array<{
name: string | undefined;
options: string[];
}>;
options: Record<string, string[]>;
ua: UserAgent[];
};

type GetMetadataParams<TItem extends BaseItem, TData = unknown> = {
plugins: Array<AutocompletePlugin<TItem, TData>>;
options: AutocompleteOptionsWithMetadata<TItem>;
};

export function getMetadata<TItem extends BaseItem, TData = unknown>({
plugins,
options,
}: GetMetadataParams<TItem, TData>) {
const optionsKey = ((options.__autocomplete_metadata
?.userAgents as UserAgent[]) || [])[0]?.segment;

const extraOptions = optionsKey
? {
[optionsKey]: Object.keys(
(options.__autocomplete_metadata
?.options as AutocompleteOptions<TItem>) || {}
),
}
: {};

return {
plugins: plugins.map((plugin) => ({
name: plugin.name,
options: Object.keys(plugin.__autocomplete_pluginOptions || []),
})),
options: {
'autocomplete-core': Object.keys(options),
...extraOptions,
},
ua: userAgents.concat(
(options.__autocomplete_metadata?.userAgents as any) || []
),
};
}

type InlineMetadataParams = {
metadata: AutocompleteMetadata;
environment: AutocompleteEnvironment;
};

export function injectMetadata({
metadata,
environment,
}: InlineMetadataParams) {
const isMetadataEnabled = environment.navigator?.userAgent.includes(
'Algolia Crawler'
);

if (isMetadataEnabled) {
const metadataContainer = environment.document.createElement('meta');
const headRef = environment.document.querySelector('head');

metadataContainer.name = 'algolia:metadata';

setTimeout(() => {
metadataContainer.content = JSON.stringify(metadata);
headRef!.appendChild(metadataContainer);
}, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export type AutocompleteEnvironment =
assign: Location['assign'];
};
open: Window['open'];
navigator: Window['navigator'];
};
Loading

0 comments on commit 79212d6

Please sign in to comment.