@tiveor/scg 0.1.6 → 0.2.0

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/.prettierrc CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "singleQuote": true,
3
3
  "printWidth": 80,
4
- "editor.formatOnSave": true,
5
4
  "proseWrap": "always",
6
5
  "tabWidth": 2,
7
- "requireConfig": false,
8
6
  "useTabs": false,
9
7
  "trailingComma": "none",
10
8
  "bracketSpacing": true,
11
- "jsxBracketSameLine": false,
12
9
  "semi": true
13
10
  }
package/README.md CHANGED
@@ -1,64 +1,171 @@
1
- SCG a Random Library for Generators<br/>
2
- [![Build Status](https://travis-ci.org/tiveor/scg.svg?branch=master)](https://travis-ci.org/tiveor/scg)
1
+ # SCG - Simple Code Generator
2
+
3
3
  [![npm version](https://badge.fury.io/js/%40tiveor%2Fscg.svg)](https://badge.fury.io/js/%40tiveor%2Fscg)
4
- =============================
4
+
5
+ A utility library for code generation and template processing in Node.js. Provides helpers for template rendering (EJS, Handlebars, Pug), string manipulation, file operations, command execution, and CLI parameter parsing.
5
6
 
6
7
  ## Installation
8
+
7
9
  ```bash
8
10
  npm install @tiveor/scg
9
11
  ```
10
12
 
11
- ## Basic usage
13
+ ## Quick Start
14
+
12
15
  ```javascript
13
- const { StringHelper } = require('@tiveor/scg');
14
- const replaced = StringHelper.replace('This is a {{test}}', '{{test}}', 'joke');
15
- // replaced = "This is a joke"
16
+ const {
17
+ StringHelper,
18
+ FileHelper,
19
+ CommandHelper,
20
+ ParamHelper,
21
+ TemplateBuilder,
22
+ TEMPLATE_HANDLERS
23
+ } = require('@tiveor/scg');
16
24
  ```
17
25
 
18
- ## TemplateBuilder usage
26
+ ## API Reference
27
+
28
+ ### TemplateBuilder
29
+
30
+ Unified interface to render templates with EJS, Handlebars, or Pug.
31
+
19
32
  ```javascript
20
- const { TemplateBuilder, TEMPLATE_HANDLERS } = require('@tiveor/scg');
21
-
22
- const ejsBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
23
- ejsBuilder
24
- .render('This is a <%= test %>', {
25
- test: 'joke'
26
- })
27
- .then((replaced) => {
28
- // replaced = "This is a joke"
29
- });
30
-
31
- const pugBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
32
- pugBuilder
33
- .render('This is a #{test}', {
34
- test: 'joke'
35
- })
36
- .then((replaced) => {
37
- // replaced = "This is a joke"
38
- });
39
-
40
- const handlebarsBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
41
- handlebarsBuilder
42
- .render('This is a {{test}}', {
43
- test: 'joke'
44
- })
45
- .then((replaced) => {
46
- // replaced = "This is a joke"
47
- });
33
+ const builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
34
+
35
+ // Render from string
36
+ const html = await builder.render('Hello <%= name %>', { name: 'World' });
37
+
38
+ // Render from file
39
+ const page = await builder.renderFile('template.ejs', { title: 'Home' });
48
40
  ```
49
41
 
50
- ## Example
42
+ Available handlers: `TEMPLATE_HANDLERS.EJS`, `TEMPLATE_HANDLERS.HANDLEBARS`, `TEMPLATE_HANDLERS.PUG`
43
+
44
+ #### Examples with each engine
45
+
46
+ ```javascript
47
+ // EJS
48
+ const ejs = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
49
+ await ejs.render('Hello <%= name %>', { name: 'World' });
50
+
51
+ // Handlebars
52
+ const hbs = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
53
+ await hbs.render('Hello {{name}}', { name: 'World' });
54
+
55
+ // Pug
56
+ const pug = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
57
+ await pug.render('p #{name}', { name: 'World' });
58
+ ```
59
+
60
+ ### StringHelper
61
+
62
+ Static methods for string manipulation.
63
+
64
+ ```javascript
65
+ // Replace all occurrences of a token (regex-safe)
66
+ StringHelper.replace('Hello {{name}}!', '{{name}}', 'World');
67
+ // => "Hello World!"
68
+
69
+ // Works safely with regex special characters
70
+ StringHelper.replace('Price: $10.00', '$10.00', '$20.00');
71
+ // => "Price: $20.00"
72
+
73
+ // Capitalize first character
74
+ StringHelper.capitalize('hello');
75
+ // => "Hello"
76
+
77
+ // Escape regex special characters
78
+ StringHelper.escapeRegex('$100.00 (test)');
79
+ // => "\\$100\\.00 \\(test\\)"
80
+ ```
81
+
82
+ ### FileHelper
83
+
84
+ Static methods for file system operations.
85
+
86
+ ```javascript
87
+ // Read file to string
88
+ const content = FileHelper.readFileToString('config.txt');
89
+
90
+ // Parse JSON file to object
91
+ const config = FileHelper.convertJsonFileToObject('config.json');
92
+
93
+ // Create/remove folders
94
+ FileHelper.createFolder('output/components');
95
+ FileHelper.removeFolder('output/temp');
96
+
97
+ // Remove file
98
+ FileHelper.removeFile('output/old.txt');
99
+
100
+ // Generate file from template with variable replacement
101
+ await FileHelper.createFileFromFile({
102
+ template: 'templates/component.txt',
103
+ newFile: 'output/Button.tsx',
104
+ variables: [
105
+ { token: '{{name}}', value: 'Button' },
106
+ { token: '{{style}}', value: 'primary' }
107
+ ]
108
+ });
109
+
110
+ // Generate string from template
111
+ const result = await FileHelper.createStringFromFile({
112
+ template: 'templates/component.txt',
113
+ variables: [
114
+ { token: '{{name}}', value: 'Button' }
115
+ ]
116
+ });
117
+ ```
118
+
119
+ ### CommandHelper
120
+
121
+ Execute shell commands as promises.
122
+
123
+ ```javascript
124
+ // Run a command
125
+ const output = await CommandHelper.run('.', 'ls -la');
126
+
127
+ // Chain multiple commands
128
+ const result = await CommandHelper.run('.', 'git add .', 'git status');
129
+
130
+ // Run and clean output (strips newlines)
131
+ const version = await CommandHelper.runClean('.', 'node --version');
132
+ ```
133
+
134
+ ### ParamHelper
135
+
136
+ Parse CLI parameters from `process.argv`.
137
+
138
+ ```javascript
139
+ // Add custom parameters
140
+ ParamHelper.addCustomParam('--env=production');
141
+
142
+ // Get parameter by index
143
+ const script = ParamHelper.getCommandByIndex(1);
144
+
145
+ // Parse all --key=value parameters
146
+ // Example: node script.js --name=Alice --port=3000
147
+ const params = ParamHelper.getParams();
148
+ // => { name: "Alice", port: "3000" }
149
+ ```
150
+
151
+ ## Running Examples
152
+
51
153
  ```bash
52
154
  node example/index.js
53
155
  ```
54
156
 
55
- For more information about templates visit the official documentation for each one:
157
+ ## Running Tests
158
+
159
+ ```bash
160
+ npm test
161
+ ```
162
+
163
+ ## Template Engine Documentation
56
164
 
57
- * EJS <br/>
58
- https://ejs.co/#docs
165
+ - [EJS](https://ejs.co/#docs)
166
+ - [Pug](https://pugjs.org/api/getting-started.html)
167
+ - [Handlebars](https://handlebarsjs.com/guide/)
59
168
 
60
- * PUG <br/>
61
- https://pugjs.org/api/getting-started.html
169
+ ## License
62
170
 
63
- * Handlebars <br>
64
- https://handlebarsjs.com/guide/
171
+ MIT - Alvaro Orellana - AlvaroTech.dev
package/package.json CHANGED
@@ -1,11 +1,25 @@
1
1
  {
2
2
  "name": "@tiveor/scg",
3
- "version": "0.1.6",
4
- "description": "SCG a Random Library for Generators",
3
+ "version": "0.2.0",
4
+ "description": "Simple Code Generator - A utility library for code generation and template processing",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "mocha ./test"
7
+ "test": "mocha ./test",
8
+ "example": "node example/index.js"
8
9
  },
10
+ "engines": {
11
+ "node": ">=14.0.0"
12
+ },
13
+ "keywords": [
14
+ "code-generator",
15
+ "template",
16
+ "scaffolding",
17
+ "ejs",
18
+ "handlebars",
19
+ "pug",
20
+ "file-helper",
21
+ "string-helper"
22
+ ],
9
23
  "repository": {
10
24
  "type": "git",
11
25
  "url": "git+https://github.com/tiveor/scg.git"
@@ -1,10 +1,16 @@
1
- const { exec } = require("child_process");
1
+ const { exec } = require('child_process');
2
2
 
3
3
  class CommandHelper {
4
4
  static run(directory, ...command) {
5
- return new Promise((ok, reject) => {
6
- const cmd = command.join(" && ");
7
- //console.log(cmd);
5
+ if (!directory) {
6
+ return Promise.reject(new Error('directory is required'));
7
+ }
8
+ if (command.length === 0) {
9
+ return Promise.reject(new Error('at least one command is required'));
10
+ }
11
+
12
+ return new Promise((resolve, reject) => {
13
+ const cmd = command.join(' && ');
8
14
  exec(
9
15
  cmd,
10
16
  { cwd: directory, maxBuffer: 1024 * 1024 * 100 },
@@ -15,26 +21,19 @@ class CommandHelper {
15
21
  }
16
22
 
17
23
  if (stderr) {
18
- ok(stderr);
24
+ resolve(stderr);
19
25
  return;
20
26
  }
21
27
 
22
- ok(stdout);
28
+ resolve(stdout);
23
29
  }
24
30
  );
25
- }).catch((error) => {
26
- console.log(error);
27
31
  });
28
32
  }
29
33
 
30
34
  static runClean(folder, ...command) {
31
- return new Promise((ok, reject) => {
32
- CommandHelper.run(folder, ...command)
33
- .then((cmdRes) => {
34
- const config = cmdRes && cmdRes.replace(/\r?\n|\r/g, "");
35
- ok(config);
36
- })
37
- .catch(reject);
35
+ return CommandHelper.run(folder, ...command).then((result) => {
36
+ return result && result.replace(/\r?\n|\r/g, '');
38
37
  });
39
38
  }
40
39
  }
@@ -1,7 +1,7 @@
1
- const fs = require("fs");
2
- const readline = require("readline");
3
- const { StringHelper } = require("./string_helper");
4
- const { CommandHelper } = require("./command_helper");
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const readline = require('readline');
4
+ const { StringHelper } = require('./string_helper');
5
5
 
6
6
  class FileHelper {
7
7
  static readFileToString(fileName) {
@@ -18,7 +18,7 @@ class FileHelper {
18
18
  }
19
19
 
20
20
  static async dynamicReplace(replacement) {
21
- let res = "";
21
+ let res = '';
22
22
  for (let v in replacement.variables) {
23
23
  const properties = replacement.variables[v];
24
24
  await FileHelper.readLineByLine(replacement.template, (line) => {
@@ -43,7 +43,7 @@ class FileHelper {
43
43
  await FileHelper.readLineByLine(template, async (line) => {
44
44
  let newLine = StringHelper.replace(
45
45
  line,
46
- "@date",
46
+ '@date',
47
47
  new Date().toUTCString()
48
48
  );
49
49
 
@@ -52,7 +52,6 @@ class FileHelper {
52
52
 
53
53
  if (newLine.indexOf(replacement.token) > 0) {
54
54
  if (replacement.template) {
55
- //dynamic since there is no value
56
55
  newLine = await FileHelper.dynamicReplace(replacement);
57
56
  break;
58
57
  } else if (replacement.value) {
@@ -67,12 +66,12 @@ class FileHelper {
67
66
  }
68
67
 
69
68
  static async createStringFromFile({ template, variables }) {
70
- let res = "";
69
+ let res = '';
71
70
 
72
71
  await FileHelper.readLineByLine(template, async (line) => {
73
72
  let newLine = StringHelper.replace(
74
73
  line,
75
- "@date",
74
+ '@date',
76
75
  new Date().toUTCString()
77
76
  );
78
77
 
@@ -81,7 +80,6 @@ class FileHelper {
81
80
 
82
81
  if (newLine.indexOf(replacement.token) > 0) {
83
82
  if (replacement.template) {
84
- //dynamic since there is no value
85
83
  newLine = await FileHelper.dynamicReplace(replacement);
86
84
  break;
87
85
  } else if (replacement.value) {
@@ -89,31 +87,27 @@ class FileHelper {
89
87
  }
90
88
  }
91
89
  }
92
- res += newLine + "\n";
90
+ res += newLine + '\n';
93
91
  });
94
92
  return res;
95
93
  }
96
94
 
97
- static async readLineByLine(fileName, newLine) {
95
+ static async readLineByLine(fileName, callback) {
98
96
  const fileStream = fs.createReadStream(fileName);
99
97
 
100
98
  const rl = readline.createInterface({
101
99
  input: fileStream,
102
- crlfDelay: Infinity,
100
+ crlfDelay: Infinity
103
101
  });
104
102
 
105
- let index = 0;
106
-
107
103
  for await (const line of rl) {
108
- index++;
109
- //console.log(index);
110
- await newLine(line);
104
+ await callback(line);
111
105
  }
112
106
  }
113
107
 
114
108
  static writer(filename) {
115
109
  return fs.createWriteStream(filename, {
116
- flags: "a",
110
+ flags: 'a'
117
111
  });
118
112
  }
119
113
 
@@ -122,20 +116,24 @@ class FileHelper {
122
116
  }
123
117
 
124
118
  static createFolder(folderName) {
125
- !fs.existsSync(`./${folderName}/`) &&
126
- fs.mkdirSync(`./${folderName}/`, { recursive: true });
119
+ const resolved = path.resolve(folderName);
120
+ if (!fs.existsSync(resolved)) {
121
+ fs.mkdirSync(resolved, { recursive: true });
122
+ }
127
123
  }
128
124
 
129
125
  static removeFolder(folderName) {
130
- return CommandHelper.runClean(
131
- ".",
132
- `rm -Rf '${folderName}'`);
126
+ const resolved = path.resolve(folderName);
127
+ if (fs.existsSync(resolved)) {
128
+ fs.rmSync(resolved, { recursive: true, force: true });
129
+ }
133
130
  }
134
131
 
135
132
  static removeFile(filename) {
136
- return CommandHelper.runClean(
137
- ".",
138
- `rm -f '${filename}'`);
133
+ const resolved = path.resolve(filename);
134
+ if (fs.existsSync(resolved)) {
135
+ fs.rmSync(resolved, { force: true });
136
+ }
139
137
  }
140
138
  }
141
139
 
@@ -1,10 +1,16 @@
1
1
  class StringHelper {
2
+ static escapeRegex(string) {
3
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4
+ }
5
+
2
6
  static replace(line, token, value) {
3
- return line.replace(new RegExp(token, "g"), value);
7
+ if (typeof line !== 'string') return '';
8
+ if (typeof token !== 'string') return line;
9
+ return line.replace(new RegExp(StringHelper.escapeRegex(token), 'g'), value);
4
10
  }
5
11
 
6
12
  static capitalize(s) {
7
- if (typeof s !== "string") return "";
13
+ if (typeof s !== 'string') return '';
8
14
  return s.charAt(0).toUpperCase() + s.slice(1);
9
15
  }
10
16
  }
@@ -15,7 +15,7 @@ class TemplateBuilder {
15
15
  case TEMPLATE_HANDLERS.EJS:
16
16
  return EjsHelper.render(source, data, options);
17
17
  case TEMPLATE_HANDLERS.PUG:
18
- return PugHelper.render(fileName, data, options);
18
+ return PugHelper.render(source, data, options);
19
19
  default:
20
20
  return HandlebarsHelper.render(source, data, options);
21
21
  }
@@ -4,4 +4,4 @@ const TEMPLATE_HANDLERS = {
4
4
  PUG: 'PUG'
5
5
  };
6
6
 
7
- exports.TEMPLATE_HANDLERS = TEMPLATE_HANDLERS;
7
+ module.exports = TEMPLATE_HANDLERS;
package/test/test.js CHANGED
@@ -1,11 +1,394 @@
1
1
  var assert = require('assert');
2
- const { StringHelper } = require("../src/string_helper");
2
+ var path = require('path');
3
+ var fs = require('fs');
4
+ var os = require('os');
3
5
 
4
- describe("StringHelper", () => {
5
- describe("replace", () => {
6
+ var { StringHelper } = require('../src/string_helper');
7
+ var { FileHelper } = require('../src/file_helper');
8
+ var { CommandHelper } = require('../src/command_helper');
9
+ var { ParamHelper } = require('../src/param_helper');
10
+ var { TemplateBuilder } = require('../src/template_builder');
11
+ var TEMPLATE_HANDLERS = require('../src/template_handlers');
12
+
13
+ // Helper to get absolute paths for example templates
14
+ var exampleDir = path.join(__dirname, '..', 'example');
15
+
16
+ describe('StringHelper', function () {
17
+ describe('replace', function () {
6
18
  it('should search and replace the test param', function () {
7
- const replaced = StringHelper.replace("This is a {{test}}", "{{test}}", "joke");
8
- assert.strictEqual(replaced, "This is a joke");
19
+ var replaced = StringHelper.replace(
20
+ 'This is a {{test}}',
21
+ '{{test}}',
22
+ 'joke'
23
+ );
24
+ assert.strictEqual(replaced, 'This is a joke');
25
+ });
26
+
27
+ it('should replace all occurrences', function () {
28
+ var replaced = StringHelper.replace(
29
+ '{{name}} likes {{name}}',
30
+ '{{name}}',
31
+ 'Alice'
32
+ );
33
+ assert.strictEqual(replaced, 'Alice likes Alice');
34
+ });
35
+
36
+ it('should handle tokens with regex special characters', function () {
37
+ var replaced = StringHelper.replace(
38
+ 'Price is $100.00 total',
39
+ '$100.00',
40
+ '$200.00'
41
+ );
42
+ assert.strictEqual(replaced, 'Price is $200.00 total');
43
+ });
44
+
45
+ it('should return empty string for non-string line', function () {
46
+ assert.strictEqual(StringHelper.replace(null, 'a', 'b'), '');
47
+ assert.strictEqual(StringHelper.replace(undefined, 'a', 'b'), '');
48
+ assert.strictEqual(StringHelper.replace(123, 'a', 'b'), '');
49
+ });
50
+
51
+ it('should return line unchanged for non-string token', function () {
52
+ assert.strictEqual(StringHelper.replace('hello', null, 'b'), 'hello');
53
+ });
54
+ });
55
+
56
+ describe('escapeRegex', function () {
57
+ it('should escape regex special characters', function () {
58
+ var escaped = StringHelper.escapeRegex('$100.00 (test)');
59
+ assert.strictEqual(escaped, '\\$100\\.00 \\(test\\)');
60
+ });
61
+ });
62
+
63
+ describe('capitalize', function () {
64
+ it('should capitalize first character', function () {
65
+ assert.strictEqual(StringHelper.capitalize('hello'), 'Hello');
66
+ });
67
+
68
+ it('should return empty string for non-string', function () {
69
+ assert.strictEqual(StringHelper.capitalize(123), '');
70
+ assert.strictEqual(StringHelper.capitalize(null), '');
71
+ });
72
+
73
+ it('should handle empty string', function () {
74
+ assert.strictEqual(StringHelper.capitalize(''), '');
75
+ });
76
+
77
+ it('should handle single character', function () {
78
+ assert.strictEqual(StringHelper.capitalize('a'), 'A');
79
+ });
80
+ });
81
+ });
82
+
83
+ describe('FileHelper', function () {
84
+ var tmpDir;
85
+
86
+ beforeEach(function () {
87
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'scg-test-'));
88
+ });
89
+
90
+ afterEach(function () {
91
+ fs.rmSync(tmpDir, { recursive: true, force: true });
92
+ });
93
+
94
+ describe('readFileToString', function () {
95
+ it('should read a file and return its content as string', function () {
96
+ var filePath = path.join(tmpDir, 'test.txt');
97
+ fs.writeFileSync(filePath, 'hello world');
98
+ var content = FileHelper.readFileToString(filePath);
99
+ assert.strictEqual(content, 'hello world');
100
+ });
101
+ });
102
+
103
+ describe('convertJsonFileToObject', function () {
104
+ it('should parse a JSON file to an object', function () {
105
+ var filePath = path.join(tmpDir, 'test.json');
106
+ fs.writeFileSync(filePath, '{"name": "scg", "version": 1}');
107
+ var obj = FileHelper.convertJsonFileToObject(filePath);
108
+ assert.strictEqual(obj.name, 'scg');
109
+ assert.strictEqual(obj.version, 1);
110
+ });
111
+ });
112
+
113
+ describe('createFolder', function () {
114
+ it('should create a folder', function () {
115
+ var folderPath = path.join(tmpDir, 'new-folder');
116
+ FileHelper.createFolder(folderPath);
117
+ assert.ok(fs.existsSync(folderPath));
118
+ });
119
+
120
+ it('should create nested folders', function () {
121
+ var folderPath = path.join(tmpDir, 'a', 'b', 'c');
122
+ FileHelper.createFolder(folderPath);
123
+ assert.ok(fs.existsSync(folderPath));
124
+ });
125
+
126
+ it('should not throw if folder already exists', function () {
127
+ var folderPath = path.join(tmpDir, 'existing');
128
+ fs.mkdirSync(folderPath);
129
+ assert.doesNotThrow(function () {
130
+ FileHelper.createFolder(folderPath);
131
+ });
9
132
  });
10
- })
11
- });
133
+ });
134
+
135
+ describe('removeFolder', function () {
136
+ it('should remove a folder', function () {
137
+ var folderPath = path.join(tmpDir, 'to-remove');
138
+ fs.mkdirSync(folderPath);
139
+ FileHelper.removeFolder(folderPath);
140
+ assert.ok(!fs.existsSync(folderPath));
141
+ });
142
+
143
+ it('should not throw if folder does not exist', function () {
144
+ assert.doesNotThrow(function () {
145
+ FileHelper.removeFolder(path.join(tmpDir, 'nonexistent'));
146
+ });
147
+ });
148
+ });
149
+
150
+ describe('removeFile', function () {
151
+ it('should remove a file', function () {
152
+ var filePath = path.join(tmpDir, 'to-remove.txt');
153
+ fs.writeFileSync(filePath, 'delete me');
154
+ FileHelper.removeFile(filePath);
155
+ assert.ok(!fs.existsSync(filePath));
156
+ });
157
+
158
+ it('should not throw if file does not exist', function () {
159
+ assert.doesNotThrow(function () {
160
+ FileHelper.removeFile(path.join(tmpDir, 'nonexistent.txt'));
161
+ });
162
+ });
163
+ });
164
+
165
+ describe('simpleReplace', function () {
166
+ it('should replace token with value', function () {
167
+ var result = FileHelper.simpleReplace('Hello {{name}}', {
168
+ token: '{{name}}',
169
+ value: 'World'
170
+ });
171
+ assert.strictEqual(result, 'Hello World');
172
+ });
173
+ });
174
+ });
175
+
176
+ describe('CommandHelper', function () {
177
+ describe('run', function () {
178
+ it('should execute a command and return stdout', function () {
179
+ return CommandHelper.run('.', 'echo hello').then(function (result) {
180
+ assert.strictEqual(result.trim(), 'hello');
181
+ });
182
+ });
183
+
184
+ it('should reject when directory is missing', function () {
185
+ return CommandHelper.run(null, 'echo hello').then(
186
+ function () {
187
+ assert.fail('should have rejected');
188
+ },
189
+ function (err) {
190
+ assert.ok(err.message.includes('directory is required'));
191
+ }
192
+ );
193
+ });
194
+
195
+ it('should reject when no command is given', function () {
196
+ return CommandHelper.run('.').then(
197
+ function () {
198
+ assert.fail('should have rejected');
199
+ },
200
+ function (err) {
201
+ assert.ok(err.message.includes('at least one command is required'));
202
+ }
203
+ );
204
+ });
205
+
206
+ it('should reject on invalid command', function () {
207
+ return CommandHelper.run('.', 'nonexistent_command_xyz').then(
208
+ function () {
209
+ assert.fail('should have rejected');
210
+ },
211
+ function (err) {
212
+ assert.ok(err);
213
+ }
214
+ );
215
+ });
216
+
217
+ it('should chain multiple commands', function () {
218
+ return CommandHelper.run('.', 'echo hello', 'echo world').then(
219
+ function (result) {
220
+ assert.ok(result.includes('hello'));
221
+ assert.ok(result.includes('world'));
222
+ }
223
+ );
224
+ });
225
+ });
226
+
227
+ describe('runClean', function () {
228
+ it('should return output without newlines', function () {
229
+ return CommandHelper.runClean('.', 'echo hello').then(function (result) {
230
+ assert.strictEqual(result, 'hello');
231
+ });
232
+ });
233
+ });
234
+ });
235
+
236
+ describe('ParamHelper', function () {
237
+ var originalArgv;
238
+
239
+ beforeEach(function () {
240
+ originalArgv = process.argv.slice();
241
+ });
242
+
243
+ afterEach(function () {
244
+ process.argv = originalArgv;
245
+ });
246
+
247
+ describe('addCustomParam', function () {
248
+ it('should add a parameter to process.argv', function () {
249
+ var before = process.argv.length;
250
+ ParamHelper.addCustomParam('--test=123');
251
+ assert.strictEqual(process.argv.length, before + 1);
252
+ assert.strictEqual(process.argv[process.argv.length - 1], '--test=123');
253
+ });
254
+ });
255
+
256
+ describe('getCommandByIndex', function () {
257
+ it('should return argv value at index', function () {
258
+ var result = ParamHelper.getCommandByIndex(0);
259
+ assert.strictEqual(result, process.argv[0]);
260
+ });
261
+
262
+ it('should return empty string for out-of-bounds index', function () {
263
+ var result = ParamHelper.getCommandByIndex(9999);
264
+ assert.strictEqual(result, '');
265
+ });
266
+ });
267
+
268
+ describe('getParams', function () {
269
+ it('should parse --key=value params', function () {
270
+ process.argv = ['node', 'test', '--name=Alice', '--age=30'];
271
+ var params = ParamHelper.getParams();
272
+ assert.strictEqual(params.name, 'Alice');
273
+ assert.strictEqual(params.age, '30');
274
+ });
275
+
276
+ it('should strip quotes from values', function () {
277
+ process.argv = ['node', 'test', '--name="Alice"', "--city='Paris'"];
278
+ var params = ParamHelper.getParams();
279
+ assert.strictEqual(params.name, 'Alice');
280
+ assert.strictEqual(params.city, 'Paris');
281
+ });
282
+
283
+ it('should return empty object when no params', function () {
284
+ process.argv = ['node', 'test'];
285
+ var params = ParamHelper.getParams();
286
+ assert.deepStrictEqual(params, {});
287
+ });
288
+ });
289
+ });
290
+
291
+ describe('TemplateBuilder', function () {
292
+ describe('render (from string)', function () {
293
+ it('should render EJS template from string', function () {
294
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
295
+ return builder
296
+ .render('Hello <%= name %>', { name: 'World' })
297
+ .then(function (result) {
298
+ assert.strictEqual(result, 'Hello World');
299
+ });
300
+ });
301
+
302
+ it('should render Handlebars template from string', function () {
303
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
304
+ return builder
305
+ .render('Hello {{name}}', { name: 'World' })
306
+ .then(function (result) {
307
+ assert.strictEqual(result, 'Hello World');
308
+ });
309
+ });
310
+
311
+ it('should render Pug template from string', function () {
312
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
313
+ return builder
314
+ .render('p #{name}', { name: 'World' })
315
+ .then(function (result) {
316
+ assert.strictEqual(result, '<p>World</p>');
317
+ });
318
+ });
319
+
320
+ it('should default to Handlebars for unknown handler', function () {
321
+ var builder = new TemplateBuilder('UNKNOWN');
322
+ return builder
323
+ .render('Hello {{name}}', { name: 'World' })
324
+ .then(function (result) {
325
+ assert.strictEqual(result, 'Hello World');
326
+ });
327
+ });
328
+ });
329
+
330
+ describe('renderFile', function () {
331
+ it('should render EJS template from file', function () {
332
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
333
+ return builder
334
+ .renderFile(
335
+ path.join(exampleDir, 'ejs', 'hello.ejs'),
336
+ { title: 'Test', body: 'Body' },
337
+ {}
338
+ )
339
+ .then(function (result) {
340
+ assert.ok(result.includes('Test'));
341
+ assert.ok(result.includes('Body'));
342
+ });
343
+ });
344
+
345
+ it('should render Handlebars template from file', function () {
346
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
347
+ return builder
348
+ .renderFile(
349
+ path.join(exampleDir, 'handlebars', 'hello.handlebars'),
350
+ { title: 'Test', body: 'Body' },
351
+ {}
352
+ )
353
+ .then(function (result) {
354
+ assert.ok(result.includes('Test'));
355
+ assert.ok(result.includes('Body'));
356
+ });
357
+ });
358
+
359
+ it('should render Pug template from file', function () {
360
+ var builder = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
361
+ return builder
362
+ .renderFile(
363
+ path.join(exampleDir, 'pug', 'hello.pug'),
364
+ { title: 'Test', body: 'Body' },
365
+ {}
366
+ )
367
+ .then(function (result) {
368
+ assert.ok(result.includes('Test'));
369
+ assert.ok(result.includes('Body'));
370
+ });
371
+ });
372
+ });
373
+ });
374
+
375
+ describe('TEMPLATE_HANDLERS', function () {
376
+ it('should export HANDLEBARS, EJS, and PUG', function () {
377
+ assert.strictEqual(TEMPLATE_HANDLERS.HANDLEBARS, 'HANDLEBARS');
378
+ assert.strictEqual(TEMPLATE_HANDLERS.EJS, 'EJS');
379
+ assert.strictEqual(TEMPLATE_HANDLERS.PUG, 'PUG');
380
+ });
381
+ });
382
+
383
+ describe('index (main exports)', function () {
384
+ var scg = require('../index');
385
+
386
+ it('should export all modules', function () {
387
+ assert.ok(scg.StringHelper);
388
+ assert.ok(scg.FileHelper);
389
+ assert.ok(scg.CommandHelper);
390
+ assert.ok(scg.ParamHelper);
391
+ assert.ok(scg.TemplateBuilder);
392
+ assert.ok(scg.TEMPLATE_HANDLERS);
393
+ });
394
+ });
@@ -1,5 +0,0 @@
1
- {
2
- "emmet.includeLanguages": {
3
- "ejs": "html"
4
- }
5
- }