├── .github └── dependabot.yml ├── .gitignore ├── README.md ├── trivia-game-react ├── .editorconfig ├── .gitignore ├── .node-version ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── babel-plugin-macros.config.js ├── config.json ├── cypress.json ├── cypress │ ├── fixtures │ │ └── example.json │ ├── plugins │ │ └── index.js │ ├── support │ │ ├── commands.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── netlify.toml ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.test.tsx │ ├── App.tsx │ ├── components │ │ ├── Actions.ts │ │ ├── Button.ts │ │ ├── Container.ts │ │ ├── CorrectIcon.tsx │ │ ├── GlobalStyle.ts │ │ ├── TextContainer.ts │ │ ├── Typography.ts │ │ ├── WrongIcon.tsx │ │ ├── __tests__ │ │ │ ├── Actions.tsx │ │ │ ├── Button.tsx │ │ │ ├── Container.tsx │ │ │ ├── CorrectIcon.tsx │ │ │ ├── GlobalStyle.tsx │ │ │ ├── TextContainer.tsx │ │ │ ├── Typography.tsx │ │ │ ├── WrongIcon.tsx │ │ │ └── __snapshots__ │ │ │ │ ├── Actions.tsx.snap │ │ │ │ ├── Button.tsx.snap │ │ │ │ ├── Container.tsx.snap │ │ │ │ ├── CorrectIcon.tsx.snap │ │ │ │ ├── GlobalStyle.tsx.snap │ │ │ │ ├── TextContainer.tsx.snap │ │ │ │ ├── Typography.tsx.snap │ │ │ │ └── WrongIcon.tsx.snap │ │ └── index.ts │ ├── index.tsx │ ├── machine.ts │ ├── react-app-env.d.ts │ ├── screens │ │ ├── Failure.tsx │ │ ├── Loading.tsx │ │ ├── Quiz.tsx │ │ ├── Results.tsx │ │ ├── Welcome.tsx │ │ └── index.ts │ ├── setupTests.ts │ ├── tailwind.config.js │ ├── types.ts │ └── utils │ │ ├── fetchAndNormalizeQuizData.ts │ │ ├── fetchQuizData.ts │ │ ├── index.ts │ │ └── normalizeQuizData.ts ├── tsconfig.json └── yarn.lock ├── trivia-game-svelte ├── .editorconfig ├── .gitignore ├── .node-version ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── netlify.toml ├── package.json ├── postcss.config.js ├── public │ ├── favicon.png │ └── index.html ├── rollup.config.js ├── rollup_start_dev.js ├── src │ ├── App.svelte │ ├── components │ │ ├── Actions.svelte │ │ ├── Button.svelte │ │ ├── Container.svelte │ │ ├── CorrectIcon.svelte │ │ ├── GlobalStyle.svelte │ │ ├── H1.svelte │ │ ├── P.svelte │ │ ├── TextContainer.svelte │ │ └── WrongIcon.svelte │ ├── machine.js │ ├── main.js │ ├── screens │ │ ├── Failure.svelte │ │ ├── Loading.svelte │ │ ├── Quiz.svelte │ │ ├── Results.svelte │ │ └── Welcome.svelte │ └── utils │ │ ├── fetchAndNormalizeQuizData.js │ │ ├── fetchQuizData.js │ │ ├── index.js │ │ └── normalizeQuizData.js ├── tailwind.config.js └── yarn.lock └── trivia-game-vue ├── .editorconfig ├── .gitignore ├── .node-version ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── babel.config.js ├── netlify.toml ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── tailwind.css ├── components │ ├── Actions.vue │ ├── Button.vue │ ├── Container.vue │ ├── CorrectIcon.vue │ ├── H1.vue │ ├── P.vue │ ├── TextContainer.vue │ ├── Toggle.vue │ └── WrongIcon.vue ├── machine.js ├── main.js ├── screens │ ├── Failure.vue │ ├── Loading.vue │ ├── Quiz.vue │ ├── Results.vue │ └── Welcome.vue └── utils │ ├── fetchAndNormalizeQuizData.js │ ├── fetchQuizData.js │ ├── index.js │ └── normalizeQuizData.js └── yarn.lock /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/trivia-game-svelte" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | - package-ecosystem: npm 10 | directory: "/trivia-game-vue" 11 | schedule: 12 | interval: daily 13 | time: "10:00" 14 | open-pull-requests-limit: 10 15 | - package-ecosystem: npm 16 | directory: "/trivia-game-react" 17 | schedule: 18 | interval: daily 19 | time: "10:00" 20 | open-pull-requests-limit: 10 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xstate-examples 2 | 3 | ## Explanation 4 | This repo serves as a resource for any developer curious about [state machines](https://statecharts.github.io/what-is-a-state-machine.html) and [statecharts](https://statecharts.github.io). I've heard developers that _want_ to use state machines, but have not found the "perfect reason" to utilize them. Now the "perfect reason" is easier to find. 😉 5 | 6 | ## Repository Structure 7 | - Each example is in it's own directory. 8 | - Each example is a small application created with [Create React App](https://create-react-app.dev)/[vue-cli](https://cli.vuejs.org/)/[Svelte Template](https://github.com/sveltejs/template), [Xstate](https://xstate.js.org), [tailwind](https://tailwindcss.com), [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)/[Vue Testing Library](https://testing-library.com/docs/vue-testing-library/intro)/[Svelte Testing Library](https://testing-library.com/docs/svelte-testing-library/intro), and [cypress](https://www.cypress.io). 9 | - Each example has a README with link to the [xstate visualization tool](https://xstate.js.org/viz/) for that example's state machine/statechart. 10 | - Each example uses [model-based testing](https://css-tricks.com/model-based-testing-in-react-with-state-machines/) and state machine/statechart best practices. 11 | 12 | ## Current Examples 13 | - Trivia Game [React](/trivia-game-react) | [Vue](/trivia-game-vue) | [Svelte](/trivia-game-svelte) 14 | 15 | ## Future Examples 16 | - React Native "Simon Says" game 17 | - Authentication flow 18 | - Welcome/walkthrough flow 19 | - Todos 20 | - Ticket selection and payment flow 21 | - Stepped form/wizard 22 | - Medium-like article creation/updating 23 | 24 | ## Examples Showing Specific State Machine Concepts 25 | - [Guards](https://xstate.js.org/docs/guides/guards.html): Trivia Game [React](/trivia-game-react/src/machine.ts#L47) | [Vue](/trivia-game-vue/src/machine.js#L46) | [Svelte](/trivia-game-svelte/src/machine.js#L46) 26 | - [Transient Transitions](https://xstate.js.org/docs/guides/transitions.html#transient-transitions): Trivia Game [React](/trivia-game-react/src/machine.ts#L44-L48) | [Vue](/trivia-game-vue/src/machine.js#L43-L47) | [Svelte](/trivia-game-svelte/src/machine.js#L43-L47) 27 | - [Invoking Services (Promises)](https://xstate.js.org/docs/guides/communication.html#the-invoke-property): Trivia Game [React](/trivia-game-react/src/machine.ts#L22-L34) | [Vue](/trivia-game-vue/src/machine.js#L21-L33) | [Svelte](/trivia-game-svelte/src/machine.js#L21-L33) 28 | 29 | ## Handy Resources 30 | - [Xstate documentation](https://xstate.js.org) 31 | - [Statecharts community](https://spectrum.chat/statecharts) 32 | - [World of Statecharts](https://statecharts.github.io) 33 | -------------------------------------------------------------------------------- /trivia-game-react/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | 10 | -------------------------------------------------------------------------------- /trivia-game-react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /trivia-game-react/.node-version: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-react/.nvmrc: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-react/.prettierignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /public 12 | 13 | # misc 14 | *.DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .en.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | .cache 25 | 26 | -------------------------------------------------------------------------------- /trivia-game-react/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": false, 4 | "htmlWhitespaceSensitivity": "css", 5 | "insertPragma": false, 6 | "jsxBracketSameLine": false, 7 | "jsxSingleQuote": true, 8 | "printWidth": 80, 9 | "proseWrap": "always", 10 | "requirePragma": false, 11 | "semi": false, 12 | "singleQuote": true, 13 | "tabWidth": 2, 14 | "trailingComma": "all", 15 | "useTabs": false 16 | } 17 | 18 | -------------------------------------------------------------------------------- /trivia-game-react/README.md: -------------------------------------------------------------------------------- 1 | # Trivia Game 2 | 3 | This example showcases several state machine concepts including guards, 4 | transient functions, and invoking services. 5 | 6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068) 7 | 8 | ## Running Locally 9 | 10 | 1. After cloning and navigating into the `trivia-game-react` directory, execute: 11 | 12 | ``` 13 | yarn && yarn test 14 | ``` 15 | 16 | or 17 | 18 | ``` 19 | npm install && npm t 20 | ``` 21 | 22 | This will install dependencies and run tests to verify no issues 23 | 24 | 2. Start the application by executing: 25 | 26 | ``` 27 | yarn start 28 | ``` 29 | 30 | or 31 | 32 | ``` 33 | npm start 34 | ``` 35 | -------------------------------------------------------------------------------- /trivia-game-react/babel-plugin-macros.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | styledComponents: { 3 | displayName: true, 4 | }, 5 | tailwind: { 6 | config: './src/tailwind.config.js', 7 | styled: 'styled-components/macro', 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /trivia-game-react/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporterEnabled": "spec, mocha-junit-reporter", 3 | "mochaJunitReporterReporterOptions": { 4 | "mochaFile": "cypress/results/junit/results.[hash].xml" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /trivia-game-react/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000", 3 | "integrationFolder": "cypress/e2e", 4 | "reporter": "mocha-multi-reporters", 5 | "reporterOptions": { 6 | "configFile": "config.json" 7 | }, 8 | "supportFile": "cypress/support/index.ts", 9 | "ignoreTestFiles": "**/*.{js,ts}" 10 | } 11 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const wp = require('@cypress/webpack-preprocessor') 15 | 16 | module.exports = on => { 17 | const options = { 18 | webpackOptions: require('../webpack.config'), 19 | } 20 | on('file:preprocessor', wp(options)) 21 | // `on` is used to hook into various events Cypress emits 22 | // `config` is the resolved Cypress config 23 | } 24 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | 27 | // add a custom command cy.foo() 28 | Cypress.Commands.add('foo', () => 'foo') 29 | 30 | // see more example of adding custom commands to Cypress TS interface 31 | // in https://github.com/cypress-io/add-cypress-custom-command-in-typescript 32 | // add new command to the existing Cypress interface 33 | // tslint:disable-next-line no-namespace 34 | declare namespace Cypress { 35 | // tslint:disable-next-line interface-name 36 | interface Chainable { 37 | foo: () => string 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import '@testing-library/cypress/add-commands' 18 | import './commands' 19 | 20 | // Alternatively you can use CommonJS syntax: 21 | // require('./commands') 22 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "../node_modules", 4 | "lib": ["es5", "dom"], 5 | "module": "commonjs", 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "target": "es5", 9 | "types": ["cypress", "@testing-library/cypress"] 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /trivia-game-react/cypress/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | resolve: { 3 | extensions: ['.ts', '.js'], 4 | }, 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.ts$/, 9 | exclude: [/node_modules/], 10 | use: [ 11 | { 12 | loader: 'ts-loader', 13 | }, 14 | ], 15 | }, 16 | { 17 | test: /\.feature$/, 18 | use: [ 19 | { 20 | loader: 'cypress-cucumber-preprocessor/loader', 21 | }, 22 | ], 23 | }, 24 | ], 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /trivia-game-react/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "" 3 | command = "yarn build" 4 | publish = "/build" 5 | -------------------------------------------------------------------------------- /trivia-game-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trivia-game", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "react-scripts build", 7 | "commit": "git-cz", 8 | "cy:open": "cypress open", 9 | "cy:run": "cypress run", 10 | "format": "yarn prettier --write", 11 | "prettier": "prettier \"**/*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx)\"", 12 | "preserve": "yarn build", 13 | "serve": "serve -s build -l 3000", 14 | "setup": "yarn && yarn validate", 15 | "start": "react-scripts start", 16 | "test": "is-ci \"test:ci\" \"test:watch\"", 17 | "test:ci": "react-scripts test --ci --coverage --runInBand --reporters=default --reporters=jest-junit", 18 | "test:coverage": "react-scripts test --coverage", 19 | "test:e2e": "is-ci \"test:e2e:run\" \"test:e2e:dev\"", 20 | "test:e2e:dev": "start-server-and-test start http://localhost:3000 cy:open", 21 | "test:e2e:run": "start-server-and-test serve http://localhost:3000 cy:run", 22 | "test:watch": "react-scripts test", 23 | "validate": "lint-staged" 24 | }, 25 | "dependencies": { 26 | "@xstate/react": "5.0.5", 27 | "lean-he": "2.1.2", 28 | "react": "18.3.1", 29 | "react-dom": "19.1.0", 30 | "react-scripts": "5.0.1", 31 | "styled-components": "6.1.18", 32 | "tailwind.macro": "1.0.0-alpha.10", 33 | "typescript": "5.8.3", 34 | "xstate": "5.19.4" 35 | }, 36 | "devDependencies": { 37 | "@testing-library/cypress": "10.0.3", 38 | "@testing-library/jest-dom": "6.6.3", 39 | "@testing-library/react": "15.0.7", 40 | "@types/jest": "29.5.14", 41 | "@types/node": "22.15.30", 42 | "@types/react": "18.3.13", 43 | "@types/react-dom": "19.1.6", 44 | "@types/styled-components": "5.1.34", 45 | "@xstate/graph": "3.0.4", 46 | "@xstate/test": "0.5.1", 47 | "commitizen": "4.3.1", 48 | "cypress": "14.4.1", 49 | "cz-conventional-changelog": "3.3.0", 50 | "husky": "9.1.7", 51 | "is-ci-cli": "2.2.0", 52 | "jest-axe": "10.0.0", 53 | "jest-junit": "16.0.0", 54 | "jest-styled-components": "beta", 55 | "lint-staged": "16.1.0", 56 | "mocha": "11.5.0", 57 | "mocha-junit-reporter": "2.2.1", 58 | "mocha-multi-reporters": "1.5.1", 59 | "prettier": "3.5.3", 60 | "serve": "14.2.4", 61 | "start-server-and-test": "2.0.12" 62 | }, 63 | "eslintConfig": { 64 | "extends": "react-app" 65 | }, 66 | "browserslist": { 67 | "production": [ 68 | ">0.2%", 69 | "not dead", 70 | "not op_mini all" 71 | ], 72 | "development": [ 73 | "last 1 chrome version", 74 | "last 1 firefox version", 75 | "last 1 safari version" 76 | ] 77 | }, 78 | "husky": { 79 | "hooks": { 80 | "pre-commit": "yarn validate" 81 | } 82 | }, 83 | "config": { 84 | "commitizen": { 85 | "path": "cz-conventional-changelog" 86 | } 87 | }, 88 | "repository": { 89 | "type": "git", 90 | "url": "https://github.com/DevanB/xstate-examples/trivia-game" 91 | }, 92 | "lint-staged": { 93 | "**/*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx)": [ 94 | "prettier --write", 95 | "git add" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /trivia-game-react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/favicon.ico -------------------------------------------------------------------------------- /trivia-game-react/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /trivia-game-react/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/logo192.png -------------------------------------------------------------------------------- /trivia-game-react/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/logo512.png -------------------------------------------------------------------------------- /trivia-game-react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /trivia-game-react/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /trivia-game-react/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {cleanup, fireEvent, render} from '@testing-library/react' 3 | import App from './App' 4 | import {createModel} from '@xstate/test' 5 | import {assign, Machine} from 'xstate' 6 | 7 | const testMachine = Machine( 8 | { 9 | id: 'Machine', 10 | initial: 'welcome', 11 | context: { 12 | currentQuestion: 0, 13 | currentQuestionDisplay: 1, 14 | questions: [], 15 | totalCorrectAnswers: 0, 16 | }, 17 | states: { 18 | welcome: { 19 | on: { 20 | START_QUIZ: 'loading', 21 | }, 22 | meta: { 23 | test: ({getByTestId}: {getByTestId: any}) => { 24 | expect(getByTestId('welcome-header')) 25 | }, 26 | }, 27 | }, 28 | loading: { 29 | on: { 30 | SUCCESS: { 31 | target: 'quiz', 32 | actions: 'resolveData', 33 | }, 34 | FAILURE: 'failure', 35 | }, 36 | meta: { 37 | test: ({getByTestId}: {getByTestId: any}) => { 38 | expect(getByTestId('loading-header')) 39 | }, 40 | }, 41 | }, 42 | failure: { 43 | on: { 44 | RETRY: 'loading', 45 | START_OVER: 'welcome', 46 | }, 47 | meta: { 48 | test: ({getByTestId}: {getByTestId: any}) => { 49 | expect(getByTestId('failure-header')) 50 | }, 51 | }, 52 | }, 53 | quiz: { 54 | on: { 55 | '': { 56 | target: 'results', 57 | cond: 'allQuestionsAnswered', 58 | }, 59 | ANSWER_FALSE: { 60 | actions: 'updateAnswer', 61 | }, 62 | ANSWER_TRUE: { 63 | actions: 'updateAnswer', 64 | }, 65 | }, 66 | meta: { 67 | test: ({getByTestId}: {getByTestId: any}) => { 68 | expect(getByTestId('quiz-header')) 69 | }, 70 | }, 71 | }, 72 | results: { 73 | on: { 74 | PLAY_AGAIN: 'welcome', 75 | }, 76 | meta: { 77 | test: ({getByTestId}: {getByTestId: any}) => { 78 | expect(getByTestId('results-header')) 79 | }, 80 | }, 81 | exit: 'resetGame', 82 | }, 83 | }, 84 | }, 85 | { 86 | actions: { 87 | resetGame: assign({ 88 | currentQuestion: 0, 89 | currentQuestionDisplay: 1, 90 | questions: [], 91 | totalCorrectAnswers: 0, 92 | }), 93 | resolveData: assign({ 94 | questions: [ 95 | { 96 | category: 'Entertainment: Video Games', 97 | question: 'Unturned originally started as a Roblox game.', 98 | correctAnswer: true, 99 | userAnswer: undefined, 100 | correct: undefined, 101 | }, 102 | { 103 | category: 'Entertainment: Comics', 104 | question: 105 | 'In the comic book "Archie", Betty is friends with Veronica because she is rich.', 106 | correctAnswer: false, 107 | userAnswer: undefined, 108 | correct: undefined, 109 | }, 110 | { 111 | category: 'Entertainment: Video Games', 112 | question: 113 | 'In Undertale, having a "Fun Value" set to 56-57 will play the "Wrong Number Song Call".', 114 | correctAnswer: false, 115 | userAnswer: undefined, 116 | correct: undefined, 117 | }, 118 | { 119 | category: 'Entertainment: Video Games', 120 | question: 121 | 'TF2: Sentry rocket damage falloff is calculated ba…try and the enemy, not the engineer and the enemy', 122 | correctAnswer: false, 123 | userAnswer: undefined, 124 | correct: undefined, 125 | }, 126 | { 127 | category: 'Mythology', 128 | question: 129 | 'Rannamaari was a sea demon that haunted the people…ased monthly with the sacrifice of a virgin girl.', 130 | correctAnswer: true, 131 | userAnswer: undefined, 132 | correct: undefined, 133 | }, 134 | { 135 | category: 'General Knowledge', 136 | question: 'In Scandinavian languages, the letter Å means river.', 137 | correctAnswer: true, 138 | userAnswer: undefined, 139 | correct: undefined, 140 | }, 141 | { 142 | category: 'Entertainment: Music', 143 | question: 'The band STRFKR was also briefly known as Pyramiddd.', 144 | correctAnswer: true, 145 | userAnswer: undefined, 146 | correct: undefined, 147 | }, 148 | { 149 | category: 'Politics', 150 | question: 151 | "Nazi Germany surrendered on Harry Truman's birthday while he was president.", 152 | correctAnswer: true, 153 | userAnswer: undefined, 154 | correct: undefined, 155 | }, 156 | { 157 | category: 'Celebrities', 158 | question: 159 | "Lady Gaga's real name is Stefani Joanne Angelina Germanotta.", 160 | correctAnswer: true, 161 | userAnswer: undefined, 162 | correct: undefined, 163 | }, 164 | { 165 | category: 'History', 166 | question: 167 | "During the Winter War, the amount of Soviet Union … went missing was five times more than Finland's.", 168 | correctAnswer: true, 169 | userAnswer: undefined, 170 | correct: undefined, 171 | }, 172 | ], 173 | }), 174 | updateAnswer: assign((ctx: any, event: any) => ({ 175 | questions: [ 176 | ...ctx.questions.slice(0, ctx.currentQuestion), 177 | { 178 | ...ctx.questions[ctx.currentQuestion], 179 | userAnswer: event.answer, 180 | correct: 181 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer, 182 | }, 183 | ...ctx.questions.slice(ctx.currentQuestion + 1), 184 | ], 185 | totalCorrectAnswers: 186 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer 187 | ? (ctx.totalCorrectAnswers += 1) 188 | : ctx.totalCorrectAnswers, 189 | currentQuestion: ctx.currentQuestion += 1, 190 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1, 191 | })), 192 | }, 193 | guards: { 194 | allQuestionsAnswered: ctx => { 195 | return ( 196 | ctx.questions.filter( 197 | (question: any) => question.correct !== undefined, 198 | ).length === ctx.questions.length && true 199 | ) 200 | }, 201 | }, 202 | }, 203 | ) 204 | 205 | describe('trivia app', () => { 206 | const testModel = createModel(testMachine).withEvents({ 207 | START_QUIZ: ({getByTestId}: {getByTestId: any}) => { 208 | fireEvent.click(getByTestId('begin-button')) 209 | }, 210 | FAILURE: () => {}, 211 | SUCCESS: () => {}, 212 | RETRY: ({getByTestId}: {getByTestId: any}) => { 213 | fireEvent.click(getByTestId('retry-button')) 214 | }, 215 | START_OVER: ({getByTestId}: {getByTestId: any}) => { 216 | fireEvent.click(getByTestId('start-over-button')) 217 | }, 218 | ANSWER_TRUE: ({getByTestId}: {getByTestId: any}) => { 219 | fireEvent.click(getByTestId('answer-true-button')) 220 | }, 221 | ANSWER_FALSE: ({getByTestId}: {getByTestId: any}) => { 222 | fireEvent.click(getByTestId('answer-false-button')) 223 | }, 224 | PLAY_AGAIN: ({getByTestId}: {getByTestId: any}) => { 225 | fireEvent.click(getByTestId('play-again-button')) 226 | }, 227 | }) 228 | 229 | const testPlans = testModel.getSimplePathPlans() 230 | testPlans.forEach((plan: any) => { 231 | describe(plan.description, () => { 232 | afterEach(cleanup) 233 | plan.paths.forEach((path: any) => { 234 | it(path.description, () => { 235 | const rendered = render() 236 | return path.test(rendered) 237 | }) 238 | }) 239 | }) 240 | }) 241 | 242 | it('coverage', () => { 243 | testModel.testCoverage() 244 | }) 245 | }) 246 | -------------------------------------------------------------------------------- /trivia-game-react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {useMachine} from '@xstate/react' 3 | import tw from 'tailwind.macro' 4 | import {GlobalStyle} from './components' 5 | import machine from './machine' 6 | import { 7 | Failure as FailureScreen, 8 | Loading as LoadingScreen, 9 | Quiz as QuizScreen, 10 | Results as ResultsScreen, 11 | Welcome as WelcomeScreen, 12 | } from './screens' 13 | 14 | const AppWrapper = tw.div`min-h-screen min-w-screen h-screen w-screen flex justify-center items-center bg-gray-200` 15 | const Main = tw.main`z-20 w-11/12 h-auto max-h-screen overflow-y-scroll m-4 flex flex-col items-center bg-white rounded shadow md:w-3/4 lg:w-1/2 md:m-0` 16 | 17 | function App() { 18 | const [current, send] = useMachine(machine) 19 | 20 | const renderScreen = () => { 21 | switch (current.value) { 22 | case 'welcome': 23 | return send('START_QUIZ')} /> 24 | case 'loading': 25 | return 26 | case 'failure': 27 | return ( 28 | send('RETRY')} 30 | startOver={() => send('START_OVER')} 31 | /> 32 | ) 33 | case 'quiz': 34 | return ( 35 | send({type: 'ANSWER_FALSE', answer: false})} 37 | answerTrue={() => send({type: 'ANSWER_TRUE', answer: true})} 38 | currentQuestionNumber={current.context.currentQuestionDisplay} 39 | question={ 40 | current.context.questions[current.context.currentQuestion] 41 | } 42 | totalQuestions={current.context.questions.length} 43 | /> 44 | ) 45 | case 'results': 46 | return ( 47 | send('PLAY_AGAIN')} 49 | questions={current.context.questions} 50 | totalCorrectAnswers={current.context.totalCorrectAnswers} 51 | totalQuestions={current.context.questions.length} 52 | /> 53 | ) 54 | default: 55 | return null 56 | } 57 | } 58 | 59 | return ( 60 | 61 | 62 |
{renderScreen()}
63 |
64 | ) 65 | } 66 | 67 | export default App 68 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/Actions.ts: -------------------------------------------------------------------------------- 1 | import tw from 'tailwind.macro' 2 | 3 | export const Actions = tw.div`flex flex-col md:flex-row w-full md:w-1/2 justify-around` 4 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/Button.ts: -------------------------------------------------------------------------------- 1 | import tw from 'tailwind.macro' 2 | 3 | export const Button = tw.button`mt-4 mb-2 md:mt-0 md:mb-0 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded` 4 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/Container.ts: -------------------------------------------------------------------------------- 1 | import tw from 'tailwind.macro' 2 | 3 | export const Container = tw.div`flex flex-col justify-between items-center w-full h-full p-5` 4 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/CorrectIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import tw from 'tailwind.macro' 3 | 4 | const CheckmarkSvg = () => ( 5 | 6 | 7 | 8 | ) 9 | 10 | const Icon = tw.div`h-4 w-4 text-green-500 hover:text-green-700` 11 | 12 | export const CorrectIcon = () => ( 13 | 14 | 15 | 16 | ) 17 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/GlobalStyle.ts: -------------------------------------------------------------------------------- 1 | import {createGlobalStyle} from 'styled-components' 2 | 3 | export const GlobalStyle = createGlobalStyle` 4 | html { 5 | line-height: 1.15; 6 | -webkit-text-size-adjust: 100%; 7 | } 8 | body { 9 | margin: 0; 10 | } 11 | main { 12 | display: block; 13 | } 14 | h1 { 15 | font-size: 2em; 16 | margin: 0.67em 0; 17 | } 18 | hr { 19 | box-sizing: content-box; 20 | height: 0; 21 | overflow: visible; 22 | } 23 | pre { 24 | font-family: monospace, monospace; 25 | font-size: 1em; 26 | } 27 | a { 28 | background-color: transparent; 29 | } 30 | abbr[title] { 31 | border-bottom: none; 32 | text-decoration: underline; 33 | -webkit-text-decoration: underline dotted; 34 | text-decoration: underline dotted; 35 | } 36 | b, 37 | strong { 38 | font-weight: bolder; 39 | } 40 | code, 41 | kbd, 42 | samp { 43 | font-family: monospace, monospace; 44 | font-size: 1em; 45 | } 46 | small { 47 | font-size: 80%; 48 | } 49 | sub, 50 | sup { 51 | font-size: 75%; 52 | line-height: 0; 53 | position: relative; 54 | vertical-align: baseline; 55 | } 56 | sub { 57 | bottom: -0.25em; 58 | } 59 | sup { 60 | top: -0.5em; 61 | } 62 | img { 63 | border-style: none; 64 | } 65 | button, 66 | input, 67 | optgroup, 68 | select, 69 | textarea { 70 | font-family: inherit; 71 | font-size: 100%; 72 | line-height: 1.15; 73 | margin: 0; 74 | } 75 | button, 76 | input { 77 | overflow: visible; 78 | } 79 | button, 80 | select { 81 | text-transform: none; 82 | } 83 | button, 84 | [type="button"], 85 | [type="reset"], 86 | [type="submit"] { 87 | -webkit-appearance: button; 88 | } 89 | button::-moz-focus-inner, 90 | [type="button"]::-moz-focus-inner, 91 | [type="reset"]::-moz-focus-inner, 92 | [type="submit"]::-moz-focus-inner { 93 | border-style: none; 94 | padding: 0; 95 | } 96 | button:-moz-focusring, 97 | [type="button"]:-moz-focusring, 98 | [type="reset"]:-moz-focusring, 99 | [type="submit"]:-moz-focusring { 100 | outline: 1px dotted ButtonText; 101 | } 102 | fieldset { 103 | padding: 0.35em 0.75em 0.625em; 104 | } 105 | legend { 106 | box-sizing: border-box; 107 | color: inherit; 108 | display: table; 109 | max-width: 100%; 110 | padding: 0; 111 | white-space: normal; 112 | } 113 | progress { 114 | vertical-align: baseline; 115 | } 116 | textarea { 117 | overflow: auto; 118 | } 119 | [type="checkbox"], 120 | [type="radio"] { 121 | box-sizing: border-box; 122 | padding: 0; 123 | } 124 | [type="number"]::-webkit-inner-spin-button, 125 | [type="number"]::-webkit-outer-spin-button { 126 | height: auto; 127 | } 128 | [type="search"] { 129 | -webkit-appearance: textfield; 130 | outline-offset: -2px; 131 | } 132 | [type="search"]::-webkit-search-decoration { 133 | -webkit-appearance: none; 134 | } 135 | ::-webkit-file-upload-button { 136 | -webkit-appearance: button; 137 | font: inherit; 138 | } 139 | details { 140 | display: block; 141 | } 142 | summary { 143 | display: list-item; 144 | } 145 | template { 146 | display: none; 147 | } 148 | [hidden] { 149 | display: none; 150 | } 151 | html { 152 | box-sizing: border-box; 153 | font-family: sans-serif; 154 | } 155 | *, 156 | *::before, 157 | *::after { 158 | box-sizing: inherit; 159 | } 160 | blockquote, 161 | dl, 162 | dd, 163 | h1, 164 | h2, 165 | h3, 166 | h4, 167 | h5, 168 | h6, 169 | figure, 170 | p, 171 | pre { 172 | margin: 0; 173 | } 174 | button { 175 | background: transparent; 176 | padding: 0; 177 | } 178 | button:focus { 179 | outline: 1px dotted; 180 | outline: 5px auto -webkit-focus-ring-color; 181 | } 182 | fieldset { 183 | margin: 0; 184 | padding: 0; 185 | } 186 | ol, 187 | ul { 188 | list-style: none; 189 | margin: 0; 190 | padding: 0; 191 | } 192 | html { 193 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 1 */ 194 | line-height: 1.5; 195 | } 196 | *, 197 | *::before, 198 | *::after { 199 | border-width: 0; 200 | border-style: solid; 201 | border-color: #e2e8f0; 202 | } 203 | img { 204 | border-style: solid; 205 | } 206 | textarea { 207 | resize: vertical; 208 | } 209 | input:-ms-input-placeholder, 210 | textarea:-ms-input-placeholder { 211 | color: inherit; 212 | opacity: 0.5; 213 | } 214 | input::-ms-input-placeholder, 215 | textarea::-ms-input-placeholder { 216 | color: inherit; 217 | opacity: 0.5; 218 | } 219 | input::placeholder, 220 | textarea::placeholder { 221 | color: inherit; 222 | opacity: 0.5; 223 | } 224 | button, 225 | [role="button"] { 226 | cursor: pointer; 227 | } 228 | table { 229 | border-collapse: collapse; 230 | } 231 | h1, 232 | h2, 233 | h3, 234 | h4, 235 | h5, 236 | h6 { 237 | font-size: inherit; 238 | font-weight: inherit; 239 | } 240 | a { 241 | color: inherit; 242 | text-decoration: inherit; 243 | } 244 | button, 245 | input, 246 | optgroup, 247 | select, 248 | textarea { 249 | padding: 0; 250 | line-height: inherit; 251 | color: inherit; 252 | } 253 | pre, 254 | code, 255 | kbd, 256 | samp { 257 | font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 258 | } 259 | img, 260 | svg, 261 | video, 262 | canvas, 263 | audio, 264 | iframe, 265 | embed, 266 | object { 267 | display: block; 268 | vertical-align: middle; 269 | } 270 | img, 271 | video { 272 | max-width: 100%; 273 | height: auto; 274 | } 275 | ` 276 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/TextContainer.ts: -------------------------------------------------------------------------------- 1 | import tw from 'tailwind.macro' 2 | 3 | export const TextContainer = tw.div`flex flex-col items-center my-4` 4 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/Typography.ts: -------------------------------------------------------------------------------- 1 | import tw from 'tailwind.macro' 2 | 3 | export const H1 = tw.h1`antialiased font-sans text-2xl font-bold text-gray-800 text-center` 4 | 5 | export const P = tw.p`antialiased font-sans text-base font-nomral text-gray-800 text-center` 6 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/WrongIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import tw from 'tailwind.macro' 3 | 4 | const CloseSvg = () => ( 5 | 6 | 10 | 11 | ) 12 | 13 | const Icon = tw.div`h-4 w-4 text-red-500 hover:text-red-700` 14 | 15 | export const WrongIcon = () => ( 16 | 17 | 18 | 19 | ) 20 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/__tests__/Actions.tsx: -------------------------------------------------------------------------------- 1 | import {render} from '@testing-library/react' 2 | import React from 'react' 3 | import {Actions} from '../Actions' 4 | 5 | describe('', () => { 6 | it('should match snapshot', () => { 7 | const {container} = render() 8 | expect(container).toMatchSnapshot() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /trivia-game-react/src/components/__tests__/Button.tsx: -------------------------------------------------------------------------------- 1 | import {render} from '@testing-library/react' 2 | import React from 'react' 3 | import {Button} from '../Button' 4 | 5 | describe(' 22 | 25 | 26 | 27 | ) 28 | -------------------------------------------------------------------------------- /trivia-game-react/src/screens/Loading.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import tw from 'tailwind.macro' 3 | import {Container as Wrapper, H1} from '../components' 4 | 5 | const Container = tw(Wrapper)`justify-center` 6 | 7 | export const Loading: React.FC = () => ( 8 | 9 |

Loading...

10 |
11 | ) 12 | -------------------------------------------------------------------------------- /trivia-game-react/src/screens/Quiz.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import tw from 'tailwind.macro' 3 | import {State} from 'xstate' 4 | import {Actions, Button, Container, H1, P} from '../components' 5 | import {AppMachineContext, AppMachineEvent, Question} from '../types' 6 | 7 | const QuestionText = tw(P)`w-full md:w-4/5 mb-2 text-center` 8 | const QuestionsCount = tw(P)`text-sm mt-2` 9 | const Content = tw(Container)`w-full md:w-3/4 p-0 md:p-5` 10 | 11 | interface QuizProps { 12 | answerFalse: () => State 13 | answerTrue: () => State 14 | currentQuestionNumber: number 15 | question: Question 16 | totalQuestions: number 17 | } 18 | export const Quiz: React.FC = ({ 19 | answerFalse, 20 | answerTrue, 21 | currentQuestionNumber, 22 | question, 23 | totalQuestions, 24 | }) => { 25 | return ( 26 | 27 |

{question.category}

28 | 29 | {question.question} 30 | 31 | 34 | 37 | 38 | 39 | 40 | {currentQuestionNumber} of {totalQuestions} 41 | 42 |
43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /trivia-game-react/src/screens/Results.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import tw from 'tailwind.macro' 3 | import {State} from 'xstate' 4 | import {Button, Container, CorrectIcon, H1, WrongIcon} from '../components' 5 | import {AppMachineContext, AppMachineEvent, Question} from '../types' 6 | 7 | const QuestionResults = tw.ul`w-3/4 my-4` 8 | const Icon = tw.span`mr-4` 9 | const Result = tw.li`flex mb-4 items-center` 10 | 11 | interface ResultsProps { 12 | questions: Question[] 13 | playAgain: () => State 14 | totalCorrectAnswers: number 15 | totalQuestions: number 16 | } 17 | 18 | export const Results: React.FC = ({ 19 | playAgain, 20 | questions, 21 | totalCorrectAnswers, 22 | totalQuestions, 23 | }) => ( 24 | 25 |

26 | You scored 27 |
28 | {totalCorrectAnswers} / {totalQuestions} 29 |

30 | 31 | {questions.map(question => ( 32 | 33 | 34 | {question.correct === true ? : } 35 | {' '} 36 | {question.question} 37 | 38 | ))} 39 | 40 | 43 |
44 | ) 45 | -------------------------------------------------------------------------------- /trivia-game-react/src/screens/Welcome.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {State} from 'xstate' 3 | import {Button, Container, H1, P, TextContainer} from '../components' 4 | import {AppMachineContext, AppMachineEvent} from '../types' 5 | 6 | interface WelcomeProps { 7 | startQuiz: () => State 8 | } 9 | export const Welcome: React.FC = ({startQuiz}) => ( 10 | 11 |

Welcome to the Trivia Challenge

12 | 13 |

You will be presented with 10 true or false questions.

14 |

Can you score 100%?

15 |
16 | 19 |
20 | ) 21 | -------------------------------------------------------------------------------- /trivia-game-react/src/screens/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Failure' 2 | export * from './Loading' 3 | export * from './Quiz' 4 | export * from './Results' 5 | export * from './Welcome' 6 | -------------------------------------------------------------------------------- /trivia-game-react/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | import 'jest-axe/extend-expect' 2 | import '@testing-library/jest-dom/extend-expect' 3 | -------------------------------------------------------------------------------- /trivia-game-react/src/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: {}, 3 | variants: {}, 4 | plugins: [], 5 | } 6 | -------------------------------------------------------------------------------- /trivia-game-react/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface QuizDataQuestion { 2 | category: string 3 | type: string 4 | difficulty: string 5 | question: string 6 | correct_answer: string 7 | incorrect_answers: string[] 8 | } 9 | 10 | export interface FetchQuizDataResponse { 11 | response_code: number 12 | results: Question[] 13 | } 14 | 15 | export interface Question { 16 | category: string 17 | question: string 18 | correctAnswer: boolean 19 | userAnswer?: boolean 20 | correct?: boolean 21 | } 22 | 23 | export interface AppMachineSchema { 24 | states: { 25 | welcome: {} 26 | loading: {} 27 | failure: {} 28 | quiz: {} 29 | results: {} 30 | } 31 | } 32 | 33 | export type AppMachineEvent = 34 | | {type: 'START_QUIZ'} 35 | | {type: 'RETRY'} 36 | | {type: 'START_OVER'} 37 | | {type: 'ANSWER_FALSE'; answer: boolean} 38 | | {type: 'ANSWER_TRUE'; answer: boolean} 39 | | {type: 'PLAY_AGAIN'} 40 | 41 | export interface AppMachineContext { 42 | currentQuestion: number 43 | currentQuestionDisplay: number 44 | questions: Question[] 45 | totalCorrectAnswers: number 46 | } 47 | -------------------------------------------------------------------------------- /trivia-game-react/src/utils/fetchAndNormalizeQuizData.ts: -------------------------------------------------------------------------------- 1 | import {fetchQuizData, normalizeQuizData} from '.' 2 | 3 | export const fetchAndNormalizeQuizData = async () => { 4 | try { 5 | const data = await fetchQuizData() 6 | return Promise.resolve(normalizeQuizData(data.results)) 7 | } catch (error) { 8 | return Promise.reject(error) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /trivia-game-react/src/utils/fetchQuizData.ts: -------------------------------------------------------------------------------- 1 | export const fetchQuizData = () => 2 | fetch( 3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`, 4 | ).then(response => response.json()) 5 | -------------------------------------------------------------------------------- /trivia-game-react/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fetchAndNormalizeQuizData' 2 | export * from './fetchQuizData' 3 | export * from './normalizeQuizData' 4 | -------------------------------------------------------------------------------- /trivia-game-react/src/utils/normalizeQuizData.ts: -------------------------------------------------------------------------------- 1 | import decode from 'lean-he/decode' 2 | import {Question, QuizDataQuestion} from '../types' 3 | 4 | export const normalizeQuizData = (data: QuizDataQuestion[]): Question[] => 5 | data.reduce( 6 | (acc: Question[], obj: QuizDataQuestion) => [ 7 | ...acc, 8 | { 9 | category: decode(obj.category), 10 | question: decode(obj.question), 11 | correctAnswer: obj.correct_answer === 'True' ? true : false, 12 | userAnswer: undefined, 13 | correct: undefined, 14 | }, 15 | ], 16 | [], 17 | ) 18 | -------------------------------------------------------------------------------- /trivia-game-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /trivia-game-svelte/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | 10 | -------------------------------------------------------------------------------- /trivia-game-svelte/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | public/bundle.* 4 | -------------------------------------------------------------------------------- /trivia-game-svelte/.node-version: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-svelte/.nvmrc: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-svelte/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | .env.local 6 | .env.*.local 7 | 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | *.sw? 19 | 20 | -------------------------------------------------------------------------------- /trivia-game-svelte/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": false, 4 | "htmlWhitespaceSensitivity": "css", 5 | "insertPragma": false, 6 | "jsxBracketSameLine": false, 7 | "jsxSingleQuote": true, 8 | "printWidth": 80, 9 | "proseWrap": "always", 10 | "requirePragma": false, 11 | "semi": false, 12 | "singleQuote": true, 13 | "tabWidth": 2, 14 | "trailingComma": "all", 15 | "useTabs": false 16 | } 17 | 18 | -------------------------------------------------------------------------------- /trivia-game-svelte/README.md: -------------------------------------------------------------------------------- 1 | # Trivia Game 2 | 3 | This example showcases several state machine concepts including guards, 4 | transient functions, and invoking services. 5 | 6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068) 7 | 8 | ## Running Locally 9 | 10 | 1. After cloning and navigating into the `trivia-game-svelte` directory, execute: 11 | 12 | ``` 13 | yarn && yarn test 14 | ``` 15 | 16 | or 17 | 18 | ``` 19 | npm install && npm t 20 | ``` 21 | 22 | This will install dependencies and run tests to verify no issues 23 | 24 | 2. Start the application by executing: 25 | 26 | ``` 27 | yarn start 28 | ``` 29 | 30 | or 31 | 32 | ``` 33 | npm start 34 | ``` 35 | -------------------------------------------------------------------------------- /trivia-game-svelte/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "" 3 | command = "yarn build" 4 | publish = "/dist" 5 | -------------------------------------------------------------------------------- /trivia-game-svelte/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "@fullhuman/postcss-purgecss": "^7.0.2", 6 | "@rollup/plugin-commonjs": "^28.0.3", 7 | "@rollup/plugin-node-resolve": "^16.0.1", 8 | "@rollup/plugin-replace": "^6.0.2", 9 | "lean-he": "2.1.2", 10 | "postcss": "^8.5.4", 11 | "postcss-load-config": "^6.0.1", 12 | "rollup": "^4.41.1", 13 | "rollup-plugin-livereload": "^2.0.5", 14 | "rollup-plugin-svelte": "^7.2.2", 15 | "rollup-plugin-terser": "^7.0.2", 16 | "svelte": "^5.33.14", 17 | "svelte-preprocess": "^6.0.3", 18 | "tailwindcss": "4.1.8", 19 | "xstate": "4.38.3" 20 | }, 21 | "dependencies": { 22 | "sirv-cli": "^3.0.1", 23 | "svelte-xstate": "^1.0.1" 24 | }, 25 | "scripts": { 26 | "build": "rollup -c", 27 | "start": "rollup -c -w", 28 | "start:prod": "sirv public --single", 29 | "start:dev": "sirv public --single --dev" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /trivia-game-svelte/postcss.config.js: -------------------------------------------------------------------------------- 1 | const purgecss = require('@fullhuman/postcss-purgecss')({ 2 | content: [ 3 | './src/**/*.html', 4 | './src/**/*.svelte' 5 | ], 6 | 7 | whitelistPatterns: [/svelte-/], 8 | 9 | defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [] 10 | }); 11 | 12 | const production = !process.env.ROLLUP_WATCH 13 | 14 | module.exports = { 15 | plugins: [ 16 | require('tailwindcss'), 17 | ...(production ? [purgecss] : []) 18 | ] 19 | }; 20 | -------------------------------------------------------------------------------- /trivia-game-svelte/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-svelte/public/favicon.png -------------------------------------------------------------------------------- /trivia-game-svelte/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Svelte app 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /trivia-game-svelte/rollup.config.js: -------------------------------------------------------------------------------- 1 | import svelte from 'rollup-plugin-svelte'; 2 | import replace from '@rollup/plugin-replace'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import commonjs from '@rollup/plugin-commonjs'; 5 | import livereload from 'rollup-plugin-livereload'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | import sveltePreprocess from 'svelte-preprocess'; 8 | 9 | import rollup_start_dev from './rollup_start_dev'; 10 | 11 | const production = !process.env.ROLLUP_WATCH; 12 | 13 | export default { 14 | input: 'src/main.js', 15 | output: { 16 | sourcemap: true, 17 | format: 'iife', 18 | name: 'app', 19 | file: 'public/bundle.js' 20 | }, 21 | plugins: [ 22 | svelte({ 23 | preprocess: sveltePreprocess({ postcss: true }), 24 | // enable run-time checks when not in production 25 | dev: !production, 26 | // we'll extract any component CSS out into 27 | // a separate file — better for performance 28 | css: css => { 29 | css.write('public/bundle.css'); 30 | } 31 | }), 32 | replace({ 33 | "process.env.NODE_ENV": production 34 | ? JSON.stringify("production") 35 | : JSON.stringify("development") 36 | }), 37 | 38 | // If you have external dependencies installed from 39 | // npm, you'll most likely need these plugins. In 40 | // some cases you'll need additional configuration — 41 | // consult the documentation for details: 42 | // https://github.com/rollup/rollup-plugin-commonjs 43 | resolve({ 44 | browser: true, 45 | dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/') 46 | }), 47 | commonjs(), 48 | 49 | // In dev mode, call `npm run start:dev` once 50 | // the bundle has been generated 51 | !production && rollup_start_dev, 52 | 53 | // Watch the `public` directory and refresh the 54 | // browser on changes when not in production 55 | !production && livereload('public'), 56 | 57 | // If we're building for production (npm run build 58 | // instead of npm run dev), minify 59 | production && terser() 60 | ], 61 | watch: { 62 | clearScreen: false 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /trivia-game-svelte/rollup_start_dev.js: -------------------------------------------------------------------------------- 1 | import * as child_process from 'child_process'; 2 | 3 | let running_dev_server = false; 4 | 5 | export default { 6 | writeBundle() { 7 | if (!running_dev_server) { 8 | running_dev_server = true; 9 | child_process.spawn('npm', ['run', 'start:dev'], { stdio: ['ignore', 'inherit', 'inherit'], shell: true }); 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/App.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {#if $current.matches('welcome')} 5 | 6 | {:else if $current.matches('loading')} 7 | 8 | {:else if $current.matches('failure')} 9 | 10 | {:else if $current.matches('quiz')} 11 | 18 | {:else if $current.matches('results')} 19 | 25 | {/if} 26 |
27 |
28 | 29 | 60 | 61 | 82 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/Actions.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 16 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/Button.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/Container.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 10 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/CorrectIcon.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | 16 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/GlobalStyle.svelte: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/H1.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 10 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/P.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 10 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/TextContainer.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 10 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/components/WrongIcon.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 | 8 |
9 | 10 | 19 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/machine.js: -------------------------------------------------------------------------------- 1 | import {assign, Machine} from 'xstate' 2 | import {fetchAndNormalizeQuizData} from './utils' 3 | 4 | const machine = Machine( 5 | { 6 | id: 'Machine', 7 | initial: 'welcome', 8 | context: { 9 | currentQuestion: 0, 10 | currentQuestionDisplay: 1, 11 | questions: [], 12 | totalCorrectAnswers: 0, 13 | }, 14 | states: { 15 | welcome: { 16 | on: { 17 | START_QUIZ: 'loading', 18 | }, 19 | }, 20 | loading: { 21 | invoke: { 22 | id: 'getQuizData', 23 | src: 'fetchAndNormalizeQuizData', 24 | onDone: { 25 | target: 'quiz', 26 | actions: assign({ 27 | questions: (_, event) => event.data, 28 | }), 29 | }, 30 | onError: { 31 | target: 'failure', 32 | }, 33 | }, 34 | }, 35 | failure: { 36 | on: { 37 | RETRY: 'loading', 38 | START_OVER: 'welcome', 39 | }, 40 | }, 41 | quiz: { 42 | on: { 43 | '': { 44 | target: 'results', 45 | actions: [], 46 | cond: 'allQuestionsAnswered', 47 | }, 48 | ANSWER_FALSE: { 49 | actions: 'updateAnswer', 50 | }, 51 | ANSWER_TRUE: { 52 | actions: 'updateAnswer', 53 | }, 54 | }, 55 | }, 56 | results: { 57 | on: { 58 | PLAY_AGAIN: 'welcome', 59 | }, 60 | exit: 'resetGame', 61 | }, 62 | }, 63 | }, 64 | { 65 | actions: { 66 | resetGame: assign({ 67 | currentQuestion: 0, 68 | currentQuestionDisplay: 1, 69 | questions: [], 70 | totalCorrectAnswers: 0, 71 | }), 72 | updateAnswer: assign((ctx, event) => ({ 73 | questions: [ 74 | ...ctx.questions.slice(0, ctx.currentQuestion), 75 | { 76 | ...ctx.questions[ctx.currentQuestion], 77 | userAnswer: event.answer, 78 | correct: 79 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer, 80 | }, 81 | ...ctx.questions.slice(ctx.currentQuestion + 1), 82 | ], 83 | totalCorrectAnswers: 84 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer 85 | ? (ctx.totalCorrectAnswers += 1) 86 | : ctx.totalCorrectAnswers, 87 | currentQuestion: ctx.currentQuestion += 1, 88 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1, 89 | })), 90 | }, 91 | guards: { 92 | allQuestionsAnswered: ctx => { 93 | return ( 94 | ctx.questions.filter( 95 | (question) => question.correct !== undefined, 96 | ).length === ctx.questions.length && true 97 | ) 98 | }, 99 | }, 100 | services: { 101 | fetchAndNormalizeQuizData: () => fetchAndNormalizeQuizData(), 102 | }, 103 | }, 104 | ) 105 | 106 | export default machine 107 | 108 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte'; 2 | 3 | const app = new App({ 4 | target: document.body, 5 | props: { 6 | name: 'world' 7 | } 8 | }); 9 | 10 | export default app; -------------------------------------------------------------------------------- /trivia-game-svelte/src/screens/Failure.svelte: -------------------------------------------------------------------------------- 1 | 2 |

Failure!

3 | 4 |

Looks like there where a problem.

5 |

You can retry loading the game or start over.

6 |
7 | 8 | 11 | 14 | 15 |
16 | 17 | 36 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/screens/Loading.svelte: -------------------------------------------------------------------------------- 1 | 2 |

Loading...

3 |
4 | 5 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/screens/Quiz.svelte: -------------------------------------------------------------------------------- 1 | 2 |

{question.category}

3 | 4 |

{question.question}

5 | 6 | 9 | 12 | 13 |
14 |

15 | { currentQuestionNumber } of { totalQuestions } 16 |

17 |
18 | 19 | 40 | 41 | 66 | 67 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/screens/Results.svelte: -------------------------------------------------------------------------------- 1 | 2 |

3 | You scored 4 |
5 | {totalCorrectAnswers} / {totalQuestions} 6 |

7 |
    8 | {#each questions as question (question.question)} 9 |
  • 10 | 11 | {#if question.correct === true} 12 | 13 | {:else if question.correct === false} 14 | 15 | {/if} 16 | 17 | {question.question} 18 |
  • 19 | {/each} 20 |
21 | 24 |
25 | 26 | 44 | 45 | 58 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/screens/Welcome.svelte: -------------------------------------------------------------------------------- 1 | 2 |

Welcome to the Trivia Challenge

3 | 4 |

You will be presented with 10 true or false questions.

5 |

Can you score 100%?

6 |
7 | 10 |
11 | 12 | 26 | 27 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/utils/fetchAndNormalizeQuizData.js: -------------------------------------------------------------------------------- 1 | import {normalizeQuizData} from './normalizeQuizData' 2 | import {fetchQuizData} from './fetchQuizData' 3 | 4 | export const fetchAndNormalizeQuizData = async () => { 5 | try { 6 | const data = await fetchQuizData() 7 | return Promise.resolve(normalizeQuizData(data.results)) 8 | } catch (error) { 9 | return Promise.reject(error) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/utils/fetchQuizData.js: -------------------------------------------------------------------------------- 1 | export const fetchQuizData = () => 2 | fetch( 3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`, 4 | ).then(response => 5 | response.json()); 6 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/utils/index.js: -------------------------------------------------------------------------------- 1 | export * from './fetchAndNormalizeQuizData' 2 | export * from './fetchQuizData' 3 | export * from './normalizeQuizData' 4 | -------------------------------------------------------------------------------- /trivia-game-svelte/src/utils/normalizeQuizData.js: -------------------------------------------------------------------------------- 1 | import decode from 'lean-he/decode' 2 | 3 | export const normalizeQuizData = data => 4 | data.reduce( 5 | (acc, obj) => [ 6 | ...acc, 7 | { 8 | category: decode(obj.category), 9 | question: decode(obj.question), 10 | correctAnswer: obj.correct_answer === 'True' ? true : false, 11 | userAnswer: undefined, 12 | correct: undefined, 13 | }, 14 | ], 15 | [], 16 | ) 17 | -------------------------------------------------------------------------------- /trivia-game-svelte/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: { 3 | extend: {} 4 | }, 5 | variants: {}, 6 | plugins: [] 7 | } 8 | -------------------------------------------------------------------------------- /trivia-game-svelte/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@ampproject/remapping@^2.3.0": 6 | version "2.3.0" 7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" 8 | integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== 9 | dependencies: 10 | "@jridgewell/gen-mapping" "^0.3.5" 11 | "@jridgewell/trace-mapping" "^0.3.24" 12 | 13 | "@babel/code-frame@^7.10.4": 14 | version "7.10.4" 15 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" 16 | integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== 17 | dependencies: 18 | "@babel/highlight" "^7.10.4" 19 | 20 | "@babel/helper-validator-identifier@^7.10.4": 21 | version "7.10.4" 22 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" 23 | integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== 24 | 25 | "@babel/highlight@^7.10.4": 26 | version "7.10.4" 27 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" 28 | integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== 29 | dependencies: 30 | "@babel/helper-validator-identifier" "^7.10.4" 31 | chalk "^2.0.0" 32 | js-tokens "^4.0.0" 33 | 34 | "@fullhuman/postcss-purgecss@^7.0.2": 35 | version "7.0.2" 36 | resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-7.0.2.tgz#ccacdbc312248c76c42cfac359f4ca5121001e67" 37 | integrity sha512-U4zAXNaVztbDxO9EdcLp51F3UxxYsb/7DN89rFxFJhfk2Wua2pvw2Kf3HdspbPhW/wpHjSjsxWYoIlbTgRSjbQ== 38 | dependencies: 39 | purgecss "^7.0.2" 40 | 41 | "@isaacs/cliui@^8.0.2": 42 | version "8.0.2" 43 | resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" 44 | integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== 45 | dependencies: 46 | string-width "^5.1.2" 47 | string-width-cjs "npm:string-width@^4.2.0" 48 | strip-ansi "^7.0.1" 49 | strip-ansi-cjs "npm:strip-ansi@^6.0.1" 50 | wrap-ansi "^8.1.0" 51 | wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" 52 | 53 | "@jridgewell/gen-mapping@^0.3.0": 54 | version "0.3.2" 55 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" 56 | integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== 57 | dependencies: 58 | "@jridgewell/set-array" "^1.0.1" 59 | "@jridgewell/sourcemap-codec" "^1.4.10" 60 | "@jridgewell/trace-mapping" "^0.3.9" 61 | 62 | "@jridgewell/gen-mapping@^0.3.5": 63 | version "0.3.5" 64 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" 65 | integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== 66 | dependencies: 67 | "@jridgewell/set-array" "^1.2.1" 68 | "@jridgewell/sourcemap-codec" "^1.4.10" 69 | "@jridgewell/trace-mapping" "^0.3.24" 70 | 71 | "@jridgewell/resolve-uri@^3.1.0": 72 | version "3.1.2" 73 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 74 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== 75 | 76 | "@jridgewell/set-array@^1.0.1": 77 | version "1.1.2" 78 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" 79 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== 80 | 81 | "@jridgewell/set-array@^1.2.1": 82 | version "1.2.1" 83 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" 84 | integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== 85 | 86 | "@jridgewell/source-map@^0.3.2": 87 | version "0.3.2" 88 | resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" 89 | integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== 90 | dependencies: 91 | "@jridgewell/gen-mapping" "^0.3.0" 92 | "@jridgewell/trace-mapping" "^0.3.9" 93 | 94 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": 95 | version "1.5.0" 96 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" 97 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== 98 | 99 | "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.9": 100 | version "0.3.25" 101 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" 102 | integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== 103 | dependencies: 104 | "@jridgewell/resolve-uri" "^3.1.0" 105 | "@jridgewell/sourcemap-codec" "^1.4.14" 106 | 107 | "@polka/url@^1.0.0-next.24": 108 | version "1.0.0-next.28" 109 | resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" 110 | integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== 111 | 112 | "@rollup/plugin-commonjs@^28.0.3": 113 | version "28.0.3" 114 | resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz#44c2cc7c955c6113b96696b55e6bc2446bd67913" 115 | integrity sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ== 116 | dependencies: 117 | "@rollup/pluginutils" "^5.0.1" 118 | commondir "^1.0.1" 119 | estree-walker "^2.0.2" 120 | fdir "^6.2.0" 121 | is-reference "1.2.1" 122 | magic-string "^0.30.3" 123 | picomatch "^4.0.2" 124 | 125 | "@rollup/plugin-node-resolve@^16.0.1": 126 | version "16.0.1" 127 | resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz#2fc6b54ca3d77e12f3fb45b2a55b50720de4c95d" 128 | integrity sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA== 129 | dependencies: 130 | "@rollup/pluginutils" "^5.0.1" 131 | "@types/resolve" "1.20.2" 132 | deepmerge "^4.2.2" 133 | is-module "^1.0.0" 134 | resolve "^1.22.1" 135 | 136 | "@rollup/plugin-replace@^6.0.2": 137 | version "6.0.2" 138 | resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz#2f565d312d681e4570ff376c55c5c08eb6f1908d" 139 | integrity sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ== 140 | dependencies: 141 | "@rollup/pluginutils" "^5.0.1" 142 | magic-string "^0.30.3" 143 | 144 | "@rollup/pluginutils@^4.1.0": 145 | version "4.2.1" 146 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" 147 | integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ== 148 | dependencies: 149 | estree-walker "^2.0.1" 150 | picomatch "^2.2.2" 151 | 152 | "@rollup/pluginutils@^5.0.1": 153 | version "5.0.1" 154 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.1.tgz#63def51f5a76dadd984689d33c7f000164152a97" 155 | integrity sha512-4HaCVEXXuObvcPUaUlLt4faHYHCeQOOWNj8NKFGaRSrw3ZLD0TWeAFZicV9vXjnE2nkNuaVTfTuwAnjR+6uc9A== 156 | dependencies: 157 | "@types/estree" "^1.0.0" 158 | estree-walker "^2.0.2" 159 | picomatch "^2.3.1" 160 | 161 | "@rollup/rollup-android-arm-eabi@4.41.1": 162 | version "4.41.1" 163 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz#f39f09f60d4a562de727c960d7b202a2cf797424" 164 | integrity sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw== 165 | 166 | "@rollup/rollup-android-arm64@4.41.1": 167 | version "4.41.1" 168 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz#d19af7e23760717f1d879d4ca3d2cd247742dff2" 169 | integrity sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA== 170 | 171 | "@rollup/rollup-darwin-arm64@4.41.1": 172 | version "4.41.1" 173 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz#1c3a2fbf205d80641728e05f4a56c909e95218b7" 174 | integrity sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w== 175 | 176 | "@rollup/rollup-darwin-x64@4.41.1": 177 | version "4.41.1" 178 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz#aa66d2ba1a25e609500e13bef06dc0e71cc0c0d4" 179 | integrity sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg== 180 | 181 | "@rollup/rollup-freebsd-arm64@4.41.1": 182 | version "4.41.1" 183 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz#df10a7b6316a0ef1028c6ca71a081124c537e30d" 184 | integrity sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg== 185 | 186 | "@rollup/rollup-freebsd-x64@4.41.1": 187 | version "4.41.1" 188 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz#a3fdce8a05e95b068cbcb46e4df5185e407d0c35" 189 | integrity sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA== 190 | 191 | "@rollup/rollup-linux-arm-gnueabihf@4.41.1": 192 | version "4.41.1" 193 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz#49f766c55383bd0498014a9d76924348c2f3890c" 194 | integrity sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg== 195 | 196 | "@rollup/rollup-linux-arm-musleabihf@4.41.1": 197 | version "4.41.1" 198 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz#1d4d7d32fc557e17d52e1857817381ea365e2959" 199 | integrity sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA== 200 | 201 | "@rollup/rollup-linux-arm64-gnu@4.41.1": 202 | version "4.41.1" 203 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz#f4fc317268441e9589edad3be8f62b6c03009bc1" 204 | integrity sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA== 205 | 206 | "@rollup/rollup-linux-arm64-musl@4.41.1": 207 | version "4.41.1" 208 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz#63a1f1b0671cb17822dabae827fef0e443aebeb7" 209 | integrity sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg== 210 | 211 | "@rollup/rollup-linux-loongarch64-gnu@4.41.1": 212 | version "4.41.1" 213 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz#c659b01cc6c0730b547571fc3973e1e955369f98" 214 | integrity sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw== 215 | 216 | "@rollup/rollup-linux-powerpc64le-gnu@4.41.1": 217 | version "4.41.1" 218 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz#612e746f9ad7e58480f964d65e0d6c3f4aae69a8" 219 | integrity sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A== 220 | 221 | "@rollup/rollup-linux-riscv64-gnu@4.41.1": 222 | version "4.41.1" 223 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz#4610dbd1dcfbbae32fbc10c20ae7387acb31110c" 224 | integrity sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw== 225 | 226 | "@rollup/rollup-linux-riscv64-musl@4.41.1": 227 | version "4.41.1" 228 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz#054911fab40dc83fafc21e470193c058108f19d8" 229 | integrity sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw== 230 | 231 | "@rollup/rollup-linux-s390x-gnu@4.41.1": 232 | version "4.41.1" 233 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz#98896eca8012547c7f04bd07eaa6896825f9e1a5" 234 | integrity sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g== 235 | 236 | "@rollup/rollup-linux-x64-gnu@4.41.1": 237 | version "4.41.1" 238 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz#01cf56844a1e636ee80dfb364e72c2b7142ad896" 239 | integrity sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A== 240 | 241 | "@rollup/rollup-linux-x64-musl@4.41.1": 242 | version "4.41.1" 243 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz#e67c7531df6dff0b4c241101d4096617fbca87c3" 244 | integrity sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ== 245 | 246 | "@rollup/rollup-win32-arm64-msvc@4.41.1": 247 | version "4.41.1" 248 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz#7eeada98444e580674de6989284e4baacd48ea65" 249 | integrity sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ== 250 | 251 | "@rollup/rollup-win32-ia32-msvc@4.41.1": 252 | version "4.41.1" 253 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz#516c4b54f80587b4a390aaf4940b40870271d35d" 254 | integrity sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg== 255 | 256 | "@rollup/rollup-win32-x64-msvc@4.41.1": 257 | version "4.41.1" 258 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz#848f99b0d9936d92221bb6070baeff4db6947a30" 259 | integrity sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw== 260 | 261 | "@sveltejs/acorn-typescript@^1.0.5": 262 | version "1.0.5" 263 | resolved "https://registry.yarnpkg.com/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz#f518101d1b2e12ce80854f1cd850d3b9fb91d710" 264 | integrity sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ== 265 | 266 | "@types/estree@*", "@types/estree@1.0.7", "@types/estree@^1.0.0", "@types/estree@^1.0.5", "@types/estree@^1.0.6": 267 | version "1.0.7" 268 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" 269 | integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== 270 | 271 | "@types/node@*": 272 | version "13.1.2" 273 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.2.tgz#fe94285bf5e0782e1a9e5a8c482b1c34465fa385" 274 | integrity sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ== 275 | 276 | "@types/resolve@1.20.2": 277 | version "1.20.2" 278 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" 279 | integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== 280 | 281 | acorn@^8.12.1, acorn@^8.5.0: 282 | version "8.13.0" 283 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" 284 | integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== 285 | 286 | ansi-regex@^5.0.1: 287 | version "5.0.1" 288 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 289 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 290 | 291 | ansi-regex@^6.0.1: 292 | version "6.0.1" 293 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" 294 | integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== 295 | 296 | ansi-styles@^3.2.1: 297 | version "3.2.1" 298 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 299 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 300 | dependencies: 301 | color-convert "^1.9.0" 302 | 303 | ansi-styles@^4.0.0: 304 | version "4.3.0" 305 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 306 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 307 | dependencies: 308 | color-convert "^2.0.1" 309 | 310 | ansi-styles@^6.1.0: 311 | version "6.2.1" 312 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" 313 | integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== 314 | 315 | anymatch@~3.1.2: 316 | version "3.1.2" 317 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 318 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 319 | dependencies: 320 | normalize-path "^3.0.0" 321 | picomatch "^2.0.4" 322 | 323 | aria-query@^5.3.1: 324 | version "5.3.2" 325 | resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" 326 | integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== 327 | 328 | async-limiter@~1.0.0: 329 | version "1.0.1" 330 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" 331 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== 332 | 333 | axobject-query@^4.1.0: 334 | version "4.1.0" 335 | resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" 336 | integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== 337 | 338 | balanced-match@^1.0.0: 339 | version "1.0.2" 340 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 341 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 342 | 343 | binary-extensions@^2.0.0: 344 | version "2.0.0" 345 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 346 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== 347 | 348 | brace-expansion@^2.0.1: 349 | version "2.0.1" 350 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 351 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 352 | dependencies: 353 | balanced-match "^1.0.0" 354 | 355 | braces@~3.0.2: 356 | version "3.0.3" 357 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 358 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 359 | dependencies: 360 | fill-range "^7.1.1" 361 | 362 | buffer-from@^1.0.0: 363 | version "1.1.2" 364 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 365 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 366 | 367 | chalk@^2.0.0: 368 | version "2.4.2" 369 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 370 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 371 | dependencies: 372 | ansi-styles "^3.2.1" 373 | escape-string-regexp "^1.0.5" 374 | supports-color "^5.3.0" 375 | 376 | chokidar@^3.3.0: 377 | version "3.6.0" 378 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" 379 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 380 | dependencies: 381 | anymatch "~3.1.2" 382 | braces "~3.0.2" 383 | glob-parent "~5.1.2" 384 | is-binary-path "~2.1.0" 385 | is-glob "~4.0.1" 386 | normalize-path "~3.0.0" 387 | readdirp "~3.6.0" 388 | optionalDependencies: 389 | fsevents "~2.3.2" 390 | 391 | clsx@^2.1.1: 392 | version "2.1.1" 393 | resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" 394 | integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== 395 | 396 | color-convert@^1.9.0: 397 | version "1.9.3" 398 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 399 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 400 | dependencies: 401 | color-name "1.1.3" 402 | 403 | color-convert@^2.0.1: 404 | version "2.0.1" 405 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 406 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 407 | dependencies: 408 | color-name "~1.1.4" 409 | 410 | color-name@1.1.3: 411 | version "1.1.3" 412 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 413 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 414 | 415 | color-name@~1.1.4: 416 | version "1.1.4" 417 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 418 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 419 | 420 | commander@^12.1.0: 421 | version "12.1.0" 422 | resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" 423 | integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== 424 | 425 | commander@^2.20.0: 426 | version "2.20.3" 427 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 428 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 429 | 430 | commondir@^1.0.1: 431 | version "1.0.1" 432 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 433 | integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= 434 | 435 | console-clear@^1.1.0: 436 | version "1.1.1" 437 | resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7" 438 | integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ== 439 | 440 | cross-spawn@^7.0.0: 441 | version "7.0.6" 442 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" 443 | integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== 444 | dependencies: 445 | path-key "^3.1.0" 446 | shebang-command "^2.0.0" 447 | which "^2.0.1" 448 | 449 | cssesc@^3.0.0: 450 | version "3.0.0" 451 | resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 452 | integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== 453 | 454 | deepmerge@^4.2.2: 455 | version "4.2.2" 456 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" 457 | integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== 458 | 459 | eastasianwidth@^0.2.0: 460 | version "0.2.0" 461 | resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 462 | integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== 463 | 464 | emoji-regex@^8.0.0: 465 | version "8.0.0" 466 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 467 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 468 | 469 | emoji-regex@^9.2.2: 470 | version "9.2.2" 471 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" 472 | integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== 473 | 474 | escape-string-regexp@^1.0.5: 475 | version "1.0.5" 476 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 477 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 478 | 479 | esm-env@^1.2.1: 480 | version "1.2.1" 481 | resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.2.1.tgz#34c2a0ba60582948afbe7bd779bc66f9d3aece7e" 482 | integrity sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng== 483 | 484 | esrap@^1.4.6: 485 | version "1.4.6" 486 | resolved "https://registry.yarnpkg.com/esrap/-/esrap-1.4.6.tgz#d203ce1ee397aa2a6a716a3a2dc8619f83208c6a" 487 | integrity sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw== 488 | dependencies: 489 | "@jridgewell/sourcemap-codec" "^1.4.15" 490 | 491 | estree-walker@^2.0.1, estree-walker@^2.0.2: 492 | version "2.0.2" 493 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 494 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 495 | 496 | fdir@^6.2.0: 497 | version "6.4.0" 498 | resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae" 499 | integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ== 500 | 501 | fill-range@^7.1.1: 502 | version "7.1.1" 503 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 504 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 505 | dependencies: 506 | to-regex-range "^5.0.1" 507 | 508 | foreground-child@^3.1.0: 509 | version "3.1.1" 510 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" 511 | integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== 512 | dependencies: 513 | cross-spawn "^7.0.0" 514 | signal-exit "^4.0.1" 515 | 516 | fsevents@~2.3.2: 517 | version "2.3.2" 518 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 519 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 520 | 521 | function-bind@^1.1.2: 522 | version "1.1.2" 523 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 524 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 525 | 526 | get-port@^5.1.1: 527 | version "5.1.1" 528 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" 529 | integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== 530 | 531 | glob-parent@~5.1.2: 532 | version "5.1.2" 533 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 534 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 535 | dependencies: 536 | is-glob "^4.0.1" 537 | 538 | glob@^11.0.0: 539 | version "11.0.0" 540 | resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" 541 | integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g== 542 | dependencies: 543 | foreground-child "^3.1.0" 544 | jackspeak "^4.0.1" 545 | minimatch "^10.0.0" 546 | minipass "^7.1.2" 547 | package-json-from-dist "^1.0.0" 548 | path-scurry "^2.0.0" 549 | 550 | has-flag@^3.0.0: 551 | version "3.0.0" 552 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 553 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 554 | 555 | has-flag@^4.0.0: 556 | version "4.0.0" 557 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 558 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 559 | 560 | hasown@^2.0.2: 561 | version "2.0.2" 562 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 563 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 564 | dependencies: 565 | function-bind "^1.1.2" 566 | 567 | is-binary-path@~2.1.0: 568 | version "2.1.0" 569 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 570 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 571 | dependencies: 572 | binary-extensions "^2.0.0" 573 | 574 | is-core-module@^2.13.0: 575 | version "2.15.1" 576 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" 577 | integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== 578 | dependencies: 579 | hasown "^2.0.2" 580 | 581 | is-extglob@^2.1.1: 582 | version "2.1.1" 583 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 584 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 585 | 586 | is-fullwidth-code-point@^3.0.0: 587 | version "3.0.0" 588 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 589 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 590 | 591 | is-glob@^4.0.1, is-glob@~4.0.1: 592 | version "4.0.3" 593 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 594 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 595 | dependencies: 596 | is-extglob "^2.1.1" 597 | 598 | is-module@^1.0.0: 599 | version "1.0.0" 600 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" 601 | integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= 602 | 603 | is-number@^7.0.0: 604 | version "7.0.0" 605 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 606 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 607 | 608 | is-reference@1.2.1: 609 | version "1.2.1" 610 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" 611 | integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== 612 | dependencies: 613 | "@types/estree" "*" 614 | 615 | is-reference@^3.0.3: 616 | version "3.0.3" 617 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" 618 | integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== 619 | dependencies: 620 | "@types/estree" "^1.0.6" 621 | 622 | isexe@^2.0.0: 623 | version "2.0.0" 624 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 625 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 626 | 627 | jackspeak@^4.0.1: 628 | version "4.0.2" 629 | resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015" 630 | integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw== 631 | dependencies: 632 | "@isaacs/cliui" "^8.0.2" 633 | 634 | jest-worker@^26.2.1: 635 | version "26.2.1" 636 | resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.2.1.tgz#5d630ab93f666b53f911615bc13e662b382bd513" 637 | integrity sha512-+XcGMMJDTeEGncRb5M5Zq9P7K4sQ1sirhjdOxsN1462h6lFo9w59bl2LVQmdGEEeU3m+maZCkS2Tcc9SfCHO4A== 638 | dependencies: 639 | "@types/node" "*" 640 | merge-stream "^2.0.0" 641 | supports-color "^7.0.0" 642 | 643 | js-tokens@^4.0.0: 644 | version "4.0.0" 645 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 646 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 647 | 648 | kleur@^4.1.4: 649 | version "4.1.4" 650 | resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" 651 | integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== 652 | 653 | lean-he@2.1.2: 654 | version "2.1.2" 655 | resolved "https://registry.yarnpkg.com/lean-he/-/lean-he-2.1.2.tgz#50c2422f0ca42f6737c9c1988b555cf00ebc712f" 656 | integrity sha512-g/cq01j/rnv7JWoxFmeLgJdd/CucksyDtS+pyepO89EdT0O4KfHJokOVz/xQ4mvjKJzcrj87Q3/s2ESou90WCQ== 657 | 658 | lilconfig@^3.1.1: 659 | version "3.1.3" 660 | resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" 661 | integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== 662 | 663 | livereload-js@^3.1.0: 664 | version "3.2.2" 665 | resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.2.2.tgz#fffb018fb8a8b06d366ca1b03af6048b8732d20f" 666 | integrity sha512-xhScbNeC687ZINjEf/bD+BMiPx4s4q0mehcLb3zCc8+mykOtmaBR4vqzyIV9rIGdG9JjHaT0LiFdscvivCjX1Q== 667 | 668 | livereload@^0.9.1: 669 | version "0.9.1" 670 | resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.1.tgz#65125dabdf2db4fd3f1169e953fe56e3bcc6f477" 671 | integrity sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw== 672 | dependencies: 673 | chokidar "^3.3.0" 674 | livereload-js "^3.1.0" 675 | opts ">= 1.2.0" 676 | ws "^6.2.1" 677 | 678 | local-access@^1.0.1: 679 | version "1.0.1" 680 | resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.0.1.tgz#5121258146d64e869046c642ea4f1dd39ff942bb" 681 | integrity sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA== 682 | 683 | locate-character@^3.0.0: 684 | version "3.0.0" 685 | resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" 686 | integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== 687 | 688 | lru-cache@^11.0.0: 689 | version "11.0.2" 690 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" 691 | integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA== 692 | 693 | magic-string@^0.30.11, magic-string@^0.30.3: 694 | version "0.30.12" 695 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.12.tgz#9eb11c9d072b9bcb4940a5b2c2e1a217e4ee1a60" 696 | integrity sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw== 697 | dependencies: 698 | "@jridgewell/sourcemap-codec" "^1.5.0" 699 | 700 | merge-stream@^2.0.0: 701 | version "2.0.0" 702 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 703 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 704 | 705 | minimatch@^10.0.0: 706 | version "10.0.1" 707 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" 708 | integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== 709 | dependencies: 710 | brace-expansion "^2.0.1" 711 | 712 | minipass@^7.1.2: 713 | version "7.1.2" 714 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" 715 | integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== 716 | 717 | mri@^1.1.0: 718 | version "1.1.4" 719 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" 720 | integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== 721 | 722 | mrmime@^2.0.0: 723 | version "2.0.0" 724 | resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" 725 | integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== 726 | 727 | nanoid@^3.3.11: 728 | version "3.3.11" 729 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" 730 | integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== 731 | 732 | normalize-path@^3.0.0, normalize-path@~3.0.0: 733 | version "3.0.0" 734 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 735 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 736 | 737 | "opts@>= 1.2.0": 738 | version "1.2.7" 739 | resolved "https://registry.yarnpkg.com/opts/-/opts-1.2.7.tgz#4de4721d592c96901dae623a438c988e9ea7779f" 740 | integrity sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA== 741 | 742 | package-json-from-dist@^1.0.0: 743 | version "1.0.1" 744 | resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" 745 | integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== 746 | 747 | path-key@^3.1.0: 748 | version "3.1.1" 749 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 750 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 751 | 752 | path-parse@^1.0.7: 753 | version "1.0.7" 754 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 755 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 756 | 757 | path-scurry@^2.0.0: 758 | version "2.0.0" 759 | resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" 760 | integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== 761 | dependencies: 762 | lru-cache "^11.0.0" 763 | minipass "^7.1.2" 764 | 765 | picocolors@^1.1.1: 766 | version "1.1.1" 767 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" 768 | integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== 769 | 770 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: 771 | version "2.3.1" 772 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 773 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 774 | 775 | picomatch@^4.0.2: 776 | version "4.0.2" 777 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" 778 | integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== 779 | 780 | postcss-load-config@^6.0.1: 781 | version "6.0.1" 782 | resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" 783 | integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== 784 | dependencies: 785 | lilconfig "^3.1.1" 786 | 787 | postcss-selector-parser@^6.1.2: 788 | version "6.1.2" 789 | resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" 790 | integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== 791 | dependencies: 792 | cssesc "^3.0.0" 793 | util-deprecate "^1.0.2" 794 | 795 | postcss@^8.4.47, postcss@^8.5.4: 796 | version "8.5.4" 797 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.4.tgz#d61014ac00e11d5f58458ed7247d899bd65f99c0" 798 | integrity sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w== 799 | dependencies: 800 | nanoid "^3.3.11" 801 | picocolors "^1.1.1" 802 | source-map-js "^1.2.1" 803 | 804 | purgecss@^7.0.2: 805 | version "7.0.2" 806 | resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-7.0.2.tgz#b7dccc3ead65a4301eed98e014793719a511c633" 807 | integrity sha512-4Ku8KoxNhOWi9X1XJ73XY5fv+I+hhTRedKpGs/2gaBKU8ijUiIKF/uyyIyh7Wo713bELSICF5/NswjcuOqYouQ== 808 | dependencies: 809 | commander "^12.1.0" 810 | glob "^11.0.0" 811 | postcss "^8.4.47" 812 | postcss-selector-parser "^6.1.2" 813 | 814 | randombytes@^2.1.0: 815 | version "2.1.0" 816 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 817 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 818 | dependencies: 819 | safe-buffer "^5.1.0" 820 | 821 | readdirp@~3.6.0: 822 | version "3.6.0" 823 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 824 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 825 | dependencies: 826 | picomatch "^2.2.1" 827 | 828 | resolve.exports@^2.0.0: 829 | version "2.0.0" 830 | resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e" 831 | integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg== 832 | 833 | resolve@^1.22.1: 834 | version "1.22.8" 835 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" 836 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== 837 | dependencies: 838 | is-core-module "^2.13.0" 839 | path-parse "^1.0.7" 840 | supports-preserve-symlinks-flag "^1.0.0" 841 | 842 | rollup-plugin-livereload@^2.0.5: 843 | version "2.0.5" 844 | resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz#4747fa292a2cceb0c972c573d71b3d66b4252b37" 845 | integrity sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA== 846 | dependencies: 847 | livereload "^0.9.1" 848 | 849 | rollup-plugin-svelte@^7.2.2: 850 | version "7.2.2" 851 | resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-7.2.2.tgz#2dc4dc9564ba7a92fb1ecb5a38db4a5ff5ac8408" 852 | integrity sha512-hgnIblTRewaBEVQD6N0Q43o+y6q1TmDRhBjaEzQCi50bs8TXqjc+d1zFZyE8tsfgcfNHZQzclh4RxlFUB85H8Q== 853 | dependencies: 854 | "@rollup/pluginutils" "^4.1.0" 855 | resolve.exports "^2.0.0" 856 | 857 | rollup-plugin-terser@^7.0.2: 858 | version "7.0.2" 859 | resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" 860 | integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== 861 | dependencies: 862 | "@babel/code-frame" "^7.10.4" 863 | jest-worker "^26.2.1" 864 | serialize-javascript "^4.0.0" 865 | terser "^5.0.0" 866 | 867 | rollup@^4.41.1: 868 | version "4.41.1" 869 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.41.1.tgz#46ddc1b33cf1b0baa99320d3b0b4973dc2253b6a" 870 | integrity sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw== 871 | dependencies: 872 | "@types/estree" "1.0.7" 873 | optionalDependencies: 874 | "@rollup/rollup-android-arm-eabi" "4.41.1" 875 | "@rollup/rollup-android-arm64" "4.41.1" 876 | "@rollup/rollup-darwin-arm64" "4.41.1" 877 | "@rollup/rollup-darwin-x64" "4.41.1" 878 | "@rollup/rollup-freebsd-arm64" "4.41.1" 879 | "@rollup/rollup-freebsd-x64" "4.41.1" 880 | "@rollup/rollup-linux-arm-gnueabihf" "4.41.1" 881 | "@rollup/rollup-linux-arm-musleabihf" "4.41.1" 882 | "@rollup/rollup-linux-arm64-gnu" "4.41.1" 883 | "@rollup/rollup-linux-arm64-musl" "4.41.1" 884 | "@rollup/rollup-linux-loongarch64-gnu" "4.41.1" 885 | "@rollup/rollup-linux-powerpc64le-gnu" "4.41.1" 886 | "@rollup/rollup-linux-riscv64-gnu" "4.41.1" 887 | "@rollup/rollup-linux-riscv64-musl" "4.41.1" 888 | "@rollup/rollup-linux-s390x-gnu" "4.41.1" 889 | "@rollup/rollup-linux-x64-gnu" "4.41.1" 890 | "@rollup/rollup-linux-x64-musl" "4.41.1" 891 | "@rollup/rollup-win32-arm64-msvc" "4.41.1" 892 | "@rollup/rollup-win32-ia32-msvc" "4.41.1" 893 | "@rollup/rollup-win32-x64-msvc" "4.41.1" 894 | fsevents "~2.3.2" 895 | 896 | sade@^1.6.0: 897 | version "1.7.3" 898 | resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.3.tgz#a217ccc4fb4abb2d271648bf48f6628b2636fa1b" 899 | integrity sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw== 900 | dependencies: 901 | mri "^1.1.0" 902 | 903 | safe-buffer@^5.1.0: 904 | version "5.2.1" 905 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 906 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 907 | 908 | semiver@^1.0.0: 909 | version "1.1.0" 910 | resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f" 911 | integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg== 912 | 913 | serialize-javascript@^4.0.0: 914 | version "4.0.0" 915 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" 916 | integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== 917 | dependencies: 918 | randombytes "^2.1.0" 919 | 920 | shebang-command@^2.0.0: 921 | version "2.0.0" 922 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 923 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 924 | dependencies: 925 | shebang-regex "^3.0.0" 926 | 927 | shebang-regex@^3.0.0: 928 | version "3.0.0" 929 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 930 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 931 | 932 | signal-exit@^4.0.1: 933 | version "4.1.0" 934 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 935 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== 936 | 937 | sirv-cli@^3.0.1: 938 | version "3.0.1" 939 | resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-3.0.1.tgz#9a53e4fa85fdc08d54a76fd76a7c866cd4c3988b" 940 | integrity sha512-ICXaF2u6IQhLZ0EXF6nqUF4YODfSQSt+mGykt4qqO5rY+oIiwdg7B8w2PVDBJlQulaS2a3J8666CUoDoAuCGvg== 941 | dependencies: 942 | console-clear "^1.1.0" 943 | get-port "^5.1.1" 944 | kleur "^4.1.4" 945 | local-access "^1.0.1" 946 | sade "^1.6.0" 947 | semiver "^1.0.0" 948 | sirv "^3.0.0" 949 | tinydate "^1.0.0" 950 | 951 | sirv@^3.0.0: 952 | version "3.0.0" 953 | resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.0.tgz#f8d90fc528f65dff04cb597a88609d4e8a4361ce" 954 | integrity sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg== 955 | dependencies: 956 | "@polka/url" "^1.0.0-next.24" 957 | mrmime "^2.0.0" 958 | totalist "^3.0.0" 959 | 960 | source-map-js@^1.2.1: 961 | version "1.2.1" 962 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" 963 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== 964 | 965 | source-map-support@~0.5.20: 966 | version "0.5.21" 967 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" 968 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 969 | dependencies: 970 | buffer-from "^1.0.0" 971 | source-map "^0.6.0" 972 | 973 | source-map@^0.6.0: 974 | version "0.6.1" 975 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 976 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 977 | 978 | "string-width-cjs@npm:string-width@^4.2.0": 979 | version "4.2.3" 980 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 981 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 982 | dependencies: 983 | emoji-regex "^8.0.0" 984 | is-fullwidth-code-point "^3.0.0" 985 | strip-ansi "^6.0.1" 986 | 987 | string-width@^4.1.0: 988 | version "4.2.3" 989 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 990 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 991 | dependencies: 992 | emoji-regex "^8.0.0" 993 | is-fullwidth-code-point "^3.0.0" 994 | strip-ansi "^6.0.1" 995 | 996 | string-width@^5.0.1, string-width@^5.1.2: 997 | version "5.1.2" 998 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" 999 | integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== 1000 | dependencies: 1001 | eastasianwidth "^0.2.0" 1002 | emoji-regex "^9.2.2" 1003 | strip-ansi "^7.0.1" 1004 | 1005 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1": 1006 | version "6.0.1" 1007 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1008 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1009 | dependencies: 1010 | ansi-regex "^5.0.1" 1011 | 1012 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 1013 | version "6.0.1" 1014 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1015 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1016 | dependencies: 1017 | ansi-regex "^5.0.1" 1018 | 1019 | strip-ansi@^7.0.1: 1020 | version "7.1.0" 1021 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" 1022 | integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== 1023 | dependencies: 1024 | ansi-regex "^6.0.1" 1025 | 1026 | supports-color@^5.3.0: 1027 | version "5.5.0" 1028 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1029 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1030 | dependencies: 1031 | has-flag "^3.0.0" 1032 | 1033 | supports-color@^7.0.0: 1034 | version "7.1.0" 1035 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 1036 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 1037 | dependencies: 1038 | has-flag "^4.0.0" 1039 | 1040 | supports-preserve-symlinks-flag@^1.0.0: 1041 | version "1.0.0" 1042 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1043 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1044 | 1045 | svelte-preprocess@^6.0.3: 1046 | version "6.0.3" 1047 | resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz#fdc1f9dc41b6f22bf8b1f059e9f21eaaae181eeb" 1048 | integrity sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA== 1049 | 1050 | svelte-xstate@^1.0.1: 1051 | version "1.0.1" 1052 | resolved "https://registry.yarnpkg.com/svelte-xstate/-/svelte-xstate-1.0.1.tgz#e04b75700ec611b057bf8a14b8ce6f35a7d7d929" 1053 | integrity sha512-k/U5goMuPnfkNIo2BlwBaHejScebULsg1RmlVgosbslxvw9FRSzV4NYzXtEWyowspJC9O9g9iVQ4WkRFXMSRlQ== 1054 | dependencies: 1055 | svelte "^3.12.1" 1056 | xstate "^4.6.7" 1057 | 1058 | svelte@^3.12.1: 1059 | version "3.59.2" 1060 | resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.59.2.tgz#a137b28e025a181292b2ae2e3dca90bf8ec73aec" 1061 | integrity sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA== 1062 | 1063 | svelte@^5.33.14: 1064 | version "5.33.14" 1065 | resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.33.14.tgz#e4fcdb01f00361373e46763947b591f878cf24fc" 1066 | integrity sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA== 1067 | dependencies: 1068 | "@ampproject/remapping" "^2.3.0" 1069 | "@jridgewell/sourcemap-codec" "^1.5.0" 1070 | "@sveltejs/acorn-typescript" "^1.0.5" 1071 | "@types/estree" "^1.0.5" 1072 | acorn "^8.12.1" 1073 | aria-query "^5.3.1" 1074 | axobject-query "^4.1.0" 1075 | clsx "^2.1.1" 1076 | esm-env "^1.2.1" 1077 | esrap "^1.4.6" 1078 | is-reference "^3.0.3" 1079 | locate-character "^3.0.0" 1080 | magic-string "^0.30.11" 1081 | zimmerframe "^1.1.2" 1082 | 1083 | tailwindcss@4.1.8: 1084 | version "4.1.8" 1085 | resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.8.tgz#5d66d095ee7d82f03d6dbc6158bc248e064a5c05" 1086 | integrity sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og== 1087 | 1088 | terser@^5.0.0: 1089 | version "5.14.2" 1090 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" 1091 | integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== 1092 | dependencies: 1093 | "@jridgewell/source-map" "^0.3.2" 1094 | acorn "^8.5.0" 1095 | commander "^2.20.0" 1096 | source-map-support "~0.5.20" 1097 | 1098 | tinydate@^1.0.0: 1099 | version "1.2.0" 1100 | resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.2.0.tgz#36b4bb02715f89743f3ef9073d3573d005a28d0e" 1101 | integrity sha512-3GwPk8VhDFnUZ2TrgkhXJs6hcMAIIw4x/xkz+ayK6dGoQmp2nUwKzBXK0WnMsqkh6vfUhpqQicQF3rbshfyJkg== 1102 | 1103 | to-regex-range@^5.0.1: 1104 | version "5.0.1" 1105 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1106 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1107 | dependencies: 1108 | is-number "^7.0.0" 1109 | 1110 | totalist@^3.0.0: 1111 | version "3.0.1" 1112 | resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" 1113 | integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== 1114 | 1115 | util-deprecate@^1.0.2: 1116 | version "1.0.2" 1117 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1118 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1119 | 1120 | which@^2.0.1: 1121 | version "2.0.2" 1122 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1123 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1124 | dependencies: 1125 | isexe "^2.0.0" 1126 | 1127 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 1128 | version "7.0.0" 1129 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 1130 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 1131 | dependencies: 1132 | ansi-styles "^4.0.0" 1133 | string-width "^4.1.0" 1134 | strip-ansi "^6.0.0" 1135 | 1136 | wrap-ansi@^8.1.0: 1137 | version "8.1.0" 1138 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" 1139 | integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== 1140 | dependencies: 1141 | ansi-styles "^6.1.0" 1142 | string-width "^5.0.1" 1143 | strip-ansi "^7.0.1" 1144 | 1145 | ws@^6.2.1: 1146 | version "6.2.3" 1147 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" 1148 | integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== 1149 | dependencies: 1150 | async-limiter "~1.0.0" 1151 | 1152 | xstate@4.38.3, xstate@^4.6.7: 1153 | version "4.38.3" 1154 | resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.3.tgz#4e15e7ad3aa0ca1eea2010548a5379966d8f1075" 1155 | integrity sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw== 1156 | 1157 | zimmerframe@^1.1.2: 1158 | version "1.1.2" 1159 | resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e" 1160 | integrity sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w== 1161 | -------------------------------------------------------------------------------- /trivia-game-vue/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | 10 | -------------------------------------------------------------------------------- /trivia-game-vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /trivia-game-vue/.node-version: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-vue/.nvmrc: -------------------------------------------------------------------------------- 1 | 10.16.3 2 | 3 | -------------------------------------------------------------------------------- /trivia-game-vue/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | .env.local 6 | .env.*.local 7 | 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | *.sw? 19 | 20 | -------------------------------------------------------------------------------- /trivia-game-vue/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": false, 4 | "htmlWhitespaceSensitivity": "css", 5 | "insertPragma": false, 6 | "jsxBracketSameLine": false, 7 | "jsxSingleQuote": true, 8 | "printWidth": 80, 9 | "proseWrap": "always", 10 | "requirePragma": false, 11 | "semi": false, 12 | "singleQuote": true, 13 | "tabWidth": 2, 14 | "trailingComma": "all", 15 | "useTabs": false 16 | } 17 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/README.md: -------------------------------------------------------------------------------- 1 | # Trivia Game 2 | 3 | This example showcases several state machine concepts including guards, 4 | transient functions, and invoking services. 5 | 6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068) 7 | 8 | ## Running Locally 9 | 10 | 1. After cloning and navigating into the `trivia-game-vue` directory, execute: 11 | 12 | ``` 13 | yarn && yarn test 14 | ``` 15 | 16 | or 17 | 18 | ``` 19 | npm install && npm t 20 | ``` 21 | 22 | This will install dependencies and run tests to verify no issues 23 | 24 | 2. Start the application by executing: 25 | 26 | ``` 27 | yarn start 28 | ``` 29 | 30 | or 31 | 32 | ``` 33 | npm start 34 | ``` 35 | -------------------------------------------------------------------------------- /trivia-game-vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /trivia-game-vue/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "" 3 | command = "yarn build" 4 | publish = "/dist" 5 | -------------------------------------------------------------------------------- /trivia-game-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trivia-game-vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "vue-cli-service build", 7 | "lint": "vue-cli-service lint", 8 | "start": "vue-cli-service serve" 9 | }, 10 | "dependencies": { 11 | "core-js": "3.42.0", 12 | "lean-he": "2.1.2", 13 | "tailwindcss": "4.1.8", 14 | "vue": "3.5.16", 15 | "xstate": "5.19.4" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "5.0.8", 19 | "@vue/cli-plugin-eslint": "5.0.8", 20 | "@vue/cli-service": "5.0.8", 21 | "babel-eslint": "10.1.0", 22 | "eslint": "9.28.0", 23 | "eslint-plugin-vue": "9.33.0", 24 | "vue-template-compiler": "2.7.16" 25 | }, 26 | "eslintConfig": { 27 | "root": true, 28 | "env": { 29 | "node": true 30 | }, 31 | "extends": [ 32 | "plugin:vue/essential", 33 | "eslint:recommended" 34 | ], 35 | "rules": {}, 36 | "parserOptions": { 37 | "parser": "babel-eslint" 38 | } 39 | }, 40 | "browserslist": [ 41 | "> 1%", 42 | "last 2 versions" 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /trivia-game-vue/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugins": [ 3 | require('tailwindcss'), 4 | require('autoprefixer'), 5 | ] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /trivia-game-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-vue/public/favicon.ico -------------------------------------------------------------------------------- /trivia-game-vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | trivia-game-vue 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 71 | 72 | 93 | -------------------------------------------------------------------------------- /trivia-game-vue/src/assets/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | @tailwind components; 4 | 5 | @tailwind utilities; 6 | 7 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/Actions.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 24 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/Button.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 34 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/Container.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/CorrectIcon.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/H1.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/P.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/TextContainer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/Toggle.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 54 | 55 | 68 | -------------------------------------------------------------------------------- /trivia-game-vue/src/components/WrongIcon.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /trivia-game-vue/src/machine.js: -------------------------------------------------------------------------------- 1 | import {assign, Machine} from 'xstate' 2 | import {fetchAndNormalizeQuizData} from './utils' 3 | 4 | const machine = Machine( 5 | { 6 | id: 'Machine', 7 | initial: 'welcome', 8 | context: { 9 | currentQuestion: 0, 10 | currentQuestionDisplay: 1, 11 | questions: [], 12 | totalCorrectAnswers: 0, 13 | }, 14 | states: { 15 | welcome: { 16 | on: { 17 | START_QUIZ: 'loading', 18 | }, 19 | }, 20 | loading: { 21 | invoke: { 22 | id: 'getQuizData', 23 | src: 'fetchAndNormalizeQuizData', 24 | onDone: { 25 | target: 'quiz', 26 | actions: assign({ 27 | questions: (_, event) => event.data, 28 | }), 29 | }, 30 | onError: { 31 | target: 'failure', 32 | }, 33 | }, 34 | }, 35 | failure: { 36 | on: { 37 | RETRY: 'loading', 38 | START_OVER: 'welcome', 39 | }, 40 | }, 41 | quiz: { 42 | on: { 43 | '': { 44 | target: 'results', 45 | actions: [], 46 | cond: 'allQuestionsAnswered', 47 | }, 48 | ANSWER_FALSE: { 49 | actions: 'updateAnswer', 50 | }, 51 | ANSWER_TRUE: { 52 | actions: 'updateAnswer', 53 | }, 54 | }, 55 | }, 56 | results: { 57 | on: { 58 | PLAY_AGAIN: 'welcome', 59 | }, 60 | exit: 'resetGame', 61 | }, 62 | }, 63 | }, 64 | { 65 | actions: { 66 | resetGame: assign({ 67 | currentQuestion: 0, 68 | currentQuestionDisplay: 1, 69 | questions: [], 70 | totalCorrectAnswers: 0, 71 | }), 72 | updateAnswer: assign((ctx, event) => ({ 73 | questions: [ 74 | ...ctx.questions.slice(0, ctx.currentQuestion), 75 | { 76 | ...ctx.questions[ctx.currentQuestion], 77 | userAnswer: event.answer, 78 | correct: 79 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer, 80 | }, 81 | ...ctx.questions.slice(ctx.currentQuestion + 1), 82 | ], 83 | totalCorrectAnswers: 84 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer 85 | ? (ctx.totalCorrectAnswers += 1) 86 | : ctx.totalCorrectAnswers, 87 | currentQuestion: ctx.currentQuestion += 1, 88 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1, 89 | })), 90 | }, 91 | guards: { 92 | allQuestionsAnswered: ctx => { 93 | return ( 94 | ctx.questions.filter( 95 | (question) => question.correct !== undefined, 96 | ).length === ctx.questions.length && true 97 | ) 98 | }, 99 | }, 100 | services: { 101 | fetchAndNormalizeQuizData: () => fetchAndNormalizeQuizData(), 102 | }, 103 | }, 104 | ) 105 | 106 | export default machine 107 | -------------------------------------------------------------------------------- /trivia-game-vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | import './assets/tailwind.css' 5 | 6 | Vue.config.productionTip = false 7 | 8 | new Vue({ 9 | render: h => h(App), 10 | }).$mount('#app') 11 | -------------------------------------------------------------------------------- /trivia-game-vue/src/screens/Failure.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 47 | -------------------------------------------------------------------------------- /trivia-game-vue/src/screens/Loading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /trivia-game-vue/src/screens/Quiz.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 52 | 53 | 78 | 79 | -------------------------------------------------------------------------------- /trivia-game-vue/src/screens/Results.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 55 | 56 | 69 | -------------------------------------------------------------------------------- /trivia-game-vue/src/screens/Welcome.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 37 | -------------------------------------------------------------------------------- /trivia-game-vue/src/utils/fetchAndNormalizeQuizData.js: -------------------------------------------------------------------------------- 1 | import {fetchQuizData, normalizeQuizData} from '.' 2 | 3 | export const fetchAndNormalizeQuizData = async () => { 4 | try { 5 | const data = await fetchQuizData() 6 | return Promise.resolve(normalizeQuizData(data.results)) 7 | } catch (error) { 8 | return Promise.reject(error) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /trivia-game-vue/src/utils/fetchQuizData.js: -------------------------------------------------------------------------------- 1 | export const fetchQuizData = () => 2 | fetch( 3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`, 4 | ).then(response => 5 | response.json()); 6 | -------------------------------------------------------------------------------- /trivia-game-vue/src/utils/index.js: -------------------------------------------------------------------------------- 1 | export * from './fetchAndNormalizeQuizData' 2 | export * from './fetchQuizData' 3 | export * from './normalizeQuizData' 4 | -------------------------------------------------------------------------------- /trivia-game-vue/src/utils/normalizeQuizData.js: -------------------------------------------------------------------------------- 1 | import decode from 'lean-he/decode' 2 | 3 | export const normalizeQuizData = data => 4 | data.reduce( 5 | (acc, obj) => [ 6 | ...acc, 7 | { 8 | category: decode(obj.category), 9 | question: decode(obj.question), 10 | correctAnswer: obj.correct_answer === 'True' ? true : false, 11 | userAnswer: undefined, 12 | correct: undefined, 13 | }, 14 | ], 15 | [], 16 | ) 17 | --------------------------------------------------------------------------------