file-lang 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Roshan Singh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # file-lang
2
+
3
+ > Deterministically detect a programming language from a file path, file name, or extension.
4
+
5
+ `file-lang` is a tiny utility that maps file extensions and well-known filenames to **human‑readable language names**.
6
+
7
+ No heuristics. No content parsing. No guessing.
8
+
9
+ ---
10
+
11
+ <br />
12
+
13
+ ## Why
14
+
15
+ When building tools that analyze files, repositories, you end up rewriting the same logic again and again:
16
+
17
+ - Extract extension from paths
18
+ - Normalize weird inputs
19
+ - Map extensions to language names
20
+ - Handle unknowns safely
21
+
22
+ `file-lang` exists so you never have to think about this again.
23
+
24
+ ---
25
+
26
+ <br />
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npm install file-lang
32
+ ```
33
+
34
+ ---
35
+
36
+ <br />
37
+
38
+ ## Usage
39
+
40
+ ```ts
41
+ import { detectLanguage } from "file-lang";
42
+
43
+ detectLanguage("ts"); // "TypeScript"
44
+ detectLanguage(".ts"); // "TypeScript"
45
+ detectLanguage("index.ts"); // "TypeScript"
46
+ detectLanguage("/src/utils/file.ts"); // "TypeScript"
47
+ detectLanguage("Dockerfile"); // "Docker"
48
+ detectLanguage("unknown.ext"); // "Unknown"
49
+ ```
50
+
51
+ ---
52
+
53
+ <br />
54
+
55
+ ## Accepted Input
56
+
57
+ `detectLanguage` accepts **any string** representing:
58
+
59
+ - A file extension (`ts`, `.ts`)
60
+ - A file name (`index.ts`)
61
+ - A file path (`/path/to/file.ts`)
62
+ - Well-known filenames (`Dockerfile`, `Makefile`)
63
+
64
+ Invalid, empty, or unsupported inputs safely return:
65
+
66
+ ```ts
67
+ "Unknown";
68
+ ```
69
+
70
+ The function **never throws**.
71
+
72
+ ---
73
+
74
+ <br />
75
+
76
+ ## Output
77
+
78
+ - Returns a **human-readable language name** (Title Case)
79
+ - Returns `"Unknown"` if no mapping exists
80
+
81
+ Examples:
82
+
83
+ - `"TypeScript"`
84
+ - `"JavaScript"`
85
+ - `"Markdown"`
86
+ - `"Docker"`
87
+
88
+ ---
89
+
90
+ <br />
91
+
92
+ ## Design Principles
93
+
94
+ - Deterministic output
95
+ - Extension-based only
96
+ - Zero dependencies
97
+ - Minimal public API
98
+ - Predictable behavior
99
+
100
+ If an extension is ambiguous or unclear, `file-lang` **does not guess**.
101
+
102
+ Ambiguity resolves to `"Unknown"`.
103
+
104
+ ---
105
+
106
+ <br />
107
+
108
+ ## Contributing
109
+
110
+ Contributions are welcome, especially:
111
+
112
+ - Adding support for additional languages
113
+ - Improving test coverage
114
+
115
+ Guidelines:
116
+
117
+ - Keep changes minimal
118
+ - Follow existing naming conventions
119
+ - Do not introduce heuristics or content-based detection
@@ -0,0 +1 @@
1
+ export declare function detectLanguage(input: string): string;
@@ -0,0 +1,14 @@
1
+ import { languageMap } from "./language.js";
2
+ import { normalize } from "./normalize.js";
3
+ export function detectLanguage(input) {
4
+ // Return Unknown input is not typeof string
5
+ if (typeof input !== "string")
6
+ return "Unknown";
7
+ // Check for empty string
8
+ const trimmed = input.trim();
9
+ if (trimmed === "")
10
+ return "Unknown";
11
+ const normalized = normalize(trimmed);
12
+ const language = languageMap[normalized];
13
+ return language || "Unknown";
14
+ }
@@ -0,0 +1 @@
1
+ export { detectLanguage } from "./detectLanguage.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { detectLanguage } from "./detectLanguage.js";
@@ -0,0 +1 @@
1
+ export declare const languageMap: Record<string, string>;
@@ -0,0 +1,74 @@
1
+ export const languageMap = {
2
+ // --- Bash ---
3
+ bash: "Bash",
4
+ // --- C ---
5
+ c: "C",
6
+ // --- C++ ---
7
+ cpp: "C++",
8
+ hpp: "C++",
9
+ // --- C# ---
10
+ cs: "C#",
11
+ // --- CSS ---
12
+ css: "CSS",
13
+ // --- Elixir ---
14
+ ex: "Elixir",
15
+ exs: "Elixir",
16
+ // --- Dart ---
17
+ dart: "Dart",
18
+ // --- Docker ---
19
+ dockerfile: "Docker",
20
+ // --- Go ---
21
+ go: "Go",
22
+ // --- Haskell ---
23
+ hs: "Haskell",
24
+ lhs: "Haskell",
25
+ // --- Less ---
26
+ less: "Less",
27
+ // --- JavaScript ---
28
+ js: "JavaScript",
29
+ jsx: "JavaScript",
30
+ mjs: "JavaScript",
31
+ // --- JSON ---
32
+ json: "JSON",
33
+ // --- Java ---
34
+ java: "Java",
35
+ // --- Kotlin ---
36
+ kt: "Kotlin",
37
+ kts: "Kotlin",
38
+ // --- Lua ---
39
+ lua: "Lua",
40
+ // --- Makefile ---
41
+ makefile: "Makefile",
42
+ // --- Markdown ---
43
+ md: "Markdown",
44
+ // --- Objective-C ---
45
+ m: "Objective-C",
46
+ // --- Python ---
47
+ py: "Python",
48
+ pyw: "Python",
49
+ // --- PHP ---
50
+ php: "PHP",
51
+ php3: "PHP",
52
+ phtml: "PHP",
53
+ // --- Perl ---
54
+ pl: "Perl",
55
+ pm: "Perl",
56
+ pod: "Perl",
57
+ // --- R ---
58
+ r: "R",
59
+ // --- Rust ---
60
+ rs: "Rust",
61
+ // --- Ruby ---
62
+ rb: "Ruby",
63
+ rhtml: "Ruby",
64
+ erb: "Ruby",
65
+ // --- Shell ---
66
+ sh: "Shell",
67
+ // --- SCSS ---
68
+ scss: "SCSS",
69
+ // --- TypeScript ---
70
+ ts: "TypeScript",
71
+ tsx: "TypeScript",
72
+ // --- Text ---
73
+ txt: "Text",
74
+ };
@@ -0,0 +1 @@
1
+ export declare function normalize(input: string): string;
@@ -0,0 +1,11 @@
1
+ import { extname } from "node:path";
2
+ export function normalize(input) {
3
+ // Special case: ".ts" → "ts"
4
+ if (input.startsWith(".") && !input.includes("/") && !input.includes("\\")) {
5
+ return input.slice(1).toLowerCase();
6
+ }
7
+ const ext = extname(input);
8
+ if (!ext)
9
+ return input.toLowerCase();
10
+ return ext.slice(1).toLowerCase();
11
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "file-lang",
3
+ "version": "0.1.0",
4
+ "description": "Deterministically detect a programming language from a file path, name, or extension.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "sideEffects": false,
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "keywords": [
26
+ "language-detection",
27
+ "file-language",
28
+ "file-extension",
29
+ "developer-tools",
30
+ "static-analysis",
31
+ "repository-analysis",
32
+ "cli",
33
+ "tooling"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/alcanivorax/file-lang.git"
38
+ },
39
+ "author": "alcanivorax",
40
+ "license": "MIT",
41
+ "packageManager": "pnpm@10.27.0",
42
+ "devDependencies": {
43
+ "@types/node": "^25.0.9",
44
+ "typescript": "^5.9.3",
45
+ "vitest": "^4.0.17"
46
+ }
47
+ }