Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(#331): Add linter #382

Merged
merged 1 commit into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// eslint-disable-next-line no-undef
module.exports = {
extends: ['@tybalt/ts-recommended'],
parser: '@typescript-eslint/parser',
extends: ['plugin:@tybalt/eslint-plugin/ts-recommended'],
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plugins: ['@tybalt/eslint-plugin'],
ignorePatterns: ['packages/**/node_modules'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
};
3 changes: 3 additions & 0 deletions .github/workflows/yarn-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ jobs:
- name: Build monorepo
run: yarn build

- name: Static analysis
run: yarn lint

- name: Run unit tests
run: yarn test
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"./packages/website"
],
"devDependencies": {
"@tybalt/eslint-plugin": "workspace:^",
"eslint": "^8.46.0",
"jest": "^29.4.3",
"jest-fail-on-console": "^3.1.1",
Expand Down
5 changes: 2 additions & 3 deletions packages/cli/config/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module.exports = {
extends: ['@tybalt/ts-recommended'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: ['plugin:@tybalt/eslint-plugin/ts-recommended'],
plugins: ['@tybalt/eslint-plugin'],
};
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@chialab/esbuild-plugin-html": "^0.17.2",
"@swc/core": "^1.3.27",
"@tybalt/esbuild-plugin": "workspace:^",
"@tybalt/eslint-plugin": "workspace:^",
"@types/glob": "^8.0.1",
"browser-sync": "^2.27.11",
"chalk": "^5.2.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/commands/scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const scaffoldProject = async ({ projectName, options }: { projectName: string;
};

// Scaffolding steps specific for scaffolding an eleventy site
const scaffoldEleventy = async ({ projectName, options }: { projectName: string; options: ScaffoldCommandOptions }) => {
const scaffoldEleventy = async ({ projectName }: { projectName: string; options: ScaffoldCommandOptions }) => {
devDependencies.push('@tybalt/eleventy-plugin');
devDependencies.push('@11ty/eleventy');

Expand All @@ -154,7 +154,7 @@ const scaffoldEleventy = async ({ projectName, options }: { projectName: string;
};

// Scaffolding steps specific for scaffolding a fastify site
const scaffoldFastify = async ({ projectName, options }: { projectName: string; options: ScaffoldCommandOptions }) => {
const scaffoldFastify = async () => {
dependencies.push(
'@fastify/autoload',
'@fastify/sensible',
Expand Down Expand Up @@ -244,7 +244,7 @@ const action = async (targetArg: string, options: ScaffoldCommandOptions) => {
}
case 'fastify': {
await scaffoldProject({ projectName: options.name, options });
await scaffoldFastify({ projectName: options.name, options });
await scaffoldFastify();
await scaffoldComponent({ componentName: 'HelloWorld', options });
installDependencies();
writeScripts();
Expand Down
15 changes: 8 additions & 7 deletions packages/cli/src/commands/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ export default ({ program }: CommandContext) => {
program
.command('serve')
.description('watch a component or components')
.option('-e, --examples', 'whether to serve the examples', true)
.option('-w, --website', 'whether to serve the website', true)
.action((options: { examples: boolean; website: boolean }) => {
const server = bs.create();
.action((options: { website: boolean }) => {
if (options.website) {
bs.create();

bs.init({
server: './dist',
});
bs.init({
server: './dist',
});

bs.reload('*.html');
bs.reload('*.html');
}
});
};
2 changes: 1 addition & 1 deletion packages/cli/src/templates/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default defineComponent({
shadowMode: 'open',
props: { name: { validator: compose(string(), required) } },
render({ name }, ctx) {
return html\`<div class="${kebabCaseName}">Hello $\{name\}</div>\`;
return html\`<div class="${kebabCaseName}">Hello $\{name}</div>\`;
}
});`;
};
4 changes: 1 addition & 3 deletions packages/cli/src/templates/gitignore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { ScaffoldContext } from '../types.js';

export default ({ pascalCaseName }: ScaffoldContext) => {
export default () => {
return `node_modules/
_site/
dist/
Expand Down
2 changes: 0 additions & 2 deletions packages/cli/src/templates/jest-config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { ScaffoldContext } from '../types.js';

export default () => {
return `module.exports = {
transform: {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/templates/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('${pascalCaseName}', () => {
const mockName = 'World';
const wrapper = await mount(${pascalCaseName}, { attributes: { name: mockName } });

expect(wrapper.html()).toContain(\`Hello $\{mockName\}\`);
expect(wrapper.html()).toContain(\`Hello $\{mockName}\`);
});
});`;
};
10 changes: 5 additions & 5 deletions packages/core/src/api/context-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class TybaltContextEvent<T> implements ContextEvent<T extends UnknownContext ? a
this.#event = new CustomEvent('context-request', options);
}

NONE: 0 = 0;
CAPTURING_PHASE: 1 = 1;
AT_TARGET: 2 = 2;
BUBBLING_PHASE: 3 = 3;
NONE: 0 = 0 as const;
CAPTURING_PHASE = 1 as const;
AT_TARGET: 2 = 2 as const;
BUBBLING_PHASE: 3 = 3 as const;

get bubbles() {
return this.#event.bubbles;
Expand Down Expand Up @@ -91,7 +91,7 @@ class TybaltContextEvent<T> implements ContextEvent<T extends UnknownContext ? a
throw new Error('Method not implemented.');
}

initEvent(type: string, bubbles?: boolean | undefined, cancelable?: boolean | undefined): void {
initEvent(): void {
throw new Error('Method not implemented.');
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/api/define-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BehaviorSubject, Observable } from 'rxjs';

import ContextEvent from './context-event';

import type { DefineComponentsOptions, SetupContext, Context, UnknownContext } from '../types';
import type { DefineComponentsOptions, SetupContext } from '../types';

const nameValidator = shouldThrow(
withMessage(
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import type { SetupContext, RenderContext, PropsStateMap } from './types';

import * as components from './components';

export { SetupContext, RenderContext, PropsStateMap };

export { default as defineExample } from './api/define-example';
export { default as defineComponent } from './api/define-component';
export { default as html } from './api/html';
export { default as createContext } from './api/create-context';
export { default as ContextEvent } from './api/context-event';

/*
* It seems that esbuild doesn't parse the dependency graph to determine a correct ordering of the modules, so we
* have to export the components last to avoid errors like: TypeError: define_component_default is not a function.
*/
export * as components from './components';
3 changes: 2 additions & 1 deletion packages/core/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable */
import type { Observer } from 'rxjs';

export type PropType = String | Number | Object | Array<any>;
export type PropType = string | number | Object | Array<any>;

export type PropDefinition = {
default?: any;
Expand Down
6 changes: 6 additions & 0 deletions packages/eslint-plugin/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// eslint-disable-next-line no-undef
module.exports = {
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
};
2 changes: 0 additions & 2 deletions packages/eslint-plugin/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export default {
moduleFileExtensions: ['js', 'ts'],
extensionsToTreatAsEsm: ['.ts'],
transform: {
'^.+\\.tsx?$': 'esbuild-jest',
},
Expand Down
18 changes: 7 additions & 11 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
// @ts-ignore
import { RuleListener, RuleModule } from '@typescript-eslint/utils/ts-eslint';
import rules from './rules/index.js';
const rules = require('./rules/index.js');

const config = {
module.exports = {
rules,
configs: {
recommended: {
parserOptions: {
ecmaVersion: 2021,
},
plugins: ['@tybalt'],
env: ['browser', 'es2021'],
plugins: ['@tybalt/eslint-plugin'],
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env: { browser: true, es2021: true },
extends: ['eslint:recommended'],
rules: {
'@tybalt/component-names-are-multi-word': 'error',
},
},
'ts-recommended': {
plugins: ['@tybalt'],
plugins: ['@typescript-eslint', '@tybalt/eslint-plugin'],
parser: '@typescript-eslint/parser',
env: ['browser', 'es2021'],
extends: ['eslint:recommended'],
env: { browser: true, es2021: true },
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
rules: {
'@tybalt/component-names-are-multi-word': 'error',
},
},
},
};

export default config;
20 changes: 11 additions & 9 deletions packages/eslint-plugin/src/rules/component-names-are-multi-word.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { AST_NODE_TYPES, TSESTree, ESLintUtils } from '@typescript-eslint/utils';
import { toKebabCase } from 'js-convert-case';
import type { TSESTree } from '@typescript-eslint/types';
import type { RuleListener, RuleModule } from '@typescript-eslint/utils/ts-eslint';

import getDefinitionKey from '../utils/get-definition-key';
import { TYBALT_COMPONENT_DEFINITION } from '../utils/selectors';
import { RuleListener, RuleModule } from '@typescript-eslint/utils/ts-eslint';
const { AST_NODE_TYPES, ESLintUtils } = require('@typescript-eslint/utils');
const { toKebabCase } = require('js-convert-case');

export const RULE_NAME = 'component-names-are-multi-word';
const getDefinitionKey = require('../utils/get-definition-key');
const { TYBALT_COMPONENT_DEFINITION } = require('../utils/selectors');

const RULE_NAME = 'component-names-are-multi-word';
export type MessageIds = 'singleWordComponentName';
export type Options = [];

const createEslintRule = ESLintUtils.RuleCreator(
(name) => `https://doug-wade.github.io/tybalt/eslint-plugin/rule/${name}`,
(name: string) => `https://doug-wade.github.io/tybalt/eslint-plugin/rule/${name}`,
);

const rule: RuleModule<'singleWordComponentName', never[], RuleListener> = createEslintRule({
Expand All @@ -27,7 +29,7 @@ const rule: RuleModule<'singleWordComponentName', never[], RuleListener> = creat
},
},
defaultOptions: [],
create: (context) => {
create: (context: { report: (arg0: { messageId: string; loc: any }) => void }) => {
return {
[TYBALT_COMPONENT_DEFINITION](node: TSESTree.CallExpression) {
const definition = node.arguments[0];
Expand Down Expand Up @@ -65,4 +67,4 @@ const rule: RuleModule<'singleWordComponentName', never[], RuleListener> = creat
},
});

export default rule;
module.exports = rule;
8 changes: 2 additions & 6 deletions packages/eslint-plugin/src/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
// @ts-ignore
import { RuleListener, RuleModule } from '@typescript-eslint/utils/ts-eslint';
import componentNamesAreMultiWord from './component-names-are-multi-word.js';
const componentNamesAreMultiWord = require('./component-names-are-multi-word.js');

const config = {
module.exports = {
'component-names-are-multi-word': componentNamesAreMultiWord,
};

export default config;
9 changes: 5 additions & 4 deletions packages/eslint-plugin/src/utils/get-definition-key.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import type { TSESTree } from '@typescript-eslint/types';
const { AST_NODE_TYPES } = require('@typescript-eslint/types');

export default ({
module.exports = ({
key,
node,
}: {
Expand All @@ -13,8 +14,8 @@ export default ({
}

if (
(property.key.type === AST_NODE_TYPES.Literal && property.key.value === key) ||
(property.key.type === AST_NODE_TYPES.Identifier && property.key.name === key)
(property.key.type === AST_NODE_TYPES.Literal && (property.key as TSESTree.Literal).value === key) ||
(property.key.type === AST_NODE_TYPES.Identifier && (property.key as TSESTree.Identifier).name === key)
) {
return property;
}
Expand Down
7 changes: 5 additions & 2 deletions packages/eslint-plugin/src/utils/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export const TYBALT_COMPONENT_DEFINITION =
'CallExpression[callee.name="defineComponent"]'
const TYBALT_COMPONENT_DEFINITION = 'CallExpression[callee.name="defineComponent"]';

module.exports = {
TYBALT_COMPONENT_DEFINITION,
};
1 change: 0 additions & 1 deletion packages/eslint-plugin/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"module": "commonjs",
"sourceMap": false,
"outDir": "dist",
"esModuleInterop": true,
"moduleResolution": "node16",
"forceConsistentCasingInFileNames": true,
"strict": true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule, { MessageIds, RULE_NAME } from '../src/rules/component-names-are-multi-word';
/* eslint-disable no-undef */

const ruleTester: RuleTester = new RuleTester({
const { RuleTester } = require('@typescript-eslint/rule-tester');
const rule = require('../src/rules/component-names-are-multi-word');

const ruleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
});

const messageId: MessageIds = 'singleWordComponentName';
const messageId = 'singleWordComponentName';

ruleTester.run(RULE_NAME, rule, {
ruleTester.run('component-names-are-multi-word', rule, {
valid: [
`
export default defineComponent({
Expand Down
2 changes: 2 additions & 0 deletions packages/test-utils/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-var */

declare module globalThis {
var customElementsRegistry: Map<string, CustomElementConstructor>;
var customElementsReverseRegistry: Map<CustomElementConstructor, string>;
Expand Down
6 changes: 3 additions & 3 deletions packages/test-utils/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export type AttributeObject = Object<string, number | string>;
export type AttributeObject = NonNullable<string, number | string>;

type DOMTokenListOrBoolean<T> = T extends string ? boolean | null : Array<string>;
type NamedNodeMapOrString<T> = T extends string ? string | null | never : Object;
type NamedNodeMapOrString<T> = T extends string ? string | null | never : NonNullable<unknown>;

export interface Wrapper {
length: Number;
length: number;
find(selector: string): Wrapper | never;
findAll(selector: string): Wrapper | never;
findComponent(definition: CustomElementConstructor): Wrapper | never;
Expand Down
6 changes: 3 additions & 3 deletions packages/test-utils/src/util/base-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const reassignSlot = (element: Element): Element => {
return clone;
};

const stringifyElement = (element: Element): String => {
const stringifyElement = (element: Element): string => {
if (element.tagName === 'SLOT') {
element = reassignSlot(element);
}
Expand All @@ -47,15 +47,15 @@ const stringifyElement = (element: Element): String => {
return `${openingTag}>${children}${closingTag}>`;
};

const stringifyShadowRoot = (shadowRoot: ShadowRoot): String => {
const stringifyShadowRoot = (shadowRoot: ShadowRoot): string => {
return Array.from(shadowRoot.children).reduce((acc, childElement) => {
return acc + stringifyElement(childElement);
}, '');
};

export default class BaseWrapper implements Wrapper {
element: Element;
get length(): Number {
get length(): number {
return 1;
}

Expand Down
Loading