Skip to content

Commit 7b874fa

Browse files
mansonakategengler
authored andcommitted
fix tests for new frontmatter format
1 parent 5af9e78 commit 7b874fa

4 files changed

+202
-168
lines changed

.eslintrc.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,13 @@
1616
},
1717
"parserOptions": {
1818
"ecmaVersion": 2020
19-
}
19+
},
20+
"overrides": [
21+
{
22+
"files": "test/**/*.js",
23+
"env": {
24+
"mocha": true
25+
}
26+
}
27+
]
2028
}

lib/frontmatter-linter.js

+109-107
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,131 @@
11
const frontmatter = require('@github-docs/frontmatter');
22
const semver = require('semver');
3-
const { readdirSync } = require('fs');
4-
5-
const stages = readdirSync('./stages').map((filename) => filename.replace(/\.md$/, ''));
6-
const teams = readdirSync('./teams').map((filename) => filename.replace(/\.md$/, ''));
73

84
const releasedOrLaterStages = ['released', 'recommended'];
95

10-
const rules = {
11-
stage: {
12-
type: 'string',
13-
required: true,
14-
enum: stages,
15-
messages: {
16-
enum: `must be one of the RFC Stages: "${stages.join(
17-
'", "'
18-
)}" (See https://github.com/emberjs/rfcs#stages)`,
19-
},
20-
},
21-
'start-date': {
22-
type: 'date',
23-
required: true,
24-
allowEmpty: false,
25-
messages: {
26-
type: 'must be a date formatted YYYY-MM-DD',
27-
},
28-
},
29-
teams: {
30-
required: true,
31-
conform: function (value) {
32-
if (!value) {
33-
// it's ok for teams to be empty
34-
return true;
35-
}
36-
const result = value?.every((item) => teams.includes(item));
37-
// we need to warn like this because revalidator doesn't allow custom messages
38-
if (!result) {
39-
console.warn(`Invalid team in ${value}. Available teams: ${teams}`);
40-
}
41-
return result;
42-
},
43-
messages: {
44-
conform: `must only include any number of: ${teams}`,
45-
},
46-
},
47-
'proposal-pr': {
48-
required: true,
49-
allowEmpty: false,
50-
conform(url) {
51-
let regex = /https:\/\/github.com\/emberjs\/rfcs\/pull\/\d+(\/|$)$/;
52-
let cli = /https:\/\/github.com\/ember-cli\/rfcs\/pull\/\d+(\/|$)$/;
53-
return regex.test(url) || cli.test(url);
54-
},
55-
messages: {
56-
conform:
57-
'must be the URL for the original pull request on emberjs/rfcs, for example: https://github.com/emberjs/rfcs/pull/123',
58-
},
59-
},
60-
'Release Date': {
61-
type: 'date',
62-
required: true,
63-
allowEmpty: false,
64-
messages: {
65-
type: 'must be a date formatted YYYY-MM-DD',
66-
},
67-
},
68-
'Release Versions': {
69-
type: 'object',
70-
required: true,
71-
allowEmpty: true,
72-
conform(packages) {
73-
for (const package in packages) {
74-
if (!semver.valid(packages[package])) {
75-
return false;
76-
}
77-
}
78-
return true;
79-
},
80-
messages: {
81-
conform:
82-
'packages must each be set to the version in which the RFC work was released in that package (Should not be default vX.Y.Z, should be removed if irrelevant)',
83-
},
84-
},
85-
};
6+
module.exports = class FrontmatterLinter {
7+
constructor(stages = [], teams = []) {
8+
this.rules = {
9+
stage: {
10+
type: 'string',
11+
required: true,
12+
enum: stages,
13+
messages: {
14+
enum: `must be one of the RFC Stages: "${stages.join(
15+
'", "'
16+
)}" (See https://github.com/emberjs/rfcs#stages)`,
17+
},
18+
},
19+
'start-date': {
20+
type: 'date',
21+
required: true,
22+
allowEmpty: false,
23+
messages: {
24+
type: 'must be a date formatted YYYY-MM-DD',
25+
},
26+
},
27+
teams: {
28+
type: 'array',
29+
required: true,
30+
conform: function (value) {
31+
const result = value?.every((item) => teams.includes(item));
32+
// we need to warn like this because revalidator doesn't allow custom messages
33+
if (!result) {
34+
console.warn(`Invalid team in ${value}. Available teams: ${teams}`);
35+
}
36+
return result;
37+
},
38+
messages: {
39+
conform: `must only include any number of: ${teams}`,
40+
type: 'must be a list of one or more Ember teams',
41+
},
42+
},
43+
prs: {
44+
type: 'object',
45+
required: true,
46+
properties: {
47+
accepted: {
48+
required: true,
49+
allowEmpty: false,
50+
conform(url) {
51+
let regex = /https:\/\/github.com\/emberjs\/rfcs\/pull\/\d+(\/|$)$/;
52+
let cli = /https:\/\/github.com\/ember-cli\/rfcs\/pull\/\d+(\/|$)$/;
53+
return regex.test(url) || cli.test(url);
54+
},
55+
messages: {
56+
conform:
57+
'must be the URL for the original pull request on emberjs/rfcs, for example: https://github.com/emberjs/rfcs/pull/123',
58+
},
59+
},
60+
},
61+
},
62+
'release-date': {
63+
type: 'date',
64+
required: true,
65+
allowEmpty: false,
66+
messages: {
67+
type: 'must be a date formatted YYYY-MM-DD',
68+
},
69+
},
70+
'release-versions': {
71+
type: 'object',
72+
required: true,
73+
allowEmpty: true,
74+
conform(packages) {
75+
for (const p in packages) {
76+
if (!semver.valid(packages[p])) {
77+
return false;
78+
}
79+
}
80+
return true;
81+
},
82+
messages: {
83+
conform:
84+
'packages must each be set to the version in which the RFC work was released in that package (Should not be default vX.Y.Z, should be removed if irrelevant)',
85+
},
86+
},
87+
};
8688

87-
const defaultSchema = withRules(['stage', 'start-date', 'teams', 'proposal-pr']);
88-
const releasedOrLaterSchema = withRules([
89-
'stage',
90-
'start-date',
91-
'teams',
92-
'proposal-pr',
93-
'Release Date',
94-
'Release Versions',
95-
]);
89+
this.defaultSchema = this.withRules(['stage', 'start-date', 'teams', 'prs']);
90+
this.releasedOrLaterSchema = this.withRules([
91+
'stage',
92+
'start-date',
93+
'teams',
94+
'prs',
95+
'release-date',
96+
'release-versions',
97+
]);
98+
}
9699

97-
module.exports = class FrontmatterLinter {
98-
static lint(markdown) {
100+
lint(markdown) {
99101
const { data } = frontmatter(markdown);
100-
const schema = chooseSchema(data);
102+
const schema = this.chooseSchema(data);
101103
return this.lintWithSchema(markdown, schema);
102104
}
103105

104-
static lintWithSchema(markdown, schema) {
106+
lintWithSchema(markdown, schema) {
105107
const { errors } = frontmatter(markdown, { schema });
106108
return { messages: formatErrors(errors) };
107109
}
108-
};
109110

110-
function chooseSchema(data) {
111-
if (releasedOrLaterStages.includes(data['Stage'])) {
112-
return releasedOrLaterSchema;
111+
withRules(ruleNames) {
112+
let props = {};
113+
ruleNames.forEach((rule) => {
114+
props[rule] = this.rules[rule];
115+
});
116+
return { properties: props };
113117
}
114-
return defaultSchema;
115-
}
118+
119+
chooseSchema(data) {
120+
if (releasedOrLaterStages.includes(data['stage'])) {
121+
return this.releasedOrLaterSchema;
122+
}
123+
return this.defaultSchema;
124+
}
125+
};
116126

117127
function formatErrors(errors) {
118128
return errors.map((e) => {
119129
return `${e.property} ${e.message}`;
120130
});
121131
}
122-
123-
function withRules(ruleNames) {
124-
let props = {};
125-
ruleNames.forEach((rule) => {
126-
props[rule] = rules[rule];
127-
});
128-
return { properties: props };
129-
}

lint-rfc-frontmatter.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ const argv = require('yargs').command('* [paths..]', 'run lint on files', (yargs
88
}).argv;
99

1010
const Linter = require('./lib/frontmatter-linter');
11-
const fs = require('fs');
11+
const { readFileSync, readdirSync } = require('fs');
1212
const ResultReporter = require('./lib/result-reporter');
1313

14+
const stages = readdirSync('./stages').map((filename) => filename.replace(/\.md$/, ''));
15+
const teams = readdirSync('./teams').map((filename) => filename.replace(/\.md$/, ''));
16+
17+
const linter = new Linter(stages, teams);
18+
1419
let results = [];
1520
for (let path of argv.paths) {
16-
let file = fs.readFileSync(path, 'utf8');
17-
let { messages } = Linter.lint(file);
21+
let file = readFileSync(path, 'utf8');
22+
let { messages } = linter.lint(file);
1823
if (messages.length) {
1924
results.push({ key: path, messages });
2025
}

0 commit comments

Comments
 (0)