text-to-map 1.0.5 → 1.0.7

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.
Binary file
@@ -1,6 +1,7 @@
1
1
  import { downloadAndImportAddressPoints } from "../open-data-sync/address-points";
2
+ import { defaultBinOptions } from "./constants";
2
3
  console.time("downloadAndImportAllLatestAddressPoints");
3
- downloadAndImportAddressPoints()
4
+ downloadAndImportAddressPoints(defaultBinOptions)
4
5
  .then(() => {
5
6
  console.timeEnd("downloadAndImportAllLatestAddressPoints");
6
7
  })
@@ -1,5 +1,6 @@
1
1
  import { deleteDb } from "../open-data-sync/address-points";
2
2
  import { deleteSchoolsXmlFile } from "../open-data-sync/schools";
3
- deleteDb();
4
- deleteSchoolsXmlFile();
3
+ import { defaultBinOptions } from "./constants";
4
+ deleteDb(defaultBinOptions);
5
+ deleteSchoolsXmlFile(defaultBinOptions);
5
6
  console.log("Everything cleared, ready for a new sync.");
@@ -0,0 +1,2 @@
1
+ import { OpenDataSyncOptionsPartial } from "../utils/helpers";
2
+ export declare const defaultBinOptions: OpenDataSyncOptionsPartial;
@@ -0,0 +1,3 @@
1
+ export const defaultBinOptions = {
2
+ dataDir: "./tmp/db",
3
+ };
@@ -1,5 +1,6 @@
1
1
  import { readFileSync, writeFileSync } from "fs";
2
- import { parseOrdinanceToAddressPoints } from "../street-markdown/smd";
2
+ import { getNewMunicipality, parseOrdinanceToAddressPoints } from "../street-markdown/smd";
3
+ import { defaultBinOptions } from "./constants";
3
4
  // take first node argument as a file name
4
5
  if (process.argv.length < 3) {
5
6
  console.error("Missing file name argument");
@@ -8,7 +9,31 @@ if (process.argv.length < 3) {
8
9
  const fileName = process.argv[2];
9
10
  const fileContent = readFileSync(fileName);
10
11
  const lines = fileContent.toString().split("\n");
11
- const addressPoints = parseOrdinanceToAddressPoints(lines);
12
+ let errorCount = 0;
13
+ const errorLines = [];
14
+ let warningCount = 0;
15
+ const reportErrors = ({ lineNumber, line, errors, }) => {
16
+ errors.forEach(console.error);
17
+ console.error(`Invalid street definition on line ${lineNumber}: ${line}`);
18
+ errorCount++;
19
+ errorLines.push(`line ${lineNumber}: ${line}`);
20
+ };
21
+ const reportWarnings = ({ lineNumber, errors: warnings, }) => {
22
+ warnings.map((error) => {
23
+ console.error(`Line ${lineNumber}: ${error}`);
24
+ });
25
+ warningCount++;
26
+ };
27
+ console.time("downloadAndImportAllLatestAddressPoints");
28
+ const addressPoints = parseOrdinanceToAddressPoints(lines, defaultBinOptions, {
29
+ currentMunicipality: getNewMunicipality("Česká Lípa", defaultBinOptions),
30
+ }, reportErrors, reportWarnings);
31
+ console.timeEnd("downloadAndImportAllLatestAddressPoints");
32
+ console.log(`Parsed ${lines.length} lines, ${errorCount} errors, ${warningCount} warnings.`);
33
+ if (errorCount > 0) {
34
+ console.log("Errors:");
35
+ errorLines.forEach((line) => console.log(line));
36
+ }
12
37
  if (process.argv.length >= 4) {
13
38
  const outputFileName = process.argv[3];
14
39
  const output = JSON.stringify(addressPoints);
@@ -1,5 +1,6 @@
1
1
  import { downloadAndImportRegions } from "../open-data-sync/regions";
2
- downloadAndImportRegions()
2
+ import { defaultBinOptions } from "./constants";
3
+ downloadAndImportRegions(defaultBinOptions)
3
4
  .then(() => {
4
5
  console.log("Completed");
5
6
  })
@@ -1,5 +1,6 @@
1
1
  import { downloadAndImportSchools } from "../open-data-sync/schools";
2
- downloadAndImportSchools({ tmpDir: "tmp" })
2
+ import { defaultBinOptions } from "./constants";
3
+ downloadAndImportSchools(defaultBinOptions, true)
3
4
  .then(() => {
4
5
  console.log("Completed");
5
6
  })
@@ -1,6 +1,7 @@
1
1
  import { downloadAndImportStreets } from "../open-data-sync/streets";
2
+ import { defaultBinOptions } from "./constants";
2
3
  console.time("downloadAndImportAllStreets");
3
- downloadAndImportStreets({})
4
+ downloadAndImportStreets(defaultBinOptions)
4
5
  .then(() => {
5
6
  console.timeEnd("downloadAndImportAllStreets");
6
7
  })
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { downloadAndImportEverything } from "../index";
2
+ import { defaultBinOptions } from "./constants";
3
+ downloadAndImportEverything(defaultBinOptions);
@@ -61,11 +61,12 @@ export const insertFounders = (founders) => {
61
61
  }
62
62
  const founderId = insertAutoincrementRow([
63
63
  sanitizeMunicipalityName(founder.name),
64
+ sanitizeMunicipalityName(extractedMunicipalityName),
64
65
  founder.ico,
65
66
  String(founder.originalType),
66
67
  cityCode,
67
68
  cityDistrictCode,
68
- ], "founder", ["name", "ico", "founder_type_code", "city_code", "city_district_code"]);
69
+ ], "founder", ["name", "short_name", "ico", "founder_type_code", "city_code", "city_district_code"]);
69
70
  // founder table has unique (name, ico) with on conflict ignore, so possibly
70
71
  // the row has not been inserted
71
72
  if (founderId !== null) {
@@ -1,4 +1,4 @@
1
- export declare const Column: {
1
+ interface RegionsColumn {
2
2
  cityName: number;
3
3
  cityCode: number;
4
4
  cityType: number;
@@ -15,9 +15,17 @@ export declare const Column: {
15
15
  regionCsuCode100: number;
16
16
  regionCsuCode108Nuts: number;
17
17
  regionRuianCode: number;
18
- };
19
- export declare const insertRegionsAndOrps: (data: string[][]) => number;
20
- export declare const insertRegions: (buffer: string[][]) => number;
21
- export declare const insertCounties: (buffer: string[][]) => number;
22
- export declare const insertOrps: (buffer: string[][]) => number;
23
- export declare const insertCities: (buffer: string[][]) => number;
18
+ }
19
+ export interface RegionsTableSchema {
20
+ tableSchema: {
21
+ columns: {
22
+ name: string;
23
+ }[];
24
+ };
25
+ }
26
+ export declare const insertRegionsAndOrps: (data: string[][], schema: RegionsTableSchema) => number;
27
+ export declare const insertRegions: (buffer: string[][], columnIndex: RegionsColumn) => number;
28
+ export declare const insertCounties: (buffer: string[][], columnIndex: RegionsColumn) => number;
29
+ export declare const insertOrps: (buffer: string[][], columnIndex: RegionsColumn) => number;
30
+ export declare const insertCities: (buffer: string[][], columnIndex: RegionsColumn) => number;
31
+ export {};
@@ -1,30 +1,13 @@
1
1
  import { extractKeyValuesPairs, getDb, insertMultipleRows } from "./db";
2
- export const Column = {
3
- cityName: 0,
4
- cityCode: 1,
5
- cityType: 2,
6
- orpName: 9,
7
- orpCsuCode65: 10,
8
- orpRuianCode: 11,
9
- orpCityCode: 12,
10
- countyName: 13,
11
- countyCsuCode101Lau: 14,
12
- countyCsuCode109Nuts: 15,
13
- countyRuianCode: 16,
14
- regionName: 17,
15
- regionShortName: 18,
16
- regionCsuCode100: 19,
17
- regionCsuCode108Nuts: 20,
18
- regionRuianCode: 21,
19
- };
20
- export const insertRegionsAndOrps = (data) => {
2
+ export const insertRegionsAndOrps = (data, schema) => {
3
+ const columnIndex = getColumnIndexFromSchema(schema);
21
4
  let changes = 0;
22
- changes += insertRegions(data);
23
- changes += insertCounties(data);
24
- changes += insertOrps(data);
5
+ changes += insertRegions(data, columnIndex);
6
+ changes += insertCounties(data, columnIndex);
7
+ changes += insertOrps(data, columnIndex);
25
8
  // cities are most likely already inserted, but in case they're not,
26
9
  // we need to insert them before updating them with region data
27
- changes += insertCities(data);
10
+ changes += insertCities(data, columnIndex);
28
11
  const db = getDb();
29
12
  const updateStatement = db.prepare(`UPDATE city SET
30
13
  region_code = ?,
@@ -32,34 +15,63 @@ export const insertRegionsAndOrps = (data) => {
32
15
  orp_code = ?
33
16
  WHERE code = ?`);
34
17
  data.forEach((data) => {
35
- changes += updateStatement.run(data[Column.regionRuianCode], data[Column.countyRuianCode], data[Column.orpRuianCode], data[Column.cityCode]).changes;
18
+ changes += updateStatement.run(data[columnIndex.regionRuianCode], data[columnIndex.countyRuianCode], data[columnIndex.orpRuianCode], data[columnIndex.cityCode]).changes;
36
19
  });
37
20
  return changes;
38
21
  };
39
- export const insertRegions = (buffer) => {
40
- return insertMultipleRows(extractKeyValuesPairs(buffer, Column.regionRuianCode, [
41
- Column.regionName,
42
- Column.regionShortName,
43
- Column.regionCsuCode100,
44
- Column.regionCsuCode108Nuts,
22
+ export const insertRegions = (buffer, columnIndex) => {
23
+ return insertMultipleRows(extractKeyValuesPairs(buffer, columnIndex.regionRuianCode, [
24
+ columnIndex.regionName,
25
+ columnIndex.regionShortName,
26
+ columnIndex.regionCsuCode100,
27
+ columnIndex.regionCsuCode108Nuts,
45
28
  ]), "region", ["code", "name", "short_name", "csu_code_100", "csu_code_108_nuts"]);
46
29
  };
47
- export const insertCounties = (buffer) => {
48
- return insertMultipleRows(extractKeyValuesPairs(buffer, Column.countyRuianCode, [
49
- Column.countyName,
50
- Column.countyCsuCode101Lau,
51
- Column.countyCsuCode109Nuts,
52
- Column.regionRuianCode,
30
+ export const insertCounties = (buffer, columnIndex) => {
31
+ return insertMultipleRows(extractKeyValuesPairs(buffer, columnIndex.countyRuianCode, [
32
+ columnIndex.countyName,
33
+ columnIndex.countyCsuCode101Lau,
34
+ columnIndex.countyCsuCode109Nuts,
35
+ columnIndex.regionRuianCode,
53
36
  ]), "county", ["code", "name", "csu_code_101_lau", "csu_code_109_nuts", "region_code"]);
54
37
  };
55
- export const insertOrps = (buffer) => {
56
- return insertMultipleRows(extractKeyValuesPairs(buffer, Column.orpRuianCode, [
57
- Column.orpName,
58
- Column.orpCsuCode65,
59
- Column.regionRuianCode,
60
- Column.countyRuianCode,
38
+ export const insertOrps = (buffer, columnIndex) => {
39
+ return insertMultipleRows(extractKeyValuesPairs(buffer, columnIndex.orpRuianCode, [
40
+ columnIndex.orpName,
41
+ columnIndex.orpCsuCode65,
42
+ columnIndex.regionRuianCode,
43
+ columnIndex.countyRuianCode,
61
44
  ]), "orp", ["code", "name", "csu_code_65", "region_code", "county_code"]);
62
45
  };
63
- export const insertCities = (buffer) => {
64
- return insertMultipleRows(extractKeyValuesPairs(buffer, Column.cityCode, [Column.cityName]), "city", ["code", "name"]);
46
+ export const insertCities = (buffer, columnIndex) => {
47
+ return insertMultipleRows(extractKeyValuesPairs(buffer, columnIndex.cityCode, [columnIndex.cityName]), "city", ["code", "name"]);
48
+ };
49
+ const getColumnIndexFromSchema = (schema) => {
50
+ const names = schema.tableSchema.columns.map((column) => column.name);
51
+ const columnIndex = {
52
+ cityName: findOrDie(names, "obec_text"),
53
+ cityCode: findOrDie(names, "obec_kod"),
54
+ cityType: findOrDie(names, "obec_typ"),
55
+ orpName: findOrDie(names, "orp_text"),
56
+ orpCsuCode65: findOrDie(names, "orp_csu_cis65_kod"),
57
+ orpRuianCode: findOrDie(names, "orp_ruian_kod"),
58
+ orpCityCode: findOrDie(names, "orp_sidlo_obec_kod"),
59
+ countyName: findOrDie(names, "okres_text"),
60
+ countyCsuCode101Lau: findOrDie(names, "okres_csu_cis101_lau_kod"),
61
+ countyCsuCode109Nuts: findOrDie(names, "okres_csu_cis109_nuts_kod"),
62
+ countyRuianCode: findOrDie(names, "okres_ruian_kod"),
63
+ regionName: findOrDie(names, "kraj_text"),
64
+ regionShortName: findOrDie(names, "kraj_zkratka"),
65
+ regionCsuCode100: findOrDie(names, "kraj_csu_cis100_kod"),
66
+ regionCsuCode108Nuts: findOrDie(names, "kraj_csu_cis108_nuts_kod"),
67
+ regionRuianCode: findOrDie(names, "kraj_ruian_vusc_kod"),
68
+ };
69
+ return columnIndex;
70
+ };
71
+ const findOrDie = (columnNames, name) => {
72
+ const index = columnNames.indexOf(name);
73
+ if (index < 0) {
74
+ throw new Error(`Column '${name}' not found in region schema. Check https://data.gov.cz/datov%C3%A1-sada?iri=https%3A%2F%2Fdata.gov.cz%2Fzdroj%2Fdatov%C3%A9-sady%2F00025593%2F271b0fb7c2abb7f44e12ad57617821b2 for current dataset info or search for 'Struktura území ČR se všemi kódy území od obcí po stát dle číselníků ČSÚ, klasifikace NUTS a kódů RÚIAN.'.`);
75
+ }
76
+ return index;
65
77
  };
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@ import { downloadAndImportAddressPoints, deleteDb } from "./open-data-sync/addre
2
2
  import { downloadAndImportRegions } from "./open-data-sync/regions";
3
3
  import { downloadAndImportSchools } from "./open-data-sync/schools";
4
4
  import { downloadAndImportStreets } from "./open-data-sync/streets";
5
- import { parseOrdinanceToAddressPoints } from "./street-markdown/smd";
6
- import { OpenDataSyncOptions } from "./utils/helpers";
5
+ import { OpenDataSyncOptionsPartial } from "./utils/helpers";
7
6
  export * from "./street-markdown/types";
7
+ export * from "./street-markdown/smd";
8
8
  /**
9
9
  * Download and import all open data to SQLite DB. The DB file will be located
10
10
  * in the `dataDir` folder.
@@ -16,5 +16,5 @@ export * from "./street-markdown/types";
16
16
  * await downloadAndImportEverything({ tmpDir: "./tmp", dataDir: "./data" });
17
17
  * ```
18
18
  */
19
- export declare function downloadAndImportEverything(options?: OpenDataSyncOptions, syncStreets?: boolean): Promise<void>;
20
- export { downloadAndImportAddressPoints, deleteDb, downloadAndImportSchools, downloadAndImportStreets, downloadAndImportRegions, parseOrdinanceToAddressPoints, };
19
+ export declare function downloadAndImportEverything(options?: OpenDataSyncOptionsPartial, syncStreets?: boolean): Promise<void>;
20
+ export { downloadAndImportAddressPoints, deleteDb, downloadAndImportSchools, downloadAndImportStreets, downloadAndImportRegions, };
package/dist/index.js CHANGED
@@ -11,8 +11,8 @@ import { downloadAndImportAddressPoints, deleteDb, } from "./open-data-sync/addr
11
11
  import { downloadAndImportRegions } from "./open-data-sync/regions";
12
12
  import { downloadAndImportSchools } from "./open-data-sync/schools";
13
13
  import { downloadAndImportStreets } from "./open-data-sync/streets";
14
- import { parseOrdinanceToAddressPoints } from "./street-markdown/smd";
15
14
  export * from "./street-markdown/types";
15
+ export * from "./street-markdown/smd";
16
16
  /**
17
17
  * Download and import all open data to SQLite DB. The DB file will be located
18
18
  * in the `dataDir` folder.
@@ -34,4 +34,4 @@ export function downloadAndImportEverything(options = {}, syncStreets = true) {
34
34
  }
35
35
  });
36
36
  }
37
- export { downloadAndImportAddressPoints, deleteDb, downloadAndImportSchools, downloadAndImportStreets, downloadAndImportRegions, parseOrdinanceToAddressPoints, };
37
+ export { downloadAndImportAddressPoints, deleteDb, downloadAndImportSchools, downloadAndImportStreets, downloadAndImportRegions, };
@@ -1,3 +1,3 @@
1
- import { OpenDataSyncOptions } from "../utils/helpers";
2
- export declare const downloadAndImportAddressPoints: (options?: OpenDataSyncOptions) => Promise<void>;
3
- export declare const deleteDb: (options?: OpenDataSyncOptions) => void;
1
+ import { OpenDataSyncOptionsPartial } from "../utils/helpers";
2
+ export declare const downloadAndImportAddressPoints: (options?: OpenDataSyncOptionsPartial) => Promise<void>;
3
+ export declare const deleteDb: (options?: OpenDataSyncOptionsPartial) => void;
@@ -1,2 +1,2 @@
1
- import { OpenDataSyncOptions } from "../utils/helpers";
2
- export declare const downloadAndImportRegions: (options?: OpenDataSyncOptions) => Promise<void>;
1
+ import { OpenDataSyncOptionsPartial } from "../utils/helpers";
2
+ export declare const downloadAndImportRegions: (options?: OpenDataSyncOptionsPartial) => Promise<void>;
@@ -25,9 +25,15 @@ const downloadAndImportDataToDb = (options) => __awaiter(void 0, void 0, void 0,
25
25
  rows.push(data);
26
26
  });
27
27
  yield pipeline(response.body, iconv.decodeStream("utf-8"), parseStream);
28
+ const schemaResponse = yield fetch(options.regionsSchemaUrl);
29
+ if (schemaResponse.status !== 200) {
30
+ throw new Error(`The file could not be downloaded. HTTP Code: ${schemaResponse.status}`);
31
+ }
32
+ // @ts-ignore
33
+ const schema = yield schemaResponse.json();
28
34
  console.log("Parsing completed. Starting to import data to DB...");
29
35
  initDb(options);
30
- insertRegionsAndOrps(rows);
36
+ insertRegionsAndOrps(rows, schema);
31
37
  console.log(`Import completed. Total imported rows: ${rows.length}`);
32
38
  });
33
39
  export const downloadAndImportRegions = (options = {}) => __awaiter(void 0, void 0, void 0, function* () {
@@ -1,3 +1,3 @@
1
- import { OpenDataSyncOptions } from "../utils/helpers";
2
- export declare const downloadAndImportSchools: (options: OpenDataSyncOptions) => Promise<void>;
3
- export declare const deleteSchoolsXmlFile: (options?: OpenDataSyncOptions) => void;
1
+ import { OpenDataSyncOptionsPartial } from "../utils/helpers";
2
+ export declare const downloadAndImportSchools: (options: OpenDataSyncOptionsPartial, saveFoundersToCsv?: boolean, saveSchoolsWithoutRuianToCsv?: boolean) => Promise<void>;
3
+ export declare const deleteSchoolsXmlFile: (options?: OpenDataSyncOptionsPartial) => void;
@@ -303,10 +303,10 @@ const importDataToDb = (options, saveFoundersToCsv = false, saveSchoolsWithoutRu
303
303
  const getXmlFilePath = (options) => {
304
304
  return join(options.tmpDir, options.schoolsXmlFileName);
305
305
  };
306
- export const downloadAndImportSchools = (options) => __awaiter(void 0, void 0, void 0, function* () {
306
+ export const downloadAndImportSchools = (options, saveFoundersToCsv = false, saveSchoolsWithoutRuianToCsv = false) => __awaiter(void 0, void 0, void 0, function* () {
307
307
  const runOptions = prepareOptions(options);
308
308
  yield downloadXml(runOptions);
309
- yield importDataToDb(runOptions, false, true);
309
+ yield importDataToDb(runOptions, saveFoundersToCsv, saveSchoolsWithoutRuianToCsv);
310
310
  deleteSchoolsXmlFile(runOptions);
311
311
  });
312
312
  export const deleteSchoolsXmlFile = (options = {}) => {
@@ -1,2 +1,2 @@
1
- import { OpenDataSyncOptions } from "../utils/helpers";
2
- export declare const downloadAndImportStreets: (options: OpenDataSyncOptions) => Promise<void>;
1
+ import { OpenDataSyncOptionsPartial } from "../utils/helpers";
2
+ export declare const downloadAndImportStreets: (options: OpenDataSyncOptionsPartial) => Promise<void>;
@@ -23,7 +23,7 @@ const prepareFolders = (options) => {
23
23
  }
24
24
  };
25
25
  const getTempFolder = (options) => {
26
- return join(options.tmpDir, options.streetFolderName);
26
+ return join(options.tmpDir, options.streetZipFolderName);
27
27
  };
28
28
  const downloadZipAndParseDbfFile = (url, index, options) => __awaiter(void 0, void 0, void 0, function* () {
29
29
  const response = yield fetch(url);
@@ -1,9 +1,7 @@
1
1
  import { Founder } from "../db/types";
2
- import { OpenDataSyncOptions } from "../utils/helpers";
3
- import { Municipality } from "./types";
4
- interface MunicipalityWithFounder extends Municipality {
5
- founder: Founder | null;
6
- }
7
- export declare const parseOrdinanceToAddressPoints: (lines: string[], options?: OpenDataSyncOptions) => Municipality[];
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[];
8
5
  export declare const convertMunicipality: (municipality: MunicipalityWithFounder) => Municipality;
9
- export {};
6
+ export declare const getNewMunicipality: (name: string, options?: OpenDataSyncOptionsPartial) => MunicipalityWithFounder;
7
+ export declare const getNewSchool: (name: string, founder: Founder | null, options?: OpenDataSyncOptionsPartial) => School;
@@ -2,12 +2,152 @@ import { checkStreetExists, findAddressPoints, getAddressPointById, } from "../d
2
2
  import { setDbConfig } from "../db/db";
3
3
  import { findFounder } from "../db/founders";
4
4
  import { findSchool } from "../db/schools";
5
- import { founderToMunicipality, } from "../db/types";
5
+ import { founderToMunicipality } from "../db/types";
6
6
  import { prepareOptions } from "../utils/helpers";
7
7
  import { getSwitchMunicipality, getWholeMunicipality, isMunicipalitySwitch, isWholeMunicipality, } from "./municipality";
8
8
  import { parseLine } from "./smd-line-parser";
9
9
  import { isAddressPoint, } from "./types";
10
- const getNewMunicipality = (name) => {
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("");
33
+ }
34
+ state.currentMunicipality.schools.push(mapSchoolForExport(state.currentSchool));
35
+ }
36
+ if (state.currentMunicipality != null) {
37
+ state.municipalities.push(convertMunicipality(state.currentMunicipality));
38
+ }
39
+ return state.municipalities;
40
+ };
41
+ const filterOutSchoolAddressPoint = (addressPoints, school) => {
42
+ const schoolPosition = school.position;
43
+ return schoolPosition && isAddressPoint(schoolPosition)
44
+ ? (addressPoints = addressPoints.filter((ap) => ap.id !== schoolPosition.id))
45
+ : addressPoints;
46
+ };
47
+ export const convertMunicipality = (municipality) => {
48
+ return {
49
+ municipalityName: municipality.municipalityName,
50
+ schools: municipality.schools,
51
+ };
52
+ };
53
+ const processOneLine = (params) => {
54
+ const { line, state } = params;
55
+ if (line[0] === "#") {
56
+ processMunicipalityLine(params);
57
+ return;
58
+ }
59
+ if (line === "") {
60
+ // end of school
61
+ processEmptyLine(params);
62
+ return;
63
+ }
64
+ if (line[0] === "!") {
65
+ return;
66
+ }
67
+ if (state.currentSchool === null) {
68
+ processSchoolLine(params);
69
+ return;
70
+ }
71
+ if (isMunicipalitySwitch(line)) {
72
+ processMunicipalitySwitchLine(params);
73
+ }
74
+ else if (isWholeMunicipality(line)) {
75
+ processWholeMunicipalityLine(params);
76
+ }
77
+ else {
78
+ processAddressPointLine(params);
79
+ }
80
+ };
81
+ const processMunicipalityLine = ({ line, state }) => {
82
+ if (state.currentSchool !== null) {
83
+ state.currentMunicipality.schools.push(state.currentSchool);
84
+ state.currentSchool = null;
85
+ }
86
+ if (state.currentMunicipality !== null) {
87
+ state.municipalities.push(convertMunicipality(state.currentMunicipality));
88
+ }
89
+ state.currentMunicipality = getNewMunicipality(line.substring(1).trim());
90
+ state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
91
+ state.currentSchool = null;
92
+ };
93
+ const processEmptyLine = ({ state }) => {
94
+ if (state.currentSchool !== null) {
95
+ state.currentMunicipality.schools.push(state.currentSchool);
96
+ state.currentSchool = null;
97
+ }
98
+ };
99
+ const processSchoolLine = ({ line, lineNumber, state }) => {
100
+ if (state.currentMunicipality === null) {
101
+ throw new Error("No municipality defined on line " + lineNumber);
102
+ }
103
+ state.currentSchool = getNewSchool(line, state.currentMunicipality.founder);
104
+ state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
105
+ };
106
+ const processMunicipalitySwitchLine = ({ line, state, lineNumber, onError, }) => {
107
+ const { municipality, errors } = getSwitchMunicipality(line);
108
+ if (errors.length > 0) {
109
+ onError({ lineNumber, line, errors });
110
+ }
111
+ else {
112
+ state.currentFilterMunicipality = municipality;
113
+ }
114
+ };
115
+ const processWholeMunicipalityLine = ({ line, state, lineNumber, onError, }) => {
116
+ const { municipality, errors } = getWholeMunicipality(line);
117
+ if (errors.length > 0) {
118
+ onError({ lineNumber, line, errors });
119
+ }
120
+ else {
121
+ const addressPoints = findAddressPoints({ wholeMunicipality: true, street: "", numberSpec: [] }, municipality);
122
+ state.currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, state.currentSchool).map(mapAddressPointForExport));
123
+ }
124
+ };
125
+ const processAddressPointLine = ({ line, state, lineNumber, onError, onWarning, }) => {
126
+ const { smdLines, errors } = parseLine(line);
127
+ if (errors.length > 0) {
128
+ onError({ lineNumber, line, errors });
129
+ }
130
+ else {
131
+ smdLines.forEach((smdLine) => {
132
+ const { exists, errors } = checkStreetExists(smdLine.street, state.currentMunicipality.founder);
133
+ if (errors.length > 0) {
134
+ onWarning({ lineNumber, line, errors });
135
+ }
136
+ if (exists) {
137
+ let addressPoints = findAddressPoints(smdLine, state.currentFilterMunicipality);
138
+ state.currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, state.currentSchool).map(mapAddressPointForExport));
139
+ }
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
+ }
11
151
  const { founder, errors } = findFounder(name);
12
152
  if (errors.length > 0) {
13
153
  errors.forEach(console.error);
@@ -18,7 +158,14 @@ const getNewMunicipality = (name) => {
18
158
  schools: [],
19
159
  };
20
160
  };
21
- const getNewSchool = (name, founder) => {
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
+ }
22
169
  let exportSchool = {
23
170
  name: name,
24
171
  izo: "",
@@ -54,129 +201,3 @@ const mapSchoolForExport = (school) => ({
54
201
  const cleanLine = (line) => {
55
202
  return line.trim().replace(/–/g, "-");
56
203
  };
57
- export const parseOrdinanceToAddressPoints = (lines, options = {}) => {
58
- const readyOptions = prepareOptions(options);
59
- setDbConfig({
60
- filePath: readyOptions.dbFilePath,
61
- initFilePath: readyOptions.dbInitFilePath,
62
- });
63
- let errorCount = 0;
64
- const errorLines = [];
65
- let warningCount = 0;
66
- let lineNumber = 1;
67
- let municipalities = [];
68
- let currentMunicipality = null;
69
- let currentFilterMunicipality = null;
70
- let currentSchool = null;
71
- const reportErrors = (line, errors) => {
72
- errors.forEach(console.error);
73
- console.error(`Invalid street definition on line ${lineNumber}: ${line}`);
74
- errorCount++;
75
- errorLines.push(`line ${lineNumber}: ${line}`);
76
- };
77
- lines.forEach((rawLine) => {
78
- let line = cleanLine(rawLine);
79
- if (line[0] === "#") {
80
- // a new municipality
81
- if (currentSchool !== null) {
82
- currentMunicipality.schools.push(currentSchool);
83
- currentSchool = null;
84
- }
85
- if (currentMunicipality !== null) {
86
- municipalities.push(convertMunicipality(currentMunicipality));
87
- }
88
- currentMunicipality = getNewMunicipality(line.substring(1).trim());
89
- currentFilterMunicipality = founderToMunicipality(currentMunicipality.founder);
90
- currentSchool = null;
91
- }
92
- else if (line === "") {
93
- // empty line (end of school)
94
- if (currentSchool !== null) {
95
- currentMunicipality.schools.push(currentSchool);
96
- currentSchool = null;
97
- }
98
- }
99
- else {
100
- if (currentSchool === null) {
101
- if (currentMunicipality === null) {
102
- throw new Error("No municipality defined on line " + lineNumber);
103
- }
104
- currentSchool = getNewSchool(line, currentMunicipality.founder);
105
- currentFilterMunicipality = founderToMunicipality(currentMunicipality.founder);
106
- }
107
- else {
108
- if (line[0] !== "!") {
109
- if (isMunicipalitySwitch(line)) {
110
- const { municipality, errors } = getSwitchMunicipality(line);
111
- if (errors.length > 0) {
112
- reportErrors(line, errors);
113
- }
114
- else {
115
- currentFilterMunicipality = municipality;
116
- }
117
- }
118
- else if (isWholeMunicipality(line)) {
119
- const { municipality, errors } = getWholeMunicipality(line);
120
- if (errors.length > 0) {
121
- reportErrors(line, errors);
122
- }
123
- else {
124
- const addressPoints = findAddressPoints({ wholeMunicipality: true, street: "", numberSpec: [] }, municipality);
125
- currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, currentSchool).map(mapAddressPointForExport));
126
- }
127
- }
128
- else {
129
- // address point
130
- const { smdLines, errors } = parseLine(line);
131
- if (errors.length > 0) {
132
- reportErrors(line, errors);
133
- }
134
- else {
135
- smdLines.forEach((smdLine) => {
136
- const { exists, errors } = checkStreetExists(smdLine.street, currentMunicipality.founder);
137
- if (errors.length > 0) {
138
- errors.map((error) => {
139
- console.error(`Line ${lineNumber}: ${error}`);
140
- });
141
- warningCount++;
142
- }
143
- if (exists) {
144
- let addressPoints = findAddressPoints(smdLine, currentFilterMunicipality);
145
- currentSchool.addresses.push(...filterOutSchoolAddressPoint(addressPoints, currentSchool).map(mapAddressPointForExport));
146
- }
147
- });
148
- }
149
- }
150
- }
151
- }
152
- }
153
- lineNumber++;
154
- });
155
- if (currentSchool != null) {
156
- if (currentMunicipality == null) {
157
- currentMunicipality = getNewMunicipality("");
158
- }
159
- currentMunicipality.schools.push(mapSchoolForExport(currentSchool));
160
- }
161
- if (currentMunicipality != null) {
162
- municipalities.push(convertMunicipality(currentMunicipality));
163
- }
164
- console.log(`Parsed ${lineNumber} lines, ${errorCount} errors, ${warningCount} warnings.`);
165
- if (errorCount > 0) {
166
- console.log("Errors:");
167
- errorLines.forEach((line) => console.log(line));
168
- }
169
- return municipalities;
170
- };
171
- const filterOutSchoolAddressPoint = (addressPoints, school) => {
172
- const schoolPosition = school.position;
173
- return schoolPosition && isAddressPoint(schoolPosition)
174
- ? (addressPoints = addressPoints.filter((ap) => ap.id !== schoolPosition.id))
175
- : addressPoints;
176
- };
177
- export const convertMunicipality = (municipality) => {
178
- return {
179
- municipalityName: municipality.municipalityName,
180
- schools: municipality.schools,
181
- };
182
- };
@@ -1,5 +1,5 @@
1
- import { Municipality as DbMunicipality } from "../db/types";
2
1
  import { AddressPoint as CzechAddressPoint } from "czech-address";
2
+ import { Municipality as DbMunicipality, Founder } from "../db/types";
3
3
  export interface ProcessedSmdLines {
4
4
  smdLines: SmdLine[];
5
5
  errors: string[];
@@ -69,3 +69,26 @@ export interface DbMunicipalityResult {
69
69
  municipality: DbMunicipality;
70
70
  errors: string[];
71
71
  }
72
+ export interface MunicipalityWithFounder extends Municipality {
73
+ founder: Founder | null;
74
+ }
75
+ export interface SmdState {
76
+ currentMunicipality: MunicipalityWithFounder;
77
+ currentFilterMunicipality: DbMunicipality;
78
+ currentSchool: School;
79
+ municipalities: Municipality[];
80
+ }
81
+ export interface ProcessLineCallbackParams {
82
+ lineNumber: number;
83
+ line: string;
84
+ }
85
+ export interface ErrorCallbackParams extends ProcessLineCallbackParams {
86
+ errors: string[];
87
+ }
88
+ export interface ProcessLineParams {
89
+ line: string;
90
+ state: SmdState;
91
+ lineNumber: number;
92
+ onError: (params: ErrorCallbackParams) => void;
93
+ onWarning: (params: ErrorCallbackParams) => void;
94
+ }
@@ -1,21 +1,5 @@
1
1
  import { Founder } from "../db/types";
2
2
  export interface OpenDataSyncOptions {
3
- tmpDir?: string;
4
- dataDir?: string;
5
- dbFilePath?: string;
6
- dbInitFilePath?: string;
7
- addressPointsAtomUrl?: string;
8
- addressPointsZipFileName?: string;
9
- addressPointsCsvFolderName?: string;
10
- streetsAtomUrl?: string;
11
- streetZipFolderName?: string;
12
- streetDbfFileName?: string;
13
- schoolsXmlUrl?: string;
14
- schoolsXmlFileName?: string;
15
- regionsCsvUrl?: string;
16
- regionsCsvFileName?: string;
17
- }
18
- export interface OpenDataSyncOptionsNotEmpty {
19
3
  tmpDir: string;
20
4
  dataDir: string;
21
5
  dbFilePath: string;
@@ -24,16 +8,18 @@ export interface OpenDataSyncOptionsNotEmpty {
24
8
  addressPointsZipFileName: string;
25
9
  addressPointsCsvFolderName: string;
26
10
  streetsAtomUrl: string;
27
- streetFolderName: string;
11
+ streetZipFolderName: string;
28
12
  streetDbfFileName: string;
29
13
  schoolsXmlUrl: string;
30
14
  schoolsXmlFileName: string;
31
15
  regionsCsvUrl: string;
16
+ regionsSchemaUrl: string;
32
17
  regionsCsvFileName: string;
33
18
  }
19
+ export type OpenDataSyncOptionsPartial = Partial<OpenDataSyncOptions>;
34
20
  export declare const getAppDataDirPath: () => string;
35
- export declare const prepareOptions: (options: OpenDataSyncOptions) => OpenDataSyncOptionsNotEmpty;
36
- export declare const initDb: (options: OpenDataSyncOptionsNotEmpty) => void;
21
+ export declare const prepareOptions: (options: OpenDataSyncOptionsPartial) => OpenDataSyncOptions;
22
+ export declare const initDb: (options: OpenDataSyncOptions) => void;
37
23
  export declare const extractMunicipalityName: (founder: Founder) => string;
38
24
  export declare const sanitizeMunicipalityName: (name: string) => string;
39
25
  export declare const findClosestString: (str: string, arr: string[]) => string;
@@ -10,7 +10,7 @@ export const getAppDataDirPath = () => join(process.env.APPDATA ||
10
10
  ? process.env.HOME + "/Library/Preferences"
11
11
  : process.env.HOME + "/.local/share"), appName);
12
12
  export const prepareOptions = (options) => {
13
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
13
+ var _a;
14
14
  const dataDir = (_a = options.dataDir) !== null && _a !== void 0 ? _a : getAppDataDirPath();
15
15
  if (!existsSync(dataDir)) {
16
16
  mkdirSync(dataDir);
@@ -21,22 +21,24 @@ export const prepareOptions = (options) => {
21
21
  }
22
22
  const __filename = fileURLToPath(import.meta.url);
23
23
  const __dirname = dirname(__filename);
24
- return {
25
- tmpDir: (_b = options.tmpDir) !== null && _b !== void 0 ? _b : tmpAppDir,
24
+ const defaults = {
25
+ tmpDir: tmpAppDir,
26
26
  dataDir: dataDir,
27
- dbFilePath: (_c = options.dbFilePath) !== null && _c !== void 0 ? _c : join(dataDir, "address_points.db"),
28
- dbInitFilePath: (_d = options.dbInitFilePath) !== null && _d !== void 0 ? _d : join(__dirname, "..", "address_points_init.db"),
29
- addressPointsAtomUrl: (_e = options.addressPointsAtomUrl) !== null && _e !== void 0 ? _e : "https://atom.cuzk.cz/RUIAN-CSV-ADR-ST/RUIAN-CSV-ADR-ST.xml",
30
- addressPointsZipFileName: (_f = options.addressPointsZipFileName) !== null && _f !== void 0 ? _f : "ruian_csv.zip",
31
- addressPointsCsvFolderName: (_g = options.addressPointsCsvFolderName) !== null && _g !== void 0 ? _g : "CSV",
32
- streetsAtomUrl: (_h = options.streetsAtomUrl) !== null && _h !== void 0 ? _h : "https://atom.cuzk.cz/RUIAN-OBCE-SHP/RUIAN-OBCE-SHP.xml",
33
- streetFolderName: (_j = options.streetZipFolderName) !== null && _j !== void 0 ? _j : "streets",
34
- streetDbfFileName: (_k = options.streetDbfFileName) !== null && _k !== void 0 ? _k : "UL_L.dbf",
35
- schoolsXmlUrl: (_l = options.schoolsXmlUrl) !== null && _l !== void 0 ? _l : "https://rejstriky.msmt.cz/opendata/vrejcelk.xml",
36
- schoolsXmlFileName: (_m = options.schoolsXmlFileName) !== null && _m !== void 0 ? _m : "school-register.xml",
37
- regionsCsvUrl: (_o = options.regionsCsvUrl) !== null && _o !== void 0 ? _o : "https://www.czso.cz/documents/10180/23208674/struktura_uzemi_cr.csv",
38
- regionsCsvFileName: (_p = options.regionsCsvFileName) !== null && _p !== void 0 ? _p : "struktura_uzemi_cr.csv",
27
+ dbFilePath: join(dataDir, "address_points.db"),
28
+ dbInitFilePath: join(__dirname, "..", "address_points_init.db"),
29
+ addressPointsAtomUrl: "https://atom.cuzk.cz/RUIAN-CSV-ADR-ST/RUIAN-CSV-ADR-ST.xml",
30
+ addressPointsZipFileName: "ruian_csv.zip",
31
+ addressPointsCsvFolderName: "CSV",
32
+ streetsAtomUrl: "https://atom.cuzk.cz/RUIAN-OBCE-SHP/RUIAN-OBCE-SHP.xml",
33
+ streetZipFolderName: "streets",
34
+ streetDbfFileName: "UL_L.dbf",
35
+ schoolsXmlUrl: "https://rejstriky.msmt.cz/opendata/vrejcelk.xml",
36
+ schoolsXmlFileName: "school-register.xml",
37
+ regionsCsvUrl: "https://www.czso.cz/documents/10180/23208674/struktura_uzemi_cr.csv",
38
+ regionsSchemaUrl: "https://www.czso.cz/documents/10180/23208674/struktura_uzemi_cr-metadata.json",
39
+ regionsCsvFileName: "struktura_uzemi_cr.csv",
39
40
  };
41
+ return Object.assign(Object.assign({}, defaults), options);
40
42
  };
41
43
  export const initDb = (options) => {
42
44
  setDbConfig({
package/package.json CHANGED
@@ -29,14 +29,14 @@
29
29
  "ts-node": "^10.9.1"
30
30
  },
31
31
  "scripts": {
32
+ "sync-all": "ts-node --experimental-specifier-resolution=node --esm src/bin/sync-all.ts",
32
33
  "address-points": "ts-node --experimental-specifier-resolution=node --esm src/bin/address-points.ts",
34
+ "regions": "ts-node --experimental-specifier-resolution=node --esm src/bin/regions.ts",
33
35
  "schools": "ts-node --experimental-specifier-resolution=node --esm src/bin/schools.ts",
36
+ "streets": "ts-node --experimental-specifier-resolution=node --esm src/bin/streets.ts",
37
+ "diagrams": "ts-node --experimental-specifier-resolution=node --esm src/bin/generate-syntax-diagrams.ts",
34
38
  "clear-all": "ts-node --experimental-specifier-resolution=node --esm src/bin/clear-all.ts",
35
39
  "parse-ordinance": "ts-node --experimental-specifier-resolution=node --esm src/bin/parse-ordinance.ts",
36
- "diagrams": "ts-node --experimental-specifier-resolution=node --esm src/bin/generate-syntax-diagrams.ts",
37
- "streets": "ts-node --experimental-specifier-resolution=node --esm src/bin/streets.ts",
38
- "regions": "ts-node --experimental-specifier-resolution=node --esm src/bin/regions.ts",
39
- "dbf": "ts-node --experimental-specifier-resolution=node --esm src/bin/dbf.ts",
40
40
  "test": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js -c=jest-esm.config.mjs --no-cache",
41
41
  "ordinance-to-csv-rules": "node src/smd-to-csv/ordinance-to-csv-rules.js",
42
42
  "clean": "rimraf dist",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "name": "text-to-map",
50
50
  "description": "Text To Map usiluje o lepší, strojově zpracovatelné využití částí vyhlášek s výčtem ulic a dalších lokací. Jde o rozšiřitelnou sadu konceptů a nástrojů, které zajistí hladký převod výčtu ulic a jejich rozsahů v lidsky srozumitelném jazyce do strojově zpracovatelného, uchopitelného formátu.",
51
- "version": "1.0.5",
51
+ "version": "1.0.7",
52
52
  "main": "dist/index.js",
53
53
  "types": "dist/index.d.ts",
54
54
  "files": [