智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. "use strict";
  2. module.exports = Root;
  3. // extends Namespace
  4. var Namespace = require("./namespace");
  5. ((Root.prototype = Object.create(Namespace.prototype)).constructor = Root).className = "Root";
  6. var Field = require("./field"),
  7. Enum = require("./enum"),
  8. OneOf = require("./oneof"),
  9. util = require("./util");
  10. var Type, // cyclic
  11. parse, // might be excluded
  12. common; // "
  13. /**
  14. * Constructs a new root namespace instance.
  15. * @classdesc Root namespace wrapping all types, enums, services, sub-namespaces etc. that belong together.
  16. * @extends NamespaceBase
  17. * @constructor
  18. * @param {Object.<string,*>} [options] Top level options
  19. */
  20. function Root(options) {
  21. Namespace.call(this, "", options);
  22. /**
  23. * Deferred extension fields.
  24. * @type {Field[]}
  25. */
  26. this.deferred = [];
  27. /**
  28. * Resolved file names of loaded files.
  29. * @type {string[]}
  30. */
  31. this.files = [];
  32. /**
  33. * Edition, defaults to proto2 if unspecified.
  34. * @type {string}
  35. * @private
  36. */
  37. this._edition = "proto2";
  38. /**
  39. * Global lookup cache of fully qualified names.
  40. * @type {Object.<string,ReflectionObject>}
  41. * @private
  42. */
  43. this._fullyQualifiedObjects = {};
  44. }
  45. /**
  46. * Loads a namespace descriptor into a root namespace.
  47. * @param {INamespace} json Namespace descriptor
  48. * @param {Root} [root] Root namespace, defaults to create a new one if omitted
  49. * @param {number} [depth] Current nesting depth, defaults to `0`
  50. * @returns {Root} Root namespace
  51. */
  52. Root.fromJSON = function fromJSON(json, root, depth) {
  53. if (depth === undefined)
  54. depth = 0;
  55. if (depth > util.recursionLimit)
  56. throw Error("max depth exceeded");
  57. if (!root)
  58. root = new Root();
  59. if (json.options)
  60. root.setOptions(json.options);
  61. return root.addJSON(json.nested, depth).resolveAll();
  62. };
  63. /**
  64. * Resolves the path of an imported file, relative to the importing origin.
  65. * This method exists so you can override it with your own logic in case your imports are scattered over multiple directories.
  66. * @function
  67. * @param {string} origin The file name of the importing file
  68. * @param {string} target The file name being imported
  69. * @returns {string|null} Resolved path to `target` or `null` to skip the file
  70. */
  71. Root.prototype.resolvePath = util.path.resolve;
  72. /**
  73. * Fetch content from file path or url
  74. * This method exists so you can override it with your own logic.
  75. * @function
  76. * @param {string} path File path or url
  77. * @param {FetchCallback} callback Callback function
  78. * @returns {undefined}
  79. */
  80. Root.prototype.fetch = util.fetch;
  81. // A symbol-like function to safely signal synchronous loading
  82. /* istanbul ignore next */
  83. function SYNC() {} // eslint-disable-line no-empty-function
  84. /**
  85. * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
  86. * @param {string|string[]} filename Names of one or multiple files to load
  87. * @param {IParseOptions} options Parse options
  88. * @param {LoadCallback} callback Callback function
  89. * @returns {undefined}
  90. */
  91. Root.prototype.load = function load(filename, options, callback) {
  92. if (typeof options === "function") {
  93. callback = options;
  94. options = undefined;
  95. }
  96. var self = this;
  97. if (!callback) {
  98. return util.asPromise(load, self, filename, options);
  99. }
  100. var sync = callback === SYNC; // undocumented
  101. // Finishes loading by calling the callback (exactly once)
  102. function finish(err, root) {
  103. /* istanbul ignore if */
  104. if (!callback) {
  105. return;
  106. }
  107. if (sync) {
  108. throw err;
  109. }
  110. if (root) {
  111. root.resolveAll();
  112. }
  113. var cb = callback;
  114. callback = null;
  115. cb(err, root);
  116. }
  117. // Bundled definition existence checking
  118. function getBundledFileName(filename) {
  119. var idx = filename.lastIndexOf("google/protobuf/");
  120. if (idx > -1) {
  121. var altname = filename.substring(idx);
  122. if (Object.prototype.hasOwnProperty.call(common, altname)) return altname;
  123. }
  124. if (Object.prototype.hasOwnProperty.call(common, filename)) return filename;
  125. return null;
  126. }
  127. // Processes a single file
  128. function process(filename, source, depth) {
  129. if (depth === undefined)
  130. depth = 0;
  131. try {
  132. if (depth > util.recursionLimit)
  133. throw Error("max depth exceeded");
  134. if (util.isString(source) && source.charAt(0) === "{")
  135. source = JSON.parse(source);
  136. if (!util.isString(source))
  137. self.setOptions(source.options).addJSON(source.nested);
  138. else {
  139. parse.filename = filename;
  140. var parsed = parse(source, self, options),
  141. resolved,
  142. i = 0;
  143. if (parsed.imports)
  144. for (; i < parsed.imports.length; ++i)
  145. if (resolved = getBundledFileName(parsed.imports[i]) || self.resolvePath(filename, parsed.imports[i]))
  146. fetch(resolved, false, depth + 1);
  147. if (parsed.weakImports)
  148. for (i = 0; i < parsed.weakImports.length; ++i)
  149. if (resolved = getBundledFileName(parsed.weakImports[i]) || self.resolvePath(filename, parsed.weakImports[i]))
  150. fetch(resolved, true, depth + 1);
  151. }
  152. } catch (err) {
  153. finish(err);
  154. }
  155. if (!sync && !queued) {
  156. finish(null, self); // only once anyway
  157. }
  158. }
  159. // Fetches a single file
  160. function fetch(filename, weak, depth) {
  161. if (depth === undefined)
  162. depth = 0;
  163. filename = getBundledFileName(filename) || filename;
  164. // Skip if already loaded / attempted
  165. if (self.files.indexOf(filename) > -1) {
  166. return;
  167. }
  168. self.files.push(filename);
  169. // Shortcut bundled definitions
  170. if (Object.prototype.hasOwnProperty.call(common, filename)) {
  171. if (sync) {
  172. process(filename, common[filename], depth);
  173. } else {
  174. ++queued;
  175. setTimeout(function() {
  176. --queued;
  177. process(filename, common[filename], depth);
  178. });
  179. }
  180. return;
  181. }
  182. // Otherwise fetch from disk or network
  183. if (sync) {
  184. var source;
  185. try {
  186. source = util.fs.readFileSync(filename).toString("utf8");
  187. } catch (err) {
  188. if (!weak)
  189. finish(err);
  190. return;
  191. }
  192. process(filename, source, depth);
  193. } else {
  194. ++queued;
  195. self.fetch(filename, function(err, source) {
  196. --queued;
  197. /* istanbul ignore if */
  198. if (!callback) {
  199. return; // terminated meanwhile
  200. }
  201. if (err) {
  202. /* istanbul ignore else */
  203. if (!weak)
  204. finish(err);
  205. else if (!queued) // can't be covered reliably
  206. finish(null, self);
  207. return;
  208. }
  209. process(filename, source, depth);
  210. });
  211. }
  212. }
  213. var queued = 0;
  214. // Assembling the root namespace doesn't require working type
  215. // references anymore, so we can load everything in parallel
  216. if (util.isString(filename)) {
  217. filename = [ filename ];
  218. }
  219. for (var i = 0, resolved; i < filename.length; ++i)
  220. if (resolved = self.resolvePath("", filename[i]))
  221. fetch(resolved);
  222. if (sync) {
  223. self.resolveAll();
  224. return self;
  225. }
  226. if (!queued) {
  227. finish(null, self);
  228. }
  229. return self;
  230. };
  231. // function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined
  232. /**
  233. * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
  234. * @function Root#load
  235. * @param {string|string[]} filename Names of one or multiple files to load
  236. * @param {LoadCallback} callback Callback function
  237. * @returns {undefined}
  238. * @variation 2
  239. */
  240. // function load(filename:string, callback:LoadCallback):undefined
  241. /**
  242. * Loads one or multiple .proto or preprocessed .json files into this root namespace and returns a promise.
  243. * @function Root#load
  244. * @param {string|string[]} filename Names of one or multiple files to load
  245. * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
  246. * @returns {Promise<Root>} Promise
  247. * @variation 3
  248. */
  249. // function load(filename:string, [options:IParseOptions]):Promise<Root>
  250. /**
  251. * Synchronously loads one or multiple .proto or preprocessed .json files into this root namespace (node only).
  252. * @function Root#loadSync
  253. * @param {string|string[]} filename Names of one or multiple files to load
  254. * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
  255. * @returns {Root} Root namespace
  256. * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
  257. */
  258. Root.prototype.loadSync = function loadSync(filename, options) {
  259. if (!util.isNode)
  260. throw Error("not supported");
  261. return this.load(filename, options, SYNC);
  262. };
  263. /**
  264. * @override
  265. */
  266. Root.prototype.resolveAll = function resolveAll() {
  267. if (!this._needsRecursiveResolve) return this;
  268. if (this.deferred.length)
  269. throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
  270. return "'extend " + field.extend + "' in " + field.parent.fullName;
  271. }).join(", "));
  272. return Namespace.prototype.resolveAll.call(this);
  273. };
  274. // only uppercased (and thus conflict-free) children are exposed, see below
  275. var exposeRe = /^[A-Z]/;
  276. /**
  277. * Handles a deferred declaring extension field by creating a sister field to represent it within its extended type.
  278. * @param {Root} root Root instance
  279. * @param {Field} field Declaring extension field witin the declaring type
  280. * @returns {boolean} `true` if successfully added to the extended type, `false` otherwise
  281. * @inner
  282. * @ignore
  283. */
  284. function tryHandleExtension(root, field) {
  285. var extendedType = field.parent.lookup(field.extend);
  286. if (extendedType) {
  287. var sisterField = new Field(field.fullName, field.id, field.type, field.rule, undefined, field.options);
  288. //do not allow to extend same field twice to prevent the error
  289. if (extendedType.get(sisterField.name)) {
  290. return true;
  291. }
  292. sisterField.declaringField = field;
  293. field.extensionField = sisterField;
  294. extendedType.add(sisterField);
  295. return true;
  296. }
  297. return false;
  298. }
  299. /**
  300. * Called when any object is added to this root or its sub-namespaces.
  301. * @param {ReflectionObject} object Object added
  302. * @returns {undefined}
  303. * @private
  304. */
  305. Root.prototype._handleAdd = function _handleAdd(object) {
  306. if (object instanceof Field) {
  307. if (/* an extension field (implies not part of a oneof) */ object.extend !== undefined && /* not already handled */ !object.extensionField)
  308. if (!tryHandleExtension(this, object))
  309. this.deferred.push(object);
  310. } else if (object instanceof Enum) {
  311. if (exposeRe.test(object.name))
  312. object.parent[object.name] = object.values; // expose enum values as property of its parent
  313. } else if (!(object instanceof OneOf)) /* everything else is a namespace */ {
  314. if (object instanceof Type) // Try to handle any deferred extensions
  315. for (var i = 0; i < this.deferred.length;)
  316. if (tryHandleExtension(this, this.deferred[i]))
  317. this.deferred.splice(i, 1);
  318. else
  319. ++i;
  320. for (var j = 0; j < /* initializes */ object.nestedArray.length; ++j) // recurse into the namespace
  321. this._handleAdd(object._nestedArray[j]);
  322. if (exposeRe.test(object.name))
  323. object.parent[object.name] = object; // expose namespace as property of its parent
  324. }
  325. if (object instanceof Type || object instanceof Enum || object instanceof Field) {
  326. // Only store types and enums for quick lookup during resolve.
  327. this._fullyQualifiedObjects[object.fullName] = object;
  328. }
  329. // The above also adds uppercased (and thus conflict-free) nested types, services and enums as
  330. // properties of namespaces just like static code does. This allows using a .d.ts generated for
  331. // a static module with reflection-based solutions where the condition is met.
  332. };
  333. /**
  334. * Called when any object is removed from this root or its sub-namespaces.
  335. * @param {ReflectionObject} object Object removed
  336. * @returns {undefined}
  337. * @private
  338. */
  339. Root.prototype._handleRemove = function _handleRemove(object) {
  340. if (object instanceof Field) {
  341. if (/* an extension field */ object.extend !== undefined) {
  342. if (/* already handled */ object.extensionField) { // remove its sister field
  343. object.extensionField.parent.remove(object.extensionField);
  344. object.extensionField = null;
  345. } else { // cancel the extension
  346. var index = this.deferred.indexOf(object);
  347. /* istanbul ignore else */
  348. if (index > -1)
  349. this.deferred.splice(index, 1);
  350. }
  351. }
  352. } else if (object instanceof Enum) {
  353. if (exposeRe.test(object.name))
  354. delete object.parent[object.name]; // unexpose enum values
  355. } else if (object instanceof Namespace) {
  356. for (var i = 0; i < /* initializes */ object.nestedArray.length; ++i) // recurse into the namespace
  357. this._handleRemove(object._nestedArray[i]);
  358. if (exposeRe.test(object.name))
  359. delete object.parent[object.name]; // unexpose namespaces
  360. }
  361. delete this._fullyQualifiedObjects[object.fullName];
  362. };
  363. // Sets up cyclic dependencies (called in index-light)
  364. Root._configure = function(Type_, parse_, common_) {
  365. Type = Type_;
  366. parse = parse_;
  367. common = common_;
  368. };