-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmanual-add.js
148 lines (138 loc) · 4.01 KB
/
manual-add.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
#!/usr/bin/env node
import path from 'node:path';
import fs from 'node:fs';
import { styleText } from 'node:util';
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
import ora from 'ora';
import { Glob } from 'glob';
import { parseAllDocuments } from 'yaml';
import addFromStex from '../actions/fetch/fetch.js';
import { urlToFileId } from '../actions/fetch/util.js';
import sc4d from './sc4d.js';
import tsc from './tsc.js';
// # run()
async function run(urls, argv) {
// Sort the urls in ascending order so that dependencies are likely to be
// processed first.
urls = [urls].flat().sort();
let dependencyIndex = await buildIndex();
// Once we have the index, we'll still filter out the urls that are already
// processed. They might either be present on the Simtropolis channel, or on
// the default channel already.
urls = urls.filter(url => {
let id = urlToFileId(url);
let pkg = dependencyIndex.stex[id];
if (pkg && !pkg.local) {
console.log(styleText('yellow', `${url} is already present on one of the channels`));
return false;
} else {
return true;
}
});
const {
cache = path.resolve(
process.env.LOCALAPPDATA,
'io.github.memo33/sc4pac/cache',
),
} = argv;
const result = await addFromStex({
cache,
id: urls.length > 0 && urls.map(url => urlToFileId(url)).join(','),
requireMetadata: argv.requireMetadata ?? false,
splitOffResources: argv.split ?? false,
darkniteOnly: argv.darkniteOnly ?? false,
after: argv.after,
dependencies: 'auto',
dependencyIndex,
});
for (let pkg of result.packages) {
let { errors = [] } = pkg;
if (errors.length > 0) {
console.error(styleText('red', `There was an error with ${pkg.url}:`));
}
for (let error of errors) {
console.error(error);
}
}
}
// # buildIndex()
// This function builds up the index that maps all stex urls that have a package
const defaultUrl = 'https://memo33.github.io/sc4pac/channel/';
async function buildIndex() {
let spinner = ora(`Building up package index`).start();
let index = {
stex: {},
sc4e: {},
sc4d,
tsc,
};
await Promise.all([
buildChannelIndex(index, defaultUrl),
buildLocalIndex(index),
]);
spinner.succeed('Package index built');
return index;
}
// # buildChannelIndex(index, channel)
// Fetches a channel from a url and adds it to the index.
async function buildChannelIndex(index, channel) {
let url = new URL('./sc4pac-channel-contents.json', channel);
let { packages } = await fetch(url).then(res => res.json());
for (let pkg of packages) {
let { externalIds } = pkg;
if (!externalIds) continue;
for (let key of ['stex', 'sc4e']) {
let ids = externalIds[key] ?? [];
for (let id of ids) {
let name = `${pkg.group}:${pkg.name}`;
(index[key][id] ??= new Map()).set(name, {
id: name,
subfolder: pkg.category[0],
});
}
}
}
}
// # buildLocalIndex(index)
// Completes the package index with all our local packages. We don't fetch the
// packages from the channel url because we may have local packages that we
// require as dependencies.
async function buildLocalIndex(index) {
const glob = new Glob('**/*.yaml', {
cwd: path.resolve(import.meta.dirname, '../src'),
absolute: true,
});
let tasks = [];
for await (let file of glob) {
tasks.push(addFileToIndex(index, file));
}
await Promise.all(tasks);
}
// # addFileToIndex(index, file)
async function addFileToIndex(index, file) {
let buffer = await fs.promises.readFile(file);
let docs = parseAllDocuments(String(buffer));
for (let doc of docs) {
let parsed = doc.toJSON();
if (!parsed) continue;
if (parsed.assetId) continue;
if (!parsed.info) continue;
let {
website,
websites = [website].filter(Boolean),
} = parsed.info;
for (let website of websites) {
let id = urlToFileId(website);
let name = `${parsed.group}:${parsed.name}`;
(index.stex[id] ??= new Map()).set(name, {
id: name,
subfolder: parsed.subfolder,
local: true,
});
index.stex[id].local = true;
}
}
}
const { argv } = yargs(hideBin(process.argv));
await run(argv._, argv);