@larsgw/formica 0.9.2 → 0.10.0
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/lib/bin/process-resources-index.js +0 -0
- package/lib/bin/process-resources.d.ts +6 -1
- package/lib/bin/process-resources.js +116 -25
- package/lib/bin/validate-catalog.js +0 -0
- package/lib/bin/validate-resources-text.js +3 -1
- package/lib/resources/parse-text.js +6 -3
- package/lib/taxon-names/index.js +1 -1
- package/package.json +15 -13
- package/.gitattributes +0 -1
- package/.github/workflows/ci.yml +0 -27
- package/CHANGELOG.md +0 -390
- package/eslint.config.js +0 -34
- package/lib/bin/SHEETS.js +0 -0
- package/lib/bin/clean-links.d.ts +0 -2
- package/lib/bin/clean-links.js +0 -170
- package/lib/bin/download-place-shapes.js +0 -188
- package/lib/bin/index-place-shapes.js +0 -115
- package/lib/bin/process-resources-problems.js +0 -177
- package/lib/bin/validate-linked-data.js +0 -0
- package/lib/resources/content/clavis.js +0 -10
- package/lib/resources/content/index.js +0 -0
- package/lib/resources/content/sdd.js +0 -151
- package/lib/resources/sdd.js +0 -78
- package/src/bin/generate-linked-data.ts +0 -762
- package/src/bin/process-resources-index.ts +0 -100
- package/src/bin/process-resources.ts +0 -510
- package/src/bin/util.ts +0 -74
- package/src/bin/validate-catalog.ts +0 -122
- package/src/bin/validate-resources-text.ts +0 -25
- package/src/catalog/entities.ts +0 -62
- package/src/catalog/entity.ts +0 -116
- package/src/catalog/index.ts +0 -33
- package/src/catalog/tables/author.ts +0 -15
- package/src/catalog/tables/index.ts +0 -14
- package/src/catalog/tables/place.ts +0 -14
- package/src/catalog/tables/publisher.ts +0 -15
- package/src/catalog/tables/taxon.ts +0 -17
- package/src/catalog/tables/work.ts +0 -65
- package/src/catalog/value.ts +0 -51
- package/src/csv.ts +0 -33
- package/src/index.ts +0 -4
- package/src/module.d.ts +0 -148
- package/src/resources/diff-resource.ts +0 -226
- package/src/resources/index.ts +0 -4
- package/src/resources/parse-name.ts +0 -392
- package/src/resources/parse-text.ts +0 -408
- package/src/resources/resource.ts +0 -10
- package/src/taxon-names/index.ts +0 -79
- package/test/resources.js +0 -374
- package/tsconfig.json +0 -15
|
File without changes
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
export declare enum ResourceTaxonIdSource {
|
|
3
|
+
COL = "col",
|
|
4
|
+
GBIF = "gbif"
|
|
5
|
+
}
|
|
2
6
|
export declare enum ResourceProcessorSource {
|
|
3
7
|
All = "all",
|
|
4
8
|
Unprocessed = "unprocessed",
|
|
5
|
-
Modified = "modified"
|
|
9
|
+
Modified = "modified",
|
|
10
|
+
Dwc = "dwc"
|
|
6
11
|
}
|
|
@@ -43,18 +43,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.ResourceProcessorSource = void 0;
|
|
46
|
+
exports.ResourceProcessorSource = exports.ResourceTaxonIdSource = void 0;
|
|
47
47
|
const fs_1 = require("fs");
|
|
48
48
|
const path = __importStar(require("path"));
|
|
49
49
|
const child_process_1 = require("child_process");
|
|
50
50
|
const util = __importStar(require("util"));
|
|
51
51
|
const index_1 = require("../index");
|
|
52
52
|
const util_1 = require("./util");
|
|
53
|
+
var ResourceTaxonIdSource;
|
|
54
|
+
(function (ResourceTaxonIdSource) {
|
|
55
|
+
ResourceTaxonIdSource["COL"] = "col";
|
|
56
|
+
ResourceTaxonIdSource["GBIF"] = "gbif";
|
|
57
|
+
})(ResourceTaxonIdSource || (exports.ResourceTaxonIdSource = ResourceTaxonIdSource = {}));
|
|
53
58
|
var ResourceProcessorSource;
|
|
54
59
|
(function (ResourceProcessorSource) {
|
|
55
60
|
ResourceProcessorSource["All"] = "all";
|
|
56
61
|
ResourceProcessorSource["Unprocessed"] = "unprocessed";
|
|
57
62
|
ResourceProcessorSource["Modified"] = "modified";
|
|
63
|
+
ResourceProcessorSource["Dwc"] = "dwc";
|
|
58
64
|
})(ResourceProcessorSource || (exports.ResourceProcessorSource = ResourceProcessorSource = {}));
|
|
59
65
|
const DWC_FIELDS = [
|
|
60
66
|
'scientificNameID',
|
|
@@ -108,9 +114,14 @@ const GBIF_RANKS = [
|
|
|
108
114
|
'subspecies',
|
|
109
115
|
'variety'
|
|
110
116
|
];
|
|
111
|
-
|
|
117
|
+
const GNVERIFIER_SOURCES = {
|
|
118
|
+
gbif: 11,
|
|
119
|
+
col: 13
|
|
120
|
+
};
|
|
121
|
+
function runGnverifier(names, sources) {
|
|
122
|
+
const sourceArg = sources.map(source => GNVERIFIER_SOURCES[source]).join();
|
|
112
123
|
return new Promise((resolve, reject) => {
|
|
113
|
-
const proc = (0, child_process_1.spawn)('gnverifier', ['-s',
|
|
124
|
+
const proc = (0, child_process_1.spawn)('gnverifier', ['-s', sourceArg, '-f', 'compact', '-M']);
|
|
114
125
|
let stdout = '';
|
|
115
126
|
proc.stdout.on('data', data => { stdout += data; });
|
|
116
127
|
proc.stderr.pipe(process.stdout);
|
|
@@ -165,16 +176,44 @@ class ResourceProcessor {
|
|
|
165
176
|
}
|
|
166
177
|
run(source, config) {
|
|
167
178
|
return __awaiter(this, void 0, void 0, function* () {
|
|
179
|
+
if (source === ResourceProcessorSource.Dwc) {
|
|
180
|
+
return this.runDwc(config);
|
|
181
|
+
}
|
|
168
182
|
const ids = yield this.listWorks(source);
|
|
169
183
|
for (const id of ids) {
|
|
170
184
|
yield this.processWork(id, config);
|
|
171
185
|
}
|
|
172
186
|
});
|
|
173
187
|
}
|
|
188
|
+
runDwc(config) {
|
|
189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
const files = yield fs_1.promises.readdir(this.DIR_DWC);
|
|
191
|
+
files.sort(util_1.numericSort);
|
|
192
|
+
for (const file of files) {
|
|
193
|
+
const [workId, index] = path.basename(file, '.csv').split('-');
|
|
194
|
+
const resource = {
|
|
195
|
+
id: `${workId}:${index}`,
|
|
196
|
+
file: `${workId}-${index}`,
|
|
197
|
+
workId,
|
|
198
|
+
metadata: { levels: [] },
|
|
199
|
+
taxa: {}
|
|
200
|
+
};
|
|
201
|
+
const filePath = path.join(this.DIR_DWC, file);
|
|
202
|
+
const [header, ...rows] = index_1.csv.parseCsv(yield fs_1.promises.readFile(filePath, 'utf-8'));
|
|
203
|
+
for (const row of rows) {
|
|
204
|
+
const taxon = Object.fromEntries(header.map((h, i) => [h, row[i]]));
|
|
205
|
+
resource.taxa[taxon.scientificNameID] = taxon;
|
|
206
|
+
}
|
|
207
|
+
yield this.processResourceDwc(resource, config);
|
|
208
|
+
yield this.writeResourceDwc(resource);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
174
212
|
listWorks(source) {
|
|
175
213
|
return __awaiter(this, void 0, void 0, function* () {
|
|
176
214
|
switch (source) {
|
|
177
215
|
case ResourceProcessorSource.All:
|
|
216
|
+
case ResourceProcessorSource.Dwc:
|
|
178
217
|
return listFiles(this.DIR_TXT);
|
|
179
218
|
case ResourceProcessorSource.Unprocessed:
|
|
180
219
|
return listUnprocessedFiles(this.DIR_TXT, this.DIR_DWC);
|
|
@@ -188,15 +227,18 @@ class ResourceProcessor {
|
|
|
188
227
|
processWork(id, config) {
|
|
189
228
|
return __awaiter(this, void 0, void 0, function* () {
|
|
190
229
|
const resources = yield this.processResources(id, config);
|
|
191
|
-
yield Promise.all(resources.map(resource =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
230
|
+
yield Promise.all(resources.map(resource => this.writeResourceDwc(resource)));
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
writeResourceDwc(resource) {
|
|
234
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
235
|
+
const header = DWC_FIELDS;
|
|
236
|
+
const table = [header];
|
|
237
|
+
for (const id in resource.taxa) {
|
|
238
|
+
const taxon = resource.taxa[id];
|
|
239
|
+
table.push(header.map(column => taxon[column] || ''));
|
|
240
|
+
}
|
|
241
|
+
return fs_1.promises.writeFile(path.join(this.DIR_DWC, `${resource.file}.csv`), index_1.csv.formatCsv(table, ',').trim());
|
|
200
242
|
});
|
|
201
243
|
}
|
|
202
244
|
processResources(id, config) {
|
|
@@ -243,20 +285,18 @@ class ResourceProcessor {
|
|
|
243
285
|
const file = yield fs_1.promises.readFile(filePath, 'utf-8');
|
|
244
286
|
let old = undefined;
|
|
245
287
|
if (config.update) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
dwc.push(index_1.csv.parseCsv(yield getOldFile(filePath)));
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
old = { txt: yield getOldFile(filePath), dwc };
|
|
288
|
+
old = {
|
|
289
|
+
txt: yield getOldFile(filePath),
|
|
290
|
+
dwc: yield this.readResourceDwc(id)
|
|
291
|
+
};
|
|
254
292
|
}
|
|
255
293
|
const { resources } = yield Promise.resolve().then(() => __importStar(require('../index')));
|
|
256
294
|
return resources.parseTextFile(file, id, old);
|
|
257
295
|
}
|
|
258
296
|
catch (error) {
|
|
259
|
-
|
|
297
|
+
if (error instanceof Error) {
|
|
298
|
+
console.log(error.message);
|
|
299
|
+
}
|
|
260
300
|
yield (0, util_1.prompt)(`${id}: generating Darwin Core failed, retry? `);
|
|
261
301
|
// Clear cache to re-import
|
|
262
302
|
const prefix = path.dirname(require.resolve('../index'));
|
|
@@ -269,10 +309,25 @@ class ResourceProcessor {
|
|
|
269
309
|
}
|
|
270
310
|
});
|
|
271
311
|
}
|
|
312
|
+
readResourceDwc(id) {
|
|
313
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
314
|
+
const dwc = [];
|
|
315
|
+
for (const file of yield fs_1.promises.readdir(this.DIR_DWC)) {
|
|
316
|
+
if (file.startsWith(id + '-')) {
|
|
317
|
+
const filePath = path.join(this.DIR_DWC, file);
|
|
318
|
+
dwc.push(index_1.csv.parseCsv(yield getOldFile(filePath)));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return dwc;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
272
324
|
processResourceDwc(resource, config) {
|
|
273
325
|
return __awaiter(this, void 0, void 0, function* () {
|
|
274
326
|
console.log(`${resource.workId}: matching ${resource.id}`);
|
|
275
|
-
|
|
327
|
+
// If not all mappings will be rerun and the mappings are not already provided,
|
|
328
|
+
// read the existing DwC files and add the corresponding mappings.
|
|
329
|
+
const hasMappings = Object.values(resource.taxa).some(taxon => 'gbifAcceptedTaxonID' in taxon || 'colAcceptedTaxonID' in taxon);
|
|
330
|
+
if (!hasMappings && config.updateMappings.length < 2) {
|
|
276
331
|
const file = path.join(this.DIR_DWC, resource.file + '.csv');
|
|
277
332
|
if ((0, fs_1.existsSync)(file)) {
|
|
278
333
|
const [header, ...rows] = index_1.csv.parseCsv(yield fs_1.promises.readFile(file, 'utf-8'));
|
|
@@ -290,6 +345,8 @@ class ResourceProcessor {
|
|
|
290
345
|
}
|
|
291
346
|
}
|
|
292
347
|
}
|
|
348
|
+
}
|
|
349
|
+
if (config.updateMappings.length === 0) {
|
|
293
350
|
return resource;
|
|
294
351
|
}
|
|
295
352
|
const filteredResults = {};
|
|
@@ -304,7 +361,7 @@ class ResourceProcessor {
|
|
|
304
361
|
names.add(name);
|
|
305
362
|
filteredResults[id] = [];
|
|
306
363
|
}
|
|
307
|
-
const result = yield runGnverifier(Array.from(names).join('\n'));
|
|
364
|
+
const result = yield runGnverifier(Array.from(names).join('\n'), config.updateMappings);
|
|
308
365
|
for (const results of result.trim().split('\n')) {
|
|
309
366
|
const { name, results: matches } = JSON.parse(results);
|
|
310
367
|
if (!matches) {
|
|
@@ -339,6 +396,16 @@ class ResourceProcessor {
|
|
|
339
396
|
// for non-synonyms).
|
|
340
397
|
continue;
|
|
341
398
|
}
|
|
399
|
+
// https://github.com/gnames/gnverifier/issues/156
|
|
400
|
+
if (source === 1 || source === 13 && match.recordId !== match.currentRecordId) {
|
|
401
|
+
const [a, b, c] = match.recordId.split('|');
|
|
402
|
+
if (b && c) {
|
|
403
|
+
if (a !== c || b !== match.currentRecordId) {
|
|
404
|
+
throw new Error(`Unexpected recordId format ${match.recordId}`);
|
|
405
|
+
}
|
|
406
|
+
match.recordId = a;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
342
409
|
if (!filteredResults[loirId]) {
|
|
343
410
|
filteredResults[loirId] = [];
|
|
344
411
|
}
|
|
@@ -468,18 +535,42 @@ function main() {
|
|
|
468
535
|
'keep-mappings': {
|
|
469
536
|
type: 'boolean',
|
|
470
537
|
short: 'k'
|
|
538
|
+
},
|
|
539
|
+
'update-mappings': {
|
|
540
|
+
type: 'string',
|
|
541
|
+
short: 'u',
|
|
542
|
+
multiple: true
|
|
471
543
|
}
|
|
472
544
|
},
|
|
473
545
|
allowPositionals: true
|
|
474
546
|
});
|
|
547
|
+
if (!Object.values(ResourceProcessorSource).includes(args.values.source)) {
|
|
548
|
+
throw new Error(`Unknown argument "--source ${args.values.source}"`);
|
|
549
|
+
}
|
|
550
|
+
const mappingSources = Object.values(ResourceTaxonIdSource);
|
|
551
|
+
let updateMappings = mappingSources;
|
|
552
|
+
if (args.values['keep-mappings']) {
|
|
553
|
+
if (args.values['update-mappings']) {
|
|
554
|
+
throw new Error('Cannot provide both --keep-mappings (-k) and --update-mappings (-u)');
|
|
555
|
+
}
|
|
556
|
+
updateMappings = [];
|
|
557
|
+
}
|
|
558
|
+
else if (args.values['update-mappings']) {
|
|
559
|
+
for (const source of args.values['update-mappings']) {
|
|
560
|
+
if (!mappingSources.includes(source)) {
|
|
561
|
+
throw new Error(`Unknown argument "--update-mappings ${args.values.source}"`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
updateMappings = args.values['update-mappings'];
|
|
565
|
+
}
|
|
475
566
|
const processor = new ResourceProcessor(args.positionals[0]);
|
|
476
567
|
process.on('exit', () => {
|
|
477
568
|
process.stdout.write('\n');
|
|
478
569
|
});
|
|
479
570
|
const source = args.values.source;
|
|
480
571
|
const config = {
|
|
481
|
-
update: source
|
|
482
|
-
updateMappings
|
|
572
|
+
update: source === ResourceProcessorSource.All || source === ResourceProcessorSource.Modified,
|
|
573
|
+
updateMappings
|
|
483
574
|
};
|
|
484
575
|
processor.run(source, config).catch(error => {
|
|
485
576
|
console.error(error);
|
|
File without changes
|
|
@@ -57,7 +57,9 @@ function main(args) {
|
|
|
57
57
|
index_1.resources.parseTextFile(file, id);
|
|
58
58
|
}
|
|
59
59
|
catch (error) {
|
|
60
|
-
|
|
60
|
+
if (error instanceof Error) {
|
|
61
|
+
console.error(filePath + '\n' + error.message.replace(/^/gm, ' ') + '\n');
|
|
62
|
+
}
|
|
61
63
|
exitStatus = 1;
|
|
62
64
|
}
|
|
63
65
|
}
|
|
@@ -147,7 +147,7 @@ function parseResource(resource) {
|
|
|
147
147
|
config = parseHeader(header);
|
|
148
148
|
}
|
|
149
149
|
catch (error) {
|
|
150
|
-
throw makeParseError(error.message, resource.offsetLine + 1);
|
|
150
|
+
throw makeParseError(error instanceof Error ? error.message : 'Error', resource.offsetLine + 1);
|
|
151
151
|
}
|
|
152
152
|
const content = rest.join('');
|
|
153
153
|
const offsetLine = resource.offsetLine + (header + _).split('\n').length - 1;
|
|
@@ -257,7 +257,7 @@ function parseResourceContent(content, resource, oldIds, offsetLine) {
|
|
|
257
257
|
item = error.result;
|
|
258
258
|
}
|
|
259
259
|
else {
|
|
260
|
-
errors.push(makeParseError(error.message, lineNumber));
|
|
260
|
+
errors.push(makeParseError(error instanceof Error ? error.message : 'Error', lineNumber));
|
|
261
261
|
continue;
|
|
262
262
|
}
|
|
263
263
|
}
|
|
@@ -382,7 +382,10 @@ function parseFile(file, id, old) {
|
|
|
382
382
|
resources.push(parseResourceContent(diff, template, oldIds, content.offsetLine));
|
|
383
383
|
}
|
|
384
384
|
catch (error) {
|
|
385
|
-
|
|
385
|
+
if (error instanceof SyntaxError) {
|
|
386
|
+
errors.push(error);
|
|
387
|
+
}
|
|
388
|
+
throw error;
|
|
386
389
|
}
|
|
387
390
|
}
|
|
388
391
|
if (errors.length) {
|
package/lib/taxon-names/index.js
CHANGED
|
@@ -57,7 +57,7 @@ function groupNameMatches(results) {
|
|
|
57
57
|
function amendResource(resource, source, matches) {
|
|
58
58
|
for (const id in matches) {
|
|
59
59
|
const match = matches[id];
|
|
60
|
-
if (source === '1') {
|
|
60
|
+
if (source === '1' || source === '13') {
|
|
61
61
|
resource.taxa[id].colTaxonID = match.id;
|
|
62
62
|
if (match.currentId) {
|
|
63
63
|
resource.taxa[id].colAcceptedTaxonID = match.currentId;
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larsgw/formica",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "SDK and tools for data from the Library of Identification Resources",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib"
|
|
9
|
+
],
|
|
7
10
|
"bin": {
|
|
8
|
-
"loir-validate-catalog": "
|
|
9
|
-
"loir-validate-resources": "
|
|
10
|
-
"loir-resources-process": "
|
|
11
|
-
"loir-resources-index": "
|
|
12
|
-
"loir-generate-linked-data": "
|
|
13
|
-
"loir-catalog-clean-links": "./lib/bin/clean-links.js"
|
|
11
|
+
"loir-validate-catalog": "lib/bin/validate-catalog.js",
|
|
12
|
+
"loir-validate-resources": "lib/bin/validate-resources-text.js",
|
|
13
|
+
"loir-resources-process": "lib/bin/process-resources.js",
|
|
14
|
+
"loir-resources-index": "lib/bin/process-resources-index.js",
|
|
15
|
+
"loir-generate-linked-data": "lib/bin/generate-linked-data.js"
|
|
14
16
|
},
|
|
15
17
|
"scripts": {
|
|
16
18
|
"test": "node --test --test-reporter spec",
|
|
@@ -33,22 +35,22 @@
|
|
|
33
35
|
"homepage": "https://github.com/identification-resources/formica#readme",
|
|
34
36
|
"dependencies": {
|
|
35
37
|
"ietf-language-tag-regex": "^0.0.5",
|
|
36
|
-
"js-yaml": "^
|
|
38
|
+
"js-yaml": "^5.2.1",
|
|
37
39
|
"jsonld": "^9.0.0",
|
|
38
|
-
"n3": "^1.
|
|
40
|
+
"n3": "^2.1.1",
|
|
39
41
|
"spdx-license-list": "^6.6.0"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@eslint/eslintrc": "^3.3.1",
|
|
43
|
-
"@eslint/js": "^
|
|
45
|
+
"@eslint/js": "^10.0.1",
|
|
44
46
|
"@types/js-yaml": "^4.0.5",
|
|
45
47
|
"@types/jsonld": "^1.5.15",
|
|
46
48
|
"@types/n3": "^1.24.2",
|
|
47
|
-
"@types/node": "^
|
|
49
|
+
"@types/node": "^26.1.1",
|
|
48
50
|
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
|
49
51
|
"@typescript-eslint/parser": "^8.32.0",
|
|
50
52
|
"conventional-changelog-cli": "^5.0.0",
|
|
51
|
-
"eslint": "^
|
|
52
|
-
"typescript": "^
|
|
53
|
+
"eslint": "^10.6.0",
|
|
54
|
+
"typescript": "^6.0.3"
|
|
53
55
|
}
|
|
54
56
|
}
|
package/.gitattributes
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*.ts linguist-language=TypeScript
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: Node.js CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ "main" ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ "main" ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
build:
|
|
11
|
-
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [20.x, 22.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v3
|
|
20
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
-
uses: actions/setup-node@v3
|
|
22
|
-
with:
|
|
23
|
-
node-version: ${{ matrix.node-version }}
|
|
24
|
-
- run: npm install
|
|
25
|
-
- run: npm run build
|
|
26
|
-
- run: npm run lint
|
|
27
|
-
- run: npm test
|