@tiveor/scg 0.1.5 → 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,7 +1,8 @@
1
- SCG a Random Library for Generators<br/>
2
- [![Build Status](https://img.shields.io/travis/mde/ejs/master.svg?style=flat)](https://travis-ci.org/mde/ejs)
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
7
8
 
@@ -9,48 +10,162 @@ SCG a Random Library for Generators<br/>
9
10
  npm install @tiveor/scg
10
11
  ```
11
12
 
12
- ## Basic usage
13
+ ## Quick Start
13
14
 
14
15
  ```javascript
15
- const { StringHelper } = require('@tiveor/scg');
16
- const replaced = StringHelper.replace('This is a {{test}}', '{{test}}', 'joke');
17
- // replaced = "This is a joke"
16
+ const {
17
+ StringHelper,
18
+ FileHelper,
19
+ CommandHelper,
20
+ ParamHelper,
21
+ TemplateBuilder,
22
+ TEMPLATE_HANDLERS
23
+ } = require('@tiveor/scg');
18
24
  ```
19
25
 
20
- ## TemplateBuilder usage
26
+ ## API Reference
27
+
28
+ ### TemplateBuilder
29
+
30
+ Unified interface to render templates with EJS, Handlebars, or Pug.
21
31
 
22
32
  ```javascript
23
- const { TemplateBuilder, TEMPLATE_HANDLERS } = require('@tiveor/scg');
24
-
25
- const ejsBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
26
- ejsBuilder
27
- .render('This is a <%= test %>', {
28
- test: 'joke'
29
- })
30
- .then((replaced) => {
31
- // replaced = "This is a joke"
32
- });
33
-
34
- const pugBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
35
- pugBuilder
36
- .render('This is a #{test}', {
37
- test: 'joke'
38
- })
39
- .then((replaced) => {
40
- // replaced = "This is a joke"
41
- });
42
-
43
- const handlebarsBuilder = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
44
- handlebarsBuilder
45
- .render('This is a {{test}}', {
46
- test: 'joke'
47
- })
48
- .then((replaced) => {
49
- // replaced = "This is a joke"
50
- });
51
- ```
52
-
53
- ## Example
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' });
40
+ ```
41
+
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
+
153
+ ```bash
154
+ node example/index.js
155
+ ```
156
+
157
+ ## Running Tests
158
+
54
159
  ```bash
55
- node examples/index.js
56
- ```
160
+ npm test
161
+ ```
162
+
163
+ ## Template Engine Documentation
164
+
165
+ - [EJS](https://ejs.co/#docs)
166
+ - [Pug](https://pugjs.org/api/getting-started.html)
167
+ - [Handlebars](https://handlebarsjs.com/guide/)
168
+
169
+ ## License
170
+
171
+ MIT - Alvaro Orellana - AlvaroTech.dev
package/example/index.js CHANGED
@@ -1,132 +1,180 @@
1
- const { StringHelper } = require("../src/string_helper");
2
- const { FileHelper } = require("../src/file_helper");
3
- const { CommandHelper } = require("../src/command_helper");
4
- const { ParamHelper } = require("../src/param_helper");
5
- const { TemplateBuilder, TEMPLATE_HANDLERS } = require("../src/template_builder");
1
+ const { StringHelper } = require('../src/string_helper');
2
+ const { FileHelper } = require('../src/file_helper');
3
+ const { CommandHelper } = require('../src/command_helper');
4
+ const { ParamHelper } = require('../src/param_helper');
5
+ const { TemplateBuilder } = require('../src/template_builder');
6
+ const TEMPLATE_HANDLERS = require('../src/template_handlers');
6
7
 
7
8
  const initTest = (title) => {
8
9
  console.log(`=================${title}=================`);
9
- }
10
+ };
10
11
 
11
12
  const endTest = () => {
12
- console.log("================================");
13
- }
13
+ console.log('================================');
14
+ };
14
15
 
15
16
  //Usage StringHelper
16
17
  const testStringHelper = () => {
17
- initTest("STRING HELPER");
18
- const replaced = StringHelper.replace("This is a {{test}}", "{{test}}", "joke");
18
+ initTest('STRING HELPER');
19
+ const replaced = StringHelper.replace(
20
+ 'This is a {{test}}',
21
+ '{{test}}',
22
+ 'joke'
23
+ );
19
24
  console.log(replaced);
20
25
  endTest();
21
- }
26
+ };
22
27
 
23
28
  //Usage FileHelper
24
29
  const testFileHelper = () => {
25
- initTest("FILE HELPER");
26
- const packageObject = FileHelper.convertJsonFileToObject("package.json");
30
+ initTest('FILE HELPER');
31
+ const packageObject = FileHelper.convertJsonFileToObject('package.json');
27
32
  console.log(JSON.stringify(packageObject));
28
33
  endTest();
29
- }
30
-
34
+ };
31
35
 
32
36
  //Usage ParamHelper
33
37
  const testParamHelper = () => {
34
- initTest("Param HELPER");
38
+ initTest('Param HELPER');
35
39
  ParamHelper.addCustomParam(`--config=123`);
36
40
  ParamHelper.addCustomParam(`--test="this is a test"`);
37
41
  const params = ParamHelper.getParams();
38
- console.log("params", params);
42
+ console.log('params', params);
39
43
  const config = ParamHelper.getCommandByIndex(2);
40
44
  const test = ParamHelper.getCommandByIndex(3);
41
- console.log("config", config);
42
- console.log("test", test);
45
+ console.log('config', config);
46
+ console.log('test', test);
43
47
  endTest();
44
- }
48
+ };
45
49
 
46
50
  //Usage CommandHelper
47
51
  const testCommandHelper = () => {
48
- initTest("Command HELPER");
49
- CommandHelper.runClean(".", "pwd").then((res) => {
52
+ initTest('Command HELPER');
53
+ CommandHelper.runClean('.', 'pwd').then((res) => {
50
54
  console.log(res);
51
55
  endTest();
52
56
  });
53
- }
57
+ };
54
58
 
55
59
  //Usage TemplateBuilder with EJS
56
60
  const testTemplateEJS = async () => {
57
- initTest("TemplateBuilder with EJS");
61
+ initTest('TemplateBuilder with EJS');
58
62
  const builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
59
- builder.renderFile("example/ejs/hello.ejs", { title: "Hello EJS world", body: "this is the body" }, {})
63
+ builder
64
+ .renderFile(
65
+ 'example/ejs/hello.ejs',
66
+ { title: 'Hello EJS world', body: 'this is the body' },
67
+ {}
68
+ )
60
69
  .then((html) => {
61
70
  console.log(html);
62
71
  endTest();
63
- })
64
-
65
- builder.renderFile("example/ejs/conditional.ejs", { isDark: true, text: "Hello Dark World" }, {})
72
+ });
73
+
74
+ builder
75
+ .renderFile(
76
+ 'example/ejs/conditional.ejs',
77
+ { isDark: true, text: 'Hello Dark World' },
78
+ {}
79
+ )
66
80
  .then((html) => {
67
81
  console.log(html);
68
82
  endTest();
69
- })
70
-
71
- builder.renderFile("example/ejs/conditional.ejs", { isDark: false, text: "Hello Light World" }, {})
83
+ });
84
+
85
+ builder
86
+ .renderFile(
87
+ 'example/ejs/conditional.ejs',
88
+ { isDark: false, text: 'Hello Light World' },
89
+ {}
90
+ )
72
91
  .then((html) => {
73
92
  console.log(html);
74
93
  endTest();
75
- })
76
-
77
- }
94
+ });
95
+ };
78
96
 
79
97
  //Usage TemplateBuilder with handlebars
80
98
  const testTemplateHandlebars = async () => {
81
- initTest("TemplateBuilder with handlebars");
99
+ initTest('TemplateBuilder with handlebars');
82
100
  const builder = new TemplateBuilder(TEMPLATE_HANDLERS.HANDLEBARS);
83
- builder.renderFile("example/handlebars/hello.handlebars", { title: "Hello handlebars world", body: "this is the body" }, {})
101
+ builder
102
+ .renderFile(
103
+ 'example/handlebars/hello.handlebars',
104
+ { title: 'Hello handlebars world', body: 'this is the body' },
105
+ {}
106
+ )
84
107
  .then((html) => {
85
108
  console.log(html);
86
109
  endTest();
87
- })
88
-
89
- builder.renderFile("example/handlebars/conditional.handlebars", { isDark: true, text: "Hello Dark World" }, {})
110
+ });
111
+
112
+ builder
113
+ .renderFile(
114
+ 'example/handlebars/conditional.handlebars',
115
+ { isDark: true, text: 'Hello Dark World' },
116
+ {}
117
+ )
90
118
  .then((html) => {
91
119
  console.log(html);
92
120
  endTest();
93
- })
94
-
95
- builder.renderFile("example/handlebars/conditional.handlebars", { isDark: false, text: "Hello Light World" }, {})
121
+ });
122
+
123
+ builder
124
+ .renderFile(
125
+ 'example/handlebars/conditional.handlebars',
126
+ { isDark: false, text: 'Hello Light World' },
127
+ {}
128
+ )
96
129
  .then((html) => {
97
130
  console.log(html);
98
131
  endTest();
99
- })
100
- }
132
+ });
133
+ };
101
134
 
102
135
  //Usage TemplateBuilder with pug
103
136
  const testTemplatePug = async () => {
104
- initTest("TemplateBuilder with pug");
137
+ initTest('TemplateBuilder with pug');
105
138
  const builder = new TemplateBuilder(TEMPLATE_HANDLERS.PUG);
106
- builder.renderFile("example/pug/hello.pug", { title: "Hello pug world", body: "this is the body" }, {})
139
+ builder
140
+ .renderFile(
141
+ 'example/pug/hello.pug',
142
+ { title: 'Hello pug world', body: 'this is the body' },
143
+ {}
144
+ )
107
145
  .then((html) => {
108
146
  console.log(html);
109
147
  endTest();
110
- })
111
-
112
- builder.renderFile("example/pug/conditional.pug", { isDark: true, text: "Hello Dark World" }, {})
148
+ });
149
+
150
+ builder
151
+ .renderFile(
152
+ 'example/pug/conditional.pug',
153
+ { isDark: true, text: 'Hello Dark World' },
154
+ {}
155
+ )
113
156
  .then((html) => {
114
157
  console.log(html);
115
158
  endTest();
116
- })
117
-
118
- builder.renderFile("example/pug/conditional.pug", { isDark: false, text: "Hello Light World" }, {})
159
+ });
160
+
161
+ builder
162
+ .renderFile(
163
+ 'example/pug/conditional.pug',
164
+ { isDark: false, text: 'Hello Light World' },
165
+ {}
166
+ )
119
167
  .then((html) => {
120
168
  console.log(html);
121
169
  endTest();
122
- })
123
- }
170
+ });
171
+ };
124
172
 
125
- console.log("\nSCG Examples\n");
173
+ console.log('\nSCG Examples\n');
126
174
  //testStringHelper();
127
175
  //testFileHelper();
128
176
  //testParamHelper();
129
177
  //testCommandHelper();
130
178
  //testTemplateEJS();
131
179
  //testTemplatePug();
132
- testTemplateHandlebars();
180
+ testTemplateHandlebars();
package/index.js CHANGED
@@ -1,13 +1,15 @@
1
- const { StringHelper } = require("./src/string_helper");
2
- const { FileHelper } = require("./src/file_helper");
3
- const { CommandHelper } = require("./src/command_helper");
4
- const { ParamHelper } = require("./src/param_helper");
5
- const { TemplateBuilder } = require("./src/template_builder");
1
+ const { StringHelper } = require('./src/string_helper');
2
+ const { FileHelper } = require('./src/file_helper');
3
+ const { CommandHelper } = require('./src/command_helper');
4
+ const { ParamHelper } = require('./src/param_helper');
5
+ const { TemplateBuilder } = require('./src/template_builder');
6
+ const TEMPLATE_HANDLERS = require('./src/template_handlers');
6
7
 
7
8
  module.exports = {
8
9
  StringHelper,
9
10
  FileHelper,
10
11
  CommandHelper,
11
12
  ParamHelper,
12
- TemplateBuilder
13
- };
13
+ TemplateBuilder,
14
+ TEMPLATE_HANDLERS
15
+ };
package/package.json CHANGED
@@ -1,11 +1,25 @@
1
1
  {
2
2
  "name": "@tiveor/scg",
3
- "version": "0.1.5",
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"
@@ -22,7 +36,7 @@
22
36
  },
23
37
  "dependencies": {
24
38
  "ejs": "^3.1.6",
25
- "handlebars": "^4.7.6",
26
- "pug": "^3.0.0"
39
+ "handlebars": "^4.7.7",
40
+ "pug": "^3.0.2"
27
41
  }
28
42
  }
@@ -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
  }
@@ -1,10 +1,9 @@
1
- const { HandlebarsHelper } = require("./handlebars_helper");
2
- const { EjsHelper } = require("./ejs_helper");
3
- const { PugHelper } = require("./pug_helper");
4
-
1
+ const { HandlebarsHelper } = require('./handlebars_helper');
2
+ const { EjsHelper } = require('./ejs_helper');
3
+ const { PugHelper } = require('./pug_helper');
4
+ const TEMPLATE_HANDLERS = require('./template_handlers');
5
5
 
6
6
  class TemplateBuilder {
7
-
8
7
  constructor(templateHandler) {
9
8
  this.templateHandler = templateHandler;
10
9
  }
@@ -16,7 +15,7 @@ class TemplateBuilder {
16
15
  case TEMPLATE_HANDLERS.EJS:
17
16
  return EjsHelper.render(source, data, options);
18
17
  case TEMPLATE_HANDLERS.PUG:
19
- return PugHelper.render(fileName, data, options);
18
+ return PugHelper.render(source, data, options);
20
19
  default:
21
20
  return HandlebarsHelper.render(source, data, options);
22
21
  }
@@ -34,14 +33,6 @@ class TemplateBuilder {
34
33
  return HandlebarsHelper.renderFile(fileName, data, options);
35
34
  }
36
35
  }
37
-
38
- }
39
-
40
- const TEMPLATE_HANDLERS = {
41
- HANDLEBARS: "HANDLEBARS",
42
- EJS: "EJS",
43
- PUG: "PUG",
44
36
  }
45
37
 
46
- exports.TEMPLATE_HANDLERS = TEMPLATE_HANDLERS;
47
- exports.TemplateBuilder = TemplateBuilder;
38
+ exports.TemplateBuilder = TemplateBuilder;
@@ -0,0 +1,7 @@
1
+ const TEMPLATE_HANDLERS = {
2
+ HANDLEBARS: 'HANDLEBARS',
3
+ EJS: 'EJS',
4
+ PUG: 'PUG'
5
+ };
6
+
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
- }