json2env 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #!/usr/bin/env node
  2. /*
  3. Usage: js2on2env keyFile context-files...
  4. */
  5. var fs = require('fs')
  6. global.dump = (...args) => { for (let item of args) print(JSON.stringify(item, null, 4)) }
  7. global.print = (...args) => console.log(...args)
  8. /*
  9. js-blend - Blend objects
  10. */
  11. function clone(src) {
  12. var result
  13. if (Array.isArray(src)) {
  14. result = src.slice(0)
  15. } else if (typeof src == 'object' && !(src instanceof Date || src instanceof RegExp || src == null)) {
  16. result = Object.create(Object.getPrototypeOf(src))
  17. var i, descriptor, keys = Object.getOwnPropertyNames(src)
  18. for (i = 0; i < keys.length; i ++) {
  19. descriptor = Object.getOwnPropertyDescriptor(src, keys[ i ])
  20. if (descriptor.value && typeof descriptor.value === 'object') {
  21. descriptor.value = clone(descriptor.value)
  22. }
  23. Object.defineProperty(result, keys[i], descriptor)
  24. }
  25. } else {
  26. result = src
  27. }
  28. return result
  29. }
  30. function blend(dest, src, combine = '') {
  31. if (!src) {
  32. return dest
  33. }
  34. if (!dest || typeof dest != 'object' || Array.isArray(dest)) {
  35. return dest
  36. }
  37. for (let key of Object.getOwnPropertyNames(src)) {
  38. let property = key
  39. let op = key[0]
  40. if (op == '+') {
  41. property = key.slice(1)
  42. } else if (op == '-') {
  43. property = key.slice(1)
  44. } else if (op == '?') {
  45. property = key.slice(1)
  46. } else if (op == '=') {
  47. property = key.slice(1)
  48. } else if (combine) {
  49. op = combine
  50. } else {
  51. /* Default is to blend */
  52. op = ''
  53. }
  54. let s = src[key]
  55. if (!dest.hasOwnProperty(property)) {
  56. if (op == '-') {
  57. continue
  58. }
  59. dest[property] = clone(s)
  60. continue
  61. } else if (op == '?') {
  62. continue
  63. }
  64. let d = dest[property]
  65. if (Array.isArray(d)) {
  66. if (op == '+') {
  67. if (Array.isArray(s)) {
  68. for (let item of s) {
  69. if (d.indexOf(s) < 0) d.push(item)
  70. }
  71. } else {
  72. d.push(s)
  73. }
  74. } else if (op == '-') {
  75. if (Array.isArray(s)) {
  76. for (let item of s) {
  77. let index = d.indexOf(item)
  78. if (index >= 0) d.slice(index, 1)
  79. }
  80. } else {
  81. let index = d.indexOf(s)
  82. if (index >= 0) d.slice(index, 1)
  83. }
  84. } else {
  85. /* op == '=' */
  86. dest[property] = clone(s)
  87. }
  88. } else if (typeof d == 'object' && d !== null && d !== undefined) {
  89. if (op == '=') {
  90. dest[property] = clone(s)
  91. } else if (op == '-') {
  92. delete dest[property]
  93. } else if (typeof s == 'object') {
  94. blend(d, s, op)
  95. }
  96. } else if (typeof d == 'string') {
  97. if (op == '+') {
  98. dest[property] += ' ' + s
  99. } else if (op == '-') {
  100. if (d == s) {
  101. delete dest[property]
  102. } else {
  103. dest[property] = d.replace(s, '')
  104. }
  105. } else {
  106. /* op == '=' */
  107. dest[property] = s
  108. }
  109. } else if (typeof d == 'number') {
  110. if (op == '+') {
  111. dest[property] += s
  112. } else if (op == '-') {
  113. dest[property] -= s
  114. } else {
  115. /* op == '=' */
  116. dest[property] = s
  117. }
  118. } else {
  119. if (op == '=') {
  120. dest[property] = s
  121. } else if (op == '-') {
  122. delete dest[property]
  123. } else {
  124. dest[property] = s
  125. }
  126. }
  127. }
  128. return dest
  129. }
  130. function expand(v, ...contexts) {
  131. let json = JSON.stringify(v)
  132. for (let context of contexts) {
  133. json = template(json, context)
  134. }
  135. return JSON.parse(json)
  136. }
  137. function template(v, context) {
  138. let text = v.toString()
  139. let matches = text.match(/\$\{[^}]*}/gm)
  140. if (matches) {
  141. // context = clone(context)
  142. for (let name of matches) {
  143. let word = name.slice(2).slice(0, -1)
  144. if (context[word] == undefined) {
  145. context[word] = '${' + word + '}'
  146. }
  147. }
  148. let fn = Function('_context_', 'with (_context_) { return `' + text + '`}')
  149. return fn(context)
  150. }
  151. return text
  152. }
  153. function mapEnv(obj, prefix = '', vars = {}) {
  154. for (let name of Object.keys(obj)) {
  155. let value = obj[name]
  156. if (name == 'profiles') {
  157. continue
  158. }
  159. if (typeof value == 'object') {
  160. mapEnv(value, prefix + name.toUpperCase() + '_', vars)
  161. } else {
  162. name = (prefix + name).toUpperCase().replace(/\./g, '_').replace(/-/g, '_')
  163. vars[name] = value
  164. }
  165. }
  166. return vars
  167. }
  168. function getEnv(obj, context = {}) {
  169. let vars = mapEnv(obj)
  170. for (let [index, v] of Object.entries(vars)) {
  171. vars[index] = expand(v, context)
  172. }
  173. return vars
  174. }
  175. let file = process.argv[2]
  176. if (!fs.existsSync(file)) {
  177. process.stderr.write(`Cannot locate ${file}\n`)
  178. process.exit(1)
  179. }
  180. let data = fs.readFileSync(file)
  181. let obj = eval('(' + data + ')')
  182. let context = blend({}, obj)
  183. for (let i = 3; i < process.argv.length; i++) {
  184. let path = process.argv[i]
  185. if (fs.existsSync(path)) {
  186. data = fs.readFileSync(path)
  187. let ctx = eval('(' + data + ')')
  188. context = blend(context, ctx)
  189. }
  190. }
  191. if (context.profile && context.profiles && context.profiles[context.profile]) {
  192. blend(context, context.profiles[context.profile])
  193. }
  194. let env = getEnv(obj, context)
  195. for (let [key,value] of Object.entries(env)) {
  196. print('export ' + key + '="' + value + '"')
  197. }