@things-factory/shell 10.1.4 → 10.1.7
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/shell",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.7",
|
|
4
4
|
"description": "Core module for framework",
|
|
5
5
|
"bin": {
|
|
6
6
|
"things-factory": "bin/things-factory",
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"pg": "^8.7.3",
|
|
127
127
|
"sqlite3": "^5.0.8"
|
|
128
128
|
},
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "9a036f83f5751f9e4af9180e9a0018f716a4ba27"
|
|
130
130
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 분류색 팔레트(`--ui-category-*`)를 **정의하는 자리가 하나인지** 센다.
|
|
3
|
+
*
|
|
4
|
+
* ── 왜 주석으로는 못 막나 ───────────────────────────────────────────────────
|
|
5
|
+
* `category-color.css` 는 「도메인이 바꾸지 않는다」고 적어 두었지만, 테마는 **같은 이름이면 파일
|
|
6
|
+
* 단위로 대체되는** 구조다(builder 의 ThemeOverridePlugin). 앱이 자기 `category-color.css` 를 두면
|
|
7
|
+
* 팔레트가 통째로 갈리고, 그것 말고도 자기 CSS 어디서든 `--ui-category-3: ...` 한 줄이면 덮인다.
|
|
8
|
+
* 둘째 길은 파일을 옮겨도 안 막힌다.
|
|
9
|
+
*
|
|
10
|
+
* 그래서 세는 쪽으로 막는다 — 정의가 하나인지를.
|
|
11
|
+
*
|
|
12
|
+
* 분류색은 **부호**라서 이것이 지켜져야 한다. 「1번 = 휴무」를 한 번 배운 사람은 그것을 들고 다니고,
|
|
13
|
+
* 도메인마다 다르면 같은 것을 배운 사람이 다른 공장에서 잘못 읽는다. 오독은 오류보다 나쁘다 — 화면이
|
|
14
|
+
* 멀쩡해 보이기 때문이다.
|
|
15
|
+
*
|
|
16
|
+
* ── 덮어야 할 일이 생기면 ───────────────────────────────────────────────────
|
|
17
|
+
* 이 시험을 지우지 말고 **가운데(이 파일이 가리키는 그 CSS)를 고친다.** 「이 도메인 바탕에서 3번이
|
|
18
|
+
* 안 보인다」는 도메인이 덮을 일이 아니라 팔레트의 결함이다. 막기만 하고 길이 없으면 급한 사람이
|
|
19
|
+
* 우회한다.
|
|
20
|
+
*
|
|
21
|
+
* ── 몇 개를 봤는지도 주장한다 ───────────────────────────────────────────────
|
|
22
|
+
* 「아무것도 못 찾아서 초록」이 이 종류 시험의 대표적인 실패다. 경로가 바뀌거나 glob 이 빗나가면
|
|
23
|
+
* 검사 대상이 0이 되고, 0을 다 통과한 것으로 읽힌다. 그래서 훑은 CSS 파일 수의 하한을 함께 건다.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { readFileSync, readdirSync, statSync } from 'fs'
|
|
27
|
+
import path from 'path'
|
|
28
|
+
|
|
29
|
+
/** 저장소 안의 모든 CSS 를 훑는다. 여기가 팔레트를 덮을 수 있는 자리 전부다. */
|
|
30
|
+
const REPO_ROOT = path.resolve(__dirname, '../../..')
|
|
31
|
+
|
|
32
|
+
/** 실제로 훑는 자리. 산출물과 설치본은 소스의 사본이라 세면 같은 정의를 두 번 센다. */
|
|
33
|
+
const SKIP = new Set(['node_modules', 'dist', 'dist-client', 'dist-server', 'dist-shared', '.git', 'coverage'])
|
|
34
|
+
|
|
35
|
+
/** `--ui-category-3: #...` 처럼 값을 주는 줄. `var(--ui-category-3)` 로 읽기만 하는 줄은 아니다. */
|
|
36
|
+
const DEFINES = /--ui-category-\d+\s*:/
|
|
37
|
+
|
|
38
|
+
function cssFilesUnder(dir: string, found: string[] = []): string[] {
|
|
39
|
+
for (const entry of readdirSync(dir)) {
|
|
40
|
+
if (SKIP.has(entry) || entry.startsWith('.')) continue
|
|
41
|
+
|
|
42
|
+
const full = path.join(dir, entry)
|
|
43
|
+
let stat
|
|
44
|
+
try {
|
|
45
|
+
stat = statSync(full)
|
|
46
|
+
} catch {
|
|
47
|
+
continue // broken symlink
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (stat.isDirectory()) cssFilesUnder(full, found)
|
|
51
|
+
else if (entry.endsWith('.css')) found.push(full)
|
|
52
|
+
}
|
|
53
|
+
return found
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe('the categorical palette has one definition site', () => {
|
|
57
|
+
const files = cssFilesUnder(REPO_ROOT)
|
|
58
|
+
const definers = files.filter(file => DEFINES.test(readFileSync(file, 'utf-8')))
|
|
59
|
+
|
|
60
|
+
it('scanned enough css to make the answer mean something', () => {
|
|
61
|
+
/*
|
|
62
|
+
* Without this, a moved path or a wrong glob scans nothing, finds no overrides, and reports
|
|
63
|
+
* green. 47 css files were in scope when this was written; the floor sits under that so
|
|
64
|
+
* deleting a stylesheet does not fail the build, but gutting the scan does.
|
|
65
|
+
*/
|
|
66
|
+
expect(files.length).toBeGreaterThanOrEqual(40)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('is defined in exactly one file', () => {
|
|
70
|
+
expect(definers.map(f => path.relative(REPO_ROOT, f))).toEqual([
|
|
71
|
+
'packages/shell/client/themes/category-color.css'
|
|
72
|
+
])
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('defines all six slots there, and only six', () => {
|
|
76
|
+
const css = readFileSync(definers[0], 'utf-8')
|
|
77
|
+
const slots = new Set([...css.matchAll(/--ui-category-(\d+)\s*:/g)].map(m => m[1]))
|
|
78
|
+
|
|
79
|
+
expect([...slots].sort()).toEqual(['1', '2', '3', '4', '5', '6'])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('keeps red for status, so a kind and an error never share a colour', () => {
|
|
83
|
+
/*
|
|
84
|
+
* Slot 1 was #c0392b, which measured dE00 2.5 against the error red the plant calendar
|
|
85
|
+
* actually renders - the same collapse this palette exists to fix. A screen showing both
|
|
86
|
+
* then has red meaning two things, and "red is bad" stops holding on that screen alone.
|
|
87
|
+
*
|
|
88
|
+
* A rule saying "do not use slot 1 where status colours appear" would have to be kept on
|
|
89
|
+
* every screen, with no signal when it is not. Giving up one colour is cheaper.
|
|
90
|
+
*/
|
|
91
|
+
const css = readFileSync(definers[0], 'utf-8')
|
|
92
|
+
const declared = [...css.matchAll(/--ui-category-\d+\s*:\s*(#[0-9a-fA-F]{6})/g)].map(m => m[1].toLowerCase())
|
|
93
|
+
|
|
94
|
+
expect(declared.length).toBeGreaterThan(0)
|
|
95
|
+
expect(declared).not.toContain('#c0392b')
|
|
96
|
+
expect(declared).not.toContain('#ff9080')
|
|
97
|
+
})
|
|
98
|
+
})
|