diff --git a/apps/wing/.eslintrc.json b/apps/wing/.eslintrc.json new file mode 100644 index 00000000000..a32a468f78c --- /dev/null +++ b/apps/wing/.eslintrc.json @@ -0,0 +1,134 @@ +{ + "env": { + "jest": true, + "node": true + }, + "root": true, + "plugins": [ + "@typescript-eslint", + "import", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "extends": [ + "plugin:import/typescript", + "prettier", + "plugin:prettier/recommended" + ], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [ + ".ts", + ".tsx" + ] + }, + "import/resolver": { + "node": {}, + "typescript": { + "project": "./tsconfig.json", + "alwaysTryTypes": true + } + } + }, + "ignorePatterns": [ + "*.js", + "*.d.ts", + "node_modules/", + "*.generated.ts", + "coverage", + "!.projenrc.ts", + "!projenrc/**/*.ts" + ], + "rules": { + "prettier/prettier": [ + "error" + ], + "@typescript-eslint/no-require-imports": [ + "error" + ], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": [ + "**/test/**", + "**/build-tools/**", + "src/**", + ".projenrc.ts", + "projenrc/**/*.ts" + ], + "optionalDependencies": false, + "peerDependencies": true + } + ], + "import/no-unresolved": [ + "error" + ], + "import/order": [ + "warn", + { + "groups": [ + "builtin", + "external" + ], + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "no-duplicate-imports": [ + "error" + ], + "no-shadow": [ + "off" + ], + "@typescript-eslint/no-shadow": [ + "error" + ], + "key-spacing": [ + "error" + ], + "no-multiple-empty-lines": [ + "error" + ], + "@typescript-eslint/no-floating-promises": [ + "error" + ], + "no-return-await": [ + "off" + ], + "@typescript-eslint/return-await": [ + "error" + ], + "no-trailing-spaces": [ + "error" + ], + "dot-notation": [ + "error" + ], + "no-bitwise": [ + "error" + ], + "@typescript-eslint/member-ordering": [ + "error", + { + "default": [ + "public-static-field", + "public-static-method", + "protected-static-field", + "protected-static-method", + "private-static-field", + "private-static-method", + "field", + "constructor", + "method" + ] + } + ] + } +} diff --git a/apps/wing/package.json b/apps/wing/package.json index e08b4ff59fc..ab264dfdcce 100644 --- a/apps/wing/package.json +++ b/apps/wing/package.json @@ -21,6 +21,7 @@ }, "scripts": { "build": "tsc && pnpm copy-root-readme", + "eslint": "eslint --ext .ts src", "compile": "tsc", "copy-root-readme": "cp ../../README.md ./README.md && pnpm copy-root-assets", "copy-root-assets": "cp ../../logo/demo.gif ./logo/demo.gif", @@ -53,8 +54,16 @@ "@types/node-persist": "^3.1.4", "@types/semver-utils": "^1.1.1", "@types/uuid": "^8.3.4", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.7.4", "bump-pack": "workspace:^", "esbuild": "^0.17.19", + "eslint": "^8.50.0", + "eslint-config-prettier": "^8.10.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-import-resolver-typescript": "^3.6.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-prettier": "^4.2.1", "typescript": "^4.9.5", "vitest": "^0.30.1" }, diff --git a/apps/wing/src/analytics/collect.ts b/apps/wing/src/analytics/collect.ts index 4fce17a296c..8685c917983 100644 --- a/apps/wing/src/analytics/collect.ts +++ b/apps/wing/src/analytics/collect.ts @@ -1,16 +1,15 @@ import { Command } from "commander"; -import { AnalyticEvent } from "./event"; -import { OSCollector } from "./collectors/os-collector"; -import { NodeCollector } from "./collectors/node-collector"; -import { CLICollector } from "./collectors/cli-collector"; import { CICollector } from "./collectors/ci-collector"; -import { AnalyticsStorage } from "./storage"; +import { CLICollector } from "./collectors/cli-collector"; import { GitCollector } from "./collectors/git-collector"; - +import { NodeCollector } from "./collectors/node-collector"; +import { OSCollector } from "./collectors/os-collector"; +import { AnalyticEvent } from "./event"; +import { AnalyticsStorage } from "./storage"; /** * Collects analytics for a given command, stores it for later export - * + * * @param cmd The commander command to collect analytics for * @returns string the file path of the stored analytic */ @@ -23,11 +22,11 @@ export async function collectCommandAnalytics(cmd: Command): Promise 0 ? cmd.args[0] : '.' + appEntrypoint: cmd.args.length > 0 ? cmd.args[0] : ".", }); - - const eventName = `cli_${cmd.opts().target ?? ''}_${cmd.name()}`; - + + const eventName = `cli_${cmd.opts().target ?? ""}_${cmd.name()}`; + let event: AnalyticEvent = { event: eventName.replace(/[^a-zA-Z_]/g, ""), properties: { @@ -35,13 +34,12 @@ export async function collectCommandAnalytics(cmd: Command): Promise { const originialEnvironment = process.env; beforeEach(() => { - // Restore the environment back to where it was before any of the + // Restore the environment back to where it was before any of the // tests manipulated it - process.env = { ...originialEnvironment } + process.env = { ...originialEnvironment }; }); test("should return undefined when no ci environment is detected", async () => { @@ -20,7 +20,7 @@ describe("ci collector tests", () => { // THEN expect(ciData).toBeUndefined(); - }) + }); describe("should return correct CI environment name", () => { let collector: CICollector; @@ -36,7 +36,7 @@ describe("ci collector tests", () => { process.env.GITHUB_ACTIONS = "1"; // THEN - expect(await collector.collect()).toEqual({name: "GITHUB_ACTIONS"}) + expect(await collector.collect()).toEqual({ name: "GITHUB_ACTIONS" }); }); test("when in Gitlab ci", async () => { @@ -44,7 +44,7 @@ describe("ci collector tests", () => { process.env.GITLAB_CI = "1"; // THEN - expect(await collector.collect()).toEqual({name: "GITLAB_CI"}) + expect(await collector.collect()).toEqual({ name: "GITLAB_CI" }); }); test("when in Jekins", async () => { @@ -52,7 +52,7 @@ describe("ci collector tests", () => { process.env.JENKINS_URL = "1"; // THEN - expect(await collector.collect()).toEqual({name: "JENKINS"}) + expect(await collector.collect()).toEqual({ name: "JENKINS" }); }); test("when in Circleci", async () => { @@ -60,7 +60,7 @@ describe("ci collector tests", () => { process.env.CIRCLECI = "1"; // THEN - expect(await collector.collect()).toEqual({name: "CIRCLECI"}) + expect(await collector.collect()).toEqual({ name: "CIRCLECI" }); }); test("when in Bitbucket", async () => { @@ -68,7 +68,7 @@ describe("ci collector tests", () => { process.env.BITBUCKET_BUILD_NUMBER = "1"; // THEN - expect(await collector.collect()).toEqual({name: "BITBUCKET"}) + expect(await collector.collect()).toEqual({ name: "BITBUCKET" }); }); test("when in Azure Devops", async () => { @@ -76,7 +76,7 @@ describe("ci collector tests", () => { process.env.BUILD_BUILDID = "1"; // THEN - expect(await collector.collect()).toEqual({name: "AZURE_DEVOPS"}) + expect(await collector.collect()).toEqual({ name: "AZURE_DEVOPS" }); }); test("when in Teamcity", async () => { @@ -84,7 +84,7 @@ describe("ci collector tests", () => { process.env.TEAMCITY_VERSION = "1"; // THEN - expect(await collector.collect()).toEqual({name: "TEAMCITY"}) + expect(await collector.collect()).toEqual({ name: "TEAMCITY" }); }); test("when in AWS Codebuild", async () => { @@ -92,7 +92,7 @@ describe("ci collector tests", () => { process.env.CODEBUILD_BUILD_ID = "1"; // THEN - expect(await collector.collect()).toEqual({name: "CODEBUILD"}) + expect(await collector.collect()).toEqual({ name: "CODEBUILD" }); }); - }) -}); \ No newline at end of file + }); +}); diff --git a/apps/wing/src/analytics/collectors/ci-collector.ts b/apps/wing/src/analytics/collectors/ci-collector.ts index 914d6689f77..3af5129f934 100644 --- a/apps/wing/src/analytics/collectors/ci-collector.ts +++ b/apps/wing/src/analytics/collectors/ci-collector.ts @@ -5,7 +5,7 @@ export interface CIData { } // Map of CI environment variable identifiers to CI names -const CI_ENV: {[key: string]: string} = { +const CI_ENV: { [key: string]: string } = { // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables GITHUB_ACTIONS: "GITHUB_ACTIONS", // https://docs.gitlab.com/ee/ci/variables/predefined_variables.html @@ -22,15 +22,15 @@ const CI_ENV: {[key: string]: string} = { TEAMCITY_VERSION: "TEAMCITY", // https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-variables.html CODEBUILD_BUILD_ID: "CODEBUILD", -} +}; export class CICollector extends Collector { async collect(): Promise { for (const e in CI_ENV) { if (e in process.env) { - return {name: CI_ENV[`${e}`]} + return { name: CI_ENV[`${e}`] }; } } return undefined; } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/collectors/cli-collector.ts b/apps/wing/src/analytics/collectors/cli-collector.ts index d55d6c47d21..0b85e1b9f44 100644 --- a/apps/wing/src/analytics/collectors/cli-collector.ts +++ b/apps/wing/src/analytics/collectors/cli-collector.ts @@ -25,15 +25,16 @@ export class CLICollector extends Collector { options: `${JSON.stringify(this.cmd.opts())}`, version: PACKAGE_VERSION, wing_sdk_version: this.tryGetModuleVersion("@winglang/sdk/package.json"), - wing_console_version: this.tryGetModuleVersion(`@wingconsole/app/package.json`) - } + wing_console_version: this.tryGetModuleVersion(`@wingconsole/app/package.json`), + }; } private tryGetModuleVersion(module: string): string | undefined { try { + // eslint-disable-next-line @typescript-eslint/no-require-imports return require(module).version as string; } catch (error) { return undefined; } } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/collectors/collector.ts b/apps/wing/src/analytics/collectors/collector.ts index ec2b968e419..78e4deab85a 100644 --- a/apps/wing/src/analytics/collectors/collector.ts +++ b/apps/wing/src/analytics/collectors/collector.ts @@ -7,7 +7,7 @@ export interface Data { export abstract class Collector { abstract collect(): Promise; - protected async runCommand(cmd: string, args: string[], dir: string = '.'): Promise { + protected async runCommand(cmd: string, args: string[], dir: string = "."): Promise { try { const raw = await new Promise((resolve, reject) => { execFile(cmd, args, { cwd: dir }, (error, stdout, stderr) => { @@ -25,4 +25,4 @@ export abstract class Collector { return ""; } } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/collectors/git-collector.test.ts b/apps/wing/src/analytics/collectors/git-collector.test.ts index 9188b250e48..cca78fa2faf 100644 --- a/apps/wing/src/analytics/collectors/git-collector.test.ts +++ b/apps/wing/src/analytics/collectors/git-collector.test.ts @@ -1,15 +1,15 @@ -import { afterEach, describe, expect, test } from "vitest"; -import { GitCollector } from "./git-collector"; -import path from "path"; -import * as os from "os"; -import fs from "fs"; import { execFile } from "child_process"; import { createHash } from "crypto"; +import fs from "fs"; +import * as os from "os"; +import path from "path"; +import { afterEach, describe, expect, test } from "vitest"; +import { GitCollector } from "./git-collector"; describe("git collector tests", () => { afterEach(() => { clearCreatedRepos(); - }) + }); test("should return undefined if not in git repo", async () => { // GIVEN @@ -25,8 +25,8 @@ describe("git collector tests", () => { test("should return git data if in git repo", async () => { // GIVEN - const expectedRemoteUrl = "https://super-fake.com/test.git" - const expectedAnonymousRepoId = createHash('md5').update(expectedRemoteUrl).digest('hex'); + const expectedRemoteUrl = "https://super-fake.com/test.git"; + const expectedAnonymousRepoId = createHash("md5").update(expectedRemoteUrl).digest("hex"); const repoPath = await createFakeRepo("git-1", { remoteUrl: expectedRemoteUrl }); const collector = new GitCollector({ appEntrypoint: `${repoPath}/app.w` }); @@ -41,11 +41,11 @@ describe("git collector tests", () => { let createdRepoPaths: string[] = []; const clearCreatedRepos = () => { - createdRepoPaths.forEach(r => { - fs.rmSync(r, {recursive: true, force: true}) - }) + createdRepoPaths.forEach((r) => { + fs.rmSync(r, { recursive: true, force: true }); + }); createdRepoPaths = []; -} +}; interface FakeGitRepoProps { remoteUrl: string; @@ -53,9 +53,9 @@ interface FakeGitRepoProps { async function createFakeRepo(name: string, props?: FakeGitRepoProps): Promise { const repoPath = path.join(os.tmpdir(), "wing-git-collector-test", name); - - fs.mkdirSync(repoPath, { recursive: true}); - + + fs.mkdirSync(repoPath, { recursive: true }); + if (props) { await initializeGitRepo(repoPath, props); } @@ -77,7 +77,7 @@ async function runCommand(cmd: string, args: string[], dir: string): Promise { if (await this.isInGitRepo()) { const remoteUrl = await this.getRemoteUrl(); if (remoteUrl) { return { - anonymous_repo_id: createHash('md5').update(remoteUrl).digest('hex') - } + anonymous_repo_id: createHash("md5").update(remoteUrl).digest("hex"), + }; } } return undefined; } async isInGitRepo(): Promise { - const results = await this.runCommand('git', ['rev-parse', '--is-inside-work-tree'], this.dir); - return results.trim() === 'true'; + const results = await this.runCommand("git", ["rev-parse", "--is-inside-work-tree"], this.dir); + return results.trim() === "true"; } async getRemoteUrl(): Promise { - const results = await this.runCommand('git', ['config', '--get', 'remote.origin.url'], this.dir); + const results = await this.runCommand( + "git", + ["config", "--get", "remote.origin.url"], + this.dir + ); return results.trim(); } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/collectors/node-collector.ts b/apps/wing/src/analytics/collectors/node-collector.ts index dd1cf299da9..d80421b934e 100644 --- a/apps/wing/src/analytics/collectors/node-collector.ts +++ b/apps/wing/src/analytics/collectors/node-collector.ts @@ -8,6 +8,6 @@ export class NodeCollector extends Collector { async collect(): Promise { return { version: process.version, - } + }; } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/collectors/os-collector.ts b/apps/wing/src/analytics/collectors/os-collector.ts index 154aa89aa6f..27cae05aa45 100644 --- a/apps/wing/src/analytics/collectors/os-collector.ts +++ b/apps/wing/src/analytics/collectors/os-collector.ts @@ -1,5 +1,5 @@ -import { Collector } from "./collector"; import os from "os"; +import { Collector } from "./collector"; export interface OSData { arch: string; @@ -13,6 +13,6 @@ export class OSCollector extends Collector { arch: os.arch(), platform: os.platform(), release: os.release(), - } + }; } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/disclaimer.test.ts b/apps/wing/src/analytics/disclaimer.test.ts index 9fd3766286e..449467d41d6 100644 --- a/apps/wing/src/analytics/disclaimer.test.ts +++ b/apps/wing/src/analytics/disclaimer.test.ts @@ -1,15 +1,19 @@ -import {test, expect, describe, beforeEach, afterEach, vi} from "vitest"; -import { AnalyticsStorage } from "./storage"; -import path from "path"; -import * as os from "os"; -import { WING_DISCLAIMER, WING_DISCLAIMER_VERSION, optionallyDisplayDisclaimer, shouldDisplayDisclaimer } from "./disclaimer"; import { existsSync, unlinkSync } from "fs"; - +import * as os from "os"; +import path from "path"; +import { test, expect, describe, beforeEach, afterEach, vi } from "vitest"; +import { + WING_DISCLAIMER, + WING_DISCLAIMER_VERSION, + optionallyDisplayDisclaimer, + shouldDisplayDisclaimer, +} from "./disclaimer"; +import { AnalyticsStorage } from "./storage"; describe("disclaimer", () => { const originalTTY = process.stdin.isTTY; const nonExistentFile = path.join(os.tmpdir(), "_)(*noWayThis_file_exists%$#@.json"); - + beforeEach(() => { if (existsSync(nonExistentFile)) { unlinkSync(nonExistentFile); @@ -32,47 +36,49 @@ describe("disclaimer", () => { test("appears on first run", () => { // GIVEN - const storage = new AnalyticsStorage({configFile: nonExistentFile}); - + const storage = new AnalyticsStorage({ configFile: nonExistentFile }); + // WHEN optionallyDisplayDisclaimer(storage); - + // THEN - expect(console.log).toHaveBeenCalledWith(expect.stringContaining(WING_DISCLAIMER.split("\n")[0])); + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining(WING_DISCLAIMER.split("\n")[0]) + ); }); - + test("alters config value for displayed", () => { // GIVEN - const storage = new AnalyticsStorage({configFile: nonExistentFile}); - storage.saveConfig({anonymousId: "fake-id", disclaimerDisplayed: false}); - + const storage = new AnalyticsStorage({ configFile: nonExistentFile }); + storage.saveConfig({ anonymousId: "fake-id", disclaimerDisplayed: false }); + // WHEN optionallyDisplayDisclaimer(storage); - + // THEN expect(storage.loadConfig().disclaimerDisplayed).toBe(true); }); - + test("alters displayed version", () => { - // GIVEN - const storage = new AnalyticsStorage({configFile: nonExistentFile}); - storage.saveConfig({anonymousId: "fake-id", disclaimerDisplayed: false}); - - // WHEN + // GIVEN + const storage = new AnalyticsStorage({ configFile: nonExistentFile }); + storage.saveConfig({ anonymousId: "fake-id", disclaimerDisplayed: false }); + + // WHEN optionallyDisplayDisclaimer(storage); - + // THEN expect(storage.loadConfig().disclaimerVersion).toBe(WING_DISCLAIMER_VERSION); - }) - + }); + test("does not appear on second run", () => { // GIVEN - const storage = new AnalyticsStorage({configFile: nonExistentFile}); - + const storage = new AnalyticsStorage({ configFile: nonExistentFile }); + // WHEN optionallyDisplayDisclaimer(storage); optionallyDisplayDisclaimer(storage); - + // THEN expect(console.log).toHaveBeenCalledTimes(1); }); @@ -81,37 +87,42 @@ describe("disclaimer", () => { test("returns true if config is empty", () => { expect(shouldDisplayDisclaimer({} as any)).toBe(true); }); - + test("returns true if version is not set", () => { - expect(shouldDisplayDisclaimer({ - anonymousId: "fake-id", - disclaimerDisplayed: true - })).toBe(true); + expect( + shouldDisplayDisclaimer({ + anonymousId: "fake-id", + disclaimerDisplayed: true, + }) + ).toBe(true); }); - + test("returns true if version is not current", () => { - expect(shouldDisplayDisclaimer({ - anonymousId: "fake-id", - disclaimerDisplayed: true, - disclaimerVersion: "-100.0.0" - })).toBe(true); + expect( + shouldDisplayDisclaimer({ + anonymousId: "fake-id", + disclaimerDisplayed: true, + disclaimerVersion: "-100.0.0", + }) + ).toBe(true); }); - + test("return false if displayed version is current", () => { - expect(shouldDisplayDisclaimer({ - anonymousId: "fake-id", - disclaimerDisplayed: true, - disclaimerVersion: WING_DISCLAIMER_VERSION - })).toBe(false); - }) + expect( + shouldDisplayDisclaimer({ + anonymousId: "fake-id", + disclaimerDisplayed: true, + disclaimerVersion: WING_DISCLAIMER_VERSION, + }) + ).toBe(false); + }); }); - }) + }); describe("behavior when not in TTY", () => { - beforeEach(() => { process.stdin.isTTY = false; - }) + }); afterEach(() => { process.stdin.isTTY = originalTTY; @@ -119,8 +130,8 @@ describe("disclaimer", () => { test("does not alter config value for displayed", () => { // GIVEN - const storage = new AnalyticsStorage({configFile: nonExistentFile}); - storage.saveConfig({anonymousId: "fake-id", disclaimerDisplayed: false}); + const storage = new AnalyticsStorage({ configFile: nonExistentFile }); + storage.saveConfig({ anonymousId: "fake-id", disclaimerDisplayed: false }); // WHEN optionallyDisplayDisclaimer(storage); @@ -130,7 +141,7 @@ describe("disclaimer", () => { }); test("returns false if no matter the config", () => { - expect(shouldDisplayDisclaimer({} as any )).toBe(false); + expect(shouldDisplayDisclaimer({} as any)).toBe(false); }); }); -}) +}); diff --git a/apps/wing/src/analytics/disclaimer.ts b/apps/wing/src/analytics/disclaimer.ts index cb976580128..aafaf081e05 100644 --- a/apps/wing/src/analytics/disclaimer.ts +++ b/apps/wing/src/analytics/disclaimer.ts @@ -13,8 +13,8 @@ chance you'll encounter missing pieces, rough edges, performance issues and even god forbid, bugs 🐞. Please don't hesitate to ping us at ${chalk.blueBright.bold.underline( - "https://t.winglang.io/slack" - )} or file an issue at + "https://t.winglang.io/slack" +)} or file an issue at ${chalk.blueBright.bold.underline( "https://github.com/winglang/wing" )}. We promise to do our best to respond quickly and help out. @@ -59,8 +59,8 @@ export function optionallyDisplayDisclaimer(existingStorage?: AnalyticsStorage) storage.saveConfig(analyticsConfig); } } catch (error) { - // Incase there was any reason the config could not be loaded, + // Incase there was any reason the config could not be loaded, // just display to be super transparent :) displayDisclaimer(); } -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/event.ts b/apps/wing/src/analytics/event.ts index 56778994a83..95fd957fcb0 100644 --- a/apps/wing/src/analytics/event.ts +++ b/apps/wing/src/analytics/event.ts @@ -13,5 +13,5 @@ export interface AnalyticEvent { os: OSData; node: NodeData; ci?: CIData; - } + }; } diff --git a/apps/wing/src/analytics/export.ts b/apps/wing/src/analytics/export.ts index 8fe670b0a14..296d74f93e8 100644 --- a/apps/wing/src/analytics/export.ts +++ b/apps/wing/src/analytics/export.ts @@ -1,4 +1,4 @@ -import { spawn } from 'child_process'; +import { spawn } from "child_process"; export async function exportAnalytics(filePath: Promise) { const awaitedFilePath = await filePath; @@ -6,15 +6,19 @@ export async function exportAnalytics(filePath: Promise) { if (!awaitedFilePath || process.env.WING_DISABLE_ANALYTICS) { return; } - - const child = spawn(process.execPath, [require.resolve('./scripts/detached-export'), awaitedFilePath], { - detached: true, - stdio: 'ignore', - windowsHide: true, - env: { - ...process.env, + + const child = spawn( + process.execPath, + [require.resolve("./scripts/detached-export"), awaitedFilePath], + { + detached: true, + stdio: "ignore", + windowsHide: true, + env: { + ...process.env, + }, } - }); + ); child.unref(); -} \ No newline at end of file +} diff --git a/apps/wing/src/analytics/scripts/detached-export.ts b/apps/wing/src/analytics/scripts/detached-export.ts index 290053dc8d4..7c2586c3985 100644 --- a/apps/wing/src/analytics/scripts/detached-export.ts +++ b/apps/wing/src/analytics/scripts/detached-export.ts @@ -1,20 +1,20 @@ -import { AnalyticsStorage } from '../storage'; -import * as fs from 'fs'; -import Analytics from '@segment/analytics-node'; -import { exit } from 'process'; +import * as fs from "fs"; +import { exit } from "process"; +import Analytics from "@segment/analytics-node"; +import { AnalyticsStorage } from "../storage"; -// When this file is run as a child process, it will be passed the path +// When this file is run as a child process, it will be passed the path // to the analytics report file const filePath = process.argv[2]; -const segmentWriteKey = 'sCqPF5xSscOjJdi5Tbkqu73vfF8zkZdw' +const segmentWriteKey = "sCqPF5xSscOjJdi5Tbkqu73vfF8zkZdw"; // This debug write key is used to send events to a debug source in segment // the purpose is to make life easier for testing analytics changes without // sifting through real data. The only time we export metrics to the debug source // is if the DEBUG env var is set AND the WING_ANALYTICS_FORCE_EXPORT env var is set // this way when just running with DEBUG flag we can see analytic event files on disk -const segmentDebugWriteKey = '6r9ySJHdUGkDO80X8i4h2pGGHxYRwFe2' +const segmentDebugWriteKey = "6r9ySJHdUGkDO80X8i4h2pGGHxYRwFe2"; async function reportAnalytic() { if (process.env.DEBUG && !process.env.WING_ANALYTICS_FORCE_EXPORT) { @@ -23,10 +23,12 @@ async function reportAnalytic() { } if (!filePath) { - throw new Error('No file analytic path provided'); + throw new Error("No file analytic path provided"); } - const analytics = new Analytics({ writeKey: process.env.DEBUG ? segmentDebugWriteKey : segmentWriteKey}); + const analytics = new Analytics({ + writeKey: process.env.DEBUG ? segmentDebugWriteKey : segmentWriteKey, + }); const storage = new AnalyticsStorage(); const event = storage.loadEvent(filePath); @@ -39,7 +41,7 @@ async function reportAnalytic() { timestamp: event.timestamp, event: event.event, properties: event.properties, - } + }; const awaitTrack = async () => { return new Promise((resolve, reject) => { @@ -51,17 +53,17 @@ async function reportAnalytic() { } }); }); - } - + }; + await awaitTrack(); fs.unlinkSync(filePath); } -(async () => { +await (async () => { try { await reportAnalytic(); - } catch(err: any) { + } catch (err: any) { // TODO: add mechanism to retry maybe } -})(); \ No newline at end of file +})(); diff --git a/apps/wing/src/analytics/storage.test.ts b/apps/wing/src/analytics/storage.test.ts index 4c200a5aa83..e7c1e6a6fff 100644 --- a/apps/wing/src/analytics/storage.test.ts +++ b/apps/wing/src/analytics/storage.test.ts @@ -1,113 +1,113 @@ -import {describe, test, expect } from "vitest"; -import { AnalyticEvent } from "./event"; -import { AnalyticsConfig, AnalyticsStorage } from "./storage"; import { existsSync, mkdirSync, writeFileSync } from "fs"; -import path from "path"; import * as os from "os"; +import path from "path"; +import { describe, test, expect } from "vitest"; +import { AnalyticEvent } from "./event"; +import { AnalyticsConfig, AnalyticsStorage } from "./storage"; -describe( - "storage tests", - () => { - const DUMMY_ANALYTIC: AnalyticEvent = { - event: "some fake:event", - properties: { - cli: { - options: "\{\"-t\": \"fake-aws\"\}", - target: "fake-aws", - version: "4.2.0", - wing_console_version: "1.2.3", - wing_sdk_version: "4.5.6" - }, - os: { - arch: "x64", - platform: "xbox", - release: "360", - }, - node: { - version: "a million", - } - } - } +describe("storage tests", () => { + const DUMMY_ANALYTIC: AnalyticEvent = { + event: "some fake:event", + properties: { + cli: { + options: '{"-t": "fake-aws"}', + target: "fake-aws", + version: "4.2.0", + wing_console_version: "1.2.3", + wing_sdk_version: "4.5.6", + }, + os: { + arch: "x64", + platform: "xbox", + release: "360", + }, + node: { + version: "a million", + }, + }, + }; - describe("when analytics is opt-in", () => { - const fakeAnalyticConfig = { - optOut: false, - anonymousId: "fake-anonymous-id", - } as AnalyticsConfig; + describe("when analytics is opt-in", () => { + const fakeAnalyticConfig = { + optOut: false, + anonymousId: "fake-anonymous-id", + } as AnalyticsConfig; - test("anonymous id should not be included if in CI environment", () => { - // GIVEN - process.env.GITHUB_ACTION = "1"; - const storage = createStorageWithFakeConfig({} as any, "opt-in-1"); + test("anonymous id should not be included if in CI environment", () => { + // GIVEN + process.env.GITHUB_ACTION = "1"; + const storage = createStorageWithFakeConfig({} as any, "opt-in-1"); - // WHEN - const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); - const storedAnalytic = storage.loadEvent(analyticPath!); + // WHEN + const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); + const storedAnalytic = storage.loadEvent(analyticPath!); - // THEN - expect(analyticPath).toBeDefined(); - expect(storedAnalytic).not.toHaveProperty("anonymousId"); - }); + // THEN + expect(analyticPath).toBeDefined(); + expect(storedAnalytic).not.toHaveProperty("anonymousId"); + }); + + test("should store analytic with flattened properties and return correct filepath", async () => { + // WHEN + const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-in-2"); + const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); + const storedAnalytic = storage.loadEvent(analyticPath!); - test("should store analytic with flattened properties and return correct filepath", async () => { - // WHEN - const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-in-2"); - const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); - const storedAnalytic = storage.loadEvent(analyticPath!); - - // THEN - expect(analyticPath).toBeDefined(); - expect(storedAnalytic).toEqual(expect.objectContaining({ + // THEN + expect(analyticPath).toBeDefined(); + expect(storedAnalytic).toEqual( + expect.objectContaining({ event: DUMMY_ANALYTIC.event, properties: { - "cli_target": "fake-aws", - "cli_version": "4.2.0", - "cli_options": "\{\"-t\": \"fake-aws\"\}", - "cli_wing_console_version": "1.2.3", - "cli_wing_sdk_version": "4.5.6", - "os_arch": "x64", - "os_platform": "xbox", - "os_release": "360", - "node_version": "a million" - } - })); - }); + cli_target: "fake-aws", + cli_version: "4.2.0", + cli_options: '{"-t": "fake-aws"}', + cli_wing_console_version: "1.2.3", + cli_wing_sdk_version: "4.5.6", + os_arch: "x64", + os_platform: "xbox", + os_release: "360", + node_version: "a million", + }, + }) + ); + }); - test("can retrieve anonymous id", () => { - const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-in-3"); - expect(storage.getAnonymousId()).toBe("fake-anonymous-id"); - }); + test("can retrieve anonymous id", () => { + const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-in-3"); + expect(storage.getAnonymousId()).toBe("fake-anonymous-id"); }); + }); + describe("when analytics is opt-out", () => { + const fakeAnalyticConfig: AnalyticsConfig = { + optOut: true, + anonymousId: "fake-anonymous-id", + }; - describe("when analytics is opt-out", () => { - const fakeAnalyticConfig: AnalyticsConfig = { - optOut: true, - anonymousId: "fake-anonymous-id" - } + const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-out-1"); - const storage = createStorageWithFakeConfig(fakeAnalyticConfig, "opt-out-1"); - - test("does not store analytic", async () => { - // WHEN - const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); - const analytic = storage.loadEvent(analyticPath!); - - // THEN - expect(analyticPath).toBeUndefined(); - expect(analytic).toBeUndefined(); - }); - }); + test("does not store analytic", async () => { + // WHEN + const analyticPath = storage.storeAnalyticEvent(DUMMY_ANALYTIC); + const analytic = storage.loadEvent(analyticPath!); - } -); + // THEN + expect(analyticPath).toBeUndefined(); + expect(analytic).toBeUndefined(); + }); + }); +}); -export function createStorageWithFakeConfig(config: AnalyticsConfig, dirName: string): AnalyticsStorage { +export function createStorageWithFakeConfig( + config: AnalyticsConfig, + dirName: string +): AnalyticsStorage { const tmpDir = path.join(os.tmpdir(), dirName); const configFile = path.join(tmpDir, "analytics-fake-config.json"); if (!existsSync(tmpDir)) { mkdirSync(tmpDir); } writeFileSync(configFile, JSON.stringify(config)); - return new AnalyticsStorage({configFile: configFile, analyticsStorageDir: tmpDir}); -} \ No newline at end of file + return new AnalyticsStorage({ configFile: configFile, analyticsStorageDir: tmpDir }); +} diff --git a/apps/wing/src/analytics/storage.ts b/apps/wing/src/analytics/storage.ts index 0b57e64b509..1210d380e15 100644 --- a/apps/wing/src/analytics/storage.ts +++ b/apps/wing/src/analytics/storage.ts @@ -1,11 +1,11 @@ -import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs"; -import { AnalyticEvent } from "./event"; import { randomBytes } from "crypto"; -import {v4 as uuidv4 } from "uuid"; -import path from "path"; +import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs"; import * as os from "os"; +import path from "path"; +import { v4 as uuidv4 } from "uuid"; +import { AnalyticEvent } from "./event"; -const WING_HOME_DIR = path.join(os.homedir(), ".wing") +const WING_HOME_DIR = path.join(os.homedir(), ".wing"); /** * AnalyticsConfig is the configuration for the analytics collection @@ -25,7 +25,7 @@ export interface AnalyticsConfig { * Props for AnalyticsStorage, mostly used for testing and debugging */ interface AnalyticsStorageProps { - /** + /** * directory to store * @default path.join(os.tmpdir(), "wing-analytics") */ @@ -53,15 +53,17 @@ export class AnalyticsStorage { debug?: boolean; constructor(props?: AnalyticsStorageProps) { - this.analyticsConfigFile = props?.configFile ?? path.join(path.join(WING_HOME_DIR, 'wing-analytics-config.json')); - this.analyticsStorageDir = props?.analyticsStorageDir ?? path.join(os.tmpdir(), "wing-analytics"); + this.analyticsConfigFile = + props?.configFile ?? path.join(path.join(WING_HOME_DIR, "wing-analytics-config.json")); + this.analyticsStorageDir = + props?.analyticsStorageDir ?? path.join(os.tmpdir(), "wing-analytics"); this.debug = props?.debug; this.analyticsConfig = this.loadConfig(); } /** * Stores a single analytic event to disk - * + * * @param event the analytic event to save * @returns the path to the saved event or undefined if there was an error */ @@ -71,17 +73,16 @@ export class AnalyticsStorage { return undefined; } const eventId = uuidv4(); - + if (!existsSync(this.analyticsStorageDir)) { mkdirSync(this.analyticsStorageDir); } - + const analyticReportFile = path.join(this.analyticsStorageDir, `${eventId}.json`); - - + // attach timestamp and anonymousId to event event.timestamp = event.timestamp ?? new Date().toISOString(); - + // We add the anonymousId only if we are not in a CI environment if (event.properties.ci) { const anonymousId = this.getAnonymousId(); @@ -89,9 +90,8 @@ export class AnalyticsStorage { } this.saveEvent(analyticReportFile, event); - + return analyticReportFile; - } catch (error) { return undefined; } @@ -99,13 +99,13 @@ export class AnalyticsStorage { /** * Retrieves an analytic event from disk - * + * * @param filePath the path the event was saved to * @returns the event or undefined if there was an error */ public loadEvent(filePath: string): AnalyticEvent | undefined { try { - const fileContents = readFileSync(filePath, 'utf-8'); + const fileContents = readFileSync(filePath, "utf-8"); return JSON.parse(fileContents) as AnalyticEvent; } catch (error) { // ignore @@ -114,9 +114,9 @@ export class AnalyticsStorage { } /** - * Reads the analytics config for the user's anonymous id, + * Reads the analytics config for the user's anonymous id, * if an id does not exist, one is generated and saved to disk - * + * * @returns the anonymous id for the user */ public getAnonymousId(): string { @@ -128,40 +128,39 @@ export class AnalyticsStorage { return config.anonymousId; } - private generateAnonymousId(): string { - return randomBytes(16).toString('hex'); + return randomBytes(16).toString("hex"); } /** * Retrieves the analytics config from disk, if one does not exist * a new one is created and saved to disk - * + * * @returns the analytics config for the user */ public loadConfig(): AnalyticsConfig { try { - const fileContents = readFileSync(this.analyticsConfigFile, 'utf-8'); + const fileContents = readFileSync(this.analyticsConfigFile, "utf-8"); return JSON.parse(fileContents) as AnalyticsConfig; } catch (error: any) { if (this.debug) { - console.log(`Error loading analytics config: ${error}`) + console.log(`Error loading analytics config: ${error}`); } const analyticsConfig: AnalyticsConfig = { anonymousId: this.generateAnonymousId(), optOut: false, - } - + }; + this.saveConfig(analyticsConfig); - + return analyticsConfig; } } /** * Saves the analytics config to disk - * + * * @param config the analytics config to save to disk */ public saveConfig(config: AnalyticsConfig) { @@ -169,29 +168,38 @@ export class AnalyticsStorage { if (!existsSync(WING_HOME_DIR)) { mkdirSync(WING_HOME_DIR); } - writeFileSync(this.analyticsConfigFile, JSON.stringify(config)) + writeFileSync(this.analyticsConfigFile, JSON.stringify(config)); } catch (error) { - if (this.debug) { console.log(`Error saving config file ${error}`) } + if (this.debug) { + console.log(`Error saving config file ${error}`); + } } } /** * Helper method to flatten objects - * + * * @param properties The properties to flatten * @param parentKey The key of the parent (defaults to "") - * @returns + * @returns */ - private flattenProperties(properties: {[key: string]: any}, parentKey: string = ""): {[key: string]: any} { - return Object.keys(properties).reduce((accumulated: {[key:string]: any}, key) => { + private flattenProperties( + properties: { [key: string]: any }, + parentKey: string = "" + ): { [key: string]: any } { + return Object.keys(properties).reduce((accumulated: { [key: string]: any }, key) => { const newKey = parentKey ? `${parentKey}_${key}` : key; - if (typeof properties[key] === 'object' && properties[key] !== null && !Array.isArray(properties[key])) { + if ( + typeof properties[key] === "object" && + properties[key] !== null && + !Array.isArray(properties[key]) + ) { Object.assign(accumulated, this.flattenProperties(properties[key], newKey)); } else { accumulated[newKey] = properties[key]; } - + return accumulated; }, {}); } @@ -199,14 +207,14 @@ export class AnalyticsStorage { private saveEvent(filePath: string, event: AnalyticEvent) { try { event.properties = this.flattenProperties(event.properties) as any; - writeFileSync(filePath, JSON.stringify(event)) + writeFileSync(filePath, JSON.stringify(event)); if (this.debug) { console.log(`Analytics event stored at ${filePath}`); } } catch (error) { if (this.debug) { - console.log(`Error storing analytics event: ${error}`) + console.log(`Error storing analytics event: ${error}`); } } } -} \ No newline at end of file +} diff --git a/apps/wing/src/cli.ts b/apps/wing/src/cli.ts index 870d0a262b1..c56db763bfa 100644 --- a/apps/wing/src/cli.ts +++ b/apps/wing/src/cli.ts @@ -1,10 +1,9 @@ -import { satisfies } from "compare-versions"; - import { Command, Option } from "commander"; +import { satisfies } from "compare-versions"; import { collectCommandAnalytics } from "./analytics/collect"; -import { exportAnalytics } from "./analytics/export"; import { optionallyDisplayDisclaimer } from "./analytics/disclaimer"; +import { exportAnalytics } from "./analytics/export"; import { currentPackage } from "./util"; export const PACKAGE_VERSION = currentPackage.version; diff --git a/apps/wing/src/commands/compile.test.ts b/apps/wing/src/commands/compile.test.ts index 51cb2ce9636..8c43647fa51 100644 --- a/apps/wing/src/commands/compile.test.ts +++ b/apps/wing/src/commands/compile.test.ts @@ -1,8 +1,8 @@ -import { compile } from "./compile"; import { readdir, stat, writeFile } from "fs/promises"; -import { describe, test, expect } from "vitest"; import { join, resolve } from "path"; import { Target } from "@winglang/compiler"; +import { describe, test, expect } from "vitest"; +import { compile } from "./compile"; import { generateTmpDir } from "src/util"; const exampleDir = resolve("../../examples/tests/valid"); diff --git a/apps/wing/src/commands/compile.ts b/apps/wing/src/commands/compile.ts index cc7b7c14e28..28e5f91f98f 100644 --- a/apps/wing/src/commands/compile.ts +++ b/apps/wing/src/commands/compile.ts @@ -1,10 +1,10 @@ import { promises as fsPromise } from "fs"; import { relative } from "path"; +import * as wingCompiler from "@winglang/compiler"; import chalk from "chalk"; -import debug from "debug"; import { CHARS_ASCII, emitDiagnostic, File, Label } from "codespan-wasm"; -import * as wingCompiler from "@winglang/compiler"; +import debug from "debug"; // increase the stack trace limit to 50, useful for debugging Rust panics // (not setting the limit too high in case of infinite recursion) @@ -50,11 +50,11 @@ export async function compile(entrypoint: string, options: CompileOptions): Prom } catch (error) { if (error instanceof wingCompiler.CompileError) { // This is a bug in the user's code. Print the compiler diagnostics. - const errors = error.diagnostics; + const diagnostics = error.diagnostics; const result = []; - for (const error of errors) { - const { message, span } = error; + for (const diagnostic of diagnostics) { + const { message, span } = diagnostic; let files: File[] = []; let labels: Label[] = []; diff --git a/apps/wing/src/commands/docs.test.ts b/apps/wing/src/commands/docs.test.ts index 5fb2552e0a1..83422ee1234 100644 --- a/apps/wing/src/commands/docs.test.ts +++ b/apps/wing/src/commands/docs.test.ts @@ -1,6 +1,6 @@ import open from "open"; -import { docs } from "./docs"; import { vi, test, expect } from "vitest"; +import { docs } from "./docs"; vi.mock("open"); diff --git a/apps/wing/src/commands/lsp.ts b/apps/wing/src/commands/lsp.ts index 4751462edfd..f7c12b7d304 100644 --- a/apps/wing/src/commands/lsp.ts +++ b/apps/wing/src/commands/lsp.ts @@ -1,3 +1,4 @@ +import * as wingCompiler from "@winglang/compiler"; import { createConnection, InitializeParams, @@ -9,8 +10,6 @@ import { DocumentUri, } from "vscode-languageserver/node"; -import * as wingCompiler from "@winglang/compiler"; - export async function lsp() { let wingc = await wingCompiler.load({ imports: { @@ -53,7 +52,7 @@ export async function lsp() { } } catch (e) { // set status in ide - connection.sendDiagnostics({ + void connection.sendDiagnostics({ uri: args.textDocument.uri, diagnostics: [ { @@ -146,19 +145,19 @@ export async function lsp() { // purposely not awaiting these calls, notifications are fire-and-forget for (const [uri, diagnostics] of allDiagnostics.entries()) { - connection.sendDiagnostics({ uri, diagnostics }); + void connection.sendDiagnostics({ uri, diagnostics }); } } connection.onDidOpenTextDocument(async (params) => { - handle_event_and_update_diagnostics( + void handle_event_and_update_diagnostics( "wingc_on_did_open_text_document", params, params.textDocument.uri ); }); connection.onDidChangeTextDocument(async (params) => { - handle_event_and_update_diagnostics( + void handle_event_and_update_diagnostics( "wingc_on_did_change_text_document", params, params.textDocument.uri diff --git a/apps/wing/src/commands/run.test.ts b/apps/wing/src/commands/run.test.ts index 3eb694919b3..3a95e55c541 100644 --- a/apps/wing/src/commands/run.test.ts +++ b/apps/wing/src/commands/run.test.ts @@ -1,12 +1,11 @@ -import open from "open"; -import { createConsoleApp } from "@wingconsole/app"; -import { run } from "./run"; +import { mkdirSync, writeFileSync } from "fs"; import { mkdtemp } from "fs/promises"; -import { join } from "path"; import { tmpdir } from "os"; -import { mkdirSync, writeFileSync } from "fs"; -import { resolve } from "path"; +import { join, resolve } from "path"; +import { createConsoleApp } from "@wingconsole/app"; +import open from "open"; import { vi, test, expect } from "vitest"; +import { run } from "./run"; vi.mock("open"); diff --git a/apps/wing/src/commands/run.ts b/apps/wing/src/commands/run.ts index da48e4edbf6..60981a1e0b1 100644 --- a/apps/wing/src/commands/run.ts +++ b/apps/wing/src/commands/run.ts @@ -1,8 +1,8 @@ import { readdirSync, existsSync } from "fs"; -import { debug } from "debug"; import { resolve } from "path"; -import open from "open"; import { createConsoleApp } from "@wingconsole/app"; +import { debug } from "debug"; +import open from "open"; import { parseNumericString } from "../util"; /** @@ -69,7 +69,7 @@ export async function run(entrypoint?: string, options?: RunOptions) { await close(() => process.exit(exitCode)); }; - process.once("exit", async (c) => await onExit(c)); - process.once("SIGTERM", async () => await onExit(0)); - process.once("SIGINT", async () => await onExit(0)); + process.once("exit", async (c) => onExit(c)); + process.once("SIGTERM", async () => onExit(0)); + process.once("SIGINT", async () => onExit(0)); } diff --git a/apps/wing/src/commands/test.test.ts b/apps/wing/src/commands/test.test.ts index 5319e903bc0..006bd92269c 100644 --- a/apps/wing/src/commands/test.test.ts +++ b/apps/wing/src/commands/test.test.ts @@ -1,8 +1,7 @@ -import { describe, test, expect, beforeEach, afterEach } from "vitest"; -import { renderTestReport } from "./test"; - import { TestResult, TraceType } from "@winglang/sdk/lib/std"; import chalk from "chalk"; +import { describe, test, expect, beforeEach, afterEach } from "vitest"; +import { renderTestReport } from "./test"; const defaultChalkLevel = chalk.level; diff --git a/apps/wing/src/commands/test.ts b/apps/wing/src/commands/test.ts index 844c1da7a57..9418cbe5b51 100644 --- a/apps/wing/src/commands/test.ts +++ b/apps/wing/src/commands/test.ts @@ -1,14 +1,14 @@ -import { basename, resolve, sep } from "path"; -import { compile, CompileOptions } from "./compile"; -import chalk from "chalk"; -import { std, simulator } from "@winglang/sdk"; import * as cp from "child_process"; -import debug from "debug"; +import { readFile, rm, rmSync } from "fs"; +import { basename, resolve, sep } from "path"; import { promisify } from "util"; -import { generateTmpDir, withSpinner } from "../util"; import { Target } from "@winglang/compiler"; +import { std, simulator } from "@winglang/sdk"; +import chalk from "chalk"; +import debug from "debug"; import { nanoid } from "nanoid"; -import { readFile, rm, rmSync } from "fs"; +import { compile, CompileOptions } from "./compile"; +import { generateTmpDir, withSpinner } from "../util"; const log = debug("wing:test"); @@ -48,8 +48,8 @@ export async function test(entrypoints: string[], options: TestOptions): Promise printResults(results, Date.now() - startTime); // if we have any failures, exit with 1 - for (const test of results) { - for (const r of test.results) { + for (const testSuite of results) { + for (const r of testSuite.results) { if (r.error) { return 1; } @@ -79,20 +79,20 @@ function printResults( const areErrors = failing.length > 0 && totalSum > 1; const showTitle = totalSum > 1; - const results = []; + const res = []; if (showTitle) { // prints a list of the tests names with an icon - results.push(`Results:`); - results.push(...passing.map(({ testName }) => ` ${chalk.green("✓")} ${testName}`)); - results.push(...failing.map(({ testName }) => ` ${chalk.red("×")} ${testName}`)); + res.push(`Results:`); + res.push(...passing.map(({ testName }) => ` ${chalk.green("✓")} ${testName}`)); + res.push(...failing.map(({ testName }) => ` ${chalk.red("×")} ${testName}`)); } if (areErrors) { // prints error messages form failed tests - results.push(" "); - results.push("Errors:"); - results.push( + res.push(" "); + res.push("Errors:"); + res.push( ...failing.map(({ testName, results }) => [ `At ${testName}`, @@ -103,8 +103,8 @@ function printResults( } // prints a summary of how many tests passed and failed - results.push(" "); - results.push( + res.push(" "); + res.push( `${chalk.dim("Tests")}${failingTestsNumber ? chalk.red(` ${failingTestsNumber} failed`) : ""}${ failingTestsNumber && passingTestsNumber ? chalk.dim(" |") : "" }${passingTestsNumber ? chalk.green(` ${passingTestsNumber} passed`) : ""} ${chalk.dim( @@ -112,7 +112,7 @@ function printResults( )}` ); // prints a summary of how many tests files passed and failed - results.push( + res.push( `${chalk.dim("Test Files")}${failing.length ? chalk.red(` ${failing.length} failed`) : ""}${ failing.length && passing.length ? chalk.dim(" |") : "" }${passing.length ? chalk.green(` ${passing.length} passed`) : ""} ${chalk.dim( @@ -121,13 +121,13 @@ function printResults( ); // prints the test duration - results.push( + res.push( `${chalk.dim("Duration")} ${Math.floor(durationInSeconds / 60)}m${( durationInSeconds % 60 ).toFixed(2)}s` ); - console.log(results.filter((value) => !!value).join("\n")); + console.log(res.filter((value) => !!value).join("\n")); } async function testOne(entrypoint: string, options: TestOptions) { @@ -146,11 +146,11 @@ async function testOne(entrypoint: string, options: TestOptions) { switch (options.target) { case Target.SIM: - return await testSimulator(synthDir, options); + return testSimulator(synthDir, options); case Target.TF_AWS: - return await testTfAws(synthDir, options); + return testTfAws(synthDir, options); case Target.AWSCDK: - return await testAwsCdk(synthDir, options); + return testAwsCdk(synthDir, options); default: throw new Error(`unsupported target ${options.target}`); } @@ -184,13 +184,13 @@ export function renderTestReport(entrypoint: string, results: std.TestResult[]): const details = new Array(); // add any log messages that were emitted during the test - for (const log of result.traces) { + for (const trace of result.traces) { // only show detailed traces if we are in debug mode - if (log.type === "resource" && process.env.DEBUG) { - details.push(chalk.gray("[trace] " + log.data.message)); + if (trace.type === "resource" && process.env.DEBUG) { + details.push(chalk.gray("[trace] " + trace.data.message)); } - if (log.type === "log") { - details.push(chalk.gray(log.data.message)); + if (trace.type === "log") { + details.push(chalk.gray(trace.data.message)); } } @@ -278,7 +278,7 @@ async function testSimulator(synthDir: string, options: TestOptions) { async function testAwsCdk(synthDir: string, options: TestOptions): Promise { const { clean } = options; try { - isAwsCdkInstalled(synthDir); + await isAwsCdkInstalled(synthDir); await withSpinner("cdk deploy", () => awsCdkDeploy(synthDir)); @@ -292,18 +292,18 @@ async function testAwsCdk(synthDir: string, options: TestOptions): Promise { - const results = new Array(); + const res = new Array(); for (const path of tests) { - results.push(await testRunner.runTest(path)); + res.push(await testRunner.runTest(path)); } - return results; + return res; }); const testReport = renderTestReport(synthDir, results); @@ -369,7 +369,7 @@ async function testTfAws(synthDir: string, options: TestOptions): Promise await terraformInit(synthDir)); + await withSpinner("terraform init", async () => terraformInit(synthDir)); await withSpinner("terraform apply", () => terraformApply(synthDir)); @@ -378,18 +378,18 @@ async function testTfAws(synthDir: string, options: TestOptions): Promise { - const results = new Array(); + const res = new Array(); for (const path of tests) { - results.push(await testRunner.runTest(path)); + res.push(await testRunner.runTest(path)); } - return results; + return res; }); const testReport = renderTestReport(synthDir, results); @@ -470,17 +470,17 @@ function pickOneTestPerEnvironment(testPaths: string[]) { for (const testPath of testPaths) { const testSuffix = testPath.substring(testPath.indexOf("env") + 1); // "/" const env = testSuffix.substring(0, testSuffix.indexOf("/")); // "" - const test = testSuffix.substring(testSuffix.indexOf("/") + 1); // "" + const testName = testSuffix.substring(testSuffix.indexOf("/") + 1); // "" if (envs.has(env)) { continue; } - if (tests.has(test)) { + if (tests.has(testName)) { continue; } - tests.set(test, testPath); + tests.set(testName, testPath); envs.add(env); } diff --git a/apps/wing/src/util.ts b/apps/wing/src/util.ts index e1d06a00af1..e58693f6b09 100644 --- a/apps/wing/src/util.ts +++ b/apps/wing/src/util.ts @@ -82,4 +82,5 @@ export const currentPackage: { name: string; version: string; engines: { node: string }; + // eslint-disable-next-line @typescript-eslint/no-require-imports } = require("../package.json"); diff --git a/apps/wing/turbo.json b/apps/wing/turbo.json index f7a5f8bebe6..33b0296fedf 100644 --- a/apps/wing/turbo.json +++ b/apps/wing/turbo.json @@ -5,6 +5,9 @@ "test": { "dependsOn": ["^compile", "examples-valid#topo"] }, + "eslint": { + "dependsOn": ["^compile"] + }, "compile": { "outputs": ["dist/**"] }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f97b16debbd..4201fe258b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -334,12 +334,36 @@ importers: '@types/uuid': specifier: ^8.3.4 version: 8.3.4 + '@typescript-eslint/eslint-plugin': + specifier: ^6.7.4 + version: 6.7.4(@typescript-eslint/parser@6.7.4)(eslint@8.50.0)(typescript@4.9.5) + '@typescript-eslint/parser': + specifier: ^6.7.4 + version: 6.7.4(eslint@8.50.0)(typescript@4.9.5) bump-pack: specifier: workspace:^ version: link:../../tools/bump-pack esbuild: specifier: ^0.17.19 version: 0.17.19 + eslint: + specifier: ^8.50.0 + version: 8.50.0 + eslint-config-prettier: + specifier: ^8.10.0 + version: 8.10.0(eslint@8.50.0) + eslint-import-resolver-node: + specifier: ^0.3.9 + version: 0.3.9 + eslint-import-resolver-typescript: + specifier: ^3.6.0 + version: 3.6.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.50.0) + eslint-plugin-import: + specifier: ^2.28.1 + version: 2.28.1(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0) + eslint-plugin-prettier: + specifier: ^4.2.1 + version: 4.2.1(eslint-config-prettier@8.10.0)(eslint@8.50.0)(prettier@2.8.8) typescript: specifier: ^4.9.5 version: 4.9.5 @@ -4788,6 +4812,16 @@ packages: eslint: 8.48.0 eslint-visitor-keys: 3.4.3 + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.50.0 + eslint-visitor-keys: 3.4.3 + dev: true + /@eslint-community/regexpp@4.8.0: resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -4812,6 +4846,11 @@ packages: resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@eslint/js@8.50.0: + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@fal-works/esbuild-plugin-global-externals@2.1.2: resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} dev: true @@ -9559,6 +9598,35 @@ packages: - supports-color dev: false + /@typescript-eslint/eslint-plugin@6.7.4(@typescript-eslint/parser@6.7.4)(eslint@8.50.0)(typescript@4.9.5): + resolution: {integrity: sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.8.0 + '@typescript-eslint/parser': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.7.4 + '@typescript-eslint/type-utils': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + '@typescript-eslint/utils': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.7.4 + debug: 4.3.4 + eslint: 8.50.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser@5.62.0(eslint@8.48.0)(typescript@4.9.5): resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9598,6 +9666,27 @@ packages: - supports-color dev: false + /@typescript-eslint/parser@6.7.4(eslint@8.50.0)(typescript@4.9.5): + resolution: {integrity: sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.7.4 + '@typescript-eslint/types': 6.7.4 + '@typescript-eslint/typescript-estree': 6.7.4(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.7.4 + debug: 4.3.4 + eslint: 8.50.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.62.0: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9605,6 +9694,14 @@ packages: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 + /@typescript-eslint/scope-manager@6.7.4: + resolution: {integrity: sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.4 + '@typescript-eslint/visitor-keys': 6.7.4 + dev: true + /@typescript-eslint/type-utils@5.62.0(eslint@8.48.0)(typescript@4.9.5): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9645,10 +9742,35 @@ packages: - supports-color dev: false + /@typescript-eslint/type-utils@6.7.4(eslint@8.50.0)(typescript@4.9.5): + resolution: {integrity: sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.7.4(typescript@4.9.5) + '@typescript-eslint/utils': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + debug: 4.3.4 + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@5.62.0: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/types@6.7.4: + resolution: {integrity: sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + /@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9690,6 +9812,27 @@ packages: - supports-color dev: false + /@typescript-eslint/typescript-estree@6.7.4(typescript@4.9.5): + resolution: {integrity: sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.7.4 + '@typescript-eslint/visitor-keys': 6.7.4 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.62.0(eslint@8.48.0)(typescript@4.9.5): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9730,6 +9873,25 @@ packages: - typescript dev: false + /@typescript-eslint/utils@6.7.4(eslint@8.50.0)(typescript@4.9.5): + resolution: {integrity: sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.1 + '@typescript-eslint/scope-manager': 6.7.4 + '@typescript-eslint/types': 6.7.4 + '@typescript-eslint/typescript-estree': 6.7.4(typescript@4.9.5) + eslint: 8.50.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.62.0: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9737,6 +9899,14 @@ packages: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 + /@typescript-eslint/visitor-keys@6.7.4: + resolution: {integrity: sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.4 + eslint-visitor-keys: 3.4.3 + dev: true + /@vitejs/plugin-react-swc@3.3.2(vite@4.4.9): resolution: {integrity: sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==} peerDependencies: @@ -12768,7 +12938,7 @@ packages: dependencies: semver: 7.5.4 shelljs: 0.8.5 - typescript: 5.3.0-dev.20231002 + typescript: 5.3.0-dev.20231003 dev: true /dset@3.1.2: @@ -13362,6 +13532,15 @@ packages: dependencies: eslint: 8.48.0 + /eslint-config-prettier@8.10.0(eslint@8.50.0): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.50.0 + dev: true + /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: @@ -13393,6 +13572,29 @@ packages: - eslint-import-resolver-webpack - supports-color + /eslint-import-resolver-typescript@3.6.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.50.0): + resolution: {integrity: sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: 4.3.4 + enhanced-resolve: 5.15.0 + eslint: 8.50.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0) + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0) + fast-glob: 3.3.1 + get-tsconfig: 4.7.0 + is-core-module: 2.13.0 + is-glob: 4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.48.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} @@ -13422,6 +13624,36 @@ packages: transitivePeerDependencies: - supports-color + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + debug: 3.2.7(supports-color@5.5.0) + eslint: 8.50.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.50.0) + transitivePeerDependencies: + - supports-color + dev: true + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.48.0): resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} @@ -13456,6 +13688,41 @@ packages: - eslint-import-resolver-webpack - supports-color + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0): + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.7.4(eslint@8.50.0)(typescript@4.9.5) + array-includes: 3.1.6 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7(supports-color@5.5.0) + doctrine: 2.1.0 + eslint: 8.50.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.4)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.50.0) + has: 1.0.3 + is-core-module: 2.13.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-plugin-jsx-a11y@6.7.1(eslint@8.48.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} @@ -13497,6 +13764,23 @@ packages: prettier: 2.8.8 prettier-linter-helpers: 1.0.0 + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0)(eslint@8.50.0)(prettier@2.8.8): + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.50.0 + eslint-config-prettier: 8.10.0(eslint@8.50.0) + prettier: 2.8.8 + prettier-linter-helpers: 1.0.0 + dev: true + /eslint-plugin-react-hooks@4.6.0(eslint@8.48.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} @@ -13627,6 +13911,52 @@ packages: transitivePeerDependencies: - supports-color + /eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.8.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.21.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -21227,6 +21557,15 @@ packages: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} dev: true + /ts-api-utils@1.0.3(typescript@4.9.5): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 4.9.5 + dev: true + /ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} @@ -21820,8 +22159,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript@5.3.0-dev.20231002: - resolution: {integrity: sha512-TQXM13rrDgID8W4Ok4KDQAqwLUjLcAXL+NKv0zJiIEQfa0bOM0yoRiSgvcjaCJ4lZT4bScrq3vHspVM2x8rkOQ==} + /typescript@5.3.0-dev.20231003: + resolution: {integrity: sha512-OyUdPjo1wNYs+PVDr9ARcEPs0aOqdxterOFzQzWK6DR4tsadKPbrOx8JgTOvSUwhkNOxBOEh7BonqV2uNsTxvA==} engines: {node: '>=14.17'} hasBin: true dev: true