dx.vectormaputils.node.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /*!
  2. * DevExtreme (dx.vectormaputils.node.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. function noop() {}
  11. function eigen(x) {
  12. return x
  13. }
  14. function isFunction(target) {
  15. return "function" === typeof target
  16. }
  17. function wrapSource(source) {
  18. var stream, buffer = wrapBuffer(source),
  19. position = 0;
  20. stream = {
  21. pos: function() {
  22. return position
  23. },
  24. skip: function(count) {
  25. position += count;
  26. return stream
  27. },
  28. ui8arr: function(length) {
  29. var i = 0,
  30. list = [];
  31. list.length = length;
  32. for (; i < length; ++i) {
  33. list[i] = stream.ui8()
  34. }
  35. return list
  36. },
  37. ui8: function() {
  38. var val = ui8(buffer, position);
  39. position += 1;
  40. return val
  41. },
  42. ui16LE: function() {
  43. var val = ui16LE(buffer, position);
  44. position += 2;
  45. return val
  46. },
  47. ui32LE: function() {
  48. var val = ui32LE(buffer, position);
  49. position += 4;
  50. return val
  51. },
  52. ui32BE: function() {
  53. var val = ui32BE(buffer, position);
  54. position += 4;
  55. return val
  56. },
  57. f64LE: function() {
  58. var val = f64LE(buffer, position);
  59. position += 8;
  60. return val
  61. }
  62. };
  63. return stream
  64. }
  65. function parseCore(source, roundCoordinates, errors) {
  66. var result, shapeData = source[0] ? parseShape(wrapSource(source[0]), errors) : {},
  67. dataBaseFileData = source[1] ? parseDBF(wrapSource(source[1]), errors) : {},
  68. features = buildFeatures(shapeData.shapes || [], dataBaseFileData.records || [], roundCoordinates);
  69. if (features.length) {
  70. result = {
  71. type: "FeatureCollection",
  72. features: features
  73. };
  74. result.bbox = shapeData.bBox
  75. } else {
  76. result = null
  77. }
  78. return result
  79. }
  80. function buildFeatures(shapeData, dataBaseFileData, roundCoordinates) {
  81. var i, shape, features = [],
  82. ii = features.length = ii = Math.max(shapeData.length, dataBaseFileData.length);
  83. for (i = 0; i < ii; ++i) {
  84. shape = shapeData[i] || {};
  85. features[i] = {
  86. type: "Feature",
  87. geometry: {
  88. type: shape.geoJSON_type || null,
  89. coordinates: shape.coordinates ? roundCoordinates(shape.coordinates) : []
  90. },
  91. properties: dataBaseFileData[i] || null
  92. }
  93. }
  94. return features
  95. }
  96. function createCoordinatesRounder(precision) {
  97. var factor = Number("1E" + precision);
  98. function round(x) {
  99. return Math.round(x * factor) / factor
  100. }
  101. function process(values) {
  102. return values.map(values[0].length ? process : round)
  103. }
  104. return process
  105. }
  106. function buildParseArgs(source) {
  107. source = source || {};
  108. return ["shp", "dbf"].map(function(key) {
  109. return function(done) {
  110. if (source.substr) {
  111. key = "." + key;
  112. sendRequest(source + (source.substr(-key.length).toLowerCase() === key ? "" : key), function(e, response) {
  113. done(e, response)
  114. })
  115. } else {
  116. done(null, source[key] || null)
  117. }
  118. }
  119. })
  120. }
  121. function parse(source, parameters, callback) {
  122. var result;
  123. when(buildParseArgs(source), function(errorArray, dataArray) {
  124. callback = isFunction(parameters) && parameters || isFunction(callback) && callback || noop;
  125. parameters = !isFunction(parameters) && parameters || {};
  126. var errors = [];
  127. errorArray.forEach(function(e) {
  128. e && errors.push(e)
  129. });
  130. result = parseCore(dataArray, parameters.precision >= 0 ? createCoordinatesRounder(parameters.precision) : eigen, errors);
  131. callback(result, errors.length ? errors : null)
  132. });
  133. return result
  134. }
  135. exports.parse = parse;
  136. function when(actions, callback) {
  137. var errorArray = [],
  138. dataArray = [],
  139. counter = 1,
  140. lock = true;
  141. actions.forEach(function(action, i) {
  142. ++counter;
  143. action(function(e, data) {
  144. errorArray[i] = e;
  145. dataArray[i] = data;
  146. massDone()
  147. })
  148. });
  149. lock = false;
  150. massDone();
  151. function massDone() {
  152. --counter;
  153. if (0 === counter && !lock) {
  154. callback(errorArray, dataArray)
  155. }
  156. }
  157. }
  158. function parseShape(stream, errors) {
  159. var timeStart, timeEnd, header, record, records = [];
  160. try {
  161. timeStart = new Date;
  162. header = parseShapeHeader(stream)
  163. } catch (e) {
  164. errors.push("shp: header parsing error: " + e.message + " / " + e.description);
  165. return
  166. }
  167. if (9994 !== header.fileCode) {
  168. errors.push("shp: file code: " + header.fileCode + " / expected: 9994")
  169. }
  170. if (1e3 !== header.version) {
  171. errors.push("shp: file version: " + header.version + " / expected: 1000")
  172. }
  173. try {
  174. while (stream.pos() < header.fileLength) {
  175. record = parseShapeRecord(stream, header.type, errors);
  176. if (record) {
  177. records.push(record)
  178. } else {
  179. break
  180. }
  181. }
  182. if (stream.pos() !== header.fileLength) {
  183. errors.push("shp: file length: " + header.fileLength + " / actual: " + stream.pos())
  184. }
  185. timeEnd = new Date
  186. } catch (e) {
  187. errors.push("shp: records parsing error: " + e.message + " / " + e.description)
  188. }
  189. return {
  190. bBox: header.bBox_XY,
  191. type: header.shapeType,
  192. shapes: records,
  193. errors: errors,
  194. time: timeEnd - timeStart
  195. }
  196. }
  197. function readPointShape(stream, record) {
  198. record.coordinates = readPointArray(stream, 1)[0]
  199. }
  200. function readPolyLineShape(stream, record) {
  201. var i, bBox = readBBox(stream),
  202. numParts = readInteger(stream),
  203. numPoints = readInteger(stream),
  204. parts = readIntegerArray(stream, numParts),
  205. points = readPointArray(stream, numPoints),
  206. rings = [];
  207. rings.length = numParts;
  208. for (i = 0; i < numParts; ++i) {
  209. rings[i] = points.slice(parts[i], parts[i + 1] || numPoints)
  210. }
  211. record.bBox = bBox;
  212. record.coordinates = rings
  213. }
  214. function readMultiPointShape(stream, record) {
  215. record.bBox = readBBox(stream);
  216. record.coordinates = readPointArray(stream, readInteger(stream))
  217. }
  218. function readPointMShape(stream, record) {
  219. record.coordinates = readPointArray(stream, 1)[0];
  220. record.coordinates.push(readDoubleArray(stream, 1)[0])
  221. }
  222. function readMultiPointMShape(stream, record) {
  223. var bBox = readBBox(stream),
  224. numPoints = readInteger(stream),
  225. points = readPointArray(stream, numPoints),
  226. mBox = readPair(stream),
  227. mValues = readDoubleArray(stream, numPoints);
  228. record.bBox = bBox;
  229. record.mBox = mBox;
  230. record.coordinates = merge_XYM(points, mValues, numPoints)
  231. }
  232. function readPolyLineMShape(stream, record) {
  233. var i, from, to, bBox = readBBox(stream),
  234. numParts = readInteger(stream),
  235. numPoints = readInteger(stream),
  236. parts = readIntegerArray(stream, numParts),
  237. points = readPointArray(stream, numPoints),
  238. mBox = readPair(stream),
  239. mValues = readDoubleArray(stream, numPoints),
  240. rings = [];
  241. rings.length = numParts;
  242. for (i = 0; i < numParts; ++i) {
  243. from = parts[i];
  244. to = parts[i + 1] || numPoints;
  245. rings[i] = merge_XYM(points.slice(from, to), mValues.slice(from, to), to - from)
  246. }
  247. record.bBox = bBox;
  248. record.mBox = mBox;
  249. record.coordinates = rings
  250. }
  251. function readPointZShape(stream, record) {
  252. record.coordinates = readPointArray(stream, 1)[0];
  253. record.push(readDoubleArray(stream, 1)[0], readDoubleArray(stream, 1)[0])
  254. }
  255. function readMultiPointZShape(stream, record) {
  256. var bBox = readBBox(stream),
  257. numPoints = readInteger(stream),
  258. points = readPointArray(stream, numPoints),
  259. zBox = readPair(stream),
  260. zValues = readDoubleArray(stream, numPoints),
  261. mBox = readPair(stream),
  262. mValue = readDoubleArray(stream, numPoints);
  263. record.bBox = bBox;
  264. record.zBox = zBox;
  265. record.mBox = mBox;
  266. record.coordinates = merge_XYZM(points, zValues, mValue, numPoints)
  267. }
  268. function readPolyLineZShape(stream, record) {
  269. var i, from, to, bBox = readBBox(stream),
  270. numParts = readInteger(stream),
  271. numPoints = readInteger(stream),
  272. parts = readIntegerArray(stream, numParts),
  273. points = readPointArray(stream, numPoints),
  274. zBox = readPair(stream),
  275. zValues = readDoubleArray(stream, numPoints),
  276. mBox = readPair(stream),
  277. mValues = readDoubleArray(stream, numPoints),
  278. rings = [];
  279. rings.length = numParts;
  280. for (i = 0; i < numParts; ++i) {
  281. from = parts[i];
  282. to = parts[i + 1] || numPoints;
  283. rings[i] = merge_XYZM(points.slice(from, to), zValues.slice(from, to), mValues.slice(from, to), to - from)
  284. }
  285. record.bBox = bBox;
  286. record.zBox = zBox;
  287. record.mBox = mBox;
  288. record.coordinates = rings
  289. }
  290. function readMultiPatchShape(stream, record) {
  291. var i, from, to, bBox = readBBox(stream),
  292. numParts = readInteger(stream),
  293. numPoints = readInteger(stream),
  294. parts = readIntegerArray(stream, numParts),
  295. partTypes = readIntegerArray(stream, numParts),
  296. points = readPointArray(stream, numPoints),
  297. zBox = readPair(stream),
  298. zValues = readDoubleArray(stream, numPoints),
  299. mBox = readPair(stream),
  300. rings = [];
  301. rings.length = numParts;
  302. for (i = 0; i < numParts; ++i) {
  303. from = parts[i];
  304. to = parts[i + 1] || numPoints;
  305. rings[i] = merge_XYZM(points.slice(from, to), zValues.slice(from, to), mValues.slice(from, to), to - from)
  306. }
  307. record.bBox = bBox;
  308. record.zBox = zBox;
  309. record.mBox = mBox;
  310. record.types = partTypes;
  311. record.coordinates = rings
  312. }
  313. var SHP_TYPES = {
  314. 0: "Null",
  315. 1: "Point",
  316. 3: "PolyLine",
  317. 5: "Polygon",
  318. 8: "MultiPoint",
  319. 11: "PointZ",
  320. 13: "PolyLineZ",
  321. 15: "PolygonZ",
  322. 18: "MultiPointZ",
  323. 21: "PointM",
  324. 23: "PolyLineM",
  325. 25: "PolygonM",
  326. 28: "MultiPointM",
  327. 31: "MultiPatch"
  328. };
  329. var SHP_RECORD_PARSERS = {
  330. 0: noop,
  331. 1: readPointShape,
  332. 3: readPolyLineShape,
  333. 5: readPolyLineShape,
  334. 8: readMultiPointShape,
  335. 11: readPointZShape,
  336. 13: readPolyLineZShape,
  337. 15: readPolyLineZShape,
  338. 18: readMultiPointZShape,
  339. 21: readPointMShape,
  340. 23: readPolyLineMShape,
  341. 25: readPolyLineMShape,
  342. 28: readMultiPointMShape,
  343. 31: readMultiPatchShape
  344. };
  345. var SHP_TYPE_TO_GEOJSON_TYPE_MAP = {
  346. Null: "Null",
  347. Point: "Point",
  348. PolyLine: "MultiLineString",
  349. Polygon: "Polygon",
  350. MultiPoint: "MultiPoint",
  351. PointZ: "Point",
  352. PolyLineZ: "MultiLineString",
  353. PolygonZ: "Polygon",
  354. MultiPointZ: "MultiPoint",
  355. PointM: "Point",
  356. PolyLineM: "MultiLineString",
  357. PolygonM: "Polygon",
  358. MultiPointM: "MultiPoint",
  359. MultiPatch: "MultiPatch"
  360. };
  361. function parseShapeHeader(stream) {
  362. var header = {};
  363. header.fileCode = stream.ui32BE();
  364. stream.skip(20);
  365. header.fileLength = stream.ui32BE() << 1;
  366. header.version = stream.ui32LE();
  367. header.type_number = stream.ui32LE();
  368. header.type = SHP_TYPES[header.type_number];
  369. header.bBox_XY = readBBox(stream);
  370. header.bBox_ZM = readPointArray(stream, 2);
  371. return header
  372. }
  373. function readInteger(stream) {
  374. return stream.ui32LE()
  375. }
  376. function readIntegerArray(stream, length) {
  377. var i, array = [];
  378. array.length = length;
  379. for (i = 0; i < length; ++i) {
  380. array[i] = readInteger(stream)
  381. }
  382. return array
  383. }
  384. function readDoubleArray(stream, length) {
  385. var i, array = [];
  386. array.length = length;
  387. for (i = 0; i < length; ++i) {
  388. array[i] = stream.f64LE()
  389. }
  390. return array
  391. }
  392. function readBBox(stream) {
  393. return readDoubleArray(stream, 4)
  394. }
  395. function readPair(stream) {
  396. return [stream.f64LE(), stream.f64LE()]
  397. }
  398. function readPointArray(stream, count) {
  399. var i, points = [];
  400. points.length = count;
  401. for (i = 0; i < count; ++i) {
  402. points[i] = readPair(stream)
  403. }
  404. return points
  405. }
  406. function merge_XYM(xy, m, length) {
  407. var i, array = [];
  408. array.length = length;
  409. for (i = 0; i < length; ++i) {
  410. array[i] = [xy[i][0], xy[i][1], m[i]]
  411. }
  412. return array
  413. }
  414. function merge_XYZM(xy, z, m, length) {
  415. var i, array = [];
  416. array.length = length;
  417. for (i = 0; i < length; ++i) {
  418. array[i] = [xy[i][0], xy[i][1], z[i], m[i]]
  419. }
  420. return array
  421. }
  422. function parseShapeRecord(stream, generalType, errors) {
  423. var record = {
  424. number: stream.ui32BE()
  425. },
  426. length = stream.ui32BE() << 1,
  427. pos = stream.pos(),
  428. type = stream.ui32LE();
  429. record.type_number = type;
  430. record.type = SHP_TYPES[type];
  431. record.geoJSON_type = SHP_TYPE_TO_GEOJSON_TYPE_MAP[record.type];
  432. if (record.type) {
  433. if (record.type !== generalType) {
  434. errors.push("shp: shape #" + record.number + " type: " + record.type + " / expected: " + generalType)
  435. }
  436. SHP_RECORD_PARSERS[type](stream, record);
  437. pos = stream.pos() - pos;
  438. if (pos !== length) {
  439. errors.push("shp: shape #" + record.number + " length: " + length + " / actual: " + pos)
  440. }
  441. } else {
  442. errors.push("shp: shape #" + record.number + " type: " + type + " / unknown");
  443. record = null
  444. }
  445. return record
  446. }
  447. function parseDBF(stream, errors) {
  448. var timeStart, timeEnd, header, parseData, records;
  449. try {
  450. timeStart = new Date;
  451. header = parseDataBaseFileHeader(stream, errors);
  452. parseData = prepareDataBaseFileRecordParseData(header, errors);
  453. records = parseDataBaseFileRecords(stream, header.numberOfRecords, header.recordLength, parseData, errors);
  454. timeEnd = new Date
  455. } catch (e) {
  456. errors.push("dbf: parsing error: " + e.message + " / " + e.description)
  457. }
  458. return {
  459. records: records,
  460. errors: errors,
  461. time: timeEnd - timeStart
  462. }
  463. }
  464. function parseDataBaseFileHeader(stream, errors) {
  465. var i, term, header = {
  466. versionNumber: stream.ui8(),
  467. lastUpdate: new Date(1900 + stream.ui8(), stream.ui8() - 1, stream.ui8()),
  468. numberOfRecords: stream.ui32LE(),
  469. headerLength: stream.ui16LE(),
  470. recordLength: stream.ui16LE(),
  471. fields: []
  472. };
  473. stream.skip(20);
  474. for (i = (header.headerLength - stream.pos() - 1) / 32; i > 0; --i) {
  475. header.fields.push(parseFieldDescriptor(stream))
  476. }
  477. term = stream.ui8();
  478. if (13 !== term) {
  479. errors.push("dbf: header terminator: " + term + " / expected: 13")
  480. }
  481. return header
  482. }
  483. var _fromCharCode = String.fromCharCode;
  484. function getAsciiString(stream, length) {
  485. return _fromCharCode.apply(null, stream.ui8arr(length))
  486. }
  487. function parseFieldDescriptor(stream) {
  488. var desc = {
  489. name: getAsciiString(stream, 11).replace(/\0*$/gi, ""),
  490. type: _fromCharCode(stream.ui8()),
  491. length: stream.skip(4).ui8(),
  492. count: stream.ui8()
  493. };
  494. stream.skip(14);
  495. return desc
  496. }
  497. var DBF_FIELD_PARSERS = {
  498. C: function(stream, length) {
  499. var str = getAsciiString(stream, length);
  500. try {
  501. str = decodeURIComponent(escape(str))
  502. } catch (e) {}
  503. return str.trim()
  504. },
  505. N: function(stream, length) {
  506. var str = getAsciiString(stream, length);
  507. return parseFloat(str, 10)
  508. },
  509. D: function(stream, length) {
  510. var str = getAsciiString(stream, length);
  511. return new Date(str.substring(0, 4), str.substring(4, 6) - 1, str.substring(6, 8))
  512. }
  513. };
  514. function DBF_FIELD_PARSER_DEFAULT(stream, length) {
  515. stream.skip(length);
  516. return null
  517. }
  518. function prepareDataBaseFileRecordParseData(header, errors) {
  519. var item, field, list = [],
  520. i = 0,
  521. ii = header.fields.length,
  522. totalLength = 0;
  523. for (i = 0; i < ii; ++i) {
  524. field = header.fields[i];
  525. item = {
  526. name: field.name,
  527. parser: DBF_FIELD_PARSERS[field.type],
  528. length: field.length
  529. };
  530. if (!item.parser) {
  531. item.parser = DBF_FIELD_PARSER_DEFAULT;
  532. errors.push("dbf: field " + field.name + " type: " + field.type + " / unknown")
  533. }
  534. totalLength += field.length;
  535. list.push(item)
  536. }
  537. if (totalLength + 1 !== header.recordLength) {
  538. errors.push("dbf: record length: " + header.recordLength + " / actual: " + (totalLength + 1))
  539. }
  540. return list
  541. }
  542. function parseDataBaseFileRecords(stream, recordCount, recordLength, parseData, errors) {
  543. var i, j, pos, record, pd, jj = parseData.length,
  544. records = [];
  545. for (i = 0; i < recordCount; ++i) {
  546. record = {};
  547. pos = stream.pos();
  548. stream.skip(1);
  549. for (j = 0; j < jj; ++j) {
  550. pd = parseData[j];
  551. record[pd.name] = pd.parser(stream, pd.length)
  552. }
  553. pos = stream.pos() - pos;
  554. if (pos !== recordLength) {
  555. errors.push("dbf: record #" + (i + 1) + " length: " + recordLength + " / actual: " + pos)
  556. }
  557. records.push(record)
  558. }
  559. return records
  560. }
  561. function wrapBuffer(buffer) {
  562. return buffer
  563. }
  564. function ui8(stream, position) {
  565. return stream[position]
  566. }
  567. function ui16LE(stream, position) {
  568. return stream.readUInt16LE(position)
  569. }
  570. function ui32LE(stream, position) {
  571. return stream.readUInt32LE(position)
  572. }
  573. function ui32BE(stream, position) {
  574. return stream.readUInt32BE(position)
  575. }
  576. function f64LE(stream, position) {
  577. return stream.readDoubleLE(position)
  578. }
  579. var fs = require("fs");
  580. function sendRequest(path, callback) {
  581. fs.readFile(path, callback)
  582. }
  583. var path = require("path");
  584. function normalizeJsName(value) {
  585. return value.trim().replace("-", "_").replace(" ", "_")
  586. }
  587. function processFile(file, options, callback) {
  588. var name = path.basename(file, path.extname(file));
  589. options.info("%s: started", name);
  590. parse(file, {
  591. precision: options.precision
  592. }, function(shapeData, errors) {
  593. var content;
  594. options.info("%s: finished", name);
  595. errors && errors.forEach(function(e) {
  596. options.error(" " + e)
  597. });
  598. if (shapeData) {
  599. content = JSON.stringify(options.processData(shapeData), null, options.isDebug && 4);
  600. if (!options.isJSON) {
  601. content = options.processFileContent(content, normalizeJsName(name))
  602. }
  603. fs.writeFile(path.resolve(options.output || path.dirname(file), options.processFileName(name + (options.isJSON ? ".json" : ".js"))), content, function(e) {
  604. e && options.error(" " + e.message);
  605. callback()
  606. })
  607. } else {
  608. callback()
  609. }
  610. })
  611. }
  612. function collectFiles(dir, done) {
  613. var input = path.resolve(dir || "");
  614. fs.stat(input, function(e, stat) {
  615. if (e) {
  616. done(e, [])
  617. } else {
  618. if (stat.isFile()) {
  619. done(null, checkFile(input) ? [path.resolve(path.dirname(input), normalizeFile(input))] : [])
  620. } else {
  621. if (stat.isDirectory()) {
  622. fs.readdir(input, function(e, dirItems) {
  623. var list = [];
  624. dirItems.forEach(function(dirItem) {
  625. if (checkFile(dirItem)) {
  626. list.push(path.resolve(input, normalizeFile(dirItem)))
  627. }
  628. });
  629. done(null, list)
  630. })
  631. } else {
  632. done(null, [])
  633. }
  634. }
  635. }
  636. });
  637. function checkFile(name) {
  638. return ".shp" === path.extname(name).toLowerCase()
  639. }
  640. function normalizeFile(name) {
  641. return path.basename(name, ".shp")
  642. }
  643. }
  644. function importFile(file) {
  645. var content;
  646. try {
  647. content = require(path.resolve(String(file)))
  648. } catch (_) {}
  649. return content
  650. }
  651. function pickFunctionOption(value) {
  652. return isFunction(value) && value || value && importFile(String(value)) || null
  653. }
  654. function processFileContentByDefault(content, name) {
  655. return name + " = " + content + ";"
  656. }
  657. function prepareSettings(source, options) {
  658. options = Object.assign({}, options);
  659. if (options.settings) {
  660. options = Object.assign(importFile(options.settings) || {}, options)
  661. }
  662. return Object.assign(options, {
  663. input: source ? String(source) : null,
  664. output: options.output ? String(options.output) : null,
  665. precision: options.precision >= 0 ? Math.round(options.precision) : 4,
  666. processData: pickFunctionOption(options.processData) || eigen,
  667. processFileName: pickFunctionOption(options.processFileName) || eigen,
  668. processFileContent: pickFunctionOption(options.processFileContent) || processFileContentByDefault,
  669. info: options.isQuiet ? noop : console.info.bind(console),
  670. error: options.isQuiet ? noop : console.error.bind(console)
  671. })
  672. }
  673. function processFiles(source, options, callback) {
  674. var settings = prepareSettings(source, options && options.trim ? importFile(options) : options);
  675. settings.info("Started");
  676. collectFiles(settings.input, function(e, files) {
  677. e && settings.error(e.message);
  678. settings.info(files.map(function(file) {
  679. return " " + path.basename(file)
  680. }).join("\n"));
  681. when(files.map(function(file) {
  682. return function(done) {
  683. processFile(file, settings, done)
  684. }
  685. }), function() {
  686. settings.info("Finished");
  687. (isFunction(callback) ? callback : noop)()
  688. })
  689. })
  690. }
  691. exports.processFiles = processFiles;
  692. var COMMAND_LINE_ARG_KEYS = [{
  693. key: "--output",
  694. name: "output",
  695. arg: true,
  696. desc: "Destination directory"
  697. }, {
  698. key: "--process-data",
  699. name: "processData",
  700. arg: true,
  701. desc: "Process parsed data"
  702. }, {
  703. key: "--process-file-name",
  704. name: "processFileName",
  705. arg: true,
  706. desc: "Process output file name"
  707. }, {
  708. key: "--process-file-content",
  709. name: "processFileContent",
  710. arg: true,
  711. desc: "Process output file content"
  712. }, {
  713. key: "--precision",
  714. name: "precision",
  715. arg: true,
  716. desc: "Precision of shape coordinates"
  717. }, {
  718. key: "--json",
  719. name: "isJSON",
  720. desc: "Generate as a .json file"
  721. }, {
  722. key: "--debug",
  723. name: "isDebug",
  724. desc: "Generate non minified file"
  725. }, {
  726. key: "--quiet",
  727. name: "isQuiet",
  728. desc: "Suppress console output"
  729. }, {
  730. key: "--settings",
  731. name: "settings",
  732. arg: true,
  733. desc: "Path to settings file"
  734. }, {
  735. key: "--help",
  736. name: "isHelp",
  737. desc: "Print help"
  738. }];
  739. function parseCommandLineArgs() {
  740. var args = process.argv.slice(2),
  741. options = {
  742. isEmpty: !args.length
  743. },
  744. map = {};
  745. args.forEach(function(arg, i) {
  746. map[arg] = args[i + 1] || true
  747. });
  748. COMMAND_LINE_ARG_KEYS.forEach(function(info) {
  749. var val = map[info.key];
  750. if (val) {
  751. options[info.name] = info.arg ? val : true
  752. }
  753. });
  754. if (options.isHelp || options.isEmpty) {
  755. options = null;
  756. printCommandLineHelp()
  757. }
  758. return options
  759. }
  760. function printCommandLineHelp() {
  761. var message, parts = ["node ", path.basename(process.argv[1]), " Source "],
  762. lines = [],
  763. maxLength = Math.max.apply(null, COMMAND_LINE_ARG_KEYS.map(function(info) {
  764. return info.key.length
  765. })) + 2;
  766. COMMAND_LINE_ARG_KEYS.forEach(function(info) {
  767. var key = info.key;
  768. parts.push(key, " ");
  769. if (info.arg) {
  770. parts.push("<", key.slice(2), ">", " ")
  771. }
  772. lines.push([" ", key, Array(maxLength - key.length).join(" "), info.desc].join(""))
  773. });
  774. message = ["Generates dxVectorMap-compatible files from shapefiles.", "\n", parts.join("")].concat(lines).join("\n");
  775. console.log(message)
  776. }
  777. function runFromConsole() {
  778. var args = parseCommandLineArgs();
  779. if (args) {
  780. processFiles(process.argv[2] || "", args)
  781. }
  782. }
  783. if (require.main === module) {
  784. runFromConsole()
  785. }