poops 1.0.1 → 1.0.2

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/lib/markups.js ADDED
@@ -0,0 +1,149 @@
1
+ const helpers = require('./utils/helpers.js')
2
+ const fs = require('node:fs')
3
+ const glob = require('glob')
4
+ const nunjucks = require('nunjucks')
5
+ const path = require('node:path')
6
+ const PrintStyle = require('./utils/print-style.js')
7
+
8
+ const { pathExists, pathIsDirectory } = helpers
9
+ const pstyle = new PrintStyle()
10
+
11
+ class RelativeLoader extends nunjucks.Loader {
12
+ constructor(templatesDir, includePaths) {
13
+ super()
14
+ this.templatesDir = templatesDir
15
+ this.includePaths = includePaths || []
16
+ this.includePaths.push('_*')
17
+ }
18
+
19
+ getSource(name) {
20
+ let fullPath = name
21
+ if (!fs.existsSync(name)) {
22
+ let pattern = `**/${name}`
23
+ if (this.includePaths) {
24
+ pattern = `{${this.includePaths.join(',')}}/${pattern}`
25
+ }
26
+ fullPath = glob.sync(path.join(this.templatesDir, pattern))[0]
27
+ }
28
+ if (!fs.existsSync(fullPath)) {
29
+ throw new Error(`Template not found: ${name}`)
30
+ }
31
+
32
+ // TODO: Here we can interpret header yaml and pass it as a context, just like Jekyll does
33
+ const source = fs.readFileSync(fullPath, 'utf-8')
34
+ return { src: source, path: fullPath, noCache: true }
35
+ }
36
+
37
+ resolve(from, to) {
38
+ return path.resolve(path.dirname(from), to)
39
+ }
40
+ }
41
+
42
+ module.exports = class Markups {
43
+ constructor(config) {
44
+ this.config = config
45
+
46
+ if (!this.config.markup || !this.config.markup.in) return
47
+
48
+ this.nunjucksEnv = new nunjucks.Environment(new RelativeLoader(path.join(process.cwd(), config.markup.in), config.markup.includePaths), {
49
+ autoescape: true,
50
+ watch: false,
51
+ noCache: true
52
+ })
53
+
54
+ const pkgPath = path.join(process.cwd(), 'package.json')
55
+
56
+ if (fs.existsSync(pkgPath)) {
57
+ const pkg = require(pkgPath)
58
+ this.nunjucksEnv.addGlobal('package', pkg)
59
+ }
60
+
61
+ if (this.config.markup.site) {
62
+ this.nunjucksEnv.addGlobal('site', this.config.markup.site)
63
+ }
64
+
65
+ if (this.config.markup.data) {
66
+ for (const dataFile of this.config.markup.data) {
67
+ const data = require(path.join(process.cwd(), dataFile))
68
+ // TODO: should support YAML too. There should be a way to define the data file per template through front matter
69
+ this.nunjucksEnv.addGlobal(path.basename(dataFile, path.extname(dataFile)).replace(/[.\-\s]/g, '_'), data)
70
+ }
71
+ }
72
+
73
+ this.payload = {} // TODO: still not used. This is where we can store data from data files. Can be used to pass front matter data or even a way to pass data from files to templates
74
+
75
+ if (!this.config.markup.out) {
76
+ this.config.markup.out = process.cwd()
77
+ }
78
+ }
79
+
80
+ generateMarkupGlobPattern(excludes) {
81
+ let markupDefaultExcludes = ['node_modules', '.git', '.svn', '.hg']
82
+
83
+ if (excludes) {
84
+ markupDefaultExcludes.push(...excludes)
85
+ }
86
+
87
+ if (this.config.includePaths) {
88
+ markupDefaultExcludes.push(...this.config.includePaths)
89
+ }
90
+
91
+ markupDefaultExcludes.push('_*')
92
+
93
+ markupDefaultExcludes = [...new Set(markupDefaultExcludes)] // Remove duplicates
94
+
95
+ return `!(${markupDefaultExcludes.join('|')})/**/*.+(html|njk)`
96
+ }
97
+
98
+ compileEntry(templateName, context) {
99
+ const env = this.nunjucksEnv
100
+ return new Promise((resolve, reject) => {
101
+ env.getTemplate(templateName).render(context, (error, result) => {
102
+ if (!error) {
103
+ resolve(result)
104
+ } else {
105
+ reject(error)
106
+ }
107
+ })
108
+ })
109
+ }
110
+
111
+ compile() {
112
+ // TODO: should support multiple markup paths, for loop here!
113
+ if (!this.config.markup || !this.config.markup.in) return
114
+
115
+ const markupIn = path.join(process.cwd(), this.config.markup.in)
116
+
117
+ if (!pathExists(markupIn)) {
118
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} Markup path does not exist: ${pstyle.dim}${markupIn}${pstyle.reset}`)
119
+ return
120
+ }
121
+
122
+ if (pathIsDirectory(markupIn)) {
123
+ const markupFiles = [...glob.sync(path.join(markupIn, this.generateMarkupGlobPattern(this.config.markup.includePaths))), ...glob.sync(path.join(markupIn, '*.+(html|njk)'))]
124
+ const compilePromises = []
125
+ markupFiles.forEach((file) => {
126
+ const markupOut = path.join(process.cwd(), path.relative(this.config.markup.in, file))
127
+ const markupOutDir = path.dirname(markupOut)
128
+
129
+ if (!pathExists(markupOutDir)) {
130
+ fs.mkdirSync(markupOutDir, { recursive: true })
131
+ }
132
+
133
+ const compilePromise = this.compileEntry(file, this.payload).then((result) => {
134
+ fs.writeFileSync(markupOut, result)
135
+ })
136
+ compilePromises.push(compilePromise)
137
+ })
138
+
139
+ Promise.all(compilePromises).then(() => {
140
+ console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.dim}Compiled: ${pstyle.reset}${markupFiles.length} file${markupFiles.length > 1 ? 's' : ''} into ${pstyle.italic + pstyle.underline}${this.config.markup.out}${pstyle.reset}`)
141
+ })
142
+ } else {
143
+ this.compileEntry(markupIn, this.pkg).then((result) => {
144
+ fs.writeFileSync(path.join(process.cwd(), this.config.markup.out, path.basename(markupIn)), result)
145
+ console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${path.relative(process.cwd(), path.join(process.cwd(), this.config.markup.out, path.basename(markupIn)))}${pstyle.reset}`)
146
+ })
147
+ }
148
+ }
149
+ }
package/lib/scripts.js ADDED
@@ -0,0 +1,116 @@
1
+ const { build } = require('esbuild')
2
+ const deepmerge = require('deepmerge')
3
+ const helpers = require('./utils/helpers.js')
4
+ const fs = require('node:fs')
5
+ const PrintStyle = require('./utils/print-style.js')
6
+ const Terser = require('terser')
7
+
8
+ const {
9
+ pathExists,
10
+ mkPath,
11
+ pathForFile,
12
+ insertMinSuffix,
13
+ buildScriptOutputFilePath,
14
+ fillBannerTemplate,
15
+ buildTime,
16
+ fileSize
17
+ } = helpers
18
+
19
+ const pstyle = new PrintStyle()
20
+
21
+ module.exports = class Scripts {
22
+ constructor(config) {
23
+ this.config = config
24
+ this.banner = fillBannerTemplate(config.banner, config.pkg)
25
+ }
26
+
27
+ compile() {
28
+ if (!this.config.scripts) return
29
+ this.config.scripts = Array.isArray(this.config.scripts) ? this.config.scripts : [this.config.scripts]
30
+ for (const scriptEntry of this.config.scripts) {
31
+ if (scriptEntry.in && scriptEntry.out && pathExists(scriptEntry.in)) {
32
+ mkPath(scriptEntry.out)
33
+ this.compileEntry(scriptEntry.in, scriptEntry.out, scriptEntry.options)
34
+ }
35
+ }
36
+ }
37
+
38
+ compileEntry(infilePath, outfilePath, options = {}) {
39
+ if (!Array.isArray(infilePath)) infilePath = [infilePath]
40
+
41
+ const opts = {
42
+ logLevel: 'error',
43
+ entryPoints: infilePath,
44
+ bundle: true,
45
+ sourcemap: false,
46
+ minify: false,
47
+ format: 'iife',
48
+ target: 'es2019',
49
+ nodePaths: this.config.includePaths // Resolve `includePaths`
50
+ }
51
+
52
+ const terserOpts = {
53
+ mangle: false
54
+ }
55
+
56
+ if (this.banner) {
57
+ opts.banner = {
58
+ js: this.banner,
59
+ css: this.banner
60
+ }
61
+ }
62
+
63
+ if (!pathForFile(outfilePath)) {
64
+ opts.outdir = outfilePath
65
+ } else {
66
+ if (infilePath.length > 1) {
67
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} Cannot output multiple ${pstyle.bold + pstyle.underline}script${pstyle.reset} files to a single file. Please specify an output directory path instead.`)
68
+ process.exit(1)
69
+ }
70
+ opts.outfile = outfilePath
71
+ }
72
+
73
+ if (options.format) opts.format = options.format
74
+ if (options.target) opts.target = options.target
75
+ if (options.nodePaths) opts.nodePaths = [...new Set([...opts.nodePaths, ...options.nodePaths])]
76
+ if (options.sourcemap) opts.sourcemap = options.sourcemap
77
+
78
+ if (options.mangle) terserOpts.mangle = options.mangle
79
+
80
+ delete options.mangle
81
+ deepmerge(opts, options) // ability to pass other esbuild options `node_modules/esbuild/lib/main.d.ts`
82
+
83
+ // TODO: Actually loop the build process for each entry point!!!
84
+ const esbuildStart = performance.now()
85
+ build(opts).then(() => {
86
+ const esbuildEnd = performance.now()
87
+ for (const entry of infilePath) {
88
+ const newOutFilePath = buildScriptOutputFilePath(entry, outfilePath)
89
+ const minPath = insertMinSuffix(newOutFilePath)
90
+
91
+ if (!options.justMinified) console.log(`${pstyle.yellowBright + pstyle.bold}[script]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${newOutFilePath}${pstyle.reset} ${pstyle.greenBright}${fileSize(newOutFilePath)}${pstyle.reset} ${pstyle.green}(${buildTime(esbuildStart, esbuildEnd)})${pstyle.reset}`)
92
+ if (options.sourcemap) console.log(`${pstyle.yellowBright + pstyle.bold}[script]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${newOutFilePath}.map${pstyle.reset}`)
93
+
94
+ if (options.minify) {
95
+ const terserStart = performance.now()
96
+ Terser.minify(fs.readFileSync(newOutFilePath, 'utf-8'), { mangle: terserOpts.mangle }).then((result) => {
97
+ if (result.error) {
98
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} Error occurred during JS minification: ${pstyle.dim}${result.error}${pstyle.reset}`)
99
+ } else {
100
+ if (this.banner) result.code = this.banner + '\n' + result.code
101
+ fs.writeFileSync(minPath, result.code)
102
+ const terserEnd = performance.now()
103
+ console.log(`${pstyle.yellowBright + pstyle.bold}[script]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${minPath}${pstyle.reset} ${pstyle.greenBright}${fileSize(minPath)}${pstyle.reset} ${pstyle.green}(${buildTime(terserStart, terserEnd)})${pstyle.reset}`)
104
+ }
105
+ })
106
+
107
+ if (options.justMinified) {
108
+ fs.unlinkSync(newOutFilePath)
109
+ }
110
+ } else {
111
+ fs.unlinkSync(minPath)
112
+ }
113
+ }
114
+ })
115
+ }
116
+ }
package/lib/styles.js ADDED
@@ -0,0 +1,140 @@
1
+ const autoprefixer = require('autoprefixer')
2
+ const cssnano = require('cssnano')
3
+ const fs = require('node:fs')
4
+ const helpers = require('./utils/helpers.js')
5
+ const path = require('node:path')
6
+ const { pathToFileURL } = require('node:url')
7
+ const postcss = require('postcss')
8
+ const sass = require('sass')
9
+ const PrintStyle = require('./utils/print-style.js')
10
+
11
+ const {
12
+ pathExists,
13
+ pathIsDirectory,
14
+ mkPath,
15
+ insertMinSuffix,
16
+ buildStyleOutputFilePath,
17
+ fillBannerTemplate,
18
+ buildTime,
19
+ fileSize
20
+ } = helpers
21
+
22
+ const pstyle = new PrintStyle()
23
+
24
+ function tryToFindFile(filePath, extensions) {
25
+ const fileExt = extensions.find(ext => fs.existsSync(`${filePath}.${ext}`))
26
+ if (fileExt) {
27
+ return `${filePath}.${fileExt}`
28
+ }
29
+ return null
30
+ }
31
+
32
+ function sassPathResolver(url, resolvePath) {
33
+ if (fs.existsSync(url)) return new URL(url)
34
+ const resolvedPath = pathToFileURL(resolvePath)
35
+ if (!fs.existsSync(resolvedPath.pathname)) return null
36
+ const importPath = path.relative(process.cwd(), path.join(resolvedPath.pathname, url))
37
+
38
+ if (!fs.existsSync(importPath)) {
39
+ const correctFile = tryToFindFile(importPath, ['sass', 'scss', 'css'])
40
+ if (correctFile) return new URL(correctFile, resolvedPath)
41
+ }
42
+
43
+ if (pathIsDirectory(importPath) && !pathExists(importPath, 'index.sass') && !pathExists(importPath, 'index.scss')) {
44
+ const correctFile = tryToFindFile(importPath, ['sass', 'scss', 'css'])
45
+ if (correctFile) return new URL(correctFile, resolvedPath)
46
+
47
+ if (!pathExists(importPath, 'package.json')) return null
48
+
49
+ const pkg = require(path.join(importPath, 'package.json'))
50
+
51
+ if (pkg.sass) return new URL(path.join(importPath, pkg.sass), resolvedPath)
52
+ if (pkg.css) return new URL(path.join(importPath, pkg.css), resolvedPath)
53
+
54
+ const basename = path.basename(pkg.main)
55
+ if (pkg.main && /(\.sass|\.scss|\.css)$/i.test(basename)) return new URL(path.join(importPath, pkg.main), resolvedPath)
56
+ return null
57
+ }
58
+
59
+ return new URL(importPath, resolvedPath)
60
+ }
61
+
62
+ module.exports = class Styles {
63
+ constructor(config) {
64
+ this.config = config
65
+ this.banner = config.banner ? fillBannerTemplate(config.banner) : null
66
+ }
67
+
68
+ compile() {
69
+ if (!this.config.styles) return
70
+ this.config.styles = Array.isArray(this.config.styles) ? this.config.styles : [this.config.styles]
71
+ for (const styleEntry of this.config.styles) {
72
+ if (styleEntry.in && styleEntry.out && pathExists(styleEntry.in)) {
73
+ mkPath(styleEntry.out)
74
+ this.compileEntry(styleEntry.in, styleEntry.out, styleEntry.options)
75
+ }
76
+ }
77
+ }
78
+
79
+ compileEntry(infilePath, outfilePath, options = {}) {
80
+ const includePaths = this.config.includePaths || []
81
+
82
+ const opts = {
83
+ sourceMap: false,
84
+ sourceMapIncludeSources: false,
85
+ importers: [{
86
+ // Resolve `includePaths`.
87
+ findFileUrl(url) {
88
+ for (const includePath of includePaths) {
89
+ const resolvedPath = sassPathResolver(url, includePath)
90
+ if (resolvedPath) return resolvedPath
91
+ }
92
+ return null
93
+ }
94
+ }]
95
+ }
96
+
97
+ if (options.sourcemap) {
98
+ opts.sourceMap = options.sourcemap
99
+ opts.sourceMapIncludeSources = options.sourcemap
100
+ }
101
+
102
+ outfilePath = buildStyleOutputFilePath(infilePath, outfilePath, options)
103
+
104
+ const cssStart = performance.now()
105
+ const compiledSass = sass.compile(infilePath, opts)
106
+ const mapsrc = options.sourcemap ? `\n/*# sourceMappingURL=${path.basename(outfilePath)}.map */` : ''
107
+ if (this.banner) compiledSass.css = this.banner + '\n' + compiledSass.css
108
+ fs.writeFileSync(outfilePath, compiledSass.css + mapsrc)
109
+ const cssEnd = performance.now()
110
+ if (!options.justMinified) console.log(`${pstyle.magentaBright + pstyle.bold}[style]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${outfilePath}${pstyle.reset} ${pstyle.greenBright}${fileSize(outfilePath)}${pstyle.reset} ${pstyle.green}(${buildTime(cssStart, cssEnd)})${pstyle.reset}`)
111
+
112
+ if (compiledSass.sourceMap) {
113
+ if (this.banner) compiledSass.sourceMap.mappings = ';' + compiledSass.sourceMap.mappings
114
+ fs.writeFileSync(`${outfilePath}.map`, JSON.stringify(compiledSass.sourceMap))
115
+ console.log(`${pstyle.magentaBright + pstyle.bold}[style]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${outfilePath}.map${pstyle.reset}`)
116
+ }
117
+
118
+ const cssMinStart = performance.now()
119
+ const minPath = insertMinSuffix(outfilePath)
120
+ if (options.minify) {
121
+ postcss([autoprefixer, cssnano]).process(compiledSass.css, {
122
+ from: outfilePath,
123
+ to: minPath
124
+ }).then(result => {
125
+ if (this.banner) result.css = this.banner + '\n' + result.css
126
+ fs.writeFileSync(minPath, result.css)
127
+ const cssMinEnd = performance.now()
128
+ console.log(`${pstyle.magentaBright + pstyle.bold}[style]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${minPath}${pstyle.reset} ${pstyle.greenBright}${fileSize(minPath)}${pstyle.reset} ${pstyle.green}(${buildTime(cssMinStart, cssMinEnd)})${pstyle.reset}`)
129
+ }).catch((error) => {
130
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} Error occurred during CSS minification: ${pstyle.dim}${error}${pstyle.reset}`)
131
+ })
132
+
133
+ if (options.justMinified) {
134
+ fs.unlinkSync(outfilePath)
135
+ }
136
+ } else {
137
+ fs.unlinkSync(minPath)
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,81 @@
1
+ const fs = require('node:fs')
2
+ const path = require('node:path')
3
+
4
+ function pathExists() {
5
+ return fs.existsSync(path.join(...arguments))
6
+ }
7
+
8
+ function pathIsDirectory() {
9
+ return fs.lstatSync(path.join(...arguments)).isDirectory()
10
+ }
11
+
12
+ function mkPath(filePath) {
13
+ const dirPath = path.dirname(filePath)
14
+ if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true })
15
+ }
16
+
17
+ function pathForFile(filePath) {
18
+ return /\./.test(path.basename(filePath))
19
+ }
20
+
21
+ function insertMinSuffix(filePath) {
22
+ const { name, ext } = path.parse(filePath)
23
+ return path.join(path.dirname(filePath), `${name}.min${ext}`)
24
+ }
25
+
26
+ function buildStyleOutputFilePath(inputPath, outputPath) {
27
+ if (pathForFile(outputPath)) return outputPath
28
+ const { name } = path.parse(inputPath)
29
+ return path.join(path.join(outputPath, `${name}.css`))
30
+ }
31
+
32
+ function buildScriptOutputFilePath(inputPath, outputPath) {
33
+ if (pathForFile(outputPath)) return outputPath
34
+ const { name, ext } = path.parse(inputPath)
35
+ return path.join(path.join(outputPath, `${name}${ext.replace('t', 'j')}`))
36
+ }
37
+
38
+ function fillBannerTemplate(template, packagesPath) {
39
+ packagesPath = packagesPath || process.cwd()
40
+ const packagesFilePath = path.join(packagesPath, 'package.json')
41
+ if (!pathExists(packagesFilePath)) return template
42
+ const pkg = require(packagesFilePath)
43
+ const { name, version, homepage, description, license, author } = pkg
44
+ const year = new Date().getFullYear()
45
+
46
+ return template
47
+ .replace(/{{\s?name\s?}}/g, name)
48
+ .replace(/{{\s?version\s?}}/g, version)
49
+ .replace(/{{\s?homepage\s?}}/g, homepage)
50
+ .replace(/{{\s?description\s?}}/g, description)
51
+ .replace(/{{\s?author\s?}}/g, author)
52
+ .replace(/{{\s?license\s?}}/g, license)
53
+ .replace(/{{\s?year\s?}}/g, year)
54
+ }
55
+
56
+ function buildTime(start, end) {
57
+ const time = Math.round(end - start)
58
+ if (time < 1000) return `${time}ms`
59
+ if (time < 60 * 1000) return `${(time / 1000).toFixed(0)}s ${time % 1000}ms`
60
+ return `${(time / 1000 / 60).toFixed(0)}m ${((time / 1000) % 60).toFixed(0)}s ${time % 1000}ms`
61
+ }
62
+
63
+ function fileSize(filePath) {
64
+ const stats = fs.statSync(filePath)
65
+ const fileSizeInBytes = stats.size
66
+ if (fileSizeInBytes < 1000) return `${fileSizeInBytes}B`
67
+ if (fileSizeInBytes < 1000 * 1000) return `${(fileSizeInBytes / 1000).toFixed(0)}KB`
68
+ if (fileSizeInBytes < 1000 * 1000 * 1000) return `${(fileSizeInBytes / 1000 / 1000).toFixed(0)}MB ${fileSizeInBytes % (1000 * 1000)}KB`
69
+ return fileSizeInBytes
70
+ }
71
+
72
+ exports.pathExists = pathExists
73
+ exports.pathIsDirectory = pathIsDirectory
74
+ exports.mkPath = mkPath
75
+ exports.pathForFile = pathForFile
76
+ exports.insertMinSuffix = insertMinSuffix
77
+ exports.buildStyleOutputFilePath = buildStyleOutputFilePath
78
+ exports.buildScriptOutputFilePath = buildScriptOutputFilePath
79
+ exports.fillBannerTemplate = fillBannerTemplate
80
+ exports.buildTime = buildTime
81
+ exports.fileSize = fileSize
@@ -0,0 +1,72 @@
1
+ module.exports = class PrintStyle {
2
+ reset = '\x1b[0m'
3
+ bold = '\x1b[1m'
4
+ dim = '\x1b[2m'
5
+ italic = '\x1b[3m'
6
+ underline = '\x1b[4m'
7
+ blink = '\x1b[5m'
8
+ inverse = '\x1b[7m'
9
+ hidden = '\x1b[8m'
10
+ strikethrough = '\x1b[9m'
11
+ black = '\x1b[30m'
12
+ red = '\x1b[31m'
13
+ redBright = '\x1b[91m'
14
+ green = '\x1b[32m'
15
+ greenBright = '\x1b[92m'
16
+ yellow = '\x1b[33m'
17
+ yellowBright = '\x1b[93m'
18
+ blue = '\x1b[34m'
19
+ blueBright = '\x1b[94m'
20
+ magenta = '\x1b[35m'
21
+ magentaBright = '\x1b[95m'
22
+ cyan = '\x1b[36m'
23
+ cyanBright = '\x1b[96m'
24
+ white = '\x1b[37m'
25
+ whiteBright = '\x1b[97m'
26
+ gray = '\x1b[90m'
27
+ bgBlack = '\x1b[40m'
28
+ bgRed = '\x1b[41m'
29
+ bgRedBright = '\x1b[101m'
30
+ bgGreen = '\x1b[42m'
31
+ bgGreenBright = '\x1b[102m'
32
+ bgYellow = '\x1b[43m'
33
+ bgYellowBright = '\x1b[103m'
34
+ bgBlue = '\x1b[44m'
35
+ bgBlueBright = '\x1b[104m'
36
+ bgMagenta = '\x1b[45m'
37
+ bgMagentaBright = '\x1b[105m'
38
+ bgCyan = '\x1b[46m'
39
+ bgCyanBright = '\x1b[106m'
40
+ bgWhite = '\x1b[47m'
41
+ bgWhiteBright = '\x1b[107m'
42
+ bgGray = '\x1b[100m'
43
+ bell = '\x07'
44
+
45
+ hexToRgb(hex) {
46
+ const sanitizedHex = hex.replace('#', '')
47
+ const red = parseInt(sanitizedHex.substring(0, 2), 16)
48
+ const green = parseInt(sanitizedHex.substring(2, 4), 16)
49
+ const blue = parseInt(sanitizedHex.substring(4, 6), 16)
50
+
51
+ return [red, green, blue]
52
+ }
53
+
54
+ terminalColorIndex(red, green, blue) {
55
+ return 16 +
56
+ Math.round(red / 255 * 5) * 36 +
57
+ Math.round(green / 255 * 5) * 6 +
58
+ Math.round(blue / 255 * 5)
59
+ }
60
+
61
+ color(hex) {
62
+ const [red, green, blue] = this.hexToRgb(hex)
63
+
64
+ return `\x1b[38;5;${this.terminalColorIndex(red, green, blue)}m`
65
+ }
66
+
67
+ background(hex) {
68
+ const [red, green, blue] = this.hexToRgb(hex)
69
+
70
+ return `\x1b[48;5;${this.terminalColorIndex(red, green, blue)}m`
71
+ }
72
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "poops",
3
3
  "description": "A super simple bundler for simple web projects.",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "license": "MIT",
6
6
  "main": "poops.js",
7
7
  "repository": "https://github.com/stamat/poops.git",
@@ -27,7 +27,9 @@
27
27
  "cssnano": "^6.0.1",
28
28
  "deepmerge": "^4.3.1",
29
29
  "esbuild": "^0.18.4",
30
+ "glob": "^10.3.1",
30
31
  "livereload": "^0.9.3",
32
+ "nunjucks": "^3.2.4",
31
33
  "postcss": "^8.4.24",
32
34
  "sass": "^1.63.4",
33
35
  "serve-static": "^1.15.0",
@@ -36,7 +38,7 @@
36
38
  "devDependencies": {
37
39
  "eslint": "^8.42.0",
38
40
  "eslint-config-standard": "^17.1.0",
39
- "eslint-plugin-import": "^2.27.5",
41
+ "eslint-plugin-import": "^2.26.0",
40
42
  "eslint-plugin-n": "^16.0.0",
41
43
  "eslint-plugin-promise": "^6.1.1",
42
44
  "sulphuris": "^1.0.5"