style: format code with biome linter across multiple packages
This commit is contained in:
@@ -1,41 +1,41 @@
|
||||
{
|
||||
"name": "@nontara/server",
|
||||
"main": "index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"check-types": "tsc -b",
|
||||
"compile": "bun build --compile --minify --sourcemap --bytecode ./src/main.ts --outfile server",
|
||||
"dev": "bun run --watch src/main.ts",
|
||||
"start": "bun run dist/main.js",
|
||||
"db:local": "turso dev --db-file local.db",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"auth:generate": "bunx --bun @better-auth/cli generate --config ./src/lib/auth.ts --output ./src/db/schema/auth.ts",
|
||||
"auth:migrate": "bunx --bun @better-auth/cli migrate --config ./src/lib/auth.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hono/trpc-server": "^0.4.0",
|
||||
"@libsql/client": "^0.15.9",
|
||||
"@nontara/language-codes": "workspace:*",
|
||||
"@trpc/client": "^11.5.0",
|
||||
"@trpc/server": "^11.5.0",
|
||||
"better-auth": "^1.3.10",
|
||||
"consola": "^3.4.2",
|
||||
"dotenv": "^17.2.1",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"hono": "^4.8.2",
|
||||
"zod": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@better-auth/cli": "^1.3.11",
|
||||
"@types/bun": "^1.2.6",
|
||||
"@types/fluent-ffmpeg": "^2.1.27",
|
||||
"drizzle-kit": "^0.31.5",
|
||||
"tsdown": "^0.15.1",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
"name": "@nontara/server",
|
||||
"main": "index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"check-types": "tsc -b",
|
||||
"compile": "bun build --compile --minify --sourcemap --bytecode ./src/main.ts --outfile server",
|
||||
"dev": "bun run --watch src/main.ts",
|
||||
"start": "bun run dist/main.js",
|
||||
"db:local": "turso dev --db-file local.db",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"auth:generate": "bunx --bun @better-auth/cli generate --config ./src/lib/auth.ts --output ./src/db/schema/auth.ts",
|
||||
"auth:migrate": "bunx --bun @better-auth/cli migrate --config ./src/lib/auth.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hono/trpc-server": "^0.4.0",
|
||||
"@libsql/client": "^0.15.9",
|
||||
"@nontara/language-codes": "workspace:*",
|
||||
"@trpc/client": "^11.5.0",
|
||||
"@trpc/server": "^11.5.0",
|
||||
"better-auth": "^1.3.10",
|
||||
"consola": "^3.4.2",
|
||||
"dotenv": "^17.2.1",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"hono": "^4.8.2",
|
||||
"zod": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@better-auth/cli": "^1.3.11",
|
||||
"@types/bun": "^1.2.6",
|
||||
"@types/fluent-ffmpeg": "^2.1.27",
|
||||
"drizzle-kit": "^0.31.5",
|
||||
"tsdown": "^0.15.1",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
import * as schema from "./schema";
|
||||
|
||||
export const database = drizzle(process.env.DATABASE_FILENAME ?? "database.db", {
|
||||
schema: schema,
|
||||
});
|
||||
export const database = drizzle(
|
||||
process.env.DATABASE_FILENAME ?? "database.db",
|
||||
{
|
||||
schema: schema,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const user = sqliteTable("user", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: integer("email_verified", { mode: "boolean" })
|
||||
.default(false)
|
||||
.notNull(),
|
||||
image: text("image"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
username: text("username").unique(),
|
||||
displayUsername: text("display_username"),
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: integer("email_verified", { mode: "boolean" })
|
||||
.default(false)
|
||||
.notNull(),
|
||||
image: text("image"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
username: text("username").unique(),
|
||||
displayUsername: text("display_username"),
|
||||
});
|
||||
|
||||
export const session = sqliteTable("session", {
|
||||
id: text("id").primaryKey(),
|
||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||
token: text("token").notNull().unique(),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
id: text("id").primaryKey(),
|
||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||
token: text("token").notNull().unique(),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
});
|
||||
|
||||
export const account = sqliteTable("account", {
|
||||
id: text("id").primaryKey(),
|
||||
accountId: text("account_id").notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
accessToken: text("access_token"),
|
||||
refreshToken: text("refresh_token"),
|
||||
idToken: text("id_token"),
|
||||
accessTokenExpiresAt: integer("access_token_expires_at", {
|
||||
mode: "timestamp",
|
||||
}),
|
||||
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
||||
mode: "timestamp",
|
||||
}),
|
||||
scope: text("scope"),
|
||||
password: text("password"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
id: text("id").primaryKey(),
|
||||
accountId: text("account_id").notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
accessToken: text("access_token"),
|
||||
refreshToken: text("refresh_token"),
|
||||
idToken: text("id_token"),
|
||||
accessTokenExpiresAt: integer("access_token_expires_at", {
|
||||
mode: "timestamp",
|
||||
}),
|
||||
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
||||
mode: "timestamp",
|
||||
}),
|
||||
scope: text("scope"),
|
||||
password: text("password"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const verification = sqliteTable("verification", {
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
value: text("value").notNull(),
|
||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
value: text("value").notNull(),
|
||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||
createdAt: integer("created_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" })
|
||||
.$defaultFn(() => new Date())
|
||||
.$onUpdate(() => new Date())
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
||||
import {
|
||||
integer,
|
||||
sqliteTable,
|
||||
text,
|
||||
uniqueIndex,
|
||||
} from "drizzle-orm/sqlite-core";
|
||||
import type { LibraryType } from "./enums";
|
||||
|
||||
export const libraryFolders = sqliteTable(
|
||||
"library_folders",
|
||||
{
|
||||
id: integer("id").primaryKey().$defaultFn(() => {
|
||||
return Math.floor(100000 + Math.random() * 99999);
|
||||
}),
|
||||
id: integer("id")
|
||||
.primaryKey()
|
||||
.$defaultFn(() => {
|
||||
return Math.floor(100000 + Math.random() * 99999);
|
||||
}),
|
||||
name: text("name").notNull(), // "Movies", "TV Shows"
|
||||
type: text("type").$type<LibraryType>().notNull(), // "MOVIE" | "SERIES"
|
||||
path: text("path").notNull(), // absolute/mount path
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
index,
|
||||
integer,
|
||||
sqliteTable,
|
||||
text,
|
||||
} from "drizzle-orm/sqlite-core";
|
||||
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
|
||||
// ----- PEOPLE (base table for actors, directors, crew, etc.) -----
|
||||
export const people = sqliteTable(
|
||||
@@ -36,4 +31,4 @@ export const people = sqliteTable(
|
||||
index("idx_people_tmdb").on(t.tmdbId),
|
||||
index("idx_people_imdb").on(t.imdbId),
|
||||
],
|
||||
);
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@nontora/tmdb-metadata",
|
||||
"module": "index.ts",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@nontara/server": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"tmdb-ts": "^2.0.2"
|
||||
}
|
||||
}
|
||||
"name": "@nontora/tmdb-metadata",
|
||||
"module": "index.ts",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@nontara/server": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"tmdb-ts": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
|
||||
54
package.json
54
package.json
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"name": "nontara",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*",
|
||||
"extensions/*"
|
||||
],
|
||||
"scripts": {
|
||||
"check": "biome check --write .",
|
||||
"dev": "turbo dev",
|
||||
"build": "turbo build",
|
||||
"check-types": "turbo check-types",
|
||||
"dev:native": "turbo -F native dev",
|
||||
"dev:web": "turbo -F web dev",
|
||||
"dev:server": "turbo -F server dev",
|
||||
"db:push": "turbo -F server db:push",
|
||||
"db:studio": "turbo -F server db:studio",
|
||||
"db:generate": "turbo -F server db:generate",
|
||||
"db:migrate": "turbo -F server db:migrate"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"turbo": "^2.5.4",
|
||||
"@biomejs/biome": "^2.2.0"
|
||||
},
|
||||
"packageManager": "bun@1.2.22"
|
||||
"name": "nontara",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*",
|
||||
"extensions/*"
|
||||
],
|
||||
"scripts": {
|
||||
"check": "biome check --write .",
|
||||
"dev": "turbo dev",
|
||||
"build": "turbo build",
|
||||
"check-types": "turbo check-types",
|
||||
"dev:native": "turbo -F native dev",
|
||||
"dev:web": "turbo -F web dev",
|
||||
"dev:server": "turbo -F server dev",
|
||||
"db:push": "turbo -F server db:push",
|
||||
"db:studio": "turbo -F server db:studio",
|
||||
"db:generate": "turbo -F server db:generate",
|
||||
"db:migrate": "turbo -F server db:migrate"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"turbo": "^2.5.4",
|
||||
"@biomejs/biome": "^2.2.0"
|
||||
},
|
||||
"packageManager": "bun@1.2.22"
|
||||
}
|
||||
|
||||
@@ -1,132 +1,132 @@
|
||||
import { type Language, languages } from "./language-list";
|
||||
|
||||
/**
|
||||
* Valid language code types that can be used for filtering
|
||||
*/
|
||||
export type LanguageCodeType = "1" | "2" | "2T" | "2B" | "3" | 1 | 2 | 3;
|
||||
|
||||
/**
|
||||
* Valid criteria for searching languages
|
||||
*/
|
||||
export type LanguageCriteria = keyof Language;
|
||||
|
||||
// Re-export the Language interface for convenience
|
||||
export type { Language } from "./language-list";
|
||||
|
||||
/**
|
||||
* Returns all available languages
|
||||
* @returns Array of all language objects
|
||||
* @example
|
||||
* ```typescript
|
||||
* const allLangs = allLanguages();
|
||||
* console.log(allLangs.length); // 184
|
||||
* ```
|
||||
*/
|
||||
export function allLanguages(): readonly Language[] {
|
||||
return languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a language exists based on given criteria and value
|
||||
* @param criteria - The property to search by (e.g., 'name', '1', '2', etc.)
|
||||
* @param value - The value to search for
|
||||
* @returns True if language exists, false otherwise
|
||||
* @example
|
||||
* ```typescript
|
||||
* const exists = hasLanguage('1', 'en'); // true
|
||||
* const notExists = hasLanguage('name', 'Klingon'); // false
|
||||
* ```
|
||||
*/
|
||||
export function hasLanguage(
|
||||
criteria: LanguageCriteria,
|
||||
value: string,
|
||||
): boolean {
|
||||
return findBy(criteria, value) !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all language codes of a specific type
|
||||
* @param type - The code type to retrieve ('1', '2', '2T', '2B', '3', or numeric equivalents)
|
||||
* @returns Array of language codes, or undefined if invalid type
|
||||
* @example
|
||||
* ```typescript
|
||||
* const iso6391Codes = getCodes('1'); // ['ab', 'aa', 'af', ...]
|
||||
* const iso6392Codes = getCodes('2'); // ['abk', 'aar', 'afr', ...]
|
||||
* ```
|
||||
*/
|
||||
export function getCodes(type: LanguageCodeType): string[] | undefined {
|
||||
if (!isValidType(type)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const stringType = String(type) as keyof Language;
|
||||
return languages.map((language: Language) => language[stringType]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all language names (English or local)
|
||||
* @param useLocal - If true, returns local names; if false, returns English names
|
||||
* @returns Array of language names
|
||||
* @example
|
||||
* ```typescript
|
||||
* const englishNames = getNames(false); // ['Abkhaz', 'Afar', 'Afrikaans', ...]
|
||||
* const localNames = getNames(true); // ['Аҧсуа', 'Afaraf', 'Afrikaans', ...]
|
||||
* ```
|
||||
*/
|
||||
export function getNames(useLocal = false): string[] {
|
||||
return languages.map((language: Language) =>
|
||||
useLocal ? language.local : language.name,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a language by specific criteria and value
|
||||
* @param criteria - The property to search by
|
||||
* @param value - The value to search for
|
||||
* @returns The matching language object, or undefined if not found
|
||||
* @example
|
||||
* ```typescript
|
||||
* const english = findBy('1', 'en');
|
||||
* // { name: 'English', local: 'English', '1': 'en', '2': 'eng', ... }
|
||||
*
|
||||
* const spanish = findBy('name', 'Spanish');
|
||||
* // { name: 'Spanish', local: 'Español', '1': 'es', '2': 'spa', ... }
|
||||
* ```
|
||||
*/
|
||||
export function findBy(
|
||||
criteria: LanguageCriteria,
|
||||
value: string,
|
||||
): Language | undefined {
|
||||
return languages.find((language: Language) => language[criteria] === value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if the given type is a valid language code type
|
||||
* @param type - The type to validate
|
||||
* @returns True if valid, false otherwise
|
||||
* @internal
|
||||
*/
|
||||
function isValidType(type: unknown): type is LanguageCodeType {
|
||||
const validTypes: (string | number)[] = [1, 2, 3, "1", "2", "2B", "2T", "3"];
|
||||
return validTypes.includes(type as string | number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API object containing all language utility functions
|
||||
* @deprecated Use named exports instead
|
||||
*/
|
||||
export const langs = {
|
||||
/** @deprecated Use allLanguages() instead */
|
||||
all: allLanguages,
|
||||
/** @deprecated Use hasLanguage() instead */
|
||||
has: hasLanguage,
|
||||
/** @deprecated Use getCodes() instead */
|
||||
codes: getCodes,
|
||||
/** @deprecated Use getNames() instead */
|
||||
names: getNames,
|
||||
/** @deprecated Use findBy() instead */
|
||||
where: findBy,
|
||||
} as const;
|
||||
|
||||
// Default export for backward compatibility
|
||||
export default langs;
|
||||
import { type Language, languages } from "./language-list";
|
||||
|
||||
/**
|
||||
* Valid language code types that can be used for filtering
|
||||
*/
|
||||
export type LanguageCodeType = "1" | "2" | "2T" | "2B" | "3" | 1 | 2 | 3;
|
||||
|
||||
/**
|
||||
* Valid criteria for searching languages
|
||||
*/
|
||||
export type LanguageCriteria = keyof Language;
|
||||
|
||||
// Re-export the Language interface for convenience
|
||||
export type { Language } from "./language-list";
|
||||
|
||||
/**
|
||||
* Returns all available languages
|
||||
* @returns Array of all language objects
|
||||
* @example
|
||||
* ```typescript
|
||||
* const allLangs = allLanguages();
|
||||
* console.log(allLangs.length); // 184
|
||||
* ```
|
||||
*/
|
||||
export function allLanguages(): readonly Language[] {
|
||||
return languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a language exists based on given criteria and value
|
||||
* @param criteria - The property to search by (e.g., 'name', '1', '2', etc.)
|
||||
* @param value - The value to search for
|
||||
* @returns True if language exists, false otherwise
|
||||
* @example
|
||||
* ```typescript
|
||||
* const exists = hasLanguage('1', 'en'); // true
|
||||
* const notExists = hasLanguage('name', 'Klingon'); // false
|
||||
* ```
|
||||
*/
|
||||
export function hasLanguage(
|
||||
criteria: LanguageCriteria,
|
||||
value: string,
|
||||
): boolean {
|
||||
return findBy(criteria, value) !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all language codes of a specific type
|
||||
* @param type - The code type to retrieve ('1', '2', '2T', '2B', '3', or numeric equivalents)
|
||||
* @returns Array of language codes, or undefined if invalid type
|
||||
* @example
|
||||
* ```typescript
|
||||
* const iso6391Codes = getCodes('1'); // ['ab', 'aa', 'af', ...]
|
||||
* const iso6392Codes = getCodes('2'); // ['abk', 'aar', 'afr', ...]
|
||||
* ```
|
||||
*/
|
||||
export function getCodes(type: LanguageCodeType): string[] | undefined {
|
||||
if (!isValidType(type)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const stringType = String(type) as keyof Language;
|
||||
return languages.map((language: Language) => language[stringType]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all language names (English or local)
|
||||
* @param useLocal - If true, returns local names; if false, returns English names
|
||||
* @returns Array of language names
|
||||
* @example
|
||||
* ```typescript
|
||||
* const englishNames = getNames(false); // ['Abkhaz', 'Afar', 'Afrikaans', ...]
|
||||
* const localNames = getNames(true); // ['Аҧсуа', 'Afaraf', 'Afrikaans', ...]
|
||||
* ```
|
||||
*/
|
||||
export function getNames(useLocal = false): string[] {
|
||||
return languages.map((language: Language) =>
|
||||
useLocal ? language.local : language.name,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a language by specific criteria and value
|
||||
* @param criteria - The property to search by
|
||||
* @param value - The value to search for
|
||||
* @returns The matching language object, or undefined if not found
|
||||
* @example
|
||||
* ```typescript
|
||||
* const english = findBy('1', 'en');
|
||||
* // { name: 'English', local: 'English', '1': 'en', '2': 'eng', ... }
|
||||
*
|
||||
* const spanish = findBy('name', 'Spanish');
|
||||
* // { name: 'Spanish', local: 'Español', '1': 'es', '2': 'spa', ... }
|
||||
* ```
|
||||
*/
|
||||
export function findBy(
|
||||
criteria: LanguageCriteria,
|
||||
value: string,
|
||||
): Language | undefined {
|
||||
return languages.find((language: Language) => language[criteria] === value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if the given type is a valid language code type
|
||||
* @param type - The type to validate
|
||||
* @returns True if valid, false otherwise
|
||||
* @internal
|
||||
*/
|
||||
function isValidType(type: unknown): type is LanguageCodeType {
|
||||
const validTypes: (string | number)[] = [1, 2, 3, "1", "2", "2B", "2T", "3"];
|
||||
return validTypes.includes(type as string | number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API object containing all language utility functions
|
||||
* @deprecated Use named exports instead
|
||||
*/
|
||||
export const langs = {
|
||||
/** @deprecated Use allLanguages() instead */
|
||||
all: allLanguages,
|
||||
/** @deprecated Use hasLanguage() instead */
|
||||
has: hasLanguage,
|
||||
/** @deprecated Use getCodes() instead */
|
||||
codes: getCodes,
|
||||
/** @deprecated Use getNames() instead */
|
||||
names: getNames,
|
||||
/** @deprecated Use findBy() instead */
|
||||
where: findBy,
|
||||
} as const;
|
||||
|
||||
// Default export for backward compatibility
|
||||
export default langs;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "@nontara/language-codes",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
"name": "@nontara/language-codes",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +1,115 @@
|
||||
/**
|
||||
* Test file for the lang-codes package
|
||||
* This file demonstrates the usage and validates the functionality
|
||||
*/
|
||||
|
||||
import {
|
||||
allLanguages,
|
||||
hasLanguage,
|
||||
getCodes,
|
||||
getNames,
|
||||
findBy,
|
||||
type Language,
|
||||
type LanguageCodeType,
|
||||
type LanguageCriteria,
|
||||
langs // Legacy API
|
||||
} from "./index";
|
||||
|
||||
function runTests() {
|
||||
console.log("🧪 Testing lang-codes package...\n");
|
||||
|
||||
// Test 1: allLanguages()
|
||||
console.log("1️⃣ Testing allLanguages()");
|
||||
const allLangs = allLanguages();
|
||||
console.log(` ✅ Total languages: ${allLangs.length}`);
|
||||
console.log(` ✅ First language: ${allLangs[0].name} (${allLangs[0]['1']})`);
|
||||
console.log();
|
||||
|
||||
// Test 2: hasLanguage()
|
||||
console.log("2️⃣ Testing hasLanguage()");
|
||||
console.log(` ✅ Has English (ISO 639-1): ${hasLanguage('1', 'en')}`);
|
||||
console.log(` ✅ Has Spanish (name): ${hasLanguage('name', 'Spanish')}`);
|
||||
console.log(` ✅ Has Klingon (name): ${hasLanguage('name', 'Klingon')}`);
|
||||
console.log();
|
||||
|
||||
// Test 3: getCodes()
|
||||
console.log("3️⃣ Testing getCodes()");
|
||||
const iso1Codes = getCodes('1');
|
||||
const iso2Codes = getCodes('2');
|
||||
const invalidCodes = getCodes('invalid' as LanguageCodeType);
|
||||
console.log(` ✅ ISO 639-1 codes count: ${iso1Codes?.length}`);
|
||||
console.log(` ✅ ISO 639-2 codes count: ${iso2Codes?.length}`);
|
||||
console.log(` ✅ Invalid type returns: ${invalidCodes}`);
|
||||
console.log(` ✅ Sample ISO 639-1 codes: ${iso1Codes?.slice(0, 5).join(', ')}`);
|
||||
console.log();
|
||||
|
||||
// Test 4: getNames()
|
||||
console.log("4️⃣ Testing getNames()");
|
||||
const englishNames = getNames(false);
|
||||
const localNames = getNames(true);
|
||||
console.log(` ✅ English names count: ${englishNames.length}`);
|
||||
console.log(` ✅ Local names count: ${localNames.length}`);
|
||||
console.log(` ✅ Sample English names: ${englishNames.slice(0, 3).join(', ')}`);
|
||||
console.log(` ✅ Sample local names: ${localNames.slice(0, 3).join(', ')}`);
|
||||
console.log();
|
||||
|
||||
// Test 5: findBy()
|
||||
console.log("5️⃣ Testing findBy()");
|
||||
const english = findBy('1', 'en');
|
||||
const spanish = findBy('name', 'Spanish');
|
||||
const french = findBy('local', 'Français');
|
||||
const notFound = findBy('name', 'Klingon');
|
||||
|
||||
console.log(` ✅ English by ISO 639-1: ${english?.name} (${english?.local})`);
|
||||
console.log(` ✅ Spanish by name: ${spanish?.name} (${spanish?.['1']})`);
|
||||
console.log(` ✅ French by local name: ${french?.name} (${french?.['1']})`);
|
||||
console.log(` ✅ Klingon (not found): ${notFound}`);
|
||||
console.log();
|
||||
|
||||
// Test 6: Legacy API
|
||||
console.log("6️⃣ Testing Legacy API");
|
||||
const legacyAll = langs.all();
|
||||
const legacyHas = langs.has('1', 'de');
|
||||
const legacyCodes = langs.codes('2');
|
||||
const legacyNames = langs.names(false);
|
||||
const legacyWhere = langs.where('name', 'German');
|
||||
|
||||
console.log(` ✅ Legacy all() count: ${legacyAll.length}`);
|
||||
console.log(` ✅ Legacy has() German: ${legacyHas}`);
|
||||
console.log(` ✅ Legacy codes() count: ${legacyCodes?.length}`);
|
||||
console.log(` ✅ Legacy names() count: ${legacyNames.length}`);
|
||||
console.log(` ✅ Legacy where() German: ${legacyWhere?.name} (${legacyWhere?.['1']})`);
|
||||
console.log();
|
||||
|
||||
// Test 7: Type validation
|
||||
console.log("7️⃣ Testing Type Safety");
|
||||
const language: Language | undefined = findBy('name', 'English');
|
||||
if (language) {
|
||||
// Type-safe access to language properties
|
||||
const name: string = language.name;
|
||||
const local: string = language.local;
|
||||
const iso1: string = language['1'];
|
||||
const iso2: string = language['2'];
|
||||
console.log(` ✅ Type-safe access: ${name} (${iso1}) - ${local}`);
|
||||
}
|
||||
|
||||
// Test various code types
|
||||
const codeTypes: LanguageCodeType[] = ['1', '2', '2B', '2T', '3', 1, 2, 3];
|
||||
console.log(` ✅ Valid code types: ${codeTypes.join(', ')}`);
|
||||
console.log();
|
||||
|
||||
console.log("🎉 All tests completed successfully!");
|
||||
}
|
||||
|
||||
// Run the tests
|
||||
runTests();
|
||||
/**
|
||||
* Test file for the lang-codes package
|
||||
* This file demonstrates the usage and validates the functionality
|
||||
*/
|
||||
|
||||
import {
|
||||
allLanguages,
|
||||
findBy,
|
||||
getCodes,
|
||||
getNames,
|
||||
hasLanguage,
|
||||
type Language,
|
||||
type LanguageCodeType,
|
||||
type LanguageCriteria,
|
||||
langs, // Legacy API
|
||||
} from "./index";
|
||||
|
||||
function runTests() {
|
||||
console.log("🧪 Testing lang-codes package...\n");
|
||||
|
||||
// Test 1: allLanguages()
|
||||
console.log("1️⃣ Testing allLanguages()");
|
||||
const allLangs = allLanguages();
|
||||
console.log(` ✅ Total languages: ${allLangs.length}`);
|
||||
console.log(
|
||||
` ✅ First language: ${allLangs[0].name} (${allLangs[0]["1"]})`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
// Test 2: hasLanguage()
|
||||
console.log("2️⃣ Testing hasLanguage()");
|
||||
console.log(` ✅ Has English (ISO 639-1): ${hasLanguage("1", "en")}`);
|
||||
console.log(` ✅ Has Spanish (name): ${hasLanguage("name", "Spanish")}`);
|
||||
console.log(` ✅ Has Klingon (name): ${hasLanguage("name", "Klingon")}`);
|
||||
console.log();
|
||||
|
||||
// Test 3: getCodes()
|
||||
console.log("3️⃣ Testing getCodes()");
|
||||
const iso1Codes = getCodes("1");
|
||||
const iso2Codes = getCodes("2");
|
||||
const invalidCodes = getCodes("invalid" as LanguageCodeType);
|
||||
console.log(` ✅ ISO 639-1 codes count: ${iso1Codes?.length}`);
|
||||
console.log(` ✅ ISO 639-2 codes count: ${iso2Codes?.length}`);
|
||||
console.log(` ✅ Invalid type returns: ${invalidCodes}`);
|
||||
console.log(
|
||||
` ✅ Sample ISO 639-1 codes: ${iso1Codes?.slice(0, 5).join(", ")}`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
// Test 4: getNames()
|
||||
console.log("4️⃣ Testing getNames()");
|
||||
const englishNames = getNames(false);
|
||||
const localNames = getNames(true);
|
||||
console.log(` ✅ English names count: ${englishNames.length}`);
|
||||
console.log(` ✅ Local names count: ${localNames.length}`);
|
||||
console.log(
|
||||
` ✅ Sample English names: ${englishNames.slice(0, 3).join(", ")}`,
|
||||
);
|
||||
console.log(` ✅ Sample local names: ${localNames.slice(0, 3).join(", ")}`);
|
||||
console.log();
|
||||
|
||||
// Test 5: findBy()
|
||||
console.log("5️⃣ Testing findBy()");
|
||||
const english = findBy("1", "en");
|
||||
const spanish = findBy("name", "Spanish");
|
||||
const french = findBy("local", "Français");
|
||||
const notFound = findBy("name", "Klingon");
|
||||
|
||||
console.log(
|
||||
` ✅ English by ISO 639-1: ${english?.name} (${english?.local})`,
|
||||
);
|
||||
console.log(` ✅ Spanish by name: ${spanish?.name} (${spanish?.["1"]})`);
|
||||
console.log(` ✅ French by local name: ${french?.name} (${french?.["1"]})`);
|
||||
console.log(` ✅ Klingon (not found): ${notFound}`);
|
||||
console.log();
|
||||
|
||||
// Test 6: Legacy API
|
||||
console.log("6️⃣ Testing Legacy API");
|
||||
const legacyAll = langs.all();
|
||||
const legacyHas = langs.has("1", "de");
|
||||
const legacyCodes = langs.codes("2");
|
||||
const legacyNames = langs.names(false);
|
||||
const legacyWhere = langs.where("name", "German");
|
||||
|
||||
console.log(` ✅ Legacy all() count: ${legacyAll.length}`);
|
||||
console.log(` ✅ Legacy has() German: ${legacyHas}`);
|
||||
console.log(` ✅ Legacy codes() count: ${legacyCodes?.length}`);
|
||||
console.log(` ✅ Legacy names() count: ${legacyNames.length}`);
|
||||
console.log(
|
||||
` ✅ Legacy where() German: ${legacyWhere?.name} (${legacyWhere?.["1"]})`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
// Test 7: Type validation
|
||||
console.log("7️⃣ Testing Type Safety");
|
||||
const language: Language | undefined = findBy("name", "English");
|
||||
if (language) {
|
||||
// Type-safe access to language properties
|
||||
const name: string = language.name;
|
||||
const local: string = language.local;
|
||||
const iso1: string = language["1"];
|
||||
const iso2: string = language["2"];
|
||||
console.log(` ✅ Type-safe access: ${name} (${iso1}) - ${local}`);
|
||||
}
|
||||
|
||||
// Test various code types
|
||||
const codeTypes: LanguageCodeType[] = ["1", "2", "2B", "2T", "3", 1, 2, 3];
|
||||
console.log(` ✅ Valid code types: ${codeTypes.join(", ")}`);
|
||||
console.log();
|
||||
|
||||
console.log("🎉 All tests completed successfully!");
|
||||
}
|
||||
|
||||
// Run the tests
|
||||
runTests();
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user