-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.js
162 lines (134 loc) · 4.93 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
const { distance } = require('fastest-levenshtein');
/**
* Retrieves the catalog from the schemastore.org and returns an array of schemas.
*
* @return {Array} an array of schemas
*/
const getCatalog = async () => {
const catalog = await getFileContent('https://www.schemastore.org/api/json/catalog.json');
return JSON.parse(catalog).schemas;
}
/**
* Retrieves the content of a file from the provided download URL.
*
* @param {string} download_url - The URL from which to download the file content
* @return {Promise<string>} The text content of the downloaded file
*/
async function getFileContent(download_url) {
try {
const fileContent = await fetch(download_url, {
method: 'GET',
}
);
return fileContent.text();
}
catch (error) {
throw new Error(`Error fetching file content: ${error.message}`);
}
}
/**
* Asynchronously categorizes schemas based on groups.
*
* @return {Array} The categorized schemas sorted by name.
*/
async function categorizeSchemas() {
const catalog = await getCatalog();
const categorizedSchemas = [];
await Promise.all(
catalog.map(async schema => {
const groups = new Set(tokenize(schema.name).concat(tokenize(schema.description)));
groups.forEach(group => {
let category = categorizedSchemas.find(cat => cat.name === group);
if (!category) {
category = { name: group, schemas: [] };
categorizedSchemas.push(category);
}
category.schemas.push({ name: schema.name, url: schema.url });
});
})
);
return categorizedSchemas.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Tokenizes the input string and returns an array of tokens.
*
* @param {string} input - The input string to tokenize
* @return {Array} An array of tokens
*/
function tokenize(input) {
return input.split(/\W+/).filter(Boolean);
}
/**
* Finds the closest matches for an input among the existing categories.
*
* @param {string} input - The input to find matches for
* @param {Array} categories - The existing categories
* @return {Array} The closest matches
*/
function findClosestMatches(input, categories) {
const inputTokens = tokenize(input);
// Find the closest matches using Levenshtein distance
const closestMatches = categories.map(category => {
const categoryTokens = tokenize(category);
// Calculate the total distance between inputTokens and categoryTokens
const dist = inputTokens.reduce((totalDistance, inputToken) => {
const closestToken = categoryTokens.reduce((closest, categoryToken) => {
const currentDistance = distance(inputToken.toLowerCase(), categoryToken.toLowerCase());
return currentDistance < closest.distance ? { distance: currentDistance, token: categoryToken } : closest;
}, { distance: Infinity, token: null });
return totalDistance + closestToken.distance;
}, 0);
return { category, distance: dist };
});
// Sort by distance and return the category names
return closestMatches
.filter(match => match.distance <= input.length)
.sort((a, b) => a.distance - b.distance)
.map(match => match.category);
}
/**
* Finds schemata based on input using inquirer-autocomplete.
*
* @param {string} input - The input to search schemata for.
* @param {Array} categorizedSchemas - The array of categorized schemata.
* @return {Array} The array of filtered schemata.
*/
function findSchema(input, categorizedSchemas) {
if (!input) {
return categorizedSchemas.map(schema => schema.name);
}
const allCategories = categorizedSchemas.map(schema => schema.name);
const closestMatches = findClosestMatches(input, allCategories);
return closestMatches;
}
/**
* Fetches the schema from the schema store using autocomplete to select an entity.
*
* @return {Object} The selected schema object.
*/
async function fetchSchemaFromSchemaStore() {
const { default: autocomplete } = await import(
'inquirer-autocomplete-standalone'
);
const categorizedSchemas = await categorizeSchemas();
const answer = await autocomplete({
message: 'Which group would you want to download?',
source: async (input) => {
const filteredEntities = await findSchema(input, categorizedSchemas)
return filteredEntities.map(schema => {
return {
value: schema,
description: `${schema} selected`
}
})
}
});
const result = categorizedSchemas.find(schema => schema.name === answer);
console.log(`${answer} has ${result.schemas.length} ${result.schemas.length === 1 ? 'schema' : 'schemata'}.`);
return result;
}
module.exports = {
categorizeSchemas,
findSchema,
fetchSchemaFromSchemaStore
}