uti 8.2.3 → 8.3.1
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/dist/uti.d.mts +53 -0
- package/dist/well-known-utis.d.mts +98 -0
- package/package.json +11 -6
- package/src/uti.mjs +6 -6
- package/utils/convert-uti.mjs +102 -0
package/dist/uti.d.mts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry of UTIs.
|
|
3
|
+
* @property {Map<string,UTI>} registry
|
|
4
|
+
* @property {Map<string,UTI>} utiByMimeType
|
|
5
|
+
* @property {Map<string,UTI>} utiByFileNameExtension
|
|
6
|
+
*/
|
|
7
|
+
export class UTIController {
|
|
8
|
+
registry: Map<any, any>;
|
|
9
|
+
/** @type {Map<string,string[]>} */ utiByMimeType: Map<string, string[]>;
|
|
10
|
+
/** @type {Map<string,string[]>} */ utiByFileNameExtension: Map<string, string[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Registers additional types.
|
|
13
|
+
* @param {Object[]} types
|
|
14
|
+
*/
|
|
15
|
+
register(types: any[]): void;
|
|
16
|
+
/**
|
|
17
|
+
* Lookup a given UTI.
|
|
18
|
+
* @param {string} name UTI
|
|
19
|
+
* @return {string|undefined} UTI for the given name or undefined if UTI is not present.
|
|
20
|
+
*/
|
|
21
|
+
getUTI(name: string): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Lookup a UTIs for a mime type.
|
|
24
|
+
* @param {string} mimeType mime type to get UTIs for
|
|
25
|
+
* @return {string[]} UTIs for the given mime type
|
|
26
|
+
*/
|
|
27
|
+
getUTIsForMimeType(mimeType: string): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Lookup a UTI for a file name.
|
|
30
|
+
* First the file name extension is extracted.
|
|
31
|
+
* Then a lookup in the reistered UTIs for file name extions is executed.
|
|
32
|
+
* @param {string} fileName file to detect UTI for
|
|
33
|
+
* @return {string[]} UTIs for the given fileName
|
|
34
|
+
*/
|
|
35
|
+
getUTIsForFileName(fileName: string): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Check whenever two UTI are conformant.
|
|
38
|
+
* If a conforms to b and b conforms to c then a also conforms to c.
|
|
39
|
+
* @param {string} a first UTI
|
|
40
|
+
* @param {string} b second UTI
|
|
41
|
+
* @return {boolean} true if UTI a conforms to UTI b.
|
|
42
|
+
*/
|
|
43
|
+
conformsTo(a: string, b: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Lookup a UTI for a file name and check conformance.
|
|
46
|
+
* @param {string} fileName file to detect UTI for
|
|
47
|
+
* @param {string} uti to check conformance against
|
|
48
|
+
* @return {boolean} ture if utils for file name are conformant
|
|
49
|
+
*/
|
|
50
|
+
fileNameConformsTo(fileName: string, uti: string): boolean;
|
|
51
|
+
assignMimeTypes(name: any, mimTypes: any): void;
|
|
52
|
+
assignExtensions(name: any, extensions: any): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
declare const _default: ({
|
|
2
|
+
name: string;
|
|
3
|
+
conformsTo?: undefined;
|
|
4
|
+
mimeType?: undefined;
|
|
5
|
+
fileNameExtension?: undefined;
|
|
6
|
+
filNameExtension?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
name: string;
|
|
9
|
+
conformsTo: string;
|
|
10
|
+
mimeType?: undefined;
|
|
11
|
+
fileNameExtension?: undefined;
|
|
12
|
+
filNameExtension?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
name: string;
|
|
15
|
+
conformsTo: string[];
|
|
16
|
+
mimeType: string;
|
|
17
|
+
fileNameExtension: string;
|
|
18
|
+
filNameExtension?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
name: string;
|
|
21
|
+
conformsTo: string[];
|
|
22
|
+
fileNameExtension: string;
|
|
23
|
+
mimeType?: undefined;
|
|
24
|
+
filNameExtension?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
name: string;
|
|
27
|
+
conformsTo: string[];
|
|
28
|
+
mimeType?: undefined;
|
|
29
|
+
fileNameExtension?: undefined;
|
|
30
|
+
filNameExtension?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
name: string;
|
|
33
|
+
conformsTo: string;
|
|
34
|
+
fileNameExtension: string;
|
|
35
|
+
mimeType: string;
|
|
36
|
+
filNameExtension?: undefined;
|
|
37
|
+
} | {
|
|
38
|
+
name: string;
|
|
39
|
+
conformsTo: string;
|
|
40
|
+
fileNameExtension: string;
|
|
41
|
+
mimeType?: undefined;
|
|
42
|
+
filNameExtension?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
name: string;
|
|
45
|
+
conformsTo: string;
|
|
46
|
+
fileNameExtension: string[];
|
|
47
|
+
mimeType: string;
|
|
48
|
+
filNameExtension?: undefined;
|
|
49
|
+
} | {
|
|
50
|
+
name: string;
|
|
51
|
+
conformsTo: string;
|
|
52
|
+
fileNameExtension: string;
|
|
53
|
+
mimeType: string[];
|
|
54
|
+
filNameExtension?: undefined;
|
|
55
|
+
} | {
|
|
56
|
+
name: string;
|
|
57
|
+
conformsTo: string;
|
|
58
|
+
fileNameExtension: string[];
|
|
59
|
+
mimeType?: undefined;
|
|
60
|
+
filNameExtension?: undefined;
|
|
61
|
+
} | {
|
|
62
|
+
name: string;
|
|
63
|
+
conformsTo: string[];
|
|
64
|
+
fileNameExtension: string[];
|
|
65
|
+
mimeType: string[];
|
|
66
|
+
filNameExtension?: undefined;
|
|
67
|
+
} | {
|
|
68
|
+
name: string;
|
|
69
|
+
conformsTo: string;
|
|
70
|
+
fileNameExtension: string[];
|
|
71
|
+
mimeType: string[];
|
|
72
|
+
filNameExtension?: undefined;
|
|
73
|
+
} | {
|
|
74
|
+
name: string;
|
|
75
|
+
conformsTo: string[];
|
|
76
|
+
fileNameExtension: string[];
|
|
77
|
+
mimeType?: undefined;
|
|
78
|
+
filNameExtension?: undefined;
|
|
79
|
+
} | {
|
|
80
|
+
name: string;
|
|
81
|
+
conformsTo: string[];
|
|
82
|
+
mimeType: string;
|
|
83
|
+
fileNameExtension: string[];
|
|
84
|
+
filNameExtension?: undefined;
|
|
85
|
+
} | {
|
|
86
|
+
name: string;
|
|
87
|
+
conformsTo: string;
|
|
88
|
+
filNameExtension: string;
|
|
89
|
+
mimeType: string;
|
|
90
|
+
fileNameExtension?: undefined;
|
|
91
|
+
} | {
|
|
92
|
+
name: string;
|
|
93
|
+
fileNameExtension: string[];
|
|
94
|
+
conformsTo?: undefined;
|
|
95
|
+
mimeType?: undefined;
|
|
96
|
+
filNameExtension?: undefined;
|
|
97
|
+
})[];
|
|
98
|
+
export default _default;
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uti",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"provenance": true
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
|
-
".":
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/uti.d.mts",
|
|
11
|
+
"default": "./src/uti.mjs"
|
|
12
|
+
}
|
|
10
13
|
},
|
|
11
14
|
"description": "javascript implementation of a \"Uniform Type Identifier\" (UTI)",
|
|
12
15
|
"keywords": [
|
|
@@ -22,6 +25,7 @@
|
|
|
22
25
|
],
|
|
23
26
|
"license": "BSD-2-Clause",
|
|
24
27
|
"scripts": {
|
|
28
|
+
"prepare": "tsc --allowJs --declaration --emitDeclarationOnly --declarationDir dist -t esnext -m esnext --module nodenext --moduleResolution nodenext ./src**/*.mjs",
|
|
25
29
|
"test": "npm run test:browser-ava && npm run test:ava",
|
|
26
30
|
"test:ava": "ava --timeout 4m tests/*-ava.mjs tests/*-ava-node.mjs",
|
|
27
31
|
"test:browser-ava": "browser-ava --headless --no-keep-open tests/*-ava.mjs tests/*-ava-browser.mjs",
|
|
@@ -33,14 +37,14 @@
|
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
35
39
|
"ava": "^6.1.1",
|
|
36
|
-
"browser-ava": "^2.1.
|
|
40
|
+
"browser-ava": "^2.1.12",
|
|
37
41
|
"c8": "^9.1.0",
|
|
38
42
|
"documentation": "^14.0.3",
|
|
39
|
-
"semantic-release": "^23.0.
|
|
43
|
+
"semantic-release": "^23.0.2",
|
|
40
44
|
"typescript": "^5.3.3"
|
|
41
45
|
},
|
|
42
46
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
47
|
+
"node": ">=20.11.0",
|
|
44
48
|
"bun": ">=1.0.0"
|
|
45
49
|
},
|
|
46
50
|
"repository": {
|
|
@@ -55,7 +59,8 @@
|
|
|
55
59
|
"inheritFrom": [
|
|
56
60
|
"arlac77/template-arlac77-github",
|
|
57
61
|
"arlac77/template-browser-ava",
|
|
58
|
-
"arlac77/template-
|
|
62
|
+
"arlac77/template-javascript-component",
|
|
63
|
+
"arlac77/template-node-component",
|
|
59
64
|
"arlac77/template-typescript"
|
|
60
65
|
]
|
|
61
66
|
}
|
package/src/uti.mjs
CHANGED
|
@@ -63,8 +63,8 @@ class UTI {
|
|
|
63
63
|
*/
|
|
64
64
|
export class UTIController {
|
|
65
65
|
registry = new Map();
|
|
66
|
-
utiByMimeType = new Map();
|
|
67
|
-
utiByFileNameExtension = new Map();
|
|
66
|
+
/** @type {Map<string,string[]>} */ utiByMimeType = new Map();
|
|
67
|
+
/** @type {Map<string,string[]>} */ utiByFileNameExtension = new Map();
|
|
68
68
|
|
|
69
69
|
constructor() {
|
|
70
70
|
this.register(types);
|
|
@@ -116,7 +116,7 @@ export class UTIController {
|
|
|
116
116
|
/**
|
|
117
117
|
* Lookup a given UTI.
|
|
118
118
|
* @param {string} name UTI
|
|
119
|
-
* @return {string} UTI for the given name or undefined if UTI is not present.
|
|
119
|
+
* @return {string|undefined} UTI for the given name or undefined if UTI is not present.
|
|
120
120
|
*/
|
|
121
121
|
getUTI(name) {
|
|
122
122
|
return this.registry.get(name);
|
|
@@ -125,10 +125,10 @@ export class UTIController {
|
|
|
125
125
|
/**
|
|
126
126
|
* Lookup a UTIs for a mime type.
|
|
127
127
|
* @param {string} mimeType mime type to get UTIs for
|
|
128
|
-
* @return {string}
|
|
128
|
+
* @return {string[]} UTIs for the given mime type
|
|
129
129
|
*/
|
|
130
130
|
getUTIsForMimeType(mimeType) {
|
|
131
|
-
return this.utiByMimeType.get(mimeType);
|
|
131
|
+
return this.utiByMimeType.get(mimeType) || [];
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
@@ -136,7 +136,7 @@ export class UTIController {
|
|
|
136
136
|
* First the file name extension is extracted.
|
|
137
137
|
* Then a lookup in the reistered UTIs for file name extions is executed.
|
|
138
138
|
* @param {string} fileName file to detect UTI for
|
|
139
|
-
* @return {string[]}
|
|
139
|
+
* @return {string[]} UTIs for the given fileName
|
|
140
140
|
*/
|
|
141
141
|
getUTIsForFileName(fileName) {
|
|
142
142
|
const m = fileName.match(/(\.[\.a-zA-Z_0-9]+)$/);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import wellKnown from "../src/well-known-utis.mjs";
|
|
5
|
+
|
|
6
|
+
function asArray(object) {
|
|
7
|
+
return Array.isArray(object) ? object : object === undefined ? [] : [object];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function asScalar(object) {
|
|
11
|
+
if (object !== undefined && object?.size > 0) {
|
|
12
|
+
if (object.size === 1) {
|
|
13
|
+
for (const o of object) {
|
|
14
|
+
return o;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return [...object];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const lsregister = spawn(
|
|
22
|
+
"/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister",
|
|
23
|
+
["-dump"]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
let name, conformsTo, tags;
|
|
27
|
+
|
|
28
|
+
for await (const line of lineIterator(lsregister.stdout)) {
|
|
29
|
+
let m = line.match(/^([^:]+):\s+(.+)/);
|
|
30
|
+
if (m) {
|
|
31
|
+
switch (m[1]) {
|
|
32
|
+
case "uti":
|
|
33
|
+
name = m[2];
|
|
34
|
+
break;
|
|
35
|
+
case "conforms to":
|
|
36
|
+
conformsTo = m[2].split(/\s*,\s*/);
|
|
37
|
+
break;
|
|
38
|
+
case "tags":
|
|
39
|
+
tags = m[2].split(/\s*,\s*/);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (name && line.match(/^-/)) {
|
|
45
|
+
const b = wellKnown.find(u => u.name === name);
|
|
46
|
+
const a = {
|
|
47
|
+
name,
|
|
48
|
+
conformsTo: asScalar([...asArray(conformsTo), ...asArray(b?.conformsTo)]),
|
|
49
|
+
fileNameExtension: asScalar(
|
|
50
|
+
new Set([
|
|
51
|
+
...asArray(tags?.filter(t => t.match(/^\./))),
|
|
52
|
+
...asArray(b?.fileNameExtension)
|
|
53
|
+
])
|
|
54
|
+
),
|
|
55
|
+
mimeType: asScalar([
|
|
56
|
+
...asArray(tags?.filter(t => t.match(/^\w+\//))),
|
|
57
|
+
...asArray(b?.mimeType)
|
|
58
|
+
])
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (b) {
|
|
62
|
+
for (const p of ["conformsTo", "fileNameExtension", "mimeType"]) {
|
|
63
|
+
if (Array.isArray(b[p])) {
|
|
64
|
+
a[p] = b[p];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
wellKnown.push(a);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
name = undefined;
|
|
72
|
+
conformsTo = undefined;
|
|
73
|
+
tags = undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(JSON.stringify(wellKnown, undefined, 2));
|
|
78
|
+
|
|
79
|
+
export async function* lineIterator(stream, decoder = new TextDecoder()) {
|
|
80
|
+
const re = /\r?\n/gm;
|
|
81
|
+
let chunk = "";
|
|
82
|
+
let startIndex = 0;
|
|
83
|
+
|
|
84
|
+
for await (const value of stream) {
|
|
85
|
+
chunk += decoder.decode(value);
|
|
86
|
+
while (true) {
|
|
87
|
+
const result = re.exec(chunk);
|
|
88
|
+
if (result) {
|
|
89
|
+
yield chunk.substring(startIndex, result.index);
|
|
90
|
+
startIndex = re.lastIndex;
|
|
91
|
+
} else {
|
|
92
|
+
chunk = chunk.substring(startIndex);
|
|
93
|
+
startIndex = re.lastIndex = 0;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (startIndex < chunk.length) {
|
|
100
|
+
yield chunk;
|
|
101
|
+
}
|
|
102
|
+
}
|