sw-builder
Advanced tools
Comparing version
@@ -1,29 +0,1 @@ | ||
import { writeTextFile } from 'fs-utils-sync'; | ||
import { buildOutputPath, buildPrecacheAssetPaths, generateCacheName, readConfigFile, } from '../utils/index.js'; | ||
import { buildTemplate } from '../template/index.js'; | ||
/* ************************************************************************************************ | ||
* IMPLEMENTATION * | ||
************************************************************************************************ */ | ||
/** | ||
* Executes the sw-builder script and builds the Service Worker based on the configuration. | ||
* @param args | ||
* @throws | ||
* - NOT_A_FILE: if the path is not recognized by the OS as a file or if it doesn't exist | ||
* - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the content of the file is empty or invalid or the JSON | ||
* content cannot be parsed | ||
* - INVALID_CONFIG_VALUE: if any of the essential config values is invalid | ||
* - INVALID_TEMPLATE_NAME: if the provided template name is not supported | ||
* - NOT_A_PATH_ELEMENT: if the provided path doesn't exist or is not a valid path element | ||
*/ | ||
const run = ({ config = 'sw-builder.config.json' }) => { | ||
// load the configuration file | ||
const configuration = readConfigFile(config); | ||
// build the Service Worker's Template | ||
const template = buildTemplate(configuration.template, generateCacheName(), buildPrecacheAssetPaths(configuration.outDir, configuration.includeToPrecache, configuration.excludeFilesFromPrecache)); | ||
// finally, save the file in the specified path | ||
writeTextFile(buildOutputPath(configuration.outDir), template); | ||
}; | ||
/* ************************************************************************************************ | ||
* MODULE EXPORTS * | ||
************************************************************************************************ */ | ||
export { run, }; | ||
import{writeTextFile}from"fs-utils-sync";import{buildOutputPath,buildPrecacheAssetPaths,generateCacheName,readConfigFile}from"../utils/index.js";import{buildTemplate}from"../template/index.js";const run=({config:e="sw-builder.config.json"})=>{var e=readConfigFile(e),t=buildTemplate(e.template,generateCacheName(),buildPrecacheAssetPaths(e.outDir,e.includeToPrecache,e.excludeFilesFromPrecache));writeTextFile(buildOutputPath(e.outDir),t)};export{run}; |
@@ -1,1 +0,1 @@ | ||
export * from './build.js'; | ||
export*from"./build.js"; |
#! /usr/bin/env node | ||
import process from 'node:process'; | ||
import { parseArgs } from 'argv-utils'; | ||
import { run } from './build/index.js'; | ||
(() => { | ||
try { | ||
run(parseArgs(process.argv)); | ||
process.exit(0); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
process.exit(1); | ||
} | ||
})(); | ||
import process from"node:process";import{parseArgs}from"argv-utils";import{run}from"./build/index.js";try{run(parseArgs(process.argv)),process.exit(0)}catch(r){console.error(r),process.exit(1)} |
@@ -1,17 +0,1 @@ | ||
/* ************************************************************************************************ | ||
* IMPLEMENTATION * | ||
************************************************************************************************ */ | ||
/** | ||
* Errors | ||
* The list of errors that can occur in any of the modules. | ||
*/ | ||
var ERRORS; | ||
(function (ERRORS) { | ||
ERRORS["INVALID_TEMPLATE_NAME"] = "INVALID_TEMPLATE_NAME"; | ||
ERRORS["INVALID_CONFIG_VALUE"] = "INVALID_CONFIG_VALUE"; | ||
ERRORS["NOT_A_PATH_ELEMENT"] = "NOT_A_PATH_ELEMENT"; | ||
})(ERRORS || (ERRORS = {})); | ||
/* ************************************************************************************************ | ||
* MODULE EXPORTS * | ||
************************************************************************************************ */ | ||
export { ERRORS, }; | ||
var ERRORS;!function(E){E.INVALID_TEMPLATE_NAME="INVALID_TEMPLATE_NAME",E.INVALID_CONFIG_VALUE="INVALID_CONFIG_VALUE",E.NOT_A_PATH_ELEMENT="NOT_A_PATH_ELEMENT"}(ERRORS=ERRORS||{});export{ERRORS}; |
@@ -1,2 +0,1 @@ | ||
export * from './types.js'; | ||
export * from './errors.js'; | ||
export*from"./types.js";export*from"./errors.js"; |
@@ -1,1 +0,1 @@ | ||
export * from './template.js'; | ||
export*from"./template.js"; |
@@ -1,75 +0,1 @@ | ||
import { encodeError } from 'error-message-utils'; | ||
import { readTextFile } from 'fs-utils-sync'; | ||
import { ERRORS } from '../shared/index.js'; | ||
/* ************************************************************************************************ | ||
* HELPERS * | ||
************************************************************************************************ */ | ||
/** | ||
* Reads the raw content for a given template name. | ||
* @param name | ||
* @returns string | ||
* @throws | ||
* - NOT_A_FILE: if the path is not recognized by the OS as a file or if it doesn't exist | ||
* - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the content of the file is empty or invalid | ||
*/ | ||
const __getRawTemplate = (name) => readTextFile(`raw/sw.${name}.js`); | ||
/** | ||
* Inserts the freshly generated cacheName into the raw template. | ||
* @param rawTemplate | ||
* @param cacheName | ||
* @returns string | ||
*/ | ||
const __insertCacheName = (rawTemplate, cacheName) => (rawTemplate.replace('const CACHE_NAME = \'\';', `const CACHE_NAME = '${cacheName}';`)); | ||
/** | ||
* Stringifies a given list of asset paths that will be pre-cached. | ||
* @param precacheAssets | ||
* @returns string | ||
*/ | ||
const __stringifyPrecacheAssets = (precacheAssets) => { | ||
let assets = 'const PRECACHE_ASSETS = [\n'; | ||
assets += precacheAssets.reduce((prev, current, index) => `${prev} '${current}'${index < precacheAssets.length - 1 ? ',\n' : ','}`, ''); | ||
assets += '\n];'; | ||
return assets; | ||
}; | ||
/** | ||
* Inserts the pre-cache assets content into the raw template. | ||
* @param rawTemplate | ||
* @param precacheAssets | ||
* @returns string | ||
*/ | ||
const __insertPrecacheAssets = (rawTemplate, precacheAssets) => (rawTemplate.replace('const PRECACHE_ASSETS = [];', __stringifyPrecacheAssets(precacheAssets))); | ||
/* ************************************************************************************************ | ||
* IMPLEMENTATION * | ||
************************************************************************************************ */ | ||
/** | ||
* Builds the base template ready to be saved. | ||
* @param cacheName | ||
* @param precacheAssets | ||
* @returns string | ||
*/ | ||
const __buildBaseTemplate = (cacheName, precacheAssets) => __insertPrecacheAssets(__insertCacheName(__getRawTemplate('base'), cacheName), precacheAssets); | ||
/** | ||
* Builds a Service Worker Template by name. | ||
* @param template | ||
* @param cacheName | ||
* @param precacheAssets | ||
* @returns string | ||
* @throws | ||
* - INVALID_TEMPLATE_NAME: if the provided template name is not supported | ||
* - NOT_A_FILE: if the path is not recognized by the OS as a file or if it doesn't exist | ||
* - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the content of the file is empty or invalid | ||
*/ | ||
const buildTemplate = (template, cacheName, precacheAssets) => { | ||
switch (template) { | ||
case 'base': { | ||
return __buildBaseTemplate(cacheName, precacheAssets); | ||
} | ||
default: { | ||
throw new Error(encodeError(`The template name '${template}' is not supported.`, ERRORS.INVALID_TEMPLATE_NAME)); | ||
} | ||
} | ||
}; | ||
/* ************************************************************************************************ | ||
* MODULE EXPORTS * | ||
************************************************************************************************ */ | ||
export { buildTemplate, }; | ||
import{encodeError}from"error-message-utils";import{ERRORS}from"../shared/index.js";import{BASE_TEMPLATE}from"./templates/index.js";const __insertCacheName=(e,r)=>e.replace("const CACHE_NAME = '';",`const CACHE_NAME = '${r}';`),__stringifyPrecacheAssets=t=>{var e="const PRECACHE_ASSETS = [\n";return e+t.reduce((e,r,s)=>e+` '${r}'`+(s<t.length-1?",\n":","),"")+"\n];"},__insertPrecacheAssets=(e,r)=>e.replace("const PRECACHE_ASSETS = [];",__stringifyPrecacheAssets(r)),__buildBaseTemplate=(e,r)=>__insertPrecacheAssets(__insertCacheName(BASE_TEMPLATE,e),r),buildTemplate=(e,r,s)=>{if("base"!==e)throw new Error(encodeError(`The template name '${e}' is not supported.`,ERRORS.INVALID_TEMPLATE_NAME));return __buildBaseTemplate(r,s)};export{buildTemplate}; |
@@ -1,1 +0,1 @@ | ||
export * from './utils.js'; | ||
export*from"./utils.js"; |
@@ -1,148 +0,1 @@ | ||
import { join } from 'node:path'; | ||
import { encodeError } from 'error-message-utils'; | ||
import { isDirectory, readJSONFile, getPathElement, readDirectory, } from 'fs-utils-sync'; | ||
import { ERRORS } from '../shared/index.js'; | ||
/* ************************************************************************************************ | ||
* CONSTANTS * | ||
************************************************************************************************ */ | ||
// the characters that can be used to generate cache names | ||
const CACHE_NAME_CHARACTERS = 'abcdefghijklmnopqrstuvwxyz0123456789'; | ||
// the number of characters that will comprise the cache names | ||
const CACHE_NAME_LENGTH = 10; | ||
// the name of the file that is built and placed in the outDir | ||
const OUTPUT_NAME = 'sw.js'; | ||
/* ************************************************************************************************ | ||
* HELPERS * | ||
************************************************************************************************ */ | ||
/** | ||
* Performs the essential validations on the configuration file. Note it doesn't get into template | ||
* specific validations. | ||
* @param config | ||
* @throws | ||
* - INVALID_CONFIG_VALUE: if any of the essential config values is invalid | ||
*/ | ||
const __validateConfigFile = (config) => { | ||
if (!config || typeof config !== 'object') { | ||
console.log(config); | ||
throw new Error(encodeError('The extracted configuration is not a valid object.', ERRORS.INVALID_CONFIG_VALUE)); | ||
} | ||
if (typeof config.outDir !== 'string' || !config.outDir.length || !isDirectory(config.outDir)) { | ||
throw new Error(encodeError(`The outDir '${config.outDir}' is not a directory or doesn't exist.`, ERRORS.INVALID_CONFIG_VALUE)); | ||
} | ||
if (typeof config.template !== 'string' || !config.template.length) { | ||
throw new Error(encodeError(`The template '${config.template}' is not a valid template name.`, ERRORS.INVALID_CONFIG_VALUE)); | ||
} | ||
if (!Array.isArray(config.includeToPrecache) || !config.includeToPrecache.length) { | ||
console.log(config.includeToPrecache); | ||
throw new Error(encodeError(`The includeToPrecache '${config.includeToPrecache}' list is invalid or empty.`, ERRORS.INVALID_CONFIG_VALUE)); | ||
} | ||
if (!Array.isArray(config.excludeFilesFromPrecache)) { | ||
console.log(config.excludeFilesFromPrecache); | ||
throw new Error(encodeError(`The excludeFilesFromPrecache '${config.excludeFilesFromPrecache}' list is invalid.`, ERRORS.INVALID_CONFIG_VALUE)); | ||
} | ||
}; | ||
/** | ||
* Extracts the path element from a given path. | ||
* @param path | ||
* @returns IPathElement | ||
* @throws | ||
* - NOT_A_PATH_ELEMENT: if the provided path doesn't exist or is not a valid path element | ||
*/ | ||
const __getPathElement = (path) => { | ||
const el = getPathElement(path); | ||
if (el === null || (!el.isDirectory && !el.isFile)) { | ||
throw new Error(encodeError(`The asset '${path}' is not a path element.`, ERRORS.NOT_A_PATH_ELEMENT)); | ||
} | ||
return el; | ||
}; | ||
/** | ||
* Fully reads a given directory path and returns the files that are cacheable. | ||
* @param outDir | ||
* @param path | ||
* @param excludeFilesFromPrecache | ||
* @returns string[] | ||
*/ | ||
const __extractCacheableFilesFromDirectory = (outDir, path, excludeFilesFromPrecache) => { | ||
// read all the directory contents | ||
let content = readDirectory(path, true); | ||
// filter those paths that are not cacheable | ||
content = content.filter((p) => { | ||
const el = __getPathElement(p); | ||
return el.isFile && !excludeFilesFromPrecache.includes(el.baseName); | ||
}); | ||
// finally, remove the outDir from the path | ||
return content.map((filePath) => filePath.replace(outDir, '')); | ||
}; | ||
/* ************************************************************************************************ | ||
* IMPLEMENTATION * | ||
************************************************************************************************ */ | ||
/** | ||
* Reads, validates and returns the configuration file. | ||
* @param configPath | ||
* @returns IBaseConfig | ||
* @throws | ||
* - NOT_A_FILE: if the path is not recognized by the OS as a file or if it doesn't exist | ||
* - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the content of the file is empty or invalid | ||
* - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the file's JSON content cannot be parsed | ||
* - INVALID_CONFIG_VALUE: if any of the essential config values is invalid | ||
*/ | ||
const readConfigFile = (configPath) => { | ||
const config = readJSONFile(configPath); | ||
__validateConfigFile(config); | ||
return config; | ||
}; | ||
/** | ||
* Generates a randomly generated name to be used for the CacheStorage | ||
* @returns string | ||
*/ | ||
const generateCacheName = () => { | ||
let nm = ''; | ||
let counter = 0; | ||
while (counter < CACHE_NAME_LENGTH) { | ||
nm += CACHE_NAME_CHARACTERS.charAt(Math.floor(Math.random() * CACHE_NAME_CHARACTERS.length)); | ||
counter += 1; | ||
} | ||
return nm; | ||
}; | ||
/** | ||
* Puts the list of all the assets that must be cached based on the include and exclude lists. | ||
* @param outDir | ||
* @param includeToPrecache | ||
* @param excludeFilesFromPrecache | ||
* @returns string[] | ||
* @throws | ||
* - NOT_A_PATH_ELEMENT: if the provided path doesn't exist or is not a valid path element | ||
*/ | ||
const buildPrecacheAssetPaths = (outDir, includeToPrecache, excludeFilesFromPrecache) => { | ||
// init the list of assets | ||
const assets = ['/']; | ||
// iterate over each asset that will be precached. Ensure to avoid the root path and files that | ||
// should be excluded | ||
includeToPrecache.forEach((path) => { | ||
if (path !== '/') { | ||
const el = __getPathElement(join(outDir, path)); | ||
if (el.isFile && !excludeFilesFromPrecache.includes(el.baseName)) { | ||
assets.push(path); | ||
} | ||
else { | ||
assets.push(...__extractCacheableFilesFromDirectory(outDir, el.path, excludeFilesFromPrecache)); | ||
} | ||
} | ||
}); | ||
// finally, return the completed list | ||
return assets; | ||
}; | ||
/** | ||
* Builds the binary's output build based on the config's outDir. | ||
* @param outDir | ||
* @returns string | ||
*/ | ||
const buildOutputPath = (outDir) => join(outDir, OUTPUT_NAME); | ||
/* ************************************************************************************************ | ||
* MODULE EXPORTS * | ||
************************************************************************************************ */ | ||
export { | ||
// constants | ||
CACHE_NAME_CHARACTERS, CACHE_NAME_LENGTH, OUTPUT_NAME, | ||
// implementation | ||
readConfigFile, generateCacheName, buildPrecacheAssetPaths, buildOutputPath, }; | ||
import{join}from"node:path";import{encodeError}from"error-message-utils";import{isDirectory,readJSONFile,getPathElement,readDirectory}from"fs-utils-sync";import{ERRORS}from"../shared/index.js";const CACHE_NAME_CHARACTERS="abcdefghijklmnopqrstuvwxyz0123456789",CACHE_NAME_LENGTH=10,OUTPUT_NAME="sw.js",__validateConfigFile=e=>{if(!e||"object"!=typeof e)throw console.log(e),new Error(encodeError("The extracted configuration is not a valid object.",ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.outDir||!e.outDir.length||!isDirectory(e.outDir))throw new Error(encodeError(`The outDir '${e.outDir}' is not a directory or doesn't exist.`,ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.template||!e.template.length)throw new Error(encodeError(`The template '${e.template}' is not a valid template name.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.includeToPrecache)||!e.includeToPrecache.length)throw console.log(e.includeToPrecache),new Error(encodeError(`The includeToPrecache '${e.includeToPrecache}' list is invalid or empty.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.excludeFilesFromPrecache))throw console.log(e.excludeFilesFromPrecache),new Error(encodeError(`The excludeFilesFromPrecache '${e.excludeFilesFromPrecache}' list is invalid.`,ERRORS.INVALID_CONFIG_VALUE))},__getPathElement=e=>{var r=getPathElement(e);if(null===r||!r.isDirectory&&!r.isFile)throw new Error(encodeError(`The asset '${e}' is not a path element.`,ERRORS.NOT_A_PATH_ELEMENT));return r},__extractCacheableFilesFromDirectory=(r,e,t)=>{let o=readDirectory(e,!0);return(o=o.filter(e=>{e=__getPathElement(e);return e.isFile&&!t.includes(e.baseName)})).map(e=>e.replace(r,""))},readConfigFile=e=>{e=readJSONFile(e);return __validateConfigFile(e),e},generateCacheName=()=>{let e="",r=0;for(;r<CACHE_NAME_LENGTH;)e+=CACHE_NAME_CHARACTERS.charAt(Math.floor(Math.random()*CACHE_NAME_CHARACTERS.length)),r+=1;return e},buildPrecacheAssetPaths=(t,e,o)=>{const i=["/"];return e.forEach(e=>{var r;"/"!==e&&((r=__getPathElement(join(t,e))).isFile&&!o.includes(r.baseName)?i.push(e):i.push(...__extractCacheableFilesFromDirectory(t,r.path,o)))}),i},buildOutputPath=e=>join(e,OUTPUT_NAME);export{CACHE_NAME_CHARACTERS,CACHE_NAME_LENGTH,OUTPUT_NAME,readConfigFile,generateCacheName,buildPrecacheAssetPaths,buildOutputPath}; |
{ | ||
"name": "sw-builder", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "The sw-builder package automates the creation of your Application's Service Worker, which pre-caches your build. This leads to a better overall performance and enables users to access your PWA without an Internet connection.", | ||
@@ -9,3 +9,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"start": "rm -r -f dist && tsc --project tsconfig.build.json", | ||
"start": "ts-lib-builder --tsconfigPath=tsconfig.build.json", | ||
"test": "echo \"Error: tests are executed with npm run test:(integration|unit)\" && exit 1", | ||
@@ -50,2 +50,3 @@ "test:integration": "vitest run --config vitest.test-integration.config.ts", | ||
"eslint-config-airbnb-typescript": "^18.0.0", | ||
"ts-lib-builder": "^1.0.2", | ||
"typescript": "^5.4.5", | ||
@@ -52,0 +53,0 @@ "vitest": "^1.6.0" |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 3 instances in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
27
8%2
-33.33%16783
-35.93%7
16.67%206
-58.3%3
Infinity%