Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

symply

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

symply - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

assets/logo.png

4

index.js

@@ -5,6 +5,8 @@ const logger = require('./src/logger')

const commands = process.argv.splice(process.execArgv.length + 2)
logger.log(logo)
main().catch(err => {
main(commands).catch(err => {
logger.error('Generation finished with error: ', err)
})
{
"name": "symply",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "tape test/**/*.js"
},
"version": "0.0.2",
"description": "A dead-simple Bootstrap static site generator.",
"author": "Oleg Legun <oleg.legun@gmail.com>",
"homepage": "https://github.com/oleglegun/symply#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/oleglegun/static-site-templating-engine.git"
"url": "git+https://https://github.com/oleglegun/symply.git"
},
"author": "Oleg Legun <oleg.legun@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/oleglegun/static-site-templating-engine/issues"
"url": "https://github.com/oleglegun/symply/issues"
},
"homepage": "https://github.com/oleglegun/static-site-templating-engine#readme",
"license": "MIT",
"bin": {
"symply": "./bin/symply.js"
},
"preferGlobal": true,
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "tape test/**/*.js | tap-spec"
},
"dependencies": {
"fs-extra": "^8.1.0",
"handlebars": "^4.7.2",
"js-yaml": "^3.13.1"
"js-yaml": "^3.13.1",
"prettier": "^1.19.1"
},
"devDependencies": {
"tap-spec": "^5.0.0",
"tape": "^4.13.0"
}
}

@@ -1,22 +0,26 @@

