diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 00000000..9a37db2f --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,49 @@ +name: Lint & Build + +on: + push: + branches: + - main + pull_request: + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install node + uses: actions/setup-node@v3 + with: + node-version: 20.9.0 + + - uses: pnpm/action-setup@v2 + name: install pnpm + with: + version: 8.10.0 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: set up pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: install dependencies + run: pnpm install + + - name: lint + run: npm run lint + + - name: build + run: npm run build diff --git a/packages/eslint-plugin-youcan/src/index.ts b/packages/eslint-plugin-youcan/src/index.ts index 3a39f9e6..0148348f 100644 --- a/packages/eslint-plugin-youcan/src/index.ts +++ b/packages/eslint-plugin-youcan/src/index.ts @@ -1,7 +1,7 @@ -import genericSpacing from './rules/generic-spacing' -import ifNewline from './rules/if-newline' -import importDedupe from './rules/import-dedupe' -import preferInlineTypeImport from './rules/prefer-inline-type-import' +import genericSpacing from './rules/generic-spacing'; +import ifNewline from './rules/if-newline'; +import importDedupe from './rules/import-dedupe'; +import preferInlineTypeImport from './rules/prefer-inline-type-import'; export default { rules: { @@ -10,4 +10,4 @@ export default { 'prefer-inline-type-import': preferInlineTypeImport, 'generic-spacing': genericSpacing, }, -} +}; diff --git a/packages/eslint-plugin-youcan/src/rules/generic-spacing.ts b/packages/eslint-plugin-youcan/src/rules/generic-spacing.ts index 6df03f9d..3411c316 100644 --- a/packages/eslint-plugin-youcan/src/rules/generic-spacing.ts +++ b/packages/eslint-plugin-youcan/src/rules/generic-spacing.ts @@ -1,8 +1,8 @@ -import { createEslintRule } from '../utils' +import { createEslintRule } from '../utils'; -export const RULE_NAME = 'generic-spacing' -export type MessageIds = 'genericSpacingMismatch' -export type Options = [] +export const RULE_NAME = 'generic-spacing'; +export type MessageIds = 'genericSpacingMismatch'; +export type Options = []; export default createEslintRule({ name: RULE_NAME, @@ -20,36 +20,37 @@ export default createEslintRule({ }, defaultOptions: [], create: (context) => { - const sourceCode = context.getSourceCode() + const sourceCode = context.getSourceCode(); + return { TSTypeParameterDeclaration: (node) => { - if (!['TSCallSignatureDeclaration', 'ArrowFunctionExpression', 'TSFunctionType'].includes(node.parent.type)) { - const pre = sourceCode.text.slice(0, node.range[0]) - const preSpace = pre.match(/(\s+)$/)?.[0] + if (!['TSCallSignatureDeclaration', 'ArrowFunctionExpression', 'TSFunctionType'].includes(node.parent!.type)) { + const pre = sourceCode.text.slice(0, node.range[0]); + const preSpace = pre.match(/(\s+)$/)?.[0]; // strip space before if (preSpace && preSpace.length) { context.report({ node, messageId: 'genericSpacingMismatch', *fix(fixer) { - yield fixer.replaceTextRange([node.range[0] - preSpace.length, node.range[0]], '') + yield fixer.replaceTextRange([node.range[0] - preSpace.length, node.range[0]], ''); }, - }) + }); } } // add space between - const params = node.params + const params = node.params; for (let i = 1; i < params.length; i++) { - const prev = params[i - 1] - const current = params[i] - const from = prev.range[1] - const to = current.range[0] - const span = sourceCode.text.slice(from, to) + const prev = params[i - 1]; + const current = params[i]; + const from = prev.range[1]; + const to = current.range[0]; + const span = sourceCode.text.slice(from, to); if (span !== ', ' && !span.match(/,\n/)) { context.report({ *fix(fixer) { - yield fixer.replaceTextRange([from, to], ', ') + yield fixer.replaceTextRange([from, to], ', '); }, loc: { start: prev.loc.end, @@ -57,21 +58,22 @@ export default createEslintRule({ }, messageId: 'genericSpacingMismatch', node, - }) + }); } } }, // add space around = in type Foo TSTypeParameter: (node) => { - if (!node.default) - return - const endNode = node.constraint || node.name - const from = endNode.range[1] - const to = node.default.range[0] + if (!node.default) { + return; + } + const endNode = node.constraint || node.name; + const from = endNode.range[1]; + const to = node.default.range[0]; if (sourceCode.text.slice(from, to) !== ' = ') { context.report({ *fix(fixer) { - yield fixer.replaceTextRange([from, to], ' = ') + yield fixer.replaceTextRange([from, to], ' = '); }, loc: { start: endNode.loc.end, @@ -79,9 +81,9 @@ export default createEslintRule({ }, messageId: 'genericSpacingMismatch', node, - }) + }); } }, - } + }; }, -}) +}); diff --git a/packages/eslint-plugin-youcan/src/rules/if-newline.ts b/packages/eslint-plugin-youcan/src/rules/if-newline.ts index d495ac9c..5a7b95a7 100644 --- a/packages/eslint-plugin-youcan/src/rules/if-newline.ts +++ b/packages/eslint-plugin-youcan/src/rules/if-newline.ts @@ -1,8 +1,8 @@ -import { createEslintRule } from '../utils' +import { createEslintRule } from '../utils'; -export const RULE_NAME = 'if-newline' -export type MessageIds = 'missingIfNewline' -export type Options = [] +export const RULE_NAME = 'if-newline'; +export type MessageIds = 'missingIfNewline'; +export type Options = []; export default createEslintRule({ name: RULE_NAME, @@ -22,10 +22,14 @@ export default createEslintRule({ create: (context) => { return { IfStatement(node) { - if (!node.consequent) - return - if (node.consequent.type === 'BlockStatement') - return + if (!node.consequent) { + return; + } + + if (node.consequent.type === 'BlockStatement') { + return; + } + if (node.test.loc.end.line === node.consequent.loc.start.line) { context.report({ node, @@ -35,11 +39,11 @@ export default createEslintRule({ }, messageId: 'missingIfNewline', fix(fixer) { - return fixer.replaceTextRange([node.consequent.range[0], node.consequent.range[0]], '\n') + return fixer.replaceTextRange([node.consequent.range[0], node.consequent.range[0]], '\n'); }, - }) + }); } }, - } + }; }, -}) +}); diff --git a/packages/eslint-plugin-youcan/src/rules/import-dedupe.ts b/packages/eslint-plugin-youcan/src/rules/import-dedupe.ts index 3a4f4f5b..5d3c974c 100644 --- a/packages/eslint-plugin-youcan/src/rules/import-dedupe.ts +++ b/packages/eslint-plugin-youcan/src/rules/import-dedupe.ts @@ -1,8 +1,8 @@ -import { createEslintRule } from '../utils' +import { createEslintRule } from '../utils'; -export const RULE_NAME = 'import-dedupe' -export type MessageIds = 'importDedupe' -export type Options = [] +export const RULE_NAME = 'import-dedupe'; +export type MessageIds = 'importDedupe'; +export type Options = []; export default createEslintRule({ name: RULE_NAME, @@ -22,12 +22,13 @@ export default createEslintRule({ create: (context) => { return { ImportDeclaration(node) { - if (node.specifiers.length <= 1) - return + if (node.specifiers.length <= 1) { + return; + } - const names = new Set() + const names = new Set(); node.specifiers.forEach((n) => { - const id = n.local.name + const id = n.local.name; if (names.has(id)) { context.report({ node, @@ -37,19 +38,21 @@ export default createEslintRule({ }, messageId: 'importDedupe', fix(fixer) { - const s = n.range[0] - let e = n.range[1] - if (context.getSourceCode().text[e] === ',') - e += 1 - return fixer.removeRange([s, e]) + const s = n.range[0]; + let e = n.range[1]; + if (context.getSourceCode().text[e] === ',') { + e += 1; + } + + return fixer.removeRange([s, e]); }, - }) + }); } - names.add(id) - }) + names.add(id); + }); // console.log(node) }, - } + }; }, -}) +}); diff --git a/packages/eslint-plugin-youcan/src/rules/prefer-inline-type-import.ts b/packages/eslint-plugin-youcan/src/rules/prefer-inline-type-import.ts index 857cb49a..cc343bd0 100644 --- a/packages/eslint-plugin-youcan/src/rules/prefer-inline-type-import.ts +++ b/packages/eslint-plugin-youcan/src/rules/prefer-inline-type-import.ts @@ -1,12 +1,12 @@ // Ported from https://github.com/gajus/eslint-plugin-canonical/blob/master/src/rules/preferInlineTypeImport.js // by Gajus Kuizinas https://github.com/gajus -import type { TSESTree } from '@typescript-eslint/utils' -import type { RuleFixer, SourceCode } from '@typescript-eslint/utils/dist/ts-eslint' -import { createEslintRule } from '../utils' +import type { TSESTree } from '@typescript-eslint/utils'; +import type { RuleFixer, SourceCode } from '@typescript-eslint/utils/dist/ts-eslint'; +import { createEslintRule } from '../utils'; -export const RULE_NAME = 'prefer-inline-type-import' -export type MessageIds = 'preferInlineTypeImport' -export type Options = [] +export const RULE_NAME = 'prefer-inline-type-import'; +export type MessageIds = 'preferInlineTypeImport'; +export type Options = []; export default createEslintRule({ name: RULE_NAME, @@ -24,41 +24,44 @@ export default createEslintRule({ }, defaultOptions: [], create: (context) => { - const sourceCode = context.getSourceCode() + const sourceCode = context.getSourceCode(); + return { ImportDeclaration: (node) => { // ignore bare type imports - if (node.specifiers.length === 1 && ['ImportNamespaceSpecifier', 'ImportDefaultSpecifier'].includes(node.specifiers[0].type)) - return + if (node.specifiers.length === 1 && ['ImportNamespaceSpecifier', 'ImportDefaultSpecifier'].includes(node.specifiers[0].type)) { + return; + } if (node.importKind === 'type') { context.report({ *fix(fixer) { - yield * removeTypeSpecifier(fixer, sourceCode, node) + yield * removeTypeSpecifier(fixer, sourceCode, node); - for (const specifier of node.specifiers) - yield fixer.insertTextBefore(specifier, 'type ') + for (const specifier of node.specifiers) { + yield fixer.insertTextBefore(specifier, 'type '); + } }, loc: node.loc, messageId: 'preferInlineTypeImport', node, - }) + }); } }, - } + }; }, -}) +}); function * removeTypeSpecifier(fixer: RuleFixer, sourceCode: Readonly, node: TSESTree.ImportDeclaration) { - const importKeyword = sourceCode.getFirstToken(node) + const importKeyword = sourceCode.getFirstToken(node); - const typeIdentifier = sourceCode.getTokenAfter(importKeyword) + const typeIdentifier = sourceCode.getTokenAfter(importKeyword!); - yield fixer.remove(typeIdentifier) + yield fixer.remove(typeIdentifier!); - if (importKeyword.loc.end.column + 1 === typeIdentifier.loc.start.column) { + if (importKeyword!.loc.end.column + 1 === typeIdentifier!.loc.start.column) { yield fixer.removeRange([ - importKeyword.range[1], - importKeyword.range[1] + 1, - ]) + importKeyword!.range[1], + importKeyword!.range[1] + 1, + ]); } } diff --git a/packages/eslint-plugin-youcan/src/utils.ts b/packages/eslint-plugin-youcan/src/utils.ts index 3549847d..c886e19c 100644 --- a/packages/eslint-plugin-youcan/src/utils.ts +++ b/packages/eslint-plugin-youcan/src/utils.ts @@ -1,5 +1,5 @@ -import { ESLintUtils } from '@typescript-eslint/utils' +import { ESLintUtils } from '@typescript-eslint/utils'; export const createEslintRule = ESLintUtils.RuleCreator( ruleName => ruleName, -) +); diff --git a/packages/eslint-plugin-youcan/tsconfig.json b/packages/eslint-plugin-youcan/tsconfig.json index 30b9deca..8b0c1399 100644 --- a/packages/eslint-plugin-youcan/tsconfig.json +++ b/packages/eslint-plugin-youcan/tsconfig.json @@ -6,6 +6,6 @@ "moduleResolution": "node" }, "include": [ - "./packages/**/*.ts" + "src" ] } diff --git a/packages/vue3/src/components/Checkbox/Checkbox.stories.ts b/packages/vue3/src/components/Checkbox/Checkbox.stories.ts index f27affa7..7c61e12e 100644 --- a/packages/vue3/src/components/Checkbox/Checkbox.stories.ts +++ b/packages/vue3/src/components/Checkbox/Checkbox.stories.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import type { Meta } from '@storybook/vue3'; import Checkbox from './Checkbox.vue'; diff --git a/packages/vue3/src/components/DateInput/DateInput.stories.ts b/packages/vue3/src/components/DateInput/DateInput.stories.ts index e32eba6b..7257f3f8 100644 --- a/packages/vue3/src/components/DateInput/DateInput.stories.ts +++ b/packages/vue3/src/components/DateInput/DateInput.stories.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import type { Meta } from '@storybook/vue3'; import DateInput_ from './DateInput.vue'; diff --git a/packages/vue3/src/components/Increment/Increment.stories.ts b/packages/vue3/src/components/Increment/Increment.stories.ts index 485c825c..8b8c281e 100644 --- a/packages/vue3/src/components/Increment/Increment.stories.ts +++ b/packages/vue3/src/components/Increment/Increment.stories.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import type { Meta } from '@storybook/vue3'; import Increment_ from './Increment.vue'; diff --git a/packages/vue3/src/components/PaginationBar/PaginationBar.stories.ts b/packages/vue3/src/components/PaginationBar/PaginationBar.stories.ts index d80b273c..39a1faaf 100644 --- a/packages/vue3/src/components/PaginationBar/PaginationBar.stories.ts +++ b/packages/vue3/src/components/PaginationBar/PaginationBar.stories.ts @@ -1,6 +1,7 @@ import type { Meta } from '@storybook/vue3'; import PaginationBar from './PaginationBar.vue'; +/* eslint-disable no-console */ const meta: Meta = { title: 'Application/PaginationBar', component: PaginationBar, diff --git a/packages/vue3/src/components/RichText/RichText.vue b/packages/vue3/src/components/RichText/RichText.vue index e9237c0e..55055b1a 100644 --- a/packages/vue3/src/components/RichText/RichText.vue +++ b/packages/vue3/src/components/RichText/RichText.vue @@ -20,8 +20,8 @@ import InsertTable from './internal/Table.vue'; import { TextStyleExtended } from './extensions/textstyle'; import Colors from './internal/Color.vue'; import handleDropEvent from './handleDrop'; -import Iframe from './extensions/iframe'; -import EmojiPicker from './internal/Emojipicker.vue'; +import Iframe from './extensions/Iframe'; +import EmojiPicker from './internal/EmojiPicker.vue'; import Tooltip from './internal/Tooltip.vue'; import toolbar from './toolbar'; diff --git a/packages/vue3/src/components/RichText/extensions/textstyle.ts b/packages/vue3/src/components/RichText/extensions/textstyle.ts index a1ea6694..303d02a7 100644 --- a/packages/vue3/src/components/RichText/extensions/textstyle.ts +++ b/packages/vue3/src/components/RichText/extensions/textstyle.ts @@ -20,6 +20,7 @@ export const TextStyleExtended = TextStyle.extend({ if (!attributes.fontSize) { return {}; } + return { style: `font-size: ${attributes.fontSize}px`, }; diff --git a/packages/vue3/src/components/RichText/handleDrop.ts b/packages/vue3/src/components/RichText/handleDrop.ts index 8fafc713..4f97bd7b 100644 --- a/packages/vue3/src/components/RichText/handleDrop.ts +++ b/packages/vue3/src/components/RichText/handleDrop.ts @@ -1,3 +1,5 @@ +/* eslint-disable no-alert */ + import type { EditorView } from '@tiptap/pm/view'; const MAX_IMAGE_SIZE_MB = 10; @@ -23,15 +25,19 @@ export default function (view: EditorView, event: DragEvent, slice: unknown, mov } else { const src = await uploadImage(file); - if (!src) { return alert('failed to update the image'); } + if (!src) { + return alert('failed to update the image'); + } const { schema } = view.state; const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY })!; const node = schema.nodes.image.create({ src }); const transaction = view.state.tr.insert(coordinates.pos, node); + return view.dispatch(transaction); } }; + return true; } diff --git a/packages/vue3/src/components/RichText/toolbar.ts b/packages/vue3/src/components/RichText/toolbar.ts index 8470b84f..0221f00f 100644 --- a/packages/vue3/src/components/RichText/toolbar.ts +++ b/packages/vue3/src/components/RichText/toolbar.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-alert */ // @unocss-include import type { Editor } from '@tiptap/vue-3'; @@ -12,6 +13,7 @@ const fontSizes: DropdownItemArray = (() => { _items.push({ label: String(i), value: i }); } } + return _items; })(); @@ -109,7 +111,9 @@ export default function (editor: ShallowRef): Record= 0.8'} dev: true - /prismjs@1.29.0: - resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} - engines: {node: '>=6'} - dev: false - /private@0.1.8: resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} engines: {node: '>= 0.6'}