@defra/forms-engine-plugin 4.0.24 → 4.0.25

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.
@@ -139,7 +139,7 @@
139
139
  "type": "Markdown",
140
140
  "name": "markdown",
141
141
  "title": "Title",
142
- "content": "### This is a H3 in markdown\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
142
+ "content": "# Markdown - This is H1\n## This is H2\n### This is H3\n#### This is H4\n##### This is H5\n###### This is H6\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
143
143
  "options": {},
144
144
  "schema": {}
145
145
  },
@@ -147,7 +147,7 @@
147
147
  "type": "DeclarationField",
148
148
  "name": "declaration",
149
149
  "title": "Declaration",
150
- "content": "By submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
150
+ "content": "# H1\nBy submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
151
151
  "hint": "Please read and confirm the following terms",
152
152
  "options": {
153
153
  "required": false
@@ -9,6 +9,7 @@ export declare class DeclarationField extends FormComponent {
9
9
  formSchema: ArraySchema<StringSchema[]>;
10
10
  stateSchema: BooleanSchema;
11
11
  content: string;
12
+ headerStartLevel: number;
12
13
  constructor(def: DeclarationFieldComponent, props: ConstructorParameters<typeof FormComponent>[1]);
13
14
  getFormValueFromState(state: FormSubmissionState): "true" | "false";
14
15
  getFormDataFromState(state: FormSubmissionState): FormPayload;
@@ -30,6 +31,7 @@ export declare class DeclarationField extends FormComponent {
30
31
  value: string;
31
32
  checked: boolean;
32
33
  }[];
34
+ headerStartLevel: number;
33
35
  label: {
34
36
  text: string;
35
37
  };
@@ -1,8 +1,10 @@
1
+ import { ComponentType, hasFormComponents, isFormType } from '@defra/forms-model';
1
2
  import joi from 'joi';
2
3
  import { FormComponent, isFormValue } from "./FormComponent.js";
3
4
  import { messageTemplate } from "../pageControllers/validationOptions.js";
4
5
  export class DeclarationField extends FormComponent {
5
6
  DEFAULT_DECLARATION_LABEL = 'I understand and agree';
7
+ headerStartLevel;
6
8
  constructor(def, props) {
7
9
  super(def, props);
8
10
  const {
@@ -23,6 +25,10 @@ export class DeclarationField extends FormComponent {
23
25
  this.options = options;
24
26
  this.content = content;
25
27
  this.declarationConfirmationLabel = options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL;
28
+ const formComponents = hasFormComponents(props.page?.pageDef) ? props.page.pageDef.components : [];
29
+ const numOfQuestionsOnPage = formComponents.filter(q => isFormType(q.type)).length;
30
+ const hasGuidance = formComponents.some((comp, idx) => comp.type === ComponentType.Markdown && idx === 0);
31
+ this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3;
26
32
  }
27
33
  getFormValueFromState(state) {
28
34
  const {
@@ -89,7 +95,8 @@ export class DeclarationField extends FormComponent {
89
95
  text: declarationConfirmationLabel,
90
96
  value: 'true',
91
97
  checked: isChecked
92
- }]
98
+ }],
99
+ headerStartLevel: this.headerStartLevel
93
100
  };
94
101
  }
95
102
  isValue(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"DeclarationField.js","names":["joi","FormComponent","isFormValue","messageTemplate","DeclarationField","DEFAULT_DECLARATION_LABEL","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","length","every","v","getContextValueFromFormValue","getFormValue","undefined","getDisplayStringFromFormValue","getViewModel","errors","defaultDeclarationConfirmationLabel","hint","viewModel","fieldset","legend","text","classes","isChecked","checked","Array","isArray","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import { type DeclarationFieldComponent, type Item } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n private readonly DEFAULT_DECLARATION_LABEL = 'I understand and agree'\n\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n this.declarationConfirmationLabel =\n options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n return value === 'true' ? this.declarationConfirmationLabel : 'Not provided'\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const defaultDeclarationConfirmationLabel =\n 'I confirm that I understand and accept this declaration'\n const {\n hint,\n content,\n declarationConfirmationLabel = defaultDeclarationConfirmationLabel\n } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const isChecked =\n payload[this.name] === 'true' || payload[this.name] === true\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ]\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"DeclarationField.js","names":["ComponentType","hasFormComponents","isFormType","joi","FormComponent","isFormValue","messageTemplate","DeclarationField","DEFAULT_DECLARATION_LABEL","headerStartLevel","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","formComponents","page","pageDef","components","numOfQuestionsOnPage","filter","q","type","length","hasGuidance","some","comp","idx","Markdown","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","every","v","getContextValueFromFormValue","getFormValue","undefined","getDisplayStringFromFormValue","getViewModel","errors","defaultDeclarationConfirmationLabel","hint","viewModel","fieldset","legend","text","classes","isChecked","checked","Array","isArray","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import {\n ComponentType,\n hasFormComponents,\n isFormType,\n type DeclarationFieldComponent,\n type Item\n} from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n private readonly DEFAULT_DECLARATION_LABEL = 'I understand and agree'\n\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n headerStartLevel: number\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n this.declarationConfirmationLabel =\n options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL\n const formComponents = hasFormComponents(props.page?.pageDef)\n ? props.page.pageDef.components\n : []\n const numOfQuestionsOnPage = formComponents.filter((q) =>\n isFormType(q.type)\n ).length\n const hasGuidance = formComponents.some(\n (comp, idx) => comp.type === ComponentType.Markdown && idx === 0\n )\n this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n return value === 'true' ? this.declarationConfirmationLabel : 'Not provided'\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const defaultDeclarationConfirmationLabel =\n 'I confirm that I understand and accept this declaration'\n const {\n hint,\n content,\n declarationConfirmationLabel = defaultDeclarationConfirmationLabel\n } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const isChecked =\n payload[this.name] === 'true' || payload[this.name] === true\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ],\n headerStartLevel: this.headerStartLevel\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -3,9 +3,11 @@ import { ComponentBase } from '~/src/server/plugins/engine/components/ComponentB
3
3
  export declare class Markdown extends ComponentBase {
4
4
  options: MarkdownComponent['options'];
5
5
  content: MarkdownComponent['content'];
6
+ headerStartLevel: number;
6
7
  constructor(def: MarkdownComponent, props: ConstructorParameters<typeof ComponentBase>[1]);
7
8
  getViewModel(): {
8
9
  content: string;
10
+ headerStartLevel: number;
9
11
  label?: import("./types.js").Label;
10
12
  type?: string;
11
13
  id?: string;
@@ -1,6 +1,7 @@
1
1
  import { ComponentBase } from "./ComponentBase.js";
2
2
  export class Markdown extends ComponentBase {
3
3
  content;
4
+ headerStartLevel;
4
5
  constructor(def, props) {
5
6
  super(def, props);
6
7
  const {
@@ -9,6 +10,7 @@ export class Markdown extends ComponentBase {
9
10
  } = def;
10
11
  this.content = content;
11
12
  this.options = options;
13
+ this.headerStartLevel = 2;
12
14
  }
13
15
  getViewModel() {
14
16
  const {
@@ -17,7 +19,8 @@ export class Markdown extends ComponentBase {
17
19
  } = this;
18
20
  return {
19
21
  ...viewModel,
20
- content
22
+ content,
23
+ headerStartLevel: this.headerStartLevel
21
24
  };
22
25
  }
23
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.js","names":["ComponentBase","Markdown","content","constructor","def","props","options","getViewModel","viewModel"],"sources":["../../../../../src/server/plugins/engine/components/Markdown.ts"],"sourcesContent":["import { type MarkdownComponent } from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\n\nexport class Markdown extends ComponentBase {\n declare options: MarkdownComponent['options']\n content: MarkdownComponent['content']\n\n constructor(\n def: MarkdownComponent,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { content, options } = def\n\n this.content = content\n this.options = options\n }\n\n getViewModel() {\n const { content, viewModel } = this\n\n return {\n ...viewModel,\n content\n }\n }\n}\n"],"mappings":"AAEA,SAASA,aAAa;AAEtB,OAAO,MAAMC,QAAQ,SAASD,aAAa,CAAC;EAE1CE,OAAO;EAEPC,WAAWA,CACTC,GAAsB,EACtBC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEH,OAAO;MAAEI;IAAQ,CAAC,GAAGF,GAAG;IAEhC,IAAI,CAACF,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACI,OAAO,GAAGA,OAAO;EACxB;EAEAC,YAAYA,CAAA,EAAG;IACb,MAAM;MAAEL,OAAO;MAAEM;IAAU,CAAC,GAAG,IAAI;IAEnC,OAAO;MACL,GAAGA,SAAS;MACZN;IACF,CAAC;EACH;AACF","ignoreList":[]}
1
+ {"version":3,"file":"Markdown.js","names":["ComponentBase","Markdown","content","headerStartLevel","constructor","def","props","options","getViewModel","viewModel"],"sources":["../../../../../src/server/plugins/engine/components/Markdown.ts"],"sourcesContent":["import { type MarkdownComponent } from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\n\nexport class Markdown extends ComponentBase {\n declare options: MarkdownComponent['options']\n content: MarkdownComponent['content']\n headerStartLevel: number\n\n constructor(\n def: MarkdownComponent,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { content, options } = def\n\n this.content = content\n this.options = options\n this.headerStartLevel = 2\n }\n\n getViewModel() {\n const { content, viewModel } = this\n\n return {\n ...viewModel,\n content,\n headerStartLevel: this.headerStartLevel\n }\n }\n}\n"],"mappings":"AAEA,SAASA,aAAa;AAEtB,OAAO,MAAMC,QAAQ,SAASD,aAAa,CAAC;EAE1CE,OAAO;EACPC,gBAAgB;EAEhBC,WAAWA,CACTC,GAAsB,EACtBC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEJ,OAAO;MAAEK;IAAQ,CAAC,GAAGF,GAAG;IAEhC,IAAI,CAACH,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACK,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACJ,gBAAgB,GAAG,CAAC;EAC3B;EAEAK,YAAYA,CAAA,EAAG;IACb,MAAM;MAAEN,OAAO;MAAEO;IAAU,CAAC,GAAG,IAAI;IAEnC,OAAO;MACL,GAAGA,SAAS;MACZP,OAAO;MACPC,gBAAgB,EAAE,IAAI,CAACA;IACzB,CAAC;EACH;AACF","ignoreList":[]}
@@ -17,7 +17,10 @@ export const prepareNunjucksEnvironment = function (env, pluginOptions) {
17
17
  for (const [name, nunjucksFilter] of Object.entries(filters)) {
18
18
  env.addFilter(name, nunjucksFilter);
19
19
  }
20
- env.addFilter('markdown', text => markdownToHtml(text, pluginOptions.baseUrl));
20
+ env.addFilter('markdown', (text, startingHeaderLevel) => markdownToHtml(text, {
21
+ baseUrl: pluginOptions.baseUrl,
22
+ startingHeaderLevel
23
+ }));
21
24
  for (const [name, nunjucksGlobal] of Object.entries(globals)) {
22
25
  env.addGlobal(name, nunjucksGlobal);
23
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","filters","getPageHref","context","globals","VIEW_PATH","PLUGIN_PATH","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string) =>\n markdownToHtml(text, pluginOptions.baseUrl)\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY;AAEd,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAEhB,MAAMC,OAAO,GAAG;EACdP,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC;AACF,CAAC;AAED,OAAO,MAAMK,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACZ,OAAO,CAAC,EAAE;IAC5DO,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAGC,IAAY,IACrCrB,cAAc,CAACqB,IAAI,EAAEN,aAAa,CAACO,OAAO,CAC5C,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEO,cAAc,CAAC,IAAIL,MAAM,CAACC,OAAO,CAACT,OAAO,CAAC,EAAE;IAC5DI,GAAG,CAACU,SAAS,CAACR,IAAI,EAAEO,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIR,aAAa,CAACR,OAAO,EAAE;IACzB,KAAK,MAAM,CAACS,IAAI,EAAES,MAAM,CAAC,IAAIP,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACR,OAAO,CAAC,EAAE;MAClEO,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAES,MAAM,CAAC;MAC3BxB,MAAM,CAACyB,cAAc,CAACV,IAAI,EAAES,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIV,aAAa,CAACL,OAAO,EAAE;IACzBQ,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACL,OAAO,CAAC,CAACiB,OAAO,CAAC,CAAC,CAACX,IAAI,EAAEY,EAAE,CAAC,KAAK;MAC5Dd,GAAG,CAACU,SAAS,CAACR,IAAI,EAAEY,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAe1B,MAAM","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","filters","getPageHref","context","globals","VIEW_PATH","PLUGIN_PATH","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","startingHeaderLevel","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>\n markdownToHtml(text, {\n baseUrl: pluginOptions.baseUrl,\n startingHeaderLevel\n })\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY;AAEd,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAEhB,MAAMC,OAAO,GAAG;EACdP,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC;AACF,CAAC;AAED,OAAO,MAAMK,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACZ,OAAO,CAAC,EAAE;IAC5DO,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAE,CAACC,IAAY,EAAEC,mBAA4B,KACnEtB,cAAc,CAACqB,IAAI,EAAE;IACnBE,OAAO,EAAER,aAAa,CAACQ,OAAO;IAC9BD;EACF,CAAC,CACH,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEQ,cAAc,CAAC,IAAIN,MAAM,CAACC,OAAO,CAACT,OAAO,CAAC,EAAE;IAC5DI,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEQ,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIT,aAAa,CAACR,OAAO,EAAE;IACzB,KAAK,MAAM,CAACS,IAAI,EAAEU,MAAM,CAAC,IAAIR,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACR,OAAO,CAAC,EAAE;MAClEO,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEU,MAAM,CAAC;MAC3BzB,MAAM,CAAC0B,cAAc,CAACX,IAAI,EAAEU,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIX,aAAa,CAACL,OAAO,EAAE;IACzBQ,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACL,OAAO,CAAC,CAACkB,OAAO,CAAC,CAAC,CAACZ,IAAI,EAAEa,EAAE,CAAC,KAAK;MAC5Df,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEa,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAe3B,MAAM","ignoreList":[]}
@@ -5,7 +5,7 @@
5
5
  {% macro DeclarationField(component) %}
6
6
  {% set content %}
7
7
  <div class="app-prose-scope">
8
- {{ component.model.content | markdown | safe }}
8
+ {{ component.model.content | markdown(component.model.headerStartLevel) | safe }}
9
9
  </div>
10
10
  {% endset %}
11
11
  {% set checkboxes = component.model | merge({ formGroup: { beforeInputs: { html: content } } }) %}
@@ -1,5 +1,5 @@
1
1
  {% macro Markdown(component) %}
2
2
  <div class="app-prose-scope">
3
- {{ component.model.content | markdown | safe }}
3
+ {{ component.model.content | markdown(component.model.headerStartLevel) | safe }}
4
4
  </div>
5
5
  {% endmacro %}
@@ -12,7 +12,7 @@
12
12
  }) }}
13
13
  <h2 class="govuk-heading-m">What happens next</h2>
14
14
  <div class="app-prose-scope">
15
- {{ submissionGuidance | markdown | safe }}
15
+ {{ submissionGuidance | markdown(3) | safe }}
16
16
  </div>
17
17
  </div>
18
18
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/forms-engine-plugin",
3
- "version": "4.0.24",
3
+ "version": "4.0.25",
4
4
  "description": "Defra forms engine",
5
5
  "type": "module",
6
6
  "files": [
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "license": "SEE LICENSE IN LICENSE",
72
72
  "dependencies": {
73
- "@defra/forms-model": "^3.0.580",
73
+ "@defra/forms-model": "^3.0.584",
74
74
  "@defra/hapi-tracing": "^1.29.0",
75
75
  "@elastic/ecs-pino-format": "^1.5.0",
76
76
  "@hapi/boom": "^10.0.1",
@@ -91,6 +91,7 @@
91
91
  "blankie": "^5.0.0",
92
92
  "blipp": "^4.0.2",
93
93
  "btoa": "^1.2.1",
94
+ "chokidar": "3.6.0",
94
95
  "convict": "^6.2.4",
95
96
  "date-fns": "^4.1.0",
96
97
  "dotenv": "^17.2.3",
@@ -139,7 +139,7 @@
139
139
  "type": "Markdown",
140
140
  "name": "markdown",
141
141
  "title": "Title",
142
- "content": "### This is a H3 in markdown\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
142
+ "content": "# Markdown - This is H1\n## This is H2\n### This is H3\n#### This is H4\n##### This is H5\n###### This is H6\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
143
143
  "options": {},
144
144
  "schema": {}
145
145
  },
@@ -147,7 +147,7 @@
147
147
  "type": "DeclarationField",
148
148
  "name": "declaration",
149
149
  "title": "Declaration",
150
- "content": "By submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
150
+ "content": "# H1\nBy submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
151
151
  "hint": "Please read and confirm the following terms",
152
152
  "options": {
153
153
  "required": false
@@ -11,6 +11,8 @@ import {
11
11
  } from '~/src/server/plugins/engine/components/helpers/components.js'
12
12
  import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
13
13
  import definition from '~/test/form/definitions/blank.js'
14
+ import declarationWithGuidance from '~/test/form/definitions/declaration-with-guidance.js'
15
+ import declarationWithoutGuidance from '~/test/form/definitions/declaration-without-guidance.js'
14
16
  import { getFormData, getFormState } from '~/test/helpers/component-helpers.js'
15
17
 
16
18
  describe('DeclarationField', () => {
@@ -481,4 +483,26 @@ describe('DeclarationField', () => {
481
483
  expect(DeclarationField.isBool(true)).toBe(true)
482
484
  })
483
485
  })
486
+
487
+ describe('Markdown header starting level', () => {
488
+ test('should determine startHeadingLevel is 3 some guidance', () => {
489
+ const modelDecl = new FormModel(declarationWithGuidance, {
490
+ basePath: 'test'
491
+ })
492
+ const field = modelDecl.componentMap.get(
493
+ 'declarationField'
494
+ ) as DeclarationField
495
+ expect(field.headerStartLevel).toBe(3)
496
+ })
497
+
498
+ test('should determine startHeadingLevel is 2 when no guidance', () => {
499
+ const modelDecl = new FormModel(declarationWithoutGuidance, {
500
+ basePath: 'test'
501
+ })
502
+ const field = modelDecl.componentMap.get(
503
+ 'declarationField'
504
+ ) as DeclarationField
505
+ expect(field.headerStartLevel).toBe(2)
506
+ })
507
+ })
484
508
  })
@@ -1,4 +1,10 @@
1
- import { type DeclarationFieldComponent, type Item } from '@defra/forms-model'
1
+ import {
2
+ ComponentType,
3
+ hasFormComponents,
4
+ isFormType,
5
+ type DeclarationFieldComponent,
6
+ type Item
7
+ } from '@defra/forms-model'
2
8
  import joi, {
3
9
  type ArraySchema,
4
10
  type BooleanSchema,
@@ -30,6 +36,7 @@ export class DeclarationField extends FormComponent {
30
36
  declare formSchema: ArraySchema<StringSchema[]>
31
37
  declare stateSchema: BooleanSchema
32
38
  declare content: string
39
+ headerStartLevel: number
33
40
 
34
41
  constructor(
35
42
  def: DeclarationFieldComponent,
@@ -64,6 +71,16 @@ export class DeclarationField extends FormComponent {
64
71
  this.content = content
65
72
  this.declarationConfirmationLabel =
66
73
  options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL
74
+ const formComponents = hasFormComponents(props.page?.pageDef)
75
+ ? props.page.pageDef.components
76
+ : []
77
+ const numOfQuestionsOnPage = formComponents.filter((q) =>
78
+ isFormType(q.type)
79
+ ).length
80
+ const hasGuidance = formComponents.some(
81
+ (comp, idx) => comp.type === ComponentType.Markdown && idx === 0
82
+ )
83
+ this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3
67
84
  }
68
85
 
69
86
  getFormValueFromState(state: FormSubmissionState) {
@@ -133,7 +150,8 @@ export class DeclarationField extends FormComponent {
133
150
  value: 'true',
134
151
  checked: isChecked
135
152
  }
136
- ]
153
+ ],
154
+ headerStartLevel: this.headerStartLevel
137
155
  }
138
156
  }
139
157
 
@@ -5,6 +5,7 @@ import { ComponentBase } from '~/src/server/plugins/engine/components/ComponentB
5
5
  export class Markdown extends ComponentBase {
6
6
  declare options: MarkdownComponent['options']
7
7
  content: MarkdownComponent['content']
8
+ headerStartLevel: number
8
9
 
9
10
  constructor(
10
11
  def: MarkdownComponent,
@@ -16,6 +17,7 @@ export class Markdown extends ComponentBase {
16
17
 
17
18
  this.content = content
18
19
  this.options = options
20
+ this.headerStartLevel = 2
19
21
  }
20
22
 
21
23
  getViewModel() {
@@ -23,7 +25,8 @@ export class Markdown extends ComponentBase {
23
25
 
24
26
  return {
25
27
  ...viewModel,
26
- content
28
+ content,
29
+ headerStartLevel: this.headerStartLevel
27
30
  }
28
31
  }
29
32
  }
@@ -33,8 +33,11 @@ export const prepareNunjucksEnvironment = function (
33
33
  env.addFilter(name, nunjucksFilter)
34
34
  }
35
35
 
36
- env.addFilter('markdown', (text: string) =>
37
- markdownToHtml(text, pluginOptions.baseUrl)
36
+ env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>
37
+ markdownToHtml(text, {
38
+ baseUrl: pluginOptions.baseUrl,
39
+ startingHeaderLevel
40
+ })
38
41
  )
39
42
 
40
43
  for (const [name, nunjucksGlobal] of Object.entries(globals)) {
@@ -5,7 +5,7 @@
5
5
  {% macro DeclarationField(component) %}
6
6
  {% set content %}
7
7
  <div class="app-prose-scope">
8
- {{ component.model.content | markdown | safe }}
8
+ {{ component.model.content | markdown(component.model.headerStartLevel) | safe }}
9
9
  </div>
10
10
  {% endset %}
11
11
  {% set checkboxes = component.model | merge({ formGroup: { beforeInputs: { html: content } } }) %}
@@ -1,5 +1,5 @@
1
1
  {% macro Markdown(component) %}
2
2
  <div class="app-prose-scope">
3
- {{ component.model.content | markdown | safe }}
3
+ {{ component.model.content | markdown(component.model.headerStartLevel) | safe }}
4
4
  </div>
5
5
  {% endmacro %}
@@ -12,7 +12,7 @@
12
12
  }) }}
13
13
  <h2 class="govuk-heading-m">What happens next</h2>
14
14
  <div class="app-prose-scope">
15
- {{ submissionGuidance | markdown | safe }}
15
+ {{ submissionGuidance | markdown(3) | safe }}
16
16
  </div>
17
17
  </div>
18
18
  </div>