diff --git a/cursorless-nx/libs/generate-examples/.babelrc b/cursorless-nx/libs/generate-examples/.babelrc new file mode 100644 index 0000000000..e24a5465f3 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/.babelrc @@ -0,0 +1,10 @@ +{ + "presets": [ + [ + "@nrwl/web/babel", + { + "useBuiltIns": "usage" + } + ] + ] +} diff --git a/cursorless-nx/libs/generate-examples/.eslintrc.json b/cursorless-nx/libs/generate-examples/.eslintrc.json new file mode 100644 index 0000000000..9d9c0db55b --- /dev/null +++ b/cursorless-nx/libs/generate-examples/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/cursorless-nx/libs/generate-examples/README.md b/cursorless-nx/libs/generate-examples/README.md new file mode 100644 index 0000000000..41ab501054 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/README.md @@ -0,0 +1,11 @@ +# generate-examples + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build generate-examples` to build the library. + +## Running unit tests + +Run `nx test generate-examples` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/cursorless-nx/libs/generate-examples/jest.config.js b/cursorless-nx/libs/generate-examples/jest.config.js new file mode 100644 index 0000000000..85725d68fb --- /dev/null +++ b/cursorless-nx/libs/generate-examples/jest.config.js @@ -0,0 +1,15 @@ +/* eslint-disable */ +export default { + displayName: 'generate-examples', + preset: '../../jest.preset.js', + globals: { + 'ts-jest': { + tsconfig: '/tsconfig.spec.json', + }, + }, + transform: { + '^.+\\.[tj]s$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/libs/generate-examples', +}; diff --git a/cursorless-nx/libs/generate-examples/package-lock.json b/cursorless-nx/libs/generate-examples/package-lock.json new file mode 100644 index 0000000000..c7c5eb2cdd --- /dev/null +++ b/cursorless-nx/libs/generate-examples/package-lock.json @@ -0,0 +1,881 @@ +{ + "name": "@cursorless/generate-examples", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@cursorless/generate-examples", + "version": "0.0.1", + "dependencies": { + "fs-extra": "11.1.0", + "prettier": "2.8.4", + "shiki": "0.14.3", + "tsx": "3.12.7", + "yaml": "2.2.1" + } + }, + "node_modules/@esbuild-kit/cjs-loader": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz", + "integrity": "sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==", + "dependencies": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", + "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", + "dependencies": { + "esbuild": "~0.17.6", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", + "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", + "dependencies": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.2.tgz", + "integrity": "sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/shiki": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", + "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/tsx": { + "version": "3.12.7", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz", + "integrity": "sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==", + "dependencies": { + "@esbuild-kit/cjs-loader": "^2.4.2", + "@esbuild-kit/core-utils": "^3.0.0", + "@esbuild-kit/esm-loader": "^2.5.5" + }, + "bin": { + "tsx": "dist/cli.js" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==" + }, + "node_modules/yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "engines": { + "node": ">= 14" + } + } + }, + "dependencies": { + "@esbuild-kit/cjs-loader": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz", + "integrity": "sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==", + "requires": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "@esbuild-kit/core-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", + "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", + "requires": { + "esbuild": "~0.17.6", + "source-map-support": "^0.5.21" + } + }, + "@esbuild-kit/esm-loader": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", + "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", + "requires": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "optional": true + }, + "ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "requires": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "get-tsconfig": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.2.tgz", + "integrity": "sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==", + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==" + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, + "shiki": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", + "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "requires": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "tsx": { + "version": "3.12.7", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz", + "integrity": "sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==", + "requires": { + "@esbuild-kit/cjs-loader": "^2.4.2", + "@esbuild-kit/core-utils": "^3.0.0", + "@esbuild-kit/esm-loader": "^2.5.5", + "fsevents": "~2.3.2" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==" + }, + "yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==" + } + } +} diff --git a/cursorless-nx/libs/generate-examples/package.json b/cursorless-nx/libs/generate-examples/package.json new file mode 100644 index 0000000000..c569188084 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/package.json @@ -0,0 +1,17 @@ +{ + "name": "@cursorless/generate-examples", + "version": "0.0.1", + "type": "module", + "scripts": { + "build": "tsx src/lib/buildDictionary", + "test": "jest", + "test:watch": "jest --watch" + }, + "dependencies": { + "fs-extra": "11.1.0", + "prettier": "2.8.4", + "shiki": "0.14.3", + "tsx": "3.12.7", + "yaml": "2.2.1" + } +} diff --git a/cursorless-nx/libs/generate-examples/project.json b/cursorless-nx/libs/generate-examples/project.json new file mode 100644 index 0000000000..1396590a7e --- /dev/null +++ b/cursorless-nx/libs/generate-examples/project.json @@ -0,0 +1,33 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/generate-examples/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nrwl/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/generate-examples", + "main": "libs/generate-examples/src/index.ts", + "tsConfig": "libs/generate-examples/tsconfig.lib.json", + "assets": ["libs/generate-examples/*.md"] + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/generate-examples/**/*.ts"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/libs/generate-examples"], + "options": { + "jestConfig": "libs/generate-examples/jest.config.ts", + "passWithNoTests": true + } + } + }, + "tags": [] +} diff --git a/cursorless-nx/libs/generate-examples/src/index.ts b/cursorless-nx/libs/generate-examples/src/index.ts new file mode 100644 index 0000000000..1efb8fa2e7 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/index.ts @@ -0,0 +1 @@ +export * from './lib/generate-examples'; diff --git a/cursorless-nx/libs/generate-examples/src/lib/buildDictionary.ts b/cursorless-nx/libs/generate-examples/src/lib/buildDictionary.ts new file mode 100644 index 0000000000..de3a6c2780 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/buildDictionary.ts @@ -0,0 +1,23 @@ +import { loadFixture } from './loadFixture.js'; + +Promise.all([ + loadFixture('actions', 'bringArgMadeAfterLook'), + loadFixture('decorations', 'chuckBlockAirUntilBatt'), + loadFixture('decorations', 'cutFine'), + loadFixture('decorations', 'chuckLineFine'), + loadFixture('actions', 'bringAirAndBatAndCapToAfterItemEach'), +]).then((allItems) => { + allItems.forEach((item) => { + if (item) + console.log(` +.wrapper + .before + ${item.before.replace(/\n/gi, '\n ')} + .during + ${(item.during || item.before).replace(/\n/gi, '\n ')} + .command ${item.command} + .after + ${item.after.replace(/\n/gi, '\n ')} +`); + }); +}); diff --git a/cursorless-nx/libs/generate-examples/src/lib/buildSpokenForm.ts b/cursorless-nx/libs/generate-examples/src/lib/buildSpokenForm.ts new file mode 100644 index 0000000000..26f974c6c1 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/buildSpokenForm.ts @@ -0,0 +1,189 @@ +import path from 'path'; +import fs from 'fs-extra'; +const cursorlessRoot = path.resolve('../../../src'); + +const commandDictionaryJson = fs.readJSONSync( + path.join( + cursorlessRoot, + '../cursorless-nx/libs/cheatsheet/src/lib/data/sampleSpokenFormInfos/defaults.json' + ) +) as typeof import('../../../cheatsheet/src/lib/data/sampleSpokenFormInfos/defaults.json'); + +const letters = 'abcdefghijklmnopqrstuvwxyz'.split(''); +const defaultAlphabet = + 'air bat cap drum each fine gust harp sit jury crunch look made near odd pit quench red sun trap urge vest whale plex yank zip' + .split(' ') + .map((word, index) => [letters[index], word] as const); + +const defaultDigits = 'zero one two three four five six seven eight nine' + .split(' ') + .map((word, index) => [`${index}`, word] as const); + +const letterDictionary = defaultAlphabet + .concat(defaultDigits) + .reduce((r, [key, value]) => ({ ...r, [key]: value }), {}); + +const commandDictionary = commandDictionaryJson.sections.reduce( + (topResult, section) => { + return { + ...topResult, + [section.id]: section.items.reduce( + (r, { id, variations }) => ({ + ...r, + [id]: variations[0].spokenForm, + }), + {} + ), + }; + }, + {} as Record< + typeof commandDictionaryJson['sections'][number]['id'], + Record< + typeof commandDictionaryJson['sections'][number]['items'][number]['id'], + typeof commandDictionaryJson['sections'][number]['items'][number]['variations'][0]['spokenForm'] + > + > +); + +type CommandDictionary = typeof commandDictionary; + +interface Modifier { + type: 'position' | 'containingScope'; + position: keyof CommandDictionary['positions']; + scopeType: { + type: keyof CommandDictionary['scopes']; + }; +} +type PrimitiveTarget = { + type: 'primitive'; + modifiers?: Modifier[]; + position?: keyof CommandDictionary['positions']; + mark?: { + type: 'decoratedSymbol'; + character: keyof typeof letterDictionary; + }; +}; + +type RangeTarget = { + type: 'range'; + excludeAnchor?: boolean; + excludeActive?: boolean; + anchor: Target; + active: Target; +}; + +type ListTarget = { + type: 'list'; + elements: Target[]; +}; + +type Target = PrimitiveTarget | RangeTarget | ListTarget; +type Command = { action: { name: string }; targets: Target[] }; + +function interpolate( + template: string, + handleAction: (counter: number) => string +) { + let counter = -1; + return template.replace(/<[a-z0-9]+>/gi, () => handleAction(++counter)); +} + +class SpokenForm { + private command: Command; + + constructor(command: Command) { + this.command = command; + } + + public build() { + return interpolate(this.getTemplate(), (counter) => + this.parseTarget(this.command.targets[counter]) + ); + } + + private getTemplate() { + return commandDictionary['actions'][this.command.action.name]; + } + + private parseTarget(target: Target): string { + if (!target) throw new Error(`Excess mark`); + switch (target.type) { + case 'primitive': + return this.parsePrimitiveTarget(target); + case 'range': + return this.parseRangeTarget(target); + case 'list': + return this.parseListTarget(target); + default: { + // @ts-expect-error - if this is hit we need to add new cases and types + throw new Error(`Unknown target type ${target.type}`); + } + } + } + parsePrimitiveTarget(target: PrimitiveTarget) { + let prefix = + target.modifiers + ?.filter((v): v is Modifier => !!v) + ?.map((mod) => { + switch (mod.type) { + case 'position': + return commandDictionary['positions'][mod.position]; + case 'containingScope': + return commandDictionary['scopes'][mod.scopeType.type]; + } + throw new Error(`Unknown modifier type ${mod.type}`); + }) + .join(' ') || ''; + if (target.position) { + prefix = `${commandDictionary['positions'][target.position]} ${prefix}`; + } + if (target.mark) { + if (target.mark.type !== 'decoratedSymbol') + throw new Error(`Unknown target type ${target.mark.type}`); + return ( + (prefix ? prefix + ' ' : '') + letterDictionary[target.mark.character] + ); + } + if (!prefix) throw new Error(`Unknown mark`); + return prefix; + } + + parseRangeTarget(target: RangeTarget) { + let compoundTargetKey; + if (target.excludeAnchor && target.excludeActive) + compoundTargetKey = 'rangeExclusive'; + else if (!target.excludeAnchor && !target.excludeActive) + compoundTargetKey = 'rangeInclusive'; + else if (!target.excludeAnchor && target.excludeActive) + compoundTargetKey = 'rangeExcludingEnd'; + else throw new Error(`Bad inclusion range`); + return interpolate( + commandDictionary['compoundTargets'][compoundTargetKey], + (index) => { + if (index === 0) return this.parseTarget(target.anchor); + if (index === 1) return this.parseTarget(target.active); + return ''; + } + ); + } + parseListTarget(target: ListTarget) { + return target.elements.reduce((result, element) => { + if (!result) return this.parseTarget(element); + return interpolate( + commandDictionary['compoundTargets']['listConnective'], + (index) => { + if (index === 0) return result; + if (index === 1) return this.parseTarget(element); + throw Error(`Invalid List`); + } + ); + }, ''); + } +} + +export function buildSpokenForm(command: { + action: { name: string }; + targets: Target[]; +}) { + return new SpokenForm(command).build(); +} diff --git a/cursorless-nx/libs/generate-examples/src/lib/generate-examples.ts b/cursorless-nx/libs/generate-examples/src/lib/generate-examples.ts new file mode 100644 index 0000000000..246cf0e168 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/generate-examples.ts @@ -0,0 +1,3 @@ +export function generateExamples(): string { + return 'generate-examples'; +} diff --git a/cursorless-nx/libs/generate-examples/src/lib/generateHtml.spec.ts b/cursorless-nx/libs/generate-examples/src/lib/generateHtml.spec.ts new file mode 100644 index 0000000000..8742a9e506 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/generateHtml.spec.ts @@ -0,0 +1,310 @@ +import prettier from 'prettier'; +import { generateHtml as unformettedFunc } from './generateHtml'; + +async function generateHtml(...args: Parameters) { + return prettier.format(await unformettedFunc(...args), { + singleAttributePerLine: true, + htmlWhitespaceSensitivity: 'ignore', + parser: 'babel', + }); +} + +describe('generateHtml', () => { + it('should select whole line', async () => { + expect( + await generateHtml( + { + documentContents: ' const oneLine = 1;\nconst line2 = 2;', + selections: [ + { + type: 'line', + anchor: { line: 1, character: 0 }, + active: { line: 1, character: 22 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+             
+            const
+             
+            oneLine
+             
+            =
+             
+            1
+            ;
+          
+          
+            const
+             
+            line2
+             
+            =
+             
+            2
+            ;
+          
+        
+      
; + " + `); + }); + it('should select single token', async () => { + expect( + await generateHtml( + { + documentContents: ' const oneLine = 1;\nconst line2 = 2;', + selections: [ + { + type: 'selection', + anchor: { line: 0, character: 8 }, + active: { line: 0, character: 15 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+             
+            const
+             
+            
+              oneLine
+            
+             
+            =
+             
+            1
+            ;
+          
+          
+            const
+             
+            line2
+             
+            =
+             
+            2
+            ;
+          
+        
+      
; + " + `); + }); + + it('should select multiple tokens', async () => { + expect( + await generateHtml( + { + documentContents: 'const oneLine = 1;', + selections: [ + { + type: 'selection', + anchor: { line: 0, character: 6 }, + active: { line: 0, character: 17 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            
+              oneLine
+               
+              =
+               
+              1
+            
+            ;
+          
+        
+      
; + " + `); + }); + + it('should select inside tokens', async () => { + expect( + await generateHtml( + { + documentContents: 'const oneLine = "line";', + selections: [ + { + type: 'selection', + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 19 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            one
+            
+              Line
+               
+              =
+               
+              
+                "li
+              
+            
+            ne"
+            ;
+          
+        
+      
; + " + `); + }); + + it('should select inside single token', async () => { + expect( + await generateHtml( + { + documentContents: 'const oneLine = 1;', + selections: [ + { + type: 'selection', + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 11 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            one
+            
+              Li
+            
+            ne
+             
+            =
+             
+            1
+            ;
+          
+        
+      
; + " + `); + }); + it('should select superset ranges', async () => { + expect( + await generateHtml( + { + documentContents: 'const oneLine = 1;', + selections: [ + { + type: 'selection', + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 11 }, + }, + ], + thatMark: [ + { + type: 'selection', + anchor: { line: 0, character: 6 }, + active: { line: 0, character: 13 }, + }, + ], + }, + + 'typescript' + ) + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            
+              one
+            
+            
+              Li
+            
+            
+              ne
+            
+             
+            =
+             
+            1
+            ;
+          
+        
+      
; + " + `); + }); +}); diff --git a/cursorless-nx/libs/generate-examples/src/lib/generateHtml.ts b/cursorless-nx/libs/generate-examples/src/lib/generateHtml.ts new file mode 100644 index 0000000000..8396ccdd11 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/generateHtml.ts @@ -0,0 +1,389 @@ +import { getHighlighter, Lang } from 'shiki'; +import { renderToHtml, HatType, SelectionType, Token } from './renderToHtml'; + +export interface SelectionAnchor { + line: number; + character: number; +} + +interface CursorlessFixtureSelection { + type: 'line' | 'selection'; + name?: string; + anchor: SelectionAnchor; + active: SelectionAnchor; +} +interface CursorlessFixtureState { + documentContents: any; + marks?: Record< + `${HatType}.${string}`, + { start: { line: number; character: number } } + >; + decorations?: CursorlessFixtureSelection[]; + selections?: CursorlessFixtureSelection[]; + thatMark?: [CursorlessFixtureSelection]; + sourceMark?: [CursorlessFixtureSelection]; +} + +export async function generateHtml(state: CursorlessFixtureState, lang: Lang) { + return new HTMLGenerator(state, lang).generate(); +} + +const highlighter = getHighlighter({ theme: 'css-variables' }); + +class HTMLGenerator { + private state: CursorlessFixtureState; + private lang: Lang; + private tokens: Token[][]; + private lineOptions: any[]; + + constructor(state: CursorlessFixtureState, lang: Lang) { + this.state = state; + this.lang = lang; + this.tokens = []; + this.lineOptions = []; + } + + async generate() { + await this.getTokens(); + this.applyMarks(); + this.applyAllSelections(); + return renderToHtml(this.tokens, { + bg: 'var(--shiki-color-background)', + fg: 'var(--shiki-color-text)', + lineOptions: this.lineOptions, + }); + } + + async getTokens() { + this.tokens = (await highlighter) + .codeToThemedTokens(this.state.documentContents, this.lang) + .map((line) => + line.map( + (token) => + ({ + ...token, + type: 'token', + } as Token) + ) + ); + } + + applyMarks() { + Object.entries(this.state.marks || {}).forEach(([key, mark]) => { + const [type, letterArg] = key.split('.') as [HatType, string]; + const letter = !letterArg || letterArg === '' ? '.' : letterArg; + const line = this.tokens[mark.start.line]; + if (!line) return; + this.insertHat( + line as Extract[], + type, + letter, + mark.start.character + ); + }); + } + insertHat( + line: Extract[], + hatType: HatType, + markCharacter: string, + wordStart: number + ) { + let rawIndex = 0; + for (let t = 0; t < line.length; t += 1) { + const token = line[t]; + if (token.content.length + rawIndex < wordStart) { + rawIndex += token.content.length; + continue; + } + for (let i = 0; i < token.content.length; i += 1) { + rawIndex += 1; + if (token.content[i] === markCharacter) { + line.splice( + t, + 1, + { ...token, content: token.content.substring(0, i) }, + { + type: 'hat', + hatType, + content: token.content.substring(i, i + 1), + }, + { ...token, content: token.content.substring(i + 1) } + ); + return; + } + } + throw new Error(`Mark not found`); + } + } + + applyAllSelections() { + if (!this.applySelectionsFromState('decorations')) { + this.applySelectionsFromState('selections'); + } + this.applySelectionsFromState('thatMark'); + this.applySelectionsFromState('sourceMark'); + } + + applySelectionsFromState( + key: 'decorations' | 'selections' | 'thatMark' | 'sourceMark' + ): boolean { + const selections = this.state[key]; + if (!selections?.length) return false; + const selectionParser = new SelectionParser( + this.tokens, + key.replace(/s$/gi, '') as SelectionType + ); + selections.forEach((selection) => { + if (selection.type === 'line') { + return this.applyLineSelection(key, selection); + } + selectionParser.parse(selection); + }); + return true; + } + + getSelectionClasses( + selectionType: keyof typeof this.state, + selection: CursorlessFixtureSelection + ) { + const classes = [selectionType.replace(/s$/g, '')]; + if (selection.name) { + classes.push(selection.name); + } + return classes; + } + + applyLineSelection( + selectionType: keyof typeof this.state, + selection: CursorlessFixtureSelection + ) { + const classes = this.getSelectionClasses(selectionType, selection); + const { anchor: start, active: end } = selection; + for (let i = start.line + 1; i <= end.line + 1; i += 1) + this.lineOptions.push({ + line: i, + classes, + }); + } +} + +class SelectionParser { + private lines: Token[][]; + private selectionType: SelectionType; + + constructor(lines: Token[][], selectionType: SelectionType) { + this.lines = lines; + this.selectionType = selectionType; + } + + parse(selection: CursorlessFixtureSelection) { + const { anchor: start, active: end } = selection; + for (let l = end.line; l <= start.line; l += 1) { + if (l !== end.line && l !== start.line) { + this.handleInsideLine(l); + continue; + } + this.lines[l] = this.parseLine(l, start, end); + } + } + + parseLine(l: number, start: SelectionAnchor, end: SelectionAnchor) { + const lineParser = new SelectionLineParser( + this.selectionType, + this.lines[l] + ); + if (end.line === start.line) + return lineParser.parse(start.character, end.character); + if (l === end.line) return lineParser.parse(0, end.character); + return lineParser.parse(start.character, Infinity); + } + + handleInsideLine(currentLine: number) { + this.lines[currentLine] = [ + { + type: 'selection', + selection: this.lines[currentLine], + className: this.selectionType, + }, + ]; + } +} + +type BaseToken = Exclude; +type SelectionToken = Extract; + +class SelectionLineParser { + selectionType: SelectionType; + line: Token[]; + result: Token[]; + activeSelectionTypes: string[]; + startIndex: number; + endIndex: number; + rawIndex = 0; + + constructor(selectionType: SelectionType, line: Token[]) { + this.selectionType = selectionType; + this.line = [...line]; + this.result = []; + this.activeSelectionTypes = []; + this.startIndex = 0; + this.endIndex = Infinity; + } + + hasRemainingTokens() { + return this.line.length > 0; + } + + getTokenState(tokenStart: number, tokenEnd: number) { + if (tokenEnd <= this.startIndex || this.endIndex <= tokenStart) + return 'outside'; + if (tokenStart === this.startIndex && tokenEnd === this.endIndex) + return 'entire'; + if (!this.getCurrentSelectionToken() && tokenEnd >= this.endIndex) + return 'inner'; + if (!this.getCurrentSelectionToken()) return 'start'; + if (tokenEnd >= this.endIndex) return 'end'; + return 'continue'; + } + + getCurrentSelectionToken() { + const lastResult = this.result[this.result.length - 1]; + return lastResult?.type === 'selection' ? lastResult : undefined; + } + + parse(startIndex: number, endIndex: number) { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.rawIndex = 0; + while (this.hasRemainingTokens()) { + this.parseToken(this.line.shift()); + } + return this.result; + } + + parseToken(token: Token | undefined) { + if (!token) return; + if (token.type === 'selection') return this.parseSelection(token); + const tokenStart = this.rawIndex; + this.incrementRawIndex(token); + const tokenEnd = this.rawIndex; + const state = this.getTokenState(tokenStart, tokenEnd); + switch (state) { + case 'outside': { + this.result.push(token); + return; + } + case 'entire': { + this.createSelection(token); + return; + } + case 'start': { + this.startSelection(token); + return; + } + case 'continue': { + this.getCurrentSelectionToken()?.selection.push(token); + return; + } + case 'end': { + this.endSelection(token); + return; + } + case 'inner': { + this.innerSelection(token); + return; + } + } + } + + parseSelection(token: SelectionToken) { + this.activeSelectionTypes.push(token.className); + this.result.push({ + type: 'selection', + className: this.activeSelectionTypes.join(' '), + selection: [], + }); + for (const subToken of token.selection) { + this.parseToken(subToken); + } + this.activeSelectionTypes.pop(); + this.result.push({ + type: 'selection', + className: this.activeSelectionTypes.join(' '), + selection: [], + }); + } + + getCurrentSelectionClassName() { + return this.selectionType; + } + + incrementRawIndex(token: BaseToken) { + this.rawIndex += token.content.length; + } + + createSelection(token: Token) { + this.activeSelectionTypes.push( + (token as SelectionToken).className || this.getCurrentSelectionClassName() + ); + this.result.push({ + type: 'selection', + className: this.activeSelectionTypes.join(' '), + selection: [token], + }); + } + + startSelection(token: BaseToken) { + const selectionStartIndex = + token.content.length - (this.rawIndex - this.startIndex); + const preSelectionContent = token.content.substring(0, selectionStartIndex); + const selectionContent = token.content.substring(selectionStartIndex); + if (preSelectionContent.length) { + this.result.push({ + ...token, + content: preSelectionContent, + }); + } + this.createSelection({ ...token, content: selectionContent }); + } + + endSelection(token: BaseToken) { + const selectionStartIndex = + token.content.length - (this.rawIndex - this.endIndex); + const selectionContent = token.content.substring(0, selectionStartIndex); + const postSelectionContent = token.content.substring(selectionStartIndex); + this.getCurrentSelectionToken()?.selection.push({ + ...token, + content: selectionContent, + }); + this.activeSelectionTypes.pop(); + if (postSelectionContent.length) + this.result.push({ + ...token, + content: postSelectionContent, + }); + } + + innerSelection(token: BaseToken) { + const stringStart = + token.content.length - (this.rawIndex - this.startIndex); + const stringEnd = token.content.length - (this.rawIndex - this.endIndex); + const preSelectionContent = token.content.substring(0, stringStart); + const selectionContent = token.content.substring(stringStart, stringEnd); + const postSelectionContent = token.content.substring(stringEnd); + if (preSelectionContent.length) + this.result.push({ + ...token, + content: preSelectionContent, + }); + this.createSelection({ + ...token, + content: selectionContent, + }); + if (postSelectionContent.length) + this.result.push({ + ...token, + content: postSelectionContent, + }); + } +} diff --git a/cursorless-nx/libs/generate-examples/src/lib/loadFixture.ts b/cursorless-nx/libs/generate-examples/src/lib/loadFixture.ts new file mode 100644 index 0000000000..1cec6937d0 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/loadFixture.ts @@ -0,0 +1,84 @@ +import path from 'path'; +import fs from 'fs-extra'; +import * as yaml from 'yaml'; + +import { buildSpokenForm } from './buildSpokenForm'; +import { generateHtml, SelectionAnchor } from './generateHtml'; + +const fixturesDir = path.join( + '../../../packages', + 'cursorless-vscode-e2e', + 'suite', + 'fixtures', + 'recorded' +); + +async function safeGenerateHtml( + ...args: [stateName: string, ...rest: Parameters] +) { + const [stateName, state, languageId] = args; + try { + return await generateHtml(state, languageId); + } catch (e) { + console.log('error in state', stateName, e); + console.log(JSON.stringify(state, null, 2)); + throw e; + } +} + +export async function loadFixture(folder: string, name: string) { + const filepath = path.join(fixturesDir, folder, `${name}.yml`); + const data = yaml.parse(await fs.readFile(filepath, 'utf-8')); + if (data.command.version !== 2) return; + try { + const during = data.decorations + ? await safeGenerateHtml( + 'decorations', + { + ...data.initialState, + decorations: data.decorations.map( + ({ + name, + type, + start, + end, + }: { + name: string; + type: string; + start: SelectionAnchor; + end: SelectionAnchor; + }) => ({ + name, + type, + anchor: start, + active: end, + }) + ), + }, + data.languageId + ) + : undefined; + const before = await safeGenerateHtml( + 'initialState', + data.initialState, + data.languageId + ); + const after = await safeGenerateHtml( + 'finalState', + data.finalState, + data.languageId + ); + return { + language: data.languageId, + command: buildSpokenForm(data.command), + originalCommand: data.command.spokenForm, + during, + before, + after, + }; + } catch (e) { + console.log('error', filepath, e); + console.log(JSON.stringify(data, null, 2)); + throw e; + } +} diff --git a/cursorless-nx/libs/generate-examples/src/lib/renderToHtml.ts b/cursorless-nx/libs/generate-examples/src/lib/renderToHtml.ts new file mode 100644 index 0000000000..a367647df5 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/src/lib/renderToHtml.ts @@ -0,0 +1,193 @@ +// forked from https://github.com/SimeonC/shiki/blob/main/packages/shiki/src/renderer.ts + +import { IThemedToken } from 'shiki'; + +// MIT License +const FontStyle = { + NotSet: -1, + None: 0, + Italic: 1, + Bold: 2, + Underline: 4, +} as const; + +export function groupBy( + elements: TObject[], + keyGetter: (element: TObject) => string +) { + const map = new Map(); + for (const element of elements) { + const key = keyGetter(element); + if (map.has(key)) { + const group = map.get(key); + group.push(element); + } else { + map.set(key, [element]); + } + } + return map; +} + +export type HatType = 'default'; +interface BaseElementProps { + style?: string; + children: string; + className?: string; +} + +const elements = { + pre({ className, style = '', children }: BaseElementProps) { + return `
${children}
`; + }, + + code({ children }: Pick) { + return `${children}`; + }, + + line({ className, children }: Omit) { + return `${children}`; + }, + + token({ style = '', children }: Omit) { + return `${children}`; + }, + + selection({ style = '', className, children }: BaseElementProps) { + return `${children}`; + }, + + hat({ hatType, children }: { hatType: HatType; children: string }) { + return `${children}`; + }, +} as const; +export type SelectionType = + | 'decoration' + | 'selection' + | 'thatMark' + | 'sourceMark'; +export type Token = + | ({ + type: 'token'; + } & IThemedToken) + | { + type: 'selection'; + className: string; + selection: Token[]; + } + | { + type: 'hat'; + hatType: HatType; + content: string; + }; + +export function renderToHtml( + lines: Token[][], + options: { + langId?: string; + bg?: string; + fg?: string; + lineOptions?: { line: string }[]; + } = {} +) { + const bg = options.bg || '#fff'; + const optionsByLineNumber = groupBy( + options.lineOptions ?? [], + (option) => option.line + ); + + function h< + TType extends keyof typeof elements, + TProps extends BaseElementProps = Parameters[0] + >(type: TType, props: Omit, children: string[]) { + const element = elements[type] as typeof elements[TType]; + if (element) { + children = children.filter(Boolean); + + return element({ + ...props, + children: type === 'code' ? children.join('\n') : children.join(''), + } as any); + } + + return ''; + } + + function handleToken(token: Token): string { + if (token.type === 'selection') { + return h( + 'selection', + { className: token.className }, + token.selection.map((token) => handleToken(token)) + ); + } + if (token.type === 'hat') { + return h('hat', token, [escapeHtml(token.content)]); + } + + const cssDeclarations = [`color: ${token.color || options.fg}`]; + if (token.fontStyle && FontStyle.Italic) { + cssDeclarations.push('font-style: italic'); + } + if (token.fontStyle && FontStyle.Bold) { + cssDeclarations.push('font-weight: bold'); + } + if (token.fontStyle && FontStyle.Underline) { + cssDeclarations.push('text-decoration: underline'); + } + + return h( + 'token', + { + style: cssDeclarations.join('; '), + }, + [escapeHtml(token.content)] + ); + } + + return h('pre', { className: 'shiki', style: `background-color: ${bg}` }, [ + options.langId ? `
${options.langId}
` : '', + h( + 'code', + {}, + lines.map((line, index) => { + const lineNumber = index + 1; + const lineOptions = optionsByLineNumber.get(lineNumber) ?? []; + const lineClasses = getLineClasses(lineOptions).join(' '); + return h( + 'line', + { + className: lineClasses, + }, + line.length === 0 + ? [' '] + : line.map((token) => handleToken(token)) + ); + }) + ), + ]); +} + +const htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', +} as const; + +function escapeHtml(html: string) { + return (html || '').replace( + /[&<>"']/g, + (chr) => htmlEscapes[chr as keyof typeof htmlEscapes] + ); +} + +function getLineClasses(lineOptions: { classes?: string }[]) { + const lineClasses = new Set(['line']); + for (const lineOption of lineOptions) { + for (const lineClass of lineOption.classes ?? []) { + lineClasses.add(lineClass); + } + } + return Array.from(lineClasses); +} diff --git a/cursorless-nx/libs/generate-examples/tsconfig.json b/cursorless-nx/libs/generate-examples/tsconfig.json new file mode 100644 index 0000000000..01d978e7e6 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/cursorless-nx/libs/generate-examples/tsconfig.lib.json b/cursorless-nx/libs/generate-examples/tsconfig.lib.json new file mode 100644 index 0000000000..694751a4ef --- /dev/null +++ b/cursorless-nx/libs/generate-examples/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": [] + }, + "include": ["**/*.ts", "jest.config.js"], + "exclude": ["jest.config.js", "**/*.spec.ts", "**/*.test.ts"] +} diff --git a/cursorless-nx/libs/generate-examples/tsconfig.spec.json b/cursorless-nx/libs/generate-examples/tsconfig.spec.json new file mode 100644 index 0000000000..ef1c413913 --- /dev/null +++ b/cursorless-nx/libs/generate-examples/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["jest.config.js", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] +} diff --git a/cursorless-nx/workspace.json b/cursorless-nx/workspace.json index 086431b2b1..4272cb7139 100644 --- a/cursorless-nx/workspace.json +++ b/cursorless-nx/workspace.json @@ -6,7 +6,8 @@ "cheatsheet-local-e2e": "apps/cheatsheet-local-e2e", "cursorless-org": "apps/cursorless-org", "cursorless-org-e2e": "apps/cursorless-org-e2e", - "embedded-video": "libs/react/embedded-video" + "embedded-video": "libs/react/embedded-video", + "generate-examples": "libs/generate-examples" }, "$schema": "./node_modules/nx/schemas/workspace-schema.json" }