@lism-css/mcp 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/docs-index.json +160 -71
- package/dist/data/guides/SKILL.md +80 -110
- package/dist/data/guides/antipatterns-layout.md +19 -23
- package/dist/data/guides/antipatterns.md +6 -5
- package/dist/data/guides/base-styles.md +1 -1
- package/dist/data/guides/components-core.md +8 -7
- package/dist/data/guides/components-ui.md +74 -6
- package/dist/data/guides/css-rules.md +9 -17
- package/dist/data/guides/customize.md +11 -26
- package/dist/data/guides/naming.md +11 -23
- package/dist/data/guides/property-class/all-props.md +5 -5
- package/dist/data/guides/property-class/bd.md +3 -0
- package/dist/data/guides/property-class/hov.md +1 -0
- package/dist/data/guides/property-class.md +1 -1
- package/dist/data/guides/references/authoring.md +32 -44
- package/dist/data/guides/references/page-sections.md +1 -1
- package/dist/data/guides/references/verification.md +4 -4
- package/dist/data/guides/responsive.md +4 -24
- package/dist/data/guides/set-class.md +2 -2
- package/dist/data/guides/tokens.md +48 -24
- package/dist/data/guides/trait-class/has--transition.md +17 -2
- package/dist/data/guides/trait-class.md +2 -13
- package/dist/data/guides/utility-class.md +1 -9
- package/dist/data/meta.js +2 -2
- package/dist/lib/markdown-utils.d.ts +3 -22
- package/dist/lib/markdown-utils.js +7 -30
- package/dist/lib/search.d.ts +1 -4
- package/dist/lib/search.js +6 -34
- package/dist/tools/convert-css.js +8 -25
- package/package.json +1 -1
|
@@ -1,38 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Markdown から指定した見出しのセクションを抽出する。
|
|
3
|
-
* 同レベル以上の次の見出しが来るまでの内容を返す。
|
|
4
|
-
* @param md - Markdown 全文
|
|
5
|
-
* @param heading - 見出しテキスト(`#` プレフィックスあり・なし両可)
|
|
6
|
-
*/
|
|
1
|
+
/** 指定見出しから同レベル以上の次の見出しまでを抽出する。headingは#の有無を問わない。 */
|
|
7
2
|
export declare function extractSection(md: string, heading: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Markdown から全ての見出しとその開始行を抽出する。
|
|
10
|
-
*/
|
|
11
3
|
export declare function listHeadings(md: string): {
|
|
12
4
|
level: number;
|
|
13
5
|
text: string;
|
|
14
6
|
line: number;
|
|
15
7
|
}[];
|
|
16
8
|
export interface PropRow {
|
|
17
|
-
/** Lism Prop 名(例: "fz") */
|
|
18
9
|
prop: string;
|
|
19
|
-
/** CSS プロパティ名(例: "font-size")。変数形式("--hl")も含む */
|
|
20
10
|
cssProperty: string;
|
|
21
|
-
/** 所属する ### セクション名 */
|
|
22
11
|
sectionName: string;
|
|
23
|
-
/** プリセット値クラス列の生テキスト(例: "-fz:base, -fz:5xl, ...") */
|
|
24
12
|
presetColumn: string;
|
|
25
13
|
}
|
|
26
|
-
/**
|
|
27
|
-
* property-class.md のテーブルを全て解析して PropRow[] を返す。
|
|
28
|
-
* `| Prop | CSS プロパティ | ...` 形式のテーブルのみ対象とする。
|
|
29
|
-
*/
|
|
14
|
+
/** Property Classの対象テーブルを解析してPropRowへ変換する。 */
|
|
30
15
|
export declare function parsePropRows(md: string): PropRow[];
|
|
31
|
-
/**
|
|
32
|
-
* Markdown からコンポーネント名に一致するセクションを探して返す。
|
|
33
|
-
*
|
|
34
|
-
* components-ui.md のように各コンポーネントが `## ComponentName` で始まる場合に有効。
|
|
35
|
-
*/
|
|
16
|
+
/** 各コンポーネントが`## ComponentName`で始まる文書向け。 */
|
|
36
17
|
export declare function findComponentByHeading(md: string, name: string): string;
|
|
37
18
|
/**
|
|
38
19
|
* Markdown 内のテーブルセル(`` `<ComponentName>` ``)からコンポーネントを含む
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
/** 見出しの `#` レベルを返す(見出しでなければ 0) */
|
|
2
1
|
function headingLevel(line) {
|
|
3
2
|
const m = line.match(/^(#{1,6})\s/);
|
|
4
3
|
return m ? m[1].length : 0;
|
|
5
4
|
}
|
|
6
|
-
/**
|
|
7
|
-
* Markdown から指定した見出しのセクションを抽出する。
|
|
8
|
-
* 同レベル以上の次の見出しが来るまでの内容を返す。
|
|
9
|
-
* @param md - Markdown 全文
|
|
10
|
-
* @param heading - 見出しテキスト(`#` プレフィックスあり・なし両可)
|
|
11
|
-
*/
|
|
5
|
+
/** 指定見出しから同レベル以上の次の見出しまでを抽出する。headingは#の有無を問わない。 */
|
|
12
6
|
export function extractSection(md, heading) {
|
|
13
7
|
const headingText = heading.replace(/^#+\s*/, '').trim();
|
|
14
8
|
const lines = md.split('\n');
|
|
@@ -34,9 +28,6 @@ export function extractSection(md, heading) {
|
|
|
34
28
|
}
|
|
35
29
|
return lines.slice(startIdx, endIdx).join('\n').trimEnd();
|
|
36
30
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Markdown から全ての見出しとその開始行を抽出する。
|
|
39
|
-
*/
|
|
40
31
|
export function listHeadings(md) {
|
|
41
32
|
return md.split('\n').flatMap((line, i) => {
|
|
42
33
|
const lv = headingLevel(line);
|
|
@@ -45,38 +36,32 @@ export function listHeadings(md) {
|
|
|
45
36
|
return [{ level: lv, text: line.replace(/^#+\s*/, '').trim(), line: i }];
|
|
46
37
|
});
|
|
47
38
|
}
|
|
48
|
-
/**
|
|
49
|
-
* property-class.md のテーブルを全て解析して PropRow[] を返す。
|
|
50
|
-
* `| Prop | CSS プロパティ | ...` 形式のテーブルのみ対象とする。
|
|
51
|
-
*/
|
|
39
|
+
/** Property Classの対象テーブルを解析してPropRowへ変換する。 */
|
|
52
40
|
export function parsePropRows(md) {
|
|
53
41
|
const lines = md.split('\n');
|
|
54
42
|
const rows = [];
|
|
55
43
|
let currentSection = '';
|
|
56
44
|
let inPropTable = false;
|
|
45
|
+
// 見出しと対象テーブルの範囲を追跡する。
|
|
57
46
|
for (const line of lines) {
|
|
58
47
|
const lv = headingLevel(line);
|
|
59
|
-
// セクション見出しを追跡(### レベル)
|
|
60
48
|
if (lv >= 2) {
|
|
61
49
|
currentSection = line.replace(/^#+\s*/, '').trim();
|
|
62
50
|
inPropTable = false;
|
|
63
51
|
continue;
|
|
64
52
|
}
|
|
65
|
-
// Property Class テーブルのヘッダー行を検出
|
|
66
53
|
if (line.includes('Prop') && line.includes('CSS プロパティ')) {
|
|
67
54
|
inPropTable = true;
|
|
68
55
|
continue;
|
|
69
56
|
}
|
|
70
|
-
// 区切り行はスキップ
|
|
71
57
|
if (inPropTable && /^\|[-\s|:]+\|/.test(line)) {
|
|
72
58
|
continue;
|
|
73
59
|
}
|
|
74
|
-
// テーブルの終了を検出
|
|
75
60
|
if (inPropTable && !line.startsWith('|')) {
|
|
76
61
|
inPropTable = false;
|
|
77
62
|
continue;
|
|
78
63
|
}
|
|
79
|
-
//
|
|
64
|
+
// 対象テーブルの各行をPropRowへ変換する。
|
|
80
65
|
if (inPropTable && line.startsWith('|')) {
|
|
81
66
|
const cells = line
|
|
82
67
|
.split('|')
|
|
@@ -84,9 +69,7 @@ export function parsePropRows(md) {
|
|
|
84
69
|
.filter(Boolean);
|
|
85
70
|
if (cells.length >= 2) {
|
|
86
71
|
const prop = cells[0].replace(/`/g, '').trim();
|
|
87
|
-
// CSS プロパティ: バッククォート除去、括弧内の注釈は保持しない
|
|
88
72
|
const cssPropertyRaw = cells[1].replace(/`/g, '').trim();
|
|
89
|
-
// `line-height`(`--hl` 経由) のような括弧注釈を除去
|
|
90
73
|
const cssProperty = cssPropertyRaw
|
|
91
74
|
.replace(/([^)]*)$/, '')
|
|
92
75
|
.replace(/\([^)]*\)$/, '')
|
|
@@ -103,11 +86,7 @@ export function parsePropRows(md) {
|
|
|
103
86
|
// ----------------------------------------------------------------
|
|
104
87
|
// コンポーネント検索
|
|
105
88
|
// ----------------------------------------------------------------
|
|
106
|
-
/**
|
|
107
|
-
* Markdown からコンポーネント名に一致するセクションを探して返す。
|
|
108
|
-
*
|
|
109
|
-
* components-ui.md のように各コンポーネントが `## ComponentName` で始まる場合に有効。
|
|
110
|
-
*/
|
|
89
|
+
/** 各コンポーネントが`## ComponentName`で始まる文書向け。 */
|
|
111
90
|
export function findComponentByHeading(md, name) {
|
|
112
91
|
return extractSection(md, name);
|
|
113
92
|
}
|
|
@@ -119,10 +98,9 @@ export function findComponentByHeading(md, name) {
|
|
|
119
98
|
export function findComponentInTables(md, name) {
|
|
120
99
|
const nameLower = name.toLowerCase();
|
|
121
100
|
const lines = md.split('\n');
|
|
122
|
-
// コンポーネント名のパターン: `<Flex>`, `<flex>`, または単純に "flex" がテーブル行に含まれるか
|
|
123
101
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
124
102
|
const pattern = new RegExp(`\`?<${escaped}>?\`?`, 'i');
|
|
125
|
-
//
|
|
103
|
+
// コンポーネントを含むテーブル行を探す。
|
|
126
104
|
let targetLineIdx = -1;
|
|
127
105
|
for (let i = 0; i < lines.length; i++) {
|
|
128
106
|
if (lines[i].startsWith('|') && (pattern.test(lines[i]) || lines[i].toLowerCase().includes(`\`${nameLower}\``))) {
|
|
@@ -132,7 +110,7 @@ export function findComponentInTables(md, name) {
|
|
|
132
110
|
}
|
|
133
111
|
if (targetLineIdx === -1)
|
|
134
112
|
return '';
|
|
135
|
-
//
|
|
113
|
+
// 対象行を含む##節の範囲を決める。
|
|
136
114
|
let sectionStart = -1;
|
|
137
115
|
let sectionLevel = 0;
|
|
138
116
|
for (let i = targetLineIdx; i >= 0; i--) {
|
|
@@ -145,7 +123,6 @@ export function findComponentInTables(md, name) {
|
|
|
145
123
|
}
|
|
146
124
|
if (sectionStart === -1)
|
|
147
125
|
return lines.slice(0, targetLineIdx + 20).join('\n');
|
|
148
|
-
// セクションの終端を探す
|
|
149
126
|
let sectionEnd = lines.length;
|
|
150
127
|
for (let i = sectionStart + 1; i < lines.length; i++) {
|
|
151
128
|
const lv = headingLevel(lines[i]);
|
package/dist/lib/search.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { DocsEntry, SearchResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Property Class 記法(例: "-g:5", ".-p:20", "-fz")から prop 名を抽出する。
|
|
4
|
-
* get-props-system.ts からも利用される共通ユーティリティ。
|
|
5
|
-
*/
|
|
2
|
+
/** Property Class記法からprop名を取り出す。get-props-system.tsからも利用する。 */
|
|
6
3
|
export declare function parsePropClassName(input: string): string | null;
|
|
7
4
|
export interface SearchDocsOptions {
|
|
8
5
|
category?: string;
|
package/dist/lib/search.js
CHANGED
|
@@ -4,32 +4,22 @@ function tokenize(text) {
|
|
|
4
4
|
.split(/[\s\-_./]+/)
|
|
5
5
|
.filter((t) => t.length > 0);
|
|
6
6
|
}
|
|
7
|
-
// ".-g:5" or "-g:5" → prop="g", value="5" / "-p" → prop="p"
|
|
8
7
|
const PROP_CLASS_RE = /^\.?-([a-z][a-z0-9-]*)(:.+)?$/i;
|
|
9
|
-
/**
|
|
10
|
-
* Property Class 記法(例: "-g:5", ".-p:20", "-fz")から prop 名を抽出する。
|
|
11
|
-
* get-props-system.ts からも利用される共通ユーティリティ。
|
|
12
|
-
*/
|
|
8
|
+
/** Property Class記法からprop名を取り出す。get-props-system.tsからも利用する。 */
|
|
13
9
|
export function parsePropClassName(input) {
|
|
14
10
|
const m = input.match(PROP_CLASS_RE);
|
|
15
11
|
return m ? m[1].toLowerCase() : null;
|
|
16
12
|
}
|
|
17
|
-
/**
|
|
18
|
-
* 検索クエリをCSSプロパティ名やProperty Class記法で展開する。
|
|
19
|
-
* 例: "font-size" → "font-size fz"
|
|
20
|
-
* 例: "-g:5" → "-g:5 g gap property class"
|
|
21
|
-
*/
|
|
13
|
+
/** CSSプロパティとProperty Classを相互展開して検索語を補う。 */
|
|
22
14
|
function expandQuery(query, cssPropertyMap) {
|
|
23
15
|
const additions = [];
|
|
24
16
|
const queryLower = query.toLowerCase();
|
|
25
17
|
const parsedProp = parsePropClassName(queryLower.trim());
|
|
26
18
|
if (cssPropertyMap) {
|
|
27
19
|
for (const [cssProp, lismProps] of cssPropertyMap) {
|
|
28
|
-
// Property Class 記法の逆引き(例: "-g:5" の "g" → "gap")
|
|
29
20
|
if (parsedProp && lismProps.includes(parsedProp)) {
|
|
30
21
|
additions.push(cssProp);
|
|
31
22
|
}
|
|
32
|
-
// CSSプロパティ名の展開(例: "font-size" → "fz")
|
|
33
23
|
if (queryLower.includes(cssProp)) {
|
|
34
24
|
additions.push(...lismProps);
|
|
35
25
|
}
|
|
@@ -47,20 +37,16 @@ function scoreEntry(entry, queryTokens) {
|
|
|
47
37
|
const headingsLower = entry.headings.join(' ').toLowerCase();
|
|
48
38
|
const keywordsLower = entry.keywords.join(' ').toLowerCase();
|
|
49
39
|
const snippetLower = entry.snippet.toLowerCase();
|
|
40
|
+
// titleからsnippetへ順に重みを下げる。
|
|
50
41
|
for (const token of queryTokens) {
|
|
51
|
-
// title matches are weighted highest
|
|
52
42
|
if (titleLower.includes(token))
|
|
53
43
|
score += 10;
|
|
54
|
-
// keywords
|
|
55
44
|
if (keywordsLower.includes(token))
|
|
56
45
|
score += 5;
|
|
57
|
-
// headings
|
|
58
46
|
if (headingsLower.includes(token))
|
|
59
47
|
score += 3;
|
|
60
|
-
// description
|
|
61
48
|
if (descLower.includes(token))
|
|
62
49
|
score += 2;
|
|
63
|
-
// snippet
|
|
64
50
|
if (snippetLower.includes(token))
|
|
65
51
|
score += 1;
|
|
66
52
|
}
|
|
@@ -68,7 +54,7 @@ function scoreEntry(entry, queryTokens) {
|
|
|
68
54
|
}
|
|
69
55
|
export function searchDocs(entries, query, options) {
|
|
70
56
|
const { category, limit = 10, cssPropertyMap, guideTopics } = options ?? {};
|
|
71
|
-
// CSS
|
|
57
|
+
// CSSプロパティ名とProperty Class記法も同じ検索対象へ展開する。
|
|
72
58
|
const expandedQuery = expandQuery(query, cssPropertyMap);
|
|
73
59
|
const queryTokens = tokenize(expandedQuery);
|
|
74
60
|
if (queryTokens.length === 0)
|
|
@@ -103,19 +89,14 @@ const SITE_BASE_URL = 'https://lism-css.com';
|
|
|
103
89
|
function slugToPageUrl(slug) {
|
|
104
90
|
return slug.startsWith('ui/') ? `${SITE_BASE_URL}/${slug}/` : `${SITE_BASE_URL}/docs/${slug}/`;
|
|
105
91
|
}
|
|
106
|
-
/** `sourcePath`(拡張子なし)の末尾セグメントを返す(例: `primitives/l--flex` → `l--flex`) */
|
|
107
92
|
function getBasename(withoutExt) {
|
|
108
93
|
const parts = withoutExt.split('/');
|
|
109
94
|
return parts[parts.length - 1];
|
|
110
95
|
}
|
|
111
|
-
/**
|
|
112
|
-
* 検索結果のページを詳しく見るための推奨フォローアップツール呼び出しを返す。
|
|
113
|
-
* sourcePath による判定をカテゴリによる判定より優先する。
|
|
114
|
-
*/
|
|
96
|
+
/** 検索結果を掘り下げる推奨ツールを返す。カテゴリよりsourcePathの規則を優先する。 */
|
|
115
97
|
function getNextTool(entry, guideTopics) {
|
|
116
98
|
const withoutExt = entry.sourcePath.replace(/\.mdx$/, '');
|
|
117
99
|
const basename = getBasename(withoutExt);
|
|
118
|
-
// sourcePath ベースの判定(category より優先)
|
|
119
100
|
if (withoutExt === 'core-components/lism-props') {
|
|
120
101
|
return 'get_props_system()';
|
|
121
102
|
}
|
|
@@ -128,13 +109,10 @@ function getNextTool(entry, guideTopics) {
|
|
|
128
109
|
if (withoutExt.startsWith('property-class/')) {
|
|
129
110
|
return `get_props_system(prop: "${basename}")`;
|
|
130
111
|
}
|
|
131
|
-
//
|
|
132
|
-
// パッケージが提供するコンポーネントではなく Lism CSS での実装例ページなので get_component では解決できない。
|
|
133
|
-
// 詳細が必要な場合は検索結果の url を参照してもらう。
|
|
112
|
+
// 実装例ページはパッケージ提供コンポーネントではないためget_componentでは解決できない。
|
|
134
113
|
if (withoutExt.startsWith('ui/block-examples/') || withoutExt.startsWith('ui/components/')) {
|
|
135
114
|
return null;
|
|
136
115
|
}
|
|
137
|
-
// category ベースの判定
|
|
138
116
|
switch (entry.category) {
|
|
139
117
|
case 'core-components':
|
|
140
118
|
return `get_component(name: "${basename}")`;
|
|
@@ -156,12 +134,6 @@ function getNextTool(entry, guideTopics) {
|
|
|
156
134
|
* IMPORTANT: `apps/docs/src/lib/contentSlug.ts` の `toContentSlug` と必ず同じロジックに保つこと。
|
|
157
135
|
* 別ワークスペース(apps/docs)なので直接 import できず、ローカル実装で複製している。
|
|
158
136
|
* apps/docs 側を変更した場合は必ずここも合わせて更新する。
|
|
159
|
-
*
|
|
160
|
-
* 例:
|
|
161
|
-
* `primitives/l--tileGrid.mdx` → `primitives/l--tileGrid`
|
|
162
|
-
* `trait-class/is--boxLink.mdx` → `trait-class/is--boxLink`
|
|
163
|
-
* `core-components/Group.mdx` → `core-components/group`
|
|
164
|
-
* `ui/DummyText.mdx` → `ui/dummytext`
|
|
165
137
|
*/
|
|
166
138
|
const PRESERVE_CASE_PREFIXES = ['primitives/', 'trait-class/'];
|
|
167
139
|
export function sourcePathToUrlSlug(sourcePath) {
|
|
@@ -3,7 +3,6 @@ import { loadPropsMarkdown } from '../lib/load-markdown.js';
|
|
|
3
3
|
import { parsePropRows } from '../lib/markdown-utils.js';
|
|
4
4
|
import { MetaInfoSchema } from '../lib/schemas.js';
|
|
5
5
|
import { success, error, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
|
|
6
|
-
/** 変換結果の1行 */
|
|
7
6
|
const ConversionEntrySchema = z.object({
|
|
8
7
|
css: z.string(),
|
|
9
8
|
lismProp: z.string().nullable(),
|
|
@@ -12,7 +11,6 @@ const ConversionEntrySchema = z.object({
|
|
|
12
11
|
confidence: z.enum(['exact', 'approximate', 'unmapped']),
|
|
13
12
|
note: z.string(),
|
|
14
13
|
});
|
|
15
|
-
/** コンポーネント提案 */
|
|
16
14
|
const ComponentSuggestionSchema = z.object({
|
|
17
15
|
name: z.string(),
|
|
18
16
|
reason: z.string(),
|
|
@@ -21,7 +19,6 @@ const ComponentSuggestionSchema = z.object({
|
|
|
21
19
|
// ----------------------------------------------------------------
|
|
22
20
|
// CSS パース
|
|
23
21
|
// ----------------------------------------------------------------
|
|
24
|
-
/** @ルール(@media 等)が含まれていないか検査する */
|
|
25
22
|
function detectAtRules(cssText) {
|
|
26
23
|
const atRuleMatch = cssText.match(/^@(\w[\w-]*)/m);
|
|
27
24
|
if (atRuleMatch) {
|
|
@@ -29,16 +26,12 @@ function detectAtRules(cssText) {
|
|
|
29
26
|
}
|
|
30
27
|
return null;
|
|
31
28
|
}
|
|
32
|
-
/**
|
|
33
|
-
* CSS テキストから宣言を抽出する。
|
|
34
|
-
* `;` で分割する際に `url()` 等の括弧内の `;` を無視する。
|
|
35
|
-
*/
|
|
29
|
+
/** CSSテキストから宣言を抽出する。url()などの括弧内にある`;`は区切りとみなさない。 */
|
|
36
30
|
function parseCssDeclarations(cssText) {
|
|
37
|
-
//
|
|
31
|
+
// コメントとセレクタの外枠を取り除く。
|
|
38
32
|
let cleaned = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
39
|
-
// セレクタ + ブレースを除去(裸の宣言リストも受け付ける)
|
|
40
33
|
cleaned = cleaned.replace(/[^{}]*\{/g, '').replace(/\}/g, '');
|
|
41
|
-
//
|
|
34
|
+
// 括弧の深さを追いながら宣言単位に分ける。
|
|
42
35
|
const segments = [];
|
|
43
36
|
let current = '';
|
|
44
37
|
let parenDepth = 0;
|
|
@@ -72,12 +65,10 @@ function parseCssDeclarations(cssText) {
|
|
|
72
65
|
}
|
|
73
66
|
return declarations;
|
|
74
67
|
}
|
|
75
|
-
/** プリセット値列から値を抽出する(例: "-fz:base, -fz:5xl" → ["base", "5xl"]) */
|
|
76
68
|
function extractPresetValues(presetColumn, propName) {
|
|
77
69
|
if (!presetColumn || presetColumn === '—' || presetColumn === '-')
|
|
78
70
|
return [];
|
|
79
71
|
const values = [];
|
|
80
|
-
// -{prop}:{value} パターンを全て抽出
|
|
81
72
|
const escaped = propName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
82
73
|
const regex = new RegExp(`-${escaped}:([^,\\s\`〜]+)`, 'g');
|
|
83
74
|
let match;
|
|
@@ -98,7 +89,6 @@ function buildCssPropertyMap(mappings) {
|
|
|
98
89
|
const map = new Map();
|
|
99
90
|
for (const mapping of mappings) {
|
|
100
91
|
const normalized = mapping.cssProperty.toLowerCase();
|
|
101
|
-
// CSS カスタムプロパティ形式はスキップ("--hl" 等)
|
|
102
92
|
if (!normalized.startsWith('(class:')) {
|
|
103
93
|
map.set(normalized, mapping);
|
|
104
94
|
}
|
|
@@ -108,7 +98,6 @@ function buildCssPropertyMap(mappings) {
|
|
|
108
98
|
// ----------------------------------------------------------------
|
|
109
99
|
// 値のマッピング
|
|
110
100
|
// ----------------------------------------------------------------
|
|
111
|
-
/** よくある CSS 値 → Lism トークン値の変換テーブル */
|
|
112
101
|
const VALUE_ALIASES = {
|
|
113
102
|
'space-between': 'between',
|
|
114
103
|
currentcolor: 'current',
|
|
@@ -119,10 +108,8 @@ function suggestValue(mapping, cssValue) {
|
|
|
119
108
|
const tokens = mapping.presetValues;
|
|
120
109
|
if (tokens.length === 0)
|
|
121
110
|
return null;
|
|
122
|
-
// 直接一致
|
|
123
111
|
if (tokens.includes(cssValue))
|
|
124
112
|
return cssValue;
|
|
125
|
-
// エイリアス変換後に一致
|
|
126
113
|
const aliased = VALUE_ALIASES[cssValue.toLowerCase()];
|
|
127
114
|
if (aliased && tokens.includes(aliased))
|
|
128
115
|
return aliased;
|
|
@@ -131,12 +118,12 @@ function suggestValue(mapping, cssValue) {
|
|
|
131
118
|
// ----------------------------------------------------------------
|
|
132
119
|
// コンポーネント検出
|
|
133
120
|
// ----------------------------------------------------------------
|
|
121
|
+
/** display関連の宣言から利用できるLismレイアウトコンポーネントを提案する。 */
|
|
134
122
|
function detectComponent(declarations) {
|
|
135
123
|
const propMap = new Map(declarations.map((d) => [d.property, d.value.toLowerCase()]));
|
|
136
124
|
const display = propMap.get('display');
|
|
137
125
|
const flexDirection = propMap.get('flex-direction');
|
|
138
126
|
const placeItems = propMap.get('place-items');
|
|
139
|
-
// Stack: flex + column
|
|
140
127
|
if (display === 'flex' && (flexDirection === 'column' || flexDirection === 'column-reverse')) {
|
|
141
128
|
return {
|
|
142
129
|
name: 'Stack',
|
|
@@ -144,7 +131,6 @@ function detectComponent(declarations) {
|
|
|
144
131
|
implicitCss: ['display: flex', 'flex-direction: column'],
|
|
145
132
|
};
|
|
146
133
|
}
|
|
147
|
-
// Center: grid + place-items: center
|
|
148
134
|
if (display === 'grid' && placeItems === 'center') {
|
|
149
135
|
return {
|
|
150
136
|
name: 'Center',
|
|
@@ -152,7 +138,6 @@ function detectComponent(declarations) {
|
|
|
152
138
|
implicitCss: ['display: grid', 'place-items: center'],
|
|
153
139
|
};
|
|
154
140
|
}
|
|
155
|
-
// Flex
|
|
156
141
|
if (display === 'flex') {
|
|
157
142
|
return {
|
|
158
143
|
name: 'Flex',
|
|
@@ -160,7 +145,6 @@ function detectComponent(declarations) {
|
|
|
160
145
|
implicitCss: ['display: flex'],
|
|
161
146
|
};
|
|
162
147
|
}
|
|
163
|
-
// Grid
|
|
164
148
|
if (display === 'grid') {
|
|
165
149
|
return {
|
|
166
150
|
name: 'Grid',
|
|
@@ -177,6 +161,7 @@ function findCategory(mappings, propName) {
|
|
|
177
161
|
const found = mappings.find((m) => m.prop === propName);
|
|
178
162
|
return found?.sectionName ?? 'unknown';
|
|
179
163
|
}
|
|
164
|
+
/** 変換結果からJSX使用例を組み立てる。 */
|
|
180
165
|
function buildExample(conversions, component) {
|
|
181
166
|
const tagName = component?.name ?? 'Lism';
|
|
182
167
|
const implicitCssSet = new Set(component?.implicitCss.map((c) => c.split(':')[0].trim()) ?? []);
|
|
@@ -188,7 +173,7 @@ function buildExample(conversions, component) {
|
|
|
188
173
|
styles.push(conv.css);
|
|
189
174
|
continue;
|
|
190
175
|
}
|
|
191
|
-
//
|
|
176
|
+
// コンポーネントが暗黙に持つCSSは重複出力しない。
|
|
192
177
|
if (implicitCssSet.has(cssProp))
|
|
193
178
|
continue;
|
|
194
179
|
if (conv.suggestedValue != null) {
|
|
@@ -232,7 +217,6 @@ export function registerConvertCss(server) {
|
|
|
232
217
|
annotations: READ_ONLY_ANNOTATIONS,
|
|
233
218
|
}, ({ css }) => {
|
|
234
219
|
try {
|
|
235
|
-
// @ ルール検出
|
|
236
220
|
const atRuleError = detectAtRules(css);
|
|
237
221
|
if (atRuleError) {
|
|
238
222
|
return error(atRuleError);
|
|
@@ -244,7 +228,7 @@ export function registerConvertCss(server) {
|
|
|
244
228
|
if (declarations.length === 0) {
|
|
245
229
|
return error('No CSS declarations found. Provide CSS in "property: value;" format.');
|
|
246
230
|
}
|
|
247
|
-
//
|
|
231
|
+
// 各宣言をLism Propと候補値へ変換する。
|
|
248
232
|
const conversions = declarations.map((decl) => {
|
|
249
233
|
const mapping = cssPropertyMap.get(decl.property);
|
|
250
234
|
if (!mapping) {
|
|
@@ -272,9 +256,8 @@ export function registerConvertCss(server) {
|
|
|
272
256
|
: `Use as a custom value (category: ${category})`,
|
|
273
257
|
};
|
|
274
258
|
});
|
|
275
|
-
//
|
|
259
|
+
// 変換結果からコンポーネント候補と使用例を組み立てる。
|
|
276
260
|
const suggestedComponent = detectComponent(declarations);
|
|
277
|
-
// 使用例
|
|
278
261
|
const example = buildExample(conversions, suggestedComponent);
|
|
279
262
|
return success({
|
|
280
263
|
conversions,
|