OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git / lib / reserved-names.js

66 lines · javascript ref:
/**
 * Reserved Names — single source of truth for route/name collision prevention
 *
 * All system route prefixes are listed here. Entity names (repos, groups,
 * namespaces, usernames) are validated against this list so collisions
 * with system routes are architecturally impossible.
 */

export const RESERVED_NAMES = new Set([
  // Top-level system routes
  'api',
  'admin',
  'profile',
  'search',
  'login',
  'deploy',
  'merge',
  'groups',
  'join',

  // Potential future system routes
  'static',
  'assets',
  'settings',
  'help',
  'new',
  'explore',
  'notifications',

  // Special characters / separators
  '-',
  '_'
])

export const NAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/

/**
 * Validate an entity name (repo, group, namespace, username).
 * Must be URL-safe slug: lowercase a-z, 0-9, hyphens. Not reserved.
 * @param {string} name
 * @returns {{ valid: boolean, error?: string }}
 */
export function validateName (name) {
  if (!name || typeof name !== 'string') {
    return { valid: false, error: 'Name is required' }
  }

  if (name.length < 1 || name.length > 64) {
    return { valid: false, error: 'Name must be 1-64 characters' }
  }

  if (!NAME_REGEX.test(name)) {
    return { valid: false, error: 'Name must be lowercase alphanumeric with hyphens (no leading/trailing hyphens)' }
  }

  if (name.includes('--')) {
    return { valid: false, error: 'Name must not contain consecutive hyphens' }
  }

  if (RESERVED_NAMES.has(name)) {
    return { valid: false, error: `Name "${name}" is reserved` }
  }

  return { valid: true }
}