[
  {
    "path": ".eslintignore",
    "content": "/coverage\n/dist"
  },
  {
    "path": ".eslintrc.cjs",
    "content": "/* eslint-env node */\nmodule.exports = {\n  root: true,\n  extends: ['@linusborg/eslint-config', 'plugin:vue/vue3-essential'],\n  parserOptions: {\n    ecmaVersion: 'latest',\n  },\n  overrides: [\n    {\n      files: ['*.js', '.cjs'],\n      env: {\n        node: true,\n      },\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: 'ci'\non:\n  push:\n    branches:\n      - '**'\n  pull_request:\n    branches:\n      - main\n\npermissions:\n  contents: read # to fetch code (actions/checkout)\n\njobs:\n  build-and-typecheck:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v2\n\n      - name: Set node version to 16\n        uses: actions/setup-node@v3\n        with:\n          node-version: 16\n          cache: 'pnpm'\n\n      - run: pnpm install\n\n      - name: Run build & tsc\n        run: pnpm run build\n \n  unit-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v2\n\n      - name: Set node version to 16\n        uses: actions/setup-node@v3\n        with:\n          node-version: 16\n          cache: 'pnpm'\n\n      - run: pnpm install\n\n      - name: Run unit tests\n        run: pnpm run test:unit\n  \n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v2\n\n      - name: Set node version to 16\n        uses: actions/setup-node@v3\n        with:\n          node-version: 16\n          cache: 'pnpm'\n\n      - run: pnpm install\n\n      - name: Lint codebase\n        run: pnpm run lint"
  },
  {
    "path": ".github/workflows/size.yml",
    "content": "name: \"size\"\non:\n  pull_request:\n    branches:\n      - main\njobs:\n  size:\n    runs-on: ubuntu-latest\n    env:\n      CI_JOB_NUMBER: 1\n    steps:\n      - uses: actions/checkout@v1\n      - name: Install pnpm\n        uses: pnpm/action-setup@v2\n      - uses: andresz1/size-limit-action@v1\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\n.DS_Store\ndist\ndist-ssr\ncoverage\n*.local\n\n/cypress/videos/\n/cypress/screenshots/\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\ntsconfig.app.tsbuildinfo"
  },
  {
    "path": ".prettierignore",
    "content": "dist/\n/types"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"useTabs\": false,\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\",\n  \"semi\": false\n}"
  },
  {
    "path": ".release-it.json",
    "content": "{\n  \"git\": {\n    \"commitMessage\": \"chore: release v${version}\"\n  },\n  \"github\": {\n    \"release\": true\n  },\n  \"plugins\": {\n    \"@release-it/conventional-changelog\": {\n      \"preset\": \"angular\",\n      \"infile\": \"CHANGELOG.md\"\n    }\n  },\n  \"hooks\": {\n    \"before:init\": [\"pnpm lint:ci\", \"pnpm test:ci\"],\n    \"after:bump\": [\"pnpm build\"],\n    \"after:release\": [\"echo 🥳 Successfully released ${name} v${version}.\"]\n  }\n}"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"Vue.volar\", \"Vue.vscode-typescript-vue-plugin\"]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "\n\n## [0.3.1](https://github.com/LinusBorg/vue-mixable/compare/0.3.0...0.3.1) (2022-11-17)\n\n\n### Bug Fixes\n\n* **vm:** ensure custom properties can be set and read ([784882f](https://github.com/LinusBorg/vue-mixable/commit/784882febd52ee3c3e07d0ab1b19285c44609b22))\n\n# 0.3.0 (2022-11-07)\n\n\n### Bug Fixes\n\n* add license field to package.json, add repo URL ([c1acfe6](https://github.com/LinusBorg/vue-mixable/commit/c1acfe6eb2a882d8a893f191d7ea96e644b08392))\n* add LICENSE file ([52b59b5](https://github.com/LinusBorg/vue-mixable/commit/52b59b5620f29e9109f2ab461621851a5135424f))\n* add proper files option content ([47df2e7](https://github.com/LinusBorg/vue-mixable/commit/47df2e701a1299eef5c4aa4060cfeb69ea757ead))\n* ensure cache works with the new types. ([babada7](https://github.com/LinusBorg/vue-mixable/commit/babada7b499e0fa6c3aa6e67402aac1d3857b99d))\n* isString should properly guard string type ([1629187](https://github.com/LinusBorg/vue-mixable/commit/16291871c46a7065bf5193f08a89b8c0823a9095))\n* make vue peer dep ([c8e73ff](https://github.com/LinusBorg/vue-mixable/commit/c8e73ff0ecebec1e3a1625265b21333e6884635b))\n* type in release-it config file name, add missing plugin package. ([7cae268](https://github.com/LinusBorg/vue-mixable/commit/7cae268f7d45fa4fed9b147bb15a6b0c22645d4e))\n* **types:** return type should include props and emits keys ([4c38321](https://github.com/LinusBorg/vue-mixable/commit/4c383217a67c54e0b423fdefd96c024fa605ab7a))\n\n\n### Features\n\n* add composable cache ([0838c4b](https://github.com/LinusBorg/vue-mixable/commit/0838c4b63811422f42c6adfd436d1a2300cadc4c))\n* defineMixin() allows to write typesafe mixins. ([1fd5e93](https://github.com/LinusBorg/vue-mixable/commit/1fd5e930f28745218519c01d34215b511458d3a7))\n* export defineMixin() ([0b584ec](https://github.com/LinusBorg/vue-mixable/commit/0b584ec12c924d7a04846567cdbf08ef6ffc0ea6))"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 - present Thorsten Lünborg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![current npm version](https://img.shields.io/npm/v/vue-mixable) ![npm bundle size (min+gzip)](https://badgen.net/bundlephobia/minzip/vue-mixable) ![npm downloads per month](https://img.shields.io/npm/dm/vue-mixable)\n\n![NPM](https://img.shields.io/npm/l/vue-mixable) ![CI checks](https://badgen.net/github/checks/linusborg/vue-mixable) ![types included](https://badgen.net/npm/types/vue-mixable)\n\n# 🌪 `vue-mixable`\n\n> Convert mixins into composables to reuse them in Composition API\n\n* helpful during Options API -> Composition API migrations / in mixed code-bases\n* simple API - one function call is all you need\n* TS Support (with small caveats)\n* small footprint: ![npm bundle size (min+zip)](https://badgen.net/bundlephobia/minzip/vue-mixable)\n\n## Quick Intro\n\n```js\n// given an existing mixin such as this:\nexport const messageMixin  = {\n    data() {\n        return {\n            msg: 'Hello World'\n        }\n    },\n    computed: {\n        loudMsg() {\n            return this.capitalize(this.msg) + '!!!1eleven!'\n        }\n    },\n    methods: {\n        capitalize(value) { return value.toUpperCase() }\n    } \n}\n\n// we can create a composable from it with a single function call\nimport { createComposableFromMixin } from 'vue-mixable'\nexport const useMessage = createComposableFromMixin(messageMixin)\n```\n\nThis composable can then be used in  `setup()`/ `<script setup>`:\n\n```html\n<script setup>\nconst {\n    msg, // ref\n    loudMsg, // computed() ref\n    capitalize // function\n} = useMessage()\n</script>\n```\n\n## Use cases\n\nThis library is primarily useful for developers trying to migrate a Options-API codebase using Mixins for code sharing to Composition API using composables for code sharing.\n\nOne of the challenges in such a migration is that one often cannot rewrite a mixin into a composable and replace all of that mixin's usage instances in the app at once, epsecially when mixins depend on one another, which is often the case in larger code-bases.\n\nThis is where `vue-mixable` can help: The team can keep all their mixins for the time of the migration, but convert each of them into composables with one line of code. You get have your cake, and eat it to, in a way. \n\nThen they can migrate individual components from the mixin to the composable at their own pace, and once the migration is done, they can rewrite the mixin into a proper standalone composable and finally remove the mixin from your codebase.\n\n\n## Installation\n\n```bash\nnpm install vue-mixable\n```\n\n## Usage Notes\n\n### Supported APIs\n\n`vue-mixable` provides full support for mixins that use the following Options APIs\n\n* `data`\n* `computed`\n* `methods`\n* `watch`\n* `provide`\n* `inject`\n* `props` (see Note in the next section)\n* `emits` (see Note in the next section)\n\nOptions with no direct support (currently):\n\n* `inheritAttrs`\n* `components`\n* `directives`\n* `name`\n\nIf you use any of the above options, you would have to set them manually in any component that uses the generated composable instead of the original mixin.\n\n### `props` & `emits`  options\n\nMixins can contain props definitions. Composables cannot, as they are functions invoked during component initialization (in `setup()`, at which point props must have been defined already.\n\n`vue-mixable` solves with in the following way:\n\n```js\nconst mixin = {\n    props: ['modelValue', 'age', 'street', 'city'],\n    emits: ['modelValue:update', 'certified']\n    // ...and other mixin content, i.e.:\n    data: () => ({\n        //...\n    })\n}\n\nexport const usePerson = createComposableFromMixin(mixin)\n// props and emits options will be available \n// as properties on the composable function(!)\nusePerson.props // => ['modelValue', 'age', 'street', 'city']\nusePerson.emits // => ['modelValue:update', 'certified']\n```\nUsage\n```js\nimport { usePerson } from '...'\n\nexport default defineComponent({\n    props: ['firstname', 'lastname', ...usePerson.props],\n    emits: usePerson.emits,\n    setup(props, { emit }) {\n        const person = usePerson()\n\n        return {\n\n        }\n    }\n})\n\n```\n### Shape of the composable's return value\n\nThe shape of the return value is essentially a flattened version of the mixins `data`, `computed` and `methods` properties, with `data` and `computed` being `ref()`'s. All other supported properties (lifecylces, `watch`) have nothing to expose externally.\n\n```js\nconst mixin = {\n    data: () =>({\n        a: 'A',\n        b: 'B',\n    }),\n    computed: {\n        c() { return this.A },\n        d() { return this.B }\n    },\n    methods: {\n        e() {\n            return callSomething(this.a, this.c)\n        }\n    }\n}\n\nconst useComposable = createComposableFromMixin(mixin)\n```\nwould be turned into:\n```js\n\nconst {\n    a, // ref('A')\n    b, // ref('B')\n    c, // computed ref \n    d, // computed ref\n    e, // normal function\n} = useComposable()\n```\n\n### Feature Roadmap\n\n- [ ] Support Mixins that implicitly depend on properties/APIs from other mixins.\n- [ ] Support Nested Mixins.\n- [ ] Exclude specific properties from composables return value (essentially making some mixin properties private in the composable).\n\nOut of scope / not planned\n\n- [ ] mixins with implicit circular dependencies on one another.\n\n## Caveats\n\n### `this.$watch()` in created\n\ncreating a watcher imperatively in `created` will likely not work as expected, because in the created composable, that hooks is run before `setup()` returns, so any data properties declared in the mixin/composable will be missing on `this`.\n\nPossible workarounds:\n\n- use the normal `watch:`option\n- create the watcher in `beforeMount`.\n\n## Typescript Support\n\nTypescript support is still considered unstable as we plan on improving the types, possibly introduction breaking changes to the types.\n\n**Caveats:** \n\n* For Type inference to work, each mixin object *must* have a `props` key. If your mixin does not include any props, set it to an empty object.\n* props always need to be defined in object style. array style is currently not supported and will break type inference.\n* the `emits` option cannot be provided in its array form, it must take the more verbose object form.\n```ts\nconst mixin = defineMixin({\n    props: {} // needed for proper tyep inference for now,\n    emits: {\n        'update:modelValue': (v?: any) => true, // this validator can be a NOOP returning `true`\n    },\n    data: () => ({\n        // ...\n    })\n})\n\nconst composable = createCopmposableFromMixin(mixin)\n```\n\n### `defineMixin()`\n\nThis function does not do anything at runtime, it's just providing tpe inferrence for your mixins:\n\n```ts\nconst mixin = {\n    data: () => ({\n        msg: 'Hello World',\n    }),\n    methods: {\n        test() {\n            this.msg // not inferreed correctly\n        }\n    }\n}\n\n// better:\nimport { defineMixin } from 'vue-mixable'\nconst mixin = defineMixin({\n    props: {}, // needed, see caveat explained further up.\n    data: () => ({\n        msg: 'Hello World',\n    }),\n    methods: {\n        test() {\n            this.msg // properly inferred.\n        }\n    }\n}\n```\n\n### `createComposableFromMixin()`\n\nThis function will offer full type inference for any mixin passed to it.\n\n\n## Developer Instructions\n\n\n### Compile and Minify for Production, create Type Declarations\n\n```sh\npnpm build\n```\n\n### Run Unit Tests with [Vitest](https://vitest.dev/)\n\n```sh\npnpm test:unit\n```\n\n### Lint with [ESLint](https://eslint.org/)\n\n```sh\npnpm lint\n```\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "const config = require('@commitlint/config-angular')\nmodule.exports = {\n  extends: ['@commitlint/config-angular'],\n  rules: {\n    'type-enum': [2, 'always', [...config.rules['type-enum'][2], 'chore']],\n  },\n}\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <link rel=\"icon\" href=\"/favicon.ico\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Vite App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vue-mixable\",\n  \"description\": \"Turn Vue Mixins into Composables with a simple helper function\",\n  \"version\": \"0.3.1\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"Vue\",\n    \"composables\",\n    \"mixins\",\n    \"Vue plugin\",\n    \"migration\",\n    \"compat\"\n  ],\n  \"author\": {\n    \"name\": \"Thorsten Lünborg\",\n    \"url\": \"https://github.com/linusborg\"\n  },\n  \"repository\": {\n    \"url\": \"https://github.com/LinusBorg/vue-mixable\",\n    \"type\": \"git\"\n  },\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"unpkg\": \"./dist/index.js\",\n  \"jsdelivr\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"require\": \"./dist/index.cjs\",\n      \"import\": \"./dist/index.mjs\",\n      \"default\": \"./dist/index.cjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist\",\n    \"README.md\",\n    \"LICENSE\",\n    \"src\"\n  ],\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build && tsc --declaration --emitDeclarationOnly -p tsconfig.app.json --outDir dist\",\n    \"type-check\": \"tsc --noEmit -p tsconfig.vitest.json --composite false\",\n    \"test:unit\": \"vitest --environment jsdom\",\n    \"test:ci\": \"vitest --environment jsdom --run\",\n    \"lint:ci\": \"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts\",\n    \"lint\": \"pnpm lint:ci --fix\",\n    \"size\": \"pnpm size-limit\",\n    \"release\": \"release-it\",\n    \"update-hooks\": \"pnpm simple-git-hooks\"\n  },\n  \"packageManager\": \"pnpm@7.14.1\",\n  \"simple-git-hooks\": {\n    \"pre-commit\": \"pnpm lint-staged\",\n    \"commit-msg\": \"pnpm commitlint --edit $1\"\n  },\n  \"lint-staged\": {\n    \"*.{ts,js,cjs,vue}\": \"pnpm exec eslint --max-warnings 0\"\n  },\n  \"size-limit\": [\n    {\n      \"path\": \"dist/index.cjs\",\n      \"limit\": \"2kB\"\n    }\n  ],\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"^17.2.0\",\n    \"@commitlint/config-angular\": \"^17.2.0\",\n    \"@linusborg/eslint-config\": \"^0.3.0\",\n    \"@release-it/conventional-changelog\": \"^5.1.1\",\n    \"@size-limit/preset-small-lib\": \"^8.1.0\",\n    \"@types/jsdom\": \"^20.0.1\",\n    \"@types/node\": \"^16.18.3\",\n    \"@vitest/coverage-c8\": \"^0.25.0\",\n    \"@vue/test-utils\": \"^2.1.0\",\n    \"@vue/tsconfig\": \"^0.1.3\",\n    \"eslint\": \"^8.27.0\",\n    \"jsdom\": \"^20.0.2\",\n    \"lint-staged\": \"^13.0.3\",\n    \"prettier\": \"^2.7.1\",\n    \"release-it\": \"^15.5.0\",\n    \"simple-git-hooks\": \"^2.8.1\",\n    \"size-limit\": \"^8.1.0\",\n    \"type-fest\": \"^3.2.0\",\n    \"typescript\": \"~4.7.4\",\n    \"vite\": \"^3.2.3\",\n    \"vitest\": \"^0.25.0\",\n    \"vue\": \"^3.2.41\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.2\"\n  },\n  \"peerDependenciesMeta\": {\n    \"vue\": {\n      \"optional\": true\n    }\n  }\n}\n"
  },
  {
    "path": "src/__tests__/advanced.spec.ts",
    "content": "import { describe, test, expect, vi } from 'vitest'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\n// FIXME: needs to wait until feature is done.\ndescribe.skip('advanced', () => {\n  test('nested mixins', async () => {\n    const innerSpy = vi.fn()\n    const outerSpy = vi.fn()\n    const innerMixin = defineMixin({\n      props: {\n        inner: Number,\n      },\n      data: () => ({\n        nestedProperty: 'A',\n        sharedProperty: 'A',\n      }),\n      created() {\n        innerSpy()\n      },\n      mounted() {\n        innerSpy()\n      },\n    })\n    const outerMixin = defineMixin({\n      mixins: [innerMixin],\n      props: {\n        outer: String,\n      },\n      data: () => ({\n        msg: 'Hello World',\n        sharedProperty: 'B',\n      }),\n      computed: {\n        getNestedProperty(): string {\n          return this.nestedProperty\n        },\n      },\n      mounted() {\n        outerSpy()\n      },\n    })\n    // eslint-disable-next-line no-autofix/unused-imports/no-unused-vars\n    const innerComposable = createComposableFromMixin(innerMixin)\n\n    const outerComposable = createComposableFromMixin(outerMixin)\n    const wrapper = wrapComposable(\n      outerComposable,\n      {\n        props: {\n          outer: 'Hello',\n          inner: 10,\n        },\n      },\n      {\n        props: outerComposable.props,\n      }\n    )\n    // Props\n    expect(wrapper.vm.outer).toBe('Hello')\n    expect(wrapper.vm.inner).toBe(10)\n    // Data & computed\n    expect(wrapper.vm.sharedProperty).toBe('B')\n    expect(wrapper.vm.getNestedProperty).toBe('A')\n    // Lifecycle Hooks\n    expect(innerSpy).toHaveBeenCalledTimes(2)\n    expect(outerSpy).toHaveBeenCalledTimes(1)\n  })\n})\n"
  },
  {
    "path": "src/__tests__/cache.spec.ts",
    "content": "import { describe, test, expect } from 'vitest'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\n\ndescribe('cache', () => {\n  test('works', () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        msg: 'Hello World',\n      }),\n    })\n\n    const composable1 = createComposableFromMixin(mixin)\n    const composable2 = createComposableFromMixin(mixin)\n\n    expect(composable1).toBe(composable2)\n  })\n})\n"
  },
  {
    "path": "src/__tests__/computed.spec.ts",
    "content": "import { describe, test, expect } from 'vitest'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('computed option', async () => {\n  test('computed are readable', async () => {\n    const mixin = defineMixin({\n      props: {},\n      computed: {\n        msg() {\n          return 'msg'\n        },\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).msg).toBe('msg')\n  })\n\n  test('writeable computeds work', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        internalMsg: 'A',\n      }),\n      computed: {\n        msg: {\n          get(): string {\n            return this.internalMsg\n          },\n          set(v: string) {\n            this.internalMsg = v\n          },\n        },\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div>{{ msg }}</div><button @click=\"msg = 'B'\">Click</button>`,\n      }\n    )\n\n    expect(wrapper.find('div').text()).toBe('A')\n    await wrapper.find('button').trigger('click')\n    expect(wrapper.find('div').text()).toBe('B')\n  })\n\n  test('computed have access to `this`', async () => {\n    const mixin = defineMixin({\n      props: {},\n      computed: {\n        msg() {\n          return !!this.$emit\n        },\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).msg).toBe(true)\n  })\n\n  test('computed have access to data from mixin', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        foo: 'Hello World',\n      }),\n      computed: {\n        msg(): string {\n          return this.foo\n        },\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).msg).toBe('Hello World')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/data.spec.ts",
    "content": "import { describe, test, expect } from 'vitest'\nimport { nextTick } from 'vue'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('data Option', () => {\n  test('data usable in template', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        msg: 'Hello World',\n      }),\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    // const wrapper =\n    const wrapper = wrapComposable(composable)\n\n    expect(wrapper.text()).toBe('Hello World')\n  })\n  test('data fn receives instance proxy', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: (vm: any) => {\n        return {\n          msg: vm.$emit ? 'Hello World' : '',\n        }\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    // const wrapper =\n    const wrapper = wrapComposable(composable, {}, { withProxy: true })\n\n    expect(wrapper.text()).toBe('Hello World')\n  })\n  test('data properties can be reactively reassigned', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => {\n        return {\n          msg: 'A',\n        }\n      },\n    } as const)\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div>{{ msg }}</div><button @click=\"msg = 'B'\">Click</button>`,\n      }\n    )\n\n    expect(wrapper.find('div').text()).toBe('A')\n\n    await wrapper.find('button').trigger('click')\n    await nextTick()\n    expect(wrapper.find('div').text()).toBe('B')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/helpers.ts",
    "content": "import { mount, type MountingOptions } from '@vue/test-utils'\nimport { defineComponent } from 'vue'\n\nexport const wrapComposable = <O extends MountingOptions<{}>>(\n  composable: any,\n  options: O = {} as O,\n  extensions: Record<string, any> = {}\n) =>\n  mount(\n    defineComponent({\n      ...extensions,\n      template: extensions.template ?? '<div>{{ msg }}</div>',\n      setup() {\n        return {\n          ...composable(),\n        }\n      },\n    }),\n    options\n  )\n"
  },
  {
    "path": "src/__tests__/inject.spec.ts",
    "content": "import { describe, test, expect } from 'vitest'\nimport { defineComponent, ref } from 'vue'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('inject option', async () => {\n  test('injects from mixin work', async () => {\n    const mixin = defineMixin({\n      props: {},\n      inject: {\n        foo: {\n          from: 'foo',\n          default: 'bar',\n        },\n      },\n      data(): { msg: string } {\n        return {\n          msg: (this as any).foo,\n        }\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div>{{ msg }}</div>`,\n      }\n    )\n\n    expect(wrapper.vm.msg).toBe('bar')\n  })\n\n  test('provide works', async () => {\n    const foo = ref('foo')\n    const mixin = defineMixin({\n      props: {},\n      provide: {\n        foo,\n      },\n    })\n    const Child = defineComponent({\n      inject: ['foo'],\n      template: `<div @click=\"foo = 'bar'\">{{ foo }}</div>`,\n    })\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div><Child /></div>`,\n        components: {\n          Child,\n        },\n      }\n    )\n\n    const child = wrapper.findComponent(Child)\n    expect(child.text()).toBe('foo')\n\n    await child.find('div').trigger('click')\n    expect(foo.value).toBe('bar')\n    expect(child.text()).toBe('bar')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/lifecylce.spec.ts",
    "content": "import { describe, test, expect, vi } from 'vitest'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('Lifecycle hooks', async () => {\n  test('are called with proper `this`', async () => {\n    const spy = vi.fn()\n    function testHandler() {\n      // @ts-expect-error - doesn't like this for some reason\n      if ((this as any).$emit) spy()\n    }\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        msg: 'A',\n      }),\n      beforeCreate: testHandler,\n      created: testHandler,\n      beforeMount: testHandler,\n      mounted: testHandler,\n      beforeUpdate: testHandler,\n      updated: testHandler,\n      beforeUnmount: testHandler,\n      unmounted: testHandler,\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div>{{ msg }}</div><button @click=\"msg = 'B'\">Click</button>`,\n      }\n    )\n\n    expect(spy).toHaveBeenCalledTimes(4)\n\n    await wrapper.find('button').trigger('click')\n\n    expect(spy).toHaveBeenCalledTimes(6)\n\n    await wrapper.unmount()\n\n    expect(spy).toHaveBeenCalledTimes(8)\n  })\n\n  test('can read and set custom properties on `this`', async () => {\n    const mixin = defineMixin({\n      props: {},\n      beforeCreate() {\n        ;(this as any).custom = 'A'\n      },\n      created() {\n        expect((this as any).custom).toBe('A')\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div/>`,\n      }\n    )\n\n    expect((wrapper.vm as any).custom).toBe('A')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/methods.spec.ts",
    "content": "import { describe, test, expect } from 'vitest'\nimport type { ComponentPublicInstance } from 'vue'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('methods option', () => {\n  test('methods are callable', async () => {\n    const mixin = defineMixin({\n      props: {},\n      methods: {\n        msg() {\n          return 'msg'\n        },\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).msg()).toBe('msg')\n  })\n\n  test('methods have access to `this`', async () => {\n    const mixin = defineMixin({\n      props: {},\n      methods: {\n        msg() {\n          return !!(this as unknown as ComponentPublicInstance).$emit\n        },\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).msg()).toBe(true)\n  })\n\n  test('methods have access to data from mixin', async () => {\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        msg: 'Hello World',\n      }),\n      methods: {\n        getMsg() {\n          return (this as any).msg\n        },\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(composable)\n\n    expect((wrapper.vm as any).getMsg()).toBe('Hello World')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/propsEmits.spec.ts",
    "content": "import { describe, test, expect, vi } from 'vitest'\nimport { defineComponent } from 'vue'\nimport { mount } from '@vue/test-utils'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\n// import { wrapComposable } from './helpers'\n\ndescribe('props', () => {\n  test('props as property on composable', async () => {\n    const mixin = defineMixin({\n      props: {\n        foo: String,\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const Comp = defineComponent({\n      props: composable.props,\n      template: `<div>{{ foo }}</div>`,\n    })\n\n    const wrapper = await mount(Comp, {\n      props: {\n        foo: 'bar',\n      },\n    })\n\n    expect(wrapper.find('div').text()).toBe('bar')\n  })\n})\n\ndescribe('emits', () => {\n  test('emits option on composable', async () => {\n    const mixin = defineMixin({\n      props: {},\n      emits: ['foo'],\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const Comp = defineComponent({\n      emits: composable.emits,\n      template: `<button @click=\"$emit('foo')\">Click me</button>`,\n    })\n    const spy = vi.fn()\n    const wrapper = await mount(Comp, {\n      props: {\n        onFoo: spy,\n      },\n    })\n\n    await wrapper.find('button').trigger('click')\n    expect(spy).toHaveBeenCalledTimes(1)\n    expect(wrapper.emitted()).toHaveProperty('foo')\n  })\n})\n"
  },
  {
    "path": "src/__tests__/setup.ts",
    "content": "import { config } from '@vue/test-utils'\n\nconfig.global.config.unwrapInjectedRef = true\n"
  },
  {
    "path": "src/__tests__/watch.spec.ts",
    "content": "import { describe, test, expect, vi } from 'vitest'\nimport { nextTick } from 'vue'\nimport { createComposableFromMixin } from '../createComposable'\nimport { defineMixin } from '../defineMixin'\nimport { wrapComposable } from './helpers'\n\ndescribe('watch option', async () => {\n  test('string watch', async () => {\n    const spy = vi.fn()\n    const mixin = defineMixin({\n      props: {},\n      data: () => ({\n        msg: 'A',\n      }),\n      watch: {\n        msg(...args: any[]) {\n          spy(...args)\n        },\n      },\n    })\n\n    const composable = createComposableFromMixin(mixin)\n    const wrapper = wrapComposable(\n      composable,\n      {},\n      {\n        template: `<div>{{ msg }}</div><button @click=\"msg = 'B'\">Click</button>`,\n      }\n    )\n\n    expect(spy).toHaveBeenCalledTimes(0)\n\n    await wrapper.find('button').trigger('click')\n    await nextTick()\n    expect(wrapper.vm.msg).toBe('B')\n    expect(spy).toHaveBeenCalledTimes(1)\n    expect(spy).toHaveBeenCalledWith('B', 'A', expect.any(Function))\n  })\n})\n"
  },
  {
    "path": "src/createComposable.ts",
    "content": "/**\n * Code in this file is based on the Options API implementation in Vue 3's codebase:\n * https://github.com/vuejs/core/blob/f67bb500b6071bc0e55a89709a495a27da73badd/packages/runtime-core/src/componentOptions.ts\n */\nimport {\n  onBeforeMount,\n  onMounted,\n  onBeforeUpdate,\n  onUpdated,\n  onActivated,\n  onDeactivated,\n  onBeforeUnmount,\n  onUnmounted,\n  onRenderTracked,\n  onRenderTriggered,\n  onErrorCaptured,\n  getCurrentInstance,\n  ref,\n  computed,\n  watch,\n  reactive,\n  provide,\n  type ComponentPublicInstance,\n  type WatchCallback,\n} from 'vue'\nimport { callHook, isArray, isFunction, isObject, isString } from './utils'\nimport { createContextProxy } from './vmContextProxy'\n\nimport type {\n  ComputedOptions,\n  MethodOptions,\n  ComponentOptionsWithObjectProps,\n  ComponentOptionsMixin,\n  ToRefs,\n  CreateComponentPublicInstance,\n  ExtractPropTypes,\n  ComponentPropsOptions,\n  ExtractDefaultPropTypes,\n  EmitsOptions,\n} from 'vue'\n\n// import { cache } from './cache'\n\nimport type {\n  ComponentWatchOptionItem,\n  ExtractComputedReturns,\n  EmitsToProps,\n} from './types'\nimport { resolveInjections } from './inject'\n\nexport const cache = new Map<any, any>() // TODO: properly type this\n\nexport /* @__PURE__ */ function createComposableFromMixin<\n  Props extends Readonly<ExtractPropTypes<PropsOptions>> & EmitsToProps<E>,\n  VM extends CreateComponentPublicInstance<\n    Props,\n    RawBindings,\n    D,\n    C,\n    M,\n    Mixin,\n    Extends,\n    E,\n    Props,\n    ExtractDefaultPropTypes<PropsOptions>,\n    false\n  >,\n  PropsOptions extends Readonly<ComponentPropsOptions>,\n  RawBindings,\n  D,\n  C extends ComputedOptions = {},\n  M extends MethodOptions = {},\n  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,\n  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,\n  E extends EmitsOptions = {},\n  EE extends string = string\n>(\n  mixin: ComponentOptionsWithObjectProps<\n    PropsOptions,\n    RawBindings,\n    D,\n    C,\n    M,\n    Mixin,\n    Extends,\n    E,\n    EE\n  >\n): (() => ToRefs<D> & ToRefs<ExtractComputedReturns<C>> & M) & {\n  props: PropsOptions\n  emits: E\n} {\n  const {\n    props,\n    emits,\n\n    data: dataFn,\n    computed: computedOptions,\n    methods,\n    watch,\n\n    provide: provideOptions,\n    inject: injectOptions,\n\n    // Lifecylce Hooks\n    created,\n    beforeCreate,\n    beforeMount,\n    mounted,\n    beforeUpdate,\n    updated,\n    activated,\n    deactivated,\n    beforeUnmount,\n    unmounted,\n    renderTracked,\n    renderTriggered,\n    errorCaptured,\n\n    // mixins,\n  } = mixin\n\n  if (cache.has(mixin)) {\n    return cache.get(mixin) as any\n  }\n\n  const composable = () => {\n    const instance = getCurrentInstance()!\n    const vm = instance.proxy! as VM\n\n    // if (mixins) {\n    //   mixins.forEach((mixin) => {\n    //     const composable = cache.get(mixin) ?? createComposableFromMixin(mixin)\n\n    //     Object.assign(context, composable())\n    //   })\n    // }\n\n    const context = {} as ToRefs<D> & ToRefs<ExtractComputedReturns<C>> & M\n    const reactiveContext = reactive(context)\n    const vmContextProxy = createContextProxy(vm, reactiveContext) as VM\n\n    beforeCreate && callHook(beforeCreate, instance, vm, 'bc')\n\n    // methods\n    if (methods) {\n      for (const key in methods) {\n        context[key] = methods[key].bind(vmContextProxy as any)\n      }\n    }\n\n    //inject\n    if (injectOptions) {\n      resolveInjections(injectOptions, context)\n    }\n\n    // data\n    if (dataFn) {\n      // FIXME - any has to go here\n      const data = dataFn.call(vmContextProxy as any, vmContextProxy as any)\n      for (const key in data) {\n        // FIXME - TS `this`error\n        // @ts-expect-error this doesn't quite match yet\n        context[key] = ref(data[key])\n      }\n    }\n\n    // computed\n    if (computedOptions) {\n      for (const key in computedOptions) {\n        const def = computedOptions[key]\n        const c = isFunction(def)\n          ? computed(def.bind(vmContextProxy as any))\n          : computed({\n              get: def.get.bind(vmContextProxy),\n              set: def.set.bind(vmContextProxy),\n            })\n        // FIXME - TS `this`error\n        // @ts-expect-error this doesn't quite match yet\n        context[key] = c\n      }\n    }\n\n    //watch\n    if (watch) {\n      for (const key in watch) {\n        const def = watch[key]\n        if (isArray(def)) {\n          def.forEach((d) => createWatcher(d, vmContextProxy, key))\n        } else {\n          createWatcher(def, vmContextProxy, key)\n        }\n      }\n    }\n\n    // provide\n    if (provideOptions) {\n      const provides = isFunction(provideOptions)\n        ? provideOptions.call(vmContextProxy)\n        : provideOptions\n      Reflect.ownKeys(provides).forEach((key) => {\n        provide(key, provides[key])\n      })\n    }\n\n    // Lifecycle\n    created && callHook(created, instance, vm, 'c')\n    beforeMount && onBeforeMount(beforeMount.bind(vm))\n    mounted && onMounted(mounted.bind(vm))\n    beforeUpdate && onBeforeUpdate(beforeUpdate.bind(vm))\n    updated && onUpdated(updated.bind(vm))\n    activated && onActivated(activated.bind(vm))\n    deactivated && onDeactivated(deactivated.bind(vm))\n    beforeUnmount && onBeforeUnmount(beforeUnmount.bind(vm))\n    unmounted && onUnmounted(unmounted.bind(vm))\n    renderTracked && onRenderTracked(renderTracked.bind(vm))\n    renderTriggered && onRenderTriggered(renderTriggered.bind(vm))\n    errorCaptured && onErrorCaptured(errorCaptured.bind(vm))\n\n    return context\n  }\n\n  Object.assign(composable, {\n    props,\n    emits,\n  })\n\n  cache.set(mixin, composable)\n  return composable as typeof composable & { props: PropsOptions; emits: E }\n}\n\nfunction createWatcher(\n  raw: ComponentWatchOptionItem,\n  // ctx: Record<string, any>,\n  publicThis: ComponentPublicInstance & Record<string, any>,\n  key: string\n) {\n  const getter = key.includes('.')\n    ? createPathGetter(publicThis, key)\n    : () => (publicThis as any)[key]\n  if (isString(raw)) {\n    const handler = publicThis[raw]\n    if (isFunction(handler)) {\n      watch(getter, handler as WatchCallback)\n    }\n  } else if (isFunction(raw)) {\n    watch(getter, raw.bind(publicThis))\n  } else if (isObject(raw)) {\n    if (isArray(raw)) {\n      raw.forEach((r) => createWatcher(r, publicThis, key))\n    } else {\n      const handler = isFunction(raw.handler)\n        ? raw.handler.bind(publicThis)\n        : (publicThis[raw.handler] as WatchCallback)\n      if (isFunction(handler)) {\n        watch(getter, handler, raw)\n      }\n    }\n  }\n}\n\nfunction createPathGetter(ctx: any, path: string) {\n  const segments = path.split('.')\n  return () => {\n    let cur = ctx\n    for (let i = 0; i < segments.length && cur; i++) {\n      cur = cur[segments[i]]\n    }\n    return cur\n  }\n}\n"
  },
  {
    "path": "src/defineMixin.ts",
    "content": "import type {\n  ComputedOptions,\n  MethodOptions,\n  ComponentOptionsWithObjectProps,\n  ComponentOptionsMixin,\n  ComponentPropsOptions,\n  EmitsOptions,\n} from 'vue'\n\nexport /** #__PURE__*/ function defineMixin<\n  PropsOptions extends Readonly<ComponentPropsOptions>,\n  RawBindings,\n  D,\n  C extends ComputedOptions = {},\n  M extends MethodOptions = {},\n  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,\n  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,\n  E extends EmitsOptions = {},\n  EE extends string = string\n>(\n  options: ComponentOptionsWithObjectProps<\n    PropsOptions,\n    RawBindings,\n    D,\n    C,\n    M,\n    Mixin,\n    Extends,\n    E,\n    EE\n  >\n): typeof options {\n  return options\n}\n"
  },
  {
    "path": "src/env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "src/index.ts",
    "content": "export { createComposableFromMixin } from './createComposable'\nexport { defineMixin } from './defineMixin'\n"
  },
  {
    "path": "src/inject.ts",
    "content": "/**\n * @legal\n * This code is largely based on code from the Vue 3 codebase:\n * https://github.com/vuejs/core/blob/f67bb500b6071bc0e55a89709a495a27da73badd/packages/runtime-core/src/componentOptions.ts#L823-L876\n * https://github.com/vuejs/core/blob/f67bb500b6071bc0e55a89709a495a27da73badd/packages/runtime-core/src/componentOptions.ts#L1073-L1084\n */\n\nimport {\n  inject,\n  isRef,\n  type ComponentPublicInstance,\n  type DebuggerEvent,\n  type Ref,\n} from 'vue'\n\nexport type ComponentInjectOptions = string[] | ObjectInjectOptions\n\nexport type ObjectInjectOptions = Record<\n  string | symbol,\n  string | symbol | { from?: string | symbol; default?: unknown }\n>\nexport type DebuggerHook = (e: DebuggerEvent) => void\nexport type ErrorCapturedHook<TError = unknown> = (\n  err: TError,\n  instance: ComponentPublicInstance | null,\n  info: string\n) => boolean | void\n\nimport { isArray, isObject } from './utils'\n\nexport function resolveInjections(\n  injectOptions: ComponentInjectOptions,\n  ctx: any\n) {\n  if (isArray(injectOptions)) {\n    injectOptions = normalizeInject(injectOptions)!\n  }\n  for (const key in injectOptions) {\n    const opt = (injectOptions as ObjectInjectOptions)[key]\n    let injected: unknown\n    if (isObject(opt)) {\n      if ('default' in opt) {\n        injected = inject(\n          opt.from || key,\n          opt.default,\n          true /* treat default function as factory */\n        )\n      } else {\n        injected = inject(opt.from || key)\n      }\n    } else {\n      injected = inject(opt)\n    }\n    if (isRef(injected)) {\n      // TODO remove the check in 3.3\n      Object.defineProperty(ctx, key, {\n        enumerable: true,\n        configurable: true,\n        get: () => (injected as Ref).value,\n        set: (v) => ((injected as Ref).value = v),\n      })\n    } else {\n      ctx[key] = injected\n    }\n  }\n}\n\nfunction normalizeInject(\n  raw: ComponentInjectOptions | undefined\n): ObjectInjectOptions | undefined {\n  if (!isArray(raw)) return raw\n\n  const res: ObjectInjectOptions = {}\n  for (let i = 0; i < raw.length; i++) {\n    res[raw[i]] = raw[i]\n  }\n  return res\n}\n"
  },
  {
    "path": "src/typeTest.ts",
    "content": "/**\n * This file is not to be used anywhere, it's just to test the type inference\n */\nimport { defineComponent } from 'vue'\nimport { createComposableFromMixin } from './createComposable'\nimport { defineMixin } from './defineMixin'\n\ninterface User {\n  name: string\n  street: string\n  city: string\n  hobbies: string[]\n}\n\nconst mixin = defineMixin({\n  props: {\n    show: { type: Boolean },\n    msg: { type: String, required: true },\n  },\n  emits: {\n    // eslint-disable-next-line no-autofix/unused-imports/no-unused-vars\n    'update:show': (value?: any) => true,\n  },\n  data: () => ({\n    msg: 'Hello World',\n    age: 10,\n    user: {} as User,\n  }),\n  computed: {\n    birthYear(): number {\n      return new Date().getFullYear() - this.age\n    },\n  },\n  methods: {\n    testFn(): void {\n      console.log(this.user)\n    },\n  },\n} as const)\n\nconst testComposable = createComposableFromMixin(mixin)\n\n/* eslint-disable no-autofix/unused-imports/no-unused-vars */\nconst Comp = defineComponent({\n  setup() {\n    const state = testComposable()\n\n    state.age\n    state.msg\n    state.user.value\n    state.birthYear\n    state.testFn()\n  },\n})\n\nconst props = testComposable.props\nconst emits = testComposable.emits\n\nconst CompWMixin = defineComponent({\n  mixins: [mixin],\n})\n\ntype TCompWMixin = InstanceType<typeof CompWMixin>\ntype checkAge = TCompWMixin['age']\ntype checkUser = TCompWMixin['user']\n"
  },
  {
    "path": "src/types.ts",
    "content": "/**\n * @legal\n * Various types in this file are based on code from the Vue 3 codebase:\n * https://github.com/vuejs/core/blob/f67bb500b6071bc0e55a89709a495a27da73badd/packages/runtime-core/src/componentOptions.ts\n */\n\n// TODO: replace with ComponentOptions or something\nimport type {\n  ComponentPublicInstance,\n  ComputedGetter,\n  EmitsOptions,\n  ObjectEmitsOptions,\n  WatchCallback,\n  WatchOptions,\n  WritableComputedOptions,\n} from 'vue'\n\nexport type EmitsToProps<T extends EmitsOptions> = T extends string[]\n  ? {\n      [K in string & `on${Capitalize<T[number]>}`]?: (...args: any[]) => any\n    }\n  : T extends ObjectEmitsOptions\n  ? {\n      [K in string &\n        `on${Capitalize<string & keyof T>}`]?: K extends `on${infer C}`\n        ? T[Uncapitalize<C>] extends null\n          ? (...args: any[]) => any\n          : (\n              ...args: T[Uncapitalize<C>] extends (...args: infer P) => any\n                ? P\n                : never\n            ) => any\n        : never\n    }\n  : {}\n\nexport interface MethodOptions<Context = ComponentPublicInstance> {\n  [key: string]: (\n    this: ComponentPublicInstance & Context,\n    ...args: any[]\n  ) => any\n}\n\nexport type ComputedOptions = Record<\n  string,\n  ComputedGetter<any> | WritableComputedOptions<any>\n>\nexport type ContextualizedComputedOptions<Context, T = any> = Record<\n  string,\n  | ((this: ComponentPublicInstance & Context, ...args: any[]) => any)\n  | {\n      get(): T\n      set(v: T): void\n    }\n>\nexport type ExtractComputedReturns<T extends any> = {\n  [key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }\n    ? TReturn\n    : T[key] extends (...args: any[]) => infer TReturn\n    ? TReturn\n    : never\n}\n\nexport type ObjectWatchOptionItem = {\n  handler: WatchCallback | string\n} & WatchOptions\ntype WatchOptionItem = string | WatchCallback | ObjectWatchOptionItem\nexport type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]\n"
  },
  {
    "path": "src/utils.ts",
    "content": "import {\n  callWithAsyncErrorHandling,\n  type ComponentInternalInstance,\n  type ComponentPublicInstance,\n} from 'vue'\n\nexport const isFunction = (val: unknown): val is Function =>\n  typeof val === 'function'\nexport const isArray = Array.isArray\nexport const isObject = (val: unknown): val is Record<any, any> =>\n  val !== null && typeof val === 'object'\nexport const isString = (val: unknown): val is string => typeof val === 'string'\n\n/**\n * @legal\n * taken from the Vue 3 Codebase, slightly adjusted:\n * https://github.com/vuejs/core/blob/f67bb500b6071bc0e55a89709a495a27da73badd/packages/runtime-core/src/componentOptions.ts#L878-L890\n */\nexport function callHook(\n  hook: Function,\n  instance: ComponentInternalInstance,\n  vm: ComponentPublicInstance,\n  type: 'c' | 'bc'\n) {\n  callWithAsyncErrorHandling(\n    isArray(hook) ? hook.map((h) => h.bind(vm)) : hook.bind(vm),\n    instance,\n    type as any\n  )\n}\n"
  },
  {
    "path": "src/vmContextProxy.ts",
    "content": "import type { ComponentPublicInstance } from 'vue'\n\nexport /* #__PURE__ */ function createContextProxy(\n  _vm: ComponentPublicInstance,\n  context: Record<string, any>\n) {\n  return new Proxy(_vm, {\n    get(vm, key, receiver) {\n      if (key in context) {\n        return Reflect.get(context, key, receiver)\n      } else {\n        return (vm as any)[key]\n      }\n    },\n    set(vm, key, value, receiver) {\n      if (key in context) {\n        return Reflect.set(context, key, value, receiver)\n      } else {\n        return Reflect.set(vm, key, value)\n      }\n    },\n    has(vm, property) {\n      return Reflect.has(context, property) || Reflect.has(vm, property)\n    },\n    getOwnPropertyDescriptor(vm, property) {\n      if (property in context) {\n        return Reflect.getOwnPropertyDescriptor(context, property)\n      } else {\n        return Reflect.getOwnPropertyDescriptor(vm, property)\n      }\n    },\n    defineProperty(vm, property, descriptor) {\n      return Reflect.defineProperty(vm, property, descriptor)\n    },\n    deleteProperty(vm, property) {\n      if (property in context) {\n        return Reflect.deleteProperty(context, property)\n      } else {\n        return Reflect.deleteProperty(vm, property)\n      }\n    },\n  })\n}\n"
  },
  {
    "path": "tsconfig.app.json",
    "content": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.web.json\",\n  \"include\": [\"src/env.d.tsd.ts\", \"src/**/*\", \"src/**/*.vue\"],\n  \"exclude\": [\"src/**/__tests__/*\"],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"outDir\": \"dist\",\n    \"allowJs\": true,\n    \"baseUrl\": \".\",\n    \"rootDir\": \"src\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "tsconfig.config.json",
    "content": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.node.json\",\n  \"include\": [\"vite.config.*\", \"vitest.config.*\", \"cypress.config.*\", \"playwright.config.*\"],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"types\": [\"node\"]\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"files\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.config.json\"\n    },\n    {\n      \"path\": \"./tsconfig.app.json\"\n    },\n    {\n      \"path\": \"./tsconfig.vitest.json\"\n    }\n  ]\n}\n"
  },
  {
    "path": "tsconfig.vitest.json",
    "content": "{\n  \"extends\": \"./tsconfig.app.json\",\n  \"exclude\": [],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"lib\": [],\n    \"types\": [\"node\", \"jsdom\"]\n  }\n}\n"
  },
  {
    "path": "vite.config.ts",
    "content": "/// <reference types=\"vitest\" />\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vite'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  resolve: {\n    alias: {\n      '@': fileURLToPath(new URL('./src', import.meta.url)),\n    },\n  },\n  build: {\n    lib: {\n      entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)),\n      name: 'VueComixable',\n      formats: ['es', 'cjs', 'iife'],\n      fileName: (format) => {\n        switch (format) {\n          case 'es':\n            return 'index.mjs'\n          case 'cjs':\n            return 'index.cjs'\n          case 'iife':\n            return 'index.js'\n          default:\n            return 'index.js'\n        }\n      },\n    },\n    rollupOptions: {\n      external: ['vue'],\n      output: {\n        globals: {\n          vue: 'Vue',\n        },\n      },\n    },\n  },\n  test: {\n    setupFiles: ['./src/__tests__/setup.ts'],\n  },\n})\n"
  }
]