|
2 | 2 | const fs = require('fs'); |
3 | 3 | const {program} = require('commander'); |
4 | 4 |
|
| 5 | + |
| 6 | +/* |
| 7 | +|-------------------------------------------------------------------------- |
| 8 | +| Settings |
| 9 | +|-------------------------------------------------------------------------- |
| 10 | +*/ |
| 11 | + |
5 | 12 | program |
6 | 13 | .version(require('../package').version) |
7 | 14 | .description(require('../package').description + '\n\nUSAGE: csshtml-module -i [inputFile] -o [outputFile]') |
8 | | - .requiredOption('-i, --input <file>', 'input file to convert (required)') |
| 15 | + .option('-i, --input <file>', 'input file to convert (will be ignored if --template is set)') |
9 | 16 | .requiredOption('-o, --output <file>', 'destination file. Should end with .ts or .js (required)') |
10 | | - .option('-n, --name <string>', 'the name of the JS constant') |
| 17 | + .option(' --template', 'compile to a web component template containing css and html. The --input should be added without .html and .css extension') |
11 | 18 | .option('-d, --delay <int>', 'the time, in milliseconds, that the script should wait before compiling') |
12 | | - .option('-l, --language <string>', 'typehint the language - to help IDE\'s understand the content' ) |
| 19 | + .option('-n, --name <string>', 'the name of the JS constant (will be ignored if --template is set)') |
| 20 | + .option('--html <string>', 'html file to use in template') |
| 21 | + .option('--css <string>', 'css file to use in template ') |
13 | 22 | .parse(process.argv); |
14 | 23 |
|
15 | 24 |
|
| 25 | +const settings = { |
| 26 | + input: program.getOptionValue('input'), |
| 27 | + output: program.getOptionValue('output'), |
| 28 | + name: program.getOptionValue('name') || 'content', |
| 29 | + typescript: program.getOptionValue('output').endsWith('.ts'), |
| 30 | + delay: program.getOptionValue('delay') ? parseInt(program.getOptionValue('delay')) : 5, |
| 31 | + isTemplate: !!program.getOptionValue('template'), |
| 32 | + html: program.getOptionValue('html'), |
| 33 | + css: program.getOptionValue('css') |
| 34 | +}; |
| 35 | + |
| 36 | + |
| 37 | +/** |
| 38 | + * Check if file exists and is readable |
| 39 | + * |
| 40 | + * @param filepath |
| 41 | + * @returns {boolean} |
| 42 | + */ |
| 43 | +function fileExists(filepath) { |
| 44 | + let flag = true; |
| 45 | + try { |
| 46 | + fs.accessSync(filepath, fs.constants.F_OK); |
| 47 | + } catch (e) { |
| 48 | + flag = false; |
| 49 | + } |
| 50 | + try { |
| 51 | + fs.accessSync(filepath, fs.constants.R_OK); |
| 52 | + } catch (e) { |
| 53 | + flag = false; |
| 54 | + } |
| 55 | + return flag; |
| 56 | +} |
| 57 | + |
| 58 | + |
| 59 | +/* |
| 60 | +|-------------------------------------------------------------------------- |
| 61 | +| Validate input |
| 62 | +|-------------------------------------------------------------------------- |
| 63 | +*/ |
| 64 | + |
| 65 | +/** Validate output */ |
| 66 | +if (!settings.output.endsWith('.ts') && !settings.output.endsWith('.js')) { |
| 67 | + throw new Error('Output file must end with .ts or .js'); |
| 68 | +} |
| 69 | + |
| 70 | +/** Make sure input file is defined if not --template is specified */ |
| 71 | +if (!settings.isTemplate && !settings.input) { |
| 72 | + throw new Error('Either --input or --template must be specified'); |
| 73 | +} |
| 74 | + |
| 75 | +/** Make sure input file exists if not --template is specified */ |
| 76 | +if (!settings.isTemplate && !fileExists(settings.input)) { |
| 77 | + throw new Error(`${settings.input} file does not exist or is not readable`); |
| 78 | +} |
| 79 | + |
| 80 | +if (settings.isTemplate) { |
| 81 | + /** Make sure either --css or --html is specified if --template is specified */ |
| 82 | + if (!settings.css && !settings.html) { |
| 83 | + throw new Error(`Either a --css or --html file must be specified when using --template`); |
| 84 | + } |
| 85 | + |
| 86 | + /** Make sure either --css or --html exists if --template is specified */ |
| 87 | + if ((settings.css && !fileExists(settings.css)) && (settings.html && !fileExists(settings.html))) { |
| 88 | + throw new Error(`Either a --css or --html file does not exist or is not readable`); |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | + |
| 93 | +/* |
| 94 | +|-------------------------------------------------------------------------- |
| 95 | +| Generate output |
| 96 | +|-------------------------------------------------------------------------- |
| 97 | +*/ |
| 98 | + |
16 | 99 | /** |
17 | 100 | * Get file content |
18 | 101 | * @param {string} file |
19 | 102 | * @returns {string} |
20 | 103 | */ |
21 | 104 | function fileContent(file) { |
22 | | - return fs.readFileSync(file, 'utf-8'); |
| 105 | + if (!fileExists(file)) return ''; |
| 106 | + return fs.readFileSync(file, 'utf-8').trim(); |
23 | 107 | } |
24 | 108 |
|
25 | 109 | /** |
26 | | - * Create js/ts module content |
27 | | - * @param {{inputFile: string, outputFile: string, language: (any|string), type: string}} s |
28 | | - * @param {string} content |
| 110 | + * Create js/ts module with single type |
| 111 | + * @param s |
29 | 112 | * @returns {string} |
30 | 113 | */ |
31 | | -function template(s, content) { |
32 | | - let temp = ''; |
33 | | - if (s.language) temp += `// language=${s.language}\r\n`; |
34 | | - if (s.type === 'ts') { |
35 | | - temp += `export const ${s.name}: string = \`${content}\`;`; |
36 | | - } else { |
37 | | - temp += `export const ${s.name} = \`${content}\`;`; |
38 | | - } |
39 | | - return temp; |
| 114 | +function single(s) { |
| 115 | + let lang = s.input.split('.').pop(); |
| 116 | + if (s.typescript) return `// language=${lang}\nexport const ${s.name}: string = \`${fileContent(s.input)}\`;`; |
| 117 | + return `// language=${lang}\nexport const ${s.name} = \`${fileContent(s.input)}\`;`; |
40 | 118 | } |
41 | 119 |
|
| 120 | + |
42 | 121 | /** |
43 | | - * Convert settings and content to output file |
44 | | - * |
45 | | - * @param {{inputFile: string, outputFile: string, language: (any|string), type: string}} s |
| 122 | + * Create js/ts module with template |
| 123 | + * @param s |
| 124 | + * @returns {string} |
46 | 125 | */ |
47 | | -function convert(s) { |
48 | | - const content = fileContent(s.inputFile); |
49 | | - fs.writeFile(s.outputFile, template(s, content), (err) => { |
50 | | - if (err) { |
51 | | - console.error(err); |
52 | | - return; |
53 | | - } |
54 | | - console.log(`Converted file complete: ${s.outputFile}`); |
55 | | - }); |
| 126 | +function template(s) { |
| 127 | + const content = `<style>${fileContent(s.css)}</style>${fileContent(s.html)}`.replace('<style></style>', ''); |
| 128 | + if (s.typescript) return `export const template: HTMLTemplateElement = document.createElement('template');\ntemplate.innerHTML = \`${content}\`;`; |
| 129 | + return `export const template = document.createElement('template');\ntemplate.innerHTML =\`${content}\`;`; |
56 | 130 | } |
57 | 131 |
|
| 132 | + |
58 | 133 | /** |
59 | | - * Settings default |
60 | | - * |
61 | | - * @type {{inputFile: string, outputFile: string, delay: (any|number), language: string, type: string}} |
| 134 | + * Create js/ts module content |
62 | 135 | */ |
63 | | -const settings = { |
64 | | - inputFile: program.getOptionValue('input'), |
65 | | - outputFile: program.getOptionValue('output'), |
66 | | - language: program.getOptionValue('language'), |
67 | | - name: program.getOptionValue('name') || 'css', |
68 | | - type: program.getOptionValue('output').endsWith('.ts') ? 'ts' : 'js', |
69 | | - delay: program.getOptionValue('delay') || 5 |
70 | | -}; |
71 | | - |
72 | | -setTimeout(() => convert(settings), settings.delay); |
| 136 | +setTimeout(() => { |
| 137 | + fs.writeFile(settings.output, settings.isTemplate ? template(settings) : single(settings), (err) => { |
| 138 | + if (err) throw err; |
| 139 | + console.log(`Converted file complete: ${settings.output}`); |
| 140 | + }); |
| 141 | +}, settings.delay); |
0 commit comments