diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48bcc9664..8534f02de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,18 +32,18 @@ jobs: - run: pnpm lint - uses: wyvox/action-setup-pnpm@v3 - # type-tests: - # name: "Type Tests" - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: pnpm/action-setup@v2 - # - uses: actions/setup-node@v4 - # with: - # cache: pnpm - # - run: pnpm reset - # - run: "pnpm --filter '*' run test:typecheck" - # - run: "pnpm --filter '*' run test:tsc" + type-tests: + name: "Type Tests" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + - uses: actions/setup-node@v4 + with: + cache: pnpm + - run: pnpm reset + - run: "pnpm --filter '*' run test:typecheck" + - run: "pnpm --filter '*' run test:tsc" test: name: Test diff --git a/packages/environment-ember-loose/__tests__/tsconfig.json b/packages/environment-ember-loose/__tests__/tsconfig.json deleted file mode 100644 index 07532216a..000000000 --- a/packages/environment-ember-loose/__tests__/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../../tsconfig.compileroptions.json", - "include": [".", "../-private"], - "compilerOptions": { - "rootDir": ".." - } -} diff --git a/packages/environment-ember-loose/package.json b/packages/environment-ember-loose/package.json index 678b9a19b..47c379071 100644 --- a/packages/environment-ember-loose/package.json +++ b/packages/environment-ember-loose/package.json @@ -7,19 +7,27 @@ "author": "Dan Freeman (https://github.com/dfreeman)", "main": "-private/index.js", "exports": { - ".": "./-private/index.js", - "./registry": "./registry/index.js", - "./glint-environment-definition": "./-private/environment/index.js", - "./-private/dsl": "./-private/dsl/index.js" + ".": { + "types": "./-private/index.d.ts", + "default": "./-private/index.js" + }, + "./registry": { + "types": "./registry/index.d.ts", + "default": "./registry/index.js" + }, + "./glint-environment-definition": { + "types": "./-private/environment/index.d.ts", + "default": "./-private/environment/index.js" + }, + "./-private/dsl": { + "types": "./-private/dsl/index.d.ts", + "default": "./-private/dsl/index.js" + } }, "keywords": [ "glint-environment" ], "scripts": { - "test": "echo 'no tests within this project'", - "test:tsc": "echo 'no standalone typecheck within this project'", - "test:typecheck": "glint --project __tests__/type-tests && vitest run", - "test:watch": "vitest watch", "build": "tsc --build", "prepack": "pnpm build" }, diff --git a/packages/template/package.json b/packages/template/package.json index 088e41f33..7e381ab03 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -34,7 +34,9 @@ "html-element-attributes": "^3.3.0", "html-event-attributes": "^2.2.0", "svg-element-attributes": "^2.1.0", - "svg-event-attributes": "^2.0.2" + "svg-event-attributes": "^2.0.2", + "expect-type": "^0.15.0", + "sums-up": "^2.1.0" }, "publishConfig": { "access": "public" diff --git a/packages/template/tsconfig.json b/packages/template/tsconfig.json index eb55505f2..c8a2487bb 100644 --- a/packages/template/tsconfig.json +++ b/packages/template/tsconfig.json @@ -1,4 +1,3 @@ { - "extends": "../../tsconfig.compileroptions.json", - "exclude": ["__tests__"] + "extends": "../../tsconfig.compileroptions.json" } diff --git a/packages/type-test/package.json b/packages/type-test/package.json index 2e21a6da2..6aeac762e 100644 --- a/packages/type-test/package.json +++ b/packages/type-test/package.json @@ -26,7 +26,11 @@ "@glint/template": "*" }, "devDependencies": { - "@glint/template": "workspace:*" + "@glint/core": "workspace:*", + "@glint/environment-ember-loose": "workspace:*", + "@glint/environment-ember-template-imports": "workspace:*", + "@glint/template": "workspace:*", + "ember-source": "^6.3.0" }, "publishConfig": { "access": "public" diff --git a/packages/type-test/tsconfig.json b/packages/type-test/tsconfig.json index a8d5d207e..9a62bdde7 100644 --- a/packages/type-test/tsconfig.json +++ b/packages/type-test/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../../tsconfig.compileroptions.json", "compilerOptions": { "rootDir": "src", - "outDir": "lib" + "outDir": "lib", + "types": ["ember-source/types"], }, "include": ["src"], "references": [{ "path": "../template" }] diff --git a/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts new file mode 100644 index 000000000..17dbfdb1b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=environment.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts.map new file mode 100644 index 000000000..42adeedf2 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/environment.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"environment.test.d.ts","sourceRoot":"","sources":["environment.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/environment.test.js b/test-packages/types-environment-ember-loose/__tests__/environment.test.js new file mode 100644 index 000000000..439db5c00 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/environment.test.js @@ -0,0 +1,71 @@ +import { describe, test, expect } from 'vitest'; +import envDefinition from '@glint/environment-ember-loose/glint-environment-definition'; +describe('Environments: Ember Loose', () => { + test.each(['ts', 'js'])('finds possible template paths for %s script paths', (ext) => { + let env = envDefinition({}).template; + // colocated script/template pair + expect(env?.getPossibleTemplatePaths(`hello.${ext}`)).toEqual(['hello.hbs']); + // pod component + expect(env?.getPossibleTemplatePaths(`/component.${ext}`)).toEqual([ + '/component.hbs', + '/template.hbs', + ]); + // pod route + expect(env?.getPossibleTemplatePaths(`/route.${ext}`)).toEqual([ + '/route.hbs', + { + path: '/template.hbs', + deferTo: ['/controller.ts', '/controller.js'], + }, + ]); + // pod controller + expect(env?.getPossibleTemplatePaths(`/controller.${ext}`)).toEqual([ + '/controller.hbs', + '/template.hbs', + ]); + // classic route + expect(env?.getPossibleTemplatePaths(`/routes/hello.${ext}`)).toEqual([ + '/routes/hello.hbs', + { + path: '/templates/hello.hbs', + deferTo: ['/controllers/hello.ts', '/controllers/hello.js'], + }, + ]); + // classic controller + expect(env?.getPossibleTemplatePaths(`/controllers/hello.${ext}`)).toEqual([ + '/controllers/hello.hbs', + '/templates/hello.hbs', + ]); + // classic layout component + expect(env?.getPossibleTemplatePaths(`/components/hello.${ext}`)).toEqual([ + '/components/hello.hbs', + '/templates/components/hello.hbs', + ]); + }); + test('finds possible script paths for a template', () => { + let env = envDefinition({}).template; + // colocated script/template pair + expect(env?.getPossibleScriptPaths('hello.hbs')).toEqual(['hello.ts', 'hello.js']); + // Pod component/controller/route + expect(env?.getPossibleScriptPaths('/template.hbs')).toEqual([ + '/template.ts', + '/template.js', + '/component.ts', + '/component.js', + '/controller.ts', + '/controller.js', + '/route.ts', + '/route.js', + ]); + // Classic controller/route + expect(env?.getPossibleScriptPaths('/templates/hello.hbs')).toEqual([ + '/templates/hello.ts', + '/templates/hello.js', + '/controllers/hello.ts', + '/controllers/hello.js', + '/routes/hello.ts', + '/routes/hello.js', + ]); + }); +}); +//# sourceMappingURL=environment.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/environment.test.ts b/test-packages/types-environment-ember-loose/__tests__/environment.test.ts similarity index 96% rename from packages/environment-ember-loose/__tests__/environment.test.ts rename to test-packages/types-environment-ember-loose/__tests__/environment.test.ts index 627c84dbc..9e819f531 100644 --- a/packages/environment-ember-loose/__tests__/environment.test.ts +++ b/test-packages/types-environment-ember-loose/__tests__/environment.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from 'vitest'; -import envDefinition from '../-private/environment/index.js'; +import envDefinition from '@glint/environment-ember-loose/glint-environment-definition'; describe('Environments: Ember Loose', () => { test.each(['ts', 'js'])('finds possible template paths for %s script paths', (ext) => { diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts new file mode 100644 index 000000000..d4697743e --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=ember-component.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts.map new file mode 100644 index 000000000..5452c4583 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ember-component.test.d.ts","sourceRoot":"","sources":["ember-component.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.js new file mode 100644 index 000000000..22ef5c735 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.js @@ -0,0 +1,118 @@ +var _a, _b, _c; +import Component from '@ember/component'; +import { templateForBackingValue, resolve, yieldToBlock, emitComponent, NamedArgsMarker, } from '@glint/environment-ember-loose/-private/dsl'; +import { expectTypeOf } from 'expect-type'; +{ + class NoArgsComponent extends Component { + } + _a = NoArgsComponent; + (() => { + templateForBackingValue(_a, function (__glintRef__) { + __glintRef__; + }); + })(); + resolve(NoArgsComponent)( + // @ts-expect-error: extra positional arg + 'oops'); + { + const component = emitComponent(resolve(NoArgsComponent)()); + { + // @ts-expect-error: never yields, so shouldn't accept blocks + component.blockParams.default; + } + } + emitComponent(resolve(NoArgsComponent)()); +} +{ + class StatefulComponent extends Component { + constructor() { + super(...arguments); + this.foo = 'hello'; + } + } + _b = StatefulComponent; + (() => { + templateForBackingValue(_b, function* (__glintRef__) { + expectTypeOf(__glintRef__.this.foo).toEqualTypeOf(); + expectTypeOf(__glintRef__.this).toEqualTypeOf(); + expectTypeOf(__glintRef__.args).toEqualTypeOf(); + }); + })(); + emitComponent(resolve(StatefulComponent)()); +} +{ + class YieldingComponent extends Component { + } + _c = YieldingComponent; + (() => { + templateForBackingValue(_c, function* (__glintRef__) { + // We can't directly assert on the type of e.g. `@values` here, as we don't + // have a name for it in scope: the type `T` is present on the class instance, + // but not in a `static` block. However, the yields below confirm that the + // `@values` arg, since the only information we have about that type is that + // the array element and the yielded value are the same. + yieldToBlock(__glintRef__, 'default')( + // @ts-expect-error: only a `T` is a valid yield + 123); + if (__glintRef__.args.values.length) { + yieldToBlock(__glintRef__, 'default')(__glintRef__.args.values[0]); + } + else { + yieldToBlock(__glintRef__, 'else')(); + } + }); + })(); + // @ts-expect-error: missing required arg + resolve(YieldingComponent)(); + resolve(YieldingComponent)({ + // @ts-expect-error: incorrect type for arg + values: 'hello', + ...NamedArgsMarker, + }); + resolve(YieldingComponent)({ + values: [1, 2, 3], + // @ts-expect-error: extra arg + oops: true, + ...NamedArgsMarker, + }); + expectTypeOf().toEqualTypeOf(); + { + const component = emitComponent(resolve(YieldingComponent)({ values: [1, 2, 3], ...NamedArgsMarker })); + { + const [value] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + } + } + { + const component = emitComponent(resolve(YieldingComponent)({ values: [1, 2, 3], ...NamedArgsMarker })); + { + const [...args] = component.blockParams.default; + expectTypeOf(args).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } + } +} +{ + class PositionalArgsComponent extends Component { + } + // @ts-expect-error: missing required positional arg + resolve(PositionalArgsComponent)({}); + resolve(PositionalArgsComponent)( + // @ts-expect-error: incorrect type for positional arg + 123); + resolve(PositionalArgsComponent)('a', 1, + // @ts-expect-error: extra positional arg + true); + resolve(PositionalArgsComponent)('a'); + resolve(PositionalArgsComponent)('a', 1); +} +// Components are `ComponentLike` +{ + class TestComponent extends Component { + } + expectTypeOf(TestComponent).toMatchTypeOf(); +} +//# sourceMappingURL=ember-component.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/ember-component.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/ember-component.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/ember-component.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts new file mode 100644 index 000000000..f82ecabbd --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=glimmer-component.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts.map new file mode 100644 index 000000000..454d596b3 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"glimmer-component.test.d.ts","sourceRoot":"","sources":["glimmer-component.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.js new file mode 100644 index 000000000..26c94273a --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.js @@ -0,0 +1,94 @@ +var _a, _b; +import Component from '@glimmer/component'; +import { templateForBackingValue, resolve, yieldToBlock, emitComponent, NamedArgsMarker, } from '@glint/environment-ember-loose/-private/dsl'; +import { expectTypeOf } from 'expect-type'; +{ + class NoArgsComponent extends Component { + } + resolve(NoArgsComponent)( + // @ts-expect-error: extra positional arg + 'oops'); + { + const component = emitComponent(resolve(NoArgsComponent)()); + { + // @ts-expect-error: never yields, so shouldn't accept blocks + component.blockParams.default; + } + } + emitComponent(resolve(NoArgsComponent)()); +} +{ + class StatefulComponent extends Component { + constructor() { + super(...arguments); + this.foo = 'hello'; + } + } + _a = StatefulComponent; + (() => { + templateForBackingValue(_a, function* (__glintRef__) { + expectTypeOf(__glintRef__.this.foo).toEqualTypeOf(); + expectTypeOf(__glintRef__.this).toEqualTypeOf(); + expectTypeOf(__glintRef__.args).toEqualTypeOf(); + }); + })(); + emitComponent(resolve(StatefulComponent)()); +} +{ + class YieldingComponent extends Component { + } + _b = YieldingComponent; + (() => { + templateForBackingValue(_b, function* (__glintRef__) { + // We can't directly assert on the type of e.g. `@values` here, as we don't + // have a name for it in scope: the type `T` is present on the class instance, + // but not in a `static` block. However, the yields below confirm that the + // `@values` arg, since the only information we have about that type is that + // the array element and the yielded value are the same. + yieldToBlock(__glintRef__, 'default')( + // @ts-expect-error: only a `T` is a valid yield + 123); + if (__glintRef__.args.values.length) { + yieldToBlock(__glintRef__, 'default')(__glintRef__.args.values[0]); + } + else { + yieldToBlock(__glintRef__, 'else')(); + } + }); + })(); + // @ts-expect-error: missing required arg `values` + resolve(YieldingComponent)({ ...NamedArgsMarker }); + // @ts-expect-error: incorrect type for arg + resolve(YieldingComponent)({ values: 'hello', ...NamedArgsMarker }); + resolve(YieldingComponent)({ + values: [1, 2, 3], + // @ts-expect-error: extra arg + oops: true, + ...NamedArgsMarker, + }); + { + const component = emitComponent(resolve(YieldingComponent)({ values: [1, 2, 3], ...NamedArgsMarker })); + { + const [value] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + } + } + { + const component = emitComponent(resolve(YieldingComponent)({ values: [1, 2, 3], ...NamedArgsMarker })); + { + const [...args] = component.blockParams.default; + expectTypeOf(args).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } + } +} +// Components are `ComponentLike` +{ + class TestComponent extends Component { + } + expectTypeOf(TestComponent).toMatchTypeOf(); +} +//# sourceMappingURL=glimmer-component.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/glimmer-component.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/glimmer-component.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/glimmer-component.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts new file mode 100644 index 000000000..fed3d8437 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=helper.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts.map new file mode 100644 index 000000000..18125fa48 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"helper.test.d.ts","sourceRoot":"","sources":["helper.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.js new file mode 100644 index 000000000..6e3bd3933 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.js @@ -0,0 +1,191 @@ +import Helper, { helper } from '@ember/component/helper'; +import { resolve, NamedArgsMarker } from '@glint/environment-ember-loose/-private/dsl'; +import { expectTypeOf } from 'expect-type'; +// Functional helper: fixed signature params +{ + let definition = helper(([name], { age }) => `${name}: ${age}`); + let info = resolve(definition); + expectTypeOf(info).toEqualTypeOf(); + info( + // @ts-expect-error: missing named arg + {}, 'Tom'); + info('Tom', { + age: 123, + // @ts-expect-error: extra named arg + hello: true, + ...NamedArgsMarker, + }); + // @ts-expect-error: missing positional arg + info({ age: 123, ...NamedArgsMarker }); + info('Tom', 'Ster', + // @ts-expect-error: extra positional arg + { age: 123, ...NamedArgsMarker }); + expectTypeOf(info('Tom', { age: 123, ...NamedArgsMarker })).toEqualTypeOf(); +} +// Functional helper: generic positional params +{ + let definition = helper(([a, b]) => a || b); + let or = resolve(definition); + // Using `toMatch` rather than `toEqual` because helper resolution (currently) + // uses a special `EmptyObject` type to represent empty named args. + expectTypeOf(or).toMatchTypeOf(); + or('a', 'b', { + // @ts-expect-error: extra named arg + hello: true, + ...NamedArgsMarker, + }); + // This is perhaps unexpected, but this will typecheck with the named args acting + // as the second positional argument. + expectTypeOf(or('a', { foo: 'hi', ...NamedArgsMarker })).toEqualTypeOf(); + or('a', 'b', + // @ts-expect-error: extra positional arg + 'c'); + expectTypeOf(or('a', 'b')).toEqualTypeOf(); + expectTypeOf(or('a', true)).toEqualTypeOf(); + expectTypeOf(or(false, true)).toEqualTypeOf(); +} +// Functional helper: generic named params +{ + let definition = helper((_, { value, count }) => { + return Array.from({ length: count ?? 2 }, () => value); + }); + let repeat = resolve(definition); + expectTypeOf(repeat).toEqualTypeOf(); + // @ts-expect-error: extra positional arg + repeat(123, { word: 'hi', ...NamedArgsMarker }); + // @ts-expect-error: missing required named arg + repeat({ count: 3, ...NamedArgsMarker }); + repeat({ + // @ts-expect-error: extra named arg + word: 'hello', + foo: true, + ...NamedArgsMarker, + }); + expectTypeOf(repeat({ value: 'hi', ...NamedArgsMarker })).toEqualTypeOf(); + expectTypeOf(repeat({ value: 123, count: 3, ...NamedArgsMarker })).toEqualTypeOf(); +} +// Class-based helper: named args +{ + class RepeatHelper extends Helper { + compute(_, { value, count }) { + return Array.from({ length: count ?? 2 }, () => value); + } + } + let repeat = resolve(RepeatHelper); + expectTypeOf(repeat).toEqualTypeOf(); + repeat(123, + // @ts-expect-error: extra positional arg + { word: 'hi', ...NamedArgsMarker }); + // @ts-expect-error: missing required named arg + repeat({ count: 3, ...NamedArgsMarker }); + repeat({ + value: 'hello', + // @ts-expect-error: extra named arg + foo: true, + ...NamedArgsMarker, + }); + expectTypeOf(repeat({ value: 'hi', ...NamedArgsMarker })).toEqualTypeOf(); + expectTypeOf(repeat({ value: 123, count: 3, ...NamedArgsMarker })).toEqualTypeOf(); +} +// Class-based helper: positional args +{ + class RepeatHelper extends Helper { + compute([value, count]) { + return Array.from({ length: count ?? 2 }, () => value); + } + } + let repeat = resolve(RepeatHelper); + expectTypeOf(repeat).toEqualTypeOf(); + repeat('hello', + // @ts-expect-error: unexpected named args + { word: 'hi', ...NamedArgsMarker }); + repeat('hello', 123, + // @ts-expect-error: extra positional arg in named args spot + 'hi'); + expectTypeOf(repeat('hi')).toEqualTypeOf(); + expectTypeOf(repeat(123, 3)).toEqualTypeOf(); +} +// Class-based helpers can return undefined +{ + class MaybeStringHelper extends Helper { + compute() { + if (Math.random() > 0.5) { + return 'ok'; + } + } + } + let maybeString = resolve(MaybeStringHelper); + expectTypeOf(maybeString).toEqualTypeOf(); +} +// Helpers are `HelperLike` +{ + class MyHelper extends Helper { + } + const myHelper = helper(() => []); + expectTypeOf(MyHelper).toMatchTypeOf(); + expectTypeOf(myHelper).toMatchTypeOf(); +} +// Bare-function helpers +{ + let positionalOnlyConcrete = resolve((a, b) => a + b); + expectTypeOf(positionalOnlyConcrete).toEqualTypeOf(); + expectTypeOf(positionalOnlyConcrete(1, 2)).toBeNumber(); + let positionalOnlyGeneric = resolve((a, b) => [a, b]); + expectTypeOf(positionalOnlyGeneric).toEqualTypeOf(); + expectTypeOf(positionalOnlyGeneric('hi', true)).toEqualTypeOf(); + expectTypeOf(positionalOnlyGeneric(123, Symbol())).toEqualTypeOf(); + let mixedConcrete = resolve((a, b, named) => named.fallback); + expectTypeOf(mixedConcrete).toEqualTypeOf(); + expectTypeOf(mixedConcrete(1, 2, { fallback: 123 })).toBeNumber(); + let mixedGenericNamed = resolve((a, b, named) => a + b || named.fallback); + expectTypeOf(mixedGenericNamed).toEqualTypeOf(); + expectTypeOf(mixedGenericNamed(1, 2, { fallback: 'hi' })).toEqualTypeOf(); + expectTypeOf(mixedGenericNamed(1, 2, { fallback: 3 })).toBeNumber(); + let mixedGenericPositional = resolve((a, b, named) => a || b || named.fallback); + expectTypeOf(mixedGenericPositional).toEqualTypeOf(); + expectTypeOf(mixedGenericPositional('a', 'b', { fallback: 'hi' })).toBeString(); + expectTypeOf(mixedGenericPositional(1, 2, { fallback: 'hi' })).toEqualTypeOf(); + mixedGenericPositional('a', + // @ts-expect-error: inconsistent T + 123, { fallback: 'hi' }); + let mixedGeneric = resolve((a, b, named) => [a, b, named.c]); + expectTypeOf(mixedGeneric).toEqualTypeOf(); + expectTypeOf(mixedGeneric(123, false, { c: 'hi' })).toEqualTypeOf(); + let namedOnlyConcrete = resolve((named) => named.name); + expectTypeOf(namedOnlyConcrete).toEqualTypeOf(); + expectTypeOf(namedOnlyConcrete({ age: 100, name: 'Alex' })).toBeString(); + let namedOnlyGeneric = resolve((named) => [named.t, named.u]); + expectTypeOf(namedOnlyGeneric).toEqualTypeOf(); + expectTypeOf(namedOnlyGeneric({ t: 'hi', u: 123 })).toEqualTypeOf(); + let optionalNamed = resolve((a, named) => [a, named?.cool]); + expectTypeOf(optionalNamed).toEqualTypeOf(); + expectTypeOf(optionalNamed(123)).toEqualTypeOf(); + expectTypeOf(optionalNamed(123, { cool: true, ...NamedArgsMarker })).toEqualTypeOf(); + let optionalBoth = resolve((a, b, named) => [ + a, + b, + named?.foo, + ]); + expectTypeOf(optionalBoth).toEqualTypeOf(); + expectTypeOf(optionalBoth('hi')).toEqualTypeOf(); + expectTypeOf(optionalBoth('hi', 123)).toEqualTypeOf(); + expectTypeOf(optionalBoth('hi', undefined, { foo: true, ...NamedArgsMarker })).toEqualTypeOf(); + expectTypeOf(optionalBoth('hi', 123, { foo: true, ...NamedArgsMarker })).toEqualTypeOf(); + let namedArgsInterface = resolve((pos, options) => { + console.log(pos, options); + }); + expectTypeOf(namedArgsInterface).toEqualTypeOf(); + let namedArgsType = resolve((pos, named) => { + console.log(pos, named); + }); + expectTypeOf(namedArgsType).toEqualTypeOf(); + let narrowsFirstArg = resolve((arg, key) => !!key); + expectTypeOf(narrowsFirstArg).toEqualTypeOf(); + let narrowsFirstArgTestValue; + if (narrowsFirstArg(narrowsFirstArgTestValue, 'key')) { + expectTypeOf(narrowsFirstArgTestValue.key).toBeNumber(); + } + let allOptional = resolve((a, b) => `${a}${b?.foo}`); + expectTypeOf(allOptional).toEqualTypeOf(); +} +//# sourceMappingURL=helper.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/helper.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/helper.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/helper.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts new file mode 100644 index 000000000..06a3170fa --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=action.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts.map new file mode 100644 index 000000000..ea06fa108 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"action.test.d.ts","sourceRoot":"","sources":["action.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.js new file mode 100644 index 000000000..6d257083d --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.js @@ -0,0 +1,15 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, NamedArgsMarker, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let action = resolve(Globals['action']); +// Basic plumbing +expectTypeOf(action(() => 'hi')).toEqualTypeOf(); +expectTypeOf(action((value) => value)).toEqualTypeOf(); +// Binding parameters +expectTypeOf(action((x, y) => x.padStart(y), 'hello')).toEqualTypeOf(); +expectTypeOf(action((x, y) => x.padStart(y), 'hello', 123)).toEqualTypeOf(); +expectTypeOf(action((value) => value, 'hello')).toEqualTypeOf(); +// @ts-expect-error: invalid parameter type +action((x) => x, 123); +// Extracting a value from a particular key +expectTypeOf(action(() => 'hello', { value: 'length', ...NamedArgsMarker })).toEqualTypeOf(); +//# sourceMappingURL=action.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/action.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/action.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/action.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts new file mode 100644 index 000000000..0706724ef --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=component.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts.map new file mode 100644 index 000000000..2dbcda0b6 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"component.test.d.ts","sourceRoot":"","sources":["component.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.js new file mode 100644 index 000000000..fde21742c --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.js @@ -0,0 +1,132 @@ +import Component from '@ember/component'; +import { hbs } from 'ember-cli-htmlbars'; +import { typeTest } from '@glint/type-test'; +// String-based lookups +typeTest({}, hbs ` + {{#let (component 'input') as |BoundInput|}} + + + {{! @glint-expect-error: wrong arg type}} + + {{/let}} + `); +// String-based lookups of special builtins +typeTest({}, hbs ` + {{#let (component 'link-to' route="widgets") as |Link|}} + + {{/let}} + `); +class StringComponent extends Component { +} +// Simple no-op binding +typeTest({ StringComponent, formModifier }, hbs ` + {{#let (component this.StringComponent) as |NoopCurriedStringComponent|}} + + + {{! @glint-expect-error: missing required arg }} + + + + {{@expectTypeOf value @to.beString}} + + {{/let}} + `); +// Nullable in, nullable out +typeTest({ StringComponent: StringComponent }, hbs ` + {{#let (component this.StringComponent) as |NoopCurriedStringComponent|}} + + + {{@expectTypeOf null @to.beAssignableToTypeOf NoopCurriedStringComponent}} + {{/let}} + `); +// Currying a named arg makes it optional but still override-able +typeTest({ + StringComponent, + formModifier, + expectedType: {}, +}, hbs ` + {{#let (component this.StringComponent value="hello") as |BoundStringComponent|}} + + + + {{@expectTypeOf BoundStringComponent @to.equalTypeOf this.expectedType}} + + + {{@expectTypeOf value @to.beString}} + + {{/let}} + `); +class ParametricComponent extends Component { +} +// Simple no-op binding +typeTest({ ParametricComponent, formModifier }, hbs ` + {{#let (component this.ParametricComponent) as |NoopCurriedParametricComponent|}} + + + {{! @glint-expect-error: missing required arg }} + + + + + + {{@expectTypeOf value @to.beString}} + {{@expectTypeOf index @to.beNumber}} + + + + {{@expectTypeOf value @to.beBoolean}} + {{@expectTypeOf index @to.beNumber}} + + {{/let}} + `); +// Binding a required arg makes it optional +typeTest({ ParametricComponent, formModifier }, hbs ` + {{#let (component this.ParametricComponent values=(array "hi")) as |RequiredValueCurriedParametricComponent|}} + + + + + {{! @glint-expect-error: wrong type for what we pre-bound above }} + + + + + + {{@expectTypeOf value @to.beString}} + {{@expectTypeOf index @to.beNumber}} + + {{/let}} + `); +// Binding an optional arg still leaves the required one(s) +typeTest({ ParametricComponent, formModifier }, hbs ` + {{#let (component this.ParametricComponent optional="hi") as |OptionalValueCurriedParametricComponent|}} + + + {{! @glint-expect-error: missing required arg }} + + + + + + {{@expectTypeOf value @to.beString}} + {{@expectTypeOf index @to.beNumber}} + + + + + {{@expectTypeOf value @to.beBoolean}} + {{@expectTypeOf index @to.beNumber}} + + {{/let}} + `); +//# sourceMappingURL=component.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/component.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/component.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/component.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts new file mode 100644 index 000000000..5095af3da --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=concat.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts.map new file mode 100644 index 000000000..8ac083b62 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"concat.test.d.ts","sourceRoot":"","sources":["concat.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.js new file mode 100644 index 000000000..f9bf9b532 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.js @@ -0,0 +1,7 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let concat = resolve(Globals['concat']); +// Basic plumbing +expectTypeOf(concat()).toEqualTypeOf(); +expectTypeOf(concat(1, true, 'three')).toEqualTypeOf(); +//# sourceMappingURL=concat.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/concat.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts new file mode 100644 index 000000000..15cdbc47c --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=each-in.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts.map new file mode 100644 index 000000000..084b8754f --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"each-in.test.d.ts","sourceRoot":"","sources":["each-in.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.js new file mode 100644 index 000000000..4f1d6dc46 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.js @@ -0,0 +1,123 @@ +import { expectTypeOf } from 'expect-type'; +import { emitComponent, Globals, NamedArgsMarker, resolve, } from '@glint/environment-ember-loose/-private/dsl'; +let eachIn = resolve(Globals['each-in']); +{ + const component = emitComponent(eachIn({ a: 5, b: 3 })); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } +} +// Only gives string keys +{ + const b = Symbol('b'); + const value = { a: 'hi', [b]: 123 }; + const component = emitComponent(eachIn(value)); + { + const [key, value] = component.blockParams.default; + // {{each-in}} internally uses `Object.keys`, so only string keys are included + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } +} +{ + const component = emitComponent(eachIn(maybeVal)); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +{ + const component = emitComponent(eachIn(maybeMapVal)); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +// Can render else when undefined, null, or empty. +{ + const component = emitComponent(eachIn(undefined)); + { + const [key, value] = component.blockParams.default; + // This won't get called when no value, but gets default key type + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +{ + const component = emitComponent(eachIn(null)); + { + const [key, value] = component.blockParams.default; + // This won't get called when no value, but gets default key type + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +{ + const component = emitComponent(eachIn({})); + { + const [key, value] = component.blockParams.default; + // This won't get called when no value + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +// Accept a `key` string +{ + const component = emitComponent(eachIn({ a: 5, b: 3 }, { key: 'id', ...NamedArgsMarker })); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } +} +// Accepts a Map +{ + const component = emitComponent(eachIn(new Map([ + ['a', 5], + ['b', 4], + ]), { key: 'id', ...NamedArgsMarker })); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } +} +// Accepts a custom iterable +{ + class CustomMap { + [Symbol.iterator]() { + throw new Error(); + } + } + const component = emitComponent(eachIn(new CustomMap(), { key: 'id', ...NamedArgsMarker })); + { + const [key, value] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + } +} +//# sourceMappingURL=each-in.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each-in.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts new file mode 100644 index 000000000..a82e93c96 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=each.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts.map new file mode 100644 index 000000000..defcea23b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"each.test.d.ts","sourceRoot":"","sources":["each.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.js new file mode 100644 index 000000000..01a118fdb --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.js @@ -0,0 +1,83 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, resolve, emitComponent, NamedArgsMarker, } from '@glint/environment-ember-loose/-private/dsl'; +let each = resolve(Globals['each']); +// Yield out array values and indices +{ + const component = emitComponent(each(['a', 'b', 'c'])); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } + { + const [...args] = component.blockParams.else; + expectTypeOf(args).toEqualTypeOf(); + } +} +{ + const component = emitComponent(each(proxiedArray)); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Works for other iterables +{ + const component = emitComponent(each(new Map())); + { + const [[key, value], index] = component.blockParams.default; + expectTypeOf(key).toEqualTypeOf(); + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Works for `readonly` arrays +{ + const component = emitComponent(each(['a', 'b', 'c'])); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Accept a `key` string +{ + const component = emitComponent(each([{ id: 1 }], { key: 'id', ...NamedArgsMarker })); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Works for undefined +{ + const component = emitComponent(each(arrayOrUndefined)); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Works for null +{ + const component = emitComponent(each(arrayOrNull)); + { + const [value, index] = component.blockParams.default; + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(index).toEqualTypeOf(); + } +} +// Gives `any` given `any` +{ + const component = emitComponent(each({})); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +// Gives `any` given an invalid iterable (avoiding a cascade of type errors) +{ + const component = emitComponent(each( + // @ts-expect-error: number is not a valid iterable + 123)); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +//# sourceMappingURL=each.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/each.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/each.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/each.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts new file mode 100644 index 000000000..41a658262 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=fn.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts.map new file mode 100644 index 000000000..43a809764 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"fn.test.d.ts","sourceRoot":"","sources":["fn.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.js new file mode 100644 index 000000000..cf9bc18b3 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.js @@ -0,0 +1,14 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let fn = resolve(Globals['fn']); +// @ts-expect-error: invalid arg +fn((t) => t, 123); +expectTypeOf(fn(() => true)).toEqualTypeOf(); +expectTypeOf(fn((arg) => arg.length)).toEqualTypeOf(); +expectTypeOf(fn((arg) => arg.length, 'hi')).toEqualTypeOf(); +let identity = (x) => x; +// Bound type parameters are reflected in the output +expectTypeOf(fn(identity, 'hi')).toEqualTypeOf(); +// Unbound type parameters survive to the output +expectTypeOf(fn(identity)).toEqualTypeOf(); +//# sourceMappingURL=fn.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/fn.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts new file mode 100644 index 000000000..4e08af3ac --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=get.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts.map new file mode 100644 index 000000000..48bf32ab1 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"get.test.d.ts","sourceRoot":"","sources":["get.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.js new file mode 100644 index 000000000..62730db54 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.js @@ -0,0 +1,23 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, NamedArgsMarker, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let get = resolve(Globals['get']); +// Getting a known key +expectTypeOf(get({ foo: 'hello' }, 'foo')).toEqualTypeOf(); +// Getting an unknown key +expectTypeOf(get({ foo: 'hello' }, 'baz')).toEqualTypeOf(); +get({}, 'hi', +// @ts-expect-error: invalid named arg +{ hello: 'hi', ...NamedArgsMarker }); +expectTypeOf(get(maybeFoo, 'bar')).toEqualTypeOf(); +expectTypeOf(get(mandatoryFoo, 'bar')).toEqualTypeOf(); +expectTypeOf(get(maybeString, 'length')).toEqualTypeOf(); +expectTypeOf(get(mandatoryString, 'length')).toEqualTypeOf(); +expectTypeOf(get(null, 'name')).toEqualTypeOf(); +expectTypeOf(get(undefined, 'name')).toEqualTypeOf(); +expectTypeOf(get(proxiedObject, 'content')).toEqualTypeOf(); +expectTypeOf(get(proxiedObject, 'name')).toEqualTypeOf(); +expectTypeOf(get(proxiedObject, 'unknownKey')).toEqualTypeOf(); +expectTypeOf(get(optionalProxiedObject, 'name')).toEqualTypeOf(); +expectTypeOf(get(nullProxiedObject, 'name')).toEqualTypeOf(); +expectTypeOf(get(emberArray, 'length')).toEqualTypeOf(); +//# sourceMappingURL=get.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/get.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/get.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/get.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts new file mode 100644 index 000000000..fed3d8437 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=helper.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts.map new file mode 100644 index 000000000..18125fa48 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"helper.test.d.ts","sourceRoot":"","sources":["helper.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.js new file mode 100644 index 000000000..49bebefdd --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.js @@ -0,0 +1,111 @@ +import Helper from '@ember/component/helper'; +import { hbs } from 'ember-cli-htmlbars'; +import { typeTest } from '@glint/type-test'; +class GreetHelper extends Helper { +} +// Simple no-op binding +typeTest({ greet: GreetHelper }, hbs ` + {{#let (helper this.greet) as |noopGreet|}} + {{@expectTypeOf (noopGreet "Hello" target="World") @to.beString}} + + {{! @glint-expect-error: missing positional arg }} + {{noopGreet target="World"}} + + {{! @glint-expect-error: missing positional arg }} + {{noopGreet "Hello"}} + {{/let}} + `); +// Currying a positional arg +typeTest({ greet: GreetHelper }, hbs ` + {{#let (helper this.greet "Hello") as |boundGreet|}} + {{boundGreet target="World"}} + + {{! @glint-expect-error: the positional arg is already curried }} + {{boundGreet "Hello" target="World"}} + + {{! @glint-expect-error: missing required named arg}} + {{boundGreet}} + {{/let}} + `); +// Currying a named arg +typeTest({ greet: GreetHelper }, hbs ` + {{#let (helper this.greet target="World") as |boundGreet|}} + {{boundGreet "Hello"}} + + {{boundGreet "Hello" target="World"}} + + {{! @glint-expect-error: missing required positional arg}} + {{boundGreet target="World"}} + {{/let}} + `); +// Double-currying +typeTest({ greet: GreetHelper }, hbs ` + {{#let (helper (helper this.greet "Hello") target="World") as |posThenNamed|}} + {{#let (helper (helper this.greet target="World") "Hello") as |namedThenPos|}} + {{@expectTypeOf posThenNamed @to.equalTypeOf namedThenPos}} + {{/let}} + {{/let}} + `); +class MakeArrayPositional extends Helper { +} +// No-op currying +typeTest({ makeArray: MakeArrayPositional }, hbs ` + {{#let (helper this.makeArray) as |noopMakeArray|}} + {{@expectTypeOf (noopMakeArray "hi") @to.equalTypeOf (array "ok")}} + {{@expectTypeOf (noopMakeArray (array "hi")) @to.equalTypeOf (array "ok")}} + + {{@expectTypeOf (noopMakeArray 12) @to.equalTypeOf (array 1)}} + {{@expectTypeOf (noopMakeArray (array 12)) @to.equalTypeOf (array 1)}} + + {{! @glint-expect-error: missing required arg }} + {{log (noopMakeArray)}} + {{/let}} + `); +// Currying positional generic args MUST pre-fix the type parameter, +// otherwise TypeScript can't tell whether the generic might actually +// represent named args. +typeTest({ makeArray: (MakeArrayPositional) }, hbs ` + {{#let (helper this.makeArray 123) as |makeNumberArray|}} + {{@expectTypeOf (makeNumberArray) @to.equalTypeOf (array 123)}} + {{/let}} + `); +class MakeArrayNamed extends Helper { +} +// No-op currying +typeTest({ makeArray: MakeArrayNamed }, hbs ` + {{#let (helper this.makeArray) as |noopMakeArray|}} + {{@expectTypeOf (noopMakeArray value="hi") @to.equalTypeOf (array "ok")}} + {{@expectTypeOf (noopMakeArray value=(array "hi")) @to.equalTypeOf (array "ok")}} + + {{@expectTypeOf (noopMakeArray value=12) @to.equalTypeOf (array 1)}} + {{@expectTypeOf (noopMakeArray value=(array 12)) @to.equalTypeOf (array 1)}} + + {{! @glint-expect-error: missing required arg }} + {{log (noopMakeArray)}} + {{/let}} + `); +// Currying named generic args doesn't require pre-specifying the type +typeTest({ makeArray: MakeArrayNamed }, hbs ` + {{#let (helper this.makeArray value=123) as |makeNumberArray|}} + {{@expectTypeOf (makeNumberArray) @to.equalTypeOf (array 123)}} + {{/let}} + `); +// Prebinding args at different locations +typeTest({ + myriad: class MyriadPositionals extends Helper { + }, +}, hbs ` + {{this.myriad "one" true 3}} + + {{(helper this.myriad "one" true 3)}} + {{(helper this.myriad "one" true) 3}} + {{(helper this.myriad "one") true 3}} + {{(helper this.myriad) "one" true 3}} + + {{! @glint-expect-error: missing arg }} + {{(helper this.myriad "one" true)}} + + {{! @glint-expect-error: extra arg }} + {{(helper this.myriad "one" true 3) "four"}} + `); +//# sourceMappingURL=helper.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/helper.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts new file mode 100644 index 000000000..f6118e429 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=input.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts.map new file mode 100644 index 000000000..70a97bb24 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"input.test.d.ts","sourceRoot":"","sources":["input.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.js new file mode 100644 index 000000000..0ccb57037 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.js @@ -0,0 +1,59 @@ +import { expectTypeOf } from 'expect-type'; +import { applySplattributes, emitComponent, Globals, NamedArgsMarker, resolve, } from '@glint/environment-ember-loose/-private/dsl'; +let input = resolve(Globals['input']); +let Input = resolve(Globals['Input']); +// Both casings have the same signature +expectTypeOf(input).toEqualTypeOf(Input); +Input(); +Input({ value: 'hello', ...NamedArgsMarker }); +Input({ type: 'text', value: 'hello', ...NamedArgsMarker }); +Input({ type: 'text', value: undefined, ...NamedArgsMarker }); +Input({ type: 'text', value: null, ...NamedArgsMarker }); +Input({ type: 'checkbox', checked: true, ...NamedArgsMarker }); +// NOTE: We allow all string types but, if it becomes easily possible, we should limit to valid HTMLInput types and disallow empty strings. +Input({ type: '', value: 'hello', ...NamedArgsMarker }); +Input({ type: 'string', value: 'hello', ...NamedArgsMarker }); +// Ensure we can apply -specific attributes +{ + const __glintY__ = emitComponent(Input()); + applySplattributes(new HTMLInputElement(), __glintY__.element); +} +// @ts-expect-error: `checked` only works with `@type=checkbox` +Input({ type: 'text', checked: true, ...NamedArgsMarker }); +// Event handlers +Input({ + enter: (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'insert-newline': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'escape-press': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'focus-in': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'focus-out': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'key-down': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'key-press': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + 'key-up': (value, event) => { + expectTypeOf(value).toEqualTypeOf(); + expectTypeOf(event).toEqualTypeOf(); + }, + ...NamedArgsMarker, +}); +//# sourceMappingURL=input.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/input.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/input.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/input.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts new file mode 100644 index 000000000..267229a0b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=link-to.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts.map new file mode 100644 index 000000000..ed6cbe3ab --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"link-to.test.d.ts","sourceRoot":"","sources":["link-to.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.js new file mode 100644 index 000000000..129be3d2b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.js @@ -0,0 +1,87 @@ +import { Globals, resolve, applySplattributes, emitComponent, NamedArgsMarker, } from '@glint/environment-ember-loose/-private/dsl'; +import { expectTypeOf } from 'expect-type'; +let linkTo = resolve(Globals['link-to']); +let LinkTo = resolve(Globals['LinkTo']); +emitComponent(linkTo('index', 123)); +// @ts-expect-error: bad type for route name +linkTo({}, 123); +// {{#link-to}} +{ + const component = emitComponent(linkTo('index')); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(linkTo('index')); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(linkTo('index', { query: { a: 123 }, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(linkTo('index', { models: [123, 'abc'], ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(linkTo('index', { 'current-when': 'index', ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(linkTo('index', { 'current-when': true, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + // Ensure it's also usable with only named args like `` + emitComponent(linkTo({ route: 'index', ...NamedArgsMarker })); + emitComponent(linkTo({ model: {}, ...NamedArgsMarker })); + emitComponent(linkTo({ route: 'index', model: {}, ...NamedArgsMarker })); + // @ts-expect-error: requires at least one arg, either named or positional + linkTo(); +} +// +{ + const component = emitComponent(LinkTo({ route: 'index', model: 123, ...NamedArgsMarker })); + expectTypeOf(component.element).toEqualTypeOf(); + applySplattributes(new HTMLAnchorElement(), component.element); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ route: 'index', ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ route: 'index', query: { a: 123 }, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ route: 'index', models: [123, 'abc'], ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ route: 'index', 'current-when': 'index', ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ route: 'index', 'current-when': true, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +// Requires at least one of `@route`, `@model`, `@models` or `@query` +{ + const component = emitComponent(LinkTo( + // @ts-expect-error: missing one of required props + { ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ model: 123, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ models: [123], ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +{ + const component = emitComponent(LinkTo({ query: { a: 123 }, ...NamedArgsMarker })); + expectTypeOf(component.blockParams.default).toEqualTypeOf(); +} +//# sourceMappingURL=link-to.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/link-to.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts new file mode 100644 index 000000000..88a88e40f --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=log.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts.map new file mode 100644 index 000000000..05f8692e8 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"log.test.d.ts","sourceRoot":"","sources":["log.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.js new file mode 100644 index 000000000..5ef9179ec --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.js @@ -0,0 +1,4 @@ +import { Globals, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let log = resolve(Globals['log']); +log('hello', 'world'); +//# sourceMappingURL=log.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/log.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/log.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/log.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts new file mode 100644 index 000000000..6412f2c82 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=modifier.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts.map new file mode 100644 index 000000000..a3176f7bd --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"modifier.test.d.ts","sourceRoot":"","sources":["modifier.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.js new file mode 100644 index 000000000..4984944f1 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.js @@ -0,0 +1,73 @@ +import Modifier from 'ember-modifier'; +import { hbs } from 'ember-cli-htmlbars'; +import { typeTest } from '@glint/type-test'; +class Render3DModelModifier extends Modifier { +} +// Simple no-op binding +typeTest({ renderModel: Render3DModelModifier }, hbs ` + {{#let (modifier this.renderModel) as |noopRender|}} + + + {{! @glint-expect-error: wrong element type }} +
+ + {{! @glint-expect-error: missing positional }} + + + {{! @glint-expect-error: extra named arg }} + + + {{! @glint-expect-error: extra positional arg }} + + {{/let}} + `); +// Pre-bound positional arg +typeTest({ renderModel: Render3DModelModifier }, hbs ` + {{#let (modifier this.renderModel (array)) as |boundRender|}} + + + {{! @glint-expect-error: wrong element type }} +
+ + {{! @glint-expect-error: extra named arg }} + + + {{! @glint-expect-error: extra positional arg }} + + {{/let}} + `); +// Pre-bound named arg +typeTest({ renderModel: Render3DModelModifier }, hbs ` + {{#let (modifier this.renderModel origin=(hash x=0 y=0)) as |boundRender|}} + + + + {{! @glint-expect-error: wrong element type }} +
+ + {{! @glint-expect-error: extra named arg }} + + + {{! @glint-expect-error: extra positional arg }} + + {{/let}} + `); +// Prebinding args at different locations +typeTest({ + myriad: class MyriadPositionals extends Modifier { + }, +}, hbs ` +
+ +
+
+
+
+ + {{! @glint-expect-error: missing arg }} +
+ + {{! @glint-expect-error: extra arg }} +
+ `); +//# sourceMappingURL=modifier.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/modifier.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts new file mode 100644 index 000000000..4ada65fb6 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=mount.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts.map new file mode 100644 index 000000000..5b6fc5041 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mount.test.d.ts","sourceRoot":"","sources":["mount.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.js new file mode 100644 index 000000000..d625f64a9 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.js @@ -0,0 +1,11 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, NamedArgsMarker, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let mount = resolve(Globals['mount']); +// Basic plumbing +expectTypeOf(mount('engine-name')).toEqualTypeOf(); +expectTypeOf(mount('engine-name', { model: {}, ...NamedArgsMarker })); +// @ts-expect-error: missing engine name +mount(); +// @ts-expect-error: invalid named arg +mount('engine-name', { hello: 'hi', ...NamedArgsMarker }); +//# sourceMappingURL=mount.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mount.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts new file mode 100644 index 000000000..2cee111e0 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=mut.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts.map new file mode 100644 index 000000000..f5850a75c --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mut.test.d.ts","sourceRoot":"","sources":["mut.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.js new file mode 100644 index 000000000..713e2e42b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.js @@ -0,0 +1,16 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, NamedArgsMarker, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let fn = resolve(Globals['fn']); +let mut = resolve(Globals['mut']); +// Basic plumbing +expectTypeOf(mut('hello')).toEqualTypeOf(); +// `{{fn (mut this.value)}}` returns an updater +expectTypeOf(fn(mut('hello'))).toEqualTypeOf(); +// @ts-expect-error: missing value +mut(); +// @ts-expect-error: unexpected named args +mut('hello', { + hello: 'hi', + ...NamedArgsMarker, +}); +//# sourceMappingURL=mut.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/mut.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts new file mode 100644 index 000000000..58cc9fd6d --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=on.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts.map new file mode 100644 index 000000000..cc46e146b --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"on.test.d.ts","sourceRoot":"","sources":["on.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.js new file mode 100644 index 000000000..3544d387e --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.js @@ -0,0 +1,27 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, applyModifier, resolve, NamedArgsMarker, } from '@glint/environment-ember-loose/-private/dsl'; +const on = resolve(Globals['on']); +const el = document.createElement('div'); +on(el, 'click', () => { }, { + // @ts-expect-error: extra named arg + foo: 'bar', + ...NamedArgsMarker, +}); +// @ts-expect-error: missing positional arg +on(el, 'click'); +// @ts-expect-error: extra positional arg +on(el, 'click', () => { }, 'hello'); +on(el, 'scroll', () => { }, { capture: true, once: true, passive: true, ...NamedArgsMarker }); +on(el, 'unknown', (event) => { + expectTypeOf(event).toEqualTypeOf(); +}); +on(el, 'click', (event) => { + expectTypeOf(event).toEqualTypeOf(); +}); +on(el, 'keyup', (event) => { + expectTypeOf(event).toEqualTypeOf(); +}); +applyModifier(on(el, 'click', () => { })); +applyModifier(on(new SVGRectElement(), 'click', () => { })); +applyModifier(on(new Element(), 'click', () => { })); +//# sourceMappingURL=on.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/on.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/on.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/on.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts new file mode 100644 index 000000000..16d3a2906 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=outlet.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts.map new file mode 100644 index 000000000..ea91e9c2d --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"outlet.test.d.ts","sourceRoot":"","sources":["outlet.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.js new file mode 100644 index 000000000..45944f7d4 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.js @@ -0,0 +1,13 @@ +import { expectTypeOf } from 'expect-type'; +import { Globals, NamedArgsMarker, resolve } from '@glint/environment-ember-loose/-private/dsl'; +let outlet = resolve(Globals['outlet']); +// Named outlet +expectTypeOf(outlet('outlet-name')).toEqualTypeOf(); +// Nameless main outlet +outlet(); +// @ts-expect-error: unexpected named args +outlet('outlet-name', { + hello: 'hi', + ...NamedArgsMarker, +}); +//# sourceMappingURL=outlet.test.js.map \ No newline at end of file diff --git a/packages/environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.ts similarity index 100% rename from packages/environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.ts rename to test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/outlet.test.ts diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts new file mode 100644 index 000000000..05a438ca0 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=textarea.test.d.ts.map \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts.map b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts.map new file mode 100644 index 000000000..b7b767039 --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"textarea.test.d.ts","sourceRoot":"","sources":["textarea.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.js b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.js new file mode 100644 index 000000000..144e19c9c --- /dev/null +++ b/test-packages/types-environment-ember-loose/__tests__/type-tests/intrinsics/textarea.test.js @@ -0,0 +1,44 @@ +import { expectTypeOf } from 'expect-type'; +import { applySplattributes, emitComponent, Globals, NamedArgsMarker, resolve, } from '@glint/environment-ember-loose/-private/dsl'; +let textarea = resolve(Globals['textarea']); +let Textarea = resolve(Globals['Textarea']); +// Both casings have the same signature +expectTypeOf(textarea).toEqualTypeOf(Textarea); +Textarea(); +Textarea({ value: 'hello', ...NamedArgsMarker }); +Textarea({ value: undefined, ...NamedArgsMarker }); +Textarea({ value: null, ...NamedArgsMarker }); +// Ensure we can apply