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 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.2.3",
3
+ "version": "8.3.1",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
7
7
  },
8
8
  "exports": {
9
- ".": "./src/uti.mjs"
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.10",
40
+ "browser-ava": "^2.1.12",
37
41
  "c8": "^9.1.0",
38
42
  "documentation": "^14.0.3",
39
- "semantic-release": "^23.0.0",
43
+ "semantic-release": "^23.0.2",
40
44
  "typescript": "^5.3.3"
41
45
  },
42
46
  "engines": {
43
- "node": ">=18.18.2",
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-esm-only",
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} UTI for the given mime type or undefined if no UTI is registerd for the mime type
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[]} UTI for the given fileName or undefined if no UTI is registerd for the file names extension
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
+ }