1 | import readdirRecursive from 'fs-readdir-recursive'
|
2 | import chalk from 'chalk'
|
3 | import path from 'path'
|
4 | import fs from 'fs'
|
5 |
|
6 | import { transformFile, errorTypes, formatFromAST } from '@elodin/core'
|
7 | import { logSyntaxError } from './error'
|
8 |
|
9 | export function chmod(src, dest) {
|
10 | fs.chmodSync(dest, fs.statSync(src).mode)
|
11 | }
|
12 |
|
13 | export function readdir(dirname, includeDotfiles, filter) {
|
14 | return readdirRecursive(dirname, (filename, _index, currentDirectory) => {
|
15 | const stat = fs.statSync(path.join(currentDirectory, filename))
|
16 |
|
17 | if (stat.isDirectory()) return true
|
18 |
|
19 | return (
|
20 | (includeDotfiles || filename[0] !== '.') && (!filter || filter(filename))
|
21 | )
|
22 | })
|
23 | }
|
24 |
|
25 | export function readdirForCompilable(dirname, includeDotfiles) {
|
26 | return readdir(dirname, includeDotfiles, isCompilableExtension)
|
27 | }
|
28 |
|
29 | export function isCompilableExtension(filename) {
|
30 | return path.extname(filename) === '.elo'
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | export function compile(filename, opts) {
|
49 | const log = errors =>
|
50 | errors.forEach(error => {
|
51 | const count = ++opts.errorCount
|
52 |
|
53 | if (error.type === errorTypes.INVALID_PROPERTY) {
|
54 | const { property, value, path, line, format, hint } = error
|
55 |
|
56 | const didYouMeanMessage = hint
|
57 | ? `
|
58 |
|
59 | Did you mean: ${hint}?
|
60 | `
|
61 | : ''
|
62 |
|
63 | logSyntaxError({
|
64 | count,
|
65 | path,
|
66 | lineNumber: line,
|
67 | line: chalk`{red ${property}}: ${formatFromAST(value)}`,
|
68 | message: chalk`The property {bold ${property}} is not a valid ${format} property.${didYouMeanMessage}
|
69 | {dim Check {underline https://elodin.dev/docs/language/styles#${format}} for a list of available properties.}`,
|
70 | })
|
71 | } else if (error.type === errorTypes.INVALID_VALUE) {
|
72 | const { property, value, path, line, format } = error
|
73 |
|
74 | logSyntaxError({
|
75 | count,
|
76 | path,
|
77 | lineNumber: line,
|
78 | line: chalk`${property}: {red ${formatFromAST(value)}}`,
|
79 | message: chalk`The property ${property} does not accept the value {bold ${formatFromAST(
|
80 | value
|
81 | )}}.
|
82 | {dim Check {underline https://elodin.dev/docs/language/styles#${format}} for a list of available values.}`,
|
83 | })
|
84 | } else {
|
85 | const { line, path, message, source, token } = error
|
86 |
|
87 | const lineCode = source
|
88 | ? source
|
89 | .substr(0, token.end)
|
90 | .split('\n')
|
91 | .pop()
|
92 | : ''
|
93 |
|
94 | logSyntaxError({
|
95 | count,
|
96 | path,
|
97 | lineNumber: line,
|
98 | line: chalk`{red ${lineCode}}`,
|
99 | message: chalk`${message}`,
|
100 | })
|
101 | }
|
102 | })
|
103 |
|
104 | return new Promise((resolve, reject) =>
|
105 | transformFile(filename, { ...opts, log }, resolve)
|
106 | )
|
107 | }
|
108 |
|
109 | export function deleteDir(path) {
|
110 | if (fs.existsSync(path)) {
|
111 | fs.readdirSync(path).forEach(function(file) {
|
112 | const curPath = path + '/' + file
|
113 | if (fs.lstatSync(curPath).isDirectory()) {
|
114 |
|
115 | deleteDir(curPath)
|
116 | } else {
|
117 |
|
118 | fs.unlinkSync(curPath)
|
119 | }
|
120 | })
|
121 | fs.rmdirSync(path)
|
122 | }
|
123 | }
|
124 |
|
125 | process.on('uncaughtException', function(err) {
|
126 | console.error(err)
|
127 | process.exit(1)
|
128 | })
|
129 |
|
130 | export function requireChokidar() {
|
131 | try {
|
132 | return require('chokidar')
|
133 | } catch (err) {
|
134 | console.error(
|
135 | 'The optional dependency chokidar failed to install and is required for ' +
|
136 | '--watch. Chokidar is likely not supported on your platform.'
|
137 | )
|
138 | throw err
|
139 | }
|
140 | }
|