Functions for generating and manipulating URL-safe slugs, Ltree paths, and content-as-code paths.
/**
* Generate a URL-safe slug from a name
* Converts to lowercase, replaces special characters with hyphens
* Returns random 5-character string if result is empty
* @param name - Name to convert to slug
* @returns URL-safe slug string
*/
function generateSlug(name: string): string;
/**
* Convert slug to Ltree path format
* Handles backwards compatibility with hierarchy in slugs
* @param slug - Slug string
* @returns Ltree path with underscores instead of hyphens
*/
function getLtreePathFromSlug(slug: string): string;
/**
* Convert content-as-code path to Ltree path format
* @param path - Content-as-code path with hyphens and slashes
* @returns Ltree path with underscores and dots
*/
function getLtreePathFromContentAsCodePath(path: string): string;
/**
* Convert Ltree path to content-as-code path format
* @param path - Ltree path with underscores and dots
* @returns Content-as-code path with hyphens and slashes
*/
function getContentAsCodePathFromLtreePath(path: string): string;
/**
* Filter array of paths to only include deepest (leaf) paths
* Removes paths that are prefixes of other paths
* @param paths - Array of dot-separated paths
* @returns Array containing only the deepest paths
*/
function getDeepestPaths(paths: string[]): string[];
/**
* Check if one path is a sub-path of another
* @param path - Parent path
* @param subPath - Potential sub-path
* @returns true if subPath is a direct child of path
*/
function isSubPath(parentPath: string, childPath: string): boolean;import {
generateSlug,
getLtreePathFromSlug,
getLtreePathFromContentAsCodePath,
getContentAsCodePathFromLtreePath,
getDeepestPaths,
isSubPath,
} from '@lightdash/common';
// Generate URL-safe slug from name
const slug = generateSlug('My Dashboard Name!');
// Returns: "my-dashboard-name"
// More examples
const slug2 = generateSlug('Customer #123!!!'); // 'customer-123'
const slug3 = generateSlug(' '); // Returns random string like 'a7k2x'import {
getLtreePathFromSlug,
getLtreePathFromContentAsCodePath,
getContentAsCodePathFromLtreePath,
} from '@lightdash/common';
// Convert slug to ltree path (PostgreSQL ltree type)
const ltreePath = getLtreePathFromSlug('parent/child/item');
// Returns: "parent.child.item"
// Convert slug with hyphens
const ltreePath2 = getLtreePathFromSlug('my-dashboard');
// Returns: 'my_dashboard'
// Convert content-as-code path to ltree
const ltree = getLtreePathFromContentAsCodePath('dashboards/sales/overview.yml');
// Returns: "dashboards.sales.overview"
// Convert paths between formats
const ltreePath3 = getLtreePathFromContentAsCodePath('spaces/marketing/dashboards');
// Returns: 'spaces.marketing.dashboards'
// Convert ltree path back to content path
const contentPath = getContentAsCodePathFromLtreePath('dashboards.sales.overview');
// Returns: "dashboards/sales/overview"
const codePath = getContentAsCodePathFromLtreePath('spaces.marketing.dashboards');
// Returns: 'spaces/marketing/dashboards'import { getDeepestPaths, isSubPath } from '@lightdash/common';
// Get only the deepest (leaf) paths from a list
const paths = ['a.b', 'a.b.c', 'a.b.c.d', 'x.y'];
const deepest = getDeepestPaths(paths);
// Returns: ['a.b.c.d', 'x.y']
// Get deepest paths (filter out parent paths)
const paths2 = ['spaces', 'spaces.marketing', 'spaces.marketing.dashboards', 'spaces.sales'];
const deepest2 = getDeepestPaths(paths2);
// Returns: ['spaces.marketing.dashboards', 'spaces.sales']
// Check if one path is a subpath of another
if (isSubPath('a.b', 'a.b.c.d')) {
console.log('a.b.c.d is under a.b');
}
// Check sub-path relationships
const isChild = isSubPath('spaces.marketing', 'spaces.marketing.dashboards'); // true
const isNotChild = isSubPath('spaces.marketing', 'spaces.sales'); // falseimport { generateSlug } from '@lightdash/common';
// Create dashboard with URL-safe slug
const dashboard = {
name: 'Q4 2023 Sales Report',
slug: generateSlug('Q4 2023 Sales Report'), // 'q4-2023-sales-report'
url: `/dashboards/q4-2023-sales-report`
};import { getDeepestPaths, isSubPath } from '@lightdash/common';
// Find leaf spaces in a hierarchy
const spacePaths = [
'company',
'company.marketing',
'company.marketing.campaigns',
'company.sales',
'company.sales.reports'
];
const leafSpaces = getDeepestPaths(spacePaths);
// Returns: ['company.marketing.campaigns', 'company.sales.reports']
// Check if content belongs to a space
if (isSubPath('company.marketing', 'company.marketing.campaigns')) {
console.log('Campaigns space is under marketing');
}import {
getLtreePathFromContentAsCodePath,
getContentAsCodePathFromLtreePath
} from '@lightdash/common';
// Store file path in database as ltree
const filePath = 'dashboards/sales/weekly-report.yml';
const dbPath = getLtreePathFromContentAsCodePath(filePath);
// Store: 'dashboards.sales.weekly_report' in ltree column
// Convert back when reading
const storedPath = 'dashboards.sales.weekly_report';
const originalPath = getContentAsCodePathFromLtreePath(storedPath);
// Returns: 'dashboards/sales/weekly-report'