File.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. "use strict";
  2. const conversions = require("webidl-conversions");
  3. const utils = require("./utils.js");
  4. const Blob = require("./Blob.js");
  5. const FilePropertyBag = require("./FilePropertyBag.js");
  6. const implSymbol = utils.implSymbol;
  7. const ctorRegistrySymbol = utils.ctorRegistrySymbol;
  8. const interfaceName = "File";
  9. exports.is = value => {
  10. return utils.isObject(value) && Object.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
  11. };
  12. exports.isImpl = value => {
  13. return utils.isObject(value) && value instanceof Impl.implementation;
  14. };
  15. exports.convert = (globalObject, value, { context = "The provided value" } = {}) => {
  16. if (exports.is(value)) {
  17. return utils.implForWrapper(value);
  18. }
  19. throw new globalObject.TypeError(`${context} is not of type 'File'.`);
  20. };
  21. function makeWrapper(globalObject, newTarget) {
  22. let proto;
  23. if (newTarget !== undefined) {
  24. proto = newTarget.prototype;
  25. }
  26. if (!utils.isObject(proto)) {
  27. proto = globalObject[ctorRegistrySymbol]["File"].prototype;
  28. }
  29. return Object.create(proto);
  30. }
  31. exports.create = (globalObject, constructorArgs, privateData) => {
  32. const wrapper = makeWrapper(globalObject);
  33. return exports.setup(wrapper, globalObject, constructorArgs, privateData);
  34. };
  35. exports.createImpl = (globalObject, constructorArgs, privateData) => {
  36. const wrapper = exports.create(globalObject, constructorArgs, privateData);
  37. return utils.implForWrapper(wrapper);
  38. };
  39. exports._internalSetup = (wrapper, globalObject) => {
  40. Blob._internalSetup(wrapper, globalObject);
  41. };
  42. exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
  43. privateData.wrapper = wrapper;
  44. exports._internalSetup(wrapper, globalObject);
  45. Object.defineProperty(wrapper, implSymbol, {
  46. value: new Impl.implementation(globalObject, constructorArgs, privateData),
  47. configurable: true
  48. });
  49. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  50. if (Impl.init) {
  51. Impl.init(wrapper[implSymbol]);
  52. }
  53. return wrapper;
  54. };
  55. exports.new = (globalObject, newTarget) => {
  56. const wrapper = makeWrapper(globalObject, newTarget);
  57. exports._internalSetup(wrapper, globalObject);
  58. Object.defineProperty(wrapper, implSymbol, {
  59. value: Object.create(Impl.implementation.prototype),
  60. configurable: true
  61. });
  62. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  63. if (Impl.init) {
  64. Impl.init(wrapper[implSymbol]);
  65. }
  66. return wrapper[implSymbol];
  67. };
  68. const exposed = new Set(["Window", "Worker"]);
  69. exports.install = (globalObject, globalNames) => {
  70. if (!globalNames.some(globalName => exposed.has(globalName))) {
  71. return;
  72. }
  73. const ctorRegistry = utils.initCtorRegistry(globalObject);
  74. class File extends globalObject.Blob {
  75. constructor(fileBits, fileName) {
  76. if (arguments.length < 2) {
  77. throw new globalObject.TypeError(
  78. `Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`
  79. );
  80. }
  81. const args = [];
  82. {
  83. let curArg = arguments[0];
  84. if (!utils.isObject(curArg)) {
  85. throw new globalObject.TypeError("Failed to construct 'File': parameter 1" + " is not an iterable object.");
  86. } else {
  87. const V = [];
  88. const tmp = curArg;
  89. for (let nextItem of tmp) {
  90. if (Blob.is(nextItem)) {
  91. nextItem = utils.implForWrapper(nextItem);
  92. } else if (utils.isArrayBuffer(nextItem)) {
  93. nextItem = conversions["ArrayBuffer"](nextItem, {
  94. context: "Failed to construct 'File': parameter 1" + "'s element",
  95. globals: globalObject
  96. });
  97. } else if (ArrayBuffer.isView(nextItem)) {
  98. nextItem = conversions["ArrayBufferView"](nextItem, {
  99. context: "Failed to construct 'File': parameter 1" + "'s element",
  100. globals: globalObject
  101. });
  102. } else {
  103. nextItem = conversions["USVString"](nextItem, {
  104. context: "Failed to construct 'File': parameter 1" + "'s element",
  105. globals: globalObject
  106. });
  107. }
  108. V.push(nextItem);
  109. }
  110. curArg = V;
  111. }
  112. args.push(curArg);
  113. }
  114. {
  115. let curArg = arguments[1];
  116. curArg = conversions["USVString"](curArg, {
  117. context: "Failed to construct 'File': parameter 2",
  118. globals: globalObject
  119. });
  120. args.push(curArg);
  121. }
  122. {
  123. let curArg = arguments[2];
  124. curArg = FilePropertyBag.convert(globalObject, curArg, { context: "Failed to construct 'File': parameter 3" });
  125. args.push(curArg);
  126. }
  127. return exports.setup(Object.create(new.target.prototype), globalObject, args);
  128. }
  129. get name() {
  130. const esValue = this !== null && this !== undefined ? this : globalObject;
  131. if (!exports.is(esValue)) {
  132. throw new globalObject.TypeError("'get name' called on an object that is not a valid instance of File.");
  133. }
  134. return esValue[implSymbol]["name"];
  135. }
  136. get lastModified() {
  137. const esValue = this !== null && this !== undefined ? this : globalObject;
  138. if (!exports.is(esValue)) {
  139. throw new globalObject.TypeError(
  140. "'get lastModified' called on an object that is not a valid instance of File."
  141. );
  142. }
  143. return esValue[implSymbol]["lastModified"];
  144. }
  145. }
  146. Object.defineProperties(File.prototype, {
  147. name: { enumerable: true },
  148. lastModified: { enumerable: true },
  149. [Symbol.toStringTag]: { value: "File", configurable: true }
  150. });
  151. ctorRegistry[interfaceName] = File;
  152. Object.defineProperty(globalObject, interfaceName, {
  153. configurable: true,
  154. writable: true,
  155. value: File
  156. });
  157. };
  158. const Impl = require("../../jsdom/living/file-api/File-impl.js");