JsonParser.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Parser = require("../Parser");
  7. const JsonExportsDependency = require("../dependencies/JsonExportsDependency");
  8. const memoize = require("../util/memoize");
  9. const JsonData = require("./JsonData");
  10. /** @typedef {import("../../declarations/plugins/JsonModulesPluginParser").JsonModulesPluginParserOptions} JsonModulesPluginParserOptions */
  11. /** @typedef {import("../Module").BuildInfo} BuildInfo */
  12. /** @typedef {import("../Module").BuildMeta} BuildMeta */
  13. /** @typedef {import("../Parser").ParserState} ParserState */
  14. /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
  15. /** @typedef {import("../util/fs").JsonValue} JsonValue */
  16. /**
  17. * @template T
  18. * @typedef {import("../util/memoize").FunctionReturning<T>} FunctionReturning
  19. */
  20. /** @typedef {(input: string) => Buffer | JsonValue} ParseFn */
  21. /** @type {FunctionReturning<ParseFn>} */
  22. const getParseJson = memoize(() => require("json-parse-even-better-errors"));
  23. class JsonParser extends Parser {
  24. /**
  25. * @param {JsonModulesPluginParserOptions} options parser options
  26. */
  27. constructor(options = {}) {
  28. super();
  29. /** @type {JsonModulesPluginParserOptions} */
  30. this.options = options;
  31. }
  32. /**
  33. * @param {string | Buffer | PreparsedAst} source the source to parse
  34. * @param {ParserState} state the parser state
  35. * @returns {ParserState} the parser state
  36. */
  37. parse(source, state) {
  38. if (Buffer.isBuffer(source)) {
  39. source = source.toString("utf8");
  40. }
  41. /** @type {ParseFn} */
  42. const parseFn =
  43. typeof this.options.parse === "function"
  44. ? this.options.parse
  45. : getParseJson();
  46. /** @type {Buffer | JsonValue | undefined} */
  47. let data;
  48. try {
  49. data =
  50. typeof source === "object"
  51. ? source
  52. : parseFn(source[0] === "\uFEFF" ? source.slice(1) : source);
  53. } catch (err) {
  54. throw new Error(
  55. `Cannot parse JSON: ${/** @type {Error} */ (err).message}`,
  56. { cause: err }
  57. );
  58. }
  59. const jsonData = new JsonData(/** @type {Buffer | JsonValue} */ (data));
  60. const buildInfo = /** @type {BuildInfo} */ (state.module.buildInfo);
  61. buildInfo.jsonData = jsonData;
  62. buildInfo.strict = true;
  63. const buildMeta = /** @type {BuildMeta} */ (state.module.buildMeta);
  64. buildMeta.exportsType = "default";
  65. buildMeta.defaultObject =
  66. typeof data === "object"
  67. ? this.options.namedExports === false
  68. ? false
  69. : this.options.namedExports === true
  70. ? "redirect"
  71. : "redirect-warn"
  72. : false;
  73. state.module.addDependency(
  74. new JsonExportsDependency(
  75. jsonData,
  76. /** @type {number} */
  77. (this.options.exportsDepth)
  78. )
  79. );
  80. return state;
  81. }
  82. }
  83. module.exports = JsonParser;