diff --git a/lib/gui/app/app.js b/lib/gui/app/app.js
index fc418695..935d10fe 100644
--- a/lib/gui/app/app.js
+++ b/lib/gui/app/app.js
@@ -27,6 +27,7 @@ const uuidV4 = require('uuid/v4')
// eslint-disable-next-line node/no-missing-require
const EXIT_CODES = require('../../shared/exit-codes')
+// eslint-disable-next-line node/no-missing-require
const messages = require('../../shared/messages')
const store = require('./models/store')
const packageJSON = require('../../../package.json')
diff --git a/lib/shared/drive-constraints.js b/lib/shared/drive-constraints.js
index 15c4f2f8..a719de87 100644
--- a/lib/shared/drive-constraints.js
+++ b/lib/shared/drive-constraints.js
@@ -19,6 +19,7 @@
const _ = require('lodash')
const pathIsInside = require('path-is-inside')
const prettyBytes = require('pretty-bytes')
+// eslint-disable-next-line node/no-missing-require
const messages = require('./messages')
/**
diff --git a/lib/shared/messages.js b/lib/shared/messages.js
deleted file mode 100644
index f26b6275..00000000
--- a/lib/shared/messages.js
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright 2016 balena.io
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* eslint-disable lodash/prefer-constant */
-
-'use strict'
-
-/**
- * @summary Application messages
- * @namespace messages
- * @public
- */
-module.exports = {
-
- /**
- * @summary Progress messages
- * @namespace progress
- * @memberof messages
- */
- progress: {
-
- successful: (quantity) => {
- // eslint-disable-next-line no-magic-numbers
- const plural = quantity === 1 ? '' : 's'
- return `Successful device${plural}`
- },
-
- failed: (quantity) => {
- // eslint-disable-next-line no-magic-numbers
- const plural = quantity === 1 ? '' : 's'
- return `Failed device${plural}`
- }
- },
-
- /**
- * @summary Informational messages
- * @namespace info
- * @memberof messages
- */
- info: {
-
- flashComplete: (imageBasename, [ drive ], { failed, successful }) => {
- /* eslint-disable no-magic-numbers */
- const targets = []
- if (failed + successful === 1) {
- targets.push(`to ${drive.description} (${drive.displayName})`)
- } else {
- if (successful) {
- const plural = successful === 1 ? '' : 's'
- targets.push(`to ${successful} target${plural}`)
- }
- if (failed) {
- const plural = failed === 1 ? '' : 's'
- targets.push(`and failed to be flashed to ${failed} target${plural}`)
- }
- }
- return `${imageBasename} was successfully flashed ${targets.join(' ')}`
- /* eslint-enable no-magic-numbers */
- }
-
- },
-
- /**
- * @summary Drive compatibility messages
- * @namespace compatibility
- * @memberof messages
- */
- compatibility: {
-
- sizeNotRecommended () {
- return 'Not Recommended'
- },
-
- tooSmall (additionalSpace) {
- return `Insufficient space, additional ${additionalSpace} required`
- },
-
- locked () {
- return 'Locked'
- },
-
- system () {
- return 'System Drive'
- },
-
- containsImage () {
- return 'Drive Mountpoint Contains Image'
- },
-
- // The drive is large and therefore likely not a medium you want to write to.
- largeDrive () {
- return 'Large Drive'
- }
-
- },
-
- /**
- * @summary Warning messages
- * @namespace warning
- * @memberof messages
- */
- warning: {
-
- unrecommendedDriveSize: (image, drive) => {
- return [
- `This image recommends a ${image.recommendedDriveSize}`,
- `bytes drive, however ${drive.device} is only ${drive.size} bytes.`
- ].join(' ')
- },
-
- exitWhileFlashing: () => {
- return [
- 'You are currently flashing a drive.',
- 'Closing Etcher may leave your drive in an unusable state.'
- ].join(' ')
- },
-
- looksLikeWindowsImage: () => {
- return [
- 'It looks like you are trying to burn a Windows image.\n\n',
- 'Unlike other images, Windows images require special processing to be made bootable.',
- 'We suggest you use a tool specially designed for this purpose, such as',
- 'Rufus (Windows),',
- 'WoeUSB (Linux),',
- 'or Boot Camp Assistant (macOS).'
- ].join(' ')
- },
-
- missingPartitionTable: () => {
- return [
- 'It looks like this is not a bootable image.\n\n',
- 'The image does not appear to contain a partition table,',
- 'and might not be recognized or bootable by your device.'
- ].join(' ')
- },
-
- largeDriveSize: (drive) => {
- return [
- `Drive ${drive.description} (${drive.device}) is unusually large for an SD card or USB stick.`,
- '\n\nAre you sure you want to flash this drive?'
- ].join(' ')
- }
-
- },
-
- /**
- * @summary Error messages
- * @namespace error
- * @memberof messages
- */
- error: {
-
- notEnoughSpaceInDrive: () => {
- return [
- 'Not enough space on the drive.',
- 'Please insert larger one and try again.'
- ].join(' ')
- },
-
- genericFlashError: () => {
- return 'Something went wrong. If it is a compressed image, please check that the archive is not corrupted.'
- },
-
- validation: () => {
- return [
- 'The write has been completed successfully but Etcher detected potential',
- 'corruption issues when reading the image back from the drive.',
- '\n\nPlease consider writing the image to a different drive.'
- ].join(' ')
- },
-
- invalidImage: (imagePath) => {
- return `${imagePath} is not a supported image type.`
- },
-
- openImage: (imageBasename, errorMessage) => {
- return [
- `Something went wrong while opening ${imageBasename}\n\n`,
- `Error: ${errorMessage}`
- ].join('')
- },
-
- elevationRequired: () => {
- return 'This should should be run with root/administrator permissions.'
- },
-
- flashFailure: (imageBasename, drives) => {
- /* eslint-disable no-magic-numbers */
- const target = drives.length === 1
- ? `${drives[0].description} (${drives[0].displayName})`
- : `${drives.length} targets`
- return `Something went wrong while writing ${imageBasename} to ${target}.`
- /* eslint-enable no-magic-numbers */
- },
-
- driveUnplugged: () => {
- return [
- 'Looks like Etcher lost access to the drive.',
- 'Did it get unplugged accidentally?',
- '\n\nSometimes this error is caused by faulty readers that don\'t provide stable access to the drive.'
- ].join(' ')
- },
-
- inputOutput: () => {
- return [
- 'Looks like Etcher is not able to write to this location of the drive.',
- 'This error is usually caused by a faulty drive, reader, or port.',
- '\n\nPlease try again with another drive, reader, or port.'
- ].join(' ')
- },
-
- childWriterDied: () => {
- return [
- 'The writer process ended unexpectedly.',
- 'Please try again, and contact the Etcher team if the problem persists.'
- ].join(' ')
- }
-
- }
-
-}
diff --git a/lib/shared/messages.ts b/lib/shared/messages.ts
new file mode 100644
index 00000000..322a3de0
--- /dev/null
+++ b/lib/shared/messages.ts
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2016 balena.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const progress = {
+ successful: (quantity: number) => {
+ const plural = quantity === 1 ? '' : 's';
+ return `Successful device${plural}`;
+ },
+
+ failed: (quantity: number) => {
+ const plural = quantity === 1 ? '' : 's';
+ return `Failed device${plural}`;
+ },
+};
+
+export const info = {
+ flashComplete: (
+ imageBasename: string,
+ [drive]: [{ description: string; displayName: string }],
+ { failed, successful }: { failed: number; successful: number },
+ ) => {
+ const targets = [];
+ if (failed + successful === 1) {
+ targets.push(`to ${drive.description} (${drive.displayName})`);
+ } else {
+ if (successful) {
+ const plural = successful === 1 ? '' : 's';
+ targets.push(`to ${successful} target${plural}`);
+ }
+ if (failed) {
+ const plural = failed === 1 ? '' : 's';
+ targets.push(`and failed to be flashed to ${failed} target${plural}`);
+ }
+ }
+ return `${imageBasename} was successfully flashed ${targets.join(' ')}`;
+ },
+};
+
+export const compatibility = {
+ sizeNotRecommended() {
+ return 'Not Recommended';
+ },
+
+ tooSmall(additionalSpace: number) {
+ return `Insufficient space, additional ${additionalSpace} required`;
+ },
+
+ locked() {
+ return 'Locked';
+ },
+
+ system() {
+ return 'System Drive';
+ },
+
+ containsImage() {
+ return 'Drive Mountpoint Contains Image';
+ },
+
+ // The drive is large and therefore likely not a medium you want to write to.
+ largeDrive() {
+ return 'Large Drive';
+ },
+};
+
+export const warning = {
+ unrecommendedDriveSize: (
+ image: { recommendedDriveSize: number },
+ drive: { device: string; size: number },
+ ) => {
+ return [
+ `This image recommends a ${image.recommendedDriveSize}`,
+ `bytes drive, however ${drive.device} is only ${drive.size} bytes.`,
+ ].join(' ');
+ },
+
+ exitWhileFlashing: () => {
+ return [
+ 'You are currently flashing a drive.',
+ 'Closing Etcher may leave your drive in an unusable state.',
+ ].join(' ');
+ },
+
+ looksLikeWindowsImage: () => {
+ return [
+ 'It looks like you are trying to burn a Windows image.\n\n',
+ 'Unlike other images, Windows images require special processing to be made bootable.',
+ 'We suggest you use a tool specially designed for this purpose, such as',
+ 'Rufus (Windows),',
+ 'WoeUSB (Linux),',
+ 'or Boot Camp Assistant (macOS).',
+ ].join(' ');
+ },
+
+ missingPartitionTable: () => {
+ return [
+ 'It looks like this is not a bootable image.\n\n',
+ 'The image does not appear to contain a partition table,',
+ 'and might not be recognized or bootable by your device.',
+ ].join(' ');
+ },
+
+ largeDriveSize: (drive: { description: string; device: string }) => {
+ return [
+ `Drive ${drive.description} (${drive.device}) is unusually large for an SD card or USB stick.`,
+ '\n\nAre you sure you want to flash this drive?',
+ ].join(' ');
+ },
+};
+
+export const error = {
+ notEnoughSpaceInDrive: () => {
+ return [
+ 'Not enough space on the drive.',
+ 'Please insert larger one and try again.',
+ ].join(' ');
+ },
+
+ genericFlashError: () => {
+ return 'Something went wrong. If it is a compressed image, please check that the archive is not corrupted.';
+ },
+
+ validation: () => {
+ return [
+ 'The write has been completed successfully but Etcher detected potential',
+ 'corruption issues when reading the image back from the drive.',
+ '\n\nPlease consider writing the image to a different drive.',
+ ].join(' ');
+ },
+
+ invalidImage: (imagePath: string) => {
+ return `${imagePath} is not a supported image type.`;
+ },
+
+ openImage: (imageBasename: string, errorMessage: string) => {
+ return [
+ `Something went wrong while opening ${imageBasename}\n\n`,
+ `Error: ${errorMessage}`,
+ ].join('');
+ },
+
+ elevationRequired: () => {
+ return 'This should should be run with root/administrator permissions.';
+ },
+
+ flashFailure: (
+ imageBasename: string,
+ drives: Array<{ description: string; displayName: string }>,
+ ) => {
+ const target =
+ drives.length === 1
+ ? `${drives[0].description} (${drives[0].displayName})`
+ : `${drives.length} targets`;
+ return `Something went wrong while writing ${imageBasename} to ${target}.`;
+ },
+
+ driveUnplugged: () => {
+ return [
+ 'Looks like Etcher lost access to the drive.',
+ 'Did it get unplugged accidentally?',
+ "\n\nSometimes this error is caused by faulty readers that don't provide stable access to the drive.",
+ ].join(' ');
+ },
+
+ inputOutput: () => {
+ return [
+ 'Looks like Etcher is not able to write to this location of the drive.',
+ 'This error is usually caused by a faulty drive, reader, or port.',
+ '\n\nPlease try again with another drive, reader, or port.',
+ ].join(' ');
+ },
+
+ childWriterDied: () => {
+ return [
+ 'The writer process ended unexpectedly.',
+ 'Please try again, and contact the Etcher team if the problem persists.',
+ ].join(' ');
+ },
+};
diff --git a/tests/shared/drive-constraints.spec.js b/tests/shared/drive-constraints.spec.js
index 36d6cd0e..f15fb82e 100644
--- a/tests/shared/drive-constraints.spec.js
+++ b/tests/shared/drive-constraints.spec.js
@@ -20,6 +20,7 @@ const m = require('mochainon')
const _ = require('lodash')
const path = require('path')
const constraints = require('../../lib/shared/drive-constraints')
+// eslint-disable-next-line node/no-missing-require
const messages = require('../../lib/shared/messages')
describe('Shared: DriveConstraints', function () {
diff --git a/tests/shared/messages.spec.js b/tests/shared/messages.spec.js
index 39a6ea8e..83257682 100644
--- a/tests/shared/messages.spec.js
+++ b/tests/shared/messages.spec.js
@@ -18,6 +18,7 @@
const m = require('mochainon')
const _ = require('lodash')
+// eslint-disable-next-line node/no-missing-require
const messages = require('../../lib/shared/messages')
describe('Shared: Messages', function () {