-
Notifications
You must be signed in to change notification settings - Fork 27
/
generate-specs.js
147 lines (123 loc) · 5.14 KB
/
generate-specs.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
const yaml = require("js-yaml");
const fs = require("fs");
const path = require("path");
const uniqWith = require("lodash/uniqWith");
const isEqual = require("lodash/isEqual");
const sortBy = require("lodash/sortBy");
const merge = require("lodash/merge");
const specDir = "./analyzer-specs";
const slugList = [];
function validateSlug(slug) {
// Validate slug is unique
if (slugList.includes(slug)) {
throw new Error(`The slug ${slug} already exists, slugs must be unique`);
}
slugList.push(slug);
// Validate slug does not have underscores or spaces
if (!slug.match("^[A-Za-z0-9-]*$")) {
throw new Error(`The slug ${slug} can only contain letters, numbers and dashes`);
}
}
function validateCategory(category, file) {
// Validate category does not have dashes or spaces
if (!category.match("^[A-Za-z_]*$")) {
throw new Error(`The category ${category} in ${file} can only contain letters and underscores`);
}
}
function validateTag(tag, file) {
// Validate tag does not have underscores or spaces
if (!tag.match("^[A-Za-z0-9-]*$")) {
throw new Error(`The tag ${tag} in ${file} can only contain letters, numbers and dashes`);
}
}
const tags = [];
const categories = [];
const specs = [];
fs.readdir(specDir, (err, files) => {
if (err) throw err;
files.forEach((file) => {
if (!fs.statSync(specDir + "/" + file).isDirectory()) {
throw new Error(`files must live in a subdirectory with a unique name.`);
}
// Directory names have to be unique but this will validate directory naming conventions
validateSlug(file);
// This assumes everything in the top level director is a subdirectory
const subDirPath = specDir + "/" + file;
// Read the subdirectory files one at a time
const subFile = fs.readdirSync(subDirPath);
let subdirSpecs = [];
subFile.forEach(f => {
// Load YAML file contents
const doc = yaml.safeLoad(fs.readFileSync(path.resolve(subDirPath + "/" + f)));
// Add all tags from spec to the tags array (will be filtered later)
let newTags = JSON.parse(doc.metadata.annotations.tags)
newTags.map(tag => {
validateTag(tag, f);
tags.push(tag)
});
// Build and add a category object to the categories array (will be filtered later)
validateCategory(doc.metadata.annotations.category, f);
let categoryObj = new Object();
categoryObj.name = doc.metadata.annotations.category;
const displayName = doc.metadata.annotations.category.charAt(0).toUpperCase() + doc.metadata.annotations.category.slice(1);
categoryObj.display = displayName.replace(/_/gi, " ");
categories.push(categoryObj);
// Build and add a contributor object to the spec.contributors array
const contributorsArr = []
const contributors = JSON.parse(doc.metadata.annotations.contributors);
if (contributors.length > 0) {
contributors.map(c => {
contributorsArr.push({
name: c.name,
avatarUri: c.avatarUri || "/[email protected]"
})
})
} else {
contributorsArr.push({
name: "",
avatarUri: "/[email protected]"
})
}
// Build the spec object
let specObj = new Object();
specObj.slug = file;
specObj.category = doc.metadata.annotations.category;
specObj.title = doc.metadata.annotations.title;
specObj.description = doc.metadata.annotations.description;
specObj.iconUri = doc.metadata.annotations.iconUri || "/category-icons/default-category.svg";
specObj.contributors = contributorsArr;
specObj.tags = JSON.parse(doc.metadata.annotations.tags);
// Remove annotations before setting the yaml spec
delete doc["metadata"]["annotations"];
if (doc.kind === "Preflight") {
specObj.preflightSpecYaml = yaml.safeDump(doc);
}
if (doc.kind === "SupportBundle") {
specObj.supportSpecYaml = yaml.safeDump(doc);
}
// Add spec to specs array
subdirSpecs.push(specObj);
});
// If there is a preflight and support pair, merge the specs to a single object
if (subdirSpecs.length > 1) {
merge(subdirSpecs[0], subdirSpecs[1]);
}
// Push the spec into the specs array
specs.push(subdirSpecs[0]);
});
// Build JSON file with filtered tags and categories
const jsonFile = {
_comment: `This file is generated, do not change! Last generated on ${new Date()}. To regenerate run 'make generate-specs'`,
tags: [...new Set(tags)].sort(),
categories: uniqWith(sortBy(categories, c => c.name), isEqual),
specs
};
// Write finalized JSON file to static directory
fs.writeFile("./gatsby-theme-marketing/static/specs-gen.json", JSON.stringify(jsonFile), (err) => {
if (err) throw err;
console.log("\x1b[34m%s\x1b[0m", "Tags generated:", jsonFile.tags.length);
console.log("\x1b[34m%s\x1b[0m", "Categories generated:", jsonFile.categories.length);
console.log("\x1b[34m%s\x1b[0m", "Specs generated:", jsonFile.specs.length);
console.log("\x1b[32m%s\x1b[0m", "Successfully generated specs-gen.json to the ./gatsby-theme-marketing/static directory");
});
});