text-to-map 1.0.7 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/bin/clear-all.js +21 -4
  2. package/dist/bin/init-db.d.ts +1 -0
  3. package/dist/bin/init-db.js +18 -0
  4. package/dist/bin/parse-ordinance.js +56 -42
  5. package/dist/bin/schools.js +1 -1
  6. package/dist/db/address-points.d.ts +13 -13
  7. package/dist/db/address-points.js +93 -77
  8. package/dist/db/db.d.ts +19 -10
  9. package/dist/db/db.js +124 -50
  10. package/dist/db/founders.d.ts +7 -7
  11. package/dist/db/founders.js +187 -135
  12. package/dist/db/meta.d.ts +3 -4
  13. package/dist/db/meta.js +23 -16
  14. package/dist/db/migrations/20230704125715_initial.d.ts +3 -0
  15. package/dist/db/migrations/20230704125715_initial.js +251 -0
  16. package/dist/db/regions.d.ts +5 -5
  17. package/dist/db/regions.js +40 -28
  18. package/dist/db/schools.d.ts +3 -2
  19. package/dist/db/schools.js +30 -14
  20. package/dist/db/street-sync.d.ts +4 -4
  21. package/dist/db/street-sync.js +26 -17
  22. package/dist/index.d.ts +3 -2
  23. package/dist/index.js +4 -2
  24. package/dist/open-data-sync/address-points.d.ts +0 -1
  25. package/dist/open-data-sync/address-points.js +35 -25
  26. package/dist/open-data-sync/regions.js +13 -5
  27. package/dist/open-data-sync/schools.js +19 -15
  28. package/dist/open-data-sync/streets.js +46 -33
  29. package/dist/street-markdown/municipality.d.ts +2 -2
  30. package/dist/street-markdown/municipality.js +46 -14
  31. package/dist/street-markdown/smd-line-parser.d.ts +1 -1
  32. package/dist/street-markdown/smd-line-parser.js +21 -8
  33. package/dist/street-markdown/smd.d.ts +8 -5
  34. package/dist/street-markdown/smd.js +100 -86
  35. package/dist/street-markdown/token-definition.js +6 -6
  36. package/dist/street-markdown/types.d.ts +8 -3
  37. package/dist/utils/helpers.d.ts +0 -1
  38. package/dist/utils/helpers.js +1 -8
  39. package/package.json +9 -5
@@ -11,8 +11,9 @@ import { parse } from "csv-parse";
11
11
  import iconv from "iconv-lite";
12
12
  import fetch from "node-fetch";
13
13
  import { pipeline } from "stream/promises";
14
- import { initDb, prepareOptions, } from "../utils/helpers";
15
14
  import { insertRegionsAndOrps } from "../db/regions";
15
+ import { prepareOptions } from "../utils/helpers";
16
+ import { disconnectKnex } from "../db/db";
16
17
  const downloadAndImportDataToDb = (options) => __awaiter(void 0, void 0, void 0, function* () {
17
18
  console.log("Downloading regions and ORP data...");
18
19
  const response = yield fetch(options.regionsCsvUrl);
@@ -32,11 +33,18 @@ const downloadAndImportDataToDb = (options) => __awaiter(void 0, void 0, void 0,
32
33
  // @ts-ignore
33
34
  const schema = yield schemaResponse.json();
34
35
  console.log("Parsing completed. Starting to import data to DB...");
35
- initDb(options);
36
- insertRegionsAndOrps(rows, schema);
36
+ yield insertRegionsAndOrps(rows, schema);
37
37
  console.log(`Import completed. Total imported rows: ${rows.length}`);
38
38
  });
39
39
  export const downloadAndImportRegions = (options = {}) => __awaiter(void 0, void 0, void 0, function* () {
40
- const completeOptions = prepareOptions(options);
41
- yield downloadAndImportDataToDb(completeOptions);
40
+ try {
41
+ const completeOptions = prepareOptions(options);
42
+ yield downloadAndImportDataToDb(completeOptions);
43
+ }
44
+ catch (error) {
45
+ console.log(error);
46
+ }
47
+ finally {
48
+ yield disconnectKnex();
49
+ }
42
50
  });
@@ -8,15 +8,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { createReadStream, createWriteStream, existsSync, rmSync } from "fs";
11
+ import fetch from "node-fetch";
11
12
  import { join } from "path";
12
13
  import sax from "sax";
13
- import fetch from "node-fetch";
14
- import { setDbConfig } from "../db/db";
15
- import { prepareOptions, } from "../utils/helpers";
16
14
  import { pipeline } from "stream/promises";
17
- import { MunicipalityType } from "../db/types";
18
- import { insertSchools } from "../db/schools";
15
+ import { disconnectKnex } from "../db/db";
19
16
  import { insertFounders } from "../db/founders";
17
+ import { insertSchools } from "../db/schools";
18
+ import { MunicipalityType } from "../db/types";
19
+ import { prepareOptions, } from "../utils/helpers";
20
20
  const downloadXml = (options) => __awaiter(void 0, void 0, void 0, function* () {
21
21
  if (existsSync(getXmlFilePath(options))) {
22
22
  return;
@@ -293,21 +293,25 @@ const importDataToDb = (options, saveFoundersToCsv = false, saveSchoolsWithoutRu
293
293
  });
294
294
  csv.end();
295
295
  }
296
- setDbConfig({
297
- filePath: options.dbFilePath,
298
- initFilePath: options.dbInitFilePath,
299
- });
300
- insertSchools(schools);
301
- insertFounders(Array.from(founders.values()));
296
+ yield insertSchools(schools);
297
+ yield insertFounders(Array.from(founders.values()));
302
298
  });