<div align="center">
<img src="./symply-logo.jpg" width="50%"/>
</div>
![Logo](./assets/logo.png)
> A dead simple Bootstrap static site generator for personal sites, landing pages and other small projects, where you want to be in control of everything.
A dead-simple **Bootstrap static site generator** with great flexibility and control.
Main advantages:
- Minimum magic - maximum transparency
- Total control of the generation process
- Only few dependencies
## Quick Start
**Symply** is based on well-known fast and reliable [Handlebars.js](https://github.com/wycats/handlebars.js) templating engine.
### Partials
Great for personal sites, landing pages and other small projects where you **want to be in control of everything**.
partials/block.html
## Installation
```html
`npm -g install symply`
```
## Quick Start
source/index.html
```shell
symply init # generate file structure
```html
{{> block }}
symply generate
```
Coming soon...

@@ -14,7 +14,6 @@ const fs = require('fs')

const DEFAULT_CONFIGURATION = {
SOURCE_DIR_NAME: 'source',
TEMPLATE_DIR_NAME: 'templates',
VIEWS_DIR_NAME: 'views',
SOURCE_DIR_NAME: 'src',
DISTRIBUTION_DIR_NAME: 'dist',
PARTIALS_DIR_NAME: 'partials',
VIEWS_DIR_NAME: 'views',
}

@@ -27,16 +26,14 @@

{
name: HELPERS_FILE_NAME,
name: GLOBALS_FILE_NAME,
dir: '.',
contents: 'module.exports = {\n\t\n}'
contents: "module.exports = {\n\tsiteName: 'My new site',\n}",
},
{
name: GLOBALS_FILE_NAME,
name: HELPERS_FILE_NAME,
dir: '.',
contents: 'module.exports = {\n\t\n}'
}
contents: 'module.exports = {\n\tmyCustomHelper: (data) => { return data }\n}',
},
]
function getConfiguration(configurationFilename) {
function getConfiguration(configurationFilename) {
try {

@@ -57,4 +54,5 @@ const configuration = yaml.safeLoad(

logger.info(
`Configuration file (${configurationFilename}) is not found. Using default configuration:\n`,
JSON.stringify(DEFAULT_CONFIGURATION, null, 2)
`Configuration file (${configurationFilename}) is not found. Using default configuration:\n${getPrintableConfigurationRepresentation(
DEFAULT_CONFIGURATION
)}`
)

@@ -70,3 +68,6 @@ return DEFAULT_CONFIGURATION

logger.info(err.message)
logger.info(`Using default configuration:\n`, JSON.stringify(DEFAULT_CONFIGURATION, null, 2))
logger.info(
`Using default configuration:\n`,
getPrintableConfigurationRepresentation(DEFAULT_CONFIGURATION)
)
return DEFAULT_CONFIGURATION

@@ -97,5 +98,24 @@ } else {

/**
* @param {Object<string, any>} configObject
* @returns {string}
*/
function getPrintableConfigurationRepresentation(configObject) {
let result = ''
let paddingChars = ' '
Object.keys(configObject).forEach(key => {
const value = typeof configObject[key] === 'string' ? `'${configObject[key]}'` : configObject[key]
result += `${paddingChars}${key}: ${value}\n`
})
return result
}
module.exports = {
getConfiguration,
systemFilesToBeCreated
}
systemFilesToBeCreated,
GLOBALS_FILE_NAME,
HELPERS_FILE_NAME,
}

@@ -22,5 +22,5 @@ const fs = require('fs-extra')

if (removeScanPath) {
return scanFilesInDirectory(scanPath, '', readFileContents, scanNestedDirectories)
return scanFilesInDirectory(scanPath, scanPath, readFileContents, scanNestedDirectories)
}
return scanFilesInDirectory(scanPath, scanPath, readFileContents, scanNestedDirectories)
return scanFilesInDirectory(scanPath, '', readFileContents, scanNestedDirectories)
}

@@ -96,8 +96,15 @@

/**
*
* @param {string} directoryPath
*
* @returns {boolean} Returns true if the directory is created
*/
function createDirectoryIfNotExists(directoryPath) {
if (fs.existsSync(directoryPath)) {
return
return false
}
fs.mkdirSync(directoryPath)
return true
}

@@ -109,4 +116,4 @@

* @param {string} [contents]
*
* @returns {boolean} Returns true if file is created
*
* @returns {boolean} Returns true if the file is created
*/

@@ -118,2 +125,4 @@ function createFileIfNotExists(filePath, contents) {

fs.ensureFileSync(filePath)
fs.writeFileSync(filePath, contents, { encoding: 'utf8' })

@@ -123,2 +132,17 @@ return true

/**
* Joins path parts and returns an absolute path
* @param {string[]} pathParts
* @returns {string}
*/
function joinAndResolvePath(...pathParts) {
const joinedPath = path.join(...pathParts)
if (path.isAbsolute(joinedPath)) {
return joinedPath
} else {
return path.join(process.cwd(), joinedPath)
}
}
module.exports = {

@@ -132,2 +156,3 @@ scanFiles,

createFileIfNotExists,
joinAndResolvePath,
}
const fs = require('fs')
const path = require('path')
const prettier = require('prettier')
const Handlebars = require('handlebars')
const config = require('./config')
const logger = require('./logger')
const config = require('./config')
const strings = require('./strings')
const { loadPartials } = require('./partials')
const { loadViews } = require('./views')
const { loadTemplates } = require('./templates')
const strings = require('./strings')
const { scanFiles, isFileExtensionValid, getFileContents, createFileIfNotExists } = require('./fs-helpers')
const {
scanFiles,
isFileExtensionValid,
getFileContents,
createFileIfNotExists,
createDirectoryIfNotExists,
clearDirectoryContents,
copyFileAsync,
joinAndResolvePath,
} = require('./fs-helpers')
const Handlebars = require('handlebars')
const CONFIGURATION_FILE_NAME = 'configuration.yaml'
async function main(command) {
command = 'init'
switch (command) {
async function main(commands) {
switch (commands[0]) {
case 'init':

@@ -24,3 +31,3 @@ logger.info('Initializing project...')

case 'start':
generate()
await generate()
break

@@ -32,3 +39,3 @@ default:

function generate() {
async function generate() {
/*-----------------------------------------------------------------------------

@@ -41,3 +48,3 @@ * Load configuration

/*-----------------------------------------------------------------------------
* Register partials
* Load and register partials
*----------------------------------------------------------------------------*/

@@ -52,21 +59,25 @@

/*-----------------------------------------------------------------------------
* Load views
* Load views and globals
*----------------------------------------------------------------------------*/
const views = loadViews(configuration.VIEWS_DIR_NAME)
// console.log(views)
const globals = require(joinAndResolvePath(config.GLOBALS_FILE_NAME))
/*-----------------------------------------------------------------------------
* Register helpers
* Load and register helpers; Inject views
*----------------------------------------------------------------------------*/
if (fs.existsSync(configuration.HELPERS_FILE_NAME)) {
const helpersPath = path.join(process.cwd(), configuration.HELPERS_FILE_NAME)
if (fs.existsSync(config.HELPERS_FILE_NAME)) {
const helpersPath = joinAndResolvePath(config.HELPERS_FILE_NAME)
const helpers = require(helpersPath)
Object.keys(helpers).forEach(helperName => {
Handlebars.registerHelper(helperName, injectViewDataDecorator(helpers[helperName], views))
Handlebars.registerHelper(helperName, injectHelperContextDecorator(helpers[helperName], views, globals))
})
}
/*-----------------------------------------------------------------------------
* Scan source files, detect template files for processing
*----------------------------------------------------------------------------*/
const allSourceFiles = scanFiles(configuration.SOURCE_DIR_NAME, false, true, true)

@@ -82,11 +93,52 @@

/*-----------------------------------------------------------------------------
* Compile templates with passing globals
* Format HTML output
* Save results to the distribution directory
*----------------------------------------------------------------------------*/
clearDirectoryContents(joinAndResolvePath(configuration.DISTRIBUTION_DIR_NAME))
templateSourceFiles.forEach(file => {
const templateContents = getFileContents(path.join(file.dirname, file.name))
const result = Handlebars.compile(templateContents)({})
console.log(result)
const templateContents = getFileContents(
joinAndResolvePath(configuration.SOURCE_DIR_NAME, file.dirname, file.name)
)
let formattedHTML = ''
try {
const result = Handlebars.compile(templateContents)(globals)
formattedHTML = prettier.format(result, { parser: 'html' })
} catch (err) {
if (err instanceof RangeError) {
logger.error(
'Recursive partial structure detected. Check your partials and source files. ' +
'Make sure that partials are not calling each other using {{> partialName}}.'
)
} else {
logger.error(err)
}
process.exit(1)
}
createFileIfNotExists(
joinAndResolvePath(configuration.DISTRIBUTION_DIR_NAME, file.dirname, file.name),
formattedHTML
)
})
// copy other source files to the destination folder
//
/*-----------------------------------------------------------------------------
* Copy other source files to the distribution directory
*----------------------------------------------------------------------------*/
const copyPromises = []
otherSourceFiles.forEach(file => {
const srcFilePath = joinAndResolvePath(configuration.SOURCE_DIR_NAME, file.dirname, file.name)
const distFilePath = joinAndResolvePath(configuration.DISTRIBUTION_DIR_NAME, file.dirname, file.name)
copyPromises.push(copyFileAsync(srcFilePath, distFilePath))
})
await Promise.all(copyPromises)
logger.info('Generation successfully finished.')

@@ -116,12 +168,20 @@ }

.filter(key => key.endsWith('DIR_NAME'))
.forEach(dirName => {})
.forEach(dirNameKey => {
const dirName = configuration[dirNameKey]
const dirIsCreated = createDirectoryIfNotExists(dirName)
if (dirIsCreated) {
logger.info(`Created directory: ${dirName}/`)
}
})
}
function injectViewDataDecorator(helperFunction, views) {
return function(context) {
const viewName = context && context.hash && context.hash.view
function injectHelperContextDecorator(helperFunction, views, globals) {
return function(params) {
const viewName = params && params.hash && params.hash.view
if (viewName) {
return new Handlebars.SafeString(helperFunction(views[viewName]))
return new Handlebars.SafeString(helperFunction({ globals, view: views[viewName], params: params.hash }))
} else {
return new Handlebars.SafeString(helperFunction(context))
return new Handlebars.SafeString(helperFunction({ globals, params: params.hash }))
}

@@ -131,4 +191,2 @@ }

function registerHelpers() {}
module.exports = main
module.exports = {
logo: `
███████╗██╗ ██╗███╗ ███╗██████╗ ██╗ ██╗ ██╗
██╔════╝╚██╗ ██╔╝████╗ ████║██╔══██╗██║ ╚██╗ ██╔╝
███████╗ ╚████╔╝ ██╔████╔██║██████╔╝██║ ╚████╔╝
╚════██║ ╚██╔╝ ██║╚██╔╝██║██╔═══╝ ██║ ╚██╔╝
███████║ ██║ ██║ ╚═╝ ██║██║ ███████╗██║
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝
======= Bootstrap Static Site Generator =======
███████╗ ████████╗ ███╗ ███╗ ████████╗ ██╗ ████████╗
████/══╝ ╚██████╔╝ ████╗ ████║ ███╔═══██╗ ██║ ╚██████╔╝
███████╗ ╚████╔╝ █████╗ █████║ ████████╔╝ ██║ ╚████╔╝
╚═/████║ ╚██╔╝ ████████████║ ███╔════╝ ██║ ╚██╔╝
███████║ ██║ ████████████║ ███║ ███████╗██║
╚══════╝ ╚═╝ ╚═══════════╝ ╚══╝ ╚══════╝╚═╝
======= Bootstrap Static Site Generator =======
`,

@@ -16,9 +17,11 @@ help: `

symply init Initialize project, creating necessary files and directories
symply init Initialize project creating necessary files and directories
symply generate Complile and generate static site files
alias: symply start
symply generate Compile and generate static site files
alias: symply start
symply serve Start development server
symply configuration Print current generator configuration (default + configuration.yaml)
symply serve Start development server in distribution folder
`,
}
const test = require('tape')
const path = require('path')
const {scanFiles, isFileExtensionValid} = require('../src/fs-helpers')
const { scanFiles, isFileExtensionValid, joinAndResolvePath } = require('../src/fs-helpers')
test('––––––––––––––––––– fs-helpers.js tests ––––––––––––––––––––', function(t) {
t.test('isFileExtensionValid()', function(st) {
t.test('isFileExtensionValid(fileName, validExtensionsList)', function(st) {
const testCases = [

@@ -11,9 +11,9 @@ {

expected: true,
message: '',
message: 'correctly detect valid file extension',
},
{
input: ['filename.html', ['js', 'md']],
expected: false,
message: '',
message: 'correctly detect invalid file extension',
},

@@ -24,6 +24,34 @@ ]

testCases.forEach(({input, expected, message}) => {
testCases.forEach(({ input, expected, message }) => {
st.equal(isFileExtensionValid(...input), expected, message)
})
})
t.test('joinAndResolvePath(...pathParts)', function(st) {
const testCases = [
{
inputArgs: ['/path1', 'path2'],
expected: '/path1/path2',
message: 'correctly resolve absolute path',
},
{
inputArgs: ['path1', 'path2'],
expected: process.cwd() + '/path1/path2',
message: 'correctly resolve relative path',
},
{
inputArgs: ['path1', '.', 'path2', 'path3'],
expected: process.cwd() + '/path1/path2/path3',
message: 'correctly resolve relative path with dot character',
},
]
st.plan(testCases.length)
testCases.forEach(({ inputArgs, expected, message }) => {
st.equal(joinAndResolvePath(...inputArgs), expected, message)
})
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc