From 2d8a554db4ca86efcccc38c40c00fd7794460478 Mon Sep 17 00:00:00 2001 From: jcpitre <106176106+jcpitre@users.noreply.github.com> Date: Wed, 21 Jun 2023 18:19:05 -0400 Subject: [PATCH 1/4] feat: Added missing_recommended_column notice (#1470) --- RULES.md | 259 +++++++++--------- .../MissingRecommendedColumnNotice.java | 38 +++ .../gtfsvalidator/notice/NoticeContainer.java | 11 + .../gtfsvalidator/notice/ResolvedNotice.java | 12 + .../gtfsvalidator/table/AnyTableLoader.java | 4 + .../table/GtfsColumnDescriptor.java | 4 + .../DefaultTableHeaderValidator.java | 20 +- .../validator/TableHeaderValidator.java | 1 + .../gtfsvalidator/parsing/RowParserTest.java | 6 + .../table/AnyTableLoaderTest.java | 3 + .../testgtfs/GtfsTestTableDescriptor.java | 2 + .../validator/TableHeaderValidatorTest.java | 25 +- .../table/GtfsStopTimeSchema.java | 2 + .../validator/TimepointTimeValidator.java | 19 +- .../validator/TimepointTimeValidatorTest.java | 56 +--- .../annotation/RecommendedColumn.java | 42 +++ .../gtfsvalidator/processor/Analyser.java | 1 + .../processor/GtfsFieldDescriptor.java | 4 + .../processor/TableDescriptorGenerator.java | 2 + .../RecommendedColumnAnnotationSchema.java | 11 + ...RecommendedColumnAnnotationSchemaTest.java | 51 ++++ 21 files changed, 371 insertions(+), 202 deletions(-) create mode 100644 core/src/main/java/org/mobilitydata/gtfsvalidator/notice/MissingRecommendedColumnNotice.java create mode 100644 model/src/main/java/org/mobilitydata/gtfsvalidator/annotation/RecommendedColumn.java create mode 100644 processor/tests/src/main/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchema.java create mode 100644 processor/tests/src/test/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchemaTest.java diff --git a/RULES.md b/RULES.md index 7a1b317c50..f8f1b276de 100644 --- a/RULES.md +++ b/RULES.md @@ -26,119 +26,119 @@ Each Notice is associated with a severity: `INFO`, `WARNING`, `ERROR`. ## Table of ERRORS -| Notice code | Description | -|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| -| [`block_trips_with_overlapping_stop_times`](#block_trips_with_overlapping_stop_times) | Block trips with overlapping stop times. | -| [`csv_parsing_failed`](#csv_parsing_failed) | Parsing of a CSV file failed. | -| [`decreasing_shape_distance`](#decreasing_shape_distance) | Decreasing `shape_dist_traveled` in `shapes.txt`. | -| [`decreasing_or_equal_stop_time_distance`](#decreasing_or_equal_stop_time_distance) | Decreasing or equal `shape_dist_traveled` in `stop_times.txt`. | -| [`duplicated_column`](#duplicated_column) | Duplicated column in CSV. | -| [`duplicate_key`](#duplicate_key) | Duplicated entity. | -| [`empty_column_name`](#empty_column_name) | A column name is empty. | -| [`empty_file`](#empty_file) | A CSV file is empty. | -| [`equal_shape_distance_diff_coordinates`](#equal_shape_distance_diff_coordinates) | Two consecutive points have equal `shape_dist_traveled` and different lat/lon coordinates in `shapes.txt`. | -| [`fare_transfer_rule_duration_limit_type_without_duration_limit`](#fare_transfer_rule_duration_limit_type_without_duration_limit) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified. | -| [`fare_transfer_rule_duration_limit_without_type`](#fare_transfer_rule_duration_limit_without_type) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified. | -| [`fare_transfer_rule_invalid_transfer_count`](#fare_transfer_rule_invalid_transfer_count) | A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value. | -| [`fare_transfer_rule_missing_transfer_count`](#fare_transfer_rule_missing_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. | -| [`fare_transfer_rule_with_forbidden_transfer_count`](#fare_transfer_rule_with_forbidden_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. | -| [`foreign_key_violation`](#foreign_key_violation) | Wrong foreign key. | -| [`inconsistent_agency_timezone`](#inconsistent_agency_timezone) | Inconsistent Timezone among agencies. | -| [`invalid_color`](#invalid_color) | A field contains an invalid color value. | -| [`invalid_currency`](#invalid_currency) | A field contains a wrong currency code. | -| [`invalid_currency_amount`](#invalid_currency_amount) | A currency amount field has a value that does not match the format of its corresponding currency code field. | -| [`invalid_date`](#invalid_date) | A field cannot be parsed as date. | -| [`invalid_email`](#invalid_email) | A field contains a malformed email address. | -| [`invalid_float`](#invalid_float) | A field cannot be parsed as a floating point number. | -| [`invalid_integer`](#invalid_integer) | A field cannot be parsed as an integer. | -| [`invalid_language_code`](#invalid_language_code) | A field contains a wrong language code. | -| [`invalid_phone_number`](#invalid_phone_number) | A field contains a malformed phone number. | -| [`invalid_row_length`](#invalid_row_length) | Invalid csv row length. | -| [`invalid_time`](#invalid_time) | A field cannot be parsed as time. | -| [`invalid_timezone`](#invalid_timezone) | A field cannot be parsed as a timezone. | -| [`invalid_url`](#invalid_url) | A field contains a malformed URL. | -| [`location_without_parent_station`](#location_without_parent_station) | A location that must have `parent_station` field does not have it. | -| [`location_with_unexpected_stop_time`](#location_with_unexpected_stop_time) | A location in `stops.txt` that is not a stop is referenced by some `stop_times.stop_id`. | -| [`missing_calendar_and_calendar_date_files`](#missing_calendar_and_calendar_date_files) | Missing GTFS files `calendar.txt` and `calendar_dates.txt`. | -| [`missing_level_id`](#missing_level_id) | `stops.level_id` is conditionally required. | -| [`missing_required_column`](#missing_required_column) | A required column is missing in the input file. | -| [`missing_required_field`](#missing_required_field) | A required field is missing. | -| [`missing_required_file`](#missing_required_file) | A required file is missing. | -| [`missing_stop_name`](#missing_stop_name) | `stops.stop_name` is required for `location_type` equal to `0`, `1`, or `2`. | -| [`missing_trip_edge`](#missing_trip_edge) | Missing trip edge `arrival_time` or `departure_time`. | -| [`new_line_in_value`](#new_line_in_value) | New line or carriage return in a value in CSV file. | -| [`number_out_of_range`](#number_out_of_range) | Out of range value. | -| [`overlapping_frequency`](#overlapping_frequency) | Trip frequencies overlap. | -| [`pathway_to_platform_with_boarding_areas`](#pathway_to_platform_with_boarding_areas) | A pathway has an endpoint that is a platform which has boarding areas. | -| [`pathway_to_wrong_location_type`](#pathway_to_wrong_location_type) | A pathway has an endpoint that is a station. | -| [`pathway_unreachable_location`](#pathway_unreachable_location) | A location is not reachable at least in one direction: from the entrances or to the exits. | -| [`point_near_origin`](#point_near_origin) | A point is too close to origin `(0, 0)`. | -| [`point_near_pole`](#point_near_pole) | A point is too close to the North or South Pole. | -| [`route_both_short_and_long_name_missing`](#route_both_short_and_long_name_missing) | Missing route short name and long name. | -| [`start_and_end_range_equal`](#start_and_end_range_equal) | Two date or time fields are equal. | -| [`start_and_end_range_out_of_order`](#start_and_end_range_out_of_order) | Two date or time fields are out of order. | -| [`station_with_parent_station`](#station_with_parent_station) | A station has `parent_station` field set. | -| [`stop_time_timepoint_without_times`](#stop_time_timepoint_without_times) | `arrival_time` or `departure_time` not specified for timepoint. | -| [`stop_time_with_arrival_before_previous_departure_time`](#stop_time_with_arrival_before_previous_departure_time) | Backwards time travel between stops in `stop_times.txt` | -| [`stop_time_with_only_arrival_or_departure_time`](#stop_time_with_only_arrival_or_departure_time) | Missing `stop_times.arrival_time` or `stop_times.departure_time`. | -| [`stop_without_location`](#stop_without_location) | `stop_lat` and/or `stop_lon` is missing for stop with `location_type` equal to`0`, `1`, or `2` | -| [`stop_without_zone_id`](#stop_without_zone_id) | Stop without value for `stops.zone_id`. | -| [`too_many_rows`](#too_many_rows) | A CSV file has too many rows. | -| [`transfer_with_invalid_stop_location_type`](#transfer_with_invalid_stop_location_type) | A stop id field from GTFS file `transfers.txt` references a stop that has a `location_type` other than 0 or 1 (aka Stop/Platform or Station). | -| [`transfer_with_invalid_trip_and_route`](#transfer_with_invalid_trip_and_route) | A trip id field from GTFS file `transfers.txt` references a route that does not match its `trips.txt` `route_id`. | -| [`transfer_with_invalid_trip_and_stop`](#transfer_with_invalid_trip_and_stop) | A trip id field from GTFS file `transfers.txt` references a stop that is not included in the referenced trip's stop-times. | -| [`translation_foreign_key_violation`](#translation_foreign_key_violation) | An entity with the given `record_id` and `record_sub_id` cannot be found in the referenced table. | -| [`translation_unexpected_value`](#translation_unexpected_value) | A field in a translations row has value but must be empty. | -| [`wrong_parent_location_type`](#wrong_parent_location_type) | Incorrect type of the parent location. | +| Notice code | Description | +|-----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| [`block_trips_with_overlapping_stop_times`](#block_trips_with_overlapping_stop_times) | Block trips with overlapping stop times. | +| [`csv_parsing_failed`](#csv_parsing_failed) | Parsing of a CSV file failed. | +| [`decreasing_shape_distance`](#decreasing_shape_distance) | Decreasing `shape_dist_traveled` in `shapes.txt`. | +| [`decreasing_or_equal_stop_time_distance`](#decreasing_or_equal_stop_time_distance) | Decreasing or equal `shape_dist_traveled` in `stop_times.txt`. | +| [`duplicated_column`](#duplicated_column) | Duplicated column in CSV. | +| [`duplicate_key`](#duplicate_key) | Duplicated entity. | +| [`empty_column_name`](#empty_column_name) | A column name is empty. | +| [`empty_file`](#empty_file) | A CSV file is empty. | +| [`equal_shape_distance_diff_coordinates`](#equal_shape_distance_diff_coordinates) | Two consecutive points have equal `shape_dist_traveled` and different lat/lon coordinates in `shapes.txt`. | +| [`fare_transfer_rule_duration_limit_type_without_duration_limit`](#fare_transfer_rule_duration_limit_type_without_duration_limit) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified. | +| [`fare_transfer_rule_duration_limit_without_type`](#fare_transfer_rule_duration_limit_without_type) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified. | +| [`fare_transfer_rule_invalid_transfer_count`](#fare_transfer_rule_invalid_transfer_count) | A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value. | +| [`fare_transfer_rule_missing_transfer_count`](#fare_transfer_rule_missing_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. | +| [`fare_transfer_rule_with_forbidden_transfer_count`](#fare_transfer_rule_with_forbidden_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. | +| [`foreign_key_violation`](#foreign_key_violation) | Wrong foreign key. | +| [`inconsistent_agency_timezone`](#inconsistent_agency_timezone) | Inconsistent Timezone among agencies. | +| [`invalid_color`](#invalid_color) | A field contains an invalid color value. | +| [`invalid_currency`](#invalid_currency) | A field contains a wrong currency code. | +| [`invalid_currency_amount`](#invalid_currency_amount) | A currency amount field has a value that does not match the format of its corresponding currency code field. | +| [`invalid_date`](#invalid_date) | A field cannot be parsed as date. | +| [`invalid_email`](#invalid_email) | A field contains a malformed email address. | +| [`invalid_float`](#invalid_float) | A field cannot be parsed as a floating point number. | +| [`invalid_integer`](#invalid_integer) | A field cannot be parsed as an integer. | +| [`invalid_language_code`](#invalid_language_code) | A field contains a wrong language code. | +| [`invalid_phone_number`](#invalid_phone_number) | A field contains a malformed phone number. | +| [`invalid_row_length`](#invalid_row_length) | Invalid csv row length. | +| [`invalid_time`](#invalid_time) | A field cannot be parsed as time. | +| [`invalid_timezone`](#invalid_timezone) | A field cannot be parsed as a timezone. | +| [`invalid_url`](#invalid_url) | A field contains a malformed URL. | +| [`location_without_parent_station`](#location_without_parent_station) | A location that must have `parent_station` field does not have it. | +| [`location_with_unexpected_stop_time`](#location_with_unexpected_stop_time) | A location in `stops.txt` that is not a stop is referenced by some `stop_times.stop_id`. | +| [`missing_calendar_and_calendar_date_files`](#missing_calendar_and_calendar_date_files) | Missing GTFS files `calendar.txt` and `calendar_dates.txt`. | +| [`missing_level_id`](#missing_level_id) | `stops.level_id` is conditionally required. | +| [`missing_required_column`](#missing_required_column) | A required column is missing in the input file. | +| [`missing_required_field`](#missing_required_field) | A required field is missing. | +| [`missing_required_file`](#missing_required_file) | A required file is missing. | +| [`missing_stop_name`](#missing_stop_name) | `stops.stop_name` is required for `location_type` equal to `0`, `1`, or `2`. | +| [`missing_trip_edge`](#missing_trip_edge) | Missing trip edge `arrival_time` or `departure_time`. | +| [`new_line_in_value`](#new_line_in_value) | New line or carriage return in a value in CSV file. | +| [`number_out_of_range`](#number_out_of_range) | Out of range value. | +| [`overlapping_frequency`](#overlapping_frequency) | Trip frequencies overlap. | +| [`pathway_to_platform_with_boarding_areas`](#pathway_to_platform_with_boarding_areas) | A pathway has an endpoint that is a platform which has boarding areas. | +| [`pathway_to_wrong_location_type`](#pathway_to_wrong_location_type) | A pathway has an endpoint that is a station. | +| [`pathway_unreachable_location`](#pathway_unreachable_location) | A location is not reachable at least in one direction: from the entrances or to the exits. | +| [`point_near_origin`](#point_near_origin) | A point is too close to origin `(0, 0)`. | +| [`point_near_pole`](#point_near_pole) | A point is too close to the North or South Pole. | +| [`route_both_short_and_long_name_missing`](#route_both_short_and_long_name_missing) | Missing route short name and long name. | +| [`start_and_end_range_equal`](#start_and_end_range_equal) | Two date or time fields are equal. | +| [`start_and_end_range_out_of_order`](#start_and_end_range_out_of_order) | Two date or time fields are out of order. | +| [`station_with_parent_station`](#station_with_parent_station) | A station has `parent_station` field set. | +| [`stop_time_timepoint_without_times`](#stop_time_timepoint_without_times) | `arrival_time` or `departure_time` not specified for timepoint. | +| [`stop_time_with_arrival_before_previous_departure_time`](#stop_time_with_arrival_before_previous_departure_time) | Backwards time travel between stops in `stop_times.txt` | +| [`stop_time_with_only_arrival_or_departure_time`](#stop_time_with_only_arrival_or_departure_time) | Missing `stop_times.arrival_time` or `stop_times.departure_time`. | +| [`stop_without_location`](#stop_without_location) | `stop_lat` and/or `stop_lon` is missing for stop with `location_type` equal to`0`, `1`, or `2` | +| [`stop_without_zone_id`](#stop_without_zone_id) | Stop without value for `stops.zone_id`. | +| [`too_many_rows`](#too_many_rows) | A CSV file has too many rows. | +| [`transfer_with_invalid_stop_location_type`](#transfer_with_invalid_stop_location_type) | A stop id field from GTFS file `transfers.txt` references a stop that has a `location_type` other than 0 or 1 (aka Stop/Platform or Station). | +| [`transfer_with_invalid_trip_and_route`](#transfer_with_invalid_trip_and_route) | A trip id field from GTFS file `transfers.txt` references a route that does not match its `trips.txt` `route_id`. | +| [`transfer_with_invalid_trip_and_stop`](#transfer_with_invalid_trip_and_stop) | A trip id field from GTFS file `transfers.txt` references a stop that is not included in the referenced trip's stop-times. | +| [`translation_foreign_key_violation`](#translation_foreign_key_violation) | An entity with the given `record_id` and `record_sub_id` cannot be found in the referenced table. | +| [`translation_unexpected_value`](#translation_unexpected_value) | A field in a translations row has value but must be empty. | +| [`wrong_parent_location_type`](#wrong_parent_location_type) | Incorrect type of the parent location. | ## Table of WARNINGS -| Notice code | Description | -|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [`attribution_without_role`](#attribution_without_role) | Attribution with no role. | -| [`duplicate_fare_media`](#duplicate_fare_media) | Two distinct fare media have the same fare media name and type. | -| [`duplicate_route_name`](#duplicate_route_name) | Two distinct routes have either the same `route_short_name`, the same `route_long_name`, or the same combination of `route_short_name` and `route_long_name`. | -| [`empty_row`](#empty_row) | A row in the input file has only spaces. | -| [`equal_shape_distance_same_coordinates`](#equal_shape_distance_same_coordinates) | Two consecutive points have equal `shape_dist_traveled` and the same lat/lon coordinates in `shapes.txt`. | -| [`expired_calendar`](#expired_calendar) | Dataset should not contain date ranges for services that have already expired. | -| [`fast_travel_between_consecutive_stops`](#fast_travel_between_consecutive_stops) | A transit vehicle moves too fast between two consecutive stops. | -| [`fast_travel_between_far_stops`](#fast_travel_between_far_stops) | A transit vehicle moves too fast between two far stops. | -| [`feed_expiration_date7_days`](#feed_expiration_date7_days) | Dataset should be valid for at least the next 7 days. | -| [`feed_expiration_date30_days`](#feed_expiration_date30_days) | Dataset should cover at least the next 30 days of service. | -| [`feed_info_lang_and_agency_lang_mismatch`](#feed_info_lang_and_agency_lang_mismatch) | Mismatching feed and agency language fields. | -| [`inconsistent_agency_lang`](#inconsistent_agency_lang) | Inconsistent language among agencies. | -| [`leading_or_trailing_whitespaces`](#leading_or_trailing_whitespaces) | The value in CSV file has leading or trailing whitespaces. | -| [`missing_feed_info_date`](#missing_feed_info_date) | `feed_end_date` should be provided if `feed_start_date` is provided. `feed_start_date` should be provided if `feed_end_date` is provided. | -| [`missing_recommended_file`](#missing_recommended_file) | A recommended file is missing. | -| [`missing_recommended_field`](#missing_recommended_field) | A recommended field is missing. | -| [`missing_timepoint_column`](#missing_timepoint_column) | `timepoint` column is missing for a dataset. | -| [`missing_timepoint_value`](#missing_timepoint_value) | `stop_times.timepoint` value is missing for a record. | -| [`mixed_case_recommended_field`](#mixed_case_recommended_field) | This field has customer-facing text and should use Mixed Case (should contain upper and lower case letters). | -| [`more_than_one_entity`](#more_than_one_entity) | More than one row in CSV. | -| [`non_ascii_or_non_printable_char`](#non_ascii_or_non_printable_char) | Non ascii or non printable char in `id`. | -| [`pathway_dangling_generic_node`](#pathway_dangling_generic_node) | A generic node has only one incident location in a pathway graph. | -| [`pathway_loop`](#pathway_loop) | A pathway starts and ends at the same location. | -| [`route_color_contrast`](#route_color_contrast) | Insufficient route color contrast. | -| [`route_long_name_contains_short_name`](#route_long_name_contains_short_name) | Long name should not contain short name for a single route. | -| [`route_short_name_too_long`](#route_short_name_too_long) | Short name of a route is too long (more than 12 characters). | -| [`same_name_and_description_for_route`](#same_name_and_description_for_route) | Same name and description for route. | -| [`same_name_and_description_for_stop`](#same_name_and_description_for_stop) | Same name and description for stop. | -| [`same_route_and_agency_url`](#same_route_and_agency_url) | Same `routes.route_url` and `agency.agency_url`. | -| [`same_stop_and_agency_url`](#same_stop_and_agency_url) | Same `stops.stop_url` and `agency.agency_url`. | -| [`same_stop_and_route_url`](#same_stop_and_route_url) | Same `stops.stop_url` and `routes.route_url`. | -| [`stop_has_too_many_matches_for_shape`](#stop_has_too_many_matches_for_shape) | Stop entry that has many potential matches to the trip's path of travel. | -| [`stops_match_shape_out_of_order`](#stops_match_shape_out_of_order) | Two stop entries are different than their arrival-departure order defined by the shapes.txt | -| [`stop_too_far_from_shape`](#stop_too_far_from_shape) | Stop too far from trip shape. | -| [`stop_too_far_from_shape_using_user_distance`](#stop_too_far_from_shape_using_user_distance) | Stop time too far from shape. | -| [`stop_without_stop_time`](#stop_without_stop_time) | A stop in `stops.txt` is not referenced by any `stop_times.stop_id`. | -| [`transfer_with_suspicious_mid_trip_in_seat`](#transfer_with_suspicious_mid_trip_in_seat) | A trip id field from GTFS file `transfers.txt` with an in-seat transfer type references a stop that is not in the expected position in the trip's stop-times. | -| [`translation_unknown_table_name`](#translation_unknown_table_name) | A translation references an unknown or missing GTFS table. | -| [`trip_coverage_not_active_for_next7_days`](#trip_coverage_not_active_for_next7_days) | Trips data should be valid for at least the next seven days. | -| [`unexpected_enum_value`](#unexpected_enum_value) | An enum has an unexpected value. | -| [`unusable_trip`](#unusable_trip) | Trips must have more than one stop to be usable. | -| [`unused_shape`](#unused_shape) | Shape is not used in GTFS file `trips.txt`. | -| [`unused_trip`](#unused_trip) | Trip is not be used in `stop_times.txt` | +| Notice code | Description | +|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`attribution_without_role`](#attribution_without_role) | Attribution with no role. | +| [`duplicate_fare_media`](#duplicate_fare_media) | Two distinct fare media have the same fare media name and type. | +| [`duplicate_route_name`](#duplicate_route_name) | Two distinct routes have either the same `route_short_name`, the same `route_long_name`, or the same combination of `route_short_name` and `route_long_name`. | +| [`empty_row`](#empty_row) | A row in the input file has only spaces. | +| [`equal_shape_distance_same_coordinates`](#equal_shape_distance_same_coordinates) | Two consecutive points have equal `shape_dist_traveled` and the same lat/lon coordinates in `shapes.txt`. | +| [`expired_calendar`](#expired_calendar) | Dataset should not contain date ranges for services that have already expired. | +| [`fast_travel_between_consecutive_stops`](#fast_travel_between_consecutive_stops) | A transit vehicle moves too fast between two consecutive stops. | +| [`fast_travel_between_far_stops`](#fast_travel_between_far_stops) | A transit vehicle moves too fast between two far stops. | +| [`feed_expiration_date7_days`](#feed_expiration_date7_days) | Dataset should be valid for at least the next 7 days. | +| [`feed_expiration_date30_days`](#feed_expiration_date30_days) | Dataset should cover at least the next 30 days of service. | +| [`feed_info_lang_and_agency_lang_mismatch`](#feed_info_lang_and_agency_lang_mismatch) | Mismatching feed and agency language fields. | +| [`inconsistent_agency_lang`](#inconsistent_agency_lang) | Inconsistent language among agencies. | +| [`leading_or_trailing_whitespaces`](#leading_or_trailing_whitespaces) | The value in CSV file has leading or trailing whitespaces. | +| [`missing_feed_info_date`](#missing_feed_info_date) | `feed_end_date` should be provided if `feed_start_date` is provided. `feed_start_date` should be provided if `feed_end_date` is provided. | +| [`missing_recommended_column`](#missing_recommended_column) | A recommended column is missing in the input file. | +| [`missing_recommended_file`](#missing_recommended_file) | A recommended file is missing. | +| [`missing_recommended_field`](#missing_recommended_field) | A recommended field is missing. | +| [`missing_timepoint_value`](#missing_timepoint_value) | `stop_times.timepoint` value is missing for a record. | +| [`mixed_case_recommended_field`](#mixed_case_recommended_field) | This field has customer-facing text and should use Mixed Case (should contain upper and lower case letters). | +| [`more_than_one_entity`](#more_than_one_entity) | More than one row in CSV. | +| [`non_ascii_or_non_printable_char`](#non_ascii_or_non_printable_char) | Non ascii or non printable char in `id`. | +| [`pathway_dangling_generic_node`](#pathway_dangling_generic_node) | A generic node has only one incident location in a pathway graph. | +| [`pathway_loop`](#pathway_loop) | A pathway starts and ends at the same location. | +| [`route_color_contrast`](#route_color_contrast) | Insufficient route color contrast. | +| [`route_long_name_contains_short_name`](#route_long_name_contains_short_name) | Long name should not contain short name for a single route. | +| [`route_short_name_too_long`](#route_short_name_too_long) | Short name of a route is too long (more than 12 characters). | +| [`same_name_and_description_for_route`](#same_name_and_description_for_route) | Same name and description for route. | +| [`same_name_and_description_for_stop`](#same_name_and_description_for_stop) | Same name and description for stop. | +| [`same_route_and_agency_url`](#same_route_and_agency_url) | Same `routes.route_url` and `agency.agency_url`. | +| [`same_stop_and_agency_url`](#same_stop_and_agency_url) | Same `stops.stop_url` and `agency.agency_url`. | +| [`same_stop_and_route_url`](#same_stop_and_route_url) | Same `stops.stop_url` and `routes.route_url`. | +| [`stop_has_too_many_matches_for_shape`](#stop_has_too_many_matches_for_shape) | Stop entry that has many potential matches to the trip's path of travel. | +| [`stops_match_shape_out_of_order`](#stops_match_shape_out_of_order) | Two stop entries are different than their arrival-departure order defined by the shapes.txt | +| [`stop_too_far_from_shape`](#stop_too_far_from_shape) | Stop too far from trip shape. | +| [`stop_too_far_from_shape_using_user_distance`](#stop_too_far_from_shape_using_user_distance) | Stop time too far from shape. | +| [`stop_without_stop_time`](#stop_without_stop_time) | A stop in `stops.txt` is not referenced by any `stop_times.stop_id`. | +| [`transfer_with_suspicious_mid_trip_in_seat`](#transfer_with_suspicious_mid_trip_in_seat) | A trip id field from GTFS file `transfers.txt` with an in-seat transfer type references a stop that is not in the expected position in the trip's stop-times. | +| [`translation_unknown_table_name`](#translation_unknown_table_name) | A translation references an unknown or missing GTFS table. | +| [`trip_coverage_not_active_for_next7_days`](#trip_coverage_not_active_for_next7_days) | Trips data should be valid for at least the next seven days. | +| [`unexpected_enum_value`](#unexpected_enum_value) | An enum has an unexpected value. | +| [`unusable_trip`](#unusable_trip) | Trips must have more than one stop to be usable. | +| [`unused_shape`](#unused_shape) | Shape is not used in GTFS file `trips.txt`. | +| [`unused_trip`](#unused_trip) | Trip is not be used in `stop_times.txt` | @@ -2092,6 +2092,28 @@ Even though `feed_info.start_date` and `feed_info.end_date` are optional, if one + + +### missing_recommended_column + +A recommended column is missing in the input file. + +#### References +* [GTFS terms definition](https://gtfs.org/reference/static/#term-definitions) +
+ +#### Notice fields description +| Field name | Description | Type | +|------------- |-------------------------------- |-------- | +| `filename` | The name of the faulty file. | String | +| `fieldName` | The name of the missing column. | String | + +#### Affected files +[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) + +
+ +
### missing_recommended_file @@ -2137,25 +2159,6 @@ The given field has no value in some input row, even though values are recommend - - -### missing_timepoint_column - -The `timepoint` column should be provided. - -#### References -* [stop_times.txt best practices](https://gtfs.org/schedule/best-practices/#stop_timestxt) -
- -#### Notice fields description -| Field name | Description | Type | -|---------------- |------------------------------------------------- |-------- | -| `filename` | The name of the affected file. | String | - -#### Affected files -* [`stop_times.txt`](https://gtfs.org/schedule/reference/#stop_timestxt) -
-
### missing_timepoint_value diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/MissingRecommendedColumnNotice.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/MissingRecommendedColumnNotice.java new file mode 100644 index 0000000000..926186dbfc --- /dev/null +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/MissingRecommendedColumnNotice.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mobilitydata.gtfsvalidator.notice; + +import static org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.SectionRef.TERM_DEFINITIONS; +import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.WARNING; + +import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; +import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.SectionRefs; + +/** A recommended column is missing in the input file. */ +@GtfsValidationNotice(severity = WARNING, sections = @SectionRefs(TERM_DEFINITIONS)) +public class MissingRecommendedColumnNotice extends ValidationNotice { + + /** The name of the faulty file. */ + private final String filename; + + /** The name of the missing column. */ + private final String fieldName; + + public MissingRecommendedColumnNotice(String filename, String fieldName) { + this.filename = filename; + this.fieldName = fieldName; + } +} diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java index 997325c411..c5231b5316 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java @@ -58,6 +58,7 @@ public class NoticeContainer { private final List> systemErrors = new ArrayList<>(); private final Map noticesCountPerTypeAndSeverity = new HashMap<>(); private boolean hasValidationErrors = false; + private boolean hasValidationWarnings = false; /** * Used to specify limits on amount of notices in this {@code NoticeContainer}. @@ -99,6 +100,10 @@ public void addValidationNoticeWithSeverity( if (resolved.isError()) { hasValidationErrors = true; } + if (resolved.isWarning()) { + hasValidationWarnings = true; + } + updateNoticeCount(resolved); if (validationNotices.size() >= maxTotalValidationNotices || noticesCountPerTypeAndSeverity.get(resolved.getMappingKey()) @@ -147,6 +152,7 @@ public void addAll(NoticeContainer otherContainer) { validationNotices.addAll(otherContainer.validationNotices); systemErrors.addAll(otherContainer.systemErrors); hasValidationErrors |= otherContainer.hasValidationErrors; + hasValidationWarnings |= otherContainer.hasValidationWarnings; for (Entry entry : otherContainer.noticesCountPerTypeAndSeverity.entrySet()) { int count = noticesCountPerTypeAndSeverity.getOrDefault(entry.getKey(), 0); noticesCountPerTypeAndSeverity.put(entry.getKey(), count + entry.getValue()); @@ -158,6 +164,11 @@ public boolean hasValidationErrors() { return hasValidationErrors; } + /** Tells if this container has any {@code ValidationNotice} that is a warning. */ + public boolean hasValidationWarnings() { + return hasValidationWarnings; + } + public List> getResolvedValidationNotices() { return validationNotices; } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ResolvedNotice.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ResolvedNotice.java index feb26b2271..04a61be24d 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ResolvedNotice.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ResolvedNotice.java @@ -81,4 +81,16 @@ public int hashCode() { public boolean isError() { return getSeverityLevel().ordinal() >= SeverityLevel.ERROR.ordinal(); } + + /** + * Tells if this notice is a {@code WARNING}. + * + *

This method is preferred to checking {@code severityLevel} directly since more levels may be + * added in the future. + * + * @return true if this notice is a warning, false otherwise + */ + public boolean isWarning() { + return getSeverityLevel() == SeverityLevel.WARNING; + } } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoader.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoader.java index ed2baa720b..78dd9abfec 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoader.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoader.java @@ -152,6 +152,10 @@ private static NoticeContainer validateHeaders( .filter(GtfsColumnDescriptor::headerRequired) .map(GtfsColumnDescriptor::columnName) .collect(Collectors.toSet()), + columnDescriptors.stream() + .filter(GtfsColumnDescriptor::headerRecommended) + .map(GtfsColumnDescriptor::columnName) + .collect(Collectors.toSet()), headerNotices); return headerNotices; } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsColumnDescriptor.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsColumnDescriptor.java index d75c87933d..0546e479d1 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsColumnDescriptor.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsColumnDescriptor.java @@ -11,6 +11,8 @@ public abstract class GtfsColumnDescriptor { public abstract boolean headerRequired(); + public abstract boolean headerRecommended(); + public abstract FieldLevelEnum fieldLevel(); public abstract Optional numberBounds(); @@ -33,6 +35,8 @@ public abstract static class Builder { public abstract Builder setHeaderRequired(boolean value); + public abstract Builder setHeaderRecommended(boolean value); + public abstract Builder setFieldLevel(FieldLevelEnum value); public abstract Builder setNumberBounds(Optional value); diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/DefaultTableHeaderValidator.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/DefaultTableHeaderValidator.java index 6f9b993270..3ef0f174c6 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/DefaultTableHeaderValidator.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/DefaultTableHeaderValidator.java @@ -23,6 +23,7 @@ import java.util.TreeSet; import org.mobilitydata.gtfsvalidator.notice.DuplicatedColumnNotice; import org.mobilitydata.gtfsvalidator.notice.EmptyColumnNameNotice; +import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedColumnNotice; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredColumnNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnknownColumnNotice; @@ -36,14 +37,20 @@ public void validate( CsvHeader actualHeader, Set supportedColumns, Set requiredColumns, + Set recommendedColumns, NoticeContainer noticeContainer) { if (actualHeader.getColumnCount() == 0) { // This is an empty file. return; } Map columnIndices = new HashMap<>(); - // Sorted tree set for stable order of notices. + // Sorted tree set of all the columns for stable order of notices. + // We remove the columns that are properly present and well formed from that set, and at the + // end only the missing required columns are left in the set. TreeSet missingColumns = new TreeSet<>(requiredColumns); + // We also want to find the recommended columns that are absent. We use the same scheme for + // these. + TreeSet missingRecommendedColumns = new TreeSet<>(recommendedColumns); for (int i = 0; i < actualHeader.getColumnCount(); ++i) { String column = actualHeader.getColumnName(i); // Column indices are zero-based. We add 1 to make them 1-based. @@ -59,12 +66,23 @@ public void validate( if (!supportedColumns.contains(column)) { noticeContainer.addValidationNotice(new UnknownColumnNotice(filename, column, i + 1)); } + + // If the column is present, it should not be in the missing required columns set missingColumns.remove(column); + + // If the column is present, it should not be in the missing recommended columns set + missingRecommendedColumns.remove(column); } if (!missingColumns.isEmpty()) { for (String column : missingColumns) { noticeContainer.addValidationNotice(new MissingRequiredColumnNotice(filename, column)); } } + + if (!missingRecommendedColumns.isEmpty()) { + for (String column : missingRecommendedColumns) { + noticeContainer.addValidationNotice(new MissingRecommendedColumnNotice(filename, column)); + } + } } } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java index ef42d43770..3cc5732d2d 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java @@ -28,5 +28,6 @@ void validate( CsvHeader actualHeader, Set supportedHeaders, Set requiredHeaders, + Set recommendedHeaders, NoticeContainer noticeContainer); } diff --git a/core/src/test/java/org/mobilitydata/gtfsvalidator/parsing/RowParserTest.java b/core/src/test/java/org/mobilitydata/gtfsvalidator/parsing/RowParserTest.java index c3c0db2cf7..260f3da2e2 100644 --- a/core/src/test/java/org/mobilitydata/gtfsvalidator/parsing/RowParserTest.java +++ b/core/src/test/java/org/mobilitydata/gtfsvalidator/parsing/RowParserTest.java @@ -56,6 +56,11 @@ public boolean headerRequired() { return false; } + @Override + public boolean headerRecommended() { + return false; + } + @Override public FieldLevelEnum fieldLevel() { return FieldLevelEnum.REQUIRED; @@ -141,6 +146,7 @@ public void asString_recommended_missing() { GtfsColumnDescriptor.builder() .setColumnName("column name") .setHeaderRequired(false) + .setHeaderRecommended(false) .setFieldLevel(FieldLevelEnum.RECOMMENDED) .setIsMixedCase(false) .setIsCached(false) diff --git a/core/src/test/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoaderTest.java b/core/src/test/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoaderTest.java index c715a38e2f..29802babef 100644 --- a/core/src/test/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoaderTest.java +++ b/core/src/test/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoaderTest.java @@ -88,6 +88,7 @@ public void validate( CsvHeader actualHeader, Set supportedHeaders, Set requiredHeaders, + Set recommendedHeaders, NoticeContainer noticeContainer) { noticeContainer.addValidationNotice(headerValidationNotice); } @@ -144,6 +145,7 @@ public void missingRequiredField() { GtfsColumnDescriptor.builder() .setColumnName(GtfsTestEntity.ID_FIELD_NAME) .setHeaderRequired(true) + .setHeaderRecommended(false) .setFieldLevel(FieldLevelEnum.REQUIRED) .setIsMixedCase(false) .setIsCached(false) @@ -151,6 +153,7 @@ public void missingRequiredField() { GtfsColumnDescriptor.builder() .setColumnName(GtfsTestEntity.CODE_FIELD_NAME) .setHeaderRequired(false) + .setHeaderRecommended(false) .setFieldLevel(FieldLevelEnum.REQUIRED) .setIsMixedCase(false) .setIsCached(false) diff --git a/core/src/test/java/org/mobilitydata/gtfsvalidator/testgtfs/GtfsTestTableDescriptor.java b/core/src/test/java/org/mobilitydata/gtfsvalidator/testgtfs/GtfsTestTableDescriptor.java index eb42741abc..4e6d73b0b2 100644 --- a/core/src/test/java/org/mobilitydata/gtfsvalidator/testgtfs/GtfsTestTableDescriptor.java +++ b/core/src/test/java/org/mobilitydata/gtfsvalidator/testgtfs/GtfsTestTableDescriptor.java @@ -41,6 +41,7 @@ public ImmutableList getColumns() { GtfsColumnDescriptor.builder() .setColumnName(GtfsTestEntity.ID_FIELD_NAME) .setHeaderRequired(true) + .setHeaderRecommended(false) .setFieldLevel(FieldLevelEnum.REQUIRED) .setIsMixedCase(false) .setIsCached(false) @@ -49,6 +50,7 @@ public ImmutableList getColumns() { GtfsColumnDescriptor.builder() .setColumnName(GtfsTestEntity.CODE_FIELD_NAME) .setHeaderRequired(false) + .setHeaderRecommended(false) .setFieldLevel(FieldLevelEnum.OPTIONAL) .setIsMixedCase(false) .setIsCached(false) diff --git a/core/src/test/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidatorTest.java b/core/src/test/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidatorTest.java index a26323d187..1946ecd024 100644 --- a/core/src/test/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidatorTest.java +++ b/core/src/test/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidatorTest.java @@ -19,11 +19,13 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableSet; +import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mobilitydata.gtfsvalidator.notice.DuplicatedColumnNotice; import org.mobilitydata.gtfsvalidator.notice.EmptyColumnNameNotice; +import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedColumnNotice; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredColumnNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnknownColumnNotice; @@ -40,6 +42,7 @@ public void expectedColumns() { new CsvHeader(new String[] {"stop_id", "stop_name"}), ImmutableSet.of("stop_id", "stop_name", "stop_lat", "stop_lon"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()).isEmpty(); @@ -55,6 +58,7 @@ public void unknownColumnShouldGenerateNotice() { new CsvHeader(new String[] {"stop_id", "stop_name", "stop_extra"}), ImmutableSet.of("stop_id", "stop_name"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()) @@ -71,11 +75,27 @@ public void missingRequiredColumnShouldGenerateNotice() { new CsvHeader(new String[] {"stop_name"}), ImmutableSet.of("stop_id", "stop_name"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()) .containsExactly(new MissingRequiredColumnNotice("stops.txt", "stop_id")); - assertThat(container.hasValidationErrors()).isTrue(); + } + + @Test + public void missingRecommendedColumnShouldGenerateNotice() { + NoticeContainer container = new NoticeContainer(); + new DefaultTableHeaderValidator() + .validate( + "stops.txt", + new CsvHeader(new String[] {"stop_name"}), + Set.of("stop_id", "stop_name"), + Set.of(), + Set.of("stop_id"), + container); + + assertThat(container.getValidationNotices()) + .containsExactly(new MissingRecommendedColumnNotice("stops.txt", "stop_id")); } @Test @@ -87,6 +107,7 @@ public void duplicatedColumnShouldGenerateNotice() { new CsvHeader(new String[] {"stop_id", "stop_name", "stop_id"}), ImmutableSet.of("stop_id", "stop_name"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()) @@ -103,6 +124,7 @@ public void emptyFileShouldNotGenerateNotice() { CsvHeader.EMPTY, ImmutableSet.of("stop_id", "stop_name"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()).isEmpty(); @@ -118,6 +140,7 @@ public void emptyColumnNameShouldGenerateNotice() { new CsvHeader(new String[] {"stop_id", null, "stop_name", ""}), ImmutableSet.of("stop_id", "stop_name"), ImmutableSet.of("stop_id"), + Set.of(), container); assertThat(container.getValidationNotices()) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java index 731479a1c2..f35ce24ff9 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java @@ -29,6 +29,7 @@ import org.mobilitydata.gtfsvalidator.annotation.Index; import org.mobilitydata.gtfsvalidator.annotation.NonNegative; import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey; +import org.mobilitydata.gtfsvalidator.annotation.RecommendedColumn; import org.mobilitydata.gtfsvalidator.annotation.Required; import org.mobilitydata.gtfsvalidator.type.GtfsTime; @@ -77,5 +78,6 @@ public interface GtfsStopTimeSchema extends GtfsEntity { double shapeDistTraveled(); @DefaultValue("1") + @RecommendedColumn GtfsStopTimeTimepoint timepoint(); } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidator.java index b8db497c69..972a35d8f0 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidator.java @@ -38,7 +38,6 @@ *

  • {@link StopTimeTimepointWithoutTimesNotice} - a timepoint does not specifies arrival_time * or departure_time *
  • {@link MissingTimepointValueNotice} - value for {@code stop_times.timepoint} is missing - *
  • {@link MissingTimepointColumnNotice} - field {@code stop_times.timepoint} is missing * */ @GtfsValidator @@ -55,10 +54,9 @@ public class TimepointTimeValidator extends FileValidator { public void validate(NoticeContainer noticeContainer) { if (!stopTimes.hasColumn(GtfsStopTime.TIMEPOINT_FIELD_NAME)) { // legacy datasets do not use timepoint column in stop_times.txt as a result: - // - this should be flagged; + // - this should be flagged in the header tests. // - but also no notice regarding the absence of arrival_time or departure_time should be // generated - noticeContainer.addValidationNotice(new MissingTimepointColumnNotice()); return; } for (GtfsStopTime stopTime : stopTimes.getEntities()) { @@ -139,19 +137,4 @@ static class MissingTimepointValueNotice extends ValidationNotice { this.stopSequence = stopTime.stopSequence(); } } - - /** `timepoint` column is missing for a dataset. */ - @GtfsValidationNotice( - severity = WARNING, - files = @FileRefs(GtfsStopTimeSchema.class), - bestPractices = @FileRefs(GtfsStopTimeSchema.class)) - static class MissingTimepointColumnNotice extends ValidationNotice { - - /** The name of the affected file. */ - private final String filename; - - MissingTimepointColumnNotice() { - this.filename = GtfsStopTime.FILENAME; - } - } } diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidatorTest.java index 9e3a9aed2c..159105a2af 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/TimepointTimeValidatorTest.java @@ -39,7 +39,6 @@ import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; import org.mobilitydata.gtfsvalidator.type.GtfsTime; -import org.mobilitydata.gtfsvalidator.validator.TimepointTimeValidator.MissingTimepointColumnNotice; import org.mobilitydata.gtfsvalidator.validator.TimepointTimeValidator.MissingTimepointValueNotice; import org.mobilitydata.gtfsvalidator.validator.TimepointTimeValidator.StopTimeTimepointWithoutTimesNotice; @@ -59,7 +58,8 @@ private static List generateNotices( return noticeContainer.getValidationNotices(); } - // using this header will trigger a MissingTimepointColumnNotice + // Using this header will trigger a MissingRecommendedColumnNotice since the timepoint column is + // missing. private static CsvHeader createLegacyHeader() { return new CsvHeader( new String[] { @@ -95,58 +95,6 @@ private static CsvHeader createHeaderWithTimepointColumn() { }); } - @Test - public void noTimepointColumn_noTimeProvided_shouldGenerateNotice() { - // Using createLegacyHeader() that omits the timestamp column will trigger the - // MissingTimepointColumnNotice. - // .setTimepoint(null) is used to indicate that no value is provided, although it has no effect - // in this test. - List stopTimes = new ArrayList<>(); - stopTimes.add( - new GtfsStopTime.Builder() - .setCsvRowNumber(1) - .setTripId("first trip id") - .setArrivalTime(null) - .setDepartureTime(null) - .setStopId("stop id 0") - .setStopSequence(2) - .setTimepoint((Integer) null) - .build()); - stopTimes.add( - new GtfsStopTime.Builder() - .setCsvRowNumber(4) - .setTripId("second trip id") - .setArrivalTime(null) - .setDepartureTime(null) - .setStopId("stop id 1") - .setStopSequence(2) - .setTimepoint((Integer) null) - .build()); - assertThat(generateNotices(createLegacyHeader(), stopTimes)) - .containsExactly(new MissingTimepointColumnNotice()); - } - - @Test - public void noTimepointColumn_timesProvided_shouldGenerateNotice() { - // Using createLegacyHeader() that omits the timestamp column will trigger the - // MissingTimepointColumnNotice. - // .setTimepoint(null) is used to indicate that no value is provided, although it has no effect - // in this test. - List stopTimes = new ArrayList<>(); - stopTimes.add( - new GtfsStopTime.Builder() - .setCsvRowNumber(1) - .setTripId("first trip id") - .setArrivalTime(GtfsTime.fromSecondsSinceMidnight(450)) - .setDepartureTime(GtfsTime.fromSecondsSinceMidnight(580)) - .setStopId("stop id") - .setStopSequence(2) - .setTimepoint((Integer) null) - .build()); - assertThat(generateNotices(createLegacyHeader(), stopTimes)) - .containsExactly(new MissingTimepointColumnNotice()); - } - @Test public void timepointWithNoTimeShouldGenerateNotices() { List stopTimes = new ArrayList<>(); diff --git a/model/src/main/java/org/mobilitydata/gtfsvalidator/annotation/RecommendedColumn.java b/model/src/main/java/org/mobilitydata/gtfsvalidator/annotation/RecommendedColumn.java new file mode 100644 index 0000000000..f292ebd22d --- /dev/null +++ b/model/src/main/java/org/mobilitydata/gtfsvalidator/annotation/RecommendedColumn.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.mobilitydata.gtfsvalidator.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Adds a validation that it's recommended that a column be present. A value for the field may be + * optional. + * + *

    Example. + * + *

    + *   {@literal @}GtfsTable("stop_times.txt")
    + *    public interface GtfsStopTimeSchema extends GtfsEntity {
    + *
    + *     {@literal @}DefaultValue("1")
    + *     {@literal @}RecommendedColumn
    + *      GtfsStopTimeTimepoint timepoint();
    + *   }
    + * 
    + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) +public @interface RecommendedColumn {} diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/Analyser.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/Analyser.java index f2d52b825c..0a15d5577b 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/Analyser.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/Analyser.java @@ -71,6 +71,7 @@ public GtfsFileDescriptor analyzeGtfsFileType(TypeElement type) { fieldBuilder.setRecommended(method.getAnnotation(Recommended.class) != null); fieldBuilder.setColumnRequired(method.getAnnotation(RequiredColumn.class) != null); fieldBuilder.setValueRequired(method.getAnnotation(Required.class) != null); + fieldBuilder.setColumnRecommended(method.getAnnotation(RecommendedColumn.class) != null); fieldBuilder.setMixedCase(method.getAnnotation(MixedCase.class) != null); PrimaryKey primaryKey = method.getAnnotation(PrimaryKey.class); if (primaryKey != null) { diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/GtfsFieldDescriptor.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/GtfsFieldDescriptor.java index d94b62c8ef..c5c6374fac 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/GtfsFieldDescriptor.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/GtfsFieldDescriptor.java @@ -59,6 +59,8 @@ public static GtfsFieldDescriptor.Builder builder() { public abstract boolean columnRequired(); + public abstract boolean columnRecommended(); + public boolean isHeaderRequired() { return columnRequired() || valueRequired(); } @@ -81,6 +83,8 @@ public abstract static class Builder { public abstract Builder setColumnRequired(boolean value); + public abstract Builder setColumnRecommended(boolean value); + public abstract Builder setMixedCase(boolean value); public abstract Builder setPrimaryKey(PrimaryKey annotation); diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableDescriptorGenerator.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableDescriptorGenerator.java index 825ff03e2c..304bc93c83 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableDescriptorGenerator.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableDescriptorGenerator.java @@ -186,12 +186,14 @@ private MethodSpec generateGetColumnsMethod() { "GtfsColumnDescriptor.builder()\n" + ".setColumnName($T.$L)\n" + ".setHeaderRequired($L)\n" + + ".setHeaderRecommended($L)\n" + ".setFieldLevel($T.$L)\n" + ".setIsMixedCase($L)\n" + ".setIsCached($L)\n", gtfsEntityType, fieldNameField(field.name()), field.isHeaderRequired(), + field.columnRecommended(), FieldLevelEnum.class, getFieldLevel(field), field.mixedCase(), diff --git a/processor/tests/src/main/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchema.java b/processor/tests/src/main/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchema.java new file mode 100644 index 0000000000..dff043ff42 --- /dev/null +++ b/processor/tests/src/main/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchema.java @@ -0,0 +1,11 @@ +package org.mobilitydata.gtfsvalidator.processor.tests; + +import org.mobilitydata.gtfsvalidator.annotation.GtfsTable; +import org.mobilitydata.gtfsvalidator.annotation.RecommendedColumn; + +@GtfsTable("recommended_column.txt") +public interface RecommendedColumnAnnotationSchema { + + @RecommendedColumn + String columnRecommended(); +} diff --git a/processor/tests/src/test/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchemaTest.java b/processor/tests/src/test/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchemaTest.java new file mode 100644 index 0000000000..fd600103e2 --- /dev/null +++ b/processor/tests/src/test/java/org/mobilitydata/gtfsvalidator/processor/tests/RecommendedColumnAnnotationSchemaTest.java @@ -0,0 +1,51 @@ +package org.mobilitydata.gtfsvalidator.processor.tests; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mobilitydata.gtfsvalidator.notice.MissingRequiredColumnNotice; +import org.mobilitydata.gtfsvalidator.table.RecommendedColumnAnnotationTableDescriptor; +import org.mobilitydata.gtfsvalidator.testing.LoadingHelper; +import org.mobilitydata.gtfsvalidator.validator.ValidatorLoaderException; + +@RunWith(JUnit4.class) +public class RecommendedColumnAnnotationSchemaTest { + private RecommendedColumnAnnotationTableDescriptor tableDescriptor; + private LoadingHelper helper; + + @Before + public void setup() throws ValidatorLoaderException { + tableDescriptor = new RecommendedColumnAnnotationTableDescriptor(); + helper = new LoadingHelper(); + } + + @Test + public void includingRecommendedColumnHeaderWithoutValueShouldNotGenerateNotice() + throws ValidatorLoaderException { + + helper.load(tableDescriptor, "some_column,column_recommended", "value,"); + + assertThat( + !helper + .getValidationNotices() + .contains( + new MissingRequiredColumnNotice("recommended_column.txt", "column_recommended"))); + } + + @Test + public void missingRecommendedColumnHeaderShouldGenerateNotice() throws ValidatorLoaderException { + + helper.load(tableDescriptor, "column", "value"); + // Since we use an unknown column ("column") we have to expect at least one unknown_column + // notice along with the + // missing_recommended_column notice. + assertThat( + helper + .getValidationNotices() + .contains( + new MissingRequiredColumnNotice("recommended_column.txt", "column_recommended"))); + } +} From b148d7bc744fac0c6a4f58edf724974665f7a5c4 Mon Sep 17 00:00:00 2001 From: Kevin Clough Date: Fri, 23 Jun 2023 09:08:41 -0400 Subject: [PATCH 2/4] feat: generate rules page from json file (#1508) --- web/client/.gitignore | 2 +- web/client/build.gradle | 22 +- web/client/package-lock.json | 563 +++++++++--------- web/client/package.json | 2 + web/client/src/css/components/markdown.css | 52 +- web/client/src/routes/+layout.svelte | 2 + web/client/src/routes/rules.html/+page.js | 17 +- web/client/src/routes/rules.html/+page.svelte | 244 ++++++-- .../routes/rules.html/SectionRefLink.svelte | 48 ++ 9 files changed, 620 insertions(+), 332 deletions(-) create mode 100644 web/client/src/routes/rules.html/SectionRefLink.svelte diff --git a/web/client/.gitignore b/web/client/.gitignore index 8d3365a39b..3d4439f65b 100644 --- a/web/client/.gitignore +++ b/web/client/.gitignore @@ -8,4 +8,4 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* -/static/RULES.md +/static/rules.json diff --git a/web/client/build.gradle b/web/client/build.gradle index e986d4dd20..a7bca3ce82 100644 --- a/web/client/build.gradle +++ b/web/client/build.gradle @@ -9,9 +9,29 @@ task webClientNodeModules (type: Exec) { commandLine 'npm', 'install' } +task webClientNoticeSchema (type: Exec){ + dependsOn ':cli:build' + outputs.file(file('./notice_schema.json')) + def javaCmd = System.getenv('JAVA_HOME') == null ? 'java' : "${System.getenv('JAVA_HOME')}/bin/java" + commandLine ( + javaCmd, + '-jar', + "../../cli/build/libs/gtfs-validator-${project.version}-cli.jar", + '--export_notices_schema', + '-o', + '.' + ) +} + +task webClientRulesJSON (type: Exec) { + dependsOn webClientNoticeSchema + outputs.file(file('./static/rules.json')) + commandLine 'mv', webClientNoticeSchema.outputs.files[0], outputs.files[0] +} + task webClientSetup { dependsOn webClientNodeModules - dependsOn ':copyRulesToWebClient' + dependsOn webClientRulesJSON } task webTest (type: Exec) { diff --git a/web/client/package-lock.json b/web/client/package-lock.json index 8103e03156..18a9571554 100644 --- a/web/client/package-lock.json +++ b/web/client/package-lock.json @@ -10,12 +10,14 @@ "devDependencies": { "@sveltejs/adapter-static": "^1.0.0", "@sveltejs/kit": "^1.15.1", + "@types/lodash": "^4.14.194", "@types/marked": "^4.0.8", "autoprefixer": "^10.4.13", "cypress": "^12.10.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte3": "^4.0.0", + "lodash": "^4.17.21", "marked": "^4.2.12", "postcss": "^8.4.20", "postcss-import": "^15.1.0", @@ -87,9 +89,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.10.tgz", - "integrity": "sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", "cpu": [ "arm" ], @@ -103,9 +105,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz", - "integrity": "sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", "cpu": [ "arm64" ], @@ -119,9 +121,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.10.tgz", - "integrity": "sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", "cpu": [ "x64" ], @@ -135,9 +137,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz", - "integrity": "sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", "cpu": [ "arm64" ], @@ -151,9 +153,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz", - "integrity": "sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", "cpu": [ "x64" ], @@ -167,9 +169,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz", - "integrity": "sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", "cpu": [ "arm64" ], @@ -183,9 +185,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz", - "integrity": "sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", "cpu": [ "x64" ], @@ -199,9 +201,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz", - "integrity": "sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", "cpu": [ "arm" ], @@ -215,9 +217,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz", - "integrity": "sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", "cpu": [ "arm64" ], @@ -231,9 +233,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz", - "integrity": "sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", "cpu": [ "ia32" ], @@ -247,9 +249,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz", - "integrity": "sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", "cpu": [ "loong64" ], @@ -263,9 +265,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz", - "integrity": "sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", "cpu": [ "mips64el" ], @@ -279,9 +281,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz", - "integrity": "sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", "cpu": [ "ppc64" ], @@ -295,9 +297,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz", - "integrity": "sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", "cpu": [ "riscv64" ], @@ -311,9 +313,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz", - "integrity": "sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", "cpu": [ "s390x" ], @@ -327,9 +329,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz", - "integrity": "sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", "cpu": [ "x64" ], @@ -343,9 +345,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz", - "integrity": "sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", "cpu": [ "x64" ], @@ -359,9 +361,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz", - "integrity": "sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", "cpu": [ "x64" ], @@ -375,9 +377,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz", - "integrity": "sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", "cpu": [ "x64" ], @@ -391,9 +393,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz", - "integrity": "sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", "cpu": [ "arm64" ], @@ -407,9 +409,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz", - "integrity": "sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", "cpu": [ "ia32" ], @@ -423,9 +425,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz", - "integrity": "sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", "cpu": [ "x64" ], @@ -570,13 +572,13 @@ } }, "node_modules/@sveltejs/kit": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.15.7.tgz", - "integrity": "sha512-dgdKExsMJ16X3q8tEcuDlv+QIWAlJcf7IqCU2HWV13nmtTzwSA2n4VtEx9Gy5OGhH0SUAGNIupmlf0TdFSMXbw==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.15.9.tgz", + "integrity": "sha512-Og+4WlguPVPS0PmAHefp4KxvTVZfyDN09aORVXIdKSzqzodSJiLs7Fhi/Q0z0YjmcoNLWF24tI0a6mTusL6Yfg==", "dev": true, "hasInstallScript": true, "dependencies": { - "@sveltejs/vite-plugin-svelte": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^2.1.1", "@types/cookie": "^0.5.1", "cookie": "^0.5.0", "devalue": "^4.3.0", @@ -588,7 +590,7 @@ "set-cookie-parser": "^2.5.1", "sirv": "^2.0.2", "tiny-glob": "^0.2.9", - "undici": "5.20.0" + "undici": "~5.22.0" }, "bin": { "svelte-kit": "svelte-kit.js" @@ -601,30 +603,18 @@ "vite": "^4.0.0" } }, - "node_modules/@sveltejs/kit/node_modules/magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.0.2.tgz", - "integrity": "sha512-xCEan0/NNpQuL0l5aS42FjwQ6wwskdxC3pW1OeFtEKNZwRg7Evro9lac9HesGP6TdFsTv2xMes5ASQVKbCacxg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.1.1.tgz", + "integrity": "sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==", "dev": true, "dependencies": { "debug": "^4.3.4", - "deepmerge": "^4.2.2", + "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.27.0", + "magic-string": "^0.30.0", "svelte-hmr": "^0.15.1", - "vitefu": "^0.2.3" + "vitefu": "^0.2.4" }, "engines": { "node": "^14.18.0 || >= 16" @@ -640,6 +630,12 @@ "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.194", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz", + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", + "dev": true + }, "node_modules/@types/marked": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", @@ -1537,9 +1533,9 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -1669,9 +1665,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", - "integrity": "sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", "dev": true, "hasInstallScript": true, "bin": { @@ -1681,28 +1677,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.16.10", - "@esbuild/android-arm64": "0.16.10", - "@esbuild/android-x64": "0.16.10", - "@esbuild/darwin-arm64": "0.16.10", - "@esbuild/darwin-x64": "0.16.10", - "@esbuild/freebsd-arm64": "0.16.10", - "@esbuild/freebsd-x64": "0.16.10", - "@esbuild/linux-arm": "0.16.10", - "@esbuild/linux-arm64": "0.16.10", - "@esbuild/linux-ia32": "0.16.10", - "@esbuild/linux-loong64": "0.16.10", - "@esbuild/linux-mips64el": "0.16.10", - "@esbuild/linux-ppc64": "0.16.10", - "@esbuild/linux-riscv64": "0.16.10", - "@esbuild/linux-s390x": "0.16.10", - "@esbuild/linux-x64": "0.16.10", - "@esbuild/netbsd-x64": "0.16.10", - "@esbuild/openbsd-x64": "0.16.10", - "@esbuild/sunos-x64": "0.16.10", - "@esbuild/win32-arm64": "0.16.10", - "@esbuild/win32-ia32": "0.16.10", - "@esbuild/win32-x64": "0.16.10" + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" } }, "node_modules/escalade": { @@ -2894,9 +2890,9 @@ } }, "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.13" @@ -3054,10 +3050,16 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -3302,9 +3304,9 @@ } }, "node_modules/postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "dev": true, "funding": [ { @@ -3314,10 +3316,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -3665,9 +3671,9 @@ } }, "node_modules/rollup": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", - "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", + "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -4324,15 +4330,15 @@ } }, "node_modules/undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", "dev": true, "dependencies": { "busboy": "^1.6.0" }, "engines": { - "node": ">=12.18" + "node": ">=14.0" } }, "node_modules/universalify": { @@ -4418,15 +4424,14 @@ } }, "node_modules/vite": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.2.tgz", - "integrity": "sha512-QJaY3R+tFlTagH0exVqbgkkw45B+/bXVBzF2ZD1KB5Z8RiAoiKo60vSUf6/r4c2Vh9jfGBKM4oBI9b4/1ZJYng==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "dependencies": { - "esbuild": "^0.16.3", - "postcss": "^8.4.20", - "resolve": "^1.22.1", - "rollup": "^3.7.0" + "esbuild": "^0.17.5", + "postcss": "^8.4.23", + "rollup": "^3.21.0" }, "bin": { "vite": "bin/vite.js" @@ -4630,156 +4635,156 @@ } }, "@esbuild/android-arm": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.10.tgz", - "integrity": "sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz", - "integrity": "sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.10.tgz", - "integrity": "sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz", - "integrity": "sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz", - "integrity": "sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz", - "integrity": "sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz", - "integrity": "sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz", - "integrity": "sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz", - "integrity": "sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz", - "integrity": "sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz", - "integrity": "sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz", - "integrity": "sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz", - "integrity": "sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz", - "integrity": "sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz", - "integrity": "sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz", - "integrity": "sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz", - "integrity": "sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz", - "integrity": "sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz", - "integrity": "sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz", - "integrity": "sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz", - "integrity": "sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz", - "integrity": "sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", "dev": true, "optional": true }, @@ -4885,12 +4890,12 @@ "requires": {} }, "@sveltejs/kit": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.15.7.tgz", - "integrity": "sha512-dgdKExsMJ16X3q8tEcuDlv+QIWAlJcf7IqCU2HWV13nmtTzwSA2n4VtEx9Gy5OGhH0SUAGNIupmlf0TdFSMXbw==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.15.9.tgz", + "integrity": "sha512-Og+4WlguPVPS0PmAHefp4KxvTVZfyDN09aORVXIdKSzqzodSJiLs7Fhi/Q0z0YjmcoNLWF24tI0a6mTusL6Yfg==", "dev": true, "requires": { - "@sveltejs/vite-plugin-svelte": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^2.1.1", "@types/cookie": "^0.5.1", "cookie": "^0.5.0", "devalue": "^4.3.0", @@ -4902,32 +4907,21 @@ "set-cookie-parser": "^2.5.1", "sirv": "^2.0.2", "tiny-glob": "^0.2.9", - "undici": "5.20.0" - }, - "dependencies": { - "magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" - } - } + "undici": "~5.22.0" } }, "@sveltejs/vite-plugin-svelte": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.0.2.tgz", - "integrity": "sha512-xCEan0/NNpQuL0l5aS42FjwQ6wwskdxC3pW1OeFtEKNZwRg7Evro9lac9HesGP6TdFsTv2xMes5ASQVKbCacxg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.1.1.tgz", + "integrity": "sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==", "dev": true, "requires": { "debug": "^4.3.4", - "deepmerge": "^4.2.2", + "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.27.0", + "magic-string": "^0.30.0", "svelte-hmr": "^0.15.1", - "vitefu": "^0.2.3" + "vitefu": "^0.2.4" } }, "@types/cookie": { @@ -4936,6 +4930,12 @@ "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "dev": true }, + "@types/lodash": { + "version": "4.14.194", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz", + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", + "dev": true + }, "@types/marked": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", @@ -5570,9 +5570,9 @@ "dev": true }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "defined": { @@ -5678,33 +5678,33 @@ "dev": true }, "esbuild": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", - "integrity": "sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.16.10", - "@esbuild/android-arm64": "0.16.10", - "@esbuild/android-x64": "0.16.10", - "@esbuild/darwin-arm64": "0.16.10", - "@esbuild/darwin-x64": "0.16.10", - "@esbuild/freebsd-arm64": "0.16.10", - "@esbuild/freebsd-x64": "0.16.10", - "@esbuild/linux-arm": "0.16.10", - "@esbuild/linux-arm64": "0.16.10", - "@esbuild/linux-ia32": "0.16.10", - "@esbuild/linux-loong64": "0.16.10", - "@esbuild/linux-mips64el": "0.16.10", - "@esbuild/linux-ppc64": "0.16.10", - "@esbuild/linux-riscv64": "0.16.10", - "@esbuild/linux-s390x": "0.16.10", - "@esbuild/linux-x64": "0.16.10", - "@esbuild/netbsd-x64": "0.16.10", - "@esbuild/openbsd-x64": "0.16.10", - "@esbuild/sunos-x64": "0.16.10", - "@esbuild/win32-arm64": "0.16.10", - "@esbuild/win32-ia32": "0.16.10", - "@esbuild/win32-x64": "0.16.10" + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" } }, "escalade": { @@ -6582,9 +6582,9 @@ } }, "magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", "dev": true, "requires": { "@jridgewell/sourcemap-codec": "^1.4.13" @@ -6694,9 +6694,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true }, "natural-compare": { @@ -6873,12 +6873,12 @@ "dev": true }, "postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -7094,9 +7094,9 @@ } }, "rollup": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", - "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", + "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -7539,9 +7539,9 @@ "dev": true }, "undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", "dev": true, "requires": { "busboy": "^1.6.0" @@ -7602,16 +7602,15 @@ } }, "vite": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.2.tgz", - "integrity": "sha512-QJaY3R+tFlTagH0exVqbgkkw45B+/bXVBzF2ZD1KB5Z8RiAoiKo60vSUf6/r4c2Vh9jfGBKM4oBI9b4/1ZJYng==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "requires": { - "esbuild": "^0.16.3", + "esbuild": "^0.17.5", "fsevents": "~2.3.2", - "postcss": "^8.4.20", - "resolve": "^1.22.1", - "rollup": "^3.7.0" + "postcss": "^8.4.23", + "rollup": "^3.21.0" } }, "vitefu": { diff --git a/web/client/package.json b/web/client/package.json index 9c3cf0cda9..7c084fe301 100644 --- a/web/client/package.json +++ b/web/client/package.json @@ -15,12 +15,14 @@ "devDependencies": { "@sveltejs/adapter-static": "^1.0.0", "@sveltejs/kit": "^1.15.1", + "@types/lodash": "^4.14.194", "@types/marked": "^4.0.8", "autoprefixer": "^10.4.13", "cypress": "^12.10.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte3": "^4.0.0", + "lodash": "^4.17.21", "marked": "^4.2.12", "postcss": "^8.4.20", "postcss-import": "^15.1.0", diff --git a/web/client/src/css/components/markdown.css b/web/client/src/css/components/markdown.css index 62557ae39b..a541565c37 100644 --- a/web/client/src/css/components/markdown.css +++ b/web/client/src/css/components/markdown.css @@ -36,8 +36,13 @@ @apply rounded; } + p { + max-width: 80ch; + @apply mb-4; + } + ol, ul { - @apply my-3; + @apply my-4; @apply pl-6; } @@ -49,14 +54,36 @@ @apply list-disc; } + blockquote { + @apply border-l-2; + @apply my-4; + @apply pl-4; + @apply text-mobi-dark-blue/50; + } + table { @apply my-2; } th, td { @apply align-baseline; - @apply px-3 py-2; + @apply px-4 py-3; @apply text-left; + + p, table, ol, ul { + @apply mb-4; + + &:last-child { + @apply m-0; + } + } + } + + .table-sm table, + table table { + th, td { + @apply px-3 py-2; + } } th { @@ -72,6 +99,27 @@ @apply bg-mobi-dark-blue/5; } + .table-collapse-responsive { + @media (max-width: 1023px) { + > thead, > tfoot { + display: none; + } + + > tbody { + > tr { + @apply bg-transparent; + display: block; + + > td, > th { + @apply bg-none; + @apply px-0; + display: block; + } + } + } + } + } + a[href] { @apply text-mobi-light-blue; @apply no-underline hover:underline; diff --git a/web/client/src/routes/+layout.svelte b/web/client/src/routes/+layout.svelte index b691e7785b..d958279e98 100644 --- a/web/client/src/routes/+layout.svelte +++ b/web/client/src/routes/+layout.svelte @@ -27,6 +27,8 @@ {/if} +
    +
    diff --git a/web/client/src/routes/rules.html/+page.js b/web/client/src/routes/rules.html/+page.js index 0661cabfa2..3e7be6a3b9 100644 --- a/web/client/src/routes/rules.html/+page.js +++ b/web/client/src/routes/rules.html/+page.js @@ -1,30 +1,29 @@ /** @type {import('./$types').PageLoad} */ export const load = async ({ fetch }) => { - let rulesMd = ''; + let msgHeading, msgBody, rules = null; try { - // local copy of https://raw.githubusercontent.com/MobilityData/gtfs-validator/master/RULES.md - // we could fetch it directly instead, if desired - const response = await fetch('/RULES.md'); + const response = await fetch('/rules.json'); if (response.ok) { - rulesMd = await response.text(); + rules = await response.json(); } else { throw new Error(`HTTP Error: ${response.status}`); } } catch (error) { - let msg = 'Error'; + let errorMsg = ''; if (error instanceof Error && error.message) { - msg = error.message; + errorMsg = error.message; } - rulesMd = `# ${msg}\n\nThere was a problem loading the rules file. You can try accessing it directly at https://github.com/MobilityData/gtfs-validator/blob/master/RULES.md.`; + msgHeading = errorMsg ?? 'Error'; + msgBody = 'There was a problem loading the rules file.'; } - return { rulesMd }; + return { rules, msgHeading, msgBody }; }; export const prerender = true; diff --git a/web/client/src/routes/rules.html/+page.svelte b/web/client/src/routes/rules.html/+page.svelte index 3b5e1e25b4..d0b3c1bedb 100644 --- a/web/client/src/routes/rules.html/+page.svelte +++ b/web/client/src/routes/rules.html/+page.svelte @@ -1,56 +1,226 @@
    - - {@html marked.parse(massagedMarkdown)} + {#if $page.data.msgHeading} +

    {$page.data.msgHeading}

    + {:else} +

    Validator Rules

    + {/if} + + {#if $page.data.msgBody} +

    + {$page.data.msgBody} +

    + {:else} + +
    +
    +

    Contents

    + +
    +
    + +
    +

    Introduction

    + +

    This tool is designed to assist you in testing the compliance of a dataset against the GTFS (General Transit Feed Specification) Schedule Reference and the GTFS Schedule Best Practices.

    + +

    This validator generates a list of notices, each associated with a severity level, allowing you to identify and address potential issues in your dataset. This documentation will provide a detailed overview of the rules that the validator evaluates, and ways in which the dataset can be fixed if the notice is present.

    + +

    Severities

    + +

    Each notice generated by the this validator is associated with a severity level: INFO, WARNING, or ERROR. Understanding these severities helps in assessing the impact and urgency of addressing the identified issues.

    + +

    ERROR notices correspond to GTFS Schedule Reference violations. These violations represent items explicitly required or prohibited by the GTFS Schedule Reference, denoted by the use of the terms “Required” or “must.” Errors signify critical discrepancies that must be resolved to ensure compliance with the GTFS standard.

    + +

    WARNING notices correspond to GTFS Schedule Best Practices. These recommendations are either explicitly suggested by the GTFS Schedule Reference, using the term “recommend” or “should,” or mentioned in the official GTFS Schedule Best Practices. Although not mandatory, addressing these warnings can significantly improve the quality of the data and the rider’s experience.

    + +

    INFO notices highlight items that may affect the overall quality of the feed. These notices identify unexpected findings that warrant the user’s attention.

    +
    +
    + + {#each Object.entries(categories) as [category, rules]} +
    +

    + Top + +
    + Table of {category} notices + + + +
    +

    + +
    + + + + + + + + + {#each rules as rule} + + + + + {/each} + +
    Notice codeDescription
    + + {rule.code} + + +
    {@html marked.parse(rule.shortSummary ?? '')}
    + {@html marked.parse(rule.description ?? '')} +
    +
    +
    + {/each} + +

    Notice details

    + + {#each Object.entries(rules) as [code, rule]} +
    +

    + + Table + + +
    + {code} + + + +
    +

    + +
    + {@html marked.parse(rule.shortSummary ?? '')} +
    + + {#if rule.description} +
    + {@html marked.parse(rule.description)} +
    + {/if} + + {#if rule.references} +

    References

    +
      + + {#each rule.references?.sectionReferences ?? [] as ref} +
    • + +
    • + {/each} + {#each rule.references?.fileReferences ?? [] as ref} +
    • + + {ref} + +
    • + {/each} + {#each rule.references?.bestPracticesFileReferences ?? [] as ref} +
    • + + {ref} Best Practices + +
    • + {/each} + {#each rule.references?.urlReferences ?? [] as ref} +
    • + + {ref.label} + +
    • + {/each} +
    + {/if} + + {#if rule.properties} +
    + Fields +
    + + + + + + + + + + {#each Object.entries(rule.properties) as [name, property]} + + + + + + {/each} + +
    Field nameDescriptionType
    {property.fieldName} + {@html marked.parse(property.shortSummary ?? '')} + {@html marked.parse(property.description ?? '\u2014')} + {property.type ?? '\u2014'}
    +
    +
    + {/if} +
    + {/each} + {/if}
    diff --git a/web/client/src/routes/rules.html/SectionRefLink.svelte b/web/client/src/routes/rules.html/SectionRefLink.svelte new file mode 100644 index 0000000000..2f8c4ce27e --- /dev/null +++ b/web/client/src/routes/rules.html/SectionRefLink.svelte @@ -0,0 +1,48 @@ + + + + {sectionReference.label} + From d9c1ecbcd760273b323f08c6f86a9851af098a9b Mon Sep 17 00:00:00 2001 From: cka-y <60586858+cka-y@users.noreply.github.com> Date: Mon, 26 Jun 2023 15:10:54 -0400 Subject: [PATCH 3/4] feat: Provide an explanation to users about what a GTFS Component is #1505 (#1512) * fix: display tooltip text * feat: gtfs component description --- .../report/model/NoticeView.java | 2 +- main/src/main/resources/report.html | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/NoticeView.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/NoticeView.java index 1075a64c62..2bb68c0130 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/NoticeView.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/NoticeView.java @@ -23,7 +23,7 @@ public NoticeView(ResolvedNotice notice) { this.notice = notice; this.json = notice.getContext().toJsonTree().getAsJsonObject(); this.fields = new ArrayList<>(json.keySet()); - this.comments = NoticeSchemaGenerator.loadComments(notice.getClass()); + this.comments = NoticeSchemaGenerator.loadComments(notice.getContext().getClass()); } /** diff --git a/main/src/main/resources/report.html b/main/src/main/resources/report.html index bf5637a664..b1d3d1eb40 100644 --- a/main/src/main/resources/report.html +++ b/main/src/main/resources/report.html @@ -73,6 +73,7 @@ .summary-cell { padding: 5px; box-sizing: border-box; + flex: 1; } .summary h4 { @@ -129,10 +130,19 @@ position: absolute; z-index: 1; bottom: 100%; - left: 50%; - margin-left: -60px; + transform: translateX(-50%); opacity: 0; transition: opacity 0.3s; + max-width: 400px; + min-width: 100px; + width: max-content; + white-space: normal; + } + + .tooltip { + position: relative; + display: inline-block; + cursor: help; } .tooltip:hover .tooltiptext { @@ -262,7 +272,12 @@

    Counts

    -

    GTFS Components included

    +

    + GTFS Components included + (?) + GTFS components provide a standardized vocabulary to define and describe features that are officially adopted in GTFS. + +


    From d0cfd801b603aa0afb2a254d45c31e6a8c73f9db Mon Sep 17 00:00:00 2001 From: Brian Ferris Date: Tue, 27 Jun 2023 16:32:11 -0700 Subject: [PATCH 4/4] feat: Remove unit-test that RULES.md is up-to-date with Notice classes. (#1517) --- RULES.md | 2983 +---------------- main/build.gradle | 12 - .../validator/NoticeDocumentationTest.java | 71 - 3 files changed, 1 insertion(+), 3065 deletions(-) diff --git a/RULES.md b/RULES.md index f8f1b276de..a677f63e53 100644 --- a/RULES.md +++ b/RULES.md @@ -1,2984 +1,3 @@ # Implemented notices -This document lists all the notices that are emitted by this validator.\ -For an overview what changed in each validator release, please refer to [NOTICE_MIGRATION.md](/docs/NOTICE_MIGRATION.md). - -## Definitions -### A Rule -A part of the specification that is translated into code in the validator. A Rule will describe if a set of conditions is met or not. For example: - - In the specification: in the `stops.txt` file, the field `zone_id` is required if providing fare information using `fare_rules.txt` ([source in the specification](https://gtfs.org/schedule/reference/#stopstxt)). - - In the validator: this is translated into code in the file [`StopZoneIdValidator.java`](https://github.com/MobilityData/gtfs-validator/blob/master/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopZoneIdValidator.java). - -### A Notice -The output that the user will see if the conditions aren’t met. -- For example, the output of `StopZoneIdValidator.java` is the Notice `stop_without_zone_id`. - -### The Severity of a Notice - -Each Notice is associated with a severity: `INFO`, `WARNING`, `ERROR`. - -* `ERROR` notices are for GTFS Schedule Reference violations. These are items that the [GTFS Schedule Reference](https://gtfs.org/schedule/reference/) explicitly requires or prohibits (using the language "must"). -* `WARNING` notices are for GTFS Schedule Best Practices. These are items that the [GTFS Schedule Reference](https://gtfs.org/schedule/reference/) explicitly recommends (using the language "should"), or items mentioned in the official [GTFS Schedule Best Practices](https://gtfs.org/schedule/best-practices/). -* `INFO` notices are for items that may affect the feed's quality. They are unexpected finds that should be brought to the user's attention. - -⚠️ Please note that this validator also generates `System Errors` that give information about things that may have gone wrong during the validation process such as the inability to unzip a GTFS file. These are generated in a second report `system_errors.json`. - - - -## Table of ERRORS -| Notice code | Description | -|-----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| -| [`block_trips_with_overlapping_stop_times`](#block_trips_with_overlapping_stop_times) | Block trips with overlapping stop times. | -| [`csv_parsing_failed`](#csv_parsing_failed) | Parsing of a CSV file failed. | -| [`decreasing_shape_distance`](#decreasing_shape_distance) | Decreasing `shape_dist_traveled` in `shapes.txt`. | -| [`decreasing_or_equal_stop_time_distance`](#decreasing_or_equal_stop_time_distance) | Decreasing or equal `shape_dist_traveled` in `stop_times.txt`. | -| [`duplicated_column`](#duplicated_column) | Duplicated column in CSV. | -| [`duplicate_key`](#duplicate_key) | Duplicated entity. | -| [`empty_column_name`](#empty_column_name) | A column name is empty. | -| [`empty_file`](#empty_file) | A CSV file is empty. | -| [`equal_shape_distance_diff_coordinates`](#equal_shape_distance_diff_coordinates) | Two consecutive points have equal `shape_dist_traveled` and different lat/lon coordinates in `shapes.txt`. | -| [`fare_transfer_rule_duration_limit_type_without_duration_limit`](#fare_transfer_rule_duration_limit_type_without_duration_limit) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified. | -| [`fare_transfer_rule_duration_limit_without_type`](#fare_transfer_rule_duration_limit_without_type) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified. | -| [`fare_transfer_rule_invalid_transfer_count`](#fare_transfer_rule_invalid_transfer_count) | A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value. | -| [`fare_transfer_rule_missing_transfer_count`](#fare_transfer_rule_missing_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. | -| [`fare_transfer_rule_with_forbidden_transfer_count`](#fare_transfer_rule_with_forbidden_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. | -| [`foreign_key_violation`](#foreign_key_violation) | Wrong foreign key. | -| [`inconsistent_agency_timezone`](#inconsistent_agency_timezone) | Inconsistent Timezone among agencies. | -| [`invalid_color`](#invalid_color) | A field contains an invalid color value. | -| [`invalid_currency`](#invalid_currency) | A field contains a wrong currency code. | -| [`invalid_currency_amount`](#invalid_currency_amount) | A currency amount field has a value that does not match the format of its corresponding currency code field. | -| [`invalid_date`](#invalid_date) | A field cannot be parsed as date. | -| [`invalid_email`](#invalid_email) | A field contains a malformed email address. | -| [`invalid_float`](#invalid_float) | A field cannot be parsed as a floating point number. | -| [`invalid_integer`](#invalid_integer) | A field cannot be parsed as an integer. | -| [`invalid_language_code`](#invalid_language_code) | A field contains a wrong language code. | -| [`invalid_phone_number`](#invalid_phone_number) | A field contains a malformed phone number. | -| [`invalid_row_length`](#invalid_row_length) | Invalid csv row length. | -| [`invalid_time`](#invalid_time) | A field cannot be parsed as time. | -| [`invalid_timezone`](#invalid_timezone) | A field cannot be parsed as a timezone. | -| [`invalid_url`](#invalid_url) | A field contains a malformed URL. | -| [`location_without_parent_station`](#location_without_parent_station) | A location that must have `parent_station` field does not have it. | -| [`location_with_unexpected_stop_time`](#location_with_unexpected_stop_time) | A location in `stops.txt` that is not a stop is referenced by some `stop_times.stop_id`. | -| [`missing_calendar_and_calendar_date_files`](#missing_calendar_and_calendar_date_files) | Missing GTFS files `calendar.txt` and `calendar_dates.txt`. | -| [`missing_level_id`](#missing_level_id) | `stops.level_id` is conditionally required. | -| [`missing_required_column`](#missing_required_column) | A required column is missing in the input file. | -| [`missing_required_field`](#missing_required_field) | A required field is missing. | -| [`missing_required_file`](#missing_required_file) | A required file is missing. | -| [`missing_stop_name`](#missing_stop_name) | `stops.stop_name` is required for `location_type` equal to `0`, `1`, or `2`. | -| [`missing_trip_edge`](#missing_trip_edge) | Missing trip edge `arrival_time` or `departure_time`. | -| [`new_line_in_value`](#new_line_in_value) | New line or carriage return in a value in CSV file. | -| [`number_out_of_range`](#number_out_of_range) | Out of range value. | -| [`overlapping_frequency`](#overlapping_frequency) | Trip frequencies overlap. | -| [`pathway_to_platform_with_boarding_areas`](#pathway_to_platform_with_boarding_areas) | A pathway has an endpoint that is a platform which has boarding areas. | -| [`pathway_to_wrong_location_type`](#pathway_to_wrong_location_type) | A pathway has an endpoint that is a station. | -| [`pathway_unreachable_location`](#pathway_unreachable_location) | A location is not reachable at least in one direction: from the entrances or to the exits. | -| [`point_near_origin`](#point_near_origin) | A point is too close to origin `(0, 0)`. | -| [`point_near_pole`](#point_near_pole) | A point is too close to the North or South Pole. | -| [`route_both_short_and_long_name_missing`](#route_both_short_and_long_name_missing) | Missing route short name and long name. | -| [`start_and_end_range_equal`](#start_and_end_range_equal) | Two date or time fields are equal. | -| [`start_and_end_range_out_of_order`](#start_and_end_range_out_of_order) | Two date or time fields are out of order. | -| [`station_with_parent_station`](#station_with_parent_station) | A station has `parent_station` field set. | -| [`stop_time_timepoint_without_times`](#stop_time_timepoint_without_times) | `arrival_time` or `departure_time` not specified for timepoint. | -| [`stop_time_with_arrival_before_previous_departure_time`](#stop_time_with_arrival_before_previous_departure_time) | Backwards time travel between stops in `stop_times.txt` | -| [`stop_time_with_only_arrival_or_departure_time`](#stop_time_with_only_arrival_or_departure_time) | Missing `stop_times.arrival_time` or `stop_times.departure_time`. | -| [`stop_without_location`](#stop_without_location) | `stop_lat` and/or `stop_lon` is missing for stop with `location_type` equal to`0`, `1`, or `2` | -| [`stop_without_zone_id`](#stop_without_zone_id) | Stop without value for `stops.zone_id`. | -| [`too_many_rows`](#too_many_rows) | A CSV file has too many rows. | -| [`transfer_with_invalid_stop_location_type`](#transfer_with_invalid_stop_location_type) | A stop id field from GTFS file `transfers.txt` references a stop that has a `location_type` other than 0 or 1 (aka Stop/Platform or Station). | -| [`transfer_with_invalid_trip_and_route`](#transfer_with_invalid_trip_and_route) | A trip id field from GTFS file `transfers.txt` references a route that does not match its `trips.txt` `route_id`. | -| [`transfer_with_invalid_trip_and_stop`](#transfer_with_invalid_trip_and_stop) | A trip id field from GTFS file `transfers.txt` references a stop that is not included in the referenced trip's stop-times. | -| [`translation_foreign_key_violation`](#translation_foreign_key_violation) | An entity with the given `record_id` and `record_sub_id` cannot be found in the referenced table. | -| [`translation_unexpected_value`](#translation_unexpected_value) | A field in a translations row has value but must be empty. | -| [`wrong_parent_location_type`](#wrong_parent_location_type) | Incorrect type of the parent location. | - - - -## Table of WARNINGS -| Notice code | Description | -|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [`attribution_without_role`](#attribution_without_role) | Attribution with no role. | -| [`duplicate_fare_media`](#duplicate_fare_media) | Two distinct fare media have the same fare media name and type. | -| [`duplicate_route_name`](#duplicate_route_name) | Two distinct routes have either the same `route_short_name`, the same `route_long_name`, or the same combination of `route_short_name` and `route_long_name`. | -| [`empty_row`](#empty_row) | A row in the input file has only spaces. | -| [`equal_shape_distance_same_coordinates`](#equal_shape_distance_same_coordinates) | Two consecutive points have equal `shape_dist_traveled` and the same lat/lon coordinates in `shapes.txt`. | -| [`expired_calendar`](#expired_calendar) | Dataset should not contain date ranges for services that have already expired. | -| [`fast_travel_between_consecutive_stops`](#fast_travel_between_consecutive_stops) | A transit vehicle moves too fast between two consecutive stops. | -| [`fast_travel_between_far_stops`](#fast_travel_between_far_stops) | A transit vehicle moves too fast between two far stops. | -| [`feed_expiration_date7_days`](#feed_expiration_date7_days) | Dataset should be valid for at least the next 7 days. | -| [`feed_expiration_date30_days`](#feed_expiration_date30_days) | Dataset should cover at least the next 30 days of service. | -| [`feed_info_lang_and_agency_lang_mismatch`](#feed_info_lang_and_agency_lang_mismatch) | Mismatching feed and agency language fields. | -| [`inconsistent_agency_lang`](#inconsistent_agency_lang) | Inconsistent language among agencies. | -| [`leading_or_trailing_whitespaces`](#leading_or_trailing_whitespaces) | The value in CSV file has leading or trailing whitespaces. | -| [`missing_feed_info_date`](#missing_feed_info_date) | `feed_end_date` should be provided if `feed_start_date` is provided. `feed_start_date` should be provided if `feed_end_date` is provided. | -| [`missing_recommended_column`](#missing_recommended_column) | A recommended column is missing in the input file. | -| [`missing_recommended_file`](#missing_recommended_file) | A recommended file is missing. | -| [`missing_recommended_field`](#missing_recommended_field) | A recommended field is missing. | -| [`missing_timepoint_value`](#missing_timepoint_value) | `stop_times.timepoint` value is missing for a record. | -| [`mixed_case_recommended_field`](#mixed_case_recommended_field) | This field has customer-facing text and should use Mixed Case (should contain upper and lower case letters). | -| [`more_than_one_entity`](#more_than_one_entity) | More than one row in CSV. | -| [`non_ascii_or_non_printable_char`](#non_ascii_or_non_printable_char) | Non ascii or non printable char in `id`. | -| [`pathway_dangling_generic_node`](#pathway_dangling_generic_node) | A generic node has only one incident location in a pathway graph. | -| [`pathway_loop`](#pathway_loop) | A pathway starts and ends at the same location. | -| [`route_color_contrast`](#route_color_contrast) | Insufficient route color contrast. | -| [`route_long_name_contains_short_name`](#route_long_name_contains_short_name) | Long name should not contain short name for a single route. | -| [`route_short_name_too_long`](#route_short_name_too_long) | Short name of a route is too long (more than 12 characters). | -| [`same_name_and_description_for_route`](#same_name_and_description_for_route) | Same name and description for route. | -| [`same_name_and_description_for_stop`](#same_name_and_description_for_stop) | Same name and description for stop. | -| [`same_route_and_agency_url`](#same_route_and_agency_url) | Same `routes.route_url` and `agency.agency_url`. | -| [`same_stop_and_agency_url`](#same_stop_and_agency_url) | Same `stops.stop_url` and `agency.agency_url`. | -| [`same_stop_and_route_url`](#same_stop_and_route_url) | Same `stops.stop_url` and `routes.route_url`. | -| [`stop_has_too_many_matches_for_shape`](#stop_has_too_many_matches_for_shape) | Stop entry that has many potential matches to the trip's path of travel. | -| [`stops_match_shape_out_of_order`](#stops_match_shape_out_of_order) | Two stop entries are different than their arrival-departure order defined by the shapes.txt | -| [`stop_too_far_from_shape`](#stop_too_far_from_shape) | Stop too far from trip shape. | -| [`stop_too_far_from_shape_using_user_distance`](#stop_too_far_from_shape_using_user_distance) | Stop time too far from shape. | -| [`stop_without_stop_time`](#stop_without_stop_time) | A stop in `stops.txt` is not referenced by any `stop_times.stop_id`. | -| [`transfer_with_suspicious_mid_trip_in_seat`](#transfer_with_suspicious_mid_trip_in_seat) | A trip id field from GTFS file `transfers.txt` with an in-seat transfer type references a stop that is not in the expected position in the trip's stop-times. | -| [`translation_unknown_table_name`](#translation_unknown_table_name) | A translation references an unknown or missing GTFS table. | -| [`trip_coverage_not_active_for_next7_days`](#trip_coverage_not_active_for_next7_days) | Trips data should be valid for at least the next seven days. | -| [`unexpected_enum_value`](#unexpected_enum_value) | An enum has an unexpected value. | -| [`unusable_trip`](#unusable_trip) | Trips must have more than one stop to be usable. | -| [`unused_shape`](#unused_shape) | Shape is not used in GTFS file `trips.txt`. | -| [`unused_trip`](#unused_trip) | Trip is not be used in `stop_times.txt` | - - - -## Table of INFOS - -| Notice code | Description | -|-----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| -| [`platform_without_parent_station`](#platform_without_parent_station) | A platform has no `parent_station` field set. | -| [`unknown_column`](#unknown_column) | A column name is unknown. | -| [`unknown_file`](#unknown_file) | A file is unknown. | -| [`unused_parent_station`](#unused_parent_station) | A stop has `location_type` STATION (1) but does not appear in any stop's `parent_station` field. | - - - -## Table of SYSTEM ERRORS - -| System error code | Description | -|---------------------------------------------------------------------------------|--------------------------------------------------------| -| [`i_o_error`](#i_o_error) | Error in IO operation. | -| [`runtime_exception_in_loader_error`](#runtime_exception_in_loader_error) | RuntimeException while loading GTFS dataset in memory. | -| [`runtime_exception_in_validator_error`](#runtime_exception_in_validator_error) | RuntimeException while validating GTFS archive. | -| [`thread_execution_error`](#thread_execution_error) | ExecutionException during multithreaded validation | -| [`u_r_i_syntax_error`](#u_r_i_syntax_error) | A string could not be parsed as a URI reference. | - -# More details - ERRORS - - - -### block_trips_with_overlapping_stop_times - -Trips with the same block id have overlapping stop times. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [stops.txt specification](http://gtfs.org/reference/static#stopstxt) -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |--------------------------------------------------------- |-------- | -| `csvRowNumberA` | The row number from `trips.txt` of the first faulty trip. | Long | -| `tripIdA` | The id of first faulty trip. | String | -| `serviceIdA` | The service id of the first faulty trip. | String | -| `csvRowNumberB` | The row number from `trips.txt` of the second faulty trip.| Long | -| `tripIdB` | The id of the other faulty trip. | String | -| `serviceIdB` | The service id of the other faulty trip. | String | -| `blockId` | The `trips.block_id` of the overlapping trip. | String | -| `intersection` | The overlapping period. | Date | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### csv_parsing_failed - -Parsing of a CSV file failed. One common case of the problem is when a cell value contains more than 4096 characters. - -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------- |----------------------------------------------------------------------------------------- |--------- | -| `filename` | The name of the faulty file. | Long | -| `charIndex` | The location of the last character read from before the error occurred. | Long | -| `columnIndex` | The column index where the exception occurred. | Integer | -| `lineIndex` | The line number where the exception occurred. | Long | -| `message` | The detailed message describing the error, and the internal state of the parser/writer. | String | -| `parsedContent` | The record number when the exception occurred. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) -
    - -
    - -### decreasing_shape_distance - -When sorted by `shape.shape_pt_sequence`, two consecutive shape points must not have decreasing values for `shape_dist_traveled`. - -#### References -* [shapes.txt specification](https://gtfs.org/reference/static#shapestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------------- |-------------------------------------------------------------------------------------------------|--------- | -| `shapeId` | The id of the faulty shape. | String | -| `csvRowNumber` | The row number from `shapes.txt`. | Long | -| `shapeDistTraveled` | Actual distance traveled along the shape from the first shape point to the faulty record. | Double | -| `shapePtSequence` | The faulty record's `shapes.shape_pt_sequence`. | Integer | -| `prevCsvRowNumber` | The row number from `shapes.txt` of the previous shape point. | Long | -| `prevShapeDistTraveled` | Actual distance traveled along the shape from the first shape point to the previous shape point. | Double | -| `prevShapePtSequence` | The previous record's `shapes.shape_pt_sequence`. | Integer | - -#### Affected files -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) - -
    - -
    - -### decreasing_or_equal_stop_time_distance - -When sorted by `stop_times.stop_sequence`, two consecutive entries in `stop_times.txt` should have increasing distance, based on the field `shape_dist_traveled`. If the values are equal, this is considered as an error. - -#### References -* [stops_times.txt specification](https://gtfs.org/reference/static#stop_timestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------------- |------------------------------------------------------------------------------------------------ |--------- | -| `tripId` | The id of the faulty trip. | String | -| `csvRowNumber` | The row number from `stop_times.txt`. | Long | -| `shapeDistTraveled` | Actual distance traveled along the shape from the first shape point to the faulty record. | Double | -| `stopSequence` | The faulty record's `stop_times.stop_sequence`. | Integer | -| `prevCsvRowNumber` | The row number from `stop_times.txt` of the previous stop time. | Long | -| `prevStopTimeDistTraveled`| Actual distance traveled along the shape from the first shape point to the previous stop time. | Double | -| `prevStopSequence` | The previous record's `stop_times.stop_sequence`. | Integer | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### duplicated_column - -The input file CSV header has the same column name repeated. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [Dataset files requirements](http://gtfs.org/reference/static#file-requirements) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `fieldName` | The name of the faulty field. | String | -| `firstIndex` | Index of the first occurrence. | Integer | -| `secondIndex` | Index of the other occurrence. | Integer | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### duplicate_key - -The values of the given key and rows are duplicates. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [Dataset files requirements](http://gtfs.org/reference/static#file-requirements) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |------------------------------------ |-------- | -| `filename` | The name of the faulty file | String | -| `oldCsvRowNumber` | The row of the first occurrence. | Long | -| `newCsvRowNumber` | The row of the other occurrence. | Long | -| `fieldName1` | Composite key's first field name. | String | -| `fieldValue1` | Composite key's first value. | Object | -| `fieldName2` | Composite key's second field name. | String | -| `fieldValue2` | Composite key's second value. | Object | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### empty_column_name - -A column name has not been provided. Such columns are skipped by the validator. - -#### References -* [GTFS file requirements](http://gtfs.org/reference/static/#file-requirements) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------ |--------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `index` | The index of the empty column. | Integer | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### empty_file - -Empty csv file found in the archive: file does not have any headers, or is a required file and does not have any data. The GTFS specification requires the first line of each file to contain field names and required files must have data. -#### References -* [GTFS files requirements](https://gtfs.org/reference/static#file-requirements) - -
    - -#### Notice fields description -| Field name | Description | Type | -|------------ |----------------------------- |-------- | -| `filename` | The name of the faulty file | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -### equal_shape_distance_diff_coordinates - -
    - -When sorted by `shape.shape_pt_sequence`, the values for `shape_dist_traveled` must increase along a shape. Two consecutive points with equal values for `shape_dist_traveled` and different coordinates indicate an error. - -#### References -* [shapes.txt specification](https://gtfs.org/reference/static#shapestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------------- |------------------------------------------------------------------------------------------------- |--------- | -| `shapeId` | The id of the faulty shape. | String | -| `csvRowNumber` | The row number from `shapes.txt`. | Long | -| `shapeDistTraveled` | The faulty record's `shape_dist_traveled` value. | Double | -| `shapePtSequence` | The faulty record's `shapes.shape_pt_sequence`. | Integer | -| `prevCsvRowNumber` | The row number from `shapes.txt` of the previous shape point. | Long | -| `prevShapeDistTraveled` | The previous shape point's `shape_dist_traveled` value. | Double | -| `prevShapePtSequence` | The previous record's `shapes.shape_pt_sequence`. | Integer | -| `actualDistanceBetweenShapePoints` | Actual distance traveled along the shape from the first shape point to the previous shape point. | Double | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) - -
    - -
    - -### fare_transfer_rule_duration_limit_type_without_duration_limit - -A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified. - -#### References -* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | - -#### Affected files -* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -
    - -### fare_transfer_rule_duration_limit_without_type - -A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified. - -#### References -* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | - -#### Affected files -* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -
    - -### fare_transfer_rule_invalid_transfer_count - -A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value. - -#### References -* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | -| `transferCount` | The transfer count value of the faulty record. | Integer | - -#### Affected files -* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -
    - -### fare_transfer_rule_missing_transfer_count - -A row from GTFS file `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. Per the spec, `transfer_count` is required if the two leg group ids are equal. - -#### References -* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | - -#### Affected files -* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -
    - -### fare_transfer_rule_with_forbidden_transfer_count - -A row from GTFS file `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. Per the spec, `transfer_count` is forbidden if the two leg group ids are not equal. - -#### References -* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | - -#### Affected files -* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt) - -
    - -
    - -### foreign_key_violation - -A foreign key references the primary key of another file. A foreign key violation means that the foreign key referenced from a given row (the child file) cannot be found in the corresponding file (the parent file). The Foreign keys are defined in the specification under "Type" for each file. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [GTFS files requirements](https://gtfs.org/reference/static#file-requirements) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |---------------------------------------------------- |-------- | -| `childFilename` | The name of the file from which reference is made. | String | -| `childFieldName` | The name of the field that makes reference. | String | -| `parentFilename` | The name of the file that is referred to. | String | -| `parentFieldName` | The name of the field that is referred to. | String | -| `fieldValue` | The faulty record's value. | String | -| `csvRowNumber` | The row of the faulty record. | Long | - -#### Affected files -* [`attributions.txt`](http://gtfs.org/reference/static#attributionstxt) -* [`fare_attributes.txt`](http://gtfs.org/reference/static#fare_attributestxt) -* [`fare_rules.txt`](http://gtfs.org/reference/static#fare_rulestxt) -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`tranfers.txt`](http://gtfs.org/reference/static#tranferstxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### inconsistent_agency_timezone - -Agencies from GTFS `agency.txt` have been found to have different timezones. - -#### References -* [GTFS agency.txt specification](https://gtfs.org/reference/static/#agencytxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `csvRowNumber`| The row of the faulty record. | Long | -| `expected` | Expected timezone. | String | -| `actual` | Faulty record's timezone. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) - -
    - -
    - -### invalid_color - -Value of field with type `color` is not valid. A color must be encoded as a six-digit hexadecimal number. The leading "#" is not included. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### invalid_currency - -Value of field with type `currency` is not valid. Currency code must follow ISO 4217 - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`fare_attributes.txt`](http://gtfs.org/reference/static#fare_attributestxt) - -
    - - - -### invalid_currency_amount - -A currency amount field has a value that does not match the format (e.g. expected number of decimal places) of its corresponding currency code field. The number of decimal places is specified by ISO 4217. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `amount` | Faulty currency amount value. | String | - -#### Affected files -* [`fare_products.txt`](http://gtfs.org/reference/static#fare_productstxt) - -
    - - - -### invalid_date - -Value of field with type `date` is not valid. Dates must have the YYYYMMDD format. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`calendar.txt`](http://gtfs.org/reference/static#calendartxt) -* [`calendar_dates.txt`](http://gtfs.org/reference/static#calendar_datestxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) - -
    - -
    - -### invalid_email - -Value of field with type `email` is not valid. Definitions for valid emails are quite vague. We perform strict validation using the Apache Commons EmailValidator. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -* [Apache Commons EmailValidator](https://commons.apache.org/proper/commons-validator/apidocs/org/apache/commons/validator/routines/EmailValidator.html) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`attributions.txt`](http://gtfs.org/reference/static#attributionstxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### invalid_float - -Value of field with type `float` is not valid. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`fare_attributes.txt`](http://gtfs.org/reference/static#fare_attributestxt) -* [`levels.txt`](http://gtfs.org/reference/static#levelstxt) -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### invalid_integer - -Value of field with type `integer` is not valid. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`fare_attributes.txt`](http://gtfs.org/reference/static#fare_attributestxt) -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`transfers.txt`](http://gtfs.org/reference/static#transferstxt) - -
    - -
    - -### invalid_language_code - -Value of field with type `language` is not valid. Language codes must follow IETF BCP 47. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - - - -### invalid_phone_number - -Value of field with type `phone number` is not valid. This rule uses the [PhoneNumberUtil](https://www.javadoc.io/doc/com.googlecode.libphonenumber/libphonenumber/8.4.1/com/google/i18n/phonenumbers/PhoneNumberUtil.html) class to validate a phone number based on a country code. If no country code is provided in the parameters used to run the validator, this notice won't be emitted. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### invalid_row_length - -A row in the input file has a different number of values than specified by the CSV header. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [GTFS files requirements](https://gtfs.org/reference/static#file-requirements) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------------------ |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `rowLength` | The length of the faulty record. | Integer | -| `headerCount` | The number of column in the faulty file. | Intege | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### invalid_time - -Value of field with type `time` is not valid. Time must be in the `H:MM:SS`, `HH:MM:SS` or `HHH:MM:SS` format. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### invalid_timezone - -Value of field with type `timezone` is not valid.Timezones are defined at www.iana.org. Timezone names never contain the space character but may contain an underscore. Refer to Wikipedia for a list of valid values. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#frequenciestxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - - - -### invalid_url - -Value of field with type `url` is not valid. Definitions for valid URLs are quite vague. We perform strict validation using the Apache Commons UrlValidator. - -#### References -* [Field Types Description](http://gtfs.org/reference/static/#field-types) -* [Apache Commons UrlValidator](https://commons.apache.org/proper/commons-validator/apidocs/org/apache/commons/validator/routines/UrlValidator.html) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### location_without_parent_station - -A location that must have `parent_station` field does not have it. The following location types must have `parent_station`: entrance, generic node, boarding_area. - -#### References -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------------------------- |--------- | -| `csvRowNumber`| The row of the faulty record. | Long | -| `stopId` | The id of the faulty record. | String | -| `stopName` | The `stops.stop_name` of the faulty record. | String | -| `locationType`| The `stops.location_type` of the faulty record. | Integer | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### location_with_unexpected_stop_time - -Referenced locations (using `stop_times.stop_id`) must be stops/platforms, i.e. their `stops.location_type` value must be 0 or empty. - -#### References -* [stop_times.txt GTFS specification](http://gtfs.org/reference/static#stop_timestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------ |------------------------------------------------------------ |-------- | -| `csvRowNumber` | The row number of the faulty record from `stops.txt`. | Long | -| `stopId` | The id of the faulty record from `stops.txt`. | String | -| `stopName` | The `stops.stop_name` of the faulty record. | String | -| `stopTimeCsvRowNumber` | The row number of the faulty record from `stop_times.txt`. | Long | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### missing_calendar_and_calendar_date_files - -Both files calendar_dates.txt and calendar.txt are missing from the GTFS archive. At least one of the files must be provided. - -#### References -* [calendar.txt specification](http://gtfs.org/reference/static/#calendartxt) -* [calendar_dates.txt specification](http://gtfs.org/reference/static/#calendar_datestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------ |------------- |------ | -| N/A | N/A | N/A | - -#### Affected files -* [`calendar.txt`](http://gtfs.org/reference/static#calendartxt) -* [`calendar_dates.txt`](http://gtfs.org/reference/static#calendar_datestxt) - -
    - -
    - -### missing_level_id - -GTFS file `levels.txt` is required for elevator (`pathway_mode=5`). A row from `stops.txt` linked to an elevator pathway has no value for `stops.level_id`. - -#### References -* [levels.txt specification](http://gtfs.org/reference/static/#levelstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------- |------------------------------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `stopId` | The id of the faulty stop from `stops.txt`. | String | -| `stopName` | The name of the faulty stop from `stops.txt`. | String | - -#### Affected files -* [`levels.txt`](http://gtfs.org/reference/static#levelstxt) - -
    - -
    - -### missing_required_column - -A required column is missing in the input file. - -#### References -* [GTFS terms definition](https://gtfs.org/reference/static/#term-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `fieldName` | The name of the missing column. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### missing_required_field - -The given field has no value in some input row, even though values are required. - -#### References -* [GTFS terms definition](https://gtfs.org/reference/static/#term-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | The name of the missing field. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### missing_required_file - -A required file is missing. If this notice is triggered for every core file, it might be a problem with the input. To create a zip file from the GTFS `.txt` files: select all the `.txt` files, right-click, and compress. Do not compress the folder containing the files. - -#### References -* [GTFS terms definition](https://gtfs.org/reference/static/#term-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### missing_stop_name - -`stops.stop_name` is required for locations that are stops (`location_type=0`), stations (`location_type=1`) or entrances/exits (`location_type=2`). - -#### References -* [stops.txt specification](https://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------- |--------- | -| `csvRowNumber` | The row of the faulty record. | Long | -| `locationType` | `stops.location_type` of the faulty record. | Integer | -| `stopId` | The `stops.stop_id` of the faulty record. | String | - -#### Affected files -* [stops.txt](https://gtfs.org/reference/static/#stopstxt) - -
    - -
    - -### missing_trip_edge - -First and last stop of a trip must define both `arrival_time` and `departure_time` fields. - -#### References -* [stop_times.txt specification](https://gtfs.org/reference/static/#stop_timestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------- |--------- | -| `csvRowNumber` | The row of the faulty record. | Long | -| `stopSequence` | `stops.stop_sequence` of the faulty record. | Integer | -| `tripId` | The `trips.trip_id` of the faulty record. | String | -| `specifiedField` | Name of the missing field. | String | - -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### new_line_in_value - -A value in CSV file has a new line or carriage return. - -#### References -* [GTFS file requirements](https://gtfs.org/reference/static/#file-requirements) -
    - - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Integer | -| `fieldName` | The name of the faulty field. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### number_out_of_range - -The values in the given column of the input rows are out of range. - -#### References -* [GTFS file requirements](https://gtfs.org/reference/static/#file-requirements) -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [GTFS field types](http://gtfs.org/reference/static/#field-types) -
    - - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Integer | -| `fieldName` | The name of the faulty field. | String | -| `fieldType` | The type of the faulty field. | String | -| `fieldValue` | Faulty value. | Object | - -#### Affected files -* [All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### overlapping_frequency - -Trip frequencies must not overlap in time - -#### References -* [frequencies.txt specification](http://gtfs.org/reference/static/#frequenciestxt) -
    - - -#### Notice fields description -| Field name | Description | Type | -|------------------ |------------------------------------------------ |-------- | -| `prevCsvRowNumber`| The row number of the first frequency. | Long | -| `prevEndTime` | The first frequency end time. | String | -| `currCsvRowNumber`| The overlapping frequency's row number. | Long | -| `currStartTime` | The overlapping frequency's start time. | String | -| `tripId` | The trip id associated to the first frequency. | String | - -#### Affected files -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) - -
    - -
    - -### pathway_to_platform_with_boarding_areas - -A pathway has an endpoint that is a platform which has boarding areas. A platform that has boarding -areas is treated as a parent object, not a point. In such cases, the platform must not have pathways -assigned - instead, pathways must be assigned to its boarding areas. - -#### References -* [pathways.txt specification](http://gtfs.org/reference/static/#pathwaystxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------------- |--------- | -| `csvRowNumber` | The row of the faulty row. | Integer | -| `pathwayId` | The id of the faulty pathway. | String | -| `fieldName` | The platform id field name. | String | -| `stopId` | The id of the endpoint platform. | String | - -
    - -
    - -### pathway_to_wrong_location_type - -A pathway has an endpoint that is a station. Pathways endpoints must be platforms (stops), -entrances/exits, generic nodes or boarding areas. - -#### References -* [pathways.txt specification](http://gtfs.org/reference/static/#pathwaystxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------------- |--------- | -| `csvRowNumber` | The row of the faulty row. | Integer | -| `pathwayId` | The id of the faulty pathway. | String | -| `fieldName` | The station id field name. | String | -| `stopId` | The id of the endpoint station. | String | - -
    - -
    - -### pathway_unreachable_location - -A location belongs to a station that has pathways and is not reachable at least in one direction: -from the entrances or to the exits. - -Notices are reported for platforms, boarding areas and generic nodes but not for entrances or -stations. - -Notices are not reported for platforms that have boarding areas since such platforms may not -have incident pathways. Instead, notices are reported for the boarding areas. - -#### References -* [pathways.txt specification](http://gtfs.org/reference/static/#pathwaystxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------|--------------------------------------------------|--------- | -| `csvRowNumber` | Row number of the unreachable location. | Long | -| `stopId` | The id of the unreachable location. | String | -| `stopName` | The stop name of the unreachable location. | String | -| `locationType` | The type of the unreachable location. | Integer | -| `parentStation`| The parent of the unreachable location. | String | -| `hasEntrance` | Whether the location is reachable from entrances. | String | -| `hasExit` | Whether some exit can be reached from the location. | String | - -#### Affected files -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### point_near_origin - -A point is too close to origin `(0, 0)`. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------------- |--------- | -| `filename` | The name of the affected GTFS file. | String | -| `csvRowNumber` | The row of the faulty row. | Integer | -| `entityId` | The id of the faulty entity. | String | -| `latFieldName` | The name of the field that uses latitude value. | String | -| `latFieldValue` | The latitude of the faulty row. | Double | -| `lonFieldName` | The name of the field that uses longitude value. | String | -| `lonFieldValue` | The longitude of the faulty row | Double | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) - -
    - -
    - -### point_near_pole - -A point is too close to the North or South Pole. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------------- |--------- | -| `filename` | The name of the affected GTFS file. | String | -| `csvRowNumber` | The row of the faulty row. | Integer | -| `entityId` | The id of the faulty entity. | String | -| `latFieldName` | The name of the field that uses latitude value. | String | -| `latFieldValue` | The latitude of the faulty row. | Double | -| `lonFieldName` | The name of the field that uses longitude value. | String | -| `lonFieldValue` | The longitude of the faulty row | Double | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) - -
    - -
    - -### route_both_short_and_long_name_missing - -Both `route_short_name` and `route_long_name` are missing for a route. - -#### References -* [routes.txt specification](http://gtfs.org/reference/static/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |-------------------------------------- |-------- | -| `routeId` | The id of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### start_and_end_range_equal - -The fields `frequencies.start_date` and `frequencies.end_date` have been found equal in `frequencies.txt`. The GTFS spec is currently unclear how this case should be handled (e.g., is it a trip that circulates once?). It is recommended to use a trip not defined via frequencies.txt for this case. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -[frequencies.txt specification](http://gtfs.org/reference/static#frequenciestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `entityId` | The id of the faulty entity. | String | -| `startFieldName` | The start value's field name. | String | -| `endFieldName` | The end value's field name. | String | -| `value` | The faulty value. | String | - -#### Affected files -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) - -
    - -
    - -### start_and_end_range_out_of_order - -Date or time fields have been found out of order in `calendar.txt`, `feed_info.txt` and `stop_times.txt`. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [calendar.txt specification](http://gtfs.org/reference/static#calendartxt) -* [calendar_dates.txt specification](http://gtfs.org/reference/static#calendar_datestxt) -* [feed_info.txt specification](http://gtfs.org/reference/static#feed_infotxt) -* [stop_times.txt specification](http://gtfs.org/reference/static#stop_timestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |------------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `entityId` | The faulty service id. | String | -| `startFieldName` | The start value's field name. | String | -| `startValue` | The start value. | String | -| `endFieldName` | The end value's field name. | String | -| `endValue` | The end value. | String | - -#### Affected files -* [`calendar.txt`](http://gtfs.org/reference/static#calendartxt) -* [`calendar_dates.txt`](http://gtfs.org/reference/static#calendar_datestxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### station_with_parent_station - -Field `parent_station` must be empty when `location_type` is 1. - -#### References -[stop.txt](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------- |--------------------------------------------- |-------- | -| `stopId` | The id of the faulty record. | String | -| `stopName` | The stops.stop_name of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `parentStation` | Parent station's id. | String | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### stop_time_timepoint_without_times - -Any records with `stop_times.timepoint` set to 1 must define a value for `stop_times.arrival_time` and `stop_times.departure_time` fields. - -#### References -* [GTFS stop_times.txt specification](https://gtfs.org/reference/static#stoptimestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `tripId` | The faulty record's id. | String | -| `stopSequence` | The faulty record's `stops.stop_sequence`. | String | -| `specifiedField` | Either `departure_time` or `arrival_time`. | String | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### stop_time_with_arrival_before_previous_departure_time - -For a given `trip_id`, the `arrival_time` of (n+1)-th stoptime in sequence must not precede the `departure_time` of n-th stoptime in sequence in `stop_times.txt`. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [stop_times.txt specification](http://gtfs.org/reference/static#stop_timestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------ |---------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `prevCsvRowNumber`| The row of the previous stop time. | Long | -| `tripId` | The trip_id associated to the faulty record. | String | -| `departureTime` | Departure time at the previous stop time. | String | -| `arrivalTime` | Arrival time at the faulty record. | String | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### stop_time_with_only_arrival_or_departure_time - -Missing `stop_time.arrival_time` or `stop_time.departure_time` - -#### References -* [stop_times.txt specification](http://gtfs.org/reference/static/#stop_timestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------- |-----------------------------------------------|--------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `tripId` | The trip_id associated to the faulty record. | String | -| `stopSequence` | The sequence of the faulty stop. | Integer | -| `specifiedField` | Either `arrival_time` or `departure_time` | String | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -
    - -### stop_without_location - -`stop_lat` and/or `stop_lon` are required for locations that are stops (`location_type=0`), stations (`location_type=1`) or entrances/exits (`location_type=2`). - -#### References -* [GTFS stops.txt specification](https://gtfs.org/reference/static#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------------- |-------------------------------------------- |-------- | -| `stopId` | The faulty record's id. | String | -| `locationType` | The faulty record's `stops.location_type`. | Integer | -| `csvRowNumber` | The row number of the faulty record. | Long | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### stop_without_zone_id - -If `fare_rules.txt` is provided, and `fare_rules.txt` uses at least one column among `origin_id`, `destination_id`, and `contains_id`, then all stops and platforms (location_type = 0) must have `stops.zone_id` assigned. - -#### References -* [GTFS stops.txt specification](https://gtfs.org/reference/static#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------------- |-------------------------------------------- |-------- | -| `stopId` | The faulty record's id. | String | -| `stopName` | The faulty record's `stops.stop_name`. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`fare_rules.txt`](http://gtfs.org/reference/static#farerulestxt) - -
    - -
    - -### too_many_rows - -A CSV file has too many rows. Feeds with too large files cannot be processed in a reasonable time by GTFS consumers. - -#### References -None. - -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------------|-----------------------------------------------|--------| -| `filename` | Name of the CSV file that has too many rows. | String | -| `rowNumber` | Number of the row when reading was stopped. | long | - -
    - -
    - -### transfer_with_invalid_stop_location_type - -A `from_stop_id` or `to_stop_id` field from GTFS file `transfers.txt` references a stop that has a `location_type` other than 0 or 1 (aka Stop/Platform or Station). - -#### References -* [transfers.txt specification](http://gtfs.org/reference/static/#transferstxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------------|---------------------------------------------------------------------------|--------| -| `csvRowNumber` | The row number from `transfers.txt` for the faulty entry. | long | -| `stopIdFieldName` | The name of the stop id field (e.g. `from_stop_id`) referencing the stop. | String | -| `stopId` | The referenced stop id. | String | -| `locationTypeValue` | The numeric value of the invalid location type. | int | -| `locationTypeName` | The name of the invalid location type. | String | - -
    - -
    - -### transfer_with_invalid_trip_and_route - -A `from_trip_id` or `to_trip_id` field from GTFS file `transfers.txt` references a route that does not match its `trips.txt` `route_id`. - -#### References -* [transfers.txt specification](http://gtfs.org/reference/static/#transferstxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------|------------------------------------------------------------------------------|--------| -| `csvRowNumber` | The row number from `transfers.txt` for the faulty entry. | long | -| `tripFieldName` | The name of the trip id field (e.g. `from_trip_id`) referencing a trip. | String | -| `tripId` | The referenced trip id. | String | -| `routeFieldName` | The name of the route id field (e.g. `from_route_id`) referencing the route. | String | -| `routeId` | The referenced route id. | String | -| `expectedRouteId` | The expected route id from `trips.txt`. | String | - -
    - -
    - -### transfer_with_invalid_trip_and_stop - -A `from_trip_id` or `to_trip_id` field from GTFS file `transfers.txt` references a stop that is not included in the referenced trip's stop-times. - -#### References -* [transfers.txt specification](http://gtfs.org/reference/static/#transferstxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-----------------|----------------------------------------------------------------------------|--------| -| `csvRowNumber` | The row number from `transfers.txt` for the faulty entry. | long | -| `tripFieldName` | The name of the trip id field (e.g. `from_trip_id`) referencing a trip. | String | -| `tripId` | The referenced trip id. | String | -| `stopFieldName` | The name of the stop id field (e.g. `stop_route_id`) referencing the stop. | String | -| `stopId` | The referenced stop id. | String | - -
    - -
    - -### transfer_with_suspicious_mid_trip_in_seat - -A `from_trip_id` or `to_trip_id` field from GTFS file `transfers.txt` with an in-seat transfer type references a stop that is not in the expected position in the trip's stop-times. For in-seat transfers, we expect the stop to be the last stop-time in the trip sequence for `from_stop_id` and the first stop-time for `to_stop_id`. If you are intentionally using this feature to model mid-trip transfers, you can ignore this warning, but be aware that this functionality is still considered to be partially experimental in some interpretations of the spec. - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------|---------------------------------------------------------------------------|--------| -| `csvRowNumber` | The row number from `transfers.txt` for the faulty entry. | long | -| `tripIdFieldName` | The name of the trip id field (e.g. `from_trip_id`) referencing a trip. | String | -| `tripId` | The referenced trip id. | String | -| `stopIdFieldName` | The name of the stop id field (e.g. `from_stop_id`) referencing the stop. | String | -| `stopId` | The referenced stop id. | String | - -
    - -
    - -### translation_foreign_key_violation - -An entity with the given `record_id` and `record_sub_id` cannot be found in the referenced table. - -#### References -* [translations.txt specification](http://gtfs.org/reference/static/#translationstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------|----------------------------------------|------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `tableName` | `table_name` of the faulty record. | String | -| `recordId` | `record_id` of the faulty record. | String | -| `recordSubId` | `record_sub_id` of the faulty record. | String | - -#### Affected files -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### translation_unexpected_value - -A field in a translations row has value but must be empty. - -#### References -* [translations.txt specification](http://gtfs.org/reference/static/#translationstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------------|-----------------------------------------------------------|--------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `fieldName` | The name of the field that was expected to be empty. | String | -| `fieldValue` | Actual value of the field that was expected to be empty. | String | - -#### Affected files -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### wrong_parent_location_type - -Value of field `location_type` of parent found in field `parent_station` is invalid. - -According to spec -- _Stop/platform_ can only have _Station_ as parent -- _Station_ can NOT have a parent -- _Entrance/exit_ or _generic node_ can only have _Station_ as parent -- _Boarding Area_ can only have _Platform_ as parent - -Any other combination raise this error. - -#### References -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------------- |-------------------------------------------------- |--------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `stopId` | The id of the faulty record. | String | -| `stopName` | The faulty record's `stops.stop_name`. | String | -| `locationType` | The faulty record's `stops.location_type`. | Integer | -| `parentCsvRowNumber` | The row number of the faulty record's parent. | Long | -| `parentStation` | The id of the faulty record's parent station. | String | -| `parentStopName` | The stop name of the faulty record's parent. | String | -| `parentLocationType` | The location type of the faulty record's parent. | Integer | -| `expectedLocationType`| The expected location type of the faulty record. | Integer | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -# More details - WARNINGS - -
    - -### attribution_without_role - -At least one of the fields `is_producer`, `is_operator`, or `is_authority` should be set to 1. - -#### References -* [attributions.txt specification](https://gtfs.org/reference/static#attributionstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------- |--------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `attributionId` | The id of the faulty record. | String | - -#### Affected files -* [`attributions.txt`](http://gtfs.org/reference/static#attributionstxt) - -
    - -
    - -### duplicate_fare_media - -Two distinct fare media have the same fare media name and type. - -Fare media should have a unique combination of fare media name and type. - -#### References -* [fare_media.txt specification](http://gtfs.org/reference/static/#fare_mediatxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------|------------------------------------------|-------- | -| `csvRowNumber1` | The row of the first occurrence. | Long | -| `fareMediaId1` | The id of the the first occurrence. | String | -| `csvRowNumber2` | The row of the second occurrence. | Long | -| `fareMediaId2` | The id of the the second occurrence. | String | - -#### Affected files -* [fare_media.txt](http://gtfs.org/reference/static/#fare_mediatxt) - -
    - -
    - -### duplicate_route_name - -All routes of the same `route_type` with the same `agency_id` should have unique combinations of `route_short_name` and `route_long_name`. - -Note that there may be valid cases where routes have the same short and long name, e.g., if they serve different areas. However, different directions must be modeled as the same route. - -Example of bad data: -| `route_id` | `route_short_name` | `route_long_name` | -|------------ |-------------------- |------------------- | -| route1 | U1 | Southern | -| route2 | U1 | Southern | - -#### References -* [routes.txt specification](http://gtfs.org/reference/static/#routestxt) -* [routes.txt best practices](http://gtfs.org/best-practices/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |----------------------------------------- |-------- | -| `csvRowNumber1` | The row number of the first occurrence. | Long | -| `routeId1` | The id of the the first occurrence. | String | -| `csvRowNumber2` | The row number of the other occurrence. | Long | -| `routeId2` | The id of the the other occurrence. | String | -| `routeShortName` | Common `routes.route_short_name`. | String | -| `routeLongName` | Common `routes.route_long_name`. | String | -| `routeTypeValue` | Common `routes.route_type`. | String | -| `agencyId` | Common `routes.agency_id`. | String | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - - -
    - -
    - -### empty_row - -A row in the input file has only spaces. - -#### References -* [GTFS file requirements](http://gtfs.org/reference/static/#file-requirements) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row number of the faulty record. | Long | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### equal_shape_distance_same_coordinates - -When sorted by `shape.shape_pt_sequence`, the values for `shape_dist_traveled` must increase along a shape. Two consecutive points with equal values for `shape_dist_traveled` and the same coordinates indicate a duplicative shape point. - -#### References -* [shapes.txt specification](https://gtfs.org/reference/static#shapestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------------- |------------------------------------------------------------------------------------------------- |--------- | -| `shapeId` | The id of the faulty shape. | String | -| `csvRowNumber` | The row number from `shapes.txt`. | Long | -| `shapeDistTraveled` | Actual distance traveled along the shape from the first shape point to the faulty record. | Double | -| `shapePtSequence` | The faulty record's `shapes.shape_pt_sequence`. | Integer | -| `prevCsvRowNumber` | The row number from `shapes.txt` of the previous shape point. | Long | -| `prevShapeDistTraveled` | Actual distance traveled along the shape from the first shape point to the previous shape point. | Double | -| `prevShapePtSequence` | The previous record's `shapes.shape_pt_sequence`. | Integer | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) - -
    - -
    - -### expired_calendar - - Dataset should not contain date ranges for services that have already expired. This warning takes into account the `calendar_dates.txt` file as well as the `calendar.txt` file. - -#### References -* [Dataset Publishing & General Practices](https://gtfs.org/schedule/best-practices/#dataset-publishing-general-practices) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------------- |--------- | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `serviceId`| The `service_id` for the faulty record. | Long | - -#### Affected files -[`calendar.txt`](https://gtfs.org/schedule/reference/#calendartxt) -[`calendar_dates.txt`](https://gtfs.org/schedule/reference/#calendar_datestxt) - -
    - -
    - -### fast_travel_between_consecutive_stops - -A transit vehicle moves too fast between two consecutive stops. The speed threshold depends on route type. - -##### Speed thresholds - -| Route type | Description | Threshold, km/h | -|------------|-------------|-----------------| -| 0 | Light rail | 100 | -| 1 | Subway | 150 | -| 2 | Rail | 500 | -| 3 | Bus | 150 | -| 4 | Ferry | 80 | -| 5 | Cable tram | 30 | -| 6 | Aerial lift | 50 | -| 7 | Funicular | 50 | -| 11 | Trolleybus | 150 | -| 12 | Monorail | 150 | -| - | Unknown | 200 | - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|-----------------------|---------------------------------------- |-------- | -| `tripCsvRowNumber` | The row number of the problematic trip. | Long | -| `tripId` | `trip_id` of the problematic trip. | String | -| `routeId` | `route_id` of the problematic trip. | String | -| `speedKph` | Travel speed (km/h). | Double | -| `distanceKm` | Distance between stops (km). | Double | -| `csvRowNumber1` | The row number of the first stop time. | Long | -| `stopSequence1` | `stop_sequence` of the first stop. | Integer | -| `stopId1` | `stop_id` of the first stop. | String | -| `stopName1` | `stop_name` of the first stop. | String | -| `departureTime1` | `departure_time` of the first stop. | Time | -| `csvRowNumber2` | The row number of the second stop time. | Long | -| `stopSequence2` | `stop_sequence` of the second stop. | Integer | -| `stopId2` | `stop_id` of the second stop. | String | -| `stopName2` | `stop_name` of the second stop. | String | -| `arrivalTime2` | `arrival_time` of the second stop. | Time | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### fast_travel_between_far_stops - -A transit vehicle moves too fast between far consecutive stops (more than in 10 km apart). -This normally indicates a more serious problem than too fast travel between consecutive stops. -The speed threshold depends on route type. - -##### Speed thresholds - -Same as for [`fast_travel_between_consecutive_stops`](#fast_travel_between_consecutive_stops). - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|-----------------------|---------------------------------------- |-------- | -| `tripCsvRowNumber` | The row number of the problematic trip. | Long | -| `tripId` | `trip_id` of the problematic trip. | String | -| `routeId` | `route_id` of the problematic trip. | String | -| `speedKph` | Travel speed (km/h). | Double | -| `distanceKm` | Distance between stops (km). | Double | -| `csvRowNumber1` | The row number of the first stop time. | Long | -| `stopSequence1` | `stop_sequence` of the first stop. | Integer | -| `stopId1` | `stop_id` of the first stop. | String | -| `stopName1` | `stop_name` of the first stop. | String | -| `departureTime1` | `departure_time` of the first stop. | Time | -| `csvRowNumber2` | The row number of the second stop time. | Long | -| `stopSequence2` | `stop_sequence` of the second stop. | Integer | -| `stopId2` | `stop_id` of the second stop. | String | -| `stopName2` | `stop_name` of the second stop. | String | -| `arrivalTime2` | `arrival_time` of the second stop. | Time | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### feed_expiration_date7_days - -The dataset expiration date defined in `feed_info.txt` is in seven days or less. At any time, the published GTFS dataset should be valid for at least the next 7 days. - -### References -* [General Publishing & General Practices](https://gtfs.org/best-practices/#dataset-publishing--general-practices) - -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------- |---------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `currentDate` | Current date (YYYYMMDD format). | String | -| `feedEndDate` | Feed end date (YYYYMMDD format). | String | -| `suggestedExpirationDate` | Suggested expiration date (YYYYMMDD format). | String | - -#### Affected files -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -
    - - -
    - -### feed_expiration_date30_days - -At any time, the GTFS dataset should cover at least the next 30 days of service, and ideally for as long as the operator is confident that the schedule will continue to be operated. - -#### References -* [General Publishing & General Practices](https://gtfs.org/best-practices/#dataset-publishing--general-practices) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------- |---------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `currentDate` | Current date (YYYYMMDD format). | String | -| `feedEndDate` | Feed end date (YYYYMMDD format). | String | -| `suggestedExpirationDate` | Suggested expiration date (YYYYMMDD format). | String | - -#### Affected files -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) - -
    - -
    - -### feed_info_lang_and_agency_lang_mismatch -1. Files `agency.txt` and `feed_info.txt` should define matching `agency.agency_lang` and `feed_info.feed_lang`. - The default language may be multilingual for datasets with the original text in multiple languages. In such cases, the feed_lang field should contain the language code mul defined by the norm ISO 639-2. - * If `feed_lang` is not `mul` and does not match with `agency_lang`, that's an error - * If there is more than one `agency_lang` and `feed_lang` isn't `mul`, that's an error - * If `feed_lang` is `mul` and there isn't more than one `agency_lang`, that's an error - -#### References -* [GTFS feed_info.txt specification](http://gtfs.org/reference/static/#feed_infotxt) -* [GTFS agency.txt specification](http://gtfs.org/reference/static/#agencytxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------------------- |-------- | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `agencyId` | The agency id of the faulty record. | String | -| `agencyName` | The agency name of the faulty record. | String | -| `agencyLang` | The agency language of the faulty record. | String | -| `feedLang` | The feed language of the faulty record. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) - -
    - -
    - -### inconsistent_agency_lang - -Agencies from GTFS `agency.txt` have been found to have different languages. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |------------------------------- |-------- | -| `csvRowNumber` | The row of the faulty record. | Long | -| `expected` | Expected language. | String | -| `actual` | Faulty record's language. | String | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) - -
    - -
    - -### leading_or_trailing_whitespaces - -The value in CSV file has leading or trailing whitespaces. - -#### References -* [GTFS file requirements](http://gtfs.org/reference/static/#file-requirements) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | Faulty record's field name. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### missing_feed_info_date - -Even though `feed_info.start_date` and `feed_info.end_date` are optional, if one field is provided the second one should also be provided. - -#### References -* [feed_info.txt Best practices](http://gtfs.org/best-practices/#feed_infotxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |--------------------------------------------- |-------- | -| `fieldName` | Either `feed_end_date` or `feed_start_date` | String | -| `csvRowNumber` | The row number of the faulty record. | Long | - -#### Affected files -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) -#### Notice fields description - -
    - -
    - -### missing_recommended_column - -A recommended column is missing in the input file. - -#### References -* [GTFS terms definition](https://gtfs.org/reference/static/#term-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `fieldName` | The name of the missing column. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - - -
    - -### missing_recommended_file - -A recommended file is missing. - -#### References -* [feed_info.txt best practices](https://gtfs.org/schedule/best-practices/#feed_infotxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | - -#### Affected files -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) - -
    - -
    - -### missing_recommended_field - -The given field has no value in some input row, even though values are recommended. - -#### References -* [feed_info.txt best practices](https://gtfs.org/schedule/best-practices/#feed_infotxt) -* [agency.txt best practices](https://gtfs.org/schedule/best-practices/#agencytxt) -* [fare_attributes.txt best practices](https://gtfs.org/schedule/best-practices/#fare_attributestxt) -* [routes.txt best practices](https://gtfs.org/schedule/best-practices/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------- |-------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row of the faulty record. | Long | -| `fieldName` | The name of the missing field. | String | - -#### Affected files -* [`feed_info.txt`](http://gtfs.org/reference/static#feed_infotxt) - -
    - -
    - -### missing_timepoint_value - -Even though the column `timepoint` is optional in `stop_times.txt` according to the specification, `stop_times.timepoint` should not be empty when provided. - -#### References -* [stop_times.txt specification](https://gtfs.org/schedule/reference/#stop_timestxt) -
    - - -#### Notice fields description -| Field name | Description | Type | -|---------------- |------------------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `tripId` | The faulty record's `stop_times.trip_id`. | String | -| `stopSequence` | The faulty record's `stop_times.stop_sequence`. | String | - -#### Affected files -* [`stop_times.txt`](https://gtfs.org/schedule/reference/#stop_timestxt) - -
    - -
    - -### mixed_case_recommended_field - -This field contains customer-facing text and should use Mixed Case (upper and lower case letters) to ensure good readability when displayed to riders. Avoid the use of abbreviations throughout the feed (e.g. St. for Street) unless a location is called by its abbreviated name (e.g. “JFK Airport”). Abbreviations may be problematic for accessibility by screen reader software and voice user interfaces. - -#### References -* [Best Practices for All Files](https://gtfs.org/schedule/best-practices/#practice-recommendations-organized-by-file) -
    - - -#### Notice fields description -| Field name | Description | Type | -|------------------|--------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `filename` | Name of the faulty file. | String | -| `fieldName` | Name of the faulty field. | String | -| `fieldValue` | Name of the faulty field. | String | - -#### Affected files & fields -* [`agency.agency_name`](https://gtfs.org/schedule/reference/#agencytxt) -* [`stops.stop_name`](https://gtfs.org/schedule/reference/#stopstxt) -* [`stops.stop_desc`](https://gtfs.org/schedule/reference/#stopstxt) -* [`routes.route_short_name`](https://gtfs.org/schedule/reference/#routestxt) -* [`routes.route_long_name`](https://gtfs.org/schedule/reference/#routestxt) -* [`routes.route_desc`](https://gtfs.org/schedule/reference/#routestxt) -* [`trips.trip_headsign`](https://gtfs.org/schedule/reference/#tripstxt) -* [`trips.trip_short_name`](https://gtfs.org/schedule/reference/#tripstxt) -* [`pathways.signposted_as`](https://gtfs.org/schedule/reference/#pathwaystxt) -* [`pathways.reversed_signposted_as`](https://gtfs.org/schedule/reference/#pathwaystxt) -* [`levels.level_name`](https://gtfs.org/schedule/reference/#levelstxt) - -
    - -
    - -### more_than_one_entity - -The file is expected to have a single entity but has more (e.g., "feed_info.txt"). - -#### References -* [GTFS field definition](http://gtfs.org/reference/static#field-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------- |-------------------------- |-------- | -| `filename` | Name of the faulty file. | String | -| `entityCount` | Number of occurrences. | Long | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### non_ascii_or_non_printable_char - -A value of a field with type `id` contains non ASCII or non printable characters. This is not recommended. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |---------------------------------------------- |-------- | -| `filename` | Name of the faulty file. | String | -| `csvRowNumber`| Row number of the faulty record. | Long | -| `columnName` | Name of the column where the error occurred. | String | -| `fieldValue` | Faulty value. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### pathway_dangling_generic_node - -A generic node has only one incident location in a pathway graph. Such generic node is useless -because there is no benefit in visiting it. - -#### References -* [pathways.txt specification](http://gtfs.org/reference/static/#pathwaystxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|----------------|-----------------------------------------------------|--------- | -| `csvRowNumber` | Row number of the dangling generic node. | Long | -| `stopId` | The id of the dangling generic node. | String | -| `stopName` | The stop name of the dangling generic node. | String | -| `parentStation`| The parent station of the dangling generic node. | String | - -#### Affected files -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### pathway_loop - -A pathway should not have same values for `from_stop_id` and `to_stop_id`. - -#### References -* [pathways.txt specification](http://gtfs.org/reference/static/#pathwaystxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |--------------------------------------------------------------------------------------------- |-------- | -| `csvRowNumber` | Row number of the faulty row from `pathways.txt`. | Long | -| `pathwayId` | The id of the faulty record. | String | -| `stopId` | The `pathway.stop_id` that is repeated in `pathways.from_stop_id` and `pathways.to_stop_id`. | String | - -#### Affected files -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) -
    - -
    - -### route_color_contrast - -A route's color and `route_text_color` should be contrasting. - -#### References -* [routes.txt specification](http://gtfs.org/reference/static/#routestxt) -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |--------------------------------------------- |-------- | -| `routeId` | The id of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `routeColor` | The faulty record's HTML route color. | String | -| `routeTextColor` | The faulty record's HTML route text color. | String | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### route_long_name_contains_short_name - -In routes.txt, `route_long_name` should not contain the value for `route_short_name`, because when both are provided, they are often combined by transit applications. Note that only one of the two fields is required. If there is no short name used for a route, use `route_long_name` only. - -Good examples: -| `route_short_name`/`route_long_name` | Dataset | -| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ["N"/"Judah"](https://www.sfmta.com/getting-around/transit/routes-stops/n-judah) | [Muni San Fransisco](https://storage.googleapis.com/storage/v1/b/mdb-latest/o/us-california-san-francisco-municipal-transportation-agency-sfmta-gtfs-50.zip?alt=media) | -| ["6"/"ML King Jr Blvd"](https://trimet.org/schedules/r006.htm) | [Trimet Portland Streetcar](http://developer.trimet.org/schedule/gtfs.zip) | -| ["55"/"Boulevard Saint Laurent"](https://www.stm.info/en/info/networks/bus/local/line-55-north) | [STM Montreal](https://storage.googleapis.com/storage/v1/b/mdb-latest/o/ca-quebec-societe-de-transport-de-montreal-gtfs-1221.zip?alt=media) | -| ["1"/"Rangiora/Cashmere"](https://www.metroinfo.co.nz/timetables/1-rangiora-cashmere/) | [Metro Christchurch](https://storage.googleapis.com/storage/v1/b/mdb-latest/o/nz-christchurch-christchurch-metro-gtfs-1313.zip?alt=media) | - -Bad examples: -| `route_short_name`/`route_long_name` | -|-------------------------------------------| -| "604"/"604" | -| "14"/"Route 14" | -| "2"/"Route 2: Bellows Falls In-Town" | - - -#### References -* [routes.txt Best Practices](https://gtfs.org/schedule/best-practices/#routestxt) -
    - -#### Notice fields description - -| Field name | Description | Type | -| ---------------- | -------------------------------------------- | ------ | -| `routeId` | The id of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `routeShortName` | The `route_short_name` of the faulty record. | String | -| `routeLongName` | The `route_long_name` of the faulty record. | String | - - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### route_short_name_too_long - -Short name of a route is too long (more than 12 characters). - -#### References -* [routes.txt Best Practices](https://gtfs.org/best-practices/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |------------------------------------------- |-------- | -| `routeId` | The id of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `routeShortName` | The faulty record's `route_short_name`. | String | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### same_name_and_description_for_route - -The GTFS spec defines `routes.txt` [route_desc](https://gtfs.org/reference/static/#routestxt) as: - -> Description of a route that provides useful, quality information. Do not simply duplicate the name of the route. - -See the GTFS and GTFS Best Practices links below for more examples of how to populate the `route_short_name`, `route_long_name`, and `route_desc` fields. - -#### References -[routes.txt specification](http://gtfs.org/reference/static/#routestxt) -[routes.txt Best Practices](https://gtfs.org/best-practices/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |------------------------------------------------ |-------- | -| `filename` | The name of the faulty file. | String | -| `routeId` | The id of the faulty record. | String | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `routeDesc` | The `routes.routes_desc` of the faulty record. | String | -| `specifiedField`| Either `route_short_name` or `route_long_name`. | String | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### same_name_and_description_for_stop - -The GTFS spec defines `stops.txt` [stop_description](https://gtfs.org/reference/static/#stopstxt) as: - -> Description of the location that provides useful, quality information. Do not simply duplicate the name of the location. - -#### References -[stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |----------------------------------------- |-------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `stopId` | The id of the faulty record. | String | -| `stopDesc` | The faulty record's `stop_desc`. | String | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### same_route_and_agency_url - -A route should not have the same `routes.route_url` as a record from `agency.txt`. - -#### References -* [routes.txt specification](http://gtfs.org/reference/static/#routestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |-------------------------------------------- |-------- | -| `routeCsvRowNumber` | The row number of the faulty record from `routes.txt`. | Long | -| `routeId` | The faulty record's id. | String | -| `agencyId` | The faulty record's `routes.agency_id`. | String | -| `agencyName` | The faulty record's referenced agency name. | String | -| `routeUrl` | The duplicate URL value | String | -| `agencyCsvRowNumber` | The row number of the faulty record from `agency.txt`. | Long | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) - -
    - -
    - -### same_stop_and_agency_url - -A stop should not have the same `stops.stop_url` as a record from `agency.txt`. - -#### References -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|---------------- |-------------------------------------------------------- |-------- | -| `stopCsvRowNumber`| The row number of the faulty record from `stops.txt`. | Long | -| `stopId` | The faulty record's id. | String | -| `agencyName` | The faulty record's `agency.agency_name`. | String | -| `stopUrl` | The duplicate URL value. | String | -| `agencyCsvRowNumber` | The row number of the faulty record from `agency.txt`.| Long | - -#### Affected files -* [`agency.txt`](http://gtfs.org/reference/static#agencytxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### same_stop_and_route_url - -A stop should not have the same `stop.stop_url` as a record from `routes.txt`. - -#### References -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|--------------------- |-------------------------------------------------------- |-------- | -| `stopCsvRowNumber` | The row number of the faulty record from `stops.txt`. | Long | -| `stopId` | The faulty record's id. | String | -| `stopUrl` | The duplicate URL value. | String | -| `routeId` | The faulty record's id from `routes.txt. | String | -| `routeCsvRowNumber` | The row number of the faulty record from `routes.txt`. | Long | - -#### Affected files -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### stop_has_too_many_matches_for_shape - -A stop entry that has many potential matches to the trip's path of travel, as defined by the shape entry in `shapes.txt`. - -#### References -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) -* [stops_times.txt specification](https://gtfs.org/schedule/reference/#stop_timestxt) -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------ |------------------------------------------------------------ |--------- | -| `tripCsvRowNumber` | The row number of the faulty record from `trips.txt`. | Long | -| `shapeId` | The id of the shape that is referred to. | String | -| `tripId` | The id of the trip that is referred to. | String | -| `stopTimeCsvRowNumber` | The row number of the faulty record from `stop_times.txt`. | Long | -| `stopId` | The id of the stop that is referred to. | String | -| `stopName` | The name of the stop that is referred to. | String | -| `match` | Latitude and longitude pair of the location. | Object | -| `matchCount` | The number of matches for the stop that is referred to. | Integer | - -#### Affected files -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) -* [`stops_times.txt`](https://gtfs.org/schedule/reference/#stop_timestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -
    - -
    - -### stops_match_shape_out_of_order - -Two stop entries in `stop_times.txt` are different than their arrival-departure order as defined by the shape in the `shapes.txt` file. - -#### References -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) -* [stops_times.txt specification](https://gtfs.org/schedule/reference/#stop_timestxt) -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------- |------------------------------------------------------------------- |-------- | -| `tripCsvRowNumber` | The row number of the faulty record from `trips.txt`. | Long | -| `shapeId` | The id of the shape that is referred to. | String | -| `tripId` | The id of the trip that is referred to. | String | -| `stopTimeCsvRowNumber1` | The row number of the first faulty record from `stop_times.txt`. | Long | -| `stopId1` | The id of the first stop that is referred to. | String | -| `stopName1` | The name of the first stop that is referred to. | String | -| `match1` | Latitude and longitude pair of the first matching location. | Object | -| `stopTimeCsvRowNumber2` | The row number of the second faulty record from `stop_times.txt`. | Long | -| `stopId2` | The id of the second stop that is referred to. | String | -| `stopName2` | The name of the second stop that is referred to. | String | -| `match2` | Latitude and longitude pair of the second matching location. | Object | - -#### Affected files -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) -* [`stops_times.txt`](http://gtfs.org/reference/static#stopstimestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -
    - -
    - -### stop_too_far_from_shape - -Per GTFS Best Practices, route alignments (in `shapes.txt`) should be within 100 meters of stop locations which a trip serves. - -#### References -* [GTFS Best Practices shapes.txt](https://gtfs.org/best-practices/#shapestxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------ |------------------------------------------------------------ |-------- | -| `tripCsvRowNumber` | The row number of the faulty record from `trips.txt`. | Long | -| `shapeId` | The id of the shape that is referred to. | String | -| `tripId` | The id of the trip that is referred to. | String | -| `stopTimeCsvRowNumber` | The row number of the faulty record from `stop_times.txt`. | Long | -| `stopId` | The id of the stop that is referred to. | String | -| `stopName` | The name of the stop that is referred to. | String | -| `match` | Latitude and longitude pair of the location. | Object | -| `geoDistanceToShape` | Distance from stop to shape. | Double | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stoptimestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### stop_too_far_from_shape_using_user_distance - -A stop time entry that is a large distance away from the location of the shape in `shapes.txt` as defined by `shape_dist_traveled` values. - -#### References -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) -* [stops_times.txt specification](https://gtfs.org/schedule/reference/#stop_timestxt) -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------------ |------------------------------------------------------------ |-------- | -| `tripCsvRowNumber` | The row number of the faulty record from `trips.txt`. | Long | -| `shapeId` | The id of the shape that is referred to. | String | -| `tripId` | The id of the trip that is referred to. | String | -| `stopTimeCsvRowNumber` | The row number of the faulty record from `stop_times.txt`. | Long | -| `stopId` | The id of the stop that is referred to. | String | -| `stopName` | The name of the stop that is referred to. | String | -| `match` | Latitude and longitude pair of the location. | Object | -| `geoDistanceToShape` | Distance from stop to shape. | Double | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stoptimestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - A stop time entry that is a large distance away from the location of the shape in `shapes.txt` as defined by `shape_dist_traveled` values. -
    - -
    - -### stop_without_stop_time - -A stop in `stops.txt` is not referenced by any `stop_times.stop_id`, so it is not used by any trip. -Such stops normally do not provide user value. This notice may indicate a typo in `stop_times.txt`. - -#### References -* [stops_times.txt specification](https://gtfs.org/schedule/reference/#stop_timestxt) -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------|----------------------------------------|------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `stopId` | The id of the faulty stop. | String | -| `stopName` | The name of the faulty stop. | String | - -
    - -
    - -### translation_unknown_table_name - -A translation references an unknown or missing GTFS table. - -#### References -* [translations.txt specification](http://gtfs.org/reference/static/#translationstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------------|----------------------------------------|------- | -| `csvRowNumber` | The row number of the faulty record. | Long | -| `tableName` | `table_name` of the faulty record. | String | - -#### Affected files -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) - -
    - -
    - -### trip_coverage_not_active_for_next7_days - -Trips data should be valid for at least the next seven days. This notice is triggered if the date range where a significant number of trips are running ends in less than 7 days. - -#### References - -- [Dataset Publishing & General Practices](https://gtfs.org/schedule/best-practices/#dataset-publishing-general-practices) -
    - -#### Notice fields description - -| Field name | Description | Type | -| ------------------------ | ------------------------------------------- | ---- | -| `currentDate` | The date that the dataset was validated. | Date | -| `serviceWindowStartDate` | The start date of the trips in the dataset. | Date | -| `serviceWindowEndDate` | The end date of the trips in the dataset. | Date | - -#### Affected files - -- [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### unexpected_enum_value - -An enum has an unexpected value. - -#### References -* [GTFs field definitions](http://gtfs.org/reference/static/#field-definitions) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |------------------------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `fieldName` | The name of the field where the error occurred. | String | -| `fieldValue` | Faulty value. | Integer | - -#### Affected files -* [`attributions.txt`](http://gtfs.org/reference/static#attributionstxt) -* [`calendar.txt`](http://gtfs.org/reference/static#calendartxt) -* [`calendar_dates.txt`](http://gtfs.org/reference/static#calendar_datestxt) -* [`fare_attributes.txt`](http://gtfs.org/reference/static#fare_attributestxt) -* [`frequencies.txt`](http://gtfs.org/reference/static#frequenciestxt) -* [`levels.txt`](http://gtfs.org/reference/static#levelstxt) -* [`routes.txt`](http://gtfs.org/reference/static#routestxt) -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`transfers.txt`](http://gtfs.org/reference/static#transferstxt) -* [`translations.txt`](http://gtfs.org/reference/static#translationstxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) -* [`pathways.txt`](http://gtfs.org/reference/static#pathwaystxt) - -
    - -
    - -### unusable_trip - -A trip must visit more than one stop in stop_times.txt to be usable by passengers for boarding and alighting. - -#### References: -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------------- |-------- | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `tripId` | The faulty record's id. | String | - -#### Affected files -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### unused_shape - -All records defined by GTFS `shapes.txt` should be used in `trips.txt`. - -#### References: -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [shapes.txt specification](http://gtfs.org/reference/static#shapestxt) -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------------- |-------- | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `shapeId` | The faulty record's id. | String | - -#### Affected files -* [`shapes.txt`](http://gtfs.org/reference/static#shapestxt) -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) - -
    - -
    - -### unused_trip - -Trips should be referred to at least once in `stop_times.txt`. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -* [trips.txt specification](http://gtfs.org/reference/static#tripstxt) -* [stop_times.txt specification](http://gtfs.org/reference/static#stop_timestxt) - -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |-------------------------------------- |-------- | -| `csvRowNumber`| The row number of the faulty record. | Long | -| `tripId` | The faulty record's id. | String | - -#### Affected files -* [`trips.txt`](http://gtfs.org/reference/static#tripstxt) -* [`stop_times.txt`](http://gtfs.org/reference/static#stop_timestxt) - -
    - -# More details - INFOS - -
    - -### platform_without_parent_station - -A platform has no `parent_station` field set. - -#### References -* [stops.txt specification](http://gtfs.org/reference/static/#stopstxt) -
    - -#### Notice fields description -| Field name | Description | Type | -|-------------- |----------------------------------------- |--------- | -| `csvRowNumber`| Row number of the faulty record. | Long | -| `stopId` | The id of the faulty record. | String | -| `stopName` | The stop name of the faulty record. | String | -| `locationType`| The location type of the faulty record. | Integer | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - -
    - -
    - -### unknown_column - -A column is unknown. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------- |--------- | -| `filename` | The name of the faulty file. | String | -| `fieldName` | The name of the unknown column. | String | -| `index` | The index of the faulty column. | Integer | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) - -
    - -
    - -### unknown_file - -A file is unknown. - -#### References -* [Original Python validator implementation](https://github.com/google/transitfeed) -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------- |---------| -| `filename` | The name of the unknown file. | String | - -
    - -
    - -### unused_parent_station - -A stop has `location_type` 1 (station) but does not appear in the -`parent_station` field for any stop with `location_type` 0 -(stop/platform) in `stops.txt`. - -#### Notice fields description -| Field name | Description | Type | -|------------------|----------------------------------------|------- | -| `csvRowNumber` | The row number of the faulty record. | Int | -| `stopId` | The id of the faulty stop. | String | -| `stopName` | The name of the faulty stop. | String | - -#### Affected files -* [`stops.txt`](http://gtfs.org/reference/static#stopstxt) - - - -# More details - SYSTEM ERRORS - - - -### i_o_error - -Error in IO operation. -
    - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------------------------------------- |---------| -| `exception` | The name of the exception. | String | -| `message` | The error message that explains the reason for the exception. | String | -
    - -
    - -### runtime_exception_in_loader_error - -A [RuntimeException](https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeException.html) occurred while loading a table. This normally indicates a bug in validator. -
    - - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------------------------------------- |---------| -| `filename` | The name of the file that caused the exception. | String | -| `exception` | The name of the exception. | String | -| `message` | The error message that explains the reason for the exception. | String | - -#### Affected files -[All GTFS files supported by the specification.](http://gtfs.org/reference/static#dataset-files) -
    - -
    - -### runtime_exception_in_validator_error - -A [RuntimeException](https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeException.html) occurred during validation. This normally indicates a bug in validator code, e.g., in a custom validator class. -
    - -#### Notice fields description -| Field name | Description | Type | -|------------ |--------------------------------------------------------------- |---------| -| `validator` | The name of the validator that caused the exception. | String | -| `exception` | The name of the exception. | String | -| `message` | The error message that explains the reason for the exception. | String | -
    - -
    - -### thread_execution_error - -An [ExecutionException](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutionException.html) occurred during multithreaded validation. -
    - - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------------------------------------- |---------| -| `exception` | The name of the exception. | String | -| `message` | The error message that explains the reason for the exception. | String | -
    - -
    - -### u_r_i_syntax_error - -A string could not be parsed as a URI reference. -
    - - -#### Notice fields description -| Field name | Description | Type | -|------------- |--------------------------------------------------------------- |---------| -| `exception` | The name of the exception. | String | -| `message` | The error message that explains the reason for the exception. | String | -
    +The documented list of all notices is now available at https://gtfs-validator.mobilitydata.org/rules.html diff --git a/main/build.gradle b/main/build.gradle index df34c56bb0..b20e9cb31b 100644 --- a/main/build.gradle +++ b/main/build.gradle @@ -52,16 +52,4 @@ dependencies { testImplementation 'com.google.truth:truth:1.0.1' testImplementation 'com.google.truth.extensions:truth-java8-extension:1.0.1' testImplementation 'org.mockito:mockito-core:4.5.1' -} - -// A custom task to copy RULES.md into the test resource directory so that we can reference it in -// unit tests. See NoticeDocumentationTest for more details. -tasks.register('copyRulesMarkdown', Copy) { - from "$rootDir/RULES.md" - into "$projectDir/build/resources/test" -} - -test { - // Make sure `copyRulesMarkdown` runs before we run any tests. - dependsOn 'copyRulesMarkdown' } \ No newline at end of file diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/NoticeDocumentationTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/NoticeDocumentationTest.java index 72fd32375e..37ad6656f4 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/NoticeDocumentationTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/NoticeDocumentationTest.java @@ -1,20 +1,11 @@ package org.mobilitydata.gtfsvalidator.validator; -import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import com.google.common.collect.ImmutableList; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; @@ -26,37 +17,6 @@ @RunWith(JUnit4.class) public class NoticeDocumentationTest { - private static Pattern MARKDOWN_NOTICE_SIMPLE_CLASS_NAME_ANCHOR_PATTERN = - Pattern.compile("^
    "); - - private static Pattern MARKDOWN_NOTICE_CODE_HEADER_PATTERN = - Pattern.compile("^### (([a-z0-9]+_)*[a-z0-9]+)"); - - /** - * If this test is failing, it likely means you need to update RULES.md in the project root - * directory to include an entry for a new notice. - */ - @Test - public void testThatRulesMarkdownContainsAnchorsForAllValidationNotices() throws IOException { - Set fromMarkdown = readNoticeSimpleClassNamesFromRulesMarkdown(); - Set fromSource = - discoverValidationNoticeClasses().map(Class::getSimpleName).collect(Collectors.toSet()); - - assertThat(fromMarkdown).isEqualTo(fromSource); - } - - /** - * If this test is failing, it likely means you need to update RULES.md in the project root - * directory to include an entry for a new notice. - */ - @Test - public void testThatRulesMarkdownContainsHeadersForAllValidationNotices() throws IOException { - Set fromMarkdown = readNoticeCodesFromRulesMarkdown(); - Set fromSource = - discoverValidationNoticeClasses().map(Notice::getCode).collect(Collectors.toSet()); - - assertThat(fromMarkdown).isEqualTo(fromSource); - } @Test public void testThatAllValidationNoticesAreDocumented() { @@ -164,35 +124,4 @@ private static Stream> discoverValidationNoticeClasses() { return ClassGraphDiscovery.discoverNoticeSubclasses(ClassGraphDiscovery.DEFAULT_NOTICE_PACKAGES) .stream(); } - - private static Set readNoticeSimpleClassNamesFromRulesMarkdown() throws IOException { - return readValuesFromRulesMarkdown(MARKDOWN_NOTICE_SIMPLE_CLASS_NAME_ANCHOR_PATTERN); - } - - private static Set readNoticeCodesFromRulesMarkdown() throws IOException { - return readValuesFromRulesMarkdown(MARKDOWN_NOTICE_CODE_HEADER_PATTERN); - } - - private static Set readValuesFromRulesMarkdown(Pattern pattern) throws IOException { - // RULES.md is copied into the main/build/resources/test resource directory by a custom copy - // rule in the main/build.gradle file. - try (InputStream in = NoticeDocumentationTest.class.getResourceAsStream("/RULES.md")) { - // Scan lines from the markdown file, find those that match our regex pattern, and pull out - // the matching group. - return new BufferedReader(new InputStreamReader(in)) - .lines() - .map(line -> maybeMatchAndExtract(pattern, line)) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - } - } - - private static Optional maybeMatchAndExtract(Pattern p, String line) { - Matcher m = p.matcher(line); - if (m.matches()) { - return Optional.of(m.group(1)); - } else { - return Optional.empty(); - } - } }