Files
Spencer Pincott 97737ca1ae Initial commit
2024-07-15 22:20:13 -04:00

208 lines
5.2 KiB
JavaScript

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
const p = require('path');
const fs = require('fs'); // const printAST = require('ast-pretty-print')
const {
getReplacement,
requireFromString
} = require('./helpers');
module.exports = prevalPlugin;
function prevalPlugin(babel) {
const {
types: t,
template,
transformFromAst
} = babel;
const assignmentBuilder = template('const NAME = VALUE');
return {
name: 'preval',
visitor: {
Program(path, {
file: {
opts: fileOpts
}
}) {
const firstNode = path.node.body[0] || {};
const comments = firstNode.leadingComments || [];
const isPreval = comments.some(isPrevalComment);
if (!isPreval) {
return;
}
comments.find(isPrevalComment).value = ' this file was prevaled';
const {
code: string
} = transformFromAst(path.node, null,
/* istanbul ignore next (babel 6 vs babel 7 check) */
/^6\./.test(babel.version) ? {} : {
babelrc: false,
configFile: false
});
const replacement = getReplacement({
string,
fileOpts,
babel
});
const moduleExports = (0, _extends2.default)({}, t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier('module'), t.identifier('exports')), replacement)), {
leadingComments: comments
});
path.replaceWith(t.program([moduleExports]));
},
TaggedTemplateExpression(path, {
file: {
opts: fileOpts
}
}) {
const isPreval = path.node.tag.name === 'preval';
if (!isPreval) {
return;
}
const string = path.get('quasi').evaluate().value;
if (!string) {
throw new Error('Unable to determine the value of your preval string');
}
const replacement = getReplacement({
string,
fileOpts,
babel
});
path.replaceWith(replacement);
},
ImportDeclaration(path, {
file: {
opts: fileOpts
}
}) {
const isPreval = looksLike(path, {
node: {
source: {
leadingComments(comments) {
return comments && comments.some(isPrevalComment);
}
}
}
});
if (!isPreval) {
return;
}
const prevalComment = path.node.source.leadingComments.find(isPrevalComment).value.trim();
let argValues;
if (prevalComment !== 'preval') {
const arg = prevalComment.replace(/preval\((.*)\)/, '$1').trim();
const argValue = requireFromString({
string: `module.exports = ${arg}`,
fileOpts
});
argValues = [argValue];
}
const absolutePath = p.resolve(p.dirname(fileOpts.filename), path.node.source.value);
const code = fs.readFileSync(require.resolve(absolutePath));
const replacement = getReplacement({
string: code,
fileOpts,
args: argValues,
babel
});
path.replaceWith(assignmentBuilder({
NAME: t.identifier(path.node.specifiers[0].local.name),
VALUE: replacement
}));
},
CallExpression(path, {
file: {
opts: fileOpts
}
}) {
const isPreval = looksLike(path, {
node: {
callee: {
type: 'MemberExpression',
object: {
name: 'preval'
},
property: {
name: 'require'
}
}
}
});
if (!isPreval) {
return;
}
const [source, ...args] = path.get('arguments');
const argValues = args.map(a => {
const result = a.evaluate();
if (!result.confident) {
throw new Error('preval cannot determine the value of an argument in preval.require');
}
return result.value;
});
const absolutePath = p.resolve(p.dirname(fileOpts.filename), source.node.value);
const code = fs.readFileSync(require.resolve(absolutePath));
const replacement = getReplacement({
string: code,
fileOpts,
args: argValues,
babel
});
path.replaceWith(replacement);
}
}
};
}
function isPrevalComment(comment) {
const normalisedComment = comment.value.trim().split(' ')[0].trim();
return normalisedComment.startsWith('preval') || normalisedComment.startsWith('@preval');
}
function looksLike(a, b) {
return a && b && Object.keys(b).every(bKey => {
const bVal = b[bKey];
const aVal = a[bKey];
if (typeof bVal === 'function') {
return bVal(aVal);
}
return isPrimitive(bVal) ? bVal === aVal : looksLike(aVal, bVal);
});
}
function isPrimitive(val) {
// eslint-disable-next-line
return val == null || /^[sbn]/.test(typeof val);
}
/*
eslint
import/no-unassigned-import: off,
import/no-dynamic-require: off,
max-lines-per-function: off,
*/