text-to-map 1.0.7 → 1.0.8

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.
@@ -1,5 +1,5 @@
1
1
  import { readFileSync, writeFileSync } from "fs";
2
- import { getNewMunicipality, parseOrdinanceToAddressPoints } from "../street-markdown/smd";
2
+ import { getNewMunicipality, parseOrdinanceToAddressPoints, } from "../street-markdown/smd";
3
3
  import { defaultBinOptions } from "./constants";
4
4
  // take first node argument as a file name
5
5
  if (process.argv.length < 3) {
@@ -13,20 +13,21 @@ let errorCount = 0;
13
13
  const errorLines = [];
14
14
  let warningCount = 0;
15
15
  const reportErrors = ({ lineNumber, line, errors, }) => {
16
- errors.forEach(console.error);
16
+ errors.forEach((error) => console.error(error));
17
17
  console.error(`Invalid street definition on line ${lineNumber}: ${line}`);
18
18
  errorCount++;
19
19
  errorLines.push(`line ${lineNumber}: ${line}`);
20
20
  };
21
21
  const reportWarnings = ({ lineNumber, errors: warnings, }) => {
22
- warnings.map((error) => {
23
- console.error(`Line ${lineNumber}: ${error}`);
22
+ warnings.forEach((error) => {
23
+ console.error(`Line ${lineNumber}: ${error.message}`);
24
24
  });
25
25
  warningCount++;
26
26
  };
27
27
  console.time("downloadAndImportAllLatestAddressPoints");
28
+ const { municipality } = getNewMunicipality("Česká Lípa", defaultBinOptions);
28
29
  const addressPoints = parseOrdinanceToAddressPoints(lines, defaultBinOptions, {
29
- currentMunicipality: getNewMunicipality("Česká Lípa", defaultBinOptions),
30
+ // currentMunicipality: municipality,
30
31
  }, reportErrors, reportWarnings);
31
32
  console.timeEnd("downloadAndImportAllLatestAddressPoints");
32
33
  console.log(`Parsed ${lines.length} lines, ${errorCount} errors, ${warningCount} warnings.`);
@@ -1,4 +1,4 @@
1
- import { AddressPoint, FullStreetNumber, RangeSpec, SeriesType, SmdLine, WholeMunicipalitySmdLine } from "../street-markdown/types";
1
+ import { AddressPoint, FullStreetNumber, RangeSpec, SeriesType, SmdError, SmdLine, WholeMunicipalitySmdLine } from "../street-markdown/types";
2
2
  import { Founder, Municipality } from "./types";
3
3
  export declare const Column: {
4
4
  admCode: number;
@@ -31,7 +31,7 @@ export declare const insertStreets: (buffer: string[][]) => number;
31
31
  export declare const getAddressPointById: (addressPointId: number) => AddressPoint | null;
32
32
  export declare const checkStreetExists: (streetName: string, founder: Founder) => {
33
33
  exists: boolean;
34
- errors: string[];
34
+ errors: SmdError[];
35
35
  };
36
36
  export declare const findAddressPoints: (smdLine: SmdLine | WholeMunicipalitySmdLine, municipality: Municipality) => AddressPoint[];
37
37
  export declare const isInRange: (number: number | null, letter: string | null, range: RangeSpec) => boolean;
@@ -153,7 +153,11 @@ export const checkStreetExists = (streetName, founder) => {
153
153
  }
154
154
  else {
155
155
  const closest = findClosestString(streetName, allStreets);
156
- errors.push(`Street '${streetName}' does not exist, did you mean '${closest}'?`);
156
+ errors.push({
157
+ message: `Ulice '${streetName}' v této obci neexistuje, mysleli jste '${closest}'?`,
158
+ startOffset: 0,
159
+ endOffset: streetName.length + 1,
160
+ });
157
161
  }
158
162
  return { exists: false, errors };
159
163
  };
package/dist/db/db.js CHANGED
@@ -23,6 +23,8 @@ export const getDb = (config = {}) => {
23
23
  const dbSettings = options.verbose ? { verbose: console.log } : {};
24
24
  _db = new Database(options.filePath, dbSettings);
25
25
  _db.pragma("journal_mode = WAL");
26
+ // @ts-ignore
27
+ _db.filePath = options.filePath;
26
28
  }
27
29
  return _db;
28
30
  };
@@ -1,9 +1,9 @@
1
1
  import { Founder, MunicipalityType } from "./types";
2
- import { DbMunicipalityResult } from "../street-markdown/types";
2
+ import { DbMunicipalityResult, SmdError } from "../street-markdown/types";
3
3
  export declare const insertFounders: (founders: Founder[]) => number;
4
- export declare const findFounder: (name: string) => {
4
+ export declare const findFounder: (nameWithHashtag: string) => {
5
5
  founder: Founder;
6
- errors: string[];
6
+ errors: SmdError[];
7
7
  };
8
8
  export declare const getFounderCityCode: (founder: Founder) => number;
9
9
  export declare const findMunicipalityByNameAndType: (name: string, type: MunicipalityType) => DbMunicipalityResult;
@@ -2,6 +2,7 @@ import { MunicipalityType, } from "./types";
2
2
  import { generatePlaceholders, getDb, insertAutoincrementRow, insertMultipleRows, } from "./db";
3
3
  import { extractMunicipalityName, findClosestString, sanitizeMunicipalityName, } from "../utils/helpers";
4
4
  import distance from "@turf/distance";
5
+ import { wholeLineError } from "../street-markdown/smd";
5
6
  const cityTypeCode = 261;
6
7
  const cityDistrictTypeCode = 263;
7
8
  export const insertFounders = (founders) => {
@@ -178,9 +179,18 @@ const findMunicipalitiesAndPositionsByNameAndType = (name, type) => {
178
179
  lng: row.wgs84_longitude,
179
180
  }));
180
181
  };
181
- export const findFounder = (name) => {
182
+ const extractFounderName = (line) => {
183
+ if (line[0] === "#") {
184
+ return line.substring(1).trim();
185
+ }
186
+ else {
187
+ return line.trim();
188
+ }
189
+ };
190
+ export const findFounder = (nameWithHashtag) => {
182
191
  const errors = [];
183
192
  const db = getDb();
193
+ const name = extractFounderName(nameWithHashtag);
184
194
  const exactMatchStatement = db.prepare(`SELECT f.id, f.name, f.ico, f.founder_type_code, f.city_code, f.city_district_code FROM founder f
185
195
  LEFT JOIN city c ON c.code = f.city_code
186
196
  LEFT JOIN city_district d ON d.code = f.city_district_code
@@ -197,7 +207,14 @@ export const findFounder = (name) => {
197
207
  const bestMatch = findClosestString(name, namesList);
198
208
  const bestMatchRow = allFounderNames.find((foundersNames) => foundersNames.founderName === bestMatch ||
199
209
  foundersNames.municipalityName === bestMatch);
200
- errors.push(`No exact match for founder "${name}", using "${bestMatch}" instead.`);
210
+ if (!bestMatchRow) {
211
+ errors.push(wholeLineError(`Nenašli jsme žádné zřizovatele, nejspíš jste zapomněli inicializovat databázi.`, nameWithHashtag));
212
+ return {
213
+ founder: null,
214
+ errors,
215
+ };
216
+ }
217
+ errors.push(wholeLineError(`Zřizovatel '${name}' neexistuje, mysleli jste '${bestMatch}'?`, nameWithHashtag));
201
218
  const findByIdStatement = db.prepare(`SELECT f.id, f.name, f.ico, f.founder_type_code, f.city_code, f.city_district_code FROM founder f
202
219
  WHERE f.id = ?`);
203
220
  return {
@@ -282,7 +299,11 @@ export const findMunicipalityByNameAndType = (name, type) => {
282
299
  const namesList = allNames.map((row) => row.name);
283
300
  const bestMatch = findClosestString(name, namesList);
284
301
  const bestMatchRow = allNames.find((municipality) => municipality.name === bestMatch);
285
- errors.push(`No exact match for municipality "${name}", using "${bestMatch}" instead.`);
302
+ errors.push({
303
+ message: `Obec ani městská část '${name}' neexistuje, mysleli jste '${bestMatch}'?`,
304
+ startOffset: 0,
305
+ endOffset: 0,
306
+ });
286
307
  return {
287
308
  municipality: { code: bestMatchRow.code, type },
288
309
  errors,
@@ -1,6 +1,7 @@
1
+ import { SmdError } from "../street-markdown/types";
1
2
  import { School } from "./types";
2
3
  export declare const insertSchools: (schools: School[]) => number;
3
4
  export declare const findSchool: (name: string, schools: School[]) => {
4
5
  school: School | null;
5
- errors: string[];
6
+ errors: SmdError[];
6
7
  };
@@ -1,3 +1,4 @@
1
+ import { wholeLineError } from "../street-markdown/smd";
1
2
  import { findClosestString } from "../utils/helpers";
2
3
  import { getDb, insertMultipleRows } from "./db";
3
4
  export const insertSchools = (schools) => {
@@ -35,7 +36,10 @@ export const insertSchools = (schools) => {
35
36
  };
36
37
  export const findSchool = (name, schools) => {
37
38
  if (schools.length === 0) {
38
- return { school: null, errors: ["No schools for this founder."] };
39
+ return {
40
+ school: null,
41
+ errors: [wholeLineError("Aktuální zřizovatel nemá žádné školy.", name)],
42
+ };
39
43
  }
40
44
  let school = null;
41
45
  const errors = [];
@@ -46,7 +50,7 @@ export const findSchool = (name, schools) => {
46
50
  const namesList = schools.map((school) => school.name);
47
51
  const bestMatch = findClosestString(name, namesList);
48
52
  school = schools.find((school) => bestMatch === school.name);
49
- errors.push(`No exact match for school "${name}", using "${bestMatch}" instead.`);
53
+ errors.push(wholeLineError(`Škola s názvem '${name}' neexistuje, mysleli jste '${bestMatch}'?`, name));
50
54
  return { school, errors };
51
55
  };
52
56
  const filterOutDuplicates = (schools) => {
@@ -1,35 +1,58 @@
1
1
  import { findMunicipalityByNameAndType } from "../db/founders";
2
2
  import { MunicipalityType } from "../db/types";
3
+ const municipalitySwitchStartPattern = /^navíc ulice /;
3
4
  const municipalitySwitchPattern = /^navíc ulice (z )?(?<type>městské části|městského obvodu|obce|města) (?<name>.+):$/;
5
+ const wholeMunicipalityStartPattern = /^území /;
4
6
  const wholeMunicipalityPattern = /^území (?<type>městské části|městského obvodu|obce|města) (?<name>.+)$/;
5
7
  export const isMunicipalitySwitch = (line) => {
6
- return municipalitySwitchPattern.test(line);
8
+ return municipalitySwitchStartPattern.test(line);
7
9
  };
8
10
  export const getSwitchMunicipality = (line) => {
9
11
  const match = municipalitySwitchPattern.exec(line);
10
12
  if (match === null) {
11
- throw new Error("Invalid municipality switch line");
13
+ return {
14
+ errors: [
15
+ {
16
+ 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ě).",
17
+ startOffset: 0,
18
+ endOffset: line.length + 1,
19
+ },
20
+ ],
21
+ municipality: null,
22
+ };
12
23
  }
13
24
  const { type, name } = match.groups;
14
- return getMunicipalityResult(type, name);
25
+ return getMunicipalityResult(type, name, line);
15
26
  };
16
27
  export const isWholeMunicipality = (line) => {
17
- return wholeMunicipalityPattern.test(line);
28
+ return wholeMunicipalityStartPattern.test(line);
18
29
  };
19
30
  export const getWholeMunicipality = (line) => {
20
31
  const match = wholeMunicipalityPattern.exec(line);
21
32
  if (match === null) {
22
- return { errors: ["Invalid whole municipality line"], municipality: null };
33
+ return {
34
+ errors: [
35
+ {
36
+ 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ě).",
37
+ startOffset: 0,
38
+ endOffset: line.length + 1,
39
+ },
40
+ ],
41
+ municipality: null,
42
+ };
23
43
  }
24
44
  const { type, name } = match.groups;
25
- return getMunicipalityResult(type, name);
45
+ return getMunicipalityResult(type, name, line);
26
46
  };
27
- const getMunicipalityResult = (type, name) => {
47
+ const getMunicipalityResult = (type, name, line) => {
28
48
  const typeValue = getMunicipalityType(type);
29
49
  const { municipality, errors } = findMunicipalityByNameAndType(name, typeValue);
50
+ const startOffset = line.indexOf(name);
51
+ const endOffset = startOffset + name.length + 1;
30
52
  return {
31
53
  municipality,
32
- errors,
54
+ errors: errors.map((error) => (Object.assign(Object.assign({}, error), { startOffset,
55
+ endOffset }))),
33
56
  };
34
57
  };
35
58
  const getMunicipalityType = (type) => {
@@ -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,39 @@
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
+ message: `Nesprávný zápis pravidla - nevynechali jste něco?`,
30
+ startOffset: error.token.startOffset,
31
+ endOffset: error.token.endOffset,
32
+ })));
33
+ if (showDebug) {
34
+ printLexingResultInfo(lexingResult);
35
+ }
36
+ return { smdLines: [], errors };
27
37
  }
28
38
  return { smdLines, errors };
29
39
  };
@@ -1,7 +1,11 @@
1
1
  import { Founder } from "../db/types";
2
2
  import { OpenDataSyncOptionsPartial } from "../utils/helpers";
3
- import { ErrorCallbackParams, Municipality, MunicipalityWithFounder, ProcessLineCallbackParams, School, SmdState } from "./types";
3
+ import { ErrorCallbackParams, Municipality, MunicipalityWithFounder, ProcessLineCallbackParams, School, SmdError, SmdState } from "./types";
4
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[];
5
5
  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;
6
+ export declare const getNewMunicipality: (name: string, options?: OpenDataSyncOptionsPartial) => {
7
+ municipality: MunicipalityWithFounder;
8
+ errors: SmdError[];
9
+ };
10
+ export declare const getNewSchool: (name: string, founder: Founder | null, lineNumber: number, onError: (params: ErrorCallbackParams) => void, options?: OpenDataSyncOptionsPartial) => School;
11
+ export declare const wholeLineError: (message: string, line: string) => SmdError;
@@ -29,7 +29,7 @@ export const parseOrdinanceToAddressPoints = (lines, options = {}, initialState
29
29
  }
30
30
  if (state.currentSchool != null) {
31
31
  if (state.currentMunicipality == null) {
32
- state.currentMunicipality = getNewMunicipality("");
32
+ return [];
33
33
  }
34
34
  state.currentMunicipality.schools.push(mapSchoolForExport(state.currentSchool));
35
35
  }
@@ -78,7 +78,7 @@ const processOneLine = (params) => {
78
78
  processAddressPointLine(params);
79
79
  }
80
80
  };
81
- const processMunicipalityLine = ({ line, state }) => {
81
+ const processMunicipalityLine = ({ line, state, onError }) => {
82
82
  if (state.currentSchool !== null) {
83
83
  state.currentMunicipality.schools.push(state.currentSchool);
84
84
  state.currentSchool = null;
@@ -86,7 +86,8 @@ const processMunicipalityLine = ({ line, state }) => {
86
86
  if (state.currentMunicipality !== null) {
87
87
  state.municipalities.push(convertMunicipality(state.currentMunicipality));
88
88
  }
89
- state.currentMunicipality = getNewMunicipality(line.substring(1).trim());
89
+ const { municipality, errors } = getNewMunicipality(line);
90
+ state.currentMunicipality = municipality;
90
91
  state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
91
92
  state.currentSchool = null;
92
93
  };
@@ -96,11 +97,18 @@ const processEmptyLine = ({ state }) => {
96
97
  state.currentSchool = null;
97
98
  }
98
99
  };
99
- const processSchoolLine = ({ line, lineNumber, state }) => {
100
+ const processSchoolLine = ({ line, lineNumber, state, onError, }) => {
100
101
  if (state.currentMunicipality === null) {
101
- throw new Error("No municipality defined on line " + lineNumber);
102
+ onError({
103
+ lineNumber,
104
+ line,
105
+ errors: [
106
+ wholeLineError("Definici školy musí předcházet definice zřizovatele (uvozená '#', např. '# Strakonice').", line),
107
+ ],
108
+ });
109
+ return;
102
110
  }
103
- state.currentSchool = getNewSchool(line, state.currentMunicipality.founder);
111
+ state.currentSchool = getNewSchool(line, state.currentMunicipality.founder, lineNumber, onError);
104
112
  state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder);
105
113
  };
106
114
  const processMunicipalitySwitchLine = ({ line, state, lineNumber, onError, }) => {
@@ -153,12 +161,15 @@ export const getNewMunicipality = (name, options) => {
153
161
  errors.forEach(console.error);
154
162
  }
155
163
  return {
156
- municipalityName: founder ? founder.name : "Neznámá obec",
157
- founder,
158
- schools: [],
164
+ municipality: {
165
+ municipalityName: founder ? founder.name : "Neznámá obec",
166
+ founder,
167
+ schools: [],
168
+ },
169
+ errors,
159
170
  };
160
171
  };
161
- export const getNewSchool = (name, founder, options) => {
172
+ export const getNewSchool = (name, founder, lineNumber, onError, options) => {
162
173
  if (options) {
163
174
  options = prepareOptions(options);
164
175
  setDbConfig({
@@ -167,14 +178,18 @@ export const getNewSchool = (name, founder, options) => {
167
178
  });
168
179
  }
169
180
  let exportSchool = {
170
- name: name,
181
+ name,
171
182
  izo: "",
172
183
  addresses: [],
173
184
  };
174
185
  if (founder !== null) {
175
- const { school } = findSchool(name, founder.schools);
186
+ const { school, errors } = findSchool(name, founder.schools);
187
+ if (errors.length > 0) {
188
+ onError({ lineNumber, line: name, errors });
189
+ }
176
190
  if (school) {
177
- school.izo = school.izo || "";
191
+ exportSchool.name = school.name;
192
+ exportSchool.izo = school.izo || "";
178
193
  if (school.locations.length > 0) {
179
194
  const position = getAddressPointById(school.locations[0].addressPointId);
180
195
  if (position !== null) {
@@ -196,8 +211,13 @@ const mapSchoolForExport = (school) => ({
196
211
  name: school.name,
197
212
  izo: school.izo,
198
213
  addresses: school.addresses,
199
- position: mapAddressPointForExport(school.position),
214
+ position: school.position ? mapAddressPointForExport(school.position) : null,
200
215
  });
201
216
  const cleanLine = (line) => {
202
217
  return line.trim().replace(/–/g, "-");
203
218
  };
219
+ export const wholeLineError = (message, line) => ({
220
+ message,
221
+ startOffset: 0,
222
+ endOffset: line.length + 1,
223
+ });
@@ -109,11 +109,11 @@ const Space = createToken({
109
109
  longer_alt: [MainSeparator, Separator],
110
110
  group: Lexer.SKIPPED,
111
111
  });
112
- const Colon = createToken({
113
- name: "Colon",
114
- pattern: /:/,
115
- group: Lexer.SKIPPED,
116
- });
112
+ // const Colon = createToken({
113
+ // name: "Colon",
114
+ // pattern: /:/,
115
+ // group: Lexer.SKIPPED,
116
+ // });
117
117
  const smdTokens = [
118
118
  MainSeparator,
119
119
  Separator,
@@ -130,7 +130,7 @@ const smdTokens = [
130
130
  Hyphen,
131
131
  Slash,
132
132
  Space,
133
- Colon,
133
+ // Colon,
134
134
  StreetName,
135
135
  ];
136
136
  MainSeparator.LABEL = "' - '";
@@ -2,7 +2,7 @@ import { AddressPoint as CzechAddressPoint } from "czech-address";
2
2
  import { Municipality as DbMunicipality, Founder } from "../db/types";
3
3
  export interface ProcessedSmdLines {
4
4
  smdLines: SmdLine[];
5
- errors: string[];
5
+ errors: SmdError[];
6
6
  }
7
7
  export interface SmdLine {
8
8
  street: string;
@@ -67,7 +67,7 @@ export interface Municipality {
67
67
  }
68
68
  export interface DbMunicipalityResult {
69
69
  municipality: DbMunicipality;
70
- errors: string[];
70
+ errors: SmdError[];
71
71
  }
72
72
  export interface MunicipalityWithFounder extends Municipality {
73
73
  founder: Founder | null;
@@ -83,7 +83,7 @@ export interface ProcessLineCallbackParams {
83
83
  line: string;
84
84
  }
85
85
  export interface ErrorCallbackParams extends ProcessLineCallbackParams {
86
- errors: string[];
86
+ errors: SmdError[];
87
87
  }
88
88
  export interface ProcessLineParams {
89
89
  line: string;
@@ -92,3 +92,8 @@ export interface ProcessLineParams {
92
92
  onError: (params: ErrorCallbackParams) => void;
93
93
  onWarning: (params: ErrorCallbackParams) => void;
94
94
  }
95
+ export interface SmdError {
96
+ startOffset: number;
97
+ endOffset: number;
98
+ message: string;
99
+ }
package/package.json CHANGED
@@ -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.7",
51
+ "version": "1.0.8",
52
52
  "main": "dist/index.js",
53
53
  "types": "dist/index.d.ts",
54
54
  "files": [