UNPKG

json.macro

Version:

Directly load json files into your code via babel macros.

392 lines (364 loc) 14.8 kB
"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;