Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

standalone.js 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. 'use strict';
  2. const _ = require('lodash');
  3. const createStylelint = require('./createStylelint');
  4. const createStylelintResult = require('./createStylelintResult');
  5. const debug = require('debug')('stylelint:standalone');
  6. const fastGlob = require('fast-glob');
  7. const FileCache = require('./utils/FileCache');
  8. const filterFilePaths = require('./utils/filterFilePaths');
  9. const formatters = require('./formatters');
  10. const fs = require('fs');
  11. const getFormatterOptionsText = require('./utils/getFormatterOptionsText');
  12. const globby = require('globby');
  13. const hash = require('./utils/hash');
  14. const NoFilesFoundError = require('./utils/noFilesFoundError');
  15. const path = require('path');
  16. const pkg = require('../package.json');
  17. const prepareReturnValue = require('./prepareReturnValue');
  18. const { default: ignore } = require('ignore');
  19. const DEFAULT_IGNORE_FILENAME = '.stylelintignore';
  20. const FILE_NOT_FOUND_ERROR_CODE = 'ENOENT';
  21. const ALWAYS_IGNORED_GLOBS = ['**/node_modules/**'];
  22. const writeFileAtomic = require('write-file-atomic');
  23. /** @typedef {import('stylelint').StylelintStandaloneOptions} StylelintStandaloneOptions */
  24. /** @typedef {import('stylelint').StylelintStandaloneReturnValue} StylelintStandaloneReturnValue */
  25. /** @typedef {import('stylelint').StylelintResult} StylelintResult */
  26. /** @typedef {import('stylelint').Formatter} Formatter */
  27. /** @typedef {import('stylelint').FormatterIdentifier} FormatterIdentifier */
  28. /**
  29. * @param {StylelintStandaloneOptions} options
  30. * @returns {Promise<StylelintStandaloneReturnValue>}
  31. */
  32. module.exports = function (options) {
  33. const cacheLocation = options.cacheLocation;
  34. const code = options.code;
  35. const codeFilename = options.codeFilename;
  36. const config = options.config;
  37. const configBasedir = options.configBasedir;
  38. const configFile = options.configFile;
  39. const configOverrides = options.configOverrides;
  40. const customSyntax = options.customSyntax;
  41. const globbyOptions = options.globbyOptions;
  42. const files = options.files;
  43. const fix = options.fix;
  44. const formatter = options.formatter;
  45. const ignoreDisables = options.ignoreDisables;
  46. const reportNeedlessDisables = options.reportNeedlessDisables;
  47. const reportInvalidScopeDisables = options.reportInvalidScopeDisables;
  48. const reportDescriptionlessDisables = options.reportDescriptionlessDisables;
  49. const syntax = options.syntax;
  50. const allowEmptyInput = options.allowEmptyInput || false;
  51. const useCache = options.cache || false;
  52. /** @type {FileCache} */
  53. let fileCache;
  54. const startTime = Date.now();
  55. // The ignorer will be used to filter file paths after the glob is checked,
  56. // before any files are actually read
  57. const ignoreFilePath = options.ignorePath || DEFAULT_IGNORE_FILENAME;
  58. const absoluteIgnoreFilePath = path.isAbsolute(ignoreFilePath)
  59. ? ignoreFilePath
  60. : path.resolve(process.cwd(), ignoreFilePath);
  61. let ignoreText = '';
  62. try {
  63. ignoreText = fs.readFileSync(absoluteIgnoreFilePath, 'utf8');
  64. } catch (readError) {
  65. if (readError.code !== FILE_NOT_FOUND_ERROR_CODE) throw readError;
  66. }
  67. const ignorePattern = options.ignorePattern || [];
  68. const ignorer = ignore().add(ignoreText).add(ignorePattern);
  69. const isValidCode = typeof code === 'string';
  70. if ((!files && !isValidCode) || (files && (code || isValidCode))) {
  71. throw new Error('You must pass stylelint a `files` glob or a `code` string, though not both');
  72. }
  73. /** @type {Formatter} */
  74. let formatterFunction;
  75. try {
  76. formatterFunction = getFormatterFunction(formatter);
  77. } catch (error) {
  78. return Promise.reject(error);
  79. }
  80. const stylelint = createStylelint({
  81. config,
  82. configFile,
  83. configBasedir,
  84. configOverrides,
  85. ignoreDisables,
  86. ignorePath: ignoreFilePath,
  87. reportNeedlessDisables,
  88. reportInvalidScopeDisables,
  89. reportDescriptionlessDisables,
  90. syntax,
  91. customSyntax,
  92. fix,
  93. });
  94. if (!files) {
  95. const absoluteCodeFilename =
  96. codeFilename !== undefined && !path.isAbsolute(codeFilename)
  97. ? path.join(process.cwd(), codeFilename)
  98. : codeFilename;
  99. // if file is ignored, return nothing
  100. if (
  101. absoluteCodeFilename &&
  102. !filterFilePaths(ignorer, [path.relative(process.cwd(), absoluteCodeFilename)]).length
  103. ) {
  104. return Promise.resolve(prepareReturnValue([], options, formatterFunction));
  105. }
  106. return stylelint
  107. ._lintSource({
  108. code,
  109. codeFilename: absoluteCodeFilename,
  110. })
  111. .then((postcssResult) => {
  112. // Check for file existence
  113. return /** @type {Promise<void>} */ (new Promise((resolve, reject) => {
  114. if (!absoluteCodeFilename) {
  115. reject();
  116. return;
  117. }
  118. fs.stat(absoluteCodeFilename, (err) => {
  119. if (err) {
  120. reject();
  121. } else {
  122. resolve();
  123. }
  124. });
  125. }))
  126. .then(() => {
  127. return stylelint._createStylelintResult(postcssResult, absoluteCodeFilename);
  128. })
  129. .catch(() => {
  130. return stylelint._createStylelintResult(postcssResult);
  131. });
  132. })
  133. .catch(_.partial(handleError, stylelint))
  134. .then((stylelintResult) => {
  135. const postcssResult = stylelintResult._postcssResult;
  136. const returnValue = prepareReturnValue([stylelintResult], options, formatterFunction);
  137. if (options.fix && postcssResult && !postcssResult.stylelint.ignored) {
  138. if (!postcssResult.stylelint.disableWritingFix) {
  139. // If we're fixing, the output should be the fixed code
  140. returnValue.output = postcssResult.root.toString(postcssResult.opts.syntax);
  141. } else {
  142. // If the writing of the fix is disabled, the input code is returned as-is
  143. returnValue.output = code;
  144. }
  145. }
  146. return returnValue;
  147. });
  148. }
  149. let fileList = files;
  150. if (typeof fileList === 'string') {
  151. fileList = [fileList];
  152. }
  153. fileList = fileList.map((entry) => {
  154. const cwd = _.get(globbyOptions, 'cwd', process.cwd());
  155. const absolutePath = !path.isAbsolute(entry) ? path.join(cwd, entry) : path.normalize(entry);
  156. if (fs.existsSync(absolutePath)) {
  157. // This path points to a file. Return an escaped path to avoid globbing
  158. return fastGlob.escapePath(entry);
  159. }
  160. return entry;
  161. });
  162. if (!options.disableDefaultIgnores) {
  163. fileList = fileList.concat(ALWAYS_IGNORED_GLOBS.map((glob) => `!${glob}`));
  164. }
  165. if (useCache) {
  166. const stylelintVersion = pkg.version;
  167. const hashOfConfig = hash(`${stylelintVersion}_${JSON.stringify(config || {})}`);
  168. fileCache = new FileCache(cacheLocation, hashOfConfig);
  169. } else {
  170. // No need to calculate hash here, we just want to delete cache file.
  171. fileCache = new FileCache(cacheLocation);
  172. // Remove cache file if cache option is disabled
  173. fileCache.destroy();
  174. }
  175. return globby(fileList, globbyOptions)
  176. .then((filePaths) => {
  177. // The ignorer filter needs to check paths relative to cwd
  178. filePaths = filterFilePaths(
  179. ignorer,
  180. filePaths.map((p) => path.relative(process.cwd(), p)),
  181. );
  182. if (!filePaths.length) {
  183. if (!allowEmptyInput) {
  184. throw new NoFilesFoundError(fileList);
  185. }
  186. return Promise.all([]);
  187. }
  188. const cwd = _.get(globbyOptions, 'cwd', process.cwd());
  189. let absoluteFilePaths = filePaths.map((filePath) => {
  190. const absoluteFilepath = !path.isAbsolute(filePath)
  191. ? path.join(cwd, filePath)
  192. : path.normalize(filePath);
  193. return absoluteFilepath;
  194. });
  195. if (useCache) {
  196. absoluteFilePaths = absoluteFilePaths.filter(fileCache.hasFileChanged.bind(fileCache));
  197. }
  198. const getStylelintResults = absoluteFilePaths.map((absoluteFilepath) => {
  199. debug(`Processing ${absoluteFilepath}`);
  200. return stylelint
  201. ._lintSource({
  202. filePath: absoluteFilepath,
  203. })
  204. .then((postcssResult) => {
  205. if (postcssResult.stylelint.stylelintError && useCache) {
  206. debug(`${absoluteFilepath} contains linting errors and will not be cached.`);
  207. fileCache.removeEntry(absoluteFilepath);
  208. }
  209. /**
  210. * If we're fixing, save the file with changed code
  211. * @type {Promise<Error | void>}
  212. */
  213. let fixFile = Promise.resolve();
  214. if (
  215. postcssResult.root &&
  216. postcssResult.opts &&
  217. !postcssResult.stylelint.ignored &&
  218. options.fix &&
  219. !postcssResult.stylelint.disableWritingFix
  220. ) {
  221. // @ts-ignore TODO TYPES toString accepts 0 arguments
  222. const fixedCss = postcssResult.root.toString(postcssResult.opts.syntax);
  223. if (
  224. postcssResult.root &&
  225. postcssResult.root.source &&
  226. // @ts-ignore TODO TYPES css is unknown property
  227. postcssResult.root.source.input.css !== fixedCss
  228. ) {
  229. fixFile = writeFileAtomic(absoluteFilepath, fixedCss);
  230. }
  231. }
  232. return fixFile.then(() =>
  233. stylelint._createStylelintResult(postcssResult, absoluteFilepath),
  234. );
  235. })
  236. .catch((error) => {
  237. // On any error, we should not cache the lint result
  238. fileCache.removeEntry(absoluteFilepath);
  239. return handleError(stylelint, error, absoluteFilepath);
  240. });
  241. });
  242. return Promise.all(getStylelintResults);
  243. })
  244. .then((stylelintResults) => {
  245. if (useCache) {
  246. fileCache.reconcile();
  247. }
  248. const rtn = prepareReturnValue(stylelintResults, options, formatterFunction);
  249. debug(`Linting complete in ${Date.now() - startTime}ms`);
  250. return rtn;
  251. });
  252. };
  253. /**
  254. * @param {FormatterIdentifier | undefined} selected
  255. * @returns {Formatter}
  256. */
  257. function getFormatterFunction(selected) {
  258. /** @type {Formatter} */
  259. let formatterFunction;
  260. if (typeof selected === 'string') {
  261. formatterFunction = formatters[selected];
  262. if (formatterFunction === undefined) {
  263. throw new Error(
  264. `You must use a valid formatter option: ${getFormatterOptionsText()} or a function`,
  265. );
  266. }
  267. } else if (typeof selected === 'function') {
  268. formatterFunction = selected;
  269. } else {
  270. formatterFunction = formatters.json;
  271. }
  272. return formatterFunction;
  273. }
  274. /**
  275. * @param {import('stylelint').StylelintInternalApi} stylelint
  276. * @param {any} error
  277. * @param {string} [filePath]
  278. * @return {Promise<StylelintResult>}
  279. */
  280. function handleError(stylelint, error, filePath = undefined) {
  281. if (error.name === 'CssSyntaxError') {
  282. return createStylelintResult(stylelint, undefined, filePath, error);
  283. }
  284. throw error;
  285. }