@swiftwc/eslint-plugin 1.0.0 → 1.1.1

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/README.md CHANGED
@@ -1,3 +1,15 @@
1
1
  # @swiftwc/eslint-plugin
2
2
 
3
3
  [README](https://github.com/swiftwc/ui/blob/main/README.md)
4
+
5
+ ## Documentation
6
+
7
+ Visit [swiftwc.github.io/ui/](https://swiftwc.github.io/ui/) to view the documentation.
8
+
9
+ ## Contributing
10
+
11
+ Please read the [contributing guide](https://github.com/swiftwc/ui/blob/main/CONTRIBUTING.md).
12
+
13
+ ## License
14
+
15
+ Licensed under the [MIT license](https://github.com/swiftwc/ui/blob/main/LICENSE.md).
@@ -0,0 +1,2 @@
1
+ import { swiftwc } from '../index.js';
2
+ export default swiftwc;
@@ -0,0 +1,19 @@
1
+ import { RULES, swiftwc, validate } from '../index.js';
2
+ swiftwc.rules['allowed-tags'].meta.docs.description = 'Restrict allowed HTML tags';
3
+ swiftwc.rules['allowed-tags'].meta.messages.disallowedTag = 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}';
4
+ swiftwc.rules['allowed-tags'].create = (context) => {
5
+ return {
6
+ // '*': (node) => {
7
+ // if('GlimmerElementNode' !== node.type) return
8
+ GlimmerElementNode(node) {
9
+ // @ts-expect-error
10
+ const tag = node.tag;
11
+ const allowedParents = RULES[tag];
12
+ if (!allowedParents)
13
+ return; // 👈 ignore unknown tags completely
14
+ // @ts-expect-error
15
+ validate(tag, (item) => item.tag, allowedParents, context, node);
16
+ },
17
+ };
18
+ };
19
+ export default swiftwc;
@@ -0,0 +1,2 @@
1
+ import { swiftwc } from '../index.js';
2
+ export default swiftwc;
@@ -0,0 +1,15 @@
1
+ import { RULES, swiftwc, validate } from '../index.js';
2
+ swiftwc.rules['allowed-tags'].meta.docs.description = 'Restrict allowed HTML tags';
3
+ swiftwc.rules['allowed-tags'].meta.messages.disallowedTag = 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}';
4
+ swiftwc.rules['allowed-tags'].create = (context) => {
5
+ return {
6
+ Tag(node) {
7
+ const tag = node.name;
8
+ const allowedParents = RULES[tag];
9
+ if (!allowedParents)
10
+ return; // 👈 ignore unknown tags completely
11
+ validate(tag, (item) => item.parent, allowedParents, context, node);
12
+ },
13
+ };
14
+ };
15
+ export default swiftwc;
@@ -0,0 +1,32 @@
1
+ import type { RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ export type TagNode = {
3
+ name: string;
4
+ type: string;
5
+ parent?: TagNode;
6
+ };
7
+ export declare const RULES: Record<string, string[]>;
8
+ export declare function validate(tag: string, getParentTag: (node: TagNode) => TagNode | undefined, allowedParents: string[], context: RuleContext<string, readonly unknown[]>, node: TagNode): void;
9
+ export declare const swiftwc: {
10
+ meta: {
11
+ name: any;
12
+ version: any;
13
+ namespace: string;
14
+ };
15
+ configs: {};
16
+ rules: {
17
+ 'allowed-tags': {
18
+ meta: {
19
+ type: "problem";
20
+ docs: {
21
+ description: string;
22
+ url: string;
23
+ };
24
+ schema: never[];
25
+ messages: {
26
+ disallowedTag: string;
27
+ };
28
+ };
29
+ create(context: Readonly<RuleContext<string, readonly unknown[]>>): RuleListener;
30
+ };
31
+ };
32
+ };
@@ -0,0 +1,125 @@
1
+ import { readFileSync } from 'fs';
2
+ export const RULES = {
3
+ 'v-keyboard': ['body'],
4
+ 'scroll-view': ['body-view', 'dialog', 'navigation-stack', 'navigation-split-view', 'detail-placeholder'],
5
+ dialog: ['tab-view', 'template'],
6
+ };
7
+ export function validate(tag, getParentTag, allowedParents, context, node) {
8
+ let parentTag = getParentTag(node), isValid = false;
9
+ while (parentTag) {
10
+ if (parentTag.type === node.type && allowedParents.includes(parentTag.name)) {
11
+ isValid = true;
12
+ break;
13
+ }
14
+ parentTag = getParentTag(parentTag);
15
+ }
16
+ if (isValid)
17
+ return;
18
+ context.report({
19
+ // @ts-expect-error
20
+ node,
21
+ messageId: 'disallowedTag',
22
+ data: {
23
+ tag,
24
+ allowed: allowedParents.join(', '),
25
+ },
26
+ });
27
+ }
28
+ const { name, version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
29
+ export const swiftwc = {
30
+ meta: {
31
+ name,
32
+ version,
33
+ namespace: 'swiftwc',
34
+ },
35
+ configs: {},
36
+ rules: {
37
+ 'allowed-tags': {
38
+ meta: {
39
+ type: 'problem',
40
+ docs: {
41
+ description: 'Restrict allowed HTML tags',
42
+ url: `https://github.com/swiftwc/ui`,
43
+ },
44
+ // languages: ['html/html'],
45
+ schema: [],
46
+ // schema: [
47
+ // {
48
+ // type: 'object',
49
+ // properties: {
50
+ // allowed: {
51
+ // type: 'array',
52
+ // items: { type: 'string' },
53
+ // },
54
+ // },
55
+ // additionalProperties: false,
56
+ // },
57
+ // ],
58
+ messages: {
59
+ disallowedTag: 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}',
60
+ },
61
+ },
62
+ // create(context) {
63
+ // const options = context.options?.[0] || {},
64
+ // allowed = new Set(options.allowed || [...DEFAULT_ALLOWED])
65
+ // return {
66
+ // Tag(node) {
67
+ // const tag = node.name
68
+ // if (!allowed.has(tag)) {
69
+ // context.report({
70
+ // node,
71
+ // messageId: 'disallowedTag',
72
+ // data: {
73
+ // tag,
74
+ // allowed: [...allowed].join(', '),
75
+ // },
76
+ // })
77
+ // }
78
+ // },
79
+ // }
80
+ // },
81
+ create(context) {
82
+ return {
83
+ Tag(node) {
84
+ const tag = node.name;
85
+ const allowedParents = RULES[tag];
86
+ if (!allowedParents)
87
+ return; // 👈 ignore unknown tags completely
88
+ validate(tag, (item) => item.parent, allowedParents, context, node);
89
+ // let parent = node.parent
90
+ // let valid = false
91
+ // while (parent) {
92
+ // if (parent.type === 'Tag' && allowedParents.includes(parent.name)) {
93
+ // valid = true
94
+ // break
95
+ // }
96
+ // parent = parent.parent
97
+ // }
98
+ // if (!valid) {
99
+ // context.report({
100
+ // node,
101
+ // messageId: 'disallowedTag',
102
+ // data: {
103
+ // tag,
104
+ // allowed: allowedParents.join(', '),
105
+ // },
106
+ // })
107
+ // }
108
+ },
109
+ };
110
+ },
111
+ },
112
+ },
113
+ };
114
+ Object.assign(swiftwc.configs, {
115
+ recommended: [
116
+ {
117
+ plugins: {
118
+ swiftwc,
119
+ },
120
+ rules: {
121
+ 'swiftwc/allowed-tags': 'error', //['error', { allowed: ['div', 'span', 'my-button', 'my-card'] }],
122
+ },
123
+ },
124
+ ],
125
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftwc/eslint-plugin",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Rules enforcing best practices while using SwiftWC.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -22,11 +22,22 @@
22
22
  },
23
23
  "type": "module",
24
24
  "peerDependencies": {
25
- "@swiftwc/ui": "^1.0.0",
25
+ "@swiftwc/ui": "*",
26
26
  "eslint": ">=10.0.0"
27
27
  },
28
28
  "exports": {
29
- "./html/en": "./html/en.js",
30
- "./emberjs/en": "./emberjs/en.js"
29
+ "./html/en": "./generated/html/en.js",
30
+ "./emberjs/en": "./generated/emberjs/en.js"
31
+ },
32
+ "scripts": {
33
+ "prebuild": "rm -rf generated",
34
+ "build": "npm run build:ts",
35
+ "build:ts:watch": "npm run prebuild && tsc --watch",
36
+ "build:ts": "tsc",
37
+ "format:check": "prettier . --check",
38
+ "format:write": "prettier . --write"
39
+ },
40
+ "devDependencies": {
41
+ "@typescript-eslint/utils": "^8.59.2"
31
42
  }
32
43
  }
@@ -0,0 +1,24 @@
1
+ import type { RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint'
2
+ import { RULES, swiftwc, validate, type TagNode } from '../index.js'
3
+
4
+ swiftwc.rules['allowed-tags'].meta.docs.description = 'Restrict allowed HTML tags'
5
+
6
+ swiftwc.rules['allowed-tags'].meta.messages.disallowedTag = 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}'
7
+
8
+ swiftwc.rules['allowed-tags'].create = (context: Readonly<RuleContext<string, readonly unknown[]>>): RuleListener => {
9
+ return {
10
+ // '*': (node) => {
11
+ // if('GlimmerElementNode' !== node.type) return
12
+ GlimmerElementNode(node: TagNode) {
13
+ // @ts-expect-error
14
+ const tag = node.tag
15
+
16
+ const allowedParents = RULES[tag]
17
+ if (!allowedParents) return // 👈 ignore unknown tags completely
18
+
19
+ validate(tag, (item) => item.parent, allowedParents, context, node)
20
+ },
21
+ }
22
+ }
23
+
24
+ export default swiftwc
@@ -1,12 +1,13 @@
1
- import { RULES, swiftwc, validate } from '../src/index.js'
1
+ import type { RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint'
2
+ import { RULES, swiftwc, validate, type TagNode } from '../index.js'
2
3
 
3
4
  swiftwc.rules['allowed-tags'].meta.docs.description = 'Restrict allowed HTML tags'
4
5
 
5
6
  swiftwc.rules['allowed-tags'].meta.messages.disallowedTag = 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}'
6
7
 
7
- swiftwc.rules['allowed-tags'].create = (context) => {
8
+ swiftwc.rules['allowed-tags'].create = (context: Readonly<RuleContext<string, readonly unknown[]>>): RuleListener => {
8
9
  return {
9
- Tag(node) {
10
+ Tag(node: TagNode) {
10
11
  const tag = node.name
11
12
 
12
13
  const allowedParents = RULES[tag]
@@ -1,6 +1,13 @@
1
+ import type { Linter, RuleContext, RuleListener } from '@typescript-eslint/utils/ts-eslint'
1
2
  import { readFileSync } from 'fs'
2
3
 
3
- export const RULES = {
4
+ export type TagNode = {
5
+ name: string
6
+ type: string
7
+ parent?: TagNode
8
+ }
9
+
10
+ export const RULES: Record<string, string[]> = {
4
11
  'v-keyboard': ['body'],
5
12
 
6
13
  'scroll-view': ['body-view', 'dialog', 'navigation-stack', 'navigation-split-view', 'detail-placeholder'],
@@ -8,25 +15,29 @@ export const RULES = {
8
15
  dialog: ['tab-view', 'template'],
9
16
  }
10
17
 
11
- export function validate(tag, getParentTag, allowedParents, context, node) {
12
- // let parent = getParentTag(node)
13
- // let isValid = false
14
-
15
- // while (parent) {
16
- // if (parent.type === 'Tag' && allowedParents.includes(parent.name)) {
17
- // isValid = true
18
- // break
19
- // }
20
- // parent = getParentTag(parent)
21
- // }
22
-
23
- const parentTag = getParentTag(node)
24
-
25
- const isValid = allowedParents.includes(parentTag.name)
18
+ export function validate(
19
+ tag: string,
20
+ getParentTag: (node: TagNode) => TagNode | undefined,
21
+ allowedParents: string[],
22
+ context: RuleContext<string, readonly unknown[]>,
23
+ node: TagNode
24
+ ) {
25
+ let parentTag = getParentTag(node),
26
+ isValid = false
27
+
28
+ while (parentTag) {
29
+ if (parentTag.type === node.type && allowedParents.includes(parentTag.name)) {
30
+ isValid = true
31
+ break
32
+ }
33
+
34
+ parentTag = getParentTag(parentTag)
35
+ }
26
36
 
27
37
  if (isValid) return
28
38
 
29
39
  context.report({
40
+ // @ts-expect-error
30
41
  node,
31
42
  messageId: 'disallowedTag',
32
43
  data: {
@@ -53,7 +64,7 @@ export const swiftwc = {
53
64
  description: 'Restrict allowed HTML tags',
54
65
  url: `https://github.com/swiftwc/ui`,
55
66
  },
56
- languages: ['html/html'],
67
+ // languages: ['html/html'],
57
68
  schema: [],
58
69
  // schema: [
59
70
  // {
@@ -93,9 +104,9 @@ export const swiftwc = {
93
104
  // }
94
105
  // },
95
106
 
96
- create(context) {
107
+ create(context: Readonly<RuleContext<string, readonly unknown[]>>): RuleListener {
97
108
  return {
98
- Tag(node) {
109
+ Tag(node: TagNode) {
99
110
  const tag = node.name
100
111
 
101
112
  const allowedParents = RULES[tag]
@@ -129,7 +140,7 @@ export const swiftwc = {
129
140
  },
130
141
  },
131
142
  },
132
- }
143
+ } satisfies Linter.Plugin
133
144
 
134
145
  Object.assign(swiftwc.configs, {
135
146
  recommended: [
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "generated",
5
+ "rootDir": "src",
6
+ "skipLibCheck": true,
7
+ "module": "NodeNext",
8
+ "moduleResolution": "NodeNext",
9
+ "resolveJsonModule": true
10
+ },
11
+ "include": ["src"],
12
+ "exclude": ["**/*.test.ts"]
13
+ }
package/emberjs/en.js DELETED
@@ -1,20 +0,0 @@
1
- import { RULES, swiftwc, validate } from '../src/index.js'
2
-
3
- swiftwc.rules['allowed-tags'].meta.docs.description = 'Restrict allowed HTML tags'
4
-
5
- swiftwc.rules['allowed-tags'].meta.messages.disallowedTag = 'Tag <{{tag}}> is only allowed inside any of: {{allowed}}'
6
-
7
- swiftwc.rules['allowed-tags'].create = (context) => {
8
- return {
9
- ElementNode(node) {
10
- const tag = node.tag
11
-
12
- const allowedParents = RULES[tag]
13
- if (!allowedParents) return // 👈 ignore unknown tags completely
14
-
15
- validate(tag, (item) => item.tag, allowedParents, context, node)
16
- },
17
- }
18
- }
19
-
20
- export default swiftwc