<commit_before>import { t } from '../util/locale';
import { modeDrawLine } from '../modes';
import { operationDelete } from '../operations/index';
import { utilDisplayLabel } from '../util';
import { validationIssue, validationIssueFix } from '../core/validator';


export function validationDisconnectedWay() {
    var type = 'disconnected_way';

    var highways = {
        residential: true, service: true, track: true, unclassified: true, footway: true,
        path: true, tertiary: true, secondary: true, primary: true, living_street: true,
        cycleway: true, trunk: true, steps: true, motorway: true, motorway_link: true,
        pedestrian: true, trunk_link: true, primary_link: true, secondary_link: true,
        road: true, tertiary_link: true, bridleway: true, raceway: true, corridor: true,
        bus_guideway: true
    };

    function isTaggedAsHighway(entity) {
        return highways[entity.tags.highway];
    }


    var validation = function checkDisconnectedWay(entity, context) {
        var graph = context.graph();

        if (!isTaggedAsHighway(entity)) return [];
        if (!isDisconnectedWay(entity) && !isDisconnectedMultipolygon(entity)) return [];

        var entityLabel = utilDisplayLabel(entity, context);
        var fixes = [];

        if (entity.type === 'way' && !entity.isClosed()) {
            var first = context.entity(entity.first());
            if (first.tags.noexit !== 'yes') {
                fixes.push(new validationIssueFix({
                    icon: 'iD-operation-continue-left',
                    title: t('issues.fix.continue_from_start.title'),
                    entityIds: [entity.first()],
                    onClick: function() {
                        var vertex = context.entity(entity.first());
                        continueDrawing(entity, vertex, context);
                    }
                }));
            }
            var last = context.entity(entity.last());
            if (last.tags.noexit !== 'yes') {
                fixes.push(new validationIssueFix({
                    icon: 'iD-operation-continue',
                    title: t('issues.fix.continue_from_end.title'),
                    entityIds: [entity.last()],
                    onClick: function() {
                        var vertex = context.entity(entity.last());
                        continueDrawing(entity, vertex, context);
                    }
                }));
            }
        }

        if (!operationDelete([entity.id], context).disabled()) {
            fixes.push(new validationIssueFix({
                icon: 'iD-operation-delete',
                title: t('issues.fix.delete_feature.title'),
                entityIds: [entity.id],
                onClick: function() {
                    var id = this.issue.entities[0].id;
                    var operation = operationDelete([id], context);
                    if (!operation.disabled()) {
                        operation();
                    }
                }
            }));
        }

        return [new validationIssue({
            type: type,
            severity: 'warning',
            message: t('issues.disconnected_way.highway.message', { highway: entityLabel }),
            reference: showReference,
            entities: [entity],
            fixes: fixes
        })];


        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.disconnected_way.highway.reference'));
        }


        function vertexIsDisconnected(way, vertex, relation) {
            // can not accurately test vertices on tiles not downloaded from osm - #5938
            var osm = context.connection();
            if (osm && !osm.isDataLoaded(vertex.loc)) {
                return false;
            }

            var parents = graph.parentWays(vertex);

            // standalone vertex
            if (parents.length === 1) return true;

            // entrances are considered connected
            if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return false;

            return !parents.some(function(parentWay) {
                if (parentWay === way) return false;   // ignore the way we're testing
                if (isTaggedAsHighway(parentWay)) return true;

                return graph.parentMultipolygons(parentWay).some(function(parentRelation) {
                    // ignore the relation we're testing, if any
                    if (relation && parentRelation === relation) return false;

                    return isTaggedAsHighway(parentRelation);
                });
            });
        }


        function isDisconnectedWay(entity) {
            if (entity.type !== 'way') return false;
            return graph.childNodes(entity).every(function(vertex) {
                return vertexIsDisconnected(entity, vertex);
            });
        }


        function isDisconnectedMultipolygon(entity) {
            if (entity.type !== 'relation' || !entity.isMultipolygon()) return false;

            return entity.members.every(function(member) {
                if (member.type !== 'way') return true;

                var way = graph.hasEntity(member.id);
                if (!way) return true;

                return graph.childNodes(way).every(function(vertex) {
                    return vertexIsDisconnected(way, vertex, entity);
                });
            });
        }

        function continueDrawing(way, vertex) {
            // make sure the vertex is actually visible and editable
            var map = context.map();
            if (!map.editable() || !map.trimmedExtent().contains(vertex.loc)) {
                map.zoomToEase(vertex);
            }

            context.enter(
                modeDrawLine(context, way.id, context.graph(), context.graph(), way.affix(vertex.id), true)
            );
        }
    };


    validation.type = type;

    return validation;
}<commit_msg>Add missing `button` arg to modeDrawLine, ensure using current entities<commit_after>import { t } from '../util/locale';
import { modeDrawLine } from '../modes';
import { operationDelete } from '../operations/index';
import { utilDisplayLabel } from '../util';
import { validationIssue, validationIssueFix } from '../core/validator';


export function validationDisconnectedWay() {
    var type = 'disconnected_way';

    var highways = {
        residential: true, service: true, track: true, unclassified: true, footway: true,
        path: true, tertiary: true, secondary: true, primary: true, living_street: true,
        cycleway: true, trunk: true, steps: true, motorway: true, motorway_link: true,
        pedestrian: true, trunk_link: true, primary_link: true, secondary_link: true,
        road: true, tertiary_link: true, bridleway: true, raceway: true, corridor: true,
        bus_guideway: true
    };

    function isTaggedAsHighway(entity) {
        return highways[entity.tags.highway];
    }


    var validation = function checkDisconnectedWay(entity, context) {
        var graph = context.graph();

        if (!isTaggedAsHighway(entity)) return [];
        if (!isDisconnectedWay(entity) && !isDisconnectedMultipolygon(entity)) return [];

        var entityLabel = utilDisplayLabel(entity, context);
        var fixes = [];
        var entityID = entity.id;
        var firstID = entity.first();
        var lastID = entity.last();

        if (entity.type === 'way' && !entity.isClosed()) {
            var first = context.entity(firstID);
            if (first.tags.noexit !== 'yes') {
                fixes.push(new validationIssueFix({
                    icon: 'iD-operation-continue-left',
                    title: t('issues.fix.continue_from_start.title'),
                    entityIds: [firstID],
                    onClick: function() {
                        var way = context.entity(entityID);
                        var vertex = context.entity(firstID);
                        continueDrawing(way, vertex, context);
                    }
                }));
            }
            var last = context.entity(lastID);
            if (last.tags.noexit !== 'yes') {
                fixes.push(new validationIssueFix({
                    icon: 'iD-operation-continue',
                    title: t('issues.fix.continue_from_end.title'),
                    entityIds: [lastID],
                    onClick: function() {
                        var way = context.entity(entityID);
                        var vertex = context.entity(lastID);
                        continueDrawing(way, vertex, context);
                    }
                }));
            }
        }

        if (!operationDelete([entity.id], context).disabled()) {
            fixes.push(new validationIssueFix({
                icon: 'iD-operation-delete',
                title: t('issues.fix.delete_feature.title'),
                entityIds: [entity.id],
                onClick: function() {
                    var id = this.issue.entities[0].id;
                    var operation = operationDelete([id], context);
                    if (!operation.disabled()) {
                        operation();
                    }
                }
            }));
        }

        return [new validationIssue({
            type: type,
            severity: 'warning',
            message: t('issues.disconnected_way.highway.message', { highway: entityLabel }),
            reference: showReference,
            entities: [entity],
            fixes: fixes
        })];


        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.disconnected_way.highway.reference'));
        }


        function vertexIsDisconnected(way, vertex, relation) {
            // can not accurately test vertices on tiles not downloaded from osm - #5938
            var osm = context.connection();
            if (osm && !osm.isDataLoaded(vertex.loc)) {
                return false;
            }

            var parents = graph.parentWays(vertex);

            // standalone vertex
            if (parents.length === 1) return true;

            // entrances are considered connected
            if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return false;

            return !parents.some(function(parentWay) {
                if (parentWay === way) return false;   // ignore the way we're testing
                if (isTaggedAsHighway(parentWay)) return true;

                return graph.parentMultipolygons(parentWay).some(function(parentRelation) {
                    // ignore the relation we're testing, if any
                    if (relation && parentRelation === relation) return false;

                    return isTaggedAsHighway(parentRelation);
                });
            });
        }


        function isDisconnectedWay(entity) {
            if (entity.type !== 'way') return false;
            return graph.childNodes(entity).every(function(vertex) {
                return vertexIsDisconnected(entity, vertex);
            });
        }


        function isDisconnectedMultipolygon(entity) {
            if (entity.type !== 'relation' || !entity.isMultipolygon()) return false;

            return entity.members.every(function(member) {
                if (member.type !== 'way') return true;

                var way = graph.hasEntity(member.id);
                if (!way) return true;

                return graph.childNodes(way).every(function(vertex) {
                    return vertexIsDisconnected(way, vertex, entity);
                });
            });
        }

        function continueDrawing(way, vertex) {
            // make sure the vertex is actually visible and editable
            var map = context.map();
            if (!map.editable() || !map.trimmedExtent().contains(vertex.loc)) {
                map.zoomToEase(vertex);
            }

            context.enter(
                modeDrawLine(context, way.id, context.graph(), context.graph(), 'line', way.affix(vertex.id), true)
            );
        }
    };


    validation.type = type;

    return validation;
}
{'fraction_non_alphanumeric': 0.11616486878119466, 'fraction_numerical': 0.0011270326839478344, 'mean_word_length': 1.7030026109660574, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '354056', 'n_tokens_mistral': 3226, 'n_tokens_neox': 3006, 'n_words': 721}