Files
Laca-City/frontend/node_modules/eslint-plugin-react/lib/rules/jsx-no-useless-fragment.js
PhongPham c65cc97a33 🎯 MapView v2.0 - Global Deployment Ready
 MAJOR FEATURES:
• Auto-zoom intelligence với smart bounds fitting
• Enhanced 3D GPS markers với pulsing effects
• Professional route display với 6-layer rendering
• Status-based parking icons với availability indicators
• Production-ready build optimizations

🗺️ AUTO-ZOOM FEATURES:
• Smart bounds fitting cho GPS + selected parking
• Adaptive padding (50px) cho visual balance
• Max zoom control (level 16) để tránh quá gần
• Dynamic centering khi không có selection

🎨 ENHANCED VISUALS:
• 3D GPS marker với multi-layer pulse effects
• Advanced parking icons với status colors
• Selection highlighting với animation
• Dimming system cho non-selected items

🛣️ ROUTE SYSTEM:
• OpenRouteService API integration
• Multi-layer route rendering (glow, shadow, main, animated)
• Real-time distance & duration calculation
• Visual route info trong popup

📱 PRODUCTION READY:
• SSR safe với dynamic imports
• Build errors resolved
• Global deployment via Vercel
• Optimized performance

🌍 DEPLOYMENT:
• Vercel: https://whatever-ctk2auuxr-phong12hexdockworks-projects.vercel.app
• Bundle size: 22.8 kB optimized
• Global CDN distribution
• HTTPS enabled

💾 VERSION CONTROL:
• MapView-v2.0.tsx backup created
• MAPVIEW_VERSIONS.md documentation
• Full version history tracking
2025-07-20 19:52:16 +07:00

