@the-portland-company/shell 0.89.0 → 0.91.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/CHANGELOG.md +23 -0
- package/README.md +6 -48
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +1 -1
- package/dist/app-chrome.d.ts +1 -1
- package/dist/app-chrome.js +3 -3
- package/dist/chrome.css +0 -20
- package/dist/{chunk-SJDFAK5R.js → chunk-WDVQBUWF.js} +4 -10
- package/dist/chunk-WDVQBUWF.js.map +1 -0
- package/dist/{chunk-J23MTK56.js → chunk-ZS7MQXDQ.js} +41 -402
- package/dist/chunk-ZS7MQXDQ.js.map +1 -0
- package/dist/{index-CZylXAP4.d.cts → index-Cg5aEImm.d.cts} +8 -201
- package/dist/{index-DwkSyAip.d.ts → index-DG32i0jC.d.ts} +8 -201
- package/dist/index.cjs +58 -437
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -19
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +39 -412
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +1 -1
- package/dist/native.d.ts +1 -1
- package/dist/native.js +2 -2
- package/package.json +2 -13
- package/dist/chunk-J23MTK56.js.map +0 -1
- package/dist/chunk-SJDFAK5R.js.map +0 -1
- package/eslint/index.cjs +0 -172
- package/eslint/index.d.ts +0 -6
- package/eslint/index.mjs +0 -5
package/eslint/index.cjs
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
// Shell primitives guard. Spec: Components — shared primitives are mandatory.
|
|
3
|
-
const SHELL_PKG = '@the-portland-company/shell'
|
|
4
|
-
const LOCAL_NAMES = new Set(['Button', 'Card', 'Input', 'Select', 'Textarea', 'Checkbox', 'FileInput', 'PageHeader', 'FormColumn'])
|
|
5
|
-
const RAW_TO_PRIMITIVE = { button: 'Button', input: 'Input', select: 'Select', textarea: 'Textarea' }
|
|
6
|
-
const GLOBAL_CLASS_RE = /\b(btn|input)(-[a-z]+)?\b/
|
|
7
|
-
const EXEMPT_RE = /shell-primitive-exempt:\s*\S+/
|
|
8
|
-
|
|
9
|
-
const isShellSource = (s) => typeof s === 'string' && (s === SHELL_PKG || s.startsWith(SHELL_PKG + '/'))
|
|
10
|
-
|
|
11
|
-
/** True when an exempt comment (with a reason) is on the node's line or the line above. */
|
|
12
|
-
function isExempt(context, node) {
|
|
13
|
-
const sc = context.sourceCode || context.getSourceCode()
|
|
14
|
-
const start = node.loc.start.line
|
|
15
|
-
return sc.getAllComments().some(
|
|
16
|
-
(c) => EXEMPT_RE.test(c.value) && c.loc.end.line >= start - 1 && c.loc.end.line <= start,
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const noLocalPrimitives = {
|
|
21
|
-
meta: {
|
|
22
|
-
type: 'problem',
|
|
23
|
-
schema: [],
|
|
24
|
-
messages: {
|
|
25
|
-
local: 'Do not declare or export a local "{{name}}". Import it from @the-portland-company/shell (shared primitives are mandatory); add variants to the shell instead.',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
create(context) {
|
|
29
|
-
const report = (node, name) => {
|
|
30
|
-
if (LOCAL_NAMES.has(name) && !isExempt(context, node)) {
|
|
31
|
-
context.report({ node, messageId: 'local', data: { name } })
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
FunctionDeclaration: (n) => n.id && report(n.id, n.id.name),
|
|
36
|
-
ClassDeclaration: (n) => n.id && report(n.id, n.id.name),
|
|
37
|
-
VariableDeclarator: (n) => n.id.type === 'Identifier' && report(n.id, n.id.name),
|
|
38
|
-
ExportSpecifier(n) {
|
|
39
|
-
const parent = n.parent
|
|
40
|
-
const exported = n.exported.name || n.exported.value
|
|
41
|
-
if (parent.source) {
|
|
42
|
-
if (!isShellSource(parent.source.value)) report(n, exported)
|
|
43
|
-
} else if (n.local.name !== exported) {
|
|
44
|
-
report(n, exported) // `export { Foo as Button }`; same-name locals are caught at declaration
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const noRawControlStyling = {
|
|
52
|
-
meta: {
|
|
53
|
-
type: 'problem',
|
|
54
|
-
schema: [],
|
|
55
|
-
messages: {
|
|
56
|
-
raw: '<{{tag}}> with {{prop}} hand-rolls a control. Use <{{primitive}}> from @the-portland-company/shell, or add "// shell-primitive-exempt: <reason>".',
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
create(context) {
|
|
60
|
-
const imported = new Set()
|
|
61
|
-
return {
|
|
62
|
-
ImportDeclaration(n) {
|
|
63
|
-
if (!isShellSource(n.source.value)) return
|
|
64
|
-
for (const s of n.specifiers) if (s.type === 'ImportSpecifier') imported.add(s.imported.name || s.imported.value)
|
|
65
|
-
},
|
|
66
|
-
JSXOpeningElement(n) {
|
|
67
|
-
if (n.name.type !== 'JSXIdentifier') return
|
|
68
|
-
const tag = n.name.name
|
|
69
|
-
let primitive = RAW_TO_PRIMITIVE[tag]
|
|
70
|
-
if (tag === 'input') {
|
|
71
|
-
// <input type="checkbox|file"> needs Checkbox / FileInput; importing Input does not excuse it.
|
|
72
|
-
const typeAttr = n.attributes.find(
|
|
73
|
-
(a) => a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier' && a.name.name === 'type',
|
|
74
|
-
)
|
|
75
|
-
const v = typeAttr && typeAttr.value
|
|
76
|
-
const typeValue =
|
|
77
|
-
v && v.type === 'Literal' ? v.value
|
|
78
|
-
: v && v.type === 'JSXExpressionContainer' && v.expression.type === 'Literal' ? v.expression.value
|
|
79
|
-
: null
|
|
80
|
-
if (typeValue === 'checkbox') primitive = 'Checkbox'
|
|
81
|
-
else if (typeValue === 'file') primitive = 'FileInput'
|
|
82
|
-
}
|
|
83
|
-
if (!primitive) return
|
|
84
|
-
const attr = n.attributes.find(
|
|
85
|
-
(a) => a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier' && (a.name.name === 'className' || a.name.name === 'style'),
|
|
86
|
-
)
|
|
87
|
-
if (!attr) return
|
|
88
|
-
if (imported.has(primitive)) return // wrapping the shell primitive
|
|
89
|
-
if (isExempt(context, n)) return
|
|
90
|
-
context.report({ node: attr, messageId: 'raw', data: { tag, prop: attr.name.name, primitive } })
|
|
91
|
-
},
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const noGlobalControlClasses = {
|
|
97
|
-
meta: {
|
|
98
|
-
type: 'problem',
|
|
99
|
-
schema: [],
|
|
100
|
-
messages: {
|
|
101
|
-
global: 'className "{{value}}" relies on a global btn/input class. Use the shell Button/Input primitives.',
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
create(context) {
|
|
105
|
-
function scan(node, root) {
|
|
106
|
-
if (!node) return
|
|
107
|
-
switch (node.type) {
|
|
108
|
-
case 'Literal':
|
|
109
|
-
if (typeof node.value === 'string') check(node.value, node, root)
|
|
110
|
-
break
|
|
111
|
-
case 'TemplateLiteral':
|
|
112
|
-
node.quasis.forEach((q) => check(q.value.cooked || '', q, root))
|
|
113
|
-
node.expressions.forEach((e) => scan(e, root))
|
|
114
|
-
break
|
|
115
|
-
case 'JSXExpressionContainer':
|
|
116
|
-
scan(node.expression, root)
|
|
117
|
-
break
|
|
118
|
-
case 'ConditionalExpression':
|
|
119
|
-
scan(node.consequent, root)
|
|
120
|
-
scan(node.alternate, root)
|
|
121
|
-
break
|
|
122
|
-
case 'LogicalExpression':
|
|
123
|
-
case 'BinaryExpression':
|
|
124
|
-
scan(node.left, root)
|
|
125
|
-
scan(node.right, root)
|
|
126
|
-
break
|
|
127
|
-
case 'CallExpression':
|
|
128
|
-
node.arguments.forEach((a) => scan(a, root))
|
|
129
|
-
break
|
|
130
|
-
case 'ArrayExpression':
|
|
131
|
-
node.elements.forEach((a) => scan(a, root))
|
|
132
|
-
break
|
|
133
|
-
case 'ObjectExpression':
|
|
134
|
-
node.properties.forEach((p) => p.type === 'Property' && scan(p.key, root))
|
|
135
|
-
break
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function check(text, node, root) {
|
|
139
|
-
if (GLOBAL_CLASS_RE.test(text) && !isExempt(context, root)) {
|
|
140
|
-
context.report({ node, messageId: 'global', data: { value: text.trim() } })
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
JSXAttribute(n) {
|
|
145
|
-
if (n.name.type === 'JSXIdentifier' && n.name.name === 'className') scan(n.value, n)
|
|
146
|
-
},
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const rules = {
|
|
152
|
-
'no-local-primitives': noLocalPrimitives,
|
|
153
|
-
'no-raw-control-styling': noRawControlStyling,
|
|
154
|
-
'no-global-control-classes': noGlobalControlClasses,
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const plugin = { meta: { name: SHELL_PKG + '/eslint' }, rules, configs: {} }
|
|
158
|
-
|
|
159
|
-
// Flat config: `export default [...shell.configs.recommended]`
|
|
160
|
-
plugin.configs.recommended = [
|
|
161
|
-
{
|
|
162
|
-
files: ['**/*.{js,jsx,ts,tsx,mjs,cjs}'],
|
|
163
|
-
plugins: { 'politogy-shell': plugin },
|
|
164
|
-
rules: {
|
|
165
|
-
'politogy-shell/no-local-primitives': 'error',
|
|
166
|
-
'politogy-shell/no-raw-control-styling': 'error',
|
|
167
|
-
'politogy-shell/no-global-control-classes': 'error',
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
module.exports = plugin
|
package/eslint/index.d.ts
DELETED