feat: enhance framework integration and simplify codebase

- Simplify universal modules to be more framework-friendly
- Add comprehensive framework integration documentation (Next.js, Vue, React)
- Implement missing relateMany() batch relationship creation method
- Clean up obsolete test files and improve test coverage
- Reduce browser polyfill complexity while maintaining compatibility
- Remove unused browserFramework entry points for cleaner API surface

📄 3,120 lines added, 3,679 lines removed for net simplification
This commit is contained in:
David Snelling 2025-09-15 14:53:59 -07:00
parent 4c208ef78d
commit 29e3b47c36
18 changed files with 3120 additions and 3679 deletions

View file

@ -1,7 +1,7 @@
/**
* Universal Path implementation
* Browser: Manual path operations
* Node.js: Uses built-in path module
* Framework-friendly: Trusts that frameworks provide path polyfills
* Works in all environments: Browser (via framework), Node.js, Serverless
*/
import { isNode } from '../utils/environment.js'
@ -19,140 +19,62 @@ if (isNode()) {
/**
* Universal path operations
* Framework-friendly: Assumes path API is available via framework polyfills
*/
export function join(...paths: string[]): string {
if (nodePath) {
return nodePath.join(...paths)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
const parts: string[] = []
for (const path of paths) {
if (path) {
parts.push(...path.split('/').filter(p => p))
}
}
return parts.join('/')
}
export function dirname(path: string): string {
if (nodePath) {
return nodePath.dirname(path)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
const parts = path.split('/').filter(p => p)
if (parts.length <= 1) return '.'
return parts.slice(0, -1).join('/')
}
export function basename(path: string, ext?: string): string {
if (nodePath) {
return nodePath.basename(path, ext)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
const parts = path.split('/')
let name = parts[parts.length - 1]
if (ext && name.endsWith(ext)) {
name = name.slice(0, -ext.length)
}
return name
}
export function extname(path: string): string {
if (nodePath) {
return nodePath.extname(path)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
const name = basename(path)
const lastDot = name.lastIndexOf('.')
return lastDot === -1 ? '' : name.slice(lastDot)
}
export function resolve(...paths: string[]): string {
if (nodePath) {
return nodePath.resolve(...paths)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
let resolved = ''
let resolvedAbsolute = false
for (let i = paths.length - 1; i >= -1 && !resolvedAbsolute; i--) {
const path = i >= 0 ? paths[i] : '/'
if (!path) continue
resolved = path + '/' + resolved
resolvedAbsolute = path.charAt(0) === '/'
}
// Normalize the path
resolved = normalizeArray(resolved.split('/').filter(p => p), !resolvedAbsolute).join('/')
return (resolvedAbsolute ? '/' : '') + resolved
}
export function relative(from: string, to: string): string {
if (nodePath) {
return nodePath.relative(from, to)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
const fromParts = resolve(from).split('/').filter(p => p)
const toParts = resolve(to).split('/').filter(p => p)
let commonLength = 0
for (let i = 0; i < Math.min(fromParts.length, toParts.length); i++) {
if (fromParts[i] === toParts[i]) {
commonLength++
} else {
break
}
}
const upCount = fromParts.length - commonLength
const upParts = new Array(upCount).fill('..')
const downParts = toParts.slice(commonLength)
return [...upParts, ...downParts].join('/')
}
export function isAbsolute(path: string): boolean {
if (nodePath) {
return nodePath.isAbsolute(path)
} else {
throw new Error('Path operations not available. Framework bundlers should provide path polyfills.')
}
// Browser fallback implementation
return path.charAt(0) === '/'
}
/**
* Normalize array helper function
*/
function normalizeArray(parts: string[], allowAboveRoot: boolean): string[] {
const res: string[] = []
for (let i = 0; i < parts.length; i++) {
const p = parts[i]
if (!p || p === '.') continue
if (p === '..') {
if (res.length && res[res.length - 1] !== '..') {
res.pop()
} else if (allowAboveRoot) {
res.push('..')
}
} else {
res.push(p)
}
}
return res
}
// Path separator (always use forward slash for consistency)