303
299
  const getXmlFilePath = (options) => {
304
300
  return join(options.tmpDir, options.schoolsXmlFileName);
305
301
  };
306
302
  export const downloadAndImportSchools = (options, saveFoundersToCsv = false, saveSchoolsWithoutRuianToCsv = false) => __awaiter(void 0, void 0, void 0, function* () {
307
- const runOptions = prepareOptions(options);
308
- yield downloadXml(runOptions);
309
- yield importDataToDb(runOptions, saveFoundersToCsv, saveSchoolsWithoutRuianToCsv);
310
- deleteSchoolsXmlFile(runOptions);
303
+ try {
304
+ const runOptions = prepareOptions(options);
305
+ yield downloadXml(runOptions);
306
+ yield importDataToDb(runOptions, saveFoundersToCsv, saveSchoolsWithoutRuianToCsv);
307
+ deleteSchoolsXmlFile(runOptions);
308
+ }
309
+ catch (error) {
310
+ console.error(error);
311
+ }
312
+ finally {
313
+ yield disconnectKnex();
314
+ }
311
315
  });
312
316
  export const deleteSchoolsXmlFile = (options = {}) => {
313
317
  const runOptions = prepareOptions(options);
@@ -7,15 +7,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import fetch from "node-fetch";
11
- import { createWriteStream, rmSync, existsSync, mkdirSync } from "fs";
12
- import { pipeline } from "stream/promises";
13
- import { join } from "path";
14
10
  import AdmZip from "adm-zip";
11
+ import { createWriteStream, existsSync, mkdirSync, rmSync } from "fs";
12
+ import fetch from "node-fetch";
15
13
  import parseDBF from "parsedbf";
16
- import { prepareOptions, initDb, } from "../utils/helpers";
14
+ import { join } from "path";
15
+ import { pipeline } from "stream/promises";
17
16
  import { deleteStreets, getAllSyncedStreets, insertStreetsFromDbf, setStreetAsSynced, } from "../db/street-sync";
18
17
  import { getAllUrlsFromAtomFeed, getLatestUrlFromAtomFeed, } from "../utils/atom";
18
+ import { prepareOptions, } from "../utils/helpers";
19
+ import { disconnectKnex } from "../db/db";
20
+ import { areAddressPointsSynced } from "../db/address-points";
19
21
  const prepareFolders = (options) => {
20
22
  const tempFolder = getTempFolder(options);
21
23
  if (!existsSync(tempFolder)) {
@@ -43,36 +45,47 @@ const importDataToDb = (data) => __awaiter(void 0, void 0, void 0, function* ()
43
45
  if (data.length === 0) {
44
46
  return;
45
47
  }
46
- insertStreetsFromDbf(data);
48
+ yield insertStreetsFromDbf(data);
47
49
  });
48
50
  export const downloadAndImportStreets = (options) => __awaiter(void 0, void 0, void 0, function* () {
49
- console.log("Starting to download and import streets. This takes up to 1 hour.");
50
- const completeOptions = prepareOptions(options);
51
- initDb(completeOptions);
52
- prepareFolders(completeOptions);
53
- const allDatasetFeedLinks = yield getAllUrlsFromAtomFeed(completeOptions.streetsAtomUrl);
54
- console.log(`Total of ${allDatasetFeedLinks.length} links to ZIP files.`);
55
- const syncedStreetLinks = getAllSyncedStreets();
56
- const toDelete = [];
57
- // remove all deprecated links (not in the new list)
58
- syncedStreetLinks.forEach((link) => {
59
- if (!allDatasetFeedLinks.includes(link)) {
60
- toDelete.push(link);
61
- delete syncedStreetLinks[link];
51
+ try {
52
+ // first check if address points are already synced
53
+ if (!(yield areAddressPointsSynced())) {
54
+ throw new Error("Address points are not synced yet. First run 'npm run address-points' and then try again.");
62
55
  }
63
- });
64
- deleteStreets(toDelete);
65
- let done = syncedStreetLinks.size;
66
- console.log(`Total of ${done} links to ZIP files already stored.`);
67
- // get all links not yet stored
68
- const newLinks = allDatasetFeedLinks.filter((link) => !syncedStreetLinks.has(link));
69
- console.log(`Loading ${newLinks.length} new links to ZIP files.`);
70
- for (const link of newLinks) {
71
- const zipLink = yield getLatestUrlFromAtomFeed(link);
72
- const dbfObject = yield downloadZipAndParseDbfFile(zipLink, done, completeOptions);
73
- yield importDataToDb(dbfObject);
74
- setStreetAsSynced(link);
75
- done++;
76
- console.log(`Loaded links: ${done}/${allDatasetFeedLinks.length}`);
56
+ console.log("Starting to download and import streets. This takes up to 1 hour.");
57
+ const completeOptions = prepareOptions(options);
58
+ prepareFolders(completeOptions);
59
+ const allDatasetFeedLinks = yield getAllUrlsFromAtomFeed(completeOptions.streetsAtomUrl);
60
+ console.log(`Total of ${allDatasetFeedLinks.length} links to ZIP files.`);
61
+ const syncedStreetLinks = yield getAllSyncedStreets();
62
+ const toDelete = [];
63
+ // remove all deprecated links (not in the new list)
64
+ syncedStreetLinks.forEach((link) => {
65
+ if (!allDatasetFeedLinks.includes(link)) {
66
+ toDelete.push(link);
67
+ delete syncedStreetLinks[link];
68
+ }
69
+ });
70
+ yield deleteStreets(toDelete);
71
+ let done = syncedStreetLinks.size;
72
+ console.log(`Total of ${done} links to ZIP files already stored.`);
73
+ // get all links not yet stored
74
+ const newLinks = allDatasetFeedLinks.filter((link) => !syncedStreetLinks.has(link));
75
+ console.log(`Loading ${newLinks.length} new links to ZIP files.`);
76
+ for (const link of newLinks) {
77
+ const zipLink = yield getLatestUrlFromAtomFeed(link);
78
+ const dbfObject = yield downloadZipAndParseDbfFile(zipLink, done, completeOptions);
79
+ yield importDataToDb(dbfObject);
80
+ yield setStreetAsSynced(link);
81
+ done++;
82
+ console.log(`Loaded links: ${done}/${allDatasetFeedLinks.length}`);
83
+ }
84
+ }
85
+ catch (error) {
86
+ console.log(error);
87
+ }
88
+ finally {
89
+ yield disconnectKnex();
77
90
  }
78
91
  });
@@ -1,5 +1,5 @@
1
1
  import { DbMunicipalityResult } from "./types";
2
2
  export declare const isMunicipalitySwitch: (line: string) => boolean;
3
- export declare const getSwitchMunicipality: (line: string) => DbMunicipalityResult;
3
+ export declare const getSwitchMunicipality: (line: string) => Promise<DbMunicipalityResult>;
4
4
  export declare const isWholeMunicipality: (line: string) => boolean;
5
- export declare const getWholeMunicipality: (line: string) => DbMunicipalityResult;
5
+ export declare const getWholeMunicipality: (line: string) => Promise<DbMunicipalityResult>;
@@ -1,37 +1,69 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { findMunicipalityByNameAndType } from "../db/founders";
2
11
  import { MunicipalityType } from "../db/types";
12
+ const municipalitySwitchStartPattern = /^navíc ulice /;
3
13
  const municipalitySwitchPattern = /^navíc ulice (z )?(?<type>městské části|městského obvodu|obce|města) (?<name>.+):$/;
14
+ const wholeMunicipalityStartPattern = /^území /;
4
15
  const wholeMunicipalityPattern = /^území (?<type>městské části|městského obvodu|obce|města) (?<name>.+)$/;
5
16
  export const isMunicipalitySwitch = (line) => {
6
- return municipalitySwitchPattern.test(line);
17
+ return municipalitySwitchStartPattern.test(line);
7
18
  };
8
- export const getSwitchMunicipality = (line) => {
19
+ export const getSwitchMunicipality = (line) => __awaiter(void 0, void 0, void 0, function* () {
9
20
  const match = municipalitySwitchPattern.exec(line);
10
21
  if (match === null) {
11
- throw new Error("Invalid municipality switch line");
22
+ return {
23
+ errors: [
24
+ {
25
+ message: "Neplatný zápis pro dočasnou změnu obce v definici ulic. Správný zápis je: navíc ulice <typ> <název obce>. Např.: 'navíc ulice obce Mokrá Lhota:' (název obce musí být v 1. pádě).",
26
+ startOffset: 0,
27
+ endOffset: line.length + 1,
28
+ },
29
+ ],
30
+ municipality: null,
31
+ };
12
32
  }
13
33
  const { type, name } = match.groups;
14
- return getMunicipalityResult(type, name);
15
- };
34
+ return yield getMunicipalityResult(type, name, line);
35
+ });
16
36
  export const isWholeMunicipality = (line) => {
17
- return wholeMunicipalityPattern.test(line);
37
+ return wholeMunicipalityStartPattern.test(line);
18
38
  };
19
- export const getWholeMunicipality = (line) => {
39
+ export const getWholeMunicipality = (line) => __awaiter(void 0, void 0, void 0, function* () {
20
40
  const match = wholeMunicipalityPattern.exec(line);
21
41
  if (match === null) {
22
- return { errors: ["Invalid whole municipality line"], municipality: null };
42
+ return {
43
+ errors: [
44
+ {
45
+ message: "Neplatný zápis pro přidání celé obce. Správný zápis je: území <typ> <název obce>. Např.: 'území obce Kladno' (název obce musí být v 1. pádě).",
46
+ startOffset: 0,
47
+ endOffset: line.length + 1,
48
+ },
49
+ ],
50
+ municipality: null,
51
+ };
23
52
  }
24
53
  const { type, name } = match.groups;
25
- return getMunicipalityResult(type, name);
26
- };
27
- const getMunicipalityResult = (type, name) => {
54
+ return yield getMunicipalityResult(type, name, line);
55
+ });
56
+ const getMunicipalityResult = (type, name, line) => __awaiter(void 0, void 0, void 0, function* () {
28
57
  const typeValue = getMunicipalityType(type);
29
- const { municipality, errors } = findMunicipalityByNameAndType(name, typeValue);
58
+ const { municipality, errors } = yield findMunicipalityByNameAndType(name, typeValue);
59
+ const startOffset = line.indexOf(name);
60
+ const endOffset = startOffset + name.length + 1;
30
61
  return {
31
62
  municipality,
32
- errors,
63
+ errors: errors.map((error) => (Object.assign(Object.assign({}, error), { startOffset,
64
+ endOffset }))),
33
65
  };
34
- };
66
+ });
35
67
  const getMunicipalityType = (type) => {
36
68
  switch (type) {
37
69
  case "městské části":
@@ -1,4 +1,4 @@
1
1
  import { SmdParser } from "./smd-parser";
2
2
  import { ProcessedSmdLines } from "./types";
3
3
  export declare const smdParser: SmdParser;
4
- export declare const parseLine: (text: string) => ProcessedSmdLines;
4
+ export declare const parseLine: (text: string, showDebug?: boolean) => ProcessedSmdLines;
@@ -1,29 +1,42 @@
1
1
  import { Lexer } from "chevrotain";
2
2
  import { SmdParser } from "./smd-parser";
3
- // const token_definition = require("token_definition");
4
3
  import { tokenVocabulary, smdTokens, resetTokenState, prepareLine, } from "./token-definition";
5
4
  const printLexingResultInfo = (lexingResult) => {
6
- // console.error(JSON.stringify(lexingResult, null, "\t"));
7
5
  const tokens = lexingResult.tokens.map((token) => "'" + token.image + "' (" + token.tokenType.name + ")");
8
6
  console.error(tokens);
9
7
  };
10
8
  const smdLexer = new Lexer(smdTokens, { positionTracking: "onlyOffset" });
11
9
  export const smdParser = new SmdParser(tokenVocabulary);
12
- export const parseLine = (text) => {
10
+ export const parseLine = (text, showDebug = false) => {
13
11
  resetTokenState(); // this is needed to reset the token state between lines
14
12
  const errors = [];
15
13
  const lexingResult = smdLexer.tokenize(prepareLine(text));
16
14
  if (lexingResult.errors.length > 0) {
17
- errors.push(...lexingResult.errors.map((error) => error.message));
18
- printLexingResultInfo(lexingResult);
15
+ errors.push(...lexingResult.errors.map((error) => ({
16
+ message: `Neočekávaný znak na tomto místě.`,
17
+ startOffset: error.offset,
18
+ endOffset: error.offset + error.length + 1,
19
+ })));
20
+ if (showDebug) {
21
+ printLexingResultInfo(lexingResult);
22
+ }
19
23
  return { smdLines: [], errors };
20
24
  }
21
- // printLexingResultInfo(lexingResult);
22
25
  smdParser.input = lexingResult.tokens;
23
26
  const smdLines = smdParser.street();
24
27
  if (smdParser.errors.length > 0) {
25
- errors.push(...smdParser.errors.map((error) => error.message));
26
- printLexingResultInfo(lexingResult);
28
+ errors.push(...smdParser.errors.map((error) => {
29
+ var _a;
30
+ return ({
31
+ message: `Nesprávný zápis pravidla - nevynechali jste něco?`,
32
+ startOffset: error.token.startOffset,
33
+ endOffset: (_a = error.token.endOffset) !== null && _a !== void 0 ? _a : text.length,
34
+ });
35
+ }));
36
+ if (showDebug) {
37
+ printLexingResultInfo(lexingResult);
38
+ }
39
+ return { smdLines: [], errors };
27
40
  }
28
41
  return { smdLines, errors };
29
42
  };
@@ -1,7 +1,10 @@
1
1
  import { Founder } from "../db/types";
2
- import { OpenDataSyncOptionsPartial } from "../utils/helpers";
3
- import { ErrorCallbackParams, Municipality, MunicipalityWithFounder, ProcessLineCallbackParams, School, SmdState } from "./types";
4
- export declare const parseOrdinanceToAddressPoints: (lines: string[], options?: OpenDataSyncOptionsPartial, initialState?: Partial<SmdState>, onError?: (params: ErrorCallbackParams) => void, onWarning?: (params: ErrorCallbackParams) => void, onProcessedLine?: (params: ProcessLineCallbackParams) => void) => Municipality[];
2
+ import { ErrorCallbackParams, Municipality, MunicipalityWithFounder, ProcessLineCallbackParams, School, SmdError, SmdState } from "./types";
3
+ export declare const parseOrdinanceToAddressPoints: (lines: string[], initialState?: Partial<SmdState>, onError?: (params: ErrorCallbackParams) => void, onWarning?: (params: ErrorCallbackParams) => void, onProcessedLine?: (params: ProcessLineCallbackParams) => void) => Promise<Municipality[]>;
5
4
  export declare const convertMunicipality: (municipality: MunicipalityWithFounder) => Municipality;
6
- export declare const getNewMunicipality: (name: string, options?: OpenDataSyncOptionsPartial) => MunicipalityWithFounder;
7
- export declare const getNewSchool: (name: string, founder: Founder | null, options?: OpenDataSyncOptionsPartial) => School;
5
+ export declare const getNewMunicipality: (name: string) => Promise<{
6
+ municipality: MunicipalityWithFounder;
7
+ errors: SmdError[];
8
+ }>;
9
+ export declare const getNewSchool: (name: string, founder: Founder | null, lineNumber: number, onError: (params: ErrorCallbackParams) => void) => Promise<School>;
10
+ export declare const wholeLineError: (message: string, line: string) => SmdError;
@@ -1,43 +1,54 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { checkStreetExists, findAddressPoints, getAddressPointById, } from "../db/address-points";
2
- import { setDbConfig } from "../db/db";
11
+ import { disconnectKnex } from "../db/db";
3
12
  import { findFounder } from "../db/founders";
4
13
  import { findSchool } from "../db/schools";
5
14
  import { founderToMunicipality } from "../db/types";
6
- import { prepareOptions } from "../utils/helpers";
7
15
  import { getSwitchMunicipality, getWholeMunicipality, isMunicipalitySwitch, isWholeMunicipality, } from "./municipality";
8
16
  import { parseLine } from "./smd-line-parser";
9
17
  import { isAddressPoint, } from "./types";
10
- export const parseOrdinanceToAddressPoints = (lines, options = {}, initialState = {}, onError = () => { }, onWarning = () => { }, onProcessedLine = () => { }) => {
11
- const readyOptions = prepareOptions(options);
12
- setDbConfig({
13
- filePath: readyOptions.dbFilePath,
14
- initFilePath: readyOptions.dbInitFilePath,
15
- });
16
- const state = Object.assign({ currentMunicipality: null, currentFilterMunicipality: null, currentSchool: null, municipalities: [] }, initialState);
17
- let lineNumber = 1;
18
- for (const rawLine of lines) {
19
- const line = cleanLine(rawLine);
20
- processOneLine({
21
- line,
22
- state,
23
- lineNumber,
24
- onError,
25
- onWarning,
26
- });
27
- onProcessedLine({ lineNumber, line });
28
- lineNumber++;
29
- }
30
- if (state.currentSchool != null) {
31
- if (state.currentMunicipality == null) {
32
- state.currentMunicipality = getNewMunicipality("");
18
+ export const parseOrdinanceToAddressPoints = (lines, initialState = {}, onError = () => { }, onWarning = () => { }, onProcessedLine = () => { }) => __awaiter(void 0, void 0, void 0, function* () {
19
+ try {
20
+ const state = Object.assign({ currentMunicipality: null, currentFilterMunicipality: null, currentSchool: null, municipalities: [] }, initialState);
21
+ let lineNumber = 1;
22
+ for (const rawLine of lines) {
23
+ const line = cleanLine(rawLine);
24
+ yield processOneLine({
25
+ line,
26
+ state,
27
+ lineNumber,
28
+ onError,
29
+ onWarning,
30
+ });
31
+ onProcessedLine({ lineNumber, line });
32
+ lineNumber++;
33
+ }
34
+ if (state.currentSchool != null) {
35
+ if (state.currentMunicipality == null) {
36
+ return [];
37
+ }
38
+ state.currentMunicipality.schools.push(mapSchoolForExport(state.currentSchool));
33
39
  }
34
- state.currentMunicipality.schools.push(mapSchoolForExport(state.currentSchool));
40
+ if (state.currentMunicipality != null) {
41
+ state.municipalities.push(convertMunicipality(state.currentMunicipality));
42
+ }
43
+ return state.municipalities;
35
44
  }
36
- if (state.currentMunicipality != null) {
37
- state.municipalities.push(convertMunicipality(state.currentMunicipality));
45
+ catch (error) {
46
+ console.error(error);
38
47
  }
39
- return state.municipalities;
40
- };
48
+ finally {
49
+ yield disconnectKnex();
50
+ }
51
+ });
41
52
  const filterOutSchoolAddressPoint = (addressPoints, school) => {
42
53
  const schoolPosition = school.position;
43
54
  return schoolPosition && isAddressPoint(schoolPosition)
@@ -50,10 +61,10 @@ export const convertMunicipality = (municipality) => {
50
61
  schools: municipality.schools,
51
62
  };
52
63
  };
53
- const processOneLine = (params) => {
64
+ const processOneLine = (params) => __awaiter(void 0, void 0, void 0, function* () {
54
65
  const { line, state } = params;
55
66
  if (line[0] === "#") {
56
- processMunicipalityLine(params);
67
+ yield processMunicipalityLine(params);
57
68
  return;
58
69
  }
59
70
  if (line === "") {
@@ -65,20 +76,20 @@ const processOneLine = (params) => {
65
76
  return;
66
77
  }
67
78
  if (state.currentSchool === null) {
68
- processSchoolLine(params);
79
+ yield processSchoolLine(params);
69
80
  return;
70
81
  }
71
82
  if (isMunicipalitySwitch(line)) {
72
83
  processMunicipalitySwitchLine(params);
73
84
  }
74
85
  else if (isWholeMunicipality(line)) {
75
- processWholeMunicipalityLine(params);
86
+ yield processWholeMunicipalityLine(params);
76
87
  }
77
88
  else {
78
- processAddressPointLine(params);
89
+ yield processAddressPointLine(params);
79
90
  }
80
- };
81
- const processMunicipalityLine = ({ line, state }) => {
91
+ });
92
+ const processMunicipalityLine = ({ line, state, onError, }) => __awaiter(void 0, void 0, void 0, function* () {
82
93
  if (state.currentSchool !== null) {
83
94
  state.currentMunicipality.schools.push(state.currentSchool);
84
95
  state.currentSchool = null;
@@ -86,97 +97,95 @@ const processMunicipalityLine = ({ line, state }) => {
86
97
  if (state.currentMunicipality !== null) {
87
98
  state.municipalities.push(convertMunicipality(state.currentMunicipality));
88
99
  }
89
- state.currentMunicipality = getNewMunicipality(line.substring(1).trim());
100
+ const { municipality, errors } = yield getNewMunicipality(line);
101
+ state.currentMunicipality = municipality;
90
102
  state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
91
103
  state.currentSchool = null;
92
- };
104
+ });
93
105
  const processEmptyLine = ({ state }) => {
94
106
  if (state.currentSchool !== null) {
95
107
  state.currentMunicipality.schools.push(state.currentSchool);
96
108
  state.currentSchool = null;
97
109
  }
98
110
  };
99
- const processSchoolLine = ({ line, lineNumber, state }) => {
111
+ const processSchoolLine = ({ line, lineNumber, state, onError, }) => __awaiter(void 0, void 0, void 0, function* () {
100
112
  if (state.currentMunicipality === null) {
101
- throw new Error("No municipality defined on line " + lineNumber);
113
+ onError({
114
+ lineNumber,
115
+ line,
116
+ errors: [
117
+ wholeLineError("Definici školy musí předcházet definice zřizovatele (uvozená '#', např. '# Strakonice').", line),
118
+ ],
119
+ });
120
+ return;
102
121
  }
103
- state.currentSchool = getNewSchool(line, state.currentMunicipality.founder);
122
+ state.currentSchool = yield getNewSchool(line, state.currentMunicipality.founder, lineNumber, onError);
104
123
  state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
105
- };
106
- const processMunicipalitySwitchLine = ({ line, state, lineNumber, onError, }) => {
107
- const { municipality, errors } = getSwitchMunicipality(line);
124
+ });
125
+ const processMunicipalitySwitchLine = ({ line, state, lineNumber, onError, }) => __awaiter(void 0, void 0, void 0, function* () {
126
+ const { municipality, errors } = yield getSwitchMunicipality(line);
108
127
  if (errors.length > 0) {
109
128
  onError({ lineNumber, line, errors });
110
129
  }
111
130
  else {
112
131
  state.currentFilterMunicipality = municipality;
113
132
  }
114
- };
115
- const processWholeMunicipalityLine = ({ line, state, lineNumber, onError, }) => {
116
- const { municipality, errors } = getWholeMunicipality(line);
133
+ });
134
+ const processWholeMunicipalityLine = ({ line, state, lineNumber, onError, }) => __awaiter(void 0, void 0, void 0, function* () {
135
+ const { municipality, errors } = yield getWholeMunicipality(line);
117
136
  if (errors.length > 0) {
118
137
  onError({ lineNumber, line, errors });
119
138
  }
120
139
  else {
121
- const addressPoints = findAddressPoints({ wholeMunicipality: true, street: "", numberSpec: [] }, municipality);
140
+ const addressPoints = yield findAddressPoints({ wholeMunicipality: true, street: "", numberSpec: [] }, municipality);
122
141
  state.currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, state.currentSchool).map(mapAddressPointForExport));
123
142
  }
124
- };
125
- const processAddressPointLine = ({ line, state, lineNumber, onError, onWarning, }) => {
143
+ });
144
+ const processAddressPointLine = ({ line, state, lineNumber, onError, onWarning, }) => __awaiter(void 0, void 0, void 0, function* () {
126
145
  const { smdLines, errors } = parseLine(line);
127
146
  if (errors.length > 0) {
128
147
  onError({ lineNumber, line, errors });
129
148
  }
130
149
  else {
131
- smdLines.forEach((smdLine) => {
132
- const { exists, errors } = checkStreetExists(smdLine.street, state.currentMunicipality.founder);
150
+ for (const smdLine of smdLines) {
151
+ const { exists, errors } = yield checkStreetExists(smdLine.street, state.currentMunicipality.founder);
133
152
  if (errors.length > 0) {
134
153
  onWarning({ lineNumber, line, errors });
135
154
  }
136
155
  if (exists) {
137
- let addressPoints = findAddressPoints(smdLine, state.currentFilterMunicipality);
156
+ let addressPoints = yield findAddressPoints(smdLine, state.currentFilterMunicipality);
138
157
  state.currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, state.currentSchool).map(mapAddressPointForExport));
139
158
  }
140
- });
141
- }
142
- };
143
- export const getNewMunicipality = (name, options) => {
144
- if (options) {
145
- options = prepareOptions(options);
146
- setDbConfig({
147
- filePath: options.dbFilePath,
148
- initFilePath: options.dbInitFilePath,
149
- });
150
- }
151
- const { founder, errors } = findFounder(name);
152
- if (errors.length > 0) {
153
- errors.forEach(console.error);
159
+ }
154
160
  }
161
+ });
162
+ export const getNewMunicipality = (name) => __awaiter(void 0, void 0, void 0, function* () {
163
+ const { founder, errors } = yield findFounder(name);
155
164
  return {
156
- municipalityName: founder ? founder.name : "Neznámá obec",
157
- founder,
158
- schools: [],
165
+ municipality: {
166
+ municipalityName: founder ? founder.name : "Neznámá obec",
167
+ founder,
168
+ schools: [],
169
+ },
170
+ errors,
159
171
  };
160
- };
161
- export const getNewSchool = (name, founder, options) => {
162
- if (options) {
163
- options = prepareOptions(options);
164
- setDbConfig({
165
- filePath: options.dbFilePath,
166
- initFilePath: options.dbInitFilePath,
167
- });
168
- }
172
+ });
173
+ export const getNewSchool = (name, founder, lineNumber, onError) => __awaiter(void 0, void 0, void 0, function* () {
169
174
  let exportSchool = {
170
- name: name,
175
+ name,
171
176
  izo: "",
172
177
  addresses: [],
173
178
  };
174
179
  if (founder !== null) {
175
- const { school } = findSchool(name, founder.schools);
180
+ const { school, errors } = findSchool(name, founder.schools);
181
+ if (errors.length > 0) {
182
+ onError({ lineNumber, line: name, errors });
183
+ }
176
184
  if (school) {
177
- school.izo = school.izo || "";
185
+ exportSchool.name = school.name;
186
+ exportSchool.izo = school.izo || "";
178
187
  if (school.locations.length > 0) {
179
- const position = getAddressPointById(school.locations[0].addressPointId);
188
+ const position = yield getAddressPointById(school.locations[0].addressPointId);
180
189
  if (position !== null) {
181
190
  exportSchool.position = position;
182
191
  }
@@ -184,7 +193,7 @@ export const getNewSchool = (name, founder, options) => {
184
193
  }
185
194
  }
186
195
  return exportSchool;
187
- };
196
+ });
188
197
  const mapAddressPointForExport = (addressPoint) => {
189
198
  return {
190
199
  address: addressPoint.address,
@@ -196,8 +205,13 @@ const mapSchoolForExport = (school) => ({
196
205
  name: school.name,
197
206
  izo: school.izo,
198
207
  addresses: school.addresses,
199
- position: mapAddressPointForExport(school.position),
208
+ position: school.position ? mapAddressPointForExport(school.position) : null,
200
209
  });
201
210
  const cleanLine = (line) => {
202
211
  return line.trim().replace(/–/g, "-");
203
212
  };
213
+ export const wholeLineError = (message, line) => ({
214
+ message,
215
+ startOffset: 0,
216
+ endOffset: line.length + 1,
217
+ });