-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplopfile.js
More file actions
343 lines (330 loc) · 13.7 KB
/
plopfile.js
File metadata and controls
343 lines (330 loc) · 13.7 KB
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
'use strict';
const fs = require('fs');
const remark = require('remark');
const recommended = require('remark-preset-lint-recommended');
const html = require('remark-html');
const reporter = require('vfile-reporter');
const { makeDestPath, getRelativeToBasePath } = require('node-plop/lib/actions/_common-action-utils');
const glob = require('glob').sync;
const pckg = require('./package.json');
const Promise = require('bluebird');
const today = new Date().toISOString().split('T')[0];
const months = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
const formatDate = date => {
const dateObj = new Date(date);
return `${dateObj.getDate()} ${months[dateObj.getMonth()]} ${dateObj.getFullYear()}`;
}
const removeComments = answer => answer.replace(/(?:^|\n)\# [^\n]*/g, '').replace(/(?:(?:^|\n)\#)+\n/g, '\n').trim();
const render = remark().use(recommended).use(html).process;
const report = vfile => console.error(reporter(vfile)) || vfile;
const readFile = Promise.promisify(fs.readFile);
const writeFile = Promise.promisify(fs.writeFile);
const markdown = (answers, config, plop) => {
const fileDestPath = makeDestPath(answers, config, plop);
return readFile(config.source)
.then(render)
.then(report)
.then(vfile => writeFile(fileDestPath, vfile.contents))
.then(() => getRelativeToBasePath(fileDestPath, plop));
};
const HELP = `#
# HELP: all lines that start with a hash and a space (# ), like these help
# instructions, will be ignored - otherwise, all content is treated as markdown
# syntax, see: https://www.markdownguide.org/basic-syntax/ for details.`;
const otherContactsInstructions = `
# Please enter the details of the contact methods.
${HELP}
#
# Below are some examples that show the desired style:
#
# - text-phone - 03 8398 74663
# - your local Post Office
# - our offices:
# Home Office
# 2 Marsham Street
# Westminster
# London
# SW1P 4DF
# - further details on our [Contact Us page](/contact "Contact Us")
#
# NOTE: the spacing on the address lines is important to keep it part of the
# same list item (4 spaces at the start of those lines). Also each list item
# line should begin with a dash (-) and 3 spaces.
`;
const nonComplianceInstructions = `
# Please enter the details of any non-compliance issues. For each issue make
# sure you add:
# 1. a description of the issue, and what the effect will be for users
# 2. the WCAG 2.1 guideline that has not been met, if there is one
# 3. the date you plan to fix the issue
${HELP}
#
# Below are some examples that show the desired style:
#
# - Some images do not have a text alternative, so people using a screen
# reader cannot access the information.
# This fails WCAG guideline 1.1 Text Alternatives.
# We plan to add text alternatives for all images by September 2020. When
# we publish new content we’ll make sure our use of images meets
# accessibility standards.
# - Some of the input fields on the application form do not have clear labels
# which means they are not described well by screen readers. This could
# cause some users to not know what information they need to provide and
# stop them from completing the form.
# We plan to resolve this problem by 1 November 2020.
#
# NOTE: the dash (-), and 3 spaces, at the start of each issue, and spacing on
# the following lines are important to keep it part of the same list item (4
# spaces at the start of those lines).
`;
const disproportionateBurdenInstructions = `
# Please enter the details of the disproportionate burden claims.
#
# NOTE: it is strongly recommended that you not rely on claiming a
# disproportionate burden. It is the Home Office's view not to claim
# disproportionate burden at any point. If you still wish to make a claim
# please contact access@digital.homeoffice.gov.uk
${HELP}
`;
const outOfScopeInstructions = `
# Please enter a title and a description of any items not covered by the
# regulations.
${HELP}
#
# Below are some examples that show the desired style:
#
# #### PDFs and other documents
# Some of our PDFs and Word documents are essential to providing our services.
# For example we have PDFs with information on how users can access our
# services, and forms published as Word documents. By September 2020, we plan
# to either fix these or replace them with accessible HTML pages.
#
# The accessibility regulations do not require us to fix PDFs or other
# documents published before 23 September 2018 if they’re not essential to
# providing our services. For example, we do not plan to fix [example of
# non-essential document].
#
# Any new PDFs or Word documents we publish will meet accessibility standards.
#
# #### Live video
# We do not plan to add captions to live video streams because live video is
# exempt from meeting the accessibility regulations.
#
# NOTE: the 4 hash symbols (#### ), represent the appropriate heading style for
# the point in the statement, please prefix your titles with that.
`;
const complianceLevels = [
{ name: 'Yes, our service has been tested and is fully compliant', value: 'full', short: 'fully compliant' },
{ name: 'Our service has been tested and is mostly compliant', value: 'partial', short: 'partially compliant' },
{ name: 'Our service has been tested but is not compliant', value: 'not', short: 'non-compliant' },
{ name: 'No accessibility testing has been completed yet', value: 'untested', short: 'never tested' }
];
const stringifyComplianceStatus = input => input.map(i => i.replace(/ .*$/, '').toLowerCase()).join(' and ');
const promptFormat = ['d', '/', 'm', '/', 'yyyy'];
module.exports = (plop) => {
plop.setPrompt('date', require('inquirer-datepicker-prompt'));
plop.setHelper('formatDate', formatDate);
plop.setHelper('json', obj => JSON.stringify(obj));
plop.setHelper('natural-list', list => list.join(' and '));
plop.setActionType('markdown', markdown);
plop.setGenerator('basics', {
description: pckg.description,
prompts: [{
type: 'input',
name: 'title',
message: 'Please enter the title of the service'
}, {
type: 'input',
name: 'scope',
message: 'Please enter the scope of the service'
}, {
type: 'input',
name: 'organisation',
message: 'Please enter the name of the organisation responsible for the service'
}, {
type: 'checkbox',
name: 'accessibility-features',
message: 'Please select the accessibility features your service supports from the list',
choices: [
{ name: 'Change colours, contrast levels and fonts', short: 'change styles' },
{ name: 'Zoom in up to 300% without the text spilling off the screen', short: 'zoom' },
{ name: 'Navigate most of the website using just a keyboard', short: 'keyboard navigation' },
{ name: 'Navigate most of the website using speech recognition software', short: 'speech navigation' },
{ name: 'Listen to most of the website using a screen reader ' +
'(including the most recent versions of JAWS, NVDA and VoiceOver)', short: 'screen reader friendly' }
].map(c => ({ value: c.name, ...c }))
}, {
type: 'input',
name: 'email-address',
message: 'Please enter the email address where users can get help with the service'
}, {
type: 'input',
name: 'phone-number',
message: 'Please enter a phone number where users can get help with the service [optional]'
}, {
type: 'confirm',
name: 'other-contacts',
message: 'Are there any other forms of contact where users can get help with the service?'
}, {
type: 'editor',
name: 'other-contacts',
message: 'Please enter the details of the contact methods in the editor...',
default: otherContactsInstructions,
askAnswered: true,
when: answers => answers['other-contacts'] === true,
filter: removeComments
}, {
type: 'number',
name: 'response-time',
message: 'Please enter the maximum response time (in days)'
}, {
type: 'input',
name: 'how-to-report-issues',
message: 'Please describe the process for reporting accessibility issues to your organisation'
}, {
type: 'input',
name: 'issues-contact',
message: 'Please provide contact details for the unit or person responsible for dealing with reports'
}, {
type: 'confirm',
name: 'contact-phone-person',
message: 'Can users contact you by phone or in person?'
}, {
type: 'confirm',
name: 'deaf',
message: 'Do you provide a text relay service for people with a hearing impairment or a speech impediment?'
}, {
type: 'confirm',
name: 'induction-loops',
message: 'Do you provide audio induction loops in your offices, and can users book a sign language translator?'
}, {
type: 'input',
name: 'contact-page-link',
message: 'If you have a link to a contact page, please enter the URL [optional]'
}, {
type: 'rawlist',
name: 'compliance.level',
message: 'Has your service been tested and verified to be WCAG 2.1 AA compliant?',
choices: complianceLevels,
filter: (input, answers) => {
answers.compliance = {
...answers.compliance,
[input]: true
};
if (input !== complianceLevels[0].value) {
answers.compliance['non-accessible'] = true;
}
return complianceLevels.indexOf(complianceLevels.find(c => c.value === input)) + 1;
}
}, {
type: 'confirm',
name: 'compliance.non-accessible',
message: 'Would you still like to include the boilerplate "Non-accessible content" section?',
when: answers => answers.compliance.full
}, {
type: 'checkbox',
name: 'compliance.status',
message: 'What types of issues does your service have? [Select both if they apply]',
choices: [{
name: 'Non-compliances - i.e. content in scope of the regulations but with accessibility issues',
short: 'non-compliances'
}, {
name: 'Exemptions - i.e. inaccessible content that is out of scope of the regulations, ' +
'or it’d be a disproportionate burden for you to make it accessible',
short: 'exemptions'
}].map(c => ({ value: c.short, ...c })),
validate: answer => !!(answer && answer.length),
when: answers => answers.compliance['non-accessible']
}, {
type: 'editor',
name: 'non-compliance-list',
message: 'Please enter the details of any non-compliance issues in the editor...',
default: nonComplianceInstructions,
askAnswered: true,
when: answers => !answers.compliance.untested && answers.compliance.status.some(l => l === 'non-compliances'),
filter: removeComments
}, {
type: 'confirm',
name: 'disproportionate-burden-list',
message: 'Are you planning to claim a disproportionate burden?',
when: answers => !answers.compliance.full && !answers.compliance.untested
}, {
type: 'editor',
name: 'disproportionate-burden-list',
message: 'Please enter the details of disproportionate burden claims in the editor...',
default: disproportionateBurdenInstructions,
askAnswered: true,
when: answers => answers['disproportionate-burden-list'] === true,
filter: removeComments
}, {
type: 'editor',
name: 'not-in-scope-list',
message: 'Please enter details of items not covered by the regulations in the editor...',
default: outOfScopeInstructions,
askAnswered: true,
when: answers => answers.compliance.status.some(l => l === 'exemptions'),
filter: removeComments
}, {
type: 'date',
name: 'date-first-published',
message: 'Please enter the date this statement will be published',
format: promptFormat,
date: { max: today }
// }, {
// type: 'date',
// name: 'date-last-reviewed',
// message: 'Please enter the date this statement was last reviewed'
}, {
type: 'date',
name: 'date-tested',
message: 'Please enter the date the last accessibility test was completed',
format: promptFormat,
date: { max: today },
when: answers => !answers.compliance.untested
}, {
type: 'confirm',
name: 'home-office-tested',
message: 'Was the accessibility testing carried out by the Home Office?',
when: answers => !answers.compliance.untested
}, {
type: 'input',
name: 'organisation-tested',
message: 'Please enter the name of the organisation that did the test, or leave blank if your team did it',
when: answers => !answers.compliance.untested && !answers['home-office-tested']
}, {
type: 'input',
name: 'extra-test-info',
message: 'Please enter any extra details about how the testing was carried out [optional]',
when: answers => !answers.compliance.untested
}],
actions: answers => {
process.chdir(plop.getPlopfilePath());
const pathName = `accessibility-statements/${answers.title}-${today}`;
const versions = glob(pathName + '*')
.map(p => p.match(/-v(?<version>\d+)\.\w+/))
.map(v => parseInt(v ? v.groups.version : 0, 10));
const version = versions.length && (Math.max(...versions) + 1);
const pathNameVersion = `${pathName}${version ? '-v' + version : ''}`;
const data = {
'date-last-reviewed': today
};
return [{
type: 'add',
path: `${pathNameVersion}.json`,
template: '{{#json this}}{{/json}}',
data
}, {
type: 'add',
path: `${pathNameVersion}.md`,
templateFile: 'statement-template.md.hbs',
data
}, {
type: 'markdown',
path: `${pathNameVersion}.html`,
source: `${pathNameVersion}.md`
}];
}
});
return plop;
};