Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@hela/eslint: Implement ESLint RFC#9 #227

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
chore: resolve items; todo: move logic to glob-cache
Signed-off-by: Charlike Mike Reagent <[email protected]>
tunnckoCore committed Mar 8, 2020
commit 7338884b5cb8d2c352a5cca4aeede410699a0c8c
204 changes: 134 additions & 70 deletions packages/eslint/src/api.js
Original file line number Diff line number Diff line change
@@ -6,8 +6,10 @@
const fs = require('fs');
const util = require('util');
const path = require('path');
const isGlob = require('is-glob');
const cacache = require('cacache');
const fastGlob = require('fast-glob');
const memoizeFs = require('memoize-fs');
const globCache = require('glob-cache');
const utils = require('./utils');

@@ -26,7 +28,64 @@ async function* resolveFilesStream(patterns, options) {
}
}

async function resolveFiles(patterns, options) {
// filepath, glob patterns or File
async function resolveItems(items, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };

const memoizer = memoizeFs({
cachePath: path.join(process.cwd(), '.cache', 'glob-meta-cache'),
});
const toIntegrity = await memoizer.fn(utils.toIntegrity);

const globs = [];
const contexts = [];

await Promise.all(
[]
.concat(items)
.filter(Boolean)
.map(async (x) => {
const item = await x;

if (isGlob(item)) {
globs.push(item);
return;
}

const file = await utils.toFile(item, { toIntegrity });
const info = await cacache.get.info(opts.cacheLocation, file.path);
const hash = await cacache.get.hasContent(
opts.cacheLocation,
file.integrity,
);

const ctx = {
file,
changed: hash === false,
notFound: info === null,
cacache,
cacheLocation: opts.cacheLocation,
};

ctx.cacheFile = info;

// NOTE: not here!
// if (ctx.changed) {
// await cacache.put(opts.cacheLocation, file.path, file.contents);
// }

if (opts.forceLoad === true || ctx.changed) {
contexts.push(ctx);
}
}),
);

const results = globs.length > 0 ? await resolvePatterns(globs, opts) : [];

return results.concat(contexts);
}

async function resolvePatterns(patterns, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };

const iterable = await globCache(patterns, opts);
@@ -51,12 +110,12 @@ async function resolveFiles(patterns, options) {
* @param {string|string[]} patterns - glob patterns to match
* @param {*} options
*/
async function processFiles(patterns, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
const files = await resolveFiles(patterns, opts);
// async function processFiles(patterns, options) {
// const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
// const files = await resolveFiles(patterns, opts);

return lintFiles(files, opts);
}
// return lintFiles(files, opts);
// }

async function lintText(contents, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
@@ -77,79 +136,84 @@ async function lintText(contents, options) {
* @param {File|File[]|Context|Context[]|string|string[]} items
* @param {*} options
*/
async function lintItems(items, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
const report = {
results: [],
errorCount: 0,
warningCount: 0,
};

await Promise.all(
[]
.concat(items)
.filter(Boolean)
.map(async (item) => {
if (opts.type === 'paths' || opts.type === 'files') {
const file = await utils.toFile(await item);

const repFromText = await lintText(file.contents, opts);

// calcReport(report, repFromText);
report.results.push(file.path);

await cacache.put(opts.cacheLocation, file.path, repFromText.source, {
metadata: {
report: repFromText,
config: opts.config,
},
});

return;
}
if (opts.type === 'contexts') {
const { file, cacheFile } = await item;
const meta = cacheFile && cacheFile.metadata;
const { source, ...repFromText } = await lintText(
file.contents,
opts,
);

const reportChanged =
JSON.stringify(repFromText) !== JSON.stringify(meta && meta.report);

if (opts.forceLoad === true || reportChanged) {
// calcReport(report, repFromText);
report.results.push(file.path);

await cacache.put(opts.cacheLocation, file.path, source, {
metadata: {
report: { ...repFromText, source },
config: opts.config,
},
});
}
}
}),
);

return report;
}

async function lintFiles(files, options) {
return lintItems(files, { ...options, type: 'files' });
}
// async function lintItems(items, options) {
// const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
// const report = {
// results: [],
// errorCount: 0,
// warningCount: 0,
// };

// await Promise.all(
// []
// .concat(items)
// .filter(Boolean)
// .map(async (item) => {
// if (opts.type === 'paths' || opts.type === 'files') {
// const file = await utils.toFile(await item);

// const repFromText = await lintText(file.contents, opts);

// // calcReport(report, repFromText);
// report.results.push(file.path);

// await cacache.put(opts.cacheLocation, file.path, repFromText.source, {
// metadata: {
// report: repFromText,
// config: opts.config,
// },
// });

// return;
// }
// if (opts.type === 'contexts') {
// const { file, cacheFile } = await item;
// const meta = cacheFile && cacheFile.metadata;
// const { source, ...repFromText } = await lintText(
// file.contents,
// opts,
// );

// const reportChanged =
// JSON.stringify(repFromText) !== JSON.stringify(meta && meta.report);

// if (opts.forceLoad === true || reportChanged) {
// // calcReport(report, repFromText);
// report.results.push(file.path);

// await cacache.put(opts.cacheLocation, file.path, source, {
// metadata: {
// report: { ...repFromText, source },
// config: opts.config,
// },
// });
// }
// }
// }),
// );

// return report;
// }

// async function lintFiles(files, options) {
// return lintItems(files, { ...options, type: 'files' });
// }

// resolveFiles('modules/*/src/**/*.js', { forceLoad: true }).then(console.log);

lintFiles([
resolveItems([
// 'foobar.js',
// { path: 'foobar.js' },
// { path: 'foobar.js', contents: Buffer.from('var foobar = 1;')},
// { file: { path: 'foobar.js' } },
// { file: { path: 'foobar.js', contents: Buffer.from('sasa') } },

// and promises resolving to one of above

'modules/*/src/**/*.js',
Promise.resolve(path.join(process.cwd(), 'packages/eslint/src/api.js')),
]).then(console.log);

async function lintFiles(items, options) {
const opts = { ...utils.constants.DEFAULT_OPTIONS, ...options };
const contexts = await resolveItems(items, options);
}
2 changes: 1 addition & 1 deletion packages/eslint/src/constants.js
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ const DEFAULT_FILES = [
];

const DEFAULT_OPTIONS = {
forceReload: false,
forceLoad: false,
cacheLocation: '.cache/hela-eslint-cache',
};

43 changes: 24 additions & 19 deletions packages/eslint/src/utils.js
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@

const fs = require('fs');
const util = require('util');
const path = require('path');
const crypto = require('crypto');

const findFileUp = require('find-file-up');
const importFresh = require('import-fresh');
@@ -99,38 +101,41 @@ function isContext(item) {
return (item && isFile(item.file) && isCacheFile(item.cacheFile)) || false;
}

async function toFile(file) {
if (isFile(file)) {
return file;
}
async function toFile(file, options) {
const opts = { toIntegrity, ...options };

let x = file || {};

if ((file && typeof file.path === 'string') || typeof file === 'string') {
const contents = await readFile(file.path || file);
return {
path: file,
contents,
size: contents.length,
};
if (typeof x === 'string') {
x = { path: x };
}
if (x && typeof x.path === 'string') {
x = { ...x, path: x.path };
}

throw new Error('@hela/eslint: unknown type, pass filepath or File object');
x.contents = (x && x.contents) || (await readFile(x.path));
x.size = x.contents.length;
x.integrity = x.integrity || (await opts.toIntegrity(x.contents));

return { ...x };
// throw new Error('@hela/eslint: unknown type, pass filepath or File object');
}

async function toContext(file) {
if (isContext(file)) {
return file;
}
const f = toFile(file);
function toIntegrity(value) {
const hashId = crypto
.createHash('sha512')
.update(value)
.digest('base64');

return { file: f, cacheFile: { key: f.path } };
return `sha512-${hashId}`;
}

module.exports = {
isFile,
isCacheFile,
isContext,
toContext,
toFile,
toIntegrity,
readFile,
constants,
processLint,