Skip to content

Commit 1418dd6

Browse files
authored
Merge pull request #827 from citation-file-format/825-extra-cff-fields
2 parents 53060af + e13d335 commit 1418dd6

File tree

14 files changed

+293
-21
lines changed

14 files changed

+293
-21
lines changed

cypress/e2e/errors.cy.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,95 @@ describe('From a fixed app', () => {
267267
.should('not.have.class', 'q-field--error')
268268
cy.checkThatAppValidityIs(true)
269269
})
270+
271+
it('should validate screen Extra CFF Fields', () => {
272+
cy.visit('/extra-cff-fields')
273+
// no errors initially
274+
cy.checkThatAppValidityIs(true)
275+
276+
// YAML errors
277+
cy.dataCy('input-extra-cff-fields')
278+
.type('a: -')
279+
cy.checkThatAppValidityIs(false)
280+
cy.dataCy('list-raw-errors')
281+
.children()
282+
.should('have.length', 1)
283+
cy.dataCy('item-raw-error-keyword-0')
284+
.should('contain.text', 'keyword: "Extra CFF Fields error"')
285+
cy.dataCy('item-raw-error-message-0')
286+
.should('contain.text', 'YAML Error: end of the stream')
287+
288+
// wrong field
289+
cy.dataCy('input-extra-cff-fields')
290+
.clear()
291+
.type('bad: field')
292+
cy.checkThatAppValidityIs(false)
293+
cy.dataCy('list-raw-errors')
294+
.children()
295+
.should('have.length', 1)
296+
cy.dataCy('item-raw-error-keyword-0')
297+
.should('contain.text', 'additionalProperties')
298+
cy.dataCy('item-raw-error-message-0')
299+
.should('contain.text', 'must NOT have additional properties')
300+
301+
// preferred-citation
302+
cy.dataCy('input-extra-cff-fields')
303+
.clear()
304+
.type('preferred-citation:')
305+
cy.checkThatAppValidityIs(false)
306+
cy.dataCy('list-raw-errors')
307+
.children()
308+
.should('have.length', 1)
309+
cy.dataCy('item-raw-error-instancePath-0')
310+
.should('contain.text', '/preferred-citation')
311+
cy.dataCy('item-raw-error-message-0')
312+
.should('contain.text', 'must be object')
313+
314+
cy.dataCy('input-extra-cff-fields')
315+
.type('\n title: The Paper')
316+
cy.dataCy('list-raw-errors')
317+
.children()
318+
.should('have.length', 2)
319+
cy.dataCy('item-raw-error-instancePath-0')
320+
.should('contain.text', '/preferred-citation')
321+
cy.dataCy('item-raw-error-instancePath-1')
322+
.should('contain.text', '/preferred-citation')
323+
cy.dataCy('item-raw-error-message-0')
324+
.should('contain.text', "must have required property 'authors'")
325+
cy.dataCy('item-raw-error-message-1')
326+
.should('contain.text', "must have required property 'type'")
327+
328+
cy.dataCy('input-extra-cff-fields')
329+
.type('\n type: article\n authors:')
330+
cy.dataCy('list-raw-errors')
331+
.children()
332+
.should('have.length', 1)
333+
cy.dataCy('item-raw-error-instancePath-0')
334+
.should('contain.text', '/preferred-citation/authors')
335+
cy.dataCy('item-raw-error-message-0')
336+
.should('contain.text', 'must be array')
337+
338+
cy.dataCy('input-extra-cff-fields')
339+
.type(' [{}]')
340+
cy.checkThatAppValidityIs(true)
341+
342+
// Duplicate fields
343+
cy.dataCy('input-extra-cff-fields')
344+
.clear()
345+
.type('title: Another title\n')
346+
cy.dataCy('list-raw-errors')
347+
.children()
348+
.should('have.length', 1)
349+
cy.dataCy('item-raw-error-keyword-0')
350+
.should('contain.text', 'keyword: "Extra CFF Fields error"')
351+
cy.dataCy('item-raw-error-message-0')
352+
.should('contain.text', "Duplicate keys: 'title'")
353+
cy.dataCy('input-extra-cff-fields')
354+
.type('message: Another message')
355+
cy.dataCy('list-raw-errors')
356+
.children()
357+
.should('have.length', 1)
358+
cy.dataCy('item-raw-error-message-0')
359+
.should('contain.text', "Duplicate keys: 'title', 'message'")
360+
})
270361
})

cypress/e2e/navigation.cy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const stepNames = [
88
'abstract',
99
'keywords',
1010
'license',
11-
'version-specific'
11+
'version-specific',
12+
'extra-cff-fields'
1213
] as Array<StepNameType>
1314

