json.macro
Version:
Directly load json files into your code via babel macros.
392 lines (364 loc) • 14.8 kB
JavaScript
"use strict";
function _interopDefault(ex) {
return ex && "object" == typeof ex && "default" in ex ? ex.default : ex;
}
Object.defineProperty(exports, "__esModule", {
value: !0
});
var _classCallCheck = _interopDefault(require("@babel/runtime/helpers/classCallCheck")), _inherits = _interopDefault(require("@babel/runtime/helpers/inherits")), _possibleConstructorReturn = _interopDefault(require("@babel/runtime/helpers/possibleConstructorReturn")), _getPrototypeOf = _interopDefault(require("@babel/runtime/helpers/getPrototypeOf")), parser = require("@babel/parser"), is = _interopDefault(require("@sindresorhus/is")), babelPluginMacros = require("babel-plugin-macros"), fs = require("fs"), glob = _interopDefault(require("globby")), JSON5 = _interopDefault(require("json5")), get = _interopDefault(require("lodash.get")), path = require("path"), findPackageJson = _interopDefault(require("pkg-up")), semver = require("semver"), tsconfigResolver = require("tsconfig-resolver");
function _createForOfIteratorHelper(o) {
if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) {
if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) {
var i = 0, F = function() {};
return {
s: F,
n: function() {
return i >= o.length ? {
done: !0
} : {
done: !1,
value: o[i++]
};
},
e: function(_e) {
throw _e;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var it, err, normalCompletion = !0, didErr = !1;
return {
s: function() {
it = o[Symbol.iterator]();
},
n: function() {
var step = it.next();
return normalCompletion = step.done, step;
},
e: function(_e2) {
didErr = !0, err = _e2;
},
f: function() {
try {
normalCompletion || null == it.return || it.return();
} finally {
if (didErr) throw err;
}
}
};
}
function _unsupportedIterableToArray(o, minLen) {
if (o) {
if ("string" == typeof o) return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
return "Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n ? Array.from(o) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? _arrayLikeToArray(o, minLen) : void 0;
}
}
function _arrayLikeToArray(arr, len) {
(null == len || len > arr.length) && (len = arr.length);
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function() {
var result, Super = _getPrototypeOf(Derived);
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else result = Super.apply(this, arguments);
return _possibleConstructorReturn(this, result);
};
}
function _isNativeReflectConstruct() {
if ("undefined" == typeof Reflect || !Reflect.construct) return !1;
if (Reflect.construct.sham) return !1;
if ("function" == typeof Proxy) return !0;
try {
return Date.prototype.toString.call(Reflect.construct(Date, [], (function() {}))),
!0;
} catch (e) {
return !1;
}
}
var JsonMacroError = function(_MacroError) {
_inherits(JsonMacroError, _MacroError);
var _super = _createSuper(JsonMacroError);
function JsonMacroError(message) {
var _this;
return _classCallCheck(this, JsonMacroError), (_this = _super.call(this, message)).name = "JsonMacroError",
_this.stack = "", _this;
}
return JsonMacroError;
}(babelPluginMacros.MacroError);
function isStringOrUndefined(value) {
return is.string(value) || is.undefined(value);
}
function ensureDirectoryExists(filePath) {
var dir = path.dirname(filePath);
fs.existsSync(dir) || (ensureDirectoryExists(dir), fs.mkdirSync(dir));
}
function frameError(path, message) {
throw path.buildCodeFrameError("\n\n".concat(message, "\n\n"), JsonMacroError);
}
function evaluateNodeValue(_ref) {
var value, parentPath = _ref.parentPath, node = _ref.node, predicate = _ref.predicate;
try {
value = null == node ? void 0 : node.evaluate().value;
} catch (_unused) {
frameError(parentPath, "There was a problem evaluating the value of the argument for the code: ".concat(parentPath.getSource(), ". If the value is dynamic, please make sure that its value is statically deterministic."));
}
return predicate(value) || frameError(parentPath, "Invalid argument passed to function call. Received unsupported type '".concat(is(value), "'.")),
value;
}
function getArgumentNode(_ref2) {
var parentPath = _ref2.parentPath, _ref2$required = _ref2.required, required = void 0 === _ref2$required || _ref2$required, _ref2$index = _ref2.index, index = void 0 === _ref2$index ? 0 : _ref2$index, _ref2$maxArguments = _ref2.maxArguments, maxArguments = void 0 === _ref2$maxArguments ? 1 : _ref2$maxArguments, nodes = parentPath.get("arguments"), nodeArray = Array.isArray(nodes) ? nodes : [ nodes ];
nodeArray.length > maxArguments && frameError(parentPath, "Too many arguments provided to the function call: ".concat(parentPath.getSource(), ". This method only supports one or less."));
var node = null == nodeArray ? void 0 : nodeArray[index];
return void 0 === node && required && frameError(parentPath, "No arguments were provided when one is required: ".concat(parentPath.getSource(), ".")),
node;
}
function loadAndParseJsonFile(_ref3) {
var jsonValue, filePath = _ref3.filePath, parentPath = _ref3.parentPath;
try {
var fileContent = fs.readFileSync(filePath, {
encoding: "utf-8"
});
jsonValue = JSON5.parse(fileContent);
} catch (_unused2) {
frameError(parentPath, "There was a problem loading the provided JSON file: '".concat(filePath, "'. Please make sure the file exists and you have provided valid JSON content."));
}
return jsonValue;
}
function getFileName(state) {
var fileName = state.file.opts.filename;
if (!fileName) throw new JsonMacroError("json.macro methods can only be used on files and no filename was found");
return fileName;
}
function loadAndParsePackageJsonFile(options) {
var cwd = options.cwd, parentPath = options.parentPath, filePath = findPackageJson.sync({
cwd: cwd
});
return filePath || frameError(parentPath, "No package.json file could be loaded from your current directory. '".concat(cwd, "'")),
loadAndParseJsonFile({
filePath: filePath,
parentPath: parentPath
});
}
function replaceParentExpression(options) {
var babel = options.babel, parentPath = options.parentPath, value = options.value, expression = babel.types.parenthesizedExpression(parser.parseExpression("[".concat(JSON.stringify(value), "][0]"), {}));
parentPath.replaceWith(expression);
}
function getVersion(_ref4) {
var reference = _ref4.reference, state = _ref4.state, babel = _ref4.babel, filename = getFileName(state), parentPath = reference.parentPath, cwd = path.dirname(filename), node = getArgumentNode({
parentPath: parentPath,
required: !1
}), shouldLoadObject = node && !0 === (null == node ? void 0 : node.evaluate().value), stringVersion = loadAndParsePackageJsonFile({
cwd: cwd,
parentPath: parentPath
}).version;
stringVersion || frameError(parentPath, "No version found for the resolved `package.json` file.");
var value = stringVersion, semver$1 = semver.parse(stringVersion);
semver$1 || frameError(parentPath, "A semantic versioning object could not be parsed from the invalid string: '".concat(stringVersion, "'")),
shouldLoadObject && (value = {
build: semver$1.build,
loose: semver$1.loose,
major: semver$1.major,
minor: semver$1.minor,
patch: semver$1.patch,
prerelease: semver$1.prerelease,
raw: semver$1.raw,
version: semver$1.version
}), replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: value
});
}
function loadPackageJson(_ref5) {
var _jsonValue$key, reference = _ref5.reference, state = _ref5.state, babel = _ref5.babel, filename = getFileName(state), parentPath = reference.parentPath, cwd = path.dirname(filename), node = getArgumentNode({
parentPath: parentPath,
required: !1
}), key = node ? evaluateNodeValue({
node: node,
parentPath: parentPath,
predicate: isStringOrUndefined
}) : void 0, jsonValue = loadAndParsePackageJsonFile({
cwd: cwd,
parentPath: parentPath
});
replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: key ? null !== (_jsonValue$key = jsonValue[key]) && void 0 !== _jsonValue$key ? _jsonValue$key : null : jsonValue
});
}
function loadTsConfigJson(_ref6) {
var reference = _ref6.reference, state = _ref6.state, babel = _ref6.babel, filename = getFileName(state), parentPath = reference.parentPath, cwd = path.dirname(filename), node = getArgumentNode({
parentPath: parentPath,
required: !1
}), searchName = node ? evaluateNodeValue({
node: node,
parentPath: parentPath,
predicate: isStringOrUndefined
}) : tsconfigResolver.DEFAULT_SEARCH_NAME, result = tsconfigResolver.tsconfigResolverSync({
cwd: cwd,
cache: tsconfigResolver.CacheStrategy.Directory,
searchName: searchName
});
result.exists || frameError(parentPath, "No '".concat(searchName, "' file could be loaded from your current file. ").concat(filename)),
replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: result.config
});
}
function writeJson(_ref7) {
var reference = _ref7.reference, state = _ref7.state, babel = _ref7.babel, filename = getFileName(state), parentPath = reference.parentPath, dir = path.dirname(filename), json = evaluateNodeValue({
node: getArgumentNode({
parentPath: parentPath,
required: !0,
maxArguments: 2,
index: 0
}),
parentPath: parentPath,
predicate: is.plainObject
}), relativeFilePath = evaluateNodeValue({
node: getArgumentNode({
parentPath: parentPath,
required: !0,
maxArguments: 2,
index: 1
}),
parentPath: parentPath,
predicate: is.string
}), filePath = path.resolve(dir, relativeFilePath);
ensureDirectoryExists(filePath), fs.writeFileSync(filePath, JSON.stringify(json, null, 2), {
encoding: "utf8"
}), replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: json
});
}
function loadJson(_ref8) {
var filePath, reference = _ref8.reference, state = _ref8.state, babel = _ref8.babel, filename = getFileName(state), parentPath = reference.parentPath, dir = path.dirname(filename), rawFilePath = evaluateNodeValue({
node: getArgumentNode({
parentPath: parentPath,
required: !0,
maxArguments: 2,
index: 0
}),
parentPath: parentPath,
predicate: is.string
}), path$1 = evaluateNodeValue({
node: getArgumentNode({
parentPath: parentPath,
required: !1,
maxArguments: 2,
index: 1
}),
parentPath: parentPath,
predicate: isStringOrUndefined
});
try {
filePath = require.resolve(rawFilePath, {
paths: [ dir ]
});
} catch (_unused3) {
frameError(parentPath, "The provided path: '".concat(rawFilePath, "' does not exist"));
}
var jsonValue = loadAndParseJsonFile({
filePath: filePath,
parentPath: parentPath
});
replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: path$1 ? get(jsonValue, path$1) : jsonValue
});
}
function loadJsonFiles(_ref9) {
var reference = _ref9.reference, state = _ref9.state, babel = _ref9.babel, filename = getFileName(state), parentPath = reference.parentPath, callExpressionPath = reference.parentPath, dir = path.dirname(filename), args = callExpressionPath.get("arguments"), argsArray = Array.isArray(args) ? args : [ args ];
0 === argsArray.length && frameError(parentPath, "You must provide at least one file pattern string to the function call: '".concat(parentPath.getSource(), "'. If the value is dynamic, please make sure that its value is statically deterministic."));
var globs = argsArray.map((function(node) {
return evaluateNodeValue({
node: node,
parentPath: parentPath,
predicate: is.string
});
})), files = glob.sync(globs, {
cwd: dir
});
0 === files.length && frameError(parentPath, "The file patterns provided didn't match any files: '".concat(parentPath.getSource(), "'. If the value is dynamic, please make sure that its value is statically deterministic."));
var value = files.map((function(relativePath) {
return loadAndParseJsonFile({
filePath: path.resolve(dir, relativePath),
parentPath: parentPath
});
}));
replaceParentExpression({
babel: babel,
parentPath: parentPath,
value: value
});
}
function checkReferenceExists(options) {
var method = options.method, name = options.name, macroParameter = options.macroParameter, babel = macroParameter.babel, references = macroParameter.references, state = macroParameter.state, namedReferences = references[name];
if (namedReferences) {
var _step, _iterator = _createForOfIteratorHelper(namedReferences);
try {
for (_iterator.s(); !(_step = _iterator.n()).done; ) {
var reference = _step.value, parentPath = reference.parentPath;
if (!parentPath.isCallExpression()) throw frameError(parentPath, "'".concat(name, "' called from 'json.macro' must be used as a function call."));
method({
babel: babel,
reference: reference,
state: state
});
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
}
var supportedMethods = [ {
name: "writeJson",
method: writeJson
}, {
name: "loadJson",
method: loadJson
}, {
name: "loadJsonFiles",
method: loadJsonFiles
}, {
name: "getVersion",
method: getVersion
}, {
name: "loadPackageJson",
method: loadPackageJson
}, {
name: "loadTsConfigJson",
method: loadTsConfigJson
} ], macro = babelPluginMacros.createMacro((function(macroParameter) {
var _step2, _iterator2 = _createForOfIteratorHelper(supportedMethods);
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
var supportedMethod = _step2.value;
checkReferenceExists({
name: supportedMethod.name,
method: supportedMethod.method,
macroParameter: macroParameter
});
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}));
exports.default = macro;