@dwp/govuk-casa 9.5.1 → 9.6.0

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.
package/src/casa.js CHANGED
@@ -9,6 +9,7 @@ import ValidationError from "./lib/ValidationError.js";
9
9
  import MutableRouter from "./lib/MutableRouter.js";
10
10
  import waypointUrl from "./lib/waypoint-url.js";
11
11
  import endSession from "./lib/end-session.js";
12
+ import { generateGovukErrors } from "./routes/journey.js";
12
13
  import * as nunjucksFilters from "./lib/nunjucks-filters.js";
13
14
  import * as constants from "./lib/constants.js";
14
15
  import * as contextIdGenerators from "./lib/context-id-generators.js";
@@ -28,6 +29,7 @@ export {
28
29
  // Utilities
29
30
  waypointUrl,
30
31
  endSession,
32
+ generateGovukErrors,
31
33
 
32
34
  // Nunjucks filters
33
35
  nunjucksFilters,
@@ -88,6 +90,8 @@ export {
88
90
  /**
89
91
  * @typedef {object} I18nOptions
90
92
  * @property {string[]} dirs Directories to search for locale dictionaries
93
+ * @property {string | false} [fallbackLng=false] Fallback language to use if
94
+ * translations aren't available for a given key. Default is `false`
91
95
  * @property {string[]} [locales=['en', 'cy']] Supported locales. Default is
92
96
  * `['en', 'cy']`
93
97
  */
@@ -186,6 +190,8 @@ export {
186
190
  * generator
187
191
  * @property {symbol | Function} [errorVisibility] Option to keep page errors
188
192
  * active on GET request
193
+ * @property {boolean} [govukRebrand=false] Sets whether you wish to use the
194
+ * govuk rebrand. Default is `false`
189
195
  */
190
196
 
191
197
  /**
@@ -124,6 +124,34 @@ export function validateI18nLocales(locales = ["en", "cy"]) {
124
124
  return locales;
125
125
  }
126
126
 
127
+ /**
128
+ * Validates the i18n fallback language.
129
+ *
130
+ * @param {string} [fallback] Locale
131
+ * @param {Array} locales Array of valid locales.
132
+ * @returns {string} Fallback locale
133
+ * @throws {SyntaxError} For invalid locales.
134
+ * @throws {TypeError} For invalid type.
135
+ * @access private
136
+ */
137
+ export function validateI18nFallbackLng(fallback, locales = ["en", "cy"]) {
138
+ if (fallback === undefined) {
139
+ return false;
140
+ }
141
+ if (typeof fallback !== "string") {
142
+ throw new TypeError(
143
+ "I18n fallback language must be a string (i18n.fallbackLng)",
144
+ );
145
+ }
146
+ if (!locales.includes(fallback)) {
147
+ throw new SyntaxError(
148
+ "I18n fallback language must be included in the locales array (i18n.fallbackLng)",
149
+ );
150
+ }
151
+
152
+ return fallback;
153
+ }
154
+
127
155
  /**
128
156
  * Validates and sanitises mount url.
129
157
  *
@@ -606,6 +634,24 @@ export function validateContextIdGenerator(generator) {
606
634
  return generator;
607
635
  }
608
636
 
637
+ /**
638
+ * Validates the govuk rebrand feature flag.
639
+ *
640
+ * @param {boolean} [govukRebrand] Govuk rebrand feature flag
641
+ * @returns {boolean | true} Boolean.
642
+ * @throws {TypeError} For invalid feagure flag is set.
643
+ * @access private
644
+ */
645
+ export function validateGovukRebrand(govukRebrand) {
646
+ if (govukRebrand === undefined) {
647
+ return false;
648
+ }
649
+ if (typeof govukRebrand !== "boolean") {
650
+ throw new TypeError("govukRebrand must be a boolean");
651
+ }
652
+ return govukRebrand;
653
+ }
654
+
609
655
  /**
610
656
  * Ingest, validate, sanitise and manipulate configuration parameters.
611
657
  *
@@ -620,6 +666,7 @@ export default function ingest(config = {}) {
620
666
  i18n: validateI18nObject(config.i18n, (i18n) => ({
621
667
  dirs: validateI18nDirs(i18n.dirs),
622
668
  locales: validateI18nLocales(i18n.locales),
669
+ fallbackLng: validateI18nFallbackLng(i18n.fallbackLng, i18n.locales),
623
670
  })),
624
671
 
625
672
  // URL that will prefix all URLs in the browser address bar
@@ -669,6 +716,8 @@ export default function ingest(config = {}) {
669
716
 
670
717
  // Context ID generator
671
718
  contextIdGenerator: validateContextIdGenerator(config.contextIdGenerator),
719
+
720
+ govukRebrand: validateGovukRebrand(config.govukRebrand),
672
721
  };
673
722
 
674
723
  // Freeze to modifications
@@ -81,6 +81,7 @@ export default function configure(config = {}) {
81
81
  formMaxParams,
82
82
  formMaxBytes,
83
83
  contextIdGenerator,
84
+ govukRebrand = false,
84
85
  } = ingestedConfig;
85
86
 
86
87
  // Prepare all page hooks so they are prefixed with the `journey.` scope.
@@ -100,6 +101,7 @@ export default function configure(config = {}) {
100
101
  resolve(dirname, "../../views"),
101
102
  resolve(createRequire(dirname).resolve("govuk-frontend"), "../../"),
102
103
  ],
104
+ govukRebrand,
103
105
  });
104
106
 
105
107
  // Prepare mandatory middleware
@@ -133,6 +135,7 @@ export default function configure(config = {}) {
133
135
  plan,
134
136
  events,
135
137
  contextIdGenerator,
138
+ govukRebrand,
136
139
  });
137
140
 
138
141
  // Prepare form middleware and its constituent parts
@@ -182,6 +185,8 @@ export default function configure(config = {}) {
182
185
  // Nunjucks environment, so it can be attached to other ExpressJS instances
183
186
  // using `nunjucksEnv.express(myApp); myApp.set('view engine', 'njk');`.
184
187
  nunjucksEnv,
188
+ // govuk rebrand flag
189
+ govukRebrand,
185
190
 
186
191
  // Mandatory middleware. User must add these to their ExpressJS app.
187
192
  preMiddleware,
@@ -20,10 +20,11 @@ import {
20
20
  * Create a Nunjucks environment.
21
21
  *
22
22
  * @param {NunjucksOptions} options Nunjucks options
23
+ * @param {boolean} govukRebrand GovukRebrand flag
23
24
  * @returns {Environment} Nunjucks Environment instance
24
25
  * @access private
25
26
  */
26
- export default function nunjucksConfig({ views = [] }) {
27
+ export default function nunjucksConfig({ views = [], govukRebrand }) {
27
28
  // Prepare a single Nunjucks environment for all responses to use. Note that
28
29
  // we cannot prepare response-specific global functions/filters if we use a
29
30
  // single environment, but the performance gains of doing so are significant.
@@ -50,6 +51,7 @@ export default function nunjucksConfig({ views = [] }) {
50
51
  JSON.parse(readFileSync(resolve(dirname, "../../package.json"))).version,
51
52
  );
52
53
 
54
+ env.addGlobal("govukRebrand", govukRebrand);
53
55
  env.addGlobal("mergeObjects", mergeObjects);
54
56
  env.addGlobal("includes", includes);
55
57
  env.addGlobal("formatDateObject", formatDateObject);
@@ -43,9 +43,16 @@ const editOrigin = (req) => {
43
43
  * @param {Plan} opts.plan CASA Plan
44
44
  * @param {ContextEventHandler[]} opts.events Event handlers
45
45
  * @param {ContextIdGenerator} opts.contextIdGenerator Content ID generator
46
+ * @param {boolean} ops.govukRebrand Govuk rebrand feature flag
47
+ * @param opts.govukRebrand
46
48
  * @returns {RequestHandler[]} Middleware functions
47
49
  */
48
- export default function dataMiddleware({ plan, events, contextIdGenerator }) {
50
+ export default function dataMiddleware({
51
+ plan,
52
+ events,
53
+ contextIdGenerator,
54
+ govukRebrand,
55
+ }) {
49
56
  return [
50
57
  (req, res, next) => {
51
58
  /* ------------------------------------------------ Request decorations */
@@ -124,7 +131,8 @@ export default function dataMiddleware({ plan, events, contextIdGenerator }) {
124
131
  // htmlLang = req.language is provided by i18n-http-middleware
125
132
  // assetPath = used for linking to static assets in the govuk-frontend module
126
133
  res.locals.htmlLang = req.language;
127
- res.locals.assetPath = `${staticMountUrl}govuk/assets`;
134
+ const rebrandAssetPath = govukRebrand ? "/rebrand" : "";
135
+ res.locals.assetPath = `${staticMountUrl}govuk/assets${rebrandAssetPath}`;
128
136
 
129
137
  // Function for building URLs. This will be curried with the `mountUrl`,
130
138
  // `journeyContext`, `edit` and `editOrigin` for convenience. This means
@@ -27,6 +27,14 @@ const log = logger("routes:journey");
27
27
  * @access private
28
28
  */
29
29
 
30
+ /** @typedef {import("../casa.js").ValidationError} ValidationError */
31
+
32
+ /**
33
+ * @typedef {object} GovUkErrorObject
34
+ * @property {string} text Error message text
35
+ * @property {string} href Error message anchor href
36
+ */
37
+
30
38
  /**
31
39
  * @typedef {object} JourneyRouterOptions Options to configure static router
32
40
  * @property {GlobalHook[]} globalHooks Global hooks
@@ -62,13 +70,14 @@ const renderMiddlewareFactory = (view, contextFactory) => [
62
70
  ];
63
71
 
64
72
  /**
65
- * Generate page validation error
73
+ * Generate page validation errors
66
74
  *
67
- * @param {object} errors Object of page validation error
68
- * @param {object} req Casa request object
69
- * @returns {object[]} Array of error objects
75
+ * @param {Record<string, ValidationError>} errors Object of page validation
76
+ * errors
77
+ * @param {import("express").Request} req Casa request object
78
+ * @returns {GovUkErrorObject[]} Array of error objects
70
79
  */
71
- const generateGovukErrors = (errors, req) =>
80
+ export const generateGovukErrors = (errors, req) =>
72
81
  Object.values(errors || {}).map(([error]) => ({
73
82
  text: req.t(error.summary, error.variables),
74
83
  href: error.fieldHref,
@@ -1,5 +1,5 @@
1
1
  {% extends "govuk/template.njk" %}
2
-
2
+ {% from "govuk/components/service-navigation/macro.njk" import govukServiceNavigation %}
3
3
 
4
4
  {% block head %}
5
5
  {% include "casa/partials/styles.njk" %}
@@ -16,13 +16,26 @@
16
16
 
17
17
 
18
18
  {% block header %}
19
- {{ govukHeader({
20
- assetsPath: assetPath + "/images",
21
- serviceName: t('common:serviceName') if t else '',
22
- serviceUrl: casa.mountUrl,
23
- homepageUrl: "https://www.gov.uk/",
24
- useTudorCrown: true
25
- }) }}
19
+
20
+ {% if govukRebrand %}
21
+ {{ govukHeader({
22
+ homepageUrl: "https://www.gov.uk/"
23
+ }) }}
24
+ {% block serviceNavigation %}
25
+ {{ govukServiceNavigation({
26
+ serviceName: t('common:serviceName') if t else '',
27
+ serviceUrl: casa.mountUrl
28
+ }) }}
29
+ {% endblock %}
30
+ {% else %}
31
+ {{ govukHeader({
32
+ assetsPath: assetPath + "/images",
33
+ serviceName: t('common:serviceName') if t else '',
34
+ serviceUrl: casa.mountUrl,
35
+ homepageUrl: "https://www.gov.uk/",
36
+ useTudorCrown: true
37
+ }) }}
38
+ {% endif %}
26
39
  {% endblock %}
27
40
 
28
41