1415
describe('App navigation', () => {

cypress/e2e/spec.cy.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ const fullValidCff = {
3636
license: 'Apache-2.0',
3737
commit: '123',
3838
version: 'v1.2.3',
39-
'date-released': '2022-01-01'
39+
'date-released': '2022-01-01',
40+
'preferred-citation': {
41+
authors: [{ 'given-names': 'Some', 'family-names': 'Body' }],
42+
title: 'The Paper',
43+
type: 'article'
44+
}
4045
}
4146

4247
describe('Basic usage', () => {
@@ -225,6 +230,13 @@ describe('Basic usage', () => {
225230
cy.dataCy('btn-next')
226231
.click()
227232

233+
// Extra CFF fields screen
234+
cy.url().should('include', '/extra-cff-fields')
235+
cy.dataCy('input-extra-cff-fields')
236+
.type('preferred-citation:\n authors:\n - given-names: Some\n family-names: Body\n title: The Paper\n type: article')
237+
cy.dataCy('btn-next')
238+
.click()
239+
228240
// Finish screen
229241
cy.url().should('include', '/finish')
230242
cy.dataCy('btn-download')

src/components/RawErrorList.vue

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<h2 v-if="errors.length > 0">
3+
Error list
4+
</h2>
5+
<q-list
6+
data-cy="list-raw-errors"
7+
dense
8+
separator
9+
>
10+
<q-item
11+
v-for="(error, errorIndex) in errors"
12+
v-bind:key="errorIndex"
13+
>
14+
<q-item-section
15+
side
16+
top
17+
>
18+
<q-icon
19+
name="warning"
20+
color="red"
21+
size="24px"
22+
/>
23+
</q-item-section>
24+
<q-item-section>
25+
<q-item-label
26+
v-if="error.instancePath !== ''"
27+
v-bind:data-cy="`item-raw-error-instancePath-${errorIndex}`"
28+
>
29+
instancePath: "{{ error.instancePath }}"
30+
</q-item-label>
31+
<q-item-label
32+
v-if="error.schemaPath !== ''"
33+
v-bind:data-cy="`item-raw-error-schemaPath-${errorIndex}`"
34+
>
35+
schemaPath: "{{ error.schemaPath }}"
36+
</q-item-label>
37+
<q-item-label v-bind:data-cy="`item-raw-error-keyword-${errorIndex}`">
38+
keyword: "{{ error.keyword }}"
39+
</q-item-label>
40+
<q-item-label v-bind:data-cy="`item-raw-error-message-${errorIndex}`">
41+
message: "{{ error.message }}"
42+
</q-item-label>
43+
</q-item-section>
44+
</q-item>
45+
</q-list>
46+
</template>
47+
48+
<script lang="ts">
49+
import { defineComponent } from 'vue'
50+
import { useValidation } from 'src/store/validation'
51+
52+
export default defineComponent({
53+
name: 'RawErrorList',
54+
setup () {
55+
const { errors } = useValidation()
56+
return {
57+
errors
58+
}
59+
}
60+
})
61+
</script>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<template>
2+
<h1
3+
id="form-title"
4+
tabindex="-1"
5+
>
6+
Extra CFF Fields
7+
</h1>
8+
<p>
9+
The CFF schema supports more fields than this form implements, for instance <code>preferred-citation</code>, or <code>references</code>.
10+
These extra fields can be pasted directly here.
11+
They will be validated, but the error messages will <strong>not</strong> be parsed, so they may not be helpful.
12+
</p>
13+
14+
<q-input
15+
autogrow
16+
data-cy="input-extra-cff-fields"
17+
input-style="min-height: 100px; max-height: 444px"
18+
label="Extra CFF fields"
19+
outlined
20+
standout
21+
type="textarea"
22+
v-bind:model-value="extraCffFields"
23+
v-on:update:modelValue="setExtraCffFields"
24+
/>
25+
26+
<RawErrorList />
27+
</template>
28+
29+
<script lang="ts">
30+
import RawErrorList from 'src/components/RawErrorList.vue'
31+
import { defineComponent } from 'vue'
32+
import { useCff } from 'src/store/cff'
33+
34+
export default defineComponent({
35+
name: 'ScreenCffFields',
36+
setup () {
37+
const { extraCffFields, setExtraCffFields } = useCff()
38+
return {
39+
extraCffFields,
40+
setExtraCffFields
41+
}
42+
},
43+
components: { RawErrorList }
44+
})
45+
</script>

src/error-filtering.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,6 @@ export const screenRelatedResourcesQueries: ErrorQuery[] = [{
335335
}]
336336

337337
export const screenStartQueries: ErrorQuery[] = [{
338-
find: {
339-
instancePath: ''
340-
},
341-
replace: {
342-
message: 'Screen Start has errors'
343-
}
344-
}, {
345338
find: {
346339
instancePath: '/title'
347340
},

src/router/routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ const routes: RouteRecordRaw[] = [
4949
component: () => import('src/components/LayoutStepper.vue'),
5050
children: [{ path: '', component: () => import('src/components/ScreenVersionSpecific.vue') }]
5151
},
52+
{
53+
path: '/extra-cff-fields',
54+
component: () => import('src/components/LayoutStepper.vue'),
55+
children: [{ path: '', component: () => import('src/components/ScreenExtraCffFields.vue') }]
56+
},
5257
{
5358
path: '/finish',
5459
component: () => import('src/components/LayoutStepper.vue'),

src/store/app.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { computed, ref } from 'vue'
22
import { useRouter } from 'vue-router'
33

44
export type StepNameType = 'start' | 'authors' | 'identifiers' | 'related-resources' |
5-
'abstract' | 'keywords' | 'license' | 'version-specific' | 'finish'
5+
'abstract' | 'keywords' | 'license' | 'version-specific' | 'extra-cff-fields' | 'finish'
66

77
const stepNames = [
88
'start',
@@ -13,6 +13,7 @@ const stepNames = [
1313
'keywords',
1414
'license',
1515
'version-specific',
16+
'extra-cff-fields',
1617
'finish'
1718
] as Array<StepNameType>
1819

src/store/cff.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const getInitialData = () => {
2323
}
2424

2525
const cff = ref(getInitialData())
26+
const extraCffFields = ref('')
2627

2728
export const useCff = () => {
2829
return {
@@ -31,6 +32,7 @@ export const useCff = () => {
3132
commit: computed(() => cff.value.commit),
3233
cffVersion: computed(() => cff.value.cffVersion),
3334
dateReleased: computed(() => cff.value.dateReleased),
35+
extraCffFields: computed(() => extraCffFields.value),
3436
identifiers: computed(() => cff.value.identifiers),
3537
keywords: computed(() => cff.value.keywords),
3638
license: computed(() => cff.value.license),
@@ -46,6 +48,7 @@ export const useCff = () => {
4648
setAuthors: (newAuthors: AuthorsType) => { cff.value.authors = newAuthors },
4749
setCommit: (newCommit: string) => { cff.value.commit = newCommit === '' ? undefined : newCommit },
4850
setDateReleased: (newDateReleased: string) => { cff.value.dateReleased = newDateReleased === '' ? undefined : newDateReleased },
51+
setExtraCffFields: (newExtraCffFields: string) => { extraCffFields.value = newExtraCffFields },
4952
setIdentifiers: (newIdentifiers: IdentifiersType) => { cff.value.identifiers = newIdentifiers === [] ? undefined : newIdentifiers },
5053
setKeywords: (newKeywords: KeywordsType) => { cff.value.keywords = newKeywords === [] ? undefined : newKeywords },
5154
setLicense: (newLicense: string) => { cff.value.license = newLicense === '' ? undefined : newLicense },
@@ -59,6 +62,7 @@ export const useCff = () => {
5962
setVersion: (newVersion: string) => { cff.value.version = newVersion === '' ? undefined : newVersion },
6063
reset: () => {
6164
cff.value = getInitialData()
65+
extraCffFields.value = ''
6266
}
6367
}
6468
}

src/store/cffstr.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export const useCffstr = () => {
2626
title,
2727
type,
2828
url,
29-
version
29+
version,
30+
extraCffFields
3031
} = useCff()
3132

3233
const notEmpty = (value: unknown, prop: unknown, subject: unknown) => {
@@ -59,9 +60,9 @@ export const useCffstr = () => {
5960

6061
const makeCffstr = () => {
6162
const kebabed = makeJavascriptObject()
62-
const yamlString = yaml.dump(kebabed, { indent: 2, lineWidth: 53 })
63+
const yamlString = yaml.dump(kebabed, { indent: 2, lineWidth: 60 })
6364
const generatedBy = '# This CITATION.cff file was generated with cffinit.\n# Visit https://bit.ly/cffinit to generate yours today!\n\n'
64-
return generatedBy + yamlString
65+
return generatedBy + yamlString + extraCffFields.value
6566
}
6667
return {
6768
jsObject: computed(makeJavascriptObject),

src/store/stepper-errors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,6 @@ export const errorPerStep = {
5454
keywords: errorStateScreenKeywords,
5555
license: computed(() => false),
5656
'version-specific': errorStateScreenVersionSpecific,
57+
'extra-cff-fields': computed(() => errors.value.length > 0),
5758
finish: computed(() => false)
5859
}

0 commit comments

Comments
 (0)