260 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @fileoverview Disallow useless fragments
*/
'use strict';
const arrayIncludes = require('array-includes');
const pragmaUtil = require('../util/pragma');
const astUtil = require('../util/ast');
const jsxUtil = require('../util/jsx');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
const getText = require('../util/eslint').getText;
function isJSXText(node) {
return !!node && (node.type === 'JSXText' || node.type === 'Literal');
}
/**
* @param {string} text
* @returns {boolean}
*/
function isOnlyWhitespace(text) {
return text.trim().length === 0;
}
/**
* @param {ASTNode} node
* @returns {boolean}
*/
function isNonspaceJSXTextOrJSXCurly(node) {
return (isJSXText(node) && !isOnlyWhitespace(node.raw)) || node.type === 'JSXExpressionContainer';
}
/**
* Somehow fragment like this is useful: <Foo content={<>ee eeee eeee ...</>} />
* @param {ASTNode} node
* @returns {boolean}
*/
function isFragmentWithOnlyTextAndIsNotChild(node) {
return node.children.length === 1
&& isJSXText(node.children[0])
&& !(node.parent.type === 'JSXElement' || node.parent.type === 'JSXFragment');
}
/**
* @param {string} text
* @returns {string}
*/
function trimLikeReact(text) {
const leadingSpaces = /^\s*/.exec(text)[0];
const trailingSpaces = /\s*$/.exec(text)[0];
const start = arrayIncludes(leadingSpaces, '\n') ? leadingSpaces.length : 0;
const end = arrayIncludes(trailingSpaces, '\n') ? text.length - trailingSpaces.length : text.length;
return text.slice(start, end);
}
/**
* Test if node is like `<Fragment key={_}>_</Fragment>`
* @param {JSXElement} node
* @returns {boolean}
*/
function isKeyedElement(node) {
return node.type === 'JSXElement'
&& node.openingElement.attributes
&& node.openingElement.attributes.some(jsxUtil.isJSXAttributeKey);
}
/**
* @param {ASTNode} node
* @returns {boolean}
*/
function containsCallExpression(node) {
return node
&& node.type === 'JSXExpressionContainer'
&& astUtil.isCallExpression(node.expression);
}
const messages = {
NeedsMoreChildren: 'Fragments should contain more than one child - otherwise, theres no need for a Fragment at all.',
ChildOfHtmlElement: 'Passing a fragment to an HTML element is useless.',
};
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'suggestion',
fixable: 'code',
docs: {
description: 'Disallow unnecessary fragments',
category: 'Possible Errors',
recommended: false,
url: docsUrl('jsx-no-useless-fragment'),
},
messages,
schema: [{
type: 'object',
properties: {
allowExpressions: {
type: 'boolean',
},
},
}],
},
create(context) {
const config = context.options[0] || {};
const allowExpressions = config.allowExpressions || false;
const reactPragma = pragmaUtil.getFromContext(context);
const fragmentPragma = pragmaUtil.getFragmentFromContext(context);
/**
* Test whether a node is an padding spaces trimmed by react runtime.
* @param {ASTNode} node
* @returns {boolean}
*/
function isPaddingSpaces(node) {
return isJSXText(node)
&& isOnlyWhitespace(node.raw)
&& arrayIncludes(node.raw, '\n');
}
function isFragmentWithSingleExpression(node) {
const children = node && node.children.filter((child) => !isPaddingSpaces(child));
return (
children
&& children.length === 1
&& children[0].type === 'JSXExpressionContainer'
);
}
/**
* Test whether a JSXElement has less than two children, excluding paddings spaces.
* @param {JSXElement|JSXFragment} node
* @returns {boolean}
*/
function hasLessThanTwoChildren(node) {
if (!node || !node.children) {
return true;
}
/** @type {ASTNode[]} */
const nonPaddingChildren = node.children.filter(
(child) => !isPaddingSpaces(child)
);
if (nonPaddingChildren.length < 2) {
return !containsCallExpression(nonPaddingChildren[0]);
}
}
/**
* @param {JSXElement|JSXFragment} node
* @returns {boolean}
*/
function isChildOfHtmlElement(node) {
return node.parent.type === 'JSXElement'
&& node.parent.openingElement.name.type === 'JSXIdentifier'
&& /^[a-z]+$/.test(node.parent.openingElement.name.name);
}
/**
* @param {JSXElement|JSXFragment} node
* @return {boolean}
*/
function isChildOfComponentElement(node) {
return node.parent.type === 'JSXElement'
&& !isChildOfHtmlElement(node)
&& !jsxUtil.isFragment(node.parent, reactPragma, fragmentPragma);
}
/**
* @param {ASTNode} node
* @returns {boolean}
*/
function canFix(node) {
// Not safe to fix fragments without a jsx parent.
if (!(node.parent.type === 'JSXElement' || node.parent.type === 'JSXFragment')) {
// const a = <></>
if (node.children.length === 0) {
return false;
}
// const a = <>cat {meow}</>
if (node.children.some(isNonspaceJSXTextOrJSXCurly)) {
return false;
}
}
// Not safe to fix `<Eeee><>foo</></Eeee>` because `Eeee` might require its children be a ReactElement.
if (isChildOfComponentElement(node)) {
return false;
}
// old TS parser can't handle this one
if (node.type === 'JSXFragment' && (!node.openingFragment || !node.closingFragment)) {
return false;
}
return true;
}
/**
* @param {ASTNode} node
* @returns {Function | undefined}
*/
function getFix(node) {
if (!canFix(node)) {
return undefined;
}
return function fix(fixer) {
const opener = node.type === 'JSXFragment' ? node.openingFragment : node.openingElement;
const closer = node.type === 'JSXFragment' ? node.closingFragment : node.closingElement;
const childrenText = opener.selfClosing ? '' : getText(context).slice(opener.range[1], closer.range[0]);
return fixer.replaceText(node, trimLikeReact(childrenText));
};
}
function checkNode(node) {
if (isKeyedElement(node)) {
return;
}
if (
hasLessThanTwoChildren(node)
&& !isFragmentWithOnlyTextAndIsNotChild(node)
&& !(allowExpressions && isFragmentWithSingleExpression(node))
) {
report(context, messages.NeedsMoreChildren, 'NeedsMoreChildren', {
node,
fix: getFix(node),
});
}
if (isChildOfHtmlElement(node)) {
report(context, messages.ChildOfHtmlElement, 'ChildOfHtmlElement', {
node,
fix: getFix(node),
});
}
}
return {
JSXElement(node) {
if (jsxUtil.isFragment(node, reactPragma, fragmentPragma)) {
checkNode(node);
}
},
JSXFragment: checkNode,
};
},
};