@ucdjs/cli 0.2.2 → 0.3.1-beta.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/bin/ucd.js +1 -1
- package/dist/_shared-CgcKJJFf.mjs +113 -0
- package/dist/analyze-D8AeAGDR.mjs +75 -0
- package/dist/cli.mjs +403 -0
- package/dist/{fields-Cz0PV1Co.js → fields-BvLDPLGg.mjs} +9 -19
- package/dist/get-CHw5s5Ab.mjs +63 -0
- package/dist/hash-BAViT6QD.mjs +116 -0
- package/dist/info-D2uPOmns.mjs +100 -0
- package/dist/info-ZGysg0N_.mjs +75 -0
- package/dist/init-DilsO33p.mjs +126 -0
- package/dist/list-C1bd3Vq4.mjs +89 -0
- package/dist/mirror-DLYQGa33.mjs +130 -0
- package/dist/root-BnOeYqGP.mjs +57 -0
- package/dist/root-C_Ycy7kI.mjs +88 -0
- package/dist/{root-oHWSp_5G.js → root-CfALAyOQ.mjs} +6 -5
- package/dist/root-DXVHyPa6.mjs +61 -0
- package/dist/status-DI1HruH0.mjs +136 -0
- package/dist/sync-DEtQ-jZc.mjs +160 -0
- package/dist/validate-DVr1TaHK.mjs +114 -0
- package/dist/verify-ME4bDNIT.mjs +114 -0
- package/package.json +34 -18
- package/dist/cli-utils-DY82m2wz.js +0 -195
- package/dist/cli.js +0 -7
- package/dist/download-CCx2vdOj.js +0 -203
- /package/dist/{cli.d.ts → cli.d.mts} +0 -0
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { printHelp } from "./cli-utils-DY82m2wz.js";
|
|
2
|
-
import { gray, green, red, yellow } from "farver/fast";
|
|
3
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
-
import path, { dirname } from "node:path";
|
|
5
|
-
import { UNICODE_VERSION_METADATA, hasUCDPath, mapToUCDPathVersion } from "@luxass/unicode-utils";
|
|
6
|
-
import micromatch from "micromatch";
|
|
7
|
-
|
|
8
|
-
//#region src/cmd/download.ts
|
|
9
|
-
const CONCURRENCY_LIMIT = 3;
|
|
10
|
-
const API_URL = "https://unicode-api.luxass.dev/api/v1";
|
|
11
|
-
const UNICODE_PROXY_URL = "https://unicode-proxy.ucdjs.dev";
|
|
12
|
-
async function runDownload({ versions: providedVersions, flags }) {
|
|
13
|
-
if (flags?.help || flags?.h) {
|
|
14
|
-
printHelp({
|
|
15
|
-
headline: "Download Unicode Data Files",
|
|
16
|
-
commandName: "ucd download",
|
|
17
|
-
usage: "<...versions> [...flags]",
|
|
18
|
-
tables: { Flags: [
|
|
19
|
-
["--output-dir", "Specify the output directory."],
|
|
20
|
-
["--exclude", "Exclude files matching glob patterns (e.g., '*Test*,ReadMe.txt,*.draft')."],
|
|
21
|
-
["--exclude-test", "Exclude all test files (ending with Test.txt)."],
|
|
22
|
-
["--exclude-draft", "Exclude all draft files"],
|
|
23
|
-
["--create-comment-files", "Create comment files for each downloaded file."],
|
|
24
|
-
["--force", "Force the download, even if the files already exist."],
|
|
25
|
-
["--debug", "Enable debug output."],
|
|
26
|
-
["--help (-h)", "See all available flags."]
|
|
27
|
-
] }
|
|
28
|
-
});
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (providedVersions.length === 0) {
|
|
32
|
-
console.error(red("No versions provided. Please provide at least one version."));
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
let versions = [];
|
|
36
|
-
if (providedVersions[0] === "all") versions = UNICODE_VERSION_METADATA.filter((v) => !flags.excludeDraft || v.status !== "draft").map((v) => {
|
|
37
|
-
const mappedVersion = mapToUCDPathVersion(v.version);
|
|
38
|
-
return {
|
|
39
|
-
version: v.version,
|
|
40
|
-
mappedVersion: mappedVersion === v.version ? void 0 : mappedVersion
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
else versions = providedVersions.map((v) => {
|
|
44
|
-
const mappedVersion = mapToUCDPathVersion(v);
|
|
45
|
-
return {
|
|
46
|
-
version: v,
|
|
47
|
-
mappedVersion: mappedVersion === v ? void 0 : mappedVersion
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
const invalidVersions = versions.filter(({ version }) => !UNICODE_VERSION_METADATA.find((v) => v.version === version));
|
|
51
|
-
if (invalidVersions.length > 0) {
|
|
52
|
-
console.error(red(`Invalid version(s): ${invalidVersions.map((v) => v.version).join(", ")}. Please provide valid Unicode versions.`));
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const outputDir = flags.outputDir ?? path.join(process.cwd(), "data");
|
|
56
|
-
await mkdir(outputDir, { recursive: true });
|
|
57
|
-
const excludePatterns = flags.exclude?.split(",").map((p) => p.trim()).filter(Boolean) || [];
|
|
58
|
-
if (flags.excludeTest) excludePatterns.push("**/*Test*");
|
|
59
|
-
function getAllFilePaths(entries) {
|
|
60
|
-
const filePaths = [];
|
|
61
|
-
function collectPaths(entryList, currentPath = "") {
|
|
62
|
-
for (const entry of entryList) {
|
|
63
|
-
const fullPath = currentPath ? `${currentPath}/${entry.path}` : entry.path;
|
|
64
|
-
if (!entry.children) filePaths.push(fullPath);
|
|
65
|
-
else if (entry.children.length > 0) collectPaths(entry.children, fullPath);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
collectPaths(entries);
|
|
69
|
-
return filePaths;
|
|
70
|
-
}
|
|
71
|
-
function filterEntriesRecursive(entries) {
|
|
72
|
-
if (excludePatterns.length === 0) return entries;
|
|
73
|
-
const allPaths = getAllFilePaths(entries);
|
|
74
|
-
const patterns = ["**", ...excludePatterns.map((pattern) => `!${pattern}`)];
|
|
75
|
-
const matchedPaths = new Set(micromatch(allPaths, patterns, {
|
|
76
|
-
dot: true,
|
|
77
|
-
nocase: true,
|
|
78
|
-
debug: flags.debug
|
|
79
|
-
}));
|
|
80
|
-
function filterEntries(entryList, prefix = "") {
|
|
81
|
-
const result = [];
|
|
82
|
-
for (const entry of entryList) {
|
|
83
|
-
const fullPath = prefix ? `${prefix}/${entry.path}` : entry.path;
|
|
84
|
-
if (!entry.children) {
|
|
85
|
-
if (matchedPaths.has(fullPath)) result.push(entry);
|
|
86
|
-
} else {
|
|
87
|
-
const filteredChildren = filterEntries(entry.children, fullPath);
|
|
88
|
-
if (filteredChildren.length > 0) result.push({
|
|
89
|
-
...entry,
|
|
90
|
-
children: filteredChildren
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return result;
|
|
95
|
-
}
|
|
96
|
-
return filterEntries(entries);
|
|
97
|
-
}
|
|
98
|
-
async function processFileEntries(entries, basePath, versionOutputDir, downloadedFiles, currentDirPath = "", errors) {
|
|
99
|
-
const dirPromises = [];
|
|
100
|
-
const filePromises = [];
|
|
101
|
-
for (const entry of entries) {
|
|
102
|
-
const entryOutputPath = currentDirPath ? path.join(currentDirPath, entry.path) : entry.path;
|
|
103
|
-
const outputPath = path.join(versionOutputDir, entryOutputPath);
|
|
104
|
-
if (entry.children) dirPromises.push((async () => {
|
|
105
|
-
await mkdir(outputPath, { recursive: true });
|
|
106
|
-
await processFileEntries(entry.children || [], `${basePath}/${entry.path}`, versionOutputDir, downloadedFiles, entryOutputPath, errors);
|
|
107
|
-
})());
|
|
108
|
-
else filePromises.push((async () => {
|
|
109
|
-
try {
|
|
110
|
-
await mkdir(dirname(outputPath), { recursive: true });
|
|
111
|
-
const url = `${UNICODE_PROXY_URL}${basePath}/${entry.path}`;
|
|
112
|
-
const response = await fetch(url);
|
|
113
|
-
if (!response.ok) {
|
|
114
|
-
errors.push(`Failed to fetch ${entry.path}: ${response.status} ${response.statusText}`);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const content = await response.text();
|
|
118
|
-
if (flags.createCommentFiles) {
|
|
119
|
-
const parsed = path.parse(outputPath);
|
|
120
|
-
const commentPath = path.join(parsed.dir, `${parsed.name}.comments.txt`);
|
|
121
|
-
await writeFile(commentPath, "");
|
|
122
|
-
}
|
|
123
|
-
await writeFile(outputPath, content);
|
|
124
|
-
downloadedFiles.push(outputPath);
|
|
125
|
-
} catch (err) {
|
|
126
|
-
errors.push(`Error downloading ${entry.path}: ${err.message}`);
|
|
127
|
-
}
|
|
128
|
-
})());
|
|
129
|
-
}
|
|
130
|
-
await Promise.all([...dirPromises, ...filePromises]);
|
|
131
|
-
}
|
|
132
|
-
async function processVersion(version) {
|
|
133
|
-
console.info(`Starting download for Unicode ${green(version.version)}${version.mappedVersion ? gray(` (${green(version.mappedVersion)})`) : ""}`);
|
|
134
|
-
const downloadedFiles = [];
|
|
135
|
-
const errors = [];
|
|
136
|
-
const versionOutputDir = path.join(outputDir, `v${version.version}`);
|
|
137
|
-
await mkdir(versionOutputDir, { recursive: true });
|
|
138
|
-
try {
|
|
139
|
-
const filesResponse = await fetch(`${API_URL}/unicode-files/${version.version}`);
|
|
140
|
-
if (!filesResponse.ok) {
|
|
141
|
-
console.error(red(`Failed to fetch file list for version ${version.version}: ${filesResponse.status} ${filesResponse.statusText}`));
|
|
142
|
-
return {
|
|
143
|
-
version: version.version,
|
|
144
|
-
downloadedFiles,
|
|
145
|
-
errors: [`Failed to fetch file list: ${filesResponse.statusText}`]
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
const fileEntries = await filesResponse.json();
|
|
149
|
-
if (!Array.isArray(fileEntries)) {
|
|
150
|
-
console.error(red(`Invalid response format for version ${version.version}`));
|
|
151
|
-
return {
|
|
152
|
-
version: version.version,
|
|
153
|
-
downloadedFiles,
|
|
154
|
-
errors: ["Invalid response format"]
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
const filteredEntries = filterEntriesRecursive(fileEntries);
|
|
158
|
-
const correctVersion = version.mappedVersion ?? version.version;
|
|
159
|
-
const basePath = `/${correctVersion}${hasUCDPath(correctVersion) ? "/ucd" : ""}`;
|
|
160
|
-
await processFileEntries(filteredEntries, basePath, versionOutputDir, downloadedFiles, "", errors);
|
|
161
|
-
if (downloadedFiles.length === 0 && errors.length === 0) console.warn(yellow(`No files were downloaded for Unicode ${version.version}`));
|
|
162
|
-
else if (downloadedFiles.length > 0) {
|
|
163
|
-
console.info(green(`✓ Downloaded ${downloadedFiles.length} files for Unicode ${version.version}`));
|
|
164
|
-
if (flags.debug) downloadedFiles.forEach((file) => {
|
|
165
|
-
const relativePath = path.relative(versionOutputDir, file);
|
|
166
|
-
console.info(green(` - ${relativePath}`));
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
if (errors.length > 0) {
|
|
170
|
-
console.warn(yellow(`${errors.length} errors occurred during download of Unicode ${version.version}`));
|
|
171
|
-
if (flags.debug) errors.forEach((error) => console.error(red(` - ${error}`)));
|
|
172
|
-
}
|
|
173
|
-
} catch (err) {
|
|
174
|
-
const errorMessage = `Error processing version ${version.version}: ${err.message}`;
|
|
175
|
-
errors.push(errorMessage);
|
|
176
|
-
console.error(red(errorMessage));
|
|
177
|
-
}
|
|
178
|
-
return {
|
|
179
|
-
version: version.version,
|
|
180
|
-
downloadedFiles,
|
|
181
|
-
errors
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
const results = [];
|
|
185
|
-
const versionGroups = [];
|
|
186
|
-
for (let i = 0; i < versions.length; i += CONCURRENCY_LIMIT) versionGroups.push(versions.slice(i, i + CONCURRENCY_LIMIT));
|
|
187
|
-
for (const versionGroup of versionGroups) {
|
|
188
|
-
const batchResults = await Promise.all(versionGroup.map(processVersion));
|
|
189
|
-
results.push(...batchResults);
|
|
190
|
-
}
|
|
191
|
-
const totalFiles = results.reduce((sum, r) => sum + r.downloadedFiles.length, 0);
|
|
192
|
-
const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
|
|
193
|
-
const successfulVersions = results.filter((r) => r.downloadedFiles.length > 0).length;
|
|
194
|
-
console.info(`\n${"=".repeat(50)}`);
|
|
195
|
-
console.info("Download Summary:");
|
|
196
|
-
console.info(green(`✓ ${successfulVersions}/${results.length} versions processed successfully`));
|
|
197
|
-
console.info(green(`✓ ${totalFiles} total files downloaded`));
|
|
198
|
-
if (totalErrors > 0) console.warn(yellow(`⚠ ${totalErrors} total errors encountered`));
|
|
199
|
-
console.info("=".repeat(50));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
//#endregion
|
|
203
|
-
export { runDownload };
|
|
File without changes
|