This commit is contained in:
2024-03-22 03:47:51 +05:30
parent 8bcf3d211e
commit 89819f6fe2
28440 changed files with 3211033 additions and 2 deletions

View File

@@ -0,0 +1,29 @@
/**
* react-loadable-ssr-addon
* @author Marcos Gonçalves <contact@themgoncalves.com>
* @version 1.0.1
*/
import crypto from 'crypto';
/**
* Compute SRI Integrity
* @func computeIntegrity
* See {@link https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity Subresource Integrity} at MDN
* @param {array} algorithms - The algorithms you want to use when hashing `content`
* @param {string} source - File contents you want to hash
* @return {string} SRI hash
*/
function computeIntegrity(algorithms, source) {
return Array.isArray(algorithms)
? algorithms.map((algorithm) => {
const hash = crypto
.createHash(algorithm)
.update(source, 'utf8')
.digest('base64');
return `${algorithm}-${hash}`;
}).join(' ')
: '';
}
export default computeIntegrity;

View File

@@ -0,0 +1,25 @@
/**
* react-loadable-ssr-addon
* @author Marcos Gonçalves <contact@themgoncalves.com>
* @version 1.0.1
*/
/**
* Get file extension
* @method getFileExtension
* @static
* @param {string} filename - File name
* @returns {string} - File extension
*/
function getFileExtension(filename) {
if (!filename || typeof filename !== 'string') { return ''; }
const fileExtRegex = /\.\w{2,4}\.(?:map|gz)$|\.\w+$/i;
const name = filename.split(/[?#]/)[0]; // eslint-disable-line prefer-destructuring
const ext = name.match(fileExtRegex);
return ext && ext.length ? ext[0] : '';
}
export default getFileExtension;

View File

@@ -0,0 +1,36 @@
import test from 'ava';
import getFileExtension from './getFileExtension';
test('returns the correct file extension', (t) => {
const extensions = ['.jpeg', '.js', '.css', '.json', '.xml'];
const filePath = 'source/static/images/hello-world';
extensions.forEach((ext) => {
t.true(getFileExtension(`${filePath}${ext}`) === ext);
});
});
test('sanitize file hash', (t) => {
const hashes = ['?', '#'];
const filePath = 'source/static/images/hello-world.jpeg';
hashes.forEach((hash) => {
t.true(getFileExtension(`${filePath}${hash}d587bbd6e38337f5accd`) === '.jpeg');
});
});
test('returns empty string when there is no file extension', (t) => {
const filePath = 'source/static/resource';
t.true(getFileExtension(filePath) === '');
});
test('should work even with null/undefined arg', (t) => {
const filePaths = ['', null, undefined];
filePaths.forEach((path) => {
t.true(getFileExtension(path) === '');
});
});

View File

@@ -0,0 +1,25 @@
/**
* react-loadable-ssr-addon
* @author Marcos Gonçalves <contact@themgoncalves.com>
* @version 1.0.1
*/
/**
* Checks if object array already contains given value
* @method hasEntry
* @function
* @param {array} target - Object array to be inspected
* @param {string} targetKey - Object key to look for
* @param {string} searchFor - Value to search existence
* @returns {boolean}
*/
export default function hasEntry(target, targetKey, searchFor) {
if (!target) { return false; }
for (let i = 0; i < target.length; i += 1) {
const file = target[i][targetKey];
if (file === searchFor) { return true; }
}
return false;
}

View File

@@ -0,0 +1,46 @@
import test from 'ava';
import hasEntry from './hasEntry';
const assets = [
{
file: 'content.chunk.js',
hash: 'd41d8cd98f00b204e9800998ecf8427e',
publicPath: './',
integrity: null,
},
{
file: 'header.chunk.js',
hash: '699f4bd49870f2b90e1d1596d362efcb',
publicPath: './',
integrity: null,
},
{
file: 'shared-multilevel.chunk.js',
hash: 'ab7b8b1c1d5083c17a39ccd2962202e1',
publicPath: './',
integrity: null,
},
];
test('should flag as has entry', (t) => {
const fileName = 'header.chunk.js';
t.true(hasEntry(assets, 'file', fileName));
});
test('should flag as has no entry', (t) => {
const fileName = 'footer.chunk.js';
t.false(hasEntry(assets, 'file', fileName));
});
test('should work even with null/undefined target', (t) => {
const targets = [[], null, undefined];
targets.forEach((target) => {
t.false(hasEntry(target, 'file', 'foo.js'));
});
});

View File

@@ -0,0 +1,4 @@
export { default as computeIntegrity } from './computeIntegrity';
export { default as getFileExtension } from './getFileExtension';
export { default as unique } from './unique';
export { default as hasEntry } from './hasEntry';

View File

@@ -0,0 +1,16 @@
/**
* react-loadable-ssr-addon
* @author Marcos Gonçalves <contact@themgoncalves.com>
* @version 1.0.1
*/
/**
* Clean array to unique values
* @method unique
* @function
* @param {array} array - Array to be inspected
* @returns {array} - Array with unique values
*/
export default function unique(array) {
return array.filter((elem, pos, arr) => arr.indexOf(elem) === pos);
}

View File

@@ -0,0 +1,22 @@
import test from 'ava';
import unique from './unique';
test('it filters duplicated entries', (t) => {
const duplicated = ['two', 'four'];
const raw = ['one', 'two', 'three', 'four'];
const filtered = unique([...raw, ...duplicated]);
duplicated.forEach((dup) => {
t.true(filtered.filter((item) => item === dup).length === 1);
});
});
test('should work with null/undefined values', (t) => {
const falsy = [null, undefined];
const raw = ['one', 'two', 'three', 'four'];
const filtered = unique([...raw, ...falsy]);
falsy.forEach((value) => {
t.true(filtered.includes(value));
});
});