index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. 'use strict'
  2. const resolve = require('path').resolve
  3. const config = require('lilconfig')
  4. const yaml = require('yaml')
  5. const loadOptions = require('./options.js')
  6. const loadPlugins = require('./plugins.js')
  7. /* istanbul ignore next */
  8. const interopRequireDefault = (obj) => obj && obj.__esModule ? obj : { default: obj }
  9. /**
  10. * Process the result from cosmiconfig
  11. *
  12. * @param {Object} ctx Config Context
  13. * @param {Object} result Cosmiconfig result
  14. *
  15. * @return {Object} PostCSS Config
  16. */
  17. const processResult = (ctx, result) => {
  18. const file = result.filepath || ''
  19. let config = interopRequireDefault(result.config).default || {}
  20. if (typeof config === 'function') {
  21. config = config(ctx)
  22. } else {
  23. config = Object.assign({}, config, ctx)
  24. }
  25. if (!config.plugins) {
  26. config.plugins = []
  27. }
  28. return {
  29. plugins: loadPlugins(config, file),
  30. options: loadOptions(config, file),
  31. file: file
  32. }
  33. }
  34. /**
  35. * Builds the Config Context
  36. *
  37. * @param {Object} ctx Config Context
  38. *
  39. * @return {Object} Config Context
  40. */
  41. const createContext = (ctx) => {
  42. /**
  43. * @type {Object}
  44. *
  45. * @prop {String} cwd=process.cwd() Config search start location
  46. * @prop {String} env=process.env.NODE_ENV Config Enviroment, will be set to `development` by `postcss-load-config` if `process.env.NODE_ENV` is `undefined`
  47. */
  48. ctx = Object.assign({
  49. cwd: process.cwd(),
  50. env: process.env.NODE_ENV
  51. }, ctx)
  52. if (!ctx.env) {
  53. process.env.NODE_ENV = 'development'
  54. }
  55. return ctx
  56. }
  57. const addTypeScriptLoader = (options = {}, loader) => {
  58. const moduleName = 'postcss'
  59. return {
  60. ...options,
  61. searchPlaces: [
  62. ...(options.searchPlaces || []),
  63. 'package.json',
  64. `.${moduleName}rc`,
  65. `.${moduleName}rc.json`,
  66. `.${moduleName}rc.yaml`,
  67. `.${moduleName}rc.yml`,
  68. `.${moduleName}rc.ts`,
  69. `.${moduleName}rc.js`,
  70. `.${moduleName}rc.cjs`,
  71. `${moduleName}.config.ts`,
  72. `${moduleName}.config.js`,
  73. `${moduleName}.config.cjs`
  74. ],
  75. loaders: {
  76. ...options.loaders,
  77. '.yaml': (filepath, content) => yaml.parse(content),
  78. '.yml': (filepath, content) => yaml.parse(content),
  79. '.ts': loader
  80. }
  81. }
  82. }
  83. const withTypeScriptLoader = (rcFunc) => {
  84. return (ctx, path, options) => {
  85. return rcFunc(ctx, path, addTypeScriptLoader(options, (configFile) => {
  86. let registerer = { enabled () {} }
  87. try {
  88. // Register TypeScript compiler instance
  89. registerer = require('ts-node').register()
  90. return require(configFile)
  91. } catch (err) {
  92. if (err.code === 'MODULE_NOT_FOUND') {
  93. throw new Error(
  94. `'ts-node' is required for the TypeScript configuration files. Make sure it is installed\nError: ${err.message}`
  95. )
  96. }
  97. throw err
  98. } finally {
  99. registerer.enabled(false)
  100. }
  101. }))
  102. }
  103. }
  104. /**
  105. * Load Config
  106. *
  107. * @method rc
  108. *
  109. * @param {Object} ctx Config Context
  110. * @param {String} path Config Path
  111. * @param {Object} options Config Options
  112. *
  113. * @return {Promise} config PostCSS Config
  114. */
  115. const rc = withTypeScriptLoader((ctx, path, options) => {
  116. /**
  117. * @type {Object} The full Config Context
  118. */
  119. ctx = createContext(ctx)
  120. /**
  121. * @type {String} `process.cwd()`
  122. */
  123. path = path ? resolve(path) : process.cwd()
  124. return config.lilconfig('postcss', options)
  125. .search(path)
  126. .then((result) => {
  127. if (!result) {
  128. throw new Error(`No PostCSS Config found in: ${path}`)
  129. }
  130. return processResult(ctx, result)
  131. })
  132. })
  133. rc.sync = withTypeScriptLoader((ctx, path, options) => {
  134. /**
  135. * @type {Object} The full Config Context
  136. */
  137. ctx = createContext(ctx)
  138. /**
  139. * @type {String} `process.cwd()`
  140. */
  141. path = path ? resolve(path) : process.cwd()
  142. const result = config.lilconfigSync('postcss', options).search(path)
  143. if (!result) {
  144. throw new Error(`No PostCSS Config found in: ${path}`)
  145. }
  146. return processResult(ctx, result)
  147. })
  148. /**
  149. * Autoload Config for PostCSS
  150. *
  151. * @author Michael Ciniawsky @michael-ciniawsky <michael.ciniawsky@gmail.com>
  152. * @license MIT
  153. *
  154. * @module postcss-load-config
  155. * @version 2.1.0
  156. *
  157. * @requires comsiconfig
  158. * @requires ./options
  159. * @requires ./plugins
  160. */
  161. module.exports = rc