mod-build 4.0.83 → 4.0.84
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/CHANGELOG.md +4 -0
- package/package.json +1 -1
- package/tasks/add-files-to-gitignore.js +28 -11
- package/tasks/clean.js +14 -5
- package/tasks/grab-global-fonts.js +118 -67
- package/tasks/serve.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.0.84
|
|
4
|
+
|
|
5
|
+
- Updated `grab-global-fonts` task to grab fonts from `gwfh.mranftl.com/api/fonts` -- will default to `Roboto` unless defined in `siteconfig.js` = `fontsToDownload: ['font-name']`
|
|
6
|
+
|
|
3
7
|
## 4.0.83
|
|
4
8
|
|
|
5
9
|
- Updated `grab-jsdoc` task to use correct resource path for mod-form
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Adds entries to .gitignore file
|
|
5
|
+
* Adds entries to .gitignore file
|
|
6
|
+
* If a section with the same comment exists, adds entries below it; otherwise, appends to bottom
|
|
6
7
|
* @param {string[]} entries - Array of entries to add to .gitignore
|
|
7
8
|
* @param {string} comment - Optional comment to add before the entries
|
|
8
9
|
* @returns {Promise<void>}
|
|
@@ -27,17 +28,33 @@ export default async function addFilesToGitignore(entries, comment) {
|
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
//
|
|
31
|
-
let contentToAppend = content.trim()
|
|
32
|
-
? (content.endsWith('\n') ? '\n' : '\n\n')
|
|
33
|
-
: '';
|
|
34
|
-
|
|
31
|
+
// If comment exists, find the section and insert below it
|
|
35
32
|
if (comment) {
|
|
36
|
-
|
|
33
|
+
const commentLine = `# ${comment}`;
|
|
34
|
+
const lines = content.split('\n');
|
|
35
|
+
const sectionIndex = lines.findIndex(line => line.trim() === commentLine);
|
|
36
|
+
|
|
37
|
+
if (sectionIndex !== -1) {
|
|
38
|
+
let insertIndex = sectionIndex + 1;
|
|
39
|
+
let lastNonBlankIndex = sectionIndex;
|
|
40
|
+
|
|
41
|
+
while (insertIndex < lines.length && !lines[insertIndex].trim().startsWith('#')) {
|
|
42
|
+
if (lines[insertIndex].trim() !== '') {
|
|
43
|
+
lastNonBlankIndex = insertIndex;
|
|
44
|
+
}
|
|
45
|
+
insertIndex++;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
lines.splice(lastNonBlankIndex + 1, 0, ...entriesToAppend);
|
|
49
|
+
await fs.promises.writeFile(gitignorePath, lines.join('\n') + '\n', 'utf8');
|
|
50
|
+
console.log(`Added to .gitignore ${comment} section: ${entriesToAppend.join(', ')}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
37
53
|
}
|
|
38
|
-
contentToAppend += entriesToAppend.join('\n') + '\n';
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
55
|
+
const separator = content.trim() ? (content.endsWith('\n') ? '\n' : '\n\n') : '';
|
|
56
|
+
const newContent = comment ? `${separator}# ${comment}\n${entriesToAppend.join('\n')}\n` : `${separator}${entriesToAppend.join('\n')}\n`;
|
|
43
57
|
|
|
58
|
+
await fs.promises.appendFile(gitignorePath, newContent, 'utf8');
|
|
59
|
+
console.log(`Added to .gitignore: ${entriesToAppend.join(', ')}`);
|
|
60
|
+
}
|
package/tasks/clean.js
CHANGED
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
const baseFoldersToDelete = ['./src/resources', './src/accessible-components', './src/shared-components', './src/.tmp', './src/temp', './public/resources', './jsdoc-types'];
|
|
4
5
|
|
|
5
6
|
const filesToDelete = ['./modform.jsdoc.js'];
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
// We will want to delete all downloaded fonts (which will be all folders but ./public/fonts/branded/*)
|
|
9
|
+
const fontBaseFolder = './public/fonts';
|
|
10
|
+
const fontFoldersToDelete = fs.existsSync(fontBaseFolder)
|
|
11
|
+
? fs.readdirSync(fontBaseFolder, { withFileTypes: true }).filter(dirent => dirent.isDirectory() && dirent.name !== 'branded').map(dirent => path.join(fontBaseFolder, dirent.name))
|
|
12
|
+
: [];
|
|
13
|
+
|
|
14
|
+
const foldersToDelete = [...baseFoldersToDelete, ...fontFoldersToDelete];
|
|
15
|
+
|
|
16
|
+
await Promise.all(foldersToDelete.map(async (folder) => {
|
|
8
17
|
try {
|
|
9
18
|
await fs.promises.rm(folder, { recursive: true });
|
|
10
19
|
console.log(`Folder ${folder} deleted successfully`);
|
|
11
20
|
} catch (err) {
|
|
12
21
|
// fail silently
|
|
13
22
|
}
|
|
14
|
-
});
|
|
23
|
+
}));
|
|
15
24
|
|
|
16
|
-
filesToDelete.
|
|
25
|
+
await Promise.all(filesToDelete.map(async (file) => {
|
|
17
26
|
try {
|
|
18
27
|
await fs.promises.rm(file);
|
|
19
28
|
console.log(`File ${file} deleted successfully`);
|
|
20
29
|
} catch (err) {
|
|
21
30
|
// fail silently
|
|
22
31
|
}
|
|
23
|
-
});
|
|
32
|
+
}));
|
|
@@ -4,94 +4,145 @@ import { createWriteStream } from 'node:fs';
|
|
|
4
4
|
import * as stream from 'node:stream';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
6
|
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
7
8
|
import { responseInterceptor } from '../src/scripts/retry-axios.js';
|
|
8
9
|
import addFilesToGitignore from './add-files-to-gitignore.js';
|
|
9
10
|
|
|
10
|
-
const resourcePath = 'quote/resources/mod-site/fonts';
|
|
11
|
-
|
|
12
|
-
// Global font names
|
|
13
|
-
const fontNames = [
|
|
14
|
-
'roboto',
|
|
15
|
-
'montserrat'
|
|
16
|
-
];
|
|
17
|
-
|
|
18
11
|
// Font variants and extensions to download for each font
|
|
19
12
|
const fontVariants = ['regular', 'bold'];
|
|
20
13
|
const fontExtensions = ['ttf', 'woff2'];
|
|
21
|
-
|
|
22
|
-
// Generate array of all font files needed for download
|
|
23
|
-
const fontFiles = fontNames.flatMap(fontName => {
|
|
24
|
-
return fontVariants.flatMap(variant => {
|
|
25
|
-
return fontExtensions.map(ext => {
|
|
26
|
-
return `${fontName}/${fontName}-${variant}.${ext}`;
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
});
|
|
14
|
+
const finished = promisify(stream.finished);
|
|
30
15
|
|
|
31
16
|
const axiosInstance = axios.create();
|
|
32
17
|
responseInterceptor(axiosInstance);
|
|
33
18
|
|
|
34
|
-
const
|
|
35
|
-
|
|
19
|
+
const getFontPath = (...parts) => path.join(
|
|
20
|
+
defaultSettings.publicFolder,
|
|
21
|
+
defaultSettings.fontsSubfolder,
|
|
22
|
+
...parts
|
|
23
|
+
);
|
|
36
24
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
const directoryHasItems = (dirPath) => {
|
|
26
|
+
if (!fs.existsSync(dirPath)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return fs.readdirSync(dirPath).length > 0;
|
|
30
|
+
};
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
const getFontDownloadUrls = async (fontName) => {
|
|
33
|
+
try {
|
|
34
|
+
const url = `https://gwfh.mranftl.com/api/fonts/${fontName}?subsets=latin`;
|
|
35
|
+
const response = await axiosInstance.get(url);
|
|
36
|
+
const fontData = response.data;
|
|
37
|
+
|
|
38
|
+
if (!fontData?.variants) {
|
|
39
|
+
throw new Error('Invalid font data received');
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
axios(options).then(resp => {
|
|
58
|
-
if (resp.status !== 200) {
|
|
59
|
-
throw new Error(`${resp.status}: Error while fetching ${options.url}`);
|
|
41
|
+
|
|
42
|
+
const downloadUrls = {};
|
|
43
|
+
const targetWeights = ['400', '700'];
|
|
44
|
+
|
|
45
|
+
fontData.variants.forEach(variant => {
|
|
46
|
+
if (variant.fontStyle === 'normal' && targetWeights.includes(variant.fontWeight)) {
|
|
47
|
+
const variantName = variant.fontWeight === '400' ? 'regular' : 'bold';
|
|
48
|
+
downloadUrls[variantName] = downloadUrls[variantName] || {};
|
|
49
|
+
if (variant.ttf) {
|
|
50
|
+
downloadUrls[variantName].ttf = variant.ttf;
|
|
60
51
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
52
|
+
if (variant.woff2) {
|
|
53
|
+
downloadUrls[variantName].woff2 = variant.woff2;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return downloadUrls;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(`Error fetching font data for ${fontName}:`, error.message);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const downloadFontFile = async (fontName, variant, extension, downloadUrl) => {
|
|
66
|
+
const fileName = `${fontName}-${variant}.${extension}`;
|
|
67
|
+
const filePath = getFontPath(fontName, fileName);
|
|
68
|
+
const folderPath = path.dirname(filePath);
|
|
69
|
+
|
|
70
|
+
if (!fs.existsSync(folderPath)) {
|
|
71
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (fs.existsSync(filePath)) {
|
|
75
|
+
console.log(`${filePath} already exists, skipping...`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const resp = await axiosInstance({
|
|
81
|
+
url: downloadUrl,
|
|
82
|
+
method: 'get',
|
|
83
|
+
responseType: 'stream'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (resp.status !== 200) {
|
|
87
|
+
throw new Error(`${resp.status}: Error while fetching ${downloadUrl}`);
|
|
70
88
|
}
|
|
71
|
-
|
|
89
|
+
|
|
90
|
+
console.log(`Downloading ${filePath}...`);
|
|
91
|
+
const writer = createWriteStream(filePath);
|
|
92
|
+
resp.data.pipe(writer);
|
|
93
|
+
await finished(writer);
|
|
94
|
+
console.log(`${filePath} downloaded successfully`);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(`Error downloading ${filePath} from ${downloadUrl}:`, error.message);
|
|
97
|
+
throw new Error(`Failed to download ${filePath}: ${error.message}`);
|
|
98
|
+
}
|
|
72
99
|
};
|
|
73
100
|
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
)
|
|
101
|
+
const downloadFont = async (fontName) => {
|
|
102
|
+
const fontDir = getFontPath(fontName);
|
|
103
|
+
|
|
104
|
+
if (directoryHasItems(fontDir)) {
|
|
105
|
+
console.log(`Font directory ${fontDir} already has items, skipping ${fontName}...`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log(`Downloading font: ${fontName}`);
|
|
110
|
+
|
|
111
|
+
const downloadUrls = await getFontDownloadUrls(fontName);
|
|
78
112
|
|
|
79
|
-
|
|
113
|
+
if (!downloadUrls || Object.keys(downloadUrls).length === 0) {
|
|
114
|
+
throw new Error(`Could not find download URLs for ${fontName}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await Promise.all(
|
|
118
|
+
fontVariants.flatMap(variant =>
|
|
119
|
+
fontExtensions.map(ext => {
|
|
120
|
+
const url = downloadUrls[variant]?.[ext];
|
|
121
|
+
if (!url) {
|
|
122
|
+
console.warn(`Warning: No ${ext} URL found for ${fontName} ${variant}, skipping...`);
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
}
|
|
125
|
+
return downloadFontFile(fontName, variant, ext, url);
|
|
126
|
+
})
|
|
127
|
+
)
|
|
128
|
+
);
|
|
80
129
|
};
|
|
81
130
|
|
|
82
|
-
|
|
83
|
-
const
|
|
131
|
+
const updateGitignore = async (fontNames) => {
|
|
132
|
+
const fontEntries = fontNames.map(fontName => `${getFontPath(fontName)}/`);
|
|
133
|
+
await addFilesToGitignore(fontEntries, 'Downloaded fonts');
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// If a site has a branded font that is outside of this API - we should add it to /public/fonts/branded/{fontName}/*
|
|
137
|
+
export default async function(config) {
|
|
138
|
+
// Download fonts from config.fontsToDownload or will default to ['roboto']
|
|
139
|
+
const fontNames = config?.fontsToDownload?.length > 0 ? config.fontsToDownload : ['roboto'];
|
|
140
|
+
|
|
141
|
+
const fontsPath = getFontPath();
|
|
84
142
|
if (!fs.existsSync(fontsPath)) {
|
|
85
143
|
fs.mkdirSync(fontsPath, { recursive: true });
|
|
86
144
|
}
|
|
87
145
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return Promise.all(fontPromises).then(async () => {
|
|
94
|
-
// Update .gitignore after fonts are downloaded
|
|
95
|
-
await updateGitignore();
|
|
96
|
-
});
|
|
97
|
-
}
|
|
146
|
+
await Promise.all(fontNames.map(downloadFont));
|
|
147
|
+
await updateGitignore(fontNames);
|
|
148
|
+
}
|
package/tasks/serve.js
CHANGED
|
@@ -13,7 +13,7 @@ import { createStylelintFile, updateConfig } from '../src/scripts/plugins.js';
|
|
|
13
13
|
export async function startModBuild(config) {
|
|
14
14
|
addEditorConfig();
|
|
15
15
|
createStylelintFile();
|
|
16
|
-
grabGlobalFonts();
|
|
16
|
+
await grabGlobalFonts(config);
|
|
17
17
|
await grabB2BData(config);
|
|
18
18
|
await grabCdn(config);
|
|
19
19
|
await getDefaultTradeQuestions(config);
|