From ed036802e382306fab358ee84e0831e287476309 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 16 May 2025 13:16:45 +0300 Subject: [PATCH 01/13] Add script for manipulating and checking code samples, refactor code samples --- .code-samples.meilisearch.yaml | 1345 +++++++++++++++++------------ .gitignore | 1 + package.json | 8 +- scripts/code-samples.js | 17 + scripts/code-samples/from-yaml.js | 50 ++ scripts/code-samples/shared.js | 37 + scripts/code-samples/to-yaml.js | 73 ++ tsconfig.json | 8 +- yarn.lock | 5 + 9 files changed, 966 insertions(+), 578 deletions(-) create mode 100644 scripts/code-samples.js create mode 100644 scripts/code-samples/from-yaml.js create mode 100644 scripts/code-samples/shared.js create mode 100644 scripts/code-samples/to-yaml.js diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 5d4788ece..1c37ade72 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -1,514 +1,614 @@ # This code-samples file is used by the Meilisearch documentation # Every example written here will be automatically fetched by # the documentation on build -# You can read more on https://github.com/meilisearch/documentation/tree/master/.vuepress/code-samples +# You can read more at https://github.com/meilisearch/documentation --- synonyms_guide_1: |- - client.index('movies').updateSynonyms({ - 'great': ['fantastic'], - 'fantastic': ['great'] - }) + const _task = await _client + .index("movies") + .updateSynonyms({ + great: ["fantastic"], + fantastic: ["great"], + }) + .waitTask(); date_guide_index_1: |- - const games = require('./games.json') - client.index('games').addDocuments(games).then((res) => console.log(res)) + import games from "./games.json" with { type: "json" }; + const _task = await _client.index("games").addDocuments(games).waitTask(); date_guide_filterable_attributes_1: |- - client.index('games').updateFilterableAttributes(['release_timestamp']) + const _task = await _client + .index("games") + .updateFilterableAttributes(["release_timestamp"]) + .waitTask(); date_guide_filter_1: |- - client.index('games').search('', { - filter: 'release_timestamp >= 1514761200 AND release_timestamp < 1672527600' - }) + const _response = await _client.index("games").search("", { + filter: "release_timestamp >= 1514761200 AND release_timestamp < 1672527600", + }); date_guide_sortable_attributes_1: |- - client.index('games').updateSortableAttributes(['release_timestamp']) + const _task = await _client + .index("games") + .updateSortableAttributes(["release_timestamp"]) + .waitTask(); date_guide_sort_1: |- - client.index('games').search('', { - sort: ['release_timestamp:desc'], - }) + const _response = await _client.index("games").search("", { + sort: ["release_timestamp:desc"], + }); get_one_index_1: |- - client.index('movies').getRawInfo() + const _index = await _client.index("movies").getRawInfo(); list_all_indexes_1: |- - client.getIndexes({ limit: 3 }) + const _indexes = await _client.getIndexes({ limit: 3 }); create_an_index_1: |- - client.createIndex('movies', { primaryKey: 'id' }) + const _task = await _client + .createIndex("movies", { primaryKey: "id" }) + .waitTask(); update_an_index_1: |- - client.updateIndex('movies', { primaryKey: 'id' }) + const _task = _client.updateIndex("movies", { primaryKey: "id" }).waitTask(); delete_an_index_1: |- - client.deleteIndex('movies') + const _task = await _client.deleteIndex("movies").waitTask(); swap_indexes_1: |- - client.swapIndexes([ - { 'indexes': ['indexA', 'indexB'] }, - { 'indexes': ['indexX', 'indexY'] } - ]) + const _task = await _client + .swapIndexes([ + { indexes: ["indexA", "indexB"] }, + { indexes: ["indexX", "indexY"] }, + ]) + .waitTask(); get_one_document_1: |- - client - .index('movies') - .getDocument(25684, { fields: ['id', 'title', 'poster', 'release_date'] }) + const _documents = await _client + .index("movies") + .getDocument(25684, { fields: ["id", "title", "poster", "release_date"] }); get_documents_1: |- - client.index('movies').getDocuments({ + const _documents = await _client.index("movies").getDocuments({ limit: 2, - filter: 'genres = action' - }) + filter: "genres = action", + }); get_documents_post_1: |- - client.index('books').getDocuments({ - filter: '(rating > 3 AND (genres = Adventure OR genres = Fiction)) AND language = English', - fields: ['title', 'genres', 'rating', 'language'], - limit: 3 - }) + const _documents = await _client.index("books").getDocuments({ + filter: + "(rating > 3 AND (genres = Adventure OR genres = Fiction)) AND language = English", + fields: ["title", "genres", "rating", "language"], + limit: 3, + }); add_or_replace_documents_1: |- - client.index('movies').addDocuments([{ - id: 287947, - title: 'Shazam', - poster: 'https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg', - overview: 'A boy is given the ability to become an adult superhero in times of need with a single magic word.', - release_date: '2019-03-23' - }]) + const _task = await _client + .index("movies") + .addDocuments([ + { + id: 287947, + title: "Shazam", + poster: + "https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg", + overview: + "A boy is given the ability to become an adult superhero in times of need with a single magic word.", + release_date: "2019-03-23", + }, + ]) + .waitTask(); add_or_update_documents_1: |- - client.index('movies').updateDocuments([{ - id: 287947, - title: 'Shazam ⚡️', - genres: 'comedy' - }]) + const _task = await _client + .index("movies") + .updateDocuments([ + { + id: 287947, + title: "Shazam ⚡️", + genres: "comedy", + }, + ]) + .waitTask(); delete_all_documents_1: |- - client.index('movies').deleteAllDocuments() + const _task = await _client.index("movies").deleteAllDocuments().waitTask(); delete_one_document_1: |- - client.index('movies').deleteDocument(25684) + const _task = await _client.index("movies").deleteDocument(25684).waitTask(); delete_documents_by_batch_1: |- - client.index('movies').deleteDocuments([23488, 153738, 437035, 363869]) + const _task = await _client + .index("movies") + .deleteDocuments([23488, 153738, 437035, 363869]) + .waitTask(); delete_documents_by_filter_1: |- - client.index('movies').deleteDocuments({ - filter: 'genres = action OR genres = adventure' - }) + const _task = await _client + .index("movies") + .deleteDocuments({ + filter: "genres = action OR genres = adventure", + }) + .waitTask(); search_post_1: |- - client.index('movies').search('American ninja') + const _response = await _client.index("movies").search("American ninja"); search_get_1: |- - client.index('movies').searchGet('American ninja') + const _response = await _client.index("movies").searchGet("American ninja"); multi_search_1: |- - client.multiSearch({ queries: [ - { - indexUid: 'movies', - q: 'pooh', - limit: 5, - }, - { - indexUid: 'movies', - q: 'nemo', - limit: 5, - }, - { - indexUid: 'movie_ratings', - q: 'us', - }, - ]}) + const _response = await _client.multiSearch({ + queries: [ + { + indexUid: "movies", + q: "pooh", + limit: 5, + }, + { + indexUid: "movies", + q: "nemo", + limit: 5, + }, + { + indexUid: "movie_ratings", + q: "us", + }, + ], + }); get_all_tasks_1: |- - client.getTasks() + const _tasks = await _client.tasks.getTasks(); get_task_1: |- - client.getTask(1) + const _task = await _client.tasks.getTask(1); async_guide_filter_by_date_1: |- - client.getTasks({ afterEnqueuedAt: '2020-10-11T11:49:53.000Z' }) + const _tasks = await _client.tasks.getTasks({ + afterEnqueuedAt: "2020-10-11T11:49:53.000Z", + }); async_guide_multiple_filters_1: |- - client.getTasks({ - indexUids: ['movies'], - types: ['documentAdditionOrUpdate','documentDeletion'], - statuses: ['processing'] - }) + const _tasks = await _client.tasks.getTasks({ + indexUids: ["movies"], + types: ["documentAdditionOrUpdate", "documentDeletion"], + statuses: ["processing"], + }); async_guide_filter_by_ids_1: |- - client.getTasks({ uids: [5, 10, 13] }) + const _tasks = await _client.tasks.getTasks({ uids: [5, 10, 13] }); async_guide_filter_by_statuses_1: |- - client.getTasks({ statuses: ['failed', 'canceled'] }) + const _tasks = await _client.tasks.getTasks({ + statuses: ["failed", "canceled"], + }); async_guide_filter_by_types_1: |- - client.getTasks({ types: ['dumpCreation', 'indexSwap'] }) + const _tasks = await _client.tasks.getTasks({ + types: ["dumpCreation", "indexSwap"], + }); async_guide_filter_by_index_uids_1: |- - client.getTasks({ indexUids: ['movies'] }) + const _tasks = await _client.tasks.getTasks({ indexUids: ["movies"] }); get_all_tasks_paginating_1: |- - client.getTasks({ limit: 2, from: 10 }) + const _tasks = await _client.tasks.getTasks({ limit: 2, from: 10 }); get_all_tasks_paginating_2: |- - client.getTasks({ limit: 2, from: 8 }) + const _tasks = await _client.tasks.getTasks({ limit: 2, from: 8 }); async_guide_canceled_by_1: |- - client.getTasks({ canceledBy: [9, 15] }) + const _tasks = await _client.tasks.getTasks({ canceledBy: [9, 15] }); delete_tasks_1: |- - client.deleteTasks({ uids: [1, 2] }) + const _task = await _client.tasks.deleteTasks({ uids: [1, 2] }).waitTask(); cancel_tasks_1: |- - client.cancelTasks({ uids: [1, 2] }) + const _task = await _client.tasks.cancelTasks({ uids: [1, 2] }).waitTask(); get_one_key_1: |- - client.getKey('6062abda-a5aa-4414-ac91-ecd7944c0f8d') + const _key = await _client.getKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); get_all_keys_1: |- - client.getKeys({ limit: 3 }) + const _keys = await _client.getKeys({ limit: 3 }); create_a_key_1: |- - client.createKey({ - description: 'Add documents: Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: '2021-11-13T00:00:00Z' - }) + const _key = await _client.createKey({ + description: "Add documents: Products API key", + actions: ["documents.add"], + indexes: ["products"], + expiresAt: new Date("2021-11-13T00:00:00Z"), + }); update_a_key_1: |- - client.updateKey('6062abda-a5aa-4414-ac91-ecd7944c0f8d', { - name: 'Products/Reviews API key', - description: 'Manage documents: Products/Reviews API key', - }) + const _key = await _client.updateKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d", { + name: "Products/Reviews API key", + description: "Manage documents: Products/Reviews API key", + }); delete_a_key_1: |- - client.deleteKey('6062abda-a5aa-4414-ac91-ecd7944c0f8d') + await _client.deleteKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); get_settings_1: |- - client.index('movies').getSettings() + const _settings = await _client.index("movies").getSettings(); update_settings_1: |- - client.index('movies').updateSettings({ + const _task = await _client + .index("movies") + .updateSettings({ rankingRules: [ - 'words', - 'typo', - 'proximity', - 'attribute', - 'sort', - 'exactness', - 'release_date:desc', - 'rank:desc' - ], - distinctAttribute: 'movie_id', - searchableAttributes: [ - 'title', - 'overview', - 'genres' - ], - displayedAttributes: [ - 'title', - 'overview', - 'genres', - 'release_date' - ], - stopWords: [ - 'the', - 'a', - 'an' - ], - sortableAttributes: [ - 'title', - 'release_date' + "words", + "typo", + "proximity", + "attribute", + "sort", + "exactness", + "release_date:desc", + "rank:desc", ], + distinctAttribute: "movie_id", + searchableAttributes: ["title", "overview", "genres"], + displayedAttributes: ["title", "overview", "genres", "release_date"], + stopWords: ["the", "a", "an"], + sortableAttributes: ["title", "release_date"], synonyms: { - 'wolverine': ['xmen', 'logan'], - 'logan': ['wolverine'] + wolverine: ["xmen", "logan"], + logan: ["wolverine"], }, typoTolerance: { - 'minWordSizeForTypos': { - 'oneTypo': 8, - 'twoTypos': 10 - }, - 'disableOnAttributes': [ - 'title' - ] + minWordSizeForTypos: { + oneTypo: 8, + twoTypos: 10, + }, + disableOnAttributes: ["title"], }, pagination: { - maxTotalHits: 5000 + maxTotalHits: 5000, }, faceting: { - maxValuesPerFacet: 200 + maxValuesPerFacet: 200, }, - searchCutoffMs: 150 - }) + searchCutoffMs: 150, + }) + .waitTask(); reset_settings_1: |- - client.index('movies').resetSettings() + const _task = await _client.index("movies").resetSettings().waitTask(); get_synonyms_1: |- - client.index('movies').getSynonyms() + const _synonyms = await _client.index("movies").getSynonyms(); update_synonyms_1: |- - client.index('movies').updateSynonyms({ - wolverine: ['xmen', 'logan'], - logan: ['wolverine', 'xmen'], - wow: ['world of warcraft'] - }) + const _task = await _client + .index("movies") + .updateSynonyms({ + wolverine: ["xmen", "logan"], + logan: ["wolverine", "xmen"], + wow: ["world of warcraft"], + }) + .waitTask(); reset_synonyms_1: |- - client.index('movies').resetSynonyms() + const _task = await _client.index("movies").resetSynonyms().waitTask(); get_stop_words_1: |- - client.index('movies').getStopWords() + const _stopWords = await _client.index("movies").getStopWords(); update_stop_words_1: |- - client.index('movies').updateStopWords(['of', 'the', 'to']) + const _task = await _client + .index("movies") + .updateStopWords(["of", "the", "to"]) + .waitTask(); reset_stop_words_1: |- - client.index('movies').resetStopWords() + const _task = await _client.index("movies").resetStopWords().waitTask(); get_ranking_rules_1: |- - client.index('movies').getRankingRules() + const _rankingRules = await _client.index("movies").getRankingRules(); update_ranking_rules_1: |- - client.index('movies').updateRankingRules([ - 'words', - 'typo', - 'proximity', - 'attribute', - 'sort', - 'exactness', - 'release_date:asc', - 'rank:desc' - ]) + const _task = await _client + .index("movies") + .updateRankingRules([ + "words", + "typo", + "proximity", + "attribute", + "sort", + "exactness", + "release_date:asc", + "rank:desc", + ]) + .waitTask(); reset_ranking_rules_1: |- - client.index('movies').resetRankingRules() + const _task = await _client.index("movies").resetRankingRules().waitTask(); get_distinct_attribute_1: |- - client.index('shoes').getDistinctAttribute() + const _distinctAttribute = await _client.index("shoes").getDistinctAttribute(); update_distinct_attribute_1: |- - client.index('shoes').updateDistinctAttribute('skuid') + const _task = await _client + .index("shoes") + .updateDistinctAttribute("skuid") + .waitTask(); reset_distinct_attribute_1: |- - client.index('shoes').resetDistinctAttribute() + const _task = await _client.index("shoes").resetDistinctAttribute().waitTask(); get_searchable_attributes_1: |- - client.index('movies').getSearchableAttributes() + const _searchableAttributes = await _client + .index("movies") + .getSearchableAttributes(); update_searchable_attributes_1: |- - client.index('movies').updateSearchableAttributes([ - 'title', - 'overview', - 'genres' - ]) + const _task = await _client + .index("movies") + .updateSearchableAttributes(["title", "overview", "genres"]) + .waitTask(); reset_searchable_attributes_1: |- - client.index('movies').resetSearchableAttributes() + const _task = await _client + .index("movies") + .resetSearchableAttributes() + .waitTask(); get_displayed_attributes_1: |- - client.index('movies').getDisplayedAttributes() + const _displayedAttributes = await _client + .index("movies") + .getDisplayedAttributes(); update_displayed_attributes_1: |- - client.index('movies').updateDisplayedAttributes([ - 'title', - 'overview', - 'genres', - 'release_date' - ]) + const _task = await _client + .index("movies") + .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]) + .waitTask(); reset_displayed_attributes_1: |- - client.index('movies').resetDisplayedAttributes() + const _task = await _client + .index("movies") + .resetDisplayedAttributes() + .waitTask(); get_typo_tolerance_1: |- - client.index('books').getTypoTolerance() + const _typoTolerance = await _client.index("books").getTypoTolerance(); update_typo_tolerance_1: |- - client.index('books').updateTypoTolerance({ - minWordSizeForTypos: { + const _task = await _client + .index("books") + .updateTypoTolerance({ + minWordSizeForTypos: { oneTypo: 4, - twoTypos: 10 + twoTypos: 10, }, - disableOnAttributes: [ - 'title' - ] - }) + disableOnAttributes: ["title"], + }) + .waitTask(); reset_typo_tolerance_1: |- - client.index('books').resetTypoTolerance() + const _task = await _client.index("books").resetTypoTolerance().waitTask(); get_index_stats_1: |- - client.index('movies').getStats() + const _indexStats = await _client.index("movies").getStats(); get_indexes_stats_1: |- - client.getStats() + const _stats = await _client.getStats(); get_health_1: |- - client.health() + const _health = _client.health(); get_version_1: |- - client.getVersion() + const _version = await _client.getVersion(); distinct_attribute_guide_1: |- - client.index('jackets').updateDistinctAttribute('product_id') + const _task = await _client + .index("jackets") + .updateDistinctAttribute("product_id") + .waitTask(); field_properties_guide_searchable_1: |- - client.index('movies').updateSearchableAttributes([ - 'title', - 'overview', - 'genres', - ] - ) + const _task = await _client + .index("movies") + .updateSearchableAttributes(["title", "overview", "genres"]) + .waitTask(); field_properties_guide_displayed_1: |- - client.index('movies').updateDisplayedAttributes([ - 'title', - 'overview', - 'genres', - 'release_date', - ] - ) + const _task = await _client + .index("movies") + .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]) + .waitTask(); filtering_guide_1: |- - client.index('movie_ratings').search('Avengers', { - filter: 'release_date > 795484800' - }) + const _response = await _client.index("movie_ratings").search("Avengers", { + filter: "release_date > 795484800", + }); filtering_guide_2: |- - client.index('movie_ratings').search('Batman', { - filter: 'release_date > 795484800 AND (director = "Tim Burton" OR director = "Christopher Nolan")' - }) + const _response = await _client.index("movie_ratings").search("Batman", { + filter: + 'release_date > 795484800 AND (director = "Tim Burton" OR director = "Christopher Nolan")', + }); filtering_guide_3: |- - client.index('movie_ratings').search('Planet of the Apes', { - filter: "release_date > 1577884550 AND (NOT director = \"Tim Burton\")" - }) + const _response = await _client + .index("movie_ratings") + .search("Planet of the Apes", { + filter: 'release_date > 1577884550 AND (NOT director = "Tim Burton")', + }); filtering_guide_nested_1: |- - client.index('movie_ratings').search('thriller', { - filter: 'rating.users >= 90' - }) + const _response = await _client.index("movie_ratings").search("thriller", { + filter: "rating.users >= 90", + }); search_parameter_guide_query_1: |- - client.index('movies').search('shifu') + const _response = await _client.index("movies").search("shifu"); search_parameter_guide_offset_1: |- - client.index('movies').search('shifu', { - offset: 1 - }) + const _response = await _client.index("movies").search("shifu", { + offset: 1, + }); search_parameter_guide_limit_1: |- - client.index('movies').search('shifu', { - limit: 2 - }) + const _response = await _client.index("movies").search("shifu", { + limit: 2, + }); search_parameter_guide_retrieve_1: |- - client.index('movies').search('shifu', { - attributesToRetrieve: ['overview', 'title'] - }) + const _response = await _client.index("movies").search("shifu", { + attributesToRetrieve: ["overview", "title"], + }); search_parameter_guide_crop_1: |- - client.index('movies').search('shifu', { - attributesToCrop: ['overview'], - cropLength: 5 - }) + const _response = await _client.index("movies").search("shifu", { + attributesToCrop: ["overview"], + cropLength: 5, + }); search_parameter_guide_crop_marker_1: |- - client.index('movies').search('shifu', { - attributesToCrop: ['overview'], - cropMarker: '[…]' - }) + const _response = await _client.index("movies").search("shifu", { + attributesToCrop: ["overview"], + cropMarker: "[…]", + }); search_parameter_guide_highlight_1: |- - client.index('movies').search('winter feast', { - attributesToHighlight: ['overview'] - }) + const _response = await _client.index("movies").search("winter feast", { + attributesToHighlight: ["overview"], + }); search_parameter_guide_highlight_tag_1: |- - client.index('movies').search('winter feast', { - attributesToHighlight: ['overview'], + const _response = await _client.index("movies").search("winter feast", { + attributesToHighlight: ["overview"], highlightPreTag: '', - highlightPostTag: '' - }) + highlightPostTag: "", + }); search_parameter_guide_show_matches_position_1: |- - client.index('movies').search('winter feast', { - showMatchesPosition: true - }) + const _response = await _client.index("movies").search("winter feast", { + showMatchesPosition: true, + }); search_parameter_guide_matching_strategy_1: |- - client.index('movies').search('big fat liar', { - matchingStrategy: 'last' - }) + const _response = await _client.index("movies").search("big fat liar", { + matchingStrategy: "last", + }); search_parameter_guide_matching_strategy_2: |- - client.index('movies').search('big fat liar', { - matchingStrategy: 'all' - }) + const _response = await _client.index("movies").search("big fat liar", { + matchingStrategy: "all", + }); search_parameter_guide_hitsperpage_1: |- - client.index('movies').search('', { - hitsPerPage: 15 - }) + const _response = await _client.index("movies").search("", { + hitsPerPage: 15, + }); search_parameter_guide_page_1: |- - client.index('movies').search('', { - page: 2 - }) + const _response = await _client.index("movies").search("", { + page: 2, + }); search_parameter_guide_show_ranking_score_1: |- - client.index('movies').search('dragon', { - showRankingScore: true - }) + const _response = await _client.index("movies").search("dragon", { + showRankingScore: true, + }); search_parameter_guide_attributes_to_search_on_1: |- - client.index('movies').search('adventure', { - attributesToSearchOn: ['overview'] - }) + const _response = await _client.index("movies").search("adventure", { + attributesToSearchOn: ["overview"], + }); typo_tolerance_guide_1: |- - client.index('movies').updateTypoTolerance({ - enabled: false - }) + const _task = await _client + .index("movies") + .updateTypoTolerance({ + enabled: false, + }) + .waitTask(); typo_tolerance_guide_2: |- - client.index('movies').updateTypoTolerance({ - disableOnAttributes: ['title'] - }) + const _task = await _client + .index("movies") + .updateTypoTolerance({ + disableOnAttributes: ["title"], + }) + .waitTask(); typo_tolerance_guide_3: |- - client.index('movies').updateTypoTolerance({ - disableOnWords: ['shrek'] - }) + const _task = await _client + .index("movies") + .updateTypoTolerance({ + disableOnWords: ["shrek"], + }) + .waitTask(); typo_tolerance_guide_4: |- - client.index('movies').updateTypoTolerance({ - minWordSizeForTypos: { - oneTypo: 4, - twoTypos: 10 - } - }) + const _task = await _client + .index("movies") + .updateTypoTolerance({ + minWordSizeForTypos: { + oneTypo: 4, + twoTypos: 10, + }, + }) + .waitTask(); add_movies_json_1: |- - const movies = require('./movies.json') - client.index('movies').addDocuments(movies).then((res) => console.log(res)) + import movies from "./movies.json" with { type: "json" }; + const task = await _client.index("movies").addDocuments(movies).waitTask(); + console.log(task); primary_field_guide_update_document_primary_key: |- - client.updateIndex('books', { - primaryKey: 'title' - }) + const _task = await _client + .updateIndex("books", { primaryKey: "title" }) + .waitTask(); primary_field_guide_create_index_primary_key: |- - client.createIndex('books', { primaryKey: 'reference_number' }) + const _task = await _client + .createIndex("books", { primaryKey: "reference_number" }) + .waitTask(); primary_field_guide_add_document_primary_key: |- - client.index('books').addDocuments([ - { - reference_number: 287947, - title: 'Diary of a Wimpy Kid', - author: 'Jeff Kinney', - genres: ['comedy','humor'], - price: 5.00 - } - ], { primaryKey: 'reference_number' }) + const _task = await _client + .index("books") + .addDocuments( + [ + { + reference_number: 287947, + title: "Diary of a Wimpy Kid", + author: "Jeff Kinney", + genres: ["comedy", "humor"], + price: 5.0, + }, + ], + { primaryKey: "reference_number" }, + ) + .waitTask(); getting_started_add_documents: |- // With npm: // npm install meilisearch - + // Or with yarn: // yarn add meilisearch - + // In your .js file: + import { MeiliSearch } from "meilisearch"; + import movies from "./movies.json" with { type: "json" }; + // With the `require` syntax: - const { MeiliSearch } = require('meilisearch') - const movies = require('./movies.json') - // With the `import` syntax: - import { MeiliSearch } from 'meilisearch' - import movies from './movies.json' - + // const { MeiliSearch } = require("meilisearch"); + // const movies = require("./movies.json"); + const client = new MeiliSearch({ - host: 'http://localhost:7700', - apiKey: 'aSampleMasterKey' - }) - client.index('movies').addDocuments(movies) - .then((res) => console.log(res)) + host: "http://localhost:7700", + apiKey: "aSampleMasterKey", + }); + + const task = await client.index("movies").addDocuments(movies).waitTask(); + console.log(task); getting_started_search: |- - client.index('movies').search('botman').then((res) => console.log(res)) + const response = await _client.index("movies").search("botman"); + + console.log(response); getting_started_update_ranking_rules: |- - client.index('movies').updateRankingRules([ - 'exactness', - 'words', - 'typo', - 'proximity', - 'attribute', - 'sort', - 'release_date:asc', - 'rank:desc' - ]) + const _task = await _client + .index("movies") + .updateRankingRules([ + "exactness", + "words", + "typo", + "proximity", + "attribute", + "sort", + "release_date:asc", + "rank:desc", + ]) + .waitTask(); getting_started_update_searchable_attributes: |- - client.index('movies').updateSearchableAttributes([ - 'title' - ]) + const _task = await _client + .index("movies") + .updateSearchableAttributes(["title"]) + .waitTask(); getting_started_update_stop_words: |- - client.index('movies').updateStopWords(['the']) + const _task = await _client.index("movies").updateStopWords(["the"]).waitTask(); getting_started_check_task_status: |- - client.getTask(0) + const _task = await _client.tasks.getTask(0); getting_started_synonyms: |- - client.index('movies').updateSynonyms({ - winnie: ['piglet'], - piglet: ['winnie'] - }) + const _task = await _client + .index("movies") + .updateSynonyms({ + winnie: ["piglet"], + piglet: ["winnie"], + }) + .waitTask(); getting_started_update_displayed_attributes: |- - client.index('movies').updateDisplayedAttributes([ - 'title', - 'overview', - 'poster' - ]) + const _task = await _client + .index("movies") + .updateDisplayedAttributes(["title", "overview", "poster"]) + .waitTask(); getting_started_add_meteorites: |- - const meteorites = require('./meteorites.json') - - client.index('meteorites').addDocuments(meteorites) + import meteorites from "./meteorites.json" with { type: "json" }; + + const _task = await _client + .index("meteorites") + .addDocuments(meteorites) + .waitTask(); getting_started_configure_settings: |- - client.index('meteorites').updateSettings({ - filterableAttributes: ['mass', '_geo'], - sortableAttributes: ['mass', '_geo'] - }) + const _task = await _client + .index("meteorites") + .updateSettings({ + filterableAttributes: ["mass", "_geo"], + sortableAttributes: ["mass", "_geo"], + }) + .waitTask(); getting_started_geo_radius: |- - client.index('meteorites').search('', { filter: '_geoRadius(46.9480, 7.4474, 210000)' }) + const _response = await _client + .index("meteorites") + .search("", { filter: "_geoRadius(46.9480, 7.4474, 210000)" }); getting_started_geo_point: |- - client.index('meteorites').search('', { sort: ['_geoPoint(48.8583701, 2.2922926):asc'] }) + const _response = await _client + .index("meteorites") + .search("", { sort: ["_geoPoint(48.8583701, 2.2922926):asc"] }); getting_started_sorting: |- - client.index('meteorites').search('', { - sort: ['mass:asc'], - filter: 'mass < 200' - }) + const _response = await _client.index("meteorites").search("", { + sort: ["mass:asc"], + filter: "mass < 200", + }); getting_started_faceting: |- - client.index('movies').updateFaceting({ - maxValuesPerFacet: 2, - sortFacetValuesBy: { - '*': 'count' - } - }) + const _task = await _client + .index("movies") + .updateFaceting({ + maxValuesPerFacet: 2, + sortFacetValuesBy: { + "*": "count", + }, + }) + .waitTask(); getting_started_typo_tolerance: |- - client.index('movies').updateTypoTolerance({ - minWordSizeForTypos: { - oneTypo: 4 - } - }) + const _task = await _client + .index("movies") + .updateTypoTolerance({ + minWordSizeForTypos: { + oneTypo: 4, + }, + }) + .waitTask(); getting_started_filtering: |- - client.index('meteorites').search('', { filter: 'mass < 200' }) + const _response = await _client + .index("meteorites") + .search("", { filter: "mass < 200" }); getting_started_pagination: |- - client.index('movies').updatePagination({ maxTotalHits: 500 }) + const _task = await _client + .index("movies") + .updatePagination({ maxTotalHits: 500 }) + .waitTask(); get_filterable_attributes_1: |- - client.index('movies').getFilterableAttributes() + const _filterableAttributes = await _client + .index("movies") + .getFilterableAttributes(); update_filterable_attributes_1: |- - client.index('movies') + const _task = await _client + .index("movies") .updateFilterableAttributes([ "genres", { @@ -517,305 +617,402 @@ update_filterable_attributes_1: |- facetSearch: true, filter: { equality: true, comparison: false }, }, - } + }, ]) + .waitTask(); reset_filterable_attributes_1: |- - client.index('movies').resetFilterableAttributes() + const _task = await _client + .index("movies") + .resetFilterableAttributes() + .waitTask(); filtering_update_settings_1: |- - client.index('movies') - .updateFilterableAttributes([ - 'director', - 'genres' - ]) + const _task = await _client + .index("movies") + .updateFilterableAttributes(["director", "genres"]) + .waitTask(); faceted_search_walkthrough_filter_1: |- - client.index('movies') - .search('thriller', { - filter: [['genres = Horror', 'genres = Mystery'], 'director = "Jordan Peele"'] - }) + const _response = await _client.index("movies").search("thriller", { + filter: [ + ["genres = Horror", "genres = Mystery"], + 'director = "Jordan Peele"', + ], + }); faceted_search_update_settings_1: |- - client.index('movie_ratings').updateFilterableAttributes(['genres', 'rating', 'language']) + const _task = await _client + .index("movie_ratings") + .updateFilterableAttributes(["genres", "rating", "language"]) + .waitTask(); faceted_search_1: |- - client.index('books').search('classic', { facets: ['genres', 'rating', 'language'] }) + const _response = await _client + .index("books") + .search("classic", { facets: ["genres", "rating", "language"] }); post_dump_1: |- - client.createDump() + const _task = await _client.createDump().waitTask(); create_snapshot_1: |- - client.createSnapshot() + const _task = await _client.createSnapshot().waitTask(); phrase_search_1: |- - client.index('movies') - .search('"african american" horror') + const _response = await _client + .index("movies") + .search('"african american" horror'); sorting_guide_update_sortable_attributes_1: |- - client.index('books').updateSortableAttributes([ - 'author', - 'price' - ]) + const _task = await _client + .index("books") + .updateSortableAttributes(["author", "price"]) + .waitTask(); sorting_guide_update_ranking_rules_1: |- - client.index('books').updateRankingRules([ - 'words', - 'sort', - 'typo', - 'proximity', - 'attribute', - 'exactness' - ]) + const _task = await _client + .index("books") + .updateRankingRules([ + "words", + "sort", + "typo", + "proximity", + "attribute", + "exactness", + ]) + .waitTask(); sorting_guide_sort_parameter_1: |- - client.index('books').search('science fiction', { - sort: ['price:asc'], - }) + const _response = await _client.index("books").search("science fiction", { + sort: ["price:asc"], + }); sorting_guide_sort_parameter_2: |- - client.index('books').search('butler', { - sort: ['author:desc'], - }) + const _response = await _client.index("books").search("butler", { + sort: ["author:desc"], + }); sorting_guide_sort_nested_1: |- - client.index('books').search('science fiction', { - 'sort': ['rating.users:asc'], - }) + const _response = await _client.index("books").search("science fiction", { + sort: ["rating.users:asc"], + }); get_sortable_attributes_1: |- - client.index('books').getSortableAttributes() + const _sortableAttributes = await _client + .index("books") + .getSortableAttributes(); update_sortable_attributes_1: |- - client.index('books') - .updateSortableAttributes([ - 'price', - 'author' - ]) + const _task = await _client + .index("books") + .updateSortableAttributes(["price", "author"]) + .waitTask(); reset_sortable_attributes_1: |- - client.index('books').resetSortableAttributes() + const _task = await _client.index("books").resetSortableAttributes().waitTask(); get_pagination_settings_1: |- - client.index('books').getPagination() + const _pagination = await _client.index("books").getPagination(); update_pagination_settings_1: |- - client.index('books').updateSettings({ pagination: { maxTotalHits: 100 }}) + const _task = await _client + .index("books") + .updateSettings({ pagination: { maxTotalHits: 100 } }) + .waitTask(); reset_pagination_settings_1: |- - client.index('books').resetPagination() + const _task = await _client.index("books").resetPagination().waitTask(); get_faceting_settings_1: |- - client.index('books').getFaceting() + const _faceting = await _client.index("books").getFaceting(); update_faceting_settings_1: |- - client.index('books').updateFaceting({ - maxValuesPerFacet: 2 - sortFacetValuesBy: { - '*': 'alpha', - genres: 'count' - } - }) + const _task = await _client + .index("books") + .updateFaceting({ + maxValuesPerFacet: 2, + sortFacetValuesBy: { + "*": "alpha", + genres: "count", + }, + }) + .waitTask(); reset_faceting_settings_1: |- - client.index('books').resetFaceting() + const _task = await _client.index("books").resetFaceting().waitTask(); get_dictionary_1: |- - client.index('books').getDictionary() + const _dictionary = await _client.index("books").getDictionary(); update_dictionary_1: |- - client.index('books').updateDictionary(['J. R. R.', 'W. E. B.']) + const _task = await _client + .index("books") + .updateDictionary(["J. R. R.", "W. E. B."]) + .waitTask(); reset_dictionary_1: |- - client.index('books').resetDictionary() + const _task = await _client.index("books").resetDictionary().waitTask(); search_parameter_guide_sort_1: |- - client.index('books').search('science fiction', { - sort: ['price:asc'], - }) + const _response = await _client.index("books").search("science fiction", { + sort: ["price:asc"], + }); get_separator_tokens_1: |- - client.index('books').getSeparatorTokens() + const _separatorTokens = await _client.index("books").getSeparatorTokens(); update_separator_tokens_1: |- - client.index('books').updateSeparatorTokens(['|', '…']) + const _task = await _client + .index("books") + .updateSeparatorTokens(["|", "…"]) + .waitTask(); reset_separator_tokens_1: |- - client.index('books').resetSeparatorTokens() + const _task = await _client.index("books").resetSeparatorTokens().waitTask(); get_non_separator_tokens_1: |- - client.index('books').getNonSeparatorTokens() + const _nonSeparatorTokens = await _client + .index("books") + .getNonSeparatorTokens(); update_non_separator_tokens_1: |- - client.index('books').updateNonSeparatorTokens(['@', '#']) + const _task = await _client + .index("books") + .updateNonSeparatorTokens(["@", "#"]) + .waitTask(); reset_non_separator_tokens_1: |- - client.index('books').resetNonSeparatorTokens() + const _task = await _client.index("books").resetNonSeparatorTokens().waitTask(); get_proximity_precision_settings_1: |- - client.index('books').getProximityPrecision() + const _proximityPrecision = await _client + .index("books") + .getProximityPrecision(); update_proximity_precision_settings_1: |- - client.index('books').updateProximityPrecision('byAttribute') + const _task = await _client + .index("books") + .updateProximityPrecision("byAttribute") + .waitTask(); reset_proximity_precision_settings_1: |- - client.index('books').resetProximityPrecision() + const _task = await _client.index("books").resetProximityPrecision().waitTask(); get_search_cutoff_1: |- - client.index('movies').getSearchCutoffMs() + const _searchCutoffMs = await _client.index("movies").getSearchCutoffMs(); update_search_cutoff_1: |- - client.index('movies').updateSearchCutoffMs(150) + const _task = await _client + .index("movies") + .updateSearchCutoffMs(150) + .waitTask(); reset_search_cutoff_1: |- - client.index('movies').resetSearchCutoffMs() + const _task = await _client.index("movies").resetSearchCutoffMs().waitTask(); search_parameter_guide_facet_stats_1: |- - client.index('movie_ratings').search('Batman', { facets: ['genres', 'rating'] }) + const _response = await _client + .index("movie_ratings") + .search("Batman", { facets: ["genres", "rating"] }); geosearch_guide_filter_settings_1: |- - client.index('restaurants') - .updateFilterableAttributes([ - '_geo' - ]) + const _task = await _client + .index("restaurants") + .updateFilterableAttributes(["_geo"]) + .waitTask(); geosearch_guide_filter_usage_1: |- - client.index('restaurants').search('', { - filter: ['_geoRadius(45.472735, 9.184019, 2000)'], - }) + const _response = await _client.index("restaurants").search("", { + filter: ["_geoRadius(45.472735, 9.184019, 2000)"], + }); geosearch_guide_filter_usage_2: |- - client.index('restaurants').search('', { - filter: ['_geoRadius(45.472735, 9.184019, 2000) AND type = pizza'], - }) + const _response = await _client.index("restaurants").search("", { + filter: ["_geoRadius(45.472735, 9.184019, 2000) AND type = pizza"], + }); geosearch_guide_filter_usage_3: |- - client.index('restaurants').search('', { - filter: ['_geoBoundingBox([45.494181, 9.214024], [45.449484, 9.179175])'], - }) + const _response = await _client.index("restaurants").search("", { + filter: ["_geoBoundingBox([45.494181, 9.214024], [45.449484, 9.179175])"], + }); geosearch_guide_sort_settings_1: |- - client.index('restaurants').updateSortableAttributes([ - '_geo' - ]) + const _task = await _client + .index("restaurants") + .updateSortableAttributes(["_geo"]) + .waitTask(); geosearch_guide_sort_usage_1: |- - client.index('restaurants').search('', { - sort: ['_geoPoint(48.8561446, 2.2978204):asc'], - }) + const _response = await _client.index("restaurants").search("", { + sort: ["_geoPoint(48.8561446, 2.2978204):asc"], + }); geosearch_guide_sort_usage_2: |- - client.index('restaurants').search('', { - sort: ['_geoPoint(48.8561446, 2.2978204):asc', 'rating:desc'], - }) + const _response = await _client.index("restaurants").search("", { + sort: ["_geoPoint(48.8561446, 2.2978204):asc", "rating:desc"], + }); security_guide_search_key_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'apiKey' }) - client.index('patient_medical_records').search() + const client = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "apiKey", + }); + + const _response = await client.index("patient_medical_records").search(); security_guide_update_key_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'masterKey' }) - client.updateKey('74c9c733-3368-4738-bbe5-1d18a5fecb37', { - description: 'Default Search API Key' - }) + const client = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "masterKey", + }); + + const _key = await client.updateKey("74c9c733-3368-4738-bbe5-1d18a5fecb37", { + description: "Default Search API Key", + }); security_guide_create_key_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'masterKey' }) - client.createKey({ - description: 'Search patient records key', - actions: ['search'], - indexes: ['patient_medical_records'], - expiresAt: '2023-01-01T00:00:00Z' - }) + const client = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "masterKey", + }); + + await client.createKey({ + description: "Search patient records key", + actions: ["search"], + indexes: ["patient_medical_records"], + expiresAt: new Date("2023-01-01T00:00:00Z"), + }); security_guide_list_keys_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'masterKey' }) - client.getKeys() + const _keys = await _client.getKeys(); security_guide_delete_key_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'masterKey' }) - client.deleteKey('ac5cd97d-5a4b-4226-a868-2d0eb6d197ab') + const client = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "masterKey", + }); + + await client.deleteKey("ac5cd97d-5a4b-4226-a868-2d0eb6d197ab"); authorization_header_1: |- - const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'masterKey' }) - client.getKeys() + const _keys = await _client.getKeys(); tenant_token_guide_generate_sdk_1: |- - import { generateTenantToken } from 'meilisearch/token' - - const searchRules = { - patient_medical_records: { - filter: 'user_id = 1' - } - } - const apiKey = 'B5KdX2MY2jV6EXfUs6scSfmC...' - const apiKeyUid = '85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76' - const expiresAt = new Date('2025-12-20') // optional - - const token = await generateTenantToken({ apiKey, apiKeyUid, searchRules, expiresAt }) + import { generateTenantToken } from "meilisearch/token"; + + const _token = await generateTenantToken({ + apiKey: "B5KdX2MY2jV6EXfUs6scSfmC...", + apiKeyUid: "85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76", + searchRules: { patient_medical_records: { filter: "user_id = 1" } }, + expiresAt: new Date("2025-12-20"), // optional + }); tenant_token_guide_search_sdk_1: |- - const frontEndClient = new MeiliSearch({ host: 'http://localhost:7700', apiKey: token }) - frontEndClient.index('patient_medical_records').search('blood test') + const frontEndClient = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "", + }); + + const _response = await frontEndClient + .index("patient_medical_records") + .search("blood test"); landing_getting_started_1: |- - const client = new MeiliSearch('http://localhost:7700', 'masterKey') - - await client.index('movies').addDocuments([ - { 'id': 1, 'title': 'Carol' }, - { 'id': 2, 'title': 'Wonder Woman' }, - { 'id': 3, 'title': 'Life of Pi' }, - { 'id': 4, 'title': 'Mad Max: Fury Road' }, - { 'id': 5, 'title': 'Moana' }, - { 'id': 6, 'title': 'Philadelphia'} - ]) - + const client = new MeiliSearch({ + host: "http://localhost:7700", + apiKey: "masterKey", + }); + + await client.index("movies").addDocuments([ + { id: 1, title: "Carol" }, + { id: 2, title: "Wonder Woman" }, + { id: 3, title: "Life of Pi" }, + { id: 4, title: "Mad Max: Fury Road" }, + { id: 5, title: "Moana" }, + { id: 6, title: "Philadelphia" }, + ]); + // be aware this client is using the masterKey, it should not be used in front end - const search = await index.search('philodelphia') - console.log(search) + const search = await client.index("movies").search("philodelphia"); + console.log(search); facet_search_1: |- - client.index('books').searchForFacetValues({ - facetQuery: 'fiction', - facetName: 'genres' - filter: 'rating > 3' - }) + const _response = await _client.index("books").searchForFacetValues({ + facetQuery: "fiction", + facetName: "genres", + filter: "rating > 3", + }); facet_search_2: |- - client.index('books').updateFaceting({ - sortFacetValuesBy: { - genres: 'count' - } - }) + const _task = await _client + .index("books") + .updateFaceting({ + sortFacetValuesBy: { + genres: "count", + }, + }) + .waitTask(); facet_search_3: |- - client.index('books').searchForFacetValues({ - facetQuery: 'c', - facetName: 'genres' - }) + const _response = await _client.index("books").searchForFacetValues({ + facetQuery: "c", + facetName: "genres", + }); search_parameter_guide_show_ranking_score_details_1: |- - client.index('movies').search('dragon', { showRankingScoreDetails: true }) + const _response = await _client + .index("movies") + .search("dragon", { showRankingScoreDetails: true }); negative_search_1: |- - client.index('movies').search('-escape') + const _response = await _client.index("movies").search("-escape"); negative_search_2: |- - client.index('movies').search('-"escape"') + const _response = await _client.index("movies").search('-"escape"'); search_parameter_reference_ranking_score_threshold_1: |- - client.index('INDEX_NAME').search('badman', { rankingScoreThreshold: 0.2 }) + const _response = await _client + .index("INDEX_NAME") + .search("badman", { rankingScoreThreshold: 0.2 }); search_parameter_reference_retrieve_vectors_1: |- - client.index('INDEX_NAME').search('kitchen utensils', { + const _response = await _client.index("INDEX_NAME").search("kitchen utensils", { retrieveVectors: true, hybrid: { - embedder: 'EMBEDDER_NAME' - } - }) + embedder: "EMBEDDER_NAME", + }, + }); search_parameter_guide_hybrid_1: |- - client.index('INDEX_NAME').search('kitchen utensils', { + const _response = await _client.index("INDEX_NAME").search("kitchen utensils", { hybrid: { semanticRatio: 0.9, - embedder: 'EMBEDDER_NAME' - } - }) + embedder: "EMBEDDER_NAME", + }, + }); get_similar_post_1: |- - client.index('INDEX_NAME').searchSimilarDocuments({ id: 'TARGET_DOCUMENT_ID', embedder: 'default' }) + const _response = await _client + .index("INDEX_NAME") + .searchSimilarDocuments({ id: "TARGET_DOCUMENT_ID", embedder: "default" }); search_parameter_guide_matching_strategy_3: |- - client.index('movies').search('white shirt', { - matchingStrategy: 'frequency' - }) + const _response = await _client.index("movies").search("white shirt", { + matchingStrategy: "frequency", + }); search_parameter_reference_distinct_1: |- - client.index('INDEX_NAME').search('QUERY TERMS', { distinct: 'ATTRIBUTE_A' }) + const _response = await _client + .index("INDEX_NAME") + .search("QUERY TERMS", { distinct: "ATTRIBUTE_A" }); distinct_attribute_guide_filterable_1: |- - client.index('products').updateFilterableAttributes(['product_id', 'sku', 'url']) + const _task = await _client + .index("products") + .updateFilterableAttributes(["product_id", "sku", "url"]) + .waitTask(); distinct_attribute_guide_distinct_parameter_1: |- - client.index('products').search('white shirt', { distinct: 'sku' }) + const _response = await _client + .index("products") + .search("white shirt", { distinct: "sku" }); multi_search_federated_1: |- - client.multiSearch({ + const _response = await _client.multiSearch({ federation: {}, queries: [ { - indexUid: 'movies', - q: 'batman', + indexUid: "movies", + q: "batman", }, { - indexUid: 'comics', - q: 'batman', + indexUid: "comics", + q: "batman", }, - ] - }) + ], + }); search_parameter_reference_locales_1: |- - client.index('INDEX_NAME').search('QUERY TEXT IN JAPANESE', { locales: ['jpn'] }) + const _response = await _client + .index("INDEX_NAME") + .search("QUERY TEXT IN JAPANESE", { locales: ["jpn"] }); get_localized_attribute_settings_1: |- - client.index('INDEX_NAME').getLocalizedAttributes() + const _localizedAttributes = await _client + .index("INDEX_NAME") + .getLocalizedAttributes(); update_localized_attribute_settings_1: |- - client.index('INDEX_NAME').updateLocalizedAttributes([ - { attributePatterns: ['*_ja'], locales: ['jpn'] }, - ]) + const _task = await _client + .index("INDEX_NAME") + .updateLocalizedAttributes([ + { attributePatterns: ["*_ja"], locales: ["jpn"] }, + ]) + .waitTask(); reset_localized_attribute_settings_1: |- - client.index('INDEX_NAME').resetLocalizedAttributes() + const _task = await _client + .index("INDEX_NAME") + .resetLocalizedAttributes() + .waitTask(); get_facet_search_settings_1: |- - client.index('INDEX_NAME').getFacetSearch(); + const _facetSearch = await _client.index("INDEX_NAME").getFacetSearch(); update_facet_search_settings_1: |- - client.index('INDEX_NAME').updateFacetSearch(false); + const _task = await _client + .index("INDEX_NAME") + .updateFacetSearch(false) + .waitTask(); reset_facet_search_settings_1: |- - client.index('INDEX_NAME').resetFacetSearch(); + const _task = await _client.index("INDEX_NAME").resetFacetSearch().waitTask(); get_prefix_search_settings_1: |- - client.index('INDEX_NAME').getPrefixSearch(); + const _prefixSearch = await _client.index("INDEX_NAME").getPrefixSearch(); update_prefix_search_settings_1: |- - client.index('INDEX_NAME').updatePrefixSearch('disabled'); + const _task = await _client + .index("INDEX_NAME") + .updatePrefixSearch("disabled") + .waitTask(); reset_prefix_search_settings_1: |- - client.index('INDEX_NAME').resetPrefixSearch(); + const _task = await _client.index("INDEX_NAME").resetPrefixSearch().waitTask(); get_all_batches_1: |- - client.getBatches(); + const _batches = await _client.batches.getBatches(); get_batch_1: |- - client.getBatch(BATCH_UID); -# Vector search + const _batch = await _client.batches.getBatch(123); update_embedders_1: |- - client.index('INDEX_NAME').updateEmbedders({ - default: { - source: 'openAi', - apiKey: 'OPEN_AI_API_KEY', - model: 'text-embedding-3-small', - documentTemplate: 'A document titled '{{doc.title}}' whose description starts with {{doc.overview|truncatewords: 20}}' - } - }); + const _task = await _client + .index("INDEX_NAME") + .updateEmbedders({ + default: { + source: "openAi", + apiKey: "OPEN_AI_API_KEY", + model: "text-embedding-3-small", + documentTemplate: + "A document titled '{{doc.title}}' whose description starts with {{doc.overview|truncatewords: 20}}", + }, + }) + .waitTask(); diff --git a/.gitignore b/.gitignore index 868fe3fb0..4ee31bb32 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,4 @@ package dist_default_export_in_index no_default_export_in_index playgrounds/javascript/yarn.lock +generated-code-samples diff --git a/package.json b/package.json index 4121006e3..5b2cc9d5d 100644 --- a/package.json +++ b/package.json @@ -70,22 +70,24 @@ ], "devDependencies": { "@eslint/js": "^9.23.0", - "@vitest/coverage-v8": "^3.1.1", + "@types/js-yaml": "^4.0.9", "@types/node": "^22.15.3", "@typescript-eslint/utils": "^8.29.0", + "@vitest/coverage-v8": "^3.1.1", "@vitest/eslint-plugin": "^1.1.38", "eslint": "^9.25.1", "eslint-config-prettier": "^10.1.2", "eslint-plugin-tsdoc": "^0.4.0", - "typescript": "^5.8.3", - "vite": "^6.3.4", "globals": "^16.0.0", "husky": "^9.1.7", + "js-yaml": "^4.1.0", "lint-staged": "15.5.1", "prettier": "^3.5.3", "prettier-plugin-jsdoc": "^1.3.2", "typedoc": "^0.28.3", + "typescript": "^5.8.3", "typescript-eslint": "^8.31.1", + "vite": "^6.3.4", "vitest": "^3.1.1" }, "packageManager": "yarn@1.22.22" diff --git a/scripts/code-samples.js b/scripts/code-samples.js new file mode 100644 index 000000000..2eef7da3d --- /dev/null +++ b/scripts/code-samples.js @@ -0,0 +1,17 @@ +import { argv } from "node:process"; + +function throwInvalidArgs() { + throw new Error("expected `to-yaml` or `from-yaml` as arguments"); +} + +if (argv.length !== 3) { + throwInvalidArgs(); +} + +if (argv[2] === "to-yaml") { + await import("./code-samples/to-yaml.js"); +} else if (argv[2] === "from-yaml") { + await import("./code-samples/from-yaml.js"); +} else { + throwInvalidArgs(); +} diff --git a/scripts/code-samples/from-yaml.js b/scripts/code-samples/from-yaml.js new file mode 100644 index 000000000..97305c301 --- /dev/null +++ b/scripts/code-samples/from-yaml.js @@ -0,0 +1,50 @@ +import { writeFileSync, mkdirSync } from "node:fs"; +import { + generatedCodeSamplesDir, + iterateCodeSamples, + delimiter, +} from "./shared.js"; + +const headerImport = 'import { MeiliSearch } from "meilisearch";\n'; +const headerClientDeclaration = + 'const _client = new MeiliSearch({ host: "http://127.0.0.1:7700" });\n'; +const headerComment = + "// Code below this line will be written to code samples YAML file\n" + + delimiter + + "\n"; + +const jsonFilesToGenerate = ["games", "movies", "meteorites"]; + +try { + mkdirSync(generatedCodeSamplesDir); +} catch (error) { + if (error.code !== "EEXIST") { + throw error; + } +} + +for (const jsonFileToGenerate of jsonFilesToGenerate) { + writeFileSync( + new URL(jsonFileToGenerate + ".json", generatedCodeSamplesDir), + "[]", + ); +} + +for (const { sampleName, code } of iterateCodeSamples()) { + let header = ""; + + if (!code.includes('from "meilisearch";\n')) { + header += headerImport; + } + + if (!code.includes("new MeiliSearch(")) { + header += headerClientDeclaration; + } + + header += headerComment; + + writeFileSync( + new URL(sampleName + ".ts", generatedCodeSamplesDir), + header + code + "\n", + ); +} diff --git a/scripts/code-samples/shared.js b/scripts/code-samples/shared.js new file mode 100644 index 000000000..dd5c0bc4a --- /dev/null +++ b/scripts/code-samples/shared.js @@ -0,0 +1,37 @@ +import { readFileSync } from "node:fs"; +import { load } from "js-yaml"; + +export const codeSamplesPath = new URL( + "../../.code-samples.meilisearch.yaml", + import.meta.url, +); + +export const generatedCodeSamplesDir = new URL( + "../../generated-code-samples/", + import.meta.url, +); + +export const delimiter = "// -~-~-~-~-"; + +export function* iterateCodeSamples() { + const codeSamplesContents = readFileSync(codeSamplesPath); + + const codeSamples = load(codeSamplesContents, { + filename: codeSamplesPath.href, + onWarning: console.warn, + }); + + if (codeSamples === null || typeof codeSamples !== "object") { + throw new Error("expected `codeSamples` to be an object", { + cause: codeSamples, + }); + } + + for (const [sampleName, code] of Object.entries(codeSamples)) { + if (typeof code !== "string") { + throw new Error("expected `code` to be a string", { cause: code }); + } + + yield { sampleName, code }; + } +} diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js new file mode 100644 index 000000000..81d0d51e8 --- /dev/null +++ b/scripts/code-samples/to-yaml.js @@ -0,0 +1,73 @@ +import { readFileSync, readdirSync, writeFileSync } from "node:fs"; +import { parse } from "node:path"; +import { + codeSamplesPath, + generatedCodeSamplesDir, + iterateCodeSamples, + delimiter, +} from "./shared.js"; + +const codeSampleNamesFromYaml = Array.from( + iterateCodeSamples(), + (v) => v.sampleName, +); + +const dirEntries = readdirSync(generatedCodeSamplesDir, { + withFileTypes: true, +}); + +function throwError() { + throw new Error( + `expected generated code samples directory at ${generatedCodeSamplesDir.href} to only contain TypeScript and JSON files`, + { cause: dirEntries }, + ); +} + +const serializedCodeSamples = dirEntries + .map((dirEnt) => { + if (!dirEnt.isFile()) { + throwError(); + } + + const { ext, name } = parse(dirEnt.name); + if (ext !== ".ts" && ext !== ".json") { + throwError(); + } + + if (ext === ".json") { + return null; + } + + const codeSampleContent = readFileSync(dirEnt.parentPath + dirEnt.name, { + encoding: "utf-8", + }); + + const splitContent = codeSampleContent.split("\n"); + const indexOfDelimiter = splitContent.findIndex((v) => v === delimiter); + + const indentedContent = splitContent + .slice(indexOfDelimiter === -1 ? 0 : indexOfDelimiter + 1) + .map((v) => " " + v) + .join("\n") + .trimEnd(); + + return { name, indentedContent }; + }) + .filter((v) => v !== null) + .sort(({ name: nameA }, { name: nameB }) => { + const indexOfA = codeSampleNamesFromYaml.indexOf(nameA); + return indexOfA === -1 + ? 1 + : indexOfA - codeSampleNamesFromYaml.indexOf(nameB); + }) + .map(({ name, indentedContent }) => name + ": |-\n" + indentedContent) + .join("\n"); + +const header = + "# This code-samples file is used by the Meilisearch documentation\n" + + "# Every example written here will be automatically fetched by\n" + + "# the documentation on build\n" + + "# You can read more at https://github.com/meilisearch/documentation\n" + + "---\n"; + +writeFileSync(codeSamplesPath, header + serializedCodeSamples + "\n"); diff --git a/tsconfig.json b/tsconfig.json index 2c9559fc9..0bb66c7e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,12 @@ "lib": ["ESNext", "DOM", "DOM.Iterable"], "resolveJsonModule": true, "strict": true, - "verbatimModuleSyntax": true + "verbatimModuleSyntax": true, + // For testing purposes + // TODO: Should use this for tests as well perhaps, resolve.alias + "paths": { + "meilisearch": ["./src/index.ts"], + "meilisearch/token": ["./src/token.ts"] + } } } diff --git a/yarn.lock b/yarn.lock index 827be91b8..3f010e7cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -539,6 +539,11 @@ dependencies: "@types/unist" "*" +"@types/js-yaml@^4.0.9": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" + integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== + "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" From d80114794695dc402cec63114ba2776ce93bbd82 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 16 May 2025 18:50:11 +0300 Subject: [PATCH 02/13] Improvements, add workflow step --- .../workflows/meilisearch-prototype-tests.yml | 2 + .github/workflows/pre-release-tests.yml | 2 + .github/workflows/tests.yml | 2 + package.json | 2 + scripts/code-samples.js | 14 ++----- scripts/code-samples/from-yaml.js | 8 ++++ scripts/code-samples/to-yaml.js | 38 ++++++++++++++----- 7 files changed, 48 insertions(+), 20 deletions(-) diff --git a/.github/workflows/meilisearch-prototype-tests.yml b/.github/workflows/meilisearch-prototype-tests.yml index b47e36c86..0f9558df6 100644 --- a/.github/workflows/meilisearch-prototype-tests.yml +++ b/.github/workflows/meilisearch-prototype-tests.yml @@ -57,6 +57,8 @@ jobs: cache: yarn - name: Install dependencies run: yarn --dev + - name: Generate code sample files + run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project diff --git a/.github/workflows/pre-release-tests.yml b/.github/workflows/pre-release-tests.yml index 894b8e4c7..8249fb0a4 100644 --- a/.github/workflows/pre-release-tests.yml +++ b/.github/workflows/pre-release-tests.yml @@ -54,6 +54,8 @@ jobs: cache: yarn - name: Install dependencies run: yarn --dev + - name: Generate code sample files + run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a39efc546..be6ba5500 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,6 +47,8 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev + - name: Generate code sample files + run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project diff --git a/package.json b/package.json index 5b2cc9d5d..1036db879 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,8 @@ "test:env:nodejs": "yarn build && node tests/env/node/index.cjs && node tests/env/node/getting_started.cjs", "test:env:esm": "yarn --cwd tests/env/esm && yarn --cwd tests/env/esm start", "test:env:nitro-app": "yarn build && yarn --cwd tests/env/nitro-app test", + "generate-code-sample-files": "node scripts/code-samples.js from-yaml", + "generate-code-samples-yaml": "node scripts/code-samples.js to-yaml", "fmt": "prettier -c ./**/*.{js,ts}", "fmt:fix": "prettier -w ./**/*.{js,ts}", "lint": "eslint", diff --git a/scripts/code-samples.js b/scripts/code-samples.js index 2eef7da3d..a1868e2bb 100644 --- a/scripts/code-samples.js +++ b/scripts/code-samples.js @@ -1,17 +1,11 @@ import { argv } from "node:process"; -function throwInvalidArgs() { - throw new Error("expected `to-yaml` or `from-yaml` as arguments"); -} - -if (argv.length !== 3) { - throwInvalidArgs(); -} - -if (argv[2] === "to-yaml") { +if (argv[2] === "to-yaml" && argv.length === 3) { await import("./code-samples/to-yaml.js"); } else if (argv[2] === "from-yaml") { await import("./code-samples/from-yaml.js"); } else { - throwInvalidArgs(); + throw new Error( + "expected `to-yaml` (+ new code samples names) or `from-yaml` as arguments", + ); } diff --git a/scripts/code-samples/from-yaml.js b/scripts/code-samples/from-yaml.js index 97305c301..50bfb2056 100644 --- a/scripts/code-samples/from-yaml.js +++ b/scripts/code-samples/from-yaml.js @@ -1,3 +1,4 @@ +import { argv } from "node:process"; import { writeFileSync, mkdirSync } from "node:fs"; import { generatedCodeSamplesDir, @@ -48,3 +49,10 @@ for (const { sampleName, code } of iterateCodeSamples()) { header + code + "\n", ); } + +for (const sampleName of argv.slice(3)) { + writeFileSync( + new URL(sampleName + ".ts", generatedCodeSamplesDir), + headerImport + headerClientDeclaration + headerComment, + ); +} diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index 81d0d51e8..09418b8c4 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -1,4 +1,5 @@ -import { readFileSync, readdirSync, writeFileSync } from "node:fs"; +import { readdir } from "node:fs/promises"; +import { readFileSync, writeFileSync } from "node:fs"; import { parse } from "node:path"; import { codeSamplesPath, @@ -12,10 +13,24 @@ const codeSampleNamesFromYaml = Array.from( (v) => v.sampleName, ); -const dirEntries = readdirSync(generatedCodeSamplesDir, { +/** @type {import("node:fs").Dirent[]} */ +const dirEntries = await readdir(generatedCodeSamplesDir, { withFileTypes: true, +}).catch((error) => { + if (error?.code !== "ENOENT") { + throw error; + } + + return []; }); +if (dirEntries.length === 0) { + throw new Error( + `there are no code sample files at ${generatedCodeSamplesDir.href}\n` + + "tip: first generate them from the YAML file, consult CONTRIBUTING.md on how to use this script", + ); +} + function throwError() { throw new Error( `expected generated code samples directory at ${generatedCodeSamplesDir.href} to only contain TypeScript and JSON files`, @@ -23,7 +38,7 @@ function throwError() { ); } -const serializedCodeSamples = dirEntries +const manipulatedCodeSamples = dirEntries .map((dirEnt) => { if (!dirEnt.isFile()) { throwError(); @@ -51,15 +66,18 @@ const serializedCodeSamples = dirEntries .join("\n") .trimEnd(); - return { name, indentedContent }; + const index = codeSampleNamesFromYaml.indexOf(name); + + return { name, indentedContent, index }; }) .filter((v) => v !== null) - .sort(({ name: nameA }, { name: nameB }) => { - const indexOfA = codeSampleNamesFromYaml.indexOf(nameA); - return indexOfA === -1 - ? 1 - : indexOfA - codeSampleNamesFromYaml.indexOf(nameB); - }) + .sort(({ index: indexA }, { index: indexB }) => indexA - indexB); + +while (manipulatedCodeSamples.at(0)?.index === -1) { + manipulatedCodeSamples.push(manipulatedCodeSamples.shift()); +} + +const serializedCodeSamples = manipulatedCodeSamples .map(({ name, indentedContent }) => name + ": |-\n" + indentedContent) .join("\n"); From e4dccddf1408099c10a7c56c1b685d49b7379d09 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 16 May 2025 19:00:17 +0300 Subject: [PATCH 03/13] Wrong workflows changed --- .github/workflows/meilisearch-prototype-tests.yml | 2 -- .github/workflows/pre-release-tests.yml | 2 -- .github/workflows/tests.yml | 6 ++++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/meilisearch-prototype-tests.yml b/.github/workflows/meilisearch-prototype-tests.yml index 0f9558df6..b47e36c86 100644 --- a/.github/workflows/meilisearch-prototype-tests.yml +++ b/.github/workflows/meilisearch-prototype-tests.yml @@ -57,8 +57,6 @@ jobs: cache: yarn - name: Install dependencies run: yarn --dev - - name: Generate code sample files - run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project diff --git a/.github/workflows/pre-release-tests.yml b/.github/workflows/pre-release-tests.yml index 8249fb0a4..894b8e4c7 100644 --- a/.github/workflows/pre-release-tests.yml +++ b/.github/workflows/pre-release-tests.yml @@ -54,8 +54,6 @@ jobs: cache: yarn - name: Install dependencies run: yarn --dev - - name: Generate code sample files - run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index be6ba5500..061fdebc0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,8 +47,6 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev - - name: Generate code sample files - run: yarn generate-code-sample-files - name: Run tests run: yarn test - name: Build project @@ -77,6 +75,8 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev + - name: Generate code sample files + run: yarn generate-code-sample-files - name: Run code style check run: yarn style - name: Run yaml style check @@ -95,6 +95,8 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev + - name: Generate code sample files + run: yarn generate-code-sample-files - name: Build project run: yarn build - name: Run types check From f8c398f05bd5e9ee6ca4c334c1a66dc9235c0740 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 16 May 2025 19:05:42 +0300 Subject: [PATCH 04/13] Fix trailing spaces problem --- .code-samples.meilisearch.yaml | 30 +++++++++++++++--------------- scripts/code-samples/to-yaml.js | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 1c37ade72..ff64b0800 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -487,28 +487,28 @@ primary_field_guide_add_document_primary_key: |- getting_started_add_documents: |- // With npm: // npm install meilisearch - + // Or with yarn: // yarn add meilisearch - + // In your .js file: import { MeiliSearch } from "meilisearch"; import movies from "./movies.json" with { type: "json" }; - + // With the `require` syntax: // const { MeiliSearch } = require("meilisearch"); // const movies = require("./movies.json"); - + const client = new MeiliSearch({ host: "http://localhost:7700", apiKey: "aSampleMasterKey", }); - + const task = await client.index("movies").addDocuments(movies).waitTask(); console.log(task); getting_started_search: |- const response = await _client.index("movies").search("botman"); - + console.log(response); getting_started_update_ranking_rules: |- const _task = await _client @@ -548,7 +548,7 @@ getting_started_update_displayed_attributes: |- .waitTask(); getting_started_add_meteorites: |- import meteorites from "./meteorites.json" with { type: "json" }; - + const _task = await _client .index("meteorites") .addDocuments(meteorites) @@ -810,14 +810,14 @@ security_guide_search_key_1: |- host: "http://localhost:7700", apiKey: "apiKey", }); - + const _response = await client.index("patient_medical_records").search(); security_guide_update_key_1: |- const client = new MeiliSearch({ host: "http://localhost:7700", apiKey: "masterKey", }); - + const _key = await client.updateKey("74c9c733-3368-4738-bbe5-1d18a5fecb37", { description: "Default Search API Key", }); @@ -826,7 +826,7 @@ security_guide_create_key_1: |- host: "http://localhost:7700", apiKey: "masterKey", }); - + await client.createKey({ description: "Search patient records key", actions: ["search"], @@ -840,13 +840,13 @@ security_guide_delete_key_1: |- host: "http://localhost:7700", apiKey: "masterKey", }); - + await client.deleteKey("ac5cd97d-5a4b-4226-a868-2d0eb6d197ab"); authorization_header_1: |- const _keys = await _client.getKeys(); tenant_token_guide_generate_sdk_1: |- import { generateTenantToken } from "meilisearch/token"; - + const _token = await generateTenantToken({ apiKey: "B5KdX2MY2jV6EXfUs6scSfmC...", apiKeyUid: "85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76", @@ -858,7 +858,7 @@ tenant_token_guide_search_sdk_1: |- host: "http://localhost:7700", apiKey: "", }); - + const _response = await frontEndClient .index("patient_medical_records") .search("blood test"); @@ -867,7 +867,7 @@ landing_getting_started_1: |- host: "http://localhost:7700", apiKey: "masterKey", }); - + await client.index("movies").addDocuments([ { id: 1, title: "Carol" }, { id: 2, title: "Wonder Woman" }, @@ -876,7 +876,7 @@ landing_getting_started_1: |- { id: 5, title: "Moana" }, { id: 6, title: "Philadelphia" }, ]); - + // be aware this client is using the masterKey, it should not be used in front end const search = await client.index("movies").search("philodelphia"); console.log(search); diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index 09418b8c4..ad5b6bd28 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -62,7 +62,7 @@ const manipulatedCodeSamples = dirEntries const indentedContent = splitContent .slice(indexOfDelimiter === -1 ? 0 : indexOfDelimiter + 1) - .map((v) => " " + v) + .map((v) => (v === "" ? v : " " + v)) .join("\n") .trimEnd(); From f9a4286f37b756e6901a0743a7ffc46b79c80821 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sat, 17 May 2025 09:53:45 +0300 Subject: [PATCH 05/13] Fix JSON formatting, add workflow format check, add comments --- .github/workflows/tests.yml | 3 +++ scripts/code-samples/from-yaml.js | 6 +++++- scripts/code-samples/to-yaml.js | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 061fdebc0..7d0571608 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -79,6 +79,9 @@ jobs: run: yarn generate-code-sample-files - name: Run code style check run: yarn style + # https://github.com/prettier/prettier/issues/15438 + - name: Check formatting of code samples + run: yarn prettier --ignore-path=.prettierignore -c generated-code-samples - name: Run yaml style check uses: ibiqlik/action-yamllint@v3 with: diff --git a/scripts/code-samples/from-yaml.js b/scripts/code-samples/from-yaml.js index 50bfb2056..e6e9c5285 100644 --- a/scripts/code-samples/from-yaml.js +++ b/scripts/code-samples/from-yaml.js @@ -24,20 +24,23 @@ try { } } +// generate JSON files used by samples, so type check passes for (const jsonFileToGenerate of jsonFilesToGenerate) { writeFileSync( new URL(jsonFileToGenerate + ".json", generatedCodeSamplesDir), - "[]", + "[]\n", ); } for (const { sampleName, code } of iterateCodeSamples()) { let header = ""; + // generate import if there isn't already one if (!code.includes('from "meilisearch";\n')) { header += headerImport; } + // generate client declaration if there isn't already one if (!code.includes("new MeiliSearch(")) { header += headerClientDeclaration; } @@ -50,6 +53,7 @@ for (const { sampleName, code } of iterateCodeSamples()) { ); } +// generate additional files from arguments passed for (const sampleName of argv.slice(3)) { writeFileSync( new URL(sampleName + ".ts", generatedCodeSamplesDir), diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index ad5b6bd28..eee575730 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -61,11 +61,14 @@ const manipulatedCodeSamples = dirEntries const indexOfDelimiter = splitContent.findIndex((v) => v === delimiter); const indentedContent = splitContent + // get rid of code before delimiter .slice(indexOfDelimiter === -1 ? 0 : indexOfDelimiter + 1) + // add padding .map((v) => (v === "" ? v : " " + v)) .join("\n") .trimEnd(); + // get position in current code samples YAML file, to be able to order it the same way const index = codeSampleNamesFromYaml.indexOf(name); return { name, indentedContent, index }; @@ -73,6 +76,7 @@ const manipulatedCodeSamples = dirEntries .filter((v) => v !== null) .sort(({ index: indexA }, { index: indexB }) => indexA - indexB); +// for every new code sample, place them at the end of the file instead of the start while (manipulatedCodeSamples.at(0)?.index === -1) { manipulatedCodeSamples.push(manipulatedCodeSamples.shift()); } From ce84f373f155d6dc62be8f29c10335afa7f2a001 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 18 May 2025 21:51:04 +0300 Subject: [PATCH 06/13] Minor changes, update CONTRIBUTING.md --- .github/workflows/tests.yml | 7 ------- CONTRIBUTING.md | 14 ++++++++++++++ package.json | 6 +++--- scripts/code-samples/from-yaml.js | 9 +++++++++ scripts/code-samples/to-yaml.js | 7 +++++-- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7d0571608..a39efc546 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,13 +75,8 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev - - name: Generate code sample files - run: yarn generate-code-sample-files - name: Run code style check run: yarn style - # https://github.com/prettier/prettier/issues/15438 - - name: Check formatting of code samples - run: yarn prettier --ignore-path=.prettierignore -c generated-code-samples - name: Run yaml style check uses: ibiqlik/action-yamllint@v3 with: @@ -98,8 +93,6 @@ jobs: cache: 'yarn' - name: Install dependencies run: yarn --dev - - name: Generate code sample files - run: yarn generate-code-sample-files - name: Build project run: yarn build - name: Run types check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aea3406bf..701fd7cd4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,6 +70,20 @@ yarn style:fix yarn build ``` +### Code samples + +In this repository code samples are linted and type checked. To achieve this we generate +TypeScript files from `.code-samples.meilisearch.yaml`, and vice-versa. + +```bash +# Generate files +yarn generate-code-sample-files +# Generate YAML file +yarn generate-code-samples-yaml +# For maintainers to generate new code samples +yarn generate-code-sample-files new_sample_one new_sample_two +``` + ## Git Guidelines ### Git Branches diff --git a/package.json b/package.json index 1036db879..03d9304e5 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "build": "vite build && tsc -p tsconfig.build.json && vite --mode production-umd build", "postbuild": "node scripts/build.js", "test": "vitest run --coverage", - "types": "tsc -p tsconfig.json --noEmit", + "types": "yarn generate-code-sample-files && tsc -p tsconfig.json --noEmit", "types:watch": "yarn types --watch", "test:env:browser": "yarn build && node scripts/copy-umd-file.js --to ./tests/env/express/public && yarn --cwd tests/env/express && yarn --cwd tests/env/express test", "test:watch": "vitest watch", @@ -61,8 +61,8 @@ "fmt:fix": "prettier -w ./**/*.{js,ts}", "lint": "eslint", "lint:fix": "eslint --fix", - "style": "yarn fmt && yarn lint", - "style:fix": "yarn fmt:fix && yarn lint:fix", + "style": "yarn generate-code-sample-files && prettier --ignore-path=.prettierignore -c generated-code-samples && yarn fmt && yarn lint", + "style:fix": "yarn generate-code-sample-files && prettier --ignore-path=.prettierignore -c generated-code-samples && yarn fmt:fix && yarn lint:fix", "prepare": "husky" }, "files": [ diff --git a/scripts/code-samples/from-yaml.js b/scripts/code-samples/from-yaml.js index e6e9c5285..e80b53122 100644 --- a/scripts/code-samples/from-yaml.js +++ b/scripts/code-samples/from-yaml.js @@ -11,6 +11,7 @@ const headerClientDeclaration = 'const _client = new MeiliSearch({ host: "http://127.0.0.1:7700" });\n'; const headerComment = "// Code below this line will be written to code samples YAML file\n" + + '// For more information consult CONTRIBUTING.md "Tests and Linter" section\n' + delimiter + "\n"; @@ -32,6 +33,8 @@ for (const jsonFileToGenerate of jsonFilesToGenerate) { ); } +let generatedFileTally = 0; + for (const { sampleName, code } of iterateCodeSamples()) { let header = ""; @@ -51,6 +54,8 @@ for (const { sampleName, code } of iterateCodeSamples()) { new URL(sampleName + ".ts", generatedCodeSamplesDir), header + code + "\n", ); + + generatedFileTally += 1; } // generate additional files from arguments passed @@ -59,4 +64,8 @@ for (const sampleName of argv.slice(3)) { new URL(sampleName + ".ts", generatedCodeSamplesDir), headerImport + headerClientDeclaration + headerComment, ); + + generatedFileTally += 1; } + +console.log(`generated ${generatedFileTally} code sample file(s)`); diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index eee575730..c5ed957d5 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -86,10 +86,13 @@ const serializedCodeSamples = manipulatedCodeSamples .join("\n"); const header = - "# This code-samples file is used by the Meilisearch documentation\n" + + "# This code-samples file is used by the Meilisearch documentation.\n" + "# Every example written here will be automatically fetched by\n" + - "# the documentation on build\n" + + "# the documentation on build.\n" + "# You can read more at https://github.com/meilisearch/documentation\n" + + '# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section.' + "---\n"; writeFileSync(codeSamplesPath, header + serializedCodeSamples + "\n"); + +console.log(`generated ${manipulatedCodeSamples.length} code sample(s)`); From 0e76d6d72dd784a01e0e8d513abdac3c85f51b29 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 18 May 2025 22:01:35 +0300 Subject: [PATCH 07/13] Update scripts/code-samples/to-yaml.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- scripts/code-samples/to-yaml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index c5ed957d5..edf70281e 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -90,7 +90,7 @@ const header = "# Every example written here will be automatically fetched by\n" + "# the documentation on build.\n" + "# You can read more at https://github.com/meilisearch/documentation\n" + - '# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section.' + + '# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section.\n' + "---\n"; writeFileSync(codeSamplesPath, header + serializedCodeSamples + "\n"); From cf9419f1d6587de29ab27fb341fb0d9cd5d158fb Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 18 May 2025 22:11:17 +0300 Subject: [PATCH 08/13] Minor changes --- .code-samples.meilisearch.yaml | 9 ++++++--- scripts/code-samples/to-yaml.js | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index ff64b0800..56769f1ac 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -1,7 +1,8 @@ -# This code-samples file is used by the Meilisearch documentation +# This code-samples file is used by the Meilisearch documentation. # Every example written here will be automatically fetched by -# the documentation on build +# the documentation on build. # You can read more at https://github.com/meilisearch/documentation +# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section. --- synonyms_guide_1: |- const _task = await _client @@ -41,7 +42,9 @@ create_an_index_1: |- .createIndex("movies", { primaryKey: "id" }) .waitTask(); update_an_index_1: |- - const _task = _client.updateIndex("movies", { primaryKey: "id" }).waitTask(); + const _task = await _client + .updateIndex("movies", { primaryKey: "id" }) + .waitTask(); delete_an_index_1: |- const _task = await _client.deleteIndex("movies").waitTask(); swap_indexes_1: |- diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index c5ed957d5..b30d61218 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -90,8 +90,9 @@ const header = "# Every example written here will be automatically fetched by\n" + "# the documentation on build.\n" + "# You can read more at https://github.com/meilisearch/documentation\n" + - '# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section.' + - "---\n"; + '# This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section.\n' + + ``; +("---\n"); writeFileSync(codeSamplesPath, header + serializedCodeSamples + "\n"); From f303e2e8e6eddeb279613d1ea4cde952ee2ffc84 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 19 May 2025 11:14:42 +0300 Subject: [PATCH 09/13] Misc --- scripts/code-samples/to-yaml.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index edf70281e..7c427c901 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -1,6 +1,6 @@ import { readdir } from "node:fs/promises"; import { readFileSync, writeFileSync } from "node:fs"; -import { parse } from "node:path"; +import { parse, join } from "node:path"; import { codeSamplesPath, generatedCodeSamplesDir, @@ -53,9 +53,10 @@ const manipulatedCodeSamples = dirEntries return null; } - const codeSampleContent = readFileSync(dirEnt.parentPath + dirEnt.name, { - encoding: "utf-8", - }); + const codeSampleContent = readFileSync( + join(dirEnt.parentPath, dirEnt.name), + { encoding: "utf-8" }, + ); const splitContent = codeSampleContent.split("\n"); const indexOfDelimiter = splitContent.findIndex((v) => v === delimiter); From e147795986d641f484077dea838a6d11153f0c88 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 21 May 2025 11:16:00 +0300 Subject: [PATCH 10/13] Refactor and improve --- .code-samples.meilisearch.yaml | 866 ++++++++++++------------------ scripts/code-samples/from-yaml.js | 25 +- 2 files changed, 359 insertions(+), 532 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 56769f1ac..70b9d81bc 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -5,119 +5,91 @@ # This file is generated, read more in CONTRIBUTING.md "Tests and Linter" section. --- synonyms_guide_1: |- - const _task = await _client - .index("movies") - .updateSynonyms({ - great: ["fantastic"], - fantastic: ["great"], - }) - .waitTask(); + await client.index("movies").updateSynonyms({ + great: ["fantastic"], + fantastic: ["great"], + }); date_guide_index_1: |- import games from "./games.json" with { type: "json" }; - const _task = await _client.index("games").addDocuments(games).waitTask(); + await client.index("games").addDocuments(games); date_guide_filterable_attributes_1: |- - const _task = await _client - .index("games") - .updateFilterableAttributes(["release_timestamp"]) - .waitTask(); + await client.index("games").updateFilterableAttributes(["release_timestamp"]); date_guide_filter_1: |- - const _response = await _client.index("games").search("", { + await client.index("games").search("", { filter: "release_timestamp >= 1514761200 AND release_timestamp < 1672527600", }); date_guide_sortable_attributes_1: |- - const _task = await _client - .index("games") - .updateSortableAttributes(["release_timestamp"]) - .waitTask(); + await client.index("games").updateSortableAttributes(["release_timestamp"]); date_guide_sort_1: |- - const _response = await _client.index("games").search("", { + await client.index("games").search("", { sort: ["release_timestamp:desc"], }); get_one_index_1: |- - const _index = await _client.index("movies").getRawInfo(); + await client.index("movies").getRawInfo(); list_all_indexes_1: |- - const _indexes = await _client.getIndexes({ limit: 3 }); + await client.getIndexes({ limit: 3 }); create_an_index_1: |- - const _task = await _client - .createIndex("movies", { primaryKey: "id" }) - .waitTask(); + await client.createIndex("movies", { primaryKey: "id" }); update_an_index_1: |- - const _task = await _client - .updateIndex("movies", { primaryKey: "id" }) - .waitTask(); + await client.updateIndex("movies", { primaryKey: "id" }); delete_an_index_1: |- - const _task = await _client.deleteIndex("movies").waitTask(); + await client.deleteIndex("movies"); swap_indexes_1: |- - const _task = await _client - .swapIndexes([ - { indexes: ["indexA", "indexB"] }, - { indexes: ["indexX", "indexY"] }, - ]) - .waitTask(); + await client.swapIndexes([ + { indexes: ["indexA", "indexB"] }, + { indexes: ["indexX", "indexY"] }, + ]); get_one_document_1: |- - const _documents = await _client + await client .index("movies") .getDocument(25684, { fields: ["id", "title", "poster", "release_date"] }); get_documents_1: |- - const _documents = await _client.index("movies").getDocuments({ + await client.index("movies").getDocuments({ limit: 2, filter: "genres = action", }); get_documents_post_1: |- - const _documents = await _client.index("books").getDocuments({ + await client.index("books").getDocuments({ filter: "(rating > 3 AND (genres = Adventure OR genres = Fiction)) AND language = English", fields: ["title", "genres", "rating", "language"], limit: 3, }); add_or_replace_documents_1: |- - const _task = await _client - .index("movies") - .addDocuments([ - { - id: 287947, - title: "Shazam", - poster: - "https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg", - overview: - "A boy is given the ability to become an adult superhero in times of need with a single magic word.", - release_date: "2019-03-23", - }, - ]) - .waitTask(); + await client.index("movies").addDocuments([ + { + id: 287947, + title: "Shazam", + poster: "https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg", + overview: + "A boy is given the ability to become an adult superhero in times of need with a single magic word.", + release_date: "2019-03-23", + }, + ]); add_or_update_documents_1: |- - const _task = await _client - .index("movies") - .updateDocuments([ - { - id: 287947, - title: "Shazam ⚡️", - genres: "comedy", - }, - ]) - .waitTask(); + await client.index("movies").updateDocuments([ + { + id: 287947, + title: "Shazam ⚡️", + genres: "comedy", + }, + ]); delete_all_documents_1: |- - const _task = await _client.index("movies").deleteAllDocuments().waitTask(); + await client.index("movies").deleteAllDocuments(); delete_one_document_1: |- - const _task = await _client.index("movies").deleteDocument(25684).waitTask(); + await client.index("movies").deleteDocument(25684); delete_documents_by_batch_1: |- - const _task = await _client - .index("movies") - .deleteDocuments([23488, 153738, 437035, 363869]) - .waitTask(); + await client.index("movies").deleteDocuments([23488, 153738, 437035, 363869]); delete_documents_by_filter_1: |- - const _task = await _client - .index("movies") - .deleteDocuments({ - filter: "genres = action OR genres = adventure", - }) - .waitTask(); + await client.index("movies").deleteDocuments({ + filter: "genres = action OR genres = adventure", + }); search_post_1: |- - const _response = await _client.index("movies").search("American ninja"); + await client.index("movies").search("American ninja"); search_get_1: |- - const _response = await _client.index("movies").searchGet("American ninja"); + await client.index("movies").searchGet("American ninja"); multi_search_1: |- - const _response = await _client.multiSearch({ + await client.multiSearch({ queries: [ { indexUid: "movies", @@ -136,128 +108,119 @@ multi_search_1: |- ], }); get_all_tasks_1: |- - const _tasks = await _client.tasks.getTasks(); + await client.tasks.getTasks(); get_task_1: |- - const _task = await _client.tasks.getTask(1); + await client.tasks.getTask(1); async_guide_filter_by_date_1: |- - const _tasks = await _client.tasks.getTasks({ + await client.tasks.getTasks({ afterEnqueuedAt: "2020-10-11T11:49:53.000Z", }); async_guide_multiple_filters_1: |- - const _tasks = await _client.tasks.getTasks({ + await client.tasks.getTasks({ indexUids: ["movies"], types: ["documentAdditionOrUpdate", "documentDeletion"], statuses: ["processing"], }); async_guide_filter_by_ids_1: |- - const _tasks = await _client.tasks.getTasks({ uids: [5, 10, 13] }); + await client.tasks.getTasks({ uids: [5, 10, 13] }); async_guide_filter_by_statuses_1: |- - const _tasks = await _client.tasks.getTasks({ + await client.tasks.getTasks({ statuses: ["failed", "canceled"], }); async_guide_filter_by_types_1: |- - const _tasks = await _client.tasks.getTasks({ + await client.tasks.getTasks({ types: ["dumpCreation", "indexSwap"], }); async_guide_filter_by_index_uids_1: |- - const _tasks = await _client.tasks.getTasks({ indexUids: ["movies"] }); + await client.tasks.getTasks({ indexUids: ["movies"] }); get_all_tasks_paginating_1: |- - const _tasks = await _client.tasks.getTasks({ limit: 2, from: 10 }); + await client.tasks.getTasks({ limit: 2, from: 10 }); get_all_tasks_paginating_2: |- - const _tasks = await _client.tasks.getTasks({ limit: 2, from: 8 }); + await client.tasks.getTasks({ limit: 2, from: 8 }); async_guide_canceled_by_1: |- - const _tasks = await _client.tasks.getTasks({ canceledBy: [9, 15] }); + await client.tasks.getTasks({ canceledBy: [9, 15] }); delete_tasks_1: |- - const _task = await _client.tasks.deleteTasks({ uids: [1, 2] }).waitTask(); + await client.tasks.deleteTasks({ uids: [1, 2] }); cancel_tasks_1: |- - const _task = await _client.tasks.cancelTasks({ uids: [1, 2] }).waitTask(); + await client.tasks.cancelTasks({ uids: [1, 2] }); get_one_key_1: |- - const _key = await _client.getKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); + await client.getKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); get_all_keys_1: |- - const _keys = await _client.getKeys({ limit: 3 }); + await client.getKeys({ limit: 3 }); create_a_key_1: |- - const _key = await _client.createKey({ + await client.createKey({ description: "Add documents: Products API key", actions: ["documents.add"], indexes: ["products"], expiresAt: new Date("2021-11-13T00:00:00Z"), }); update_a_key_1: |- - const _key = await _client.updateKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d", { + await client.updateKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d", { name: "Products/Reviews API key", description: "Manage documents: Products/Reviews API key", }); delete_a_key_1: |- - await _client.deleteKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); + await client.deleteKey("6062abda-a5aa-4414-ac91-ecd7944c0f8d"); get_settings_1: |- - const _settings = await _client.index("movies").getSettings(); + await client.index("movies").getSettings(); update_settings_1: |- - const _task = await _client - .index("movies") - .updateSettings({ - rankingRules: [ - "words", - "typo", - "proximity", - "attribute", - "sort", - "exactness", - "release_date:desc", - "rank:desc", - ], - distinctAttribute: "movie_id", - searchableAttributes: ["title", "overview", "genres"], - displayedAttributes: ["title", "overview", "genres", "release_date"], - stopWords: ["the", "a", "an"], - sortableAttributes: ["title", "release_date"], - synonyms: { - wolverine: ["xmen", "logan"], - logan: ["wolverine"], - }, - typoTolerance: { - minWordSizeForTypos: { - oneTypo: 8, - twoTypos: 10, - }, - disableOnAttributes: ["title"], - }, - pagination: { - maxTotalHits: 5000, - }, - faceting: { - maxValuesPerFacet: 200, + await client.index("movies").updateSettings({ + rankingRules: [ + "words", + "typo", + "proximity", + "attribute", + "sort", + "exactness", + "release_date:desc", + "rank:desc", + ], + distinctAttribute: "movie_id", + searchableAttributes: ["title", "overview", "genres"], + displayedAttributes: ["title", "overview", "genres", "release_date"], + stopWords: ["the", "a", "an"], + sortableAttributes: ["title", "release_date"], + synonyms: { + wolverine: ["xmen", "logan"], + logan: ["wolverine"], + }, + typoTolerance: { + minWordSizeForTypos: { + oneTypo: 8, + twoTypos: 10, }, - searchCutoffMs: 150, - }) - .waitTask(); + disableOnAttributes: ["title"], + }, + pagination: { + maxTotalHits: 5000, + }, + faceting: { + maxValuesPerFacet: 200, + }, + searchCutoffMs: 150, + }); reset_settings_1: |- - const _task = await _client.index("movies").resetSettings().waitTask(); + await client.index("movies").resetSettings(); get_synonyms_1: |- - const _synonyms = await _client.index("movies").getSynonyms(); + await client.index("movies").getSynonyms(); update_synonyms_1: |- - const _task = await _client - .index("movies") - .updateSynonyms({ - wolverine: ["xmen", "logan"], - logan: ["wolverine", "xmen"], - wow: ["world of warcraft"], - }) - .waitTask(); + await client.index("movies").updateSynonyms({ + wolverine: ["xmen", "logan"], + logan: ["wolverine", "xmen"], + wow: ["world of warcraft"], + }); reset_synonyms_1: |- - const _task = await _client.index("movies").resetSynonyms().waitTask(); + await client.index("movies").resetSynonyms(); get_stop_words_1: |- - const _stopWords = await _client.index("movies").getStopWords(); + await client.index("movies").getStopWords(); update_stop_words_1: |- - const _task = await _client - .index("movies") - .updateStopWords(["of", "the", "to"]) - .waitTask(); + await client.index("movies").updateStopWords(["of", "the", "to"]); reset_stop_words_1: |- - const _task = await _client.index("movies").resetStopWords().waitTask(); + await client.index("movies").resetStopWords(); get_ranking_rules_1: |- - const _rankingRules = await _client.index("movies").getRankingRules(); + await client.index("movies").getRankingRules(); update_ranking_rules_1: |- - const _task = await _client + await client .index("movies") .updateRankingRules([ "words", @@ -268,225 +231,180 @@ update_ranking_rules_1: |- "exactness", "release_date:asc", "rank:desc", - ]) - .waitTask(); + ]); reset_ranking_rules_1: |- - const _task = await _client.index("movies").resetRankingRules().waitTask(); + await client.index("movies").resetRankingRules(); get_distinct_attribute_1: |- - const _distinctAttribute = await _client.index("shoes").getDistinctAttribute(); + await client.index("shoes").getDistinctAttribute(); update_distinct_attribute_1: |- - const _task = await _client - .index("shoes") - .updateDistinctAttribute("skuid") - .waitTask(); + await client.index("shoes").updateDistinctAttribute("skuid"); reset_distinct_attribute_1: |- - const _task = await _client.index("shoes").resetDistinctAttribute().waitTask(); + await client.index("shoes").resetDistinctAttribute(); get_searchable_attributes_1: |- - const _searchableAttributes = await _client - .index("movies") - .getSearchableAttributes(); + await client.index("movies").getSearchableAttributes(); update_searchable_attributes_1: |- - const _task = await _client + await client .index("movies") - .updateSearchableAttributes(["title", "overview", "genres"]) - .waitTask(); + .updateSearchableAttributes(["title", "overview", "genres"]); reset_searchable_attributes_1: |- - const _task = await _client - .index("movies") - .resetSearchableAttributes() - .waitTask(); + await client.index("movies").resetSearchableAttributes(); get_displayed_attributes_1: |- - const _displayedAttributes = await _client - .index("movies") - .getDisplayedAttributes(); + await client.index("movies").getDisplayedAttributes(); update_displayed_attributes_1: |- - const _task = await _client + await client .index("movies") - .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]) - .waitTask(); + .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]); reset_displayed_attributes_1: |- - const _task = await _client - .index("movies") - .resetDisplayedAttributes() - .waitTask(); + await client.index("movies").resetDisplayedAttributes(); get_typo_tolerance_1: |- - const _typoTolerance = await _client.index("books").getTypoTolerance(); + await client.index("books").getTypoTolerance(); update_typo_tolerance_1: |- - const _task = await _client - .index("books") - .updateTypoTolerance({ - minWordSizeForTypos: { - oneTypo: 4, - twoTypos: 10, - }, - disableOnAttributes: ["title"], - }) - .waitTask(); + await client.index("books").updateTypoTolerance({ + minWordSizeForTypos: { + oneTypo: 4, + twoTypos: 10, + }, + disableOnAttributes: ["title"], + }); reset_typo_tolerance_1: |- - const _task = await _client.index("books").resetTypoTolerance().waitTask(); + await client.index("books").resetTypoTolerance(); get_index_stats_1: |- - const _indexStats = await _client.index("movies").getStats(); + await client.index("movies").getStats(); get_indexes_stats_1: |- - const _stats = await _client.getStats(); + await client.getStats(); get_health_1: |- - const _health = _client.health(); + await client.health(); get_version_1: |- - const _version = await _client.getVersion(); + await client.getVersion(); distinct_attribute_guide_1: |- - const _task = await _client - .index("jackets") - .updateDistinctAttribute("product_id") - .waitTask(); + await client.index("jackets").updateDistinctAttribute("product_id"); field_properties_guide_searchable_1: |- - const _task = await _client + await client .index("movies") - .updateSearchableAttributes(["title", "overview", "genres"]) - .waitTask(); + .updateSearchableAttributes(["title", "overview", "genres"]); field_properties_guide_displayed_1: |- - const _task = await _client + await client .index("movies") - .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]) - .waitTask(); + .updateDisplayedAttributes(["title", "overview", "genres", "release_date"]); filtering_guide_1: |- - const _response = await _client.index("movie_ratings").search("Avengers", { + await client.index("movie_ratings").search("Avengers", { filter: "release_date > 795484800", }); filtering_guide_2: |- - const _response = await _client.index("movie_ratings").search("Batman", { + await client.index("movie_ratings").search("Batman", { filter: 'release_date > 795484800 AND (director = "Tim Burton" OR director = "Christopher Nolan")', }); filtering_guide_3: |- - const _response = await _client - .index("movie_ratings") - .search("Planet of the Apes", { - filter: 'release_date > 1577884550 AND (NOT director = "Tim Burton")', - }); + await client.index("movie_ratings").search("Planet of the Apes", { + filter: 'release_date > 1577884550 AND (NOT director = "Tim Burton")', + }); filtering_guide_nested_1: |- - const _response = await _client.index("movie_ratings").search("thriller", { + await client.index("movie_ratings").search("thriller", { filter: "rating.users >= 90", }); search_parameter_guide_query_1: |- - const _response = await _client.index("movies").search("shifu"); + await client.index("movies").search("shifu"); search_parameter_guide_offset_1: |- - const _response = await _client.index("movies").search("shifu", { + await client.index("movies").search("shifu", { offset: 1, }); search_parameter_guide_limit_1: |- - const _response = await _client.index("movies").search("shifu", { + await client.index("movies").search("shifu", { limit: 2, }); search_parameter_guide_retrieve_1: |- - const _response = await _client.index("movies").search("shifu", { + await client.index("movies").search("shifu", { attributesToRetrieve: ["overview", "title"], }); search_parameter_guide_crop_1: |- - const _response = await _client.index("movies").search("shifu", { + await client.index("movies").search("shifu", { attributesToCrop: ["overview"], cropLength: 5, }); search_parameter_guide_crop_marker_1: |- - const _response = await _client.index("movies").search("shifu", { + await client.index("movies").search("shifu", { attributesToCrop: ["overview"], cropMarker: "[…]", }); search_parameter_guide_highlight_1: |- - const _response = await _client.index("movies").search("winter feast", { + await client.index("movies").search("winter feast", { attributesToHighlight: ["overview"], }); search_parameter_guide_highlight_tag_1: |- - const _response = await _client.index("movies").search("winter feast", { + await client.index("movies").search("winter feast", { attributesToHighlight: ["overview"], highlightPreTag: '', highlightPostTag: "", }); search_parameter_guide_show_matches_position_1: |- - const _response = await _client.index("movies").search("winter feast", { + await client.index("movies").search("winter feast", { showMatchesPosition: true, }); search_parameter_guide_matching_strategy_1: |- - const _response = await _client.index("movies").search("big fat liar", { + await client.index("movies").search("big fat liar", { matchingStrategy: "last", }); search_parameter_guide_matching_strategy_2: |- - const _response = await _client.index("movies").search("big fat liar", { + await client.index("movies").search("big fat liar", { matchingStrategy: "all", }); search_parameter_guide_hitsperpage_1: |- - const _response = await _client.index("movies").search("", { + await client.index("movies").search("", { hitsPerPage: 15, }); search_parameter_guide_page_1: |- - const _response = await _client.index("movies").search("", { + await client.index("movies").search("", { page: 2, }); search_parameter_guide_show_ranking_score_1: |- - const _response = await _client.index("movies").search("dragon", { + await client.index("movies").search("dragon", { showRankingScore: true, }); search_parameter_guide_attributes_to_search_on_1: |- - const _response = await _client.index("movies").search("adventure", { + await client.index("movies").search("adventure", { attributesToSearchOn: ["overview"], }); typo_tolerance_guide_1: |- - const _task = await _client - .index("movies") - .updateTypoTolerance({ - enabled: false, - }) - .waitTask(); + await client.index("movies").updateTypoTolerance({ + enabled: false, + }); typo_tolerance_guide_2: |- - const _task = await _client - .index("movies") - .updateTypoTolerance({ - disableOnAttributes: ["title"], - }) - .waitTask(); + await client.index("movies").updateTypoTolerance({ + disableOnAttributes: ["title"], + }); typo_tolerance_guide_3: |- - const _task = await _client - .index("movies") - .updateTypoTolerance({ - disableOnWords: ["shrek"], - }) - .waitTask(); + await client.index("movies").updateTypoTolerance({ + disableOnWords: ["shrek"], + }); typo_tolerance_guide_4: |- - const _task = await _client - .index("movies") - .updateTypoTolerance({ - minWordSizeForTypos: { - oneTypo: 4, - twoTypos: 10, - }, - }) - .waitTask(); + await client.index("movies").updateTypoTolerance({ + minWordSizeForTypos: { + oneTypo: 4, + twoTypos: 10, + }, + }); add_movies_json_1: |- import movies from "./movies.json" with { type: "json" }; - const task = await _client.index("movies").addDocuments(movies).waitTask(); + const task = await client.index("movies").addDocuments(movies); console.log(task); primary_field_guide_update_document_primary_key: |- - const _task = await _client - .updateIndex("books", { primaryKey: "title" }) - .waitTask(); + await client.updateIndex("books", { primaryKey: "title" }); primary_field_guide_create_index_primary_key: |- - const _task = await _client - .createIndex("books", { primaryKey: "reference_number" }) - .waitTask(); + await client.createIndex("books", { primaryKey: "reference_number" }); primary_field_guide_add_document_primary_key: |- - const _task = await _client - .index("books") - .addDocuments( - [ - { - reference_number: 287947, - title: "Diary of a Wimpy Kid", - author: "Jeff Kinney", - genres: ["comedy", "humor"], - price: 5.0, - }, - ], - { primaryKey: "reference_number" }, - ) - .waitTask(); + await client.index("books").addDocuments( + [ + { + reference_number: 287947, + title: "Diary of a Wimpy Kid", + author: "Jeff Kinney", + genres: ["comedy", "humor"], + price: 5.0, + }, + ], + { primaryKey: "reference_number" }, + ); getting_started_add_documents: |- // With npm: // npm install meilisearch @@ -507,14 +425,14 @@ getting_started_add_documents: |- apiKey: "aSampleMasterKey", }); - const task = await client.index("movies").addDocuments(movies).waitTask(); + const task = await client.index("movies").addDocuments(movies); console.log(task); getting_started_search: |- - const response = await _client.index("movies").search("botman"); + const response = await client.index("movies").search("botman"); console.log(response); getting_started_update_ranking_rules: |- - const _task = await _client + await client .index("movies") .updateRankingRules([ "exactness", @@ -525,145 +443,103 @@ getting_started_update_ranking_rules: |- "sort", "release_date:asc", "rank:desc", - ]) - .waitTask(); + ]); getting_started_update_searchable_attributes: |- - const _task = await _client - .index("movies") - .updateSearchableAttributes(["title"]) - .waitTask(); + await client.index("movies").updateSearchableAttributes(["title"]); getting_started_update_stop_words: |- - const _task = await _client.index("movies").updateStopWords(["the"]).waitTask(); + await client.index("movies").updateStopWords(["the"]); getting_started_check_task_status: |- - const _task = await _client.tasks.getTask(0); + await client.tasks.getTask(0); getting_started_synonyms: |- - const _task = await _client - .index("movies") - .updateSynonyms({ - winnie: ["piglet"], - piglet: ["winnie"], - }) - .waitTask(); + await client.index("movies").updateSynonyms({ + winnie: ["piglet"], + piglet: ["winnie"], + }); getting_started_update_displayed_attributes: |- - const _task = await _client + await client .index("movies") - .updateDisplayedAttributes(["title", "overview", "poster"]) - .waitTask(); + .updateDisplayedAttributes(["title", "overview", "poster"]); getting_started_add_meteorites: |- import meteorites from "./meteorites.json" with { type: "json" }; - const _task = await _client - .index("meteorites") - .addDocuments(meteorites) - .waitTask(); + await client.index("meteorites").addDocuments(meteorites); getting_started_configure_settings: |- - const _task = await _client - .index("meteorites") - .updateSettings({ - filterableAttributes: ["mass", "_geo"], - sortableAttributes: ["mass", "_geo"], - }) - .waitTask(); + await client.index("meteorites").updateSettings({ + filterableAttributes: ["mass", "_geo"], + sortableAttributes: ["mass", "_geo"], + }); getting_started_geo_radius: |- - const _response = await _client + await client .index("meteorites") .search("", { filter: "_geoRadius(46.9480, 7.4474, 210000)" }); getting_started_geo_point: |- - const _response = await _client + await client .index("meteorites") .search("", { sort: ["_geoPoint(48.8583701, 2.2922926):asc"] }); getting_started_sorting: |- - const _response = await _client.index("meteorites").search("", { + await client.index("meteorites").search("", { sort: ["mass:asc"], filter: "mass < 200", }); getting_started_faceting: |- - const _task = await _client - .index("movies") - .updateFaceting({ - maxValuesPerFacet: 2, - sortFacetValuesBy: { - "*": "count", - }, - }) - .waitTask(); + await client.index("movies").updateFaceting({ + maxValuesPerFacet: 2, + sortFacetValuesBy: { + "*": "count", + }, + }); getting_started_typo_tolerance: |- - const _task = await _client - .index("movies") - .updateTypoTolerance({ - minWordSizeForTypos: { - oneTypo: 4, - }, - }) - .waitTask(); + await client.index("movies").updateTypoTolerance({ + minWordSizeForTypos: { + oneTypo: 4, + }, + }); getting_started_filtering: |- - const _response = await _client - .index("meteorites") - .search("", { filter: "mass < 200" }); + await client.index("meteorites").search("", { filter: "mass < 200" }); getting_started_pagination: |- - const _task = await _client - .index("movies") - .updatePagination({ maxTotalHits: 500 }) - .waitTask(); + await client.index("movies").updatePagination({ maxTotalHits: 500 }); get_filterable_attributes_1: |- - const _filterableAttributes = await _client - .index("movies") - .getFilterableAttributes(); + await client.index("movies").getFilterableAttributes(); update_filterable_attributes_1: |- - const _task = await _client - .index("movies") - .updateFilterableAttributes([ - "genres", - { - attributePatterns: ["genre"], - features: { - facetSearch: true, - filter: { equality: true, comparison: false }, - }, + await client.index("movies").updateFilterableAttributes([ + "genres", + { + attributePatterns: ["genre"], + features: { + facetSearch: true, + filter: { equality: true, comparison: false }, }, - ]) - .waitTask(); + }, + ]); reset_filterable_attributes_1: |- - const _task = await _client - .index("movies") - .resetFilterableAttributes() - .waitTask(); + await client.index("movies").resetFilterableAttributes(); filtering_update_settings_1: |- - const _task = await _client - .index("movies") - .updateFilterableAttributes(["director", "genres"]) - .waitTask(); + await client.index("movies").updateFilterableAttributes(["director", "genres"]); faceted_search_walkthrough_filter_1: |- - const _response = await _client.index("movies").search("thriller", { + await client.index("movies").search("thriller", { filter: [ ["genres = Horror", "genres = Mystery"], 'director = "Jordan Peele"', ], }); faceted_search_update_settings_1: |- - const _task = await _client + await client .index("movie_ratings") - .updateFilterableAttributes(["genres", "rating", "language"]) - .waitTask(); + .updateFilterableAttributes(["genres", "rating", "language"]); faceted_search_1: |- - const _response = await _client + await client .index("books") .search("classic", { facets: ["genres", "rating", "language"] }); post_dump_1: |- - const _task = await _client.createDump().waitTask(); + await client.createDump(); create_snapshot_1: |- - const _task = await _client.createSnapshot().waitTask(); + await client.createSnapshot(); phrase_search_1: |- - const _response = await _client - .index("movies") - .search('"african american" horror'); + await client.index("movies").search('"african american" horror'); sorting_guide_update_sortable_attributes_1: |- - const _task = await _client - .index("books") - .updateSortableAttributes(["author", "price"]) - .waitTask(); + await client.index("books").updateSortableAttributes(["author", "price"]); sorting_guide_update_ranking_rules_1: |- - const _task = await _client + await client .index("books") .updateRankingRules([ "words", @@ -672,140 +548,105 @@ sorting_guide_update_ranking_rules_1: |- "proximity", "attribute", "exactness", - ]) - .waitTask(); + ]); sorting_guide_sort_parameter_1: |- - const _response = await _client.index("books").search("science fiction", { + await client.index("books").search("science fiction", { sort: ["price:asc"], }); sorting_guide_sort_parameter_2: |- - const _response = await _client.index("books").search("butler", { + await client.index("books").search("butler", { sort: ["author:desc"], }); sorting_guide_sort_nested_1: |- - const _response = await _client.index("books").search("science fiction", { + await client.index("books").search("science fiction", { sort: ["rating.users:asc"], }); get_sortable_attributes_1: |- - const _sortableAttributes = await _client - .index("books") - .getSortableAttributes(); + await client.index("books").getSortableAttributes(); update_sortable_attributes_1: |- - const _task = await _client - .index("books") - .updateSortableAttributes(["price", "author"]) - .waitTask(); + await client.index("books").updateSortableAttributes(["price", "author"]); reset_sortable_attributes_1: |- - const _task = await _client.index("books").resetSortableAttributes().waitTask(); + await client.index("books").resetSortableAttributes(); get_pagination_settings_1: |- - const _pagination = await _client.index("books").getPagination(); + await client.index("books").getPagination(); update_pagination_settings_1: |- - const _task = await _client + await client .index("books") - .updateSettings({ pagination: { maxTotalHits: 100 } }) - .waitTask(); + .updateSettings({ pagination: { maxTotalHits: 100 } }); reset_pagination_settings_1: |- - const _task = await _client.index("books").resetPagination().waitTask(); + await client.index("books").resetPagination(); get_faceting_settings_1: |- - const _faceting = await _client.index("books").getFaceting(); + await client.index("books").getFaceting(); update_faceting_settings_1: |- - const _task = await _client - .index("books") - .updateFaceting({ - maxValuesPerFacet: 2, - sortFacetValuesBy: { - "*": "alpha", - genres: "count", - }, - }) - .waitTask(); + await client.index("books").updateFaceting({ + maxValuesPerFacet: 2, + sortFacetValuesBy: { + "*": "alpha", + genres: "count", + }, + }); reset_faceting_settings_1: |- - const _task = await _client.index("books").resetFaceting().waitTask(); + await client.index("books").resetFaceting(); get_dictionary_1: |- - const _dictionary = await _client.index("books").getDictionary(); + await client.index("books").getDictionary(); update_dictionary_1: |- - const _task = await _client - .index("books") - .updateDictionary(["J. R. R.", "W. E. B."]) - .waitTask(); + await client.index("books").updateDictionary(["J. R. R.", "W. E. B."]); reset_dictionary_1: |- - const _task = await _client.index("books").resetDictionary().waitTask(); + await client.index("books").resetDictionary(); search_parameter_guide_sort_1: |- - const _response = await _client.index("books").search("science fiction", { + await client.index("books").search("science fiction", { sort: ["price:asc"], }); get_separator_tokens_1: |- - const _separatorTokens = await _client.index("books").getSeparatorTokens(); + await client.index("books").getSeparatorTokens(); update_separator_tokens_1: |- - const _task = await _client - .index("books") - .updateSeparatorTokens(["|", "…"]) - .waitTask(); + await client.index("books").updateSeparatorTokens(["|", "…"]); reset_separator_tokens_1: |- - const _task = await _client.index("books").resetSeparatorTokens().waitTask(); + await client.index("books").resetSeparatorTokens(); get_non_separator_tokens_1: |- - const _nonSeparatorTokens = await _client - .index("books") - .getNonSeparatorTokens(); + await client.index("books").getNonSeparatorTokens(); update_non_separator_tokens_1: |- - const _task = await _client - .index("books") - .updateNonSeparatorTokens(["@", "#"]) - .waitTask(); + await client.index("books").updateNonSeparatorTokens(["@", "#"]); reset_non_separator_tokens_1: |- - const _task = await _client.index("books").resetNonSeparatorTokens().waitTask(); + await client.index("books").resetNonSeparatorTokens(); get_proximity_precision_settings_1: |- - const _proximityPrecision = await _client - .index("books") - .getProximityPrecision(); + await client.index("books").getProximityPrecision(); update_proximity_precision_settings_1: |- - const _task = await _client - .index("books") - .updateProximityPrecision("byAttribute") - .waitTask(); + await client.index("books").updateProximityPrecision("byAttribute"); reset_proximity_precision_settings_1: |- - const _task = await _client.index("books").resetProximityPrecision().waitTask(); + await client.index("books").resetProximityPrecision(); get_search_cutoff_1: |- - const _searchCutoffMs = await _client.index("movies").getSearchCutoffMs(); + await client.index("movies").getSearchCutoffMs(); update_search_cutoff_1: |- - const _task = await _client - .index("movies") - .updateSearchCutoffMs(150) - .waitTask(); + await client.index("movies").updateSearchCutoffMs(150); reset_search_cutoff_1: |- - const _task = await _client.index("movies").resetSearchCutoffMs().waitTask(); + await client.index("movies").resetSearchCutoffMs(); search_parameter_guide_facet_stats_1: |- - const _response = await _client + await client .index("movie_ratings") .search("Batman", { facets: ["genres", "rating"] }); geosearch_guide_filter_settings_1: |- - const _task = await _client - .index("restaurants") - .updateFilterableAttributes(["_geo"]) - .waitTask(); + await client.index("restaurants").updateFilterableAttributes(["_geo"]); geosearch_guide_filter_usage_1: |- - const _response = await _client.index("restaurants").search("", { + await client.index("restaurants").search("", { filter: ["_geoRadius(45.472735, 9.184019, 2000)"], }); geosearch_guide_filter_usage_2: |- - const _response = await _client.index("restaurants").search("", { + await client.index("restaurants").search("", { filter: ["_geoRadius(45.472735, 9.184019, 2000) AND type = pizza"], }); geosearch_guide_filter_usage_3: |- - const _response = await _client.index("restaurants").search("", { + await client.index("restaurants").search("", { filter: ["_geoBoundingBox([45.494181, 9.214024], [45.449484, 9.179175])"], }); geosearch_guide_sort_settings_1: |- - const _task = await _client - .index("restaurants") - .updateSortableAttributes(["_geo"]) - .waitTask(); + await client.index("restaurants").updateSortableAttributes(["_geo"]); geosearch_guide_sort_usage_1: |- - const _response = await _client.index("restaurants").search("", { + await client.index("restaurants").search("", { sort: ["_geoPoint(48.8561446, 2.2978204):asc"], }); geosearch_guide_sort_usage_2: |- - const _response = await _client.index("restaurants").search("", { + await client.index("restaurants").search("", { sort: ["_geoPoint(48.8561446, 2.2978204):asc", "rating:desc"], }); security_guide_search_key_1: |- @@ -814,14 +655,14 @@ security_guide_search_key_1: |- apiKey: "apiKey", }); - const _response = await client.index("patient_medical_records").search(); + await client.index("patient_medical_records").search(); security_guide_update_key_1: |- const client = new MeiliSearch({ host: "http://localhost:7700", apiKey: "masterKey", }); - const _key = await client.updateKey("74c9c733-3368-4738-bbe5-1d18a5fecb37", { + await client.updateKey("74c9c733-3368-4738-bbe5-1d18a5fecb37", { description: "Default Search API Key", }); security_guide_create_key_1: |- @@ -837,7 +678,7 @@ security_guide_create_key_1: |- expiresAt: new Date("2023-01-01T00:00:00Z"), }); security_guide_list_keys_1: |- - const _keys = await _client.getKeys(); + await client.getKeys(); security_guide_delete_key_1: |- const client = new MeiliSearch({ host: "http://localhost:7700", @@ -846,11 +687,11 @@ security_guide_delete_key_1: |- await client.deleteKey("ac5cd97d-5a4b-4226-a868-2d0eb6d197ab"); authorization_header_1: |- - const _keys = await _client.getKeys(); + await client.getKeys(); tenant_token_guide_generate_sdk_1: |- import { generateTenantToken } from "meilisearch/token"; - const _token = await generateTenantToken({ + await generateTenantToken({ apiKey: "B5KdX2MY2jV6EXfUs6scSfmC...", apiKeyUid: "85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76", searchRules: { patient_medical_records: { filter: "user_id = 1" } }, @@ -862,9 +703,7 @@ tenant_token_guide_search_sdk_1: |- apiKey: "", }); - const _response = await frontEndClient - .index("patient_medical_records") - .search("blood test"); + await frontEndClient.index("patient_medical_records").search("blood test"); landing_getting_started_1: |- const client = new MeiliSearch({ host: "http://localhost:7700", @@ -884,74 +723,68 @@ landing_getting_started_1: |- const search = await client.index("movies").search("philodelphia"); console.log(search); facet_search_1: |- - const _response = await _client.index("books").searchForFacetValues({ + await client.index("books").searchForFacetValues({ facetQuery: "fiction", facetName: "genres", filter: "rating > 3", }); facet_search_2: |- - const _task = await _client - .index("books") - .updateFaceting({ - sortFacetValuesBy: { - genres: "count", - }, - }) - .waitTask(); + await client.index("books").updateFaceting({ + sortFacetValuesBy: { + genres: "count", + }, + }); facet_search_3: |- - const _response = await _client.index("books").searchForFacetValues({ + await client.index("books").searchForFacetValues({ facetQuery: "c", facetName: "genres", }); search_parameter_guide_show_ranking_score_details_1: |- - const _response = await _client + await client .index("movies") .search("dragon", { showRankingScoreDetails: true }); negative_search_1: |- - const _response = await _client.index("movies").search("-escape"); + await client.index("movies").search("-escape"); negative_search_2: |- - const _response = await _client.index("movies").search('-"escape"'); + await client.index("movies").search('-"escape"'); search_parameter_reference_ranking_score_threshold_1: |- - const _response = await _client + await client .index("INDEX_NAME") .search("badman", { rankingScoreThreshold: 0.2 }); search_parameter_reference_retrieve_vectors_1: |- - const _response = await _client.index("INDEX_NAME").search("kitchen utensils", { + await client.index("INDEX_NAME").search("kitchen utensils", { retrieveVectors: true, hybrid: { embedder: "EMBEDDER_NAME", }, }); search_parameter_guide_hybrid_1: |- - const _response = await _client.index("INDEX_NAME").search("kitchen utensils", { + await client.index("INDEX_NAME").search("kitchen utensils", { hybrid: { semanticRatio: 0.9, embedder: "EMBEDDER_NAME", }, }); get_similar_post_1: |- - const _response = await _client + await client .index("INDEX_NAME") .searchSimilarDocuments({ id: "TARGET_DOCUMENT_ID", embedder: "default" }); search_parameter_guide_matching_strategy_3: |- - const _response = await _client.index("movies").search("white shirt", { + await client.index("movies").search("white shirt", { matchingStrategy: "frequency", }); search_parameter_reference_distinct_1: |- - const _response = await _client + await client .index("INDEX_NAME") .search("QUERY TERMS", { distinct: "ATTRIBUTE_A" }); distinct_attribute_guide_filterable_1: |- - const _task = await _client + await client .index("products") - .updateFilterableAttributes(["product_id", "sku", "url"]) - .waitTask(); + .updateFilterableAttributes(["product_id", "sku", "url"]); distinct_attribute_guide_distinct_parameter_1: |- - const _response = await _client - .index("products") - .search("white shirt", { distinct: "sku" }); + await client.index("products").search("white shirt", { distinct: "sku" }); multi_search_federated_1: |- - const _response = await _client.multiSearch({ + await client.multiSearch({ federation: {}, queries: [ { @@ -965,57 +798,42 @@ multi_search_federated_1: |- ], }); search_parameter_reference_locales_1: |- - const _response = await _client + await client .index("INDEX_NAME") .search("QUERY TEXT IN JAPANESE", { locales: ["jpn"] }); get_localized_attribute_settings_1: |- - const _localizedAttributes = await _client - .index("INDEX_NAME") - .getLocalizedAttributes(); + await client.index("INDEX_NAME").getLocalizedAttributes(); update_localized_attribute_settings_1: |- - const _task = await _client + await client .index("INDEX_NAME") .updateLocalizedAttributes([ { attributePatterns: ["*_ja"], locales: ["jpn"] }, - ]) - .waitTask(); + ]); reset_localized_attribute_settings_1: |- - const _task = await _client - .index("INDEX_NAME") - .resetLocalizedAttributes() - .waitTask(); + await client.index("INDEX_NAME").resetLocalizedAttributes(); get_facet_search_settings_1: |- - const _facetSearch = await _client.index("INDEX_NAME").getFacetSearch(); + await client.index("INDEX_NAME").getFacetSearch(); update_facet_search_settings_1: |- - const _task = await _client - .index("INDEX_NAME") - .updateFacetSearch(false) - .waitTask(); + await client.index("INDEX_NAME").updateFacetSearch(false); reset_facet_search_settings_1: |- - const _task = await _client.index("INDEX_NAME").resetFacetSearch().waitTask(); + await client.index("INDEX_NAME").resetFacetSearch(); get_prefix_search_settings_1: |- - const _prefixSearch = await _client.index("INDEX_NAME").getPrefixSearch(); + await client.index("INDEX_NAME").getPrefixSearch(); update_prefix_search_settings_1: |- - const _task = await _client - .index("INDEX_NAME") - .updatePrefixSearch("disabled") - .waitTask(); + await client.index("INDEX_NAME").updatePrefixSearch("disabled"); reset_prefix_search_settings_1: |- - const _task = await _client.index("INDEX_NAME").resetPrefixSearch().waitTask(); + await client.index("INDEX_NAME").resetPrefixSearch(); get_all_batches_1: |- - const _batches = await _client.batches.getBatches(); + await client.batches.getBatches(); get_batch_1: |- - const _batch = await _client.batches.getBatch(123); + await client.batches.getBatch(123); update_embedders_1: |- - const _task = await _client - .index("INDEX_NAME") - .updateEmbedders({ - default: { - source: "openAi", - apiKey: "OPEN_AI_API_KEY", - model: "text-embedding-3-small", - documentTemplate: - "A document titled '{{doc.title}}' whose description starts with {{doc.overview|truncatewords: 20}}", - }, - }) - .waitTask(); + await client.index("INDEX_NAME").updateEmbedders({ + default: { + source: "openAi", + apiKey: "OPEN_AI_API_KEY", + model: "text-embedding-3-small", + documentTemplate: + "A document titled '{{doc.title}}' whose description starts with {{doc.overview|truncatewords: 20}}", + }, + }); diff --git a/scripts/code-samples/from-yaml.js b/scripts/code-samples/from-yaml.js index e80b53122..5adc76fa2 100644 --- a/scripts/code-samples/from-yaml.js +++ b/scripts/code-samples/from-yaml.js @@ -8,7 +8,7 @@ import { const headerImport = 'import { MeiliSearch } from "meilisearch";\n'; const headerClientDeclaration = - 'const _client = new MeiliSearch({ host: "http://127.0.0.1:7700" });\n'; + 'const client = new MeiliSearch({ host: "http://127.0.0.1:7700" });\n'; const headerComment = "// Code below this line will be written to code samples YAML file\n" + '// For more information consult CONTRIBUTING.md "Tests and Linter" section\n' + @@ -33,19 +33,28 @@ for (const jsonFileToGenerate of jsonFilesToGenerate) { ); } +const clientVarRegExp = /(?<=const|let ).+(?= = new MeiliSearch\()/; + let generatedFileTally = 0; for (const { sampleName, code } of iterateCodeSamples()) { let header = ""; - // generate import if there isn't already one - if (!code.includes('from "meilisearch";\n')) { - header += headerImport; - } + const clientVarMatch = code.match(clientVarRegExp); + const clientVarLiteral = clientVarMatch?.[0] ?? "client"; + const clientVarUsageRegExp = new RegExp(`${clientVarLiteral}\\s*\\.`); + + // if there is client usage in the code sample + if (clientVarUsageRegExp.test(code)) { + // generate import if there isn't already one + if (!code.includes('from "meilisearch";\n')) { + header += headerImport; + } - // generate client declaration if there isn't already one - if (!code.includes("new MeiliSearch(")) { - header += headerClientDeclaration; + // generate client declaration if there isn't already one + if (clientVarMatch === null) { + header += headerClientDeclaration; + } } header += headerComment; From f44d8c055e69eadcc99b6abf23e1bd6fb5f03b0f Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Thu, 29 May 2025 14:57:53 +0300 Subject: [PATCH 11/13] Fix bugs, improve error messages and docs --- CONTRIBUTING.md | 8 ++++++-- scripts/code-samples/shared.js | 32 +++++++++++++++++++++++++++----- scripts/code-samples/to-yaml.js | 6 ++++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 701fd7cd4..892d62024 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,8 +72,12 @@ yarn build ### Code samples -In this repository code samples are linted and type checked. To achieve this we generate -TypeScript files from `.code-samples.meilisearch.yaml`, and vice-versa. +In this repository code samples are linted and type checked. To achieve this we +generate TypeScript files from `.code-samples.meilisearch.yaml`, and vice-versa. + +> [!WARNING] +> +> Each of these commands overwrite their target files, so use them carefully. ```bash # Generate files diff --git a/scripts/code-samples/shared.js b/scripts/code-samples/shared.js index dd5c0bc4a..922e4f3bb 100644 --- a/scripts/code-samples/shared.js +++ b/scripts/code-samples/shared.js @@ -14,22 +14,44 @@ export const generatedCodeSamplesDir = new URL( export const delimiter = "// -~-~-~-~-"; export function* iterateCodeSamples() { - const codeSamplesContents = readFileSync(codeSamplesPath); + let codeSamplesContents; + try { + codeSamplesContents = readFileSync(codeSamplesPath, { + encoding: "utf-8", + }); + } catch (error) { + if (error?.code !== "ENOENT") { + throw error; + } + + return; + } const codeSamples = load(codeSamplesContents, { filename: codeSamplesPath.href, onWarning: console.warn, }); + // YAML file is empty + if (codeSamples === undefined) { + return; + } + if (codeSamples === null || typeof codeSamples !== "object") { - throw new Error("expected `codeSamples` to be an object", { - cause: codeSamples, - }); + throw new Error( + `expected YAML contents to be of type \`Record\`; got ${String(codeSamples)}`, + { + cause: codeSamples, + }, + ); } for (const [sampleName, code] of Object.entries(codeSamples)) { if (typeof code !== "string") { - throw new Error("expected `code` to be a string", { cause: code }); + throw new Error( + `expected YAML contents to be of type \`Record\`; at ${sampleName} got ${String(code)}`, + { cause: code }, + ); } yield { sampleName, code }; diff --git a/scripts/code-samples/to-yaml.js b/scripts/code-samples/to-yaml.js index 7c427c901..03be665c9 100644 --- a/scripts/code-samples/to-yaml.js +++ b/scripts/code-samples/to-yaml.js @@ -78,8 +78,10 @@ const manipulatedCodeSamples = dirEntries .sort(({ index: indexA }, { index: indexB }) => indexA - indexB); // for every new code sample, place them at the end of the file instead of the start -while (manipulatedCodeSamples.at(0)?.index === -1) { - manipulatedCodeSamples.push(manipulatedCodeSamples.shift()); +if (manipulatedCodeSamples.some((v) => v.index !== -1)) { + while (manipulatedCodeSamples.at(0)?.index === -1) { + manipulatedCodeSamples.push(manipulatedCodeSamples.shift()); + } } const serializedCodeSamples = manipulatedCodeSamples From d7d11c842d300f44d4e9cf3d8fe70ed3e46a185e Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Thu, 29 May 2025 15:02:51 +0300 Subject: [PATCH 12/13] Misc --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 892d62024..f28f8844b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,8 +72,9 @@ yarn build ### Code samples -In this repository code samples are linted and type checked. To achieve this we -generate TypeScript files from `.code-samples.meilisearch.yaml`, and vice-versa. +In this repository, code samples are linted and type-checked. To achieve this, +we generate TypeScript files from `.code-samples.meilisearch.yaml` and vice +versa. > [!WARNING] > From 3f980f430892b2dc859b8ede24963ec1d00f4d90 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Thu, 29 May 2025 18:53:20 +0300 Subject: [PATCH 13/13] Update CONTRIBUTING.md --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f28f8844b..071853847 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,11 +81,11 @@ versa. > Each of these commands overwrite their target files, so use them carefully. ```bash -# Generate files +# Generate all the code sample files from YAML file yarn generate-code-sample-files -# Generate YAML file +# Generate YAML file from all the code sample files yarn generate-code-samples-yaml -# For maintainers to generate new code samples +# Generate all + new code sample files from YAML file yarn generate-code-sample-files new_sample_one new_sample_two ```