wovvmap-search-core
v1.0.8
Published
A production-ready, cross-platform Smart Search package.
Downloads
1,009
Maintainers
Readme
wovvmap-search-core 🚀
A high-performance, production-ready Smart Search utility for JavaScript and TypeScript apps. It features a robust internal scoring system including exact matches, prefix matches, token-overlap matching, and Enterprise-Grade Smart Fuzzy (typo-tolerant) searching!
Whether you're building a React frontend, a React Native mobile app, or a Node.js backend, this package helps you build powerful search bars with just a few lines of code.
📦 Installation
npm install wovvmap-search-core
# or
yarn add wovvmap-search-core✨ Features
- No External Dependencies: 100% pure TypeScript/JavaScript. Extremely lightweight and fast.
- Smart Typo Tolerance (Smart Vowel Levenshtein): Automatically forgives spelling mistakes with advanced vowel-aware weightings (e.g., searching "feson" perfectly finds "fashion", but correctly penalizes consonants).
- First-Letter Strictness & Stricter Prefix Rules: Reduces false positives by 95% by ensuring typos aren't completely random words (e.g., "feson" doesn't falsely match "person", and short words like "food" don't wildly match "footwear").
- Weighted Fields & Token-wise AND Logic: Give more importance to specific fields. The engine strictly ensures all words typed have some presence across your weighted fields.
- Advanced Multi-Mode Sorting: Sort results inherently by
relevance,asc,desc, or intelligentfloor_proximityout-of-the-box. - Match Tracing Metadata: Returns exactly which words triggered the search result (perfect for UI Highlighting).
- TypeScript Support: Full auto-complete and strict type safety directly out of the box.
- Isomorphic: Runs identically dynamically in the Browser (React, Vue) and on the Server (Node.js).
🚀 Quick Start (For Beginners)
Here is a very simple step-by-step example to get you started in 2 minutes!
1. Prepare your data
Let's say you have an array of objects you want a user to search through.
import { smartSearch } from "wovvmap-search-core";
// Your database or list of products/stores
const myStores = [
{ id: 1, name: "Nike Store", category: "Shoes", tags: ["sports", "running"] },
{ id: 2, name: "Apple Store", category: "Electronics", tags: ["phones", "laptops"] },
{ id: 3, name: "Zara", category: "Clothing", tags: ["fashion", "dresses"] }
];2. Configure the Search Engine
You need to tell the engine where to look and how important each field is by assigning a weight. Higher weights mean more points!
const options = {
// Fields to search in your objects
fields: [
{ path: "name", weight: 10 }, // 'name' is very important (Weight: 10)
{ path: "category", weight: 5 }, // 'category' is less important (Weight: 5)
{ path: "tags", weight: 8, isArray: true } // 'tags' is an array of keywords
],
limit: 10, // Return a maximum of 10 results
typoToleranceLevel: 2, // Typo tolerance level
includeMeta: true // Return the exact score and triggered words!
};3. Run the search
Whenever the user types via an input search bar, just pass that string into the smartSearch function:
const userQuery = "feson"; // Notice the spelling mistake!
const results = smartSearch(userQuery, myStores, options);
console.log(results);
/* Output automatically identifies the spelling mistake and smartly returns:
[
{
id: 3,
name: 'Zara',
category: 'Clothing',
tags: ['fashion', 'dresses'],
__smartSearch: {
score: 1250,
matchedWords: ["fashion"] // Tells your UI exactly what triggered it!
}
}
]
*/🛠 Advanced Options
The SearchOptions object gives you complete control over the engine:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| fields | FieldConfig[] | Required | Array defining which object keys to search and their point multiplier (weight). |
| limit | number | undefined | Maximum number of matched items to return in the array. |
| typoToleranceLevel | number | 2 | Determines how many typos are allowed via Smart Levenshtein logic. 0 means strict exact text mapping only. |
| minScore | number | 0 | Minimum score threshold to filter out very weak matches. (Recommended: 10-20 to hide false positives). |
| returnAllOnEmpty | boolean | true | If true, returns the entire limit of items when the search text is empty. If false, returns an empty array. |
| minSearchCharLength| number| 1 | The minimum number of characters required for a search to trigger. |
| includeMeta| boolean| false | If true, search results will include a hidden __smartSearch property containing the match score and matchedWords array! |
| sortBy | string | 'relevance' | Determines sorting mode: 'relevance', 'asc', 'desc', or 'floor_proximity'. |
| floorSecondarySortBy| string | 'relevance' | Tie-breaker when multiple items are on the exact same floor. 'relevance', 'asc', or 'desc'. |
| sortField | string | undefined | The object path to use when sorting asc or desc (e.g., "LocationName.text"). |
| activeFloor | number | undefined | The user's current floor. Used contextually when sortBy is 'floor_proximity'. |
| floorField | string | undefined | The object path to the floor numerical value (e.g. "z"). |
🎯 Example: Intelligent Floor Proximity Sorting
If your user is inside a mall on Floor 3, you want to show search results for Floor 3 first, then 2, 1, 0, and then floors above them 4, 5.
const options = {
fields: [{ path: "name", weight: 10 }],
sortBy: "floor_proximity",
floorSecondarySortBy: "relevance", // If 2 stores are on Floor 3, show the best keyword match first
activeFloor: 3,
floorField: "floor" // looks for item.floor
};
const results = smartSearch("shoes", myStores, options);🧠 How the Scoring Works internally
When you search for something, the engine checks every record and awards base points using Token-Wise Exponential Scoring:
- Exact Match: Highest Priority (Base multiplier 10,000)
- Starts With (Prefix): High Priority (Base multiplier 2,000)
- Contains Substring: Medium Priority (Base multiplier 500)
- Smart Fuzzy Typos: Exponential Priority. Bad matches get harshly penalized (e.g. 100 points), while near-perfect vowel typos get huge rewards (e.g. 1500+ points).
The base points are then multiplied by the weight you defined for that field. The results are ultimately computed and automatically sorted from highest points to lowest points!
For deeper understanding on the Architecture, Read the HOW_IT_WORKS.md guide.
💡 Pro Tip for React Developers
Use a useMemo hook to run your search so it calculates efficiently and doesn't freeze your UI during re-renders:
const searchResults = useMemo(() => {
if (!searchText) return myData;
return smartSearch(searchText, myData, options);
}, [searchText, myData]);Maintained with ❤️ by Wovvmap
