feat: 实现减脂体重管理App完整功能
- 实现拍照识别食物功能(集成大语言模型视觉能力) - 实现智能对话功能(集成大语言模型流式输出) - 实现食物记录和卡路里管理功能 - 实现体重记录和统计功能 - 实现健康数据管理页面 - 配置数据库表结构(用户、食物记录、体重记录) - 实现Express后端API路由 - 配置Tab导航和前端页面 - 采用健康运动配色方案
This commit is contained in:
9
eslint-plugins/fontawesome6/index.js
Normal file
9
eslint-plugins/fontawesome6/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const validName = require('./rule')
|
||||
|
||||
const plugin = {
|
||||
rules: {
|
||||
'valid-name': validName,
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = plugin
|
||||
1889
eslint-plugins/fontawesome6/names.js
Normal file
1889
eslint-plugins/fontawesome6/names.js
Normal file
File diff suppressed because it is too large
Load Diff
174
eslint-plugins/fontawesome6/rule.js
Normal file
174
eslint-plugins/fontawesome6/rule.js
Normal file
@@ -0,0 +1,174 @@
|
||||
const names = require('./names')
|
||||
const v5OnlyNames = require('./v5-only-names')
|
||||
const v5OnlyNamesSet = new Set(v5OnlyNames)
|
||||
|
||||
const DEFAULTS = {
|
||||
whitelist: names,
|
||||
componentName: 'FontAwesome6',
|
||||
attributeName: 'name',
|
||||
};
|
||||
|
||||
function getJSXAttribute(openingElement, attrName) {
|
||||
return openingElement.attributes.find(
|
||||
(attr) =>
|
||||
attr &&
|
||||
attr.type === 'JSXAttribute' &&
|
||||
attr.name &&
|
||||
attr.name.name === attrName
|
||||
);
|
||||
}
|
||||
|
||||
function getStringLiteralValue(attribute) {
|
||||
if (!attribute || !attribute.value) return null;
|
||||
|
||||
const val = attribute.value;
|
||||
|
||||
// <Comp name="hello" />
|
||||
if (val.type === 'Literal' && typeof val.value === 'string') {
|
||||
return val.value;
|
||||
}
|
||||
|
||||
// <Comp name={'hello'} />
|
||||
if (
|
||||
val.type === 'JSXExpressionContainer' &&
|
||||
val.expression &&
|
||||
val.expression.type === 'Literal' &&
|
||||
typeof val.expression.value === 'string'
|
||||
) {
|
||||
return val.expression.value;
|
||||
}
|
||||
|
||||
// <Comp name={`hello`} /> template literal without expressions
|
||||
if (
|
||||
val.type === 'JSXExpressionContainer' &&
|
||||
val.expression &&
|
||||
val.expression.type === 'TemplateLiteral' &&
|
||||
val.expression.expressions.length === 0
|
||||
) {
|
||||
return val.expression.quasis[0]?.value?.cooked ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const replacements = {
|
||||
'plus-circle': 'circle-plus',
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Ensure FontAwesome6 name prop is a string literal in whitelist',
|
||||
recommended: false,
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
whitelist: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
default: DEFAULTS.whitelist,
|
||||
},
|
||||
componentName: {
|
||||
type: 'string',
|
||||
default: DEFAULTS.componentName,
|
||||
},
|
||||
attributeName: {
|
||||
type: 'string',
|
||||
default: DEFAULTS.attributeName,
|
||||
},
|
||||
caseSensitive: {
|
||||
type: 'boolean',
|
||||
default: true
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
messages: {
|
||||
invalidName:
|
||||
'{{componentName}} 中不存在图标 {{name}},{{suggestion}}',
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = context.options && context.options[0] ? context.options[0] : {};
|
||||
const componentName = options.componentName || DEFAULTS.componentName;
|
||||
const attributeName = options.attributeName || DEFAULTS.attributeName;
|
||||
const caseSensitive = options.caseSensitive ?? true;
|
||||
|
||||
const whitelistRaw = Array.isArray(options.whitelist)
|
||||
? options.whitelist
|
||||
: DEFAULTS.whitelist;
|
||||
|
||||
const normalize = (s) =>
|
||||
caseSensitive ? String(s) : String(s).toLowerCase();
|
||||
|
||||
const whitelist = new Set(whitelistRaw.map(normalize));
|
||||
|
||||
function isTargetComponent(node) {
|
||||
// Supports: <FontAwesome6 />, <NS.FontAwesome6 />
|
||||
const nameNode = node.name;
|
||||
if (!nameNode) return false;
|
||||
|
||||
if (nameNode.type === 'JSXIdentifier') {
|
||||
return nameNode.name === componentName;
|
||||
}
|
||||
|
||||
if (nameNode.type === 'JSXMemberExpression') {
|
||||
// e.g., UI.FontAwesome6
|
||||
let base = nameNode;
|
||||
while (base.type === 'JSXMemberExpression') {
|
||||
if (base.property && base.property.name === componentName) {
|
||||
return true;
|
||||
}
|
||||
base = base.object;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement(opening) {
|
||||
if (!isTargetComponent(opening)) return;
|
||||
|
||||
const attrNode = getJSXAttribute(opening, attributeName);
|
||||
if (!attrNode) return;
|
||||
|
||||
const literal = getStringLiteralValue(attrNode);
|
||||
|
||||
// Only lint when it's a string literal
|
||||
if (literal == null) return;
|
||||
|
||||
const normalized = normalize(literal);
|
||||
if (!whitelist.has(normalized)) {
|
||||
context.report({
|
||||
node: attrNode.value || attrNode,
|
||||
messageId: 'invalidName',
|
||||
data: {
|
||||
componentName,
|
||||
name: literal,
|
||||
suggestion: getSuggestion(normalized, literal),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
function getSuggestion(name, originalName) {
|
||||
if (replacements[name]) {
|
||||
return `请更换为 ${replacements[name]}`
|
||||
}
|
||||
|
||||
if (v5OnlyNamesSet.has(name)) {
|
||||
return `${originalName} 只能和 FontAwesome5 组件一起使用`
|
||||
}
|
||||
|
||||
return '请更换为其他图标'
|
||||
}
|
||||
388
eslint-plugins/fontawesome6/v5-only-names.js
Normal file
388
eslint-plugins/fontawesome6/v5-only-names.js
Normal file
@@ -0,0 +1,388 @@
|
||||
const v5names = [
|
||||
"acquisitions-incorporated",
|
||||
"behance-square",
|
||||
"dribbble-square",
|
||||
"facebook-square",
|
||||
"font-awesome-alt",
|
||||
"font-awesome-flag",
|
||||
"font-awesome-logo-full",
|
||||
"git-square",
|
||||
"github-square",
|
||||
"google-plus-square",
|
||||
"hacker-news-square",
|
||||
"innosoft",
|
||||
"instagram-square",
|
||||
"js-square",
|
||||
"lastfm-square",
|
||||
"medium-m",
|
||||
"odnoklassniki-square",
|
||||
"penny-arcade",
|
||||
"pied-piper-square",
|
||||
"pinterest-square",
|
||||
"reddit-square",
|
||||
"slack-hash",
|
||||
"snapchat-ghost",
|
||||
"snapchat-square",
|
||||
"steam-square",
|
||||
"telegram-plane",
|
||||
"tripadvisor",
|
||||
"tumblr-square",
|
||||
"twitter-square",
|
||||
"viadeo-square",
|
||||
"vimeo-square",
|
||||
"whatsapp-square",
|
||||
"xing-square",
|
||||
"youtube-square",
|
||||
"angry",
|
||||
"arrow-alt-circle-down",
|
||||
"arrow-alt-circle-left",
|
||||
"arrow-alt-circle-right",
|
||||
"arrow-alt-circle-up",
|
||||
"calendar-alt",
|
||||
"calendar-times",
|
||||
"caret-square-down",
|
||||
"caret-square-left",
|
||||
"caret-square-right",
|
||||
"caret-square-up",
|
||||
"check-circle",
|
||||
"check-square",
|
||||
"comment-alt",
|
||||
"dizzy",
|
||||
"dot-circle",
|
||||
"edit",
|
||||
"file-alt",
|
||||
"file-archive",
|
||||
"flushed",
|
||||
"frown-open",
|
||||
"frown",
|
||||
"grimace",
|
||||
"grin-alt",
|
||||
"grin-beam-sweat",
|
||||
"grin-beam",
|
||||
"grin-hearts",
|
||||
"grin-squint-tears",
|
||||
"grin-squint",
|
||||
"grin-stars",
|
||||
"grin-tears",
|
||||
"grin-tongue-squint",
|
||||
"grin-tongue-wink",
|
||||
"grin-tongue",
|
||||
"grin-wink",
|
||||
"grin",
|
||||
"hand-paper",
|
||||
"hand-rock",
|
||||
"hdd",
|
||||
"kiss-beam",
|
||||
"kiss-wink-heart",
|
||||
"kiss",
|
||||
"laugh-beam",
|
||||
"laugh-squint",
|
||||
"laugh-wink",
|
||||
"laugh",
|
||||
"list-alt",
|
||||
"meh-blank",
|
||||
"meh-rolling-eyes",
|
||||
"meh",
|
||||
"minus-square",
|
||||
"money-bill-alt",
|
||||
"pause-circle",
|
||||
"play-circle",
|
||||
"plus-square",
|
||||
"question-circle",
|
||||
"sad-cry",
|
||||
"sad-tear",
|
||||
"save",
|
||||
"share-square",
|
||||
"smile-beam",
|
||||
"smile-wink",
|
||||
"smile",
|
||||
"sticky-note",
|
||||
"stop-circle",
|
||||
"surprise",
|
||||
"times-circle",
|
||||
"tired",
|
||||
"trash-alt",
|
||||
"user-circle",
|
||||
"window-close",
|
||||
"ad",
|
||||
"adjust",
|
||||
"air-freshener",
|
||||
"allergies",
|
||||
"ambulance",
|
||||
"american-sign-language-interpreting",
|
||||
"angle-double-down",
|
||||
"angle-double-left",
|
||||
"angle-double-right",
|
||||
"angle-double-up",
|
||||
"apple-alt",
|
||||
"archive",
|
||||
"arrow-circle-down",
|
||||
"arrow-circle-left",
|
||||
"arrow-circle-right",
|
||||
"arrow-circle-up",
|
||||
"arrows-alt-h",
|
||||
"arrows-alt-v",
|
||||
"arrows-alt",
|
||||
"assistive-listening-systems",
|
||||
"atlas",
|
||||
"backspace",
|
||||
"balance-scale-left",
|
||||
"balance-scale-right",
|
||||
"balance-scale",
|
||||
"band-aid",
|
||||
"baseball-ball",
|
||||
"basketball-ball",
|
||||
"beer",
|
||||
"bible",
|
||||
"biking",
|
||||
"birthday-cake",
|
||||
"blind",
|
||||
"book-dead",
|
||||
"book-reader",
|
||||
"border-style",
|
||||
"boxes",
|
||||
"broadcast-tower",
|
||||
"burn",
|
||||
"bus-alt",
|
||||
"car-alt",
|
||||
"car-crash",
|
||||
"chalkboard-teacher",
|
||||
"chevron-circle-down",
|
||||
"chevron-circle-left",
|
||||
"chevron-circle-right",
|
||||
"chevron-circle-up",
|
||||
"clinic-medical",
|
||||
"cloud-download-alt",
|
||||
"cloud-upload-alt",
|
||||
"cocktail",
|
||||
"coffee",
|
||||
"cog",
|
||||
"cogs",
|
||||
"columns",
|
||||
"compress-alt",
|
||||
"compress-arrows-alt",
|
||||
"concierge-bell",
|
||||
"crop-alt",
|
||||
"cut",
|
||||
"deaf",
|
||||
"diagnoses",
|
||||
"digital-tachograph",
|
||||
"directions",
|
||||
"dolly-flatbed",
|
||||
"donate",
|
||||
"drafting-compass",
|
||||
"ellipsis-h",
|
||||
"ellipsis-v",
|
||||
"envelope-square",
|
||||
"exchange-alt",
|
||||
"exclamation-circle",
|
||||
"exclamation-triangle",
|
||||
"expand-alt",
|
||||
"expand-arrows-alt",
|
||||
"external-link-alt",
|
||||
"external-link-square-alt",
|
||||
"fast-backward",
|
||||
"fast-forward",
|
||||
"feather-alt",
|
||||
"female",
|
||||
"fighter-jet",
|
||||
"file-download",
|
||||
"file-medical-alt",
|
||||
"file-upload",
|
||||
"fire-alt",
|
||||
"first-aid",
|
||||
"fist-raised",
|
||||
"football-ball",
|
||||
"funnel-dollar",
|
||||
"glass-cheers",
|
||||
"glass-martini-alt",
|
||||
"glass-martini",
|
||||
"glass-whiskey",
|
||||
"globe-africa",
|
||||
"globe-americas",
|
||||
"globe-asia",
|
||||
"globe-europe",
|
||||
"golf-ball",
|
||||
"grip-horizontal",
|
||||
"h-square",
|
||||
"hamburger",
|
||||
"hand-holding-usd",
|
||||
"hand-holding-water",
|
||||
"hands-helping",
|
||||
"hands-wash",
|
||||
"handshake-alt-slash",
|
||||
"hard-hat",
|
||||
"headphones-alt",
|
||||
"heart-broken",
|
||||
"heartbeat",
|
||||
"hiking",
|
||||
"history",
|
||||
"home",
|
||||
"hospital-alt",
|
||||
"hospital-symbol",
|
||||
"hot-tub",
|
||||
"house-damage",
|
||||
"hryvnia",
|
||||
"id-card-alt",
|
||||
"info-circle",
|
||||
"journal-whills",
|
||||
"laptop-house",
|
||||
"level-down-alt",
|
||||
"level-up-alt",
|
||||
"long-arrow-alt-down",
|
||||
"long-arrow-alt-left",
|
||||
"long-arrow-alt-right",
|
||||
"long-arrow-alt-up",
|
||||
"low-vision",
|
||||
"luggage-cart",
|
||||
"magic",
|
||||
"mail-bulk",
|
||||
"male",
|
||||
"map-marked-alt",
|
||||
"map-marked",
|
||||
"map-marker-alt",
|
||||
"map-marker",
|
||||
"map-signs",
|
||||
"mars-stroke-h",
|
||||
"mars-stroke-v",
|
||||
"medkit",
|
||||
"microphone-alt-slash",
|
||||
"microphone-alt",
|
||||
"minus-circle",
|
||||
"mobile-alt",
|
||||
"money-bill-wave-alt",
|
||||
"money-check-alt",
|
||||
"mouse-pointer",
|
||||
"mouse",
|
||||
"paint-brush",
|
||||
"parking",
|
||||
"pastafarianism",
|
||||
"pen-alt",
|
||||
"pen-square",
|
||||
"pencil-alt",
|
||||
"pencil-ruler",
|
||||
"people-carry",
|
||||
"percentage",
|
||||
"phone-alt",
|
||||
"phone-square-alt",
|
||||
"phone-square",
|
||||
"photo-video",
|
||||
"plus-circle",
|
||||
"poll-h",
|
||||
"poll",
|
||||
"portrait",
|
||||
"pound-sign",
|
||||
"pray",
|
||||
"praying-hands",
|
||||
"prescription-bottle-alt",
|
||||
"procedures",
|
||||
"project-diagram",
|
||||
"quidditch",
|
||||
"quran",
|
||||
"radiation-alt",
|
||||
"random",
|
||||
"redo-alt",
|
||||
"redo",
|
||||
"remove-format",
|
||||
"rss-square",
|
||||
"running",
|
||||
"search-dollar",
|
||||
"search-location",
|
||||
"search-minus",
|
||||
"search-plus",
|
||||
"search",
|
||||
"share-alt-square",
|
||||
"share-alt",
|
||||
"shield-alt",
|
||||
"shipping-fast",
|
||||
"shopping-bag",
|
||||
"shopping-basket",
|
||||
"shopping-cart",
|
||||
"shuttle-van",
|
||||
"sign-in-alt",
|
||||
"sign-language",
|
||||
"sign-out-alt",
|
||||
"sign",
|
||||
"skating",
|
||||
"skiing-nordic",
|
||||
"skiing",
|
||||
"sliders-h",
|
||||
"smoking-ban",
|
||||
"sms",
|
||||
"snowboarding",
|
||||
"sort-alpha-down-alt",
|
||||
"sort-alpha-down",
|
||||
"sort-alpha-up-alt",
|
||||
"sort-alpha-up",
|
||||
"sort-amount-down-alt",
|
||||
"sort-amount-down",
|
||||
"sort-amount-up-alt",
|
||||
"sort-amount-up",
|
||||
"sort-numeric-down-alt",
|
||||
"sort-numeric-down",
|
||||
"sort-numeric-up-alt",
|
||||
"sort-numeric-up",
|
||||
"space-shuttle",
|
||||
"square-root-alt",
|
||||
"star-half-alt",
|
||||
"step-backward",
|
||||
"step-forward",
|
||||
"store-alt-slash",
|
||||
"store-alt",
|
||||
"stream",
|
||||
"subway",
|
||||
"swimmer",
|
||||
"swimming-pool",
|
||||
"sync-alt",
|
||||
"sync",
|
||||
"table-tennis",
|
||||
"tablet-alt",
|
||||
"tachometer-alt",
|
||||
"tasks",
|
||||
"tenge",
|
||||
"th-large",
|
||||
"th-list",
|
||||
"th",
|
||||
"theater-masks",
|
||||
"thermometer-empty",
|
||||
"thermometer-full",
|
||||
"thermometer-half",
|
||||
"thermometer-quarter",
|
||||
"thermometer-three-quarters",
|
||||
"ticket-alt",
|
||||
"times",
|
||||
"tint-slash",
|
||||
"tint",
|
||||
"tools",
|
||||
"torah",
|
||||
"tram",
|
||||
"transgender-alt",
|
||||
"trash-restore-alt",
|
||||
"trash-restore",
|
||||
"truck-loading",
|
||||
"tshirt",
|
||||
"undo-alt",
|
||||
"undo",
|
||||
"university",
|
||||
"unlink",
|
||||
"unlock-alt",
|
||||
"user-alt-slash",
|
||||
"user-alt",
|
||||
"user-cog",
|
||||
"user-edit",
|
||||
"user-friends",
|
||||
"user-md",
|
||||
"user-times",
|
||||
"users-cog",
|
||||
"utensil-spoon",
|
||||
"volleyball-ball",
|
||||
"volume-down",
|
||||
"volume-mute",
|
||||
"volume-up",
|
||||
"vote-yea",
|
||||
"walking",
|
||||
"weight",
|
||||
"wine-glass-alt"
|
||||
]
|
||||
|
||||
module.exports = v5names
|
||||
Reference in New Issue
Block a user