UNPKG

10.2 kBJavaScriptView Raw
1#! /usr/bin/env node
2
3// MIT License
4//
5// Copyright 2016-2020 Electric Imp
6//
7// SPDX-License-Identifier: MIT
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be
17// included in all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
22// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
23// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25// OTHER DEALINGS IN THE SOFTWARE.
26
27/**
28 * Basic CLI for testing
29 */
30
31'use strict';
32
33const path = require('path');
34const Builder = require('./index');
35const packageJson = require('../package.json');
36
37/**
38 * Blackhole logger
39 */
40class NullLogger {
41 debug() {
42 }
43
44 info() {
45 }
46
47 warning() {
48 }
49
50 error() {
51 }
52}
53
54/**
55 * Print usage info
56 */
57function usageInfo() {
58 // print usage info
59 console.log(
60 `
61\u001b[36m${packageJson.name} v${packageJson.version} CLI\u001b[39m
62
63usage:\n\t\u001b[34m${Object.getOwnPropertyNames((packageJson.bin))[0]} [-l] [-D<variable> <value>]
64\t\t[--github-token <token>] [--azure-user <username> --azure-token <token>]
65\t\t[--bitbucket-server-addr <address>] [--bitbucket-server-user <username> --bitbucket-server-token <token>]
66\t\t[--lib <path_to_file>] [--use-remote-relative-includes] [--suppress-duplicate-includes-warning]
67\t\t[--cache] [--clear-cache] [--cache-exclude-list <path_to_file>]
68\t\t[--save-dependencies [<path_to_file>]] [--use-dependencies [<path_to_file>]]
69\t\t[--save-directives [<path_to_file>]] [--use-directives [<path_to_file>]] <input_file>\u001b[39m
70
71where:
72\t\u001b[34m-l\u001b[39m - generates line control statements
73\t\u001b[34m-D<varname> <value>\u001b[39m - defines a variable
74\t\u001b[34m--github-token <token>\u001b[39m - a GitHub personal access token
75\t\u001b[34m--azure-user <username>\u001b[39m - an Azure Repos username
76\t\u001b[34m--azure-token <token>\u001b[39m - an Azure Repos personal access token
77\t\u001b[34m--bitbucket-server-addr <address>\u001b[39m - a Bitbucket Server address
78\t\u001b[34m--bitbucket-server-user <username>\u001b[39m - a Bitbucket Server username
79\t\u001b[34m--bitbucket-server-token <token>\u001b[39m - a Bitbucket Server personal access token or password
80\t\u001b[34m--lib <path_to_file>\u001b[39m - include the specified JavaScript file(s) as a library
81\t\u001b[34m--use-remote-relative-includes\u001b[39m - interpret every local include as relative to the location of the source file where it is mentioned
82\t\u001b[34m--suppress-duplicate-includes-warning\u001b[39m - do not show a warning if a source file with the same content was included multiple times
83\t\u001b[34m--cache\u001b[39m - turn on caching for all files included from remote resources
84\t\u001b[34m--clear-cache\u001b[39m - clear the cache before Builder starts running
85\t\u001b[34m--cache-exclude-list <path_to_file>\u001b[39m - set the path to the file that lists resources which should not be cached
86\t\u001b[34m--save-dependencies [path_to_file]\u001b[39m - save references to the required GitHub files in the specified file
87\t\u001b[34m--use-dependencies [path_to_file]\u001b[39m - use the specified file to set which GitHub files are required
88\t\u001b[34m--save-directives [path_to_file]\u001b[39m - save Builder variable definitions in the specified file
89\t\u001b[34m--use-directives [path_to_file]\u001b[39m - use Builder variable definitions from the specified file
90\t\u001b[34m<input_file>\u001b[39m — is the path to source file which should be preprocessed
91 `.trim());
92}
93
94const dependenciesDefaultFileName = 'dependencies.json';
95const directivesDefaultFileName = 'directives.json';
96
97/**
98 * Get CLI option value
99 * @param {String} value CLI value
100 * @param {String} defaultValue, will be uses if CLI the option value was not provided
101 * @return {String}
102 */
103function getOption(args, defaultValue) {
104 if (args.length == 1 || args[0][0] === '-') {
105 return defaultValue;
106 }
107
108 return args.shift();
109}
110
111/**
112 * Read args
113 * @return {{defines: {}, lineControl: boolean, input: string, ghToken: string, cache: boolean, clean: boolean, excludeFile: string}
114 */
115function readArgs() {
116 let m;
117 const res = {
118 defines: {},
119 cache: false,
120 lineControl: false,
121 input: null,
122 ghToken: '',
123 ar: {user: null, token: null},
124 bbSrv: {addr: null, user: null, token: null},
125 clean : false,
126 excludeFile : '',
127 cacheFolder: '',
128 libs: [],
129 suppressDupWarning: false,
130 };
131 const args = process.argv.splice(2);
132
133 while (args.length > 0) {
134 const argument = args.shift();
135
136 if ('-l' === argument) {
137 res.lineControl = true;
138 } else if ('--cache' === argument || '-c' === argument) {
139 res.cache = true;
140 } else if ('--clear-cache' === argument) {
141 res.clean = true;
142 } else if (m = argument.match(/^-D(.+)$/)) {
143 res.defines[m[1]] = args.length ? args.shift() : null;
144 } else if (argument === '--azure-user') {
145 if (!args.length) {
146 throw Error('Expected argument value after ' + argument);
147 }
148 res.ar.user = args.shift();
149 } else if (argument === '--cache-exclude-list') {
150 if (!args.length) {
151 throw Error('Expected filename after ' + argument);
152 }
153 res.excludeFile = args.shift();
154 } else if (argument === '--github-token') {
155 if (!args.length) {
156 throw Error('Expected argument value after ' + argument);
157 }
158 res.ghToken = args.shift();
159 } else if (argument === '--azure-token') {
160 if (!args.length) {
161 throw Error('Expected argument value after ' + argument);
162 }
163 res.ar.token = args.shift();
164 } else if (argument === '--bitbucket-server-addr') {
165 if (!args.length) {
166 throw Error('Expected argument value after ' + argument);
167 }
168 res.bbSrv.addr = args.shift();
169 } else if (argument === '--bitbucket-server-user') {
170 if (!args.length) {
171 throw Error('Expected argument value after ' + argument);
172 }
173 res.bbSrv.user = args.shift();
174 } else if (argument === '--bitbucket-server-token') {
175 if (!args.length) {
176 throw Error('Expected argument value after ' + argument);
177 }
178 res.bbSrv.token = args.shift();
179 } else if (argument === '--lib' || argument === '--libs') {
180 if (!args.length) {
181 throw Error('Expected argument value after ' + argument);
182 }
183 res.libs.push(args.shift());
184 } else if ('--save-dependencies' === argument) {
185 if (!args.length) {
186 throw Error('Expected argument value after ' + argument);
187 }
188 res.dependenciesSaveFile = getOption(args, dependenciesDefaultFileName);
189 } else if ('--save-directives' === argument) {
190 if (!args.length) {
191 throw Error('Expected argument value after ' + argument);
192 }
193 res.directivesSaveFile = getOption(args, directivesDefaultFileName);
194 } else if ('--use-remote-relative-includes' === argument) {
195 res.remoteRelativeIncludes = true;
196 } else if ('--suppress-duplicate-includes-warning' === argument || '--suppress-duplicate' === argument) {
197 res.suppressDupWarning = true;
198 } else if ('--use-dependencies' === argument) {
199 if (!args.length) {
200 throw Error('Expected argument value after ' + argument);
201 }
202 res.dependenciesUseFile = getOption(args, dependenciesDefaultFileName);
203 } else if ('--use-directives' === argument) {
204 if (!args.length) {
205 throw Error('Expected argument value after ' + argument);
206 }
207 res.directivesUseFile = getOption(args, directivesDefaultFileName);
208 } else {
209 res.input = argument;
210 }
211 }
212
213 return res;
214}
215
216try {
217 // read args
218 const args = readArgs();
219
220 if (!args.input) {
221 usageInfo();
222 process.exit(1);
223 }
224
225 // create builder
226 const builder = new Builder({ libs: args.libs });
227 builder.machine.generateLineControlStatements = args.lineControl;
228 builder.machine.useCache = args.cache;
229 builder.logger = new NullLogger();
230 if (args.clean) {
231 builder.machine.clearCache();
232 }
233
234 // set the directory of the input file as first search dir
235 builder.machine.readers.file.inputFileDir = path.dirname(path.resolve(args.input));
236
237 // set GH credentials
238 builder.machine.readers.github.token = args.ghToken;
239 // set Azure Repos credentials
240 builder.machine.readers.azureRepos.username = args.ar.user;
241 builder.machine.readers.azureRepos.token = args.ar.token;
242 // set BB-Server addr and credentials
243 builder.machine.readers.bitbucketSrv.serverAddr = args.bbSrv.addr;
244 builder.machine.readers.bitbucketSrv.username = args.bbSrv.user;
245 builder.machine.readers.bitbucketSrv.token = args.bbSrv.token;
246 //set cache settings
247 builder.machine.excludeList = args.excludeFile;
248 // set remote relative includes
249 builder.machine.remoteRelativeIncludes = args.remoteRelativeIncludes;
250 // set supress dupicate includes warning
251 builder.machine.suppressDupWarning = args.suppressDupWarning;
252 // use dependencies
253 builder.machine.dependenciesSaveFile = args.dependenciesSaveFile;
254 builder.machine.dependenciesUseFile = args.dependenciesUseFile;
255 // use directives
256 builder.machine.directivesSaveFile = args.directivesSaveFile;
257 builder.machine.directivesUseFile = args.directivesUseFile;
258
259 // go
260 const res = builder.machine.execute(`@include "${args.input.replace(/\"/g, `'`)}"`, args.defines);
261 process.stdout.write(res);
262
263} catch (e) {
264 console.error('\u001b[31m' + (e.message || e) + '\u001b[39m');
265 process.exit(1);
266}