@glint/ember-tsc 1.0.1-unstable.845d5fa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +46 -0
  2. package/bin/glint-language-server.js +2 -0
  3. package/bin/glint.js +4 -0
  4. package/lib/cli/run-volar-tsc.d.ts +2 -0
  5. package/lib/cli/run-volar-tsc.d.ts.map +1 -0
  6. package/lib/cli/run-volar-tsc.js +30 -0
  7. package/lib/cli/run-volar-tsc.js.map +1 -0
  8. package/lib/config/config.d.ts +15 -0
  9. package/lib/config/config.d.ts.map +1 -0
  10. package/lib/config/config.js +21 -0
  11. package/lib/config/config.js.map +1 -0
  12. package/lib/config/environment.d.ts +26 -0
  13. package/lib/config/environment.d.ts.map +1 -0
  14. package/lib/config/environment.js +96 -0
  15. package/lib/config/environment.js.map +1 -0
  16. package/lib/config/index.d.ts +17 -0
  17. package/lib/config/index.d.ts.map +1 -0
  18. package/lib/config/index.js +26 -0
  19. package/lib/config/index.js.map +1 -0
  20. package/lib/config/loader.d.ts +25 -0
  21. package/lib/config/loader.d.ts.map +1 -0
  22. package/lib/config/loader.js +110 -0
  23. package/lib/config/loader.js.map +1 -0
  24. package/lib/config/types.cjs +3 -0
  25. package/lib/config/types.cjs.map +1 -0
  26. package/lib/config/types.d.cts +60 -0
  27. package/lib/config/types.d.cts.map +1 -0
  28. package/lib/environment-ember-template-imports/-private/environment/common.d.ts +13 -0
  29. package/lib/environment-ember-template-imports/-private/environment/common.d.ts.map +1 -0
  30. package/lib/environment-ember-template-imports/-private/environment/common.js +2 -0
  31. package/lib/environment-ember-template-imports/-private/environment/common.js.map +1 -0
  32. package/lib/environment-ember-template-imports/-private/environment/index.d.ts +3 -0
  33. package/lib/environment-ember-template-imports/-private/environment/index.d.ts.map +1 -0
  34. package/lib/environment-ember-template-imports/-private/environment/index.js +76 -0
  35. package/lib/environment-ember-template-imports/-private/environment/index.js.map +1 -0
  36. package/lib/environment-ember-template-imports/-private/environment/preprocess.d.ts +4 -0
  37. package/lib/environment-ember-template-imports/-private/environment/preprocess.d.ts.map +1 -0
  38. package/lib/environment-ember-template-imports/-private/environment/preprocess.js +73 -0
  39. package/lib/environment-ember-template-imports/-private/environment/preprocess.js.map +1 -0
  40. package/lib/environment-ember-template-imports/-private/environment/transform.d.ts +4 -0
  41. package/lib/environment-ember-template-imports/-private/environment/transform.d.ts.map +1 -0
  42. package/lib/environment-ember-template-imports/-private/environment/transform.js +134 -0
  43. package/lib/environment-ember-template-imports/-private/environment/transform.js.map +1 -0
  44. package/lib/index.d.ts +7 -0
  45. package/lib/index.d.ts.map +1 -0
  46. package/lib/index.js +6 -0
  47. package/lib/index.js.map +1 -0
  48. package/lib/plugins/g-compiler-errors.d.ts +12 -0
  49. package/lib/plugins/g-compiler-errors.d.ts.map +1 -0
  50. package/lib/plugins/g-compiler-errors.js +58 -0
  51. package/lib/plugins/g-compiler-errors.js.map +1 -0
  52. package/lib/plugins/g-template-tag-symbols.d.ts +11 -0
  53. package/lib/plugins/g-template-tag-symbols.d.ts.map +1 -0
  54. package/lib/plugins/g-template-tag-symbols.js +48 -0
  55. package/lib/plugins/g-template-tag-symbols.js.map +1 -0
  56. package/lib/plugins/utils.d.ts +25 -0
  57. package/lib/plugins/utils.d.ts.map +1 -0
  58. package/lib/plugins/utils.js +63 -0
  59. package/lib/plugins/utils.js.map +1 -0
  60. package/lib/transform/diagnostics/augmentation.d.ts +4 -0
  61. package/lib/transform/diagnostics/augmentation.d.ts.map +1 -0
  62. package/lib/transform/diagnostics/augmentation.js +223 -0
  63. package/lib/transform/diagnostics/augmentation.js.map +1 -0
  64. package/lib/transform/diagnostics/index.d.ts +5 -0
  65. package/lib/transform/diagnostics/index.d.ts.map +1 -0
  66. package/lib/transform/diagnostics/index.js +2 -0
  67. package/lib/transform/diagnostics/index.js.map +1 -0
  68. package/lib/transform/index.d.ts +4 -0
  69. package/lib/transform/index.d.ts.map +1 -0
  70. package/lib/transform/index.js +2 -0
  71. package/lib/transform/index.js.map +1 -0
  72. package/lib/transform/template/code-features.d.ts +30 -0
  73. package/lib/transform/template/code-features.d.ts.map +1 -0
  74. package/lib/transform/template/code-features.js +26 -0
  75. package/lib/transform/template/code-features.js.map +1 -0
  76. package/lib/transform/template/glimmer-ast-mapping-tree.d.ts +80 -0
  77. package/lib/transform/template/glimmer-ast-mapping-tree.d.ts.map +1 -0
  78. package/lib/transform/template/glimmer-ast-mapping-tree.js +132 -0
  79. package/lib/transform/template/glimmer-ast-mapping-tree.js.map +1 -0
  80. package/lib/transform/template/inlining/index.d.ts +16 -0
  81. package/lib/transform/template/inlining/index.d.ts.map +1 -0
  82. package/lib/transform/template/inlining/index.js +21 -0
  83. package/lib/transform/template/inlining/index.js.map +1 -0
  84. package/lib/transform/template/inlining/tagged-strings.d.ts +8 -0
  85. package/lib/transform/template/inlining/tagged-strings.d.ts.map +1 -0
  86. package/lib/transform/template/inlining/tagged-strings.js +140 -0
  87. package/lib/transform/template/inlining/tagged-strings.js.map +1 -0
  88. package/lib/transform/template/map-template-contents.d.ts +121 -0
  89. package/lib/transform/template/map-template-contents.d.ts.map +1 -0
  90. package/lib/transform/template/map-template-contents.js +287 -0
  91. package/lib/transform/template/map-template-contents.js.map +1 -0
  92. package/lib/transform/template/rewrite-module.d.ts +22 -0
  93. package/lib/transform/template/rewrite-module.d.ts.map +1 -0
  94. package/lib/transform/template/rewrite-module.js +265 -0
  95. package/lib/transform/template/rewrite-module.js.map +1 -0
  96. package/lib/transform/template/scope-stack.d.ts +13 -0
  97. package/lib/transform/template/scope-stack.d.ts.map +1 -0
  98. package/lib/transform/template/scope-stack.js +28 -0
  99. package/lib/transform/template/scope-stack.js.map +1 -0
  100. package/lib/transform/template/template-to-typescript.d.ts +19 -0
  101. package/lib/transform/template/template-to-typescript.d.ts.map +1 -0
  102. package/lib/transform/template/template-to-typescript.js +1095 -0
  103. package/lib/transform/template/template-to-typescript.js.map +1 -0
  104. package/lib/transform/template/transformed-module.d.ts +111 -0
  105. package/lib/transform/template/transformed-module.d.ts.map +1 -0
  106. package/lib/transform/template/transformed-module.js +287 -0
  107. package/lib/transform/template/transformed-module.js.map +1 -0
  108. package/lib/transform/util.d.ts +7 -0
  109. package/lib/transform/util.d.ts.map +1 -0
  110. package/lib/transform/util.js +15 -0
  111. package/lib/transform/util.js.map +1 -0
  112. package/lib/volar/ember-language-plugin.d.ts +14 -0
  113. package/lib/volar/ember-language-plugin.d.ts.map +1 -0
  114. package/lib/volar/ember-language-plugin.js +91 -0
  115. package/lib/volar/ember-language-plugin.js.map +1 -0
  116. package/lib/volar/gts-virtual-code.d.ts +83 -0
  117. package/lib/volar/gts-virtual-code.d.ts.map +1 -0
  118. package/lib/volar/gts-virtual-code.js +210 -0
  119. package/lib/volar/gts-virtual-code.js.map +1 -0
  120. package/lib/volar/language-server.d.ts +2 -0
  121. package/lib/volar/language-server.d.ts.map +1 -0
  122. package/lib/volar/language-server.js +214 -0
  123. package/lib/volar/language-server.js.map +1 -0
  124. package/lib/volar/script-snapshot.d.ts +17 -0
  125. package/lib/volar/script-snapshot.d.ts.map +1 -0
  126. package/lib/volar/script-snapshot.js +24 -0
  127. package/lib/volar/script-snapshot.js.map +1 -0
  128. package/package.json +114 -0
  129. package/src/cli/run-volar-tsc.ts +36 -0
  130. package/src/config/config.ts +33 -0
  131. package/src/config/environment.ts +128 -0
  132. package/src/config/index.ts +30 -0
  133. package/src/config/loader.ts +143 -0
  134. package/src/config/types.cts +85 -0
  135. package/src/environment-ember-template-imports/-private/environment/common.ts +14 -0
  136. package/src/environment-ember-template-imports/-private/environment/index.ts +83 -0
  137. package/src/environment-ember-template-imports/-private/environment/preprocess.ts +90 -0
  138. package/src/environment-ember-template-imports/-private/environment/transform.ts +202 -0
  139. package/src/index.ts +9 -0
  140. package/src/plugins/g-compiler-errors.ts +67 -0
  141. package/src/plugins/g-template-tag-symbols.ts +54 -0
  142. package/src/plugins/utils.ts +86 -0
  143. package/src/transform/diagnostics/augmentation.ts +333 -0
  144. package/src/transform/diagnostics/index.ts +5 -0
  145. package/src/transform/index.ts +4 -0
  146. package/src/transform/template/code-features.ts +30 -0
  147. package/src/transform/template/glimmer-ast-mapping-tree.ts +173 -0
  148. package/src/transform/template/inlining/index.ts +33 -0
  149. package/src/transform/template/inlining/tagged-strings.ts +187 -0
  150. package/src/transform/template/map-template-contents.ts +501 -0
  151. package/src/transform/template/rewrite-module.ts +372 -0
  152. package/src/transform/template/scope-stack.ts +34 -0
  153. package/src/transform/template/template-to-typescript.ts +1476 -0
  154. package/src/transform/template/transformed-module.ts +431 -0
  155. package/src/transform/util.ts +24 -0
  156. package/src/volar/ember-language-plugin.ts +108 -0
  157. package/src/volar/gts-virtual-code.ts +249 -0
  158. package/src/volar/language-server.ts +250 -0
  159. package/src/volar/script-snapshot.ts +27 -0
  160. package/types/-private/dsl/globals.d.ts +204 -0
  161. package/types/-private/dsl/index.d.ts +50 -0
  162. package/types/-private/dsl/integration-declarations.d.ts +143 -0
  163. package/types/-private/intrinsics/action.d.ts +45 -0
  164. package/types/-private/intrinsics/concat.d.ts +6 -0
  165. package/types/-private/intrinsics/each-in.d.ts +24 -0
  166. package/types/-private/intrinsics/each.d.ts +17 -0
  167. package/types/-private/intrinsics/fn.d.ts +44 -0
  168. package/types/-private/intrinsics/get.d.ts +31 -0
  169. package/types/-private/intrinsics/input.d.ts +24 -0
  170. package/types/-private/intrinsics/link-to.d.ts +31 -0
  171. package/types/-private/intrinsics/log.d.ts +6 -0
  172. package/types/-private/intrinsics/mount.d.ts +9 -0
  173. package/types/-private/intrinsics/mut.d.ts +14 -0
  174. package/types/-private/intrinsics/on.d.ts +21 -0
  175. package/types/-private/intrinsics/outlet.d.ts +8 -0
  176. package/types/-private/intrinsics/textarea.d.ts +16 -0
  177. package/types/-private/intrinsics/unbound.d.ts +10 -0
  178. package/types/-private/intrinsics/unique-id.d.ts +5 -0
  179. package/types/globals/index.d.ts +3 -0
  180. package/types/silent-error.d.ts +4 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-snapshot.d.ts","sourceRoot":"","sources":["../../src/volar/script-snapshot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE9D;;;;GAIG;AACH,qBAAa,cAAe,YAAW,eAAe;IACjC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAG/B,cAAc,CAAC,YAAY,EAAE,eAAe,GAAG,eAAe,GAAG,SAAS;IAI1E,SAAS,IAAI,MAAM;IAInB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;CAG5C"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @typedef {import('typescript').IScriptSnapshot} IScriptSnapshot
3
+ */
4
+ /**
5
+ * A TypeScript compatible script snapshot that wraps a string of text.
6
+ *
7
+ * @implements {IScriptSnapshot}
8
+ */
9
+ export class ScriptSnapshot {
10
+ constructor(text) {
11
+ this.text = text;
12
+ }
13
+ // Not Implemented
14
+ getChangeRange(_oldSnapshot) {
15
+ return undefined;
16
+ }
17
+ getLength() {
18
+ return this.text.length;
19
+ }
20
+ getText(start, end) {
21
+ return this.text.slice(start, end);
22
+ }
23
+ }
24
+ //# sourceMappingURL=script-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-snapshot.js","sourceRoot":"","sources":["../../src/volar/script-snapshot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,MAAM,OAAO,cAAc;IACzB,YAAmB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAEnC,kBAAkB;IAClB,cAAc,CAAC,YAA6B;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,GAAW;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "@glint/ember-tsc",
3
+ "version": "1.0.1-unstable.845d5fa",
4
+ "repository": "typed-ember/glint",
5
+ "description": "A CLI for performing typechecking on Glimmer templates",
6
+ "license": "MIT",
7
+ "author": "Dan Freeman (https://github.com/dfreeman)",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/index.d.ts",
12
+ "default": "./lib/index.js"
13
+ },
14
+ "./config-types": {
15
+ "types": "./lib/config/types.d.cts",
16
+ "default": "./lib/config/types.cjs"
17
+ },
18
+ "./bin/*": "./bin/*.js",
19
+ "./globals": "./types/globals/index.d.ts",
20
+ "./-private/dsl": {
21
+ "types": "./types/-private/dsl/index.d.ts",
22
+ "default": "./types/-private/dsl/index.d.ts"
23
+ },
24
+ "./types": "./types/-private/dsl/integration-declarations.d.ts",
25
+ "./-private/dsl/globals": "./types/-private/dsl/globals.d.ts",
26
+ "./-private/intrinsics/action": "./types/-private/intrinsics/action.d.ts",
27
+ "./-private/intrinsics/concat": "./types/-private/intrinsics/concat.d.ts",
28
+ "./-private/intrinsics/each": "./types/-private/intrinsics/each.d.ts",
29
+ "./-private/intrinsics/each-in": "./types/-private/intrinsics/each-in.d.ts",
30
+ "./-private/intrinsics/fn": "./types/-private/intrinsics/fn.d.ts",
31
+ "./-private/intrinsics/get": "./types/-private/intrinsics/get.d.ts",
32
+ "./-private/intrinsics/log": "./types/-private/intrinsics/log.d.ts",
33
+ "./-private/intrinsics/mount": "./types/-private/intrinsics/mount.d.ts",
34
+ "./-private/intrinsics/mut": "./types/-private/intrinsics/mut.d.ts",
35
+ "./-private/intrinsics/on": "./types/-private/intrinsics/on.d.ts",
36
+ "./-private/intrinsics/outlet": "./types/-private/intrinsics/outlet.d.ts",
37
+ "./-private/intrinsics/unbound": "./types/-private/intrinsics/unbound.d.ts",
38
+ "./-private/intrinsics/unique-id": "./types/-private/intrinsics/unique-id.d.ts",
39
+ "./*": {
40
+ "types": "./lib/*.d.ts",
41
+ "default": "./lib/*.js"
42
+ }
43
+ },
44
+ "files": [
45
+ "README.md",
46
+ "lib",
47
+ "bin",
48
+ "src",
49
+ "types"
50
+ ],
51
+ "bin": {
52
+ "glint": "bin/glint.js",
53
+ "glint-language-server": "bin/glint-language-server.js"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc --build",
57
+ "dev": "tsc --watch",
58
+ "prepack": "pnpm build"
59
+ },
60
+ "release-plan": {
61
+ "semverIncrementAs": {
62
+ "major": "prerelease",
63
+ "minor": "prerelease",
64
+ "patch": "prerelease"
65
+ },
66
+ "semverIncrementTag": "alpha",
67
+ "publishTag": "alpha"
68
+ },
69
+ "peerDependencies": {
70
+ "typescript": ">=5.6.0"
71
+ },
72
+ "dependencies": {
73
+ "@glimmer/syntax": ">= 0.95.0",
74
+ "@glint/template": "1.6.1-unstable.845d5fa",
75
+ "@volar/kit": "2.4.23",
76
+ "@volar/language-core": "2.4.23",
77
+ "@volar/language-server": "2.4.23",
78
+ "@volar/language-service": "2.4.23",
79
+ "@volar/source-map": "2.4.23",
80
+ "@volar/test-utils": "2.4.23",
81
+ "@volar/typescript": "2.4.23",
82
+ "computeds": "^0.0.1",
83
+ "content-tag": "^3.1.2",
84
+ "escape-string-regexp": "^4.0.0",
85
+ "semver": "^7.5.2",
86
+ "silent-error": "^1.1.1",
87
+ "uuid": "^8.3.2",
88
+ "volar-service-typescript": "volar-2.4",
89
+ "volar-service-html": "volar-2.4",
90
+ "vscode-languageserver-protocol": "^3.17.5",
91
+ "vscode-languageserver-textdocument": "^1.0.5",
92
+ "vscode-uri": "^3.0.8",
93
+ "yargs": "^17.5.1"
94
+ },
95
+ "devDependencies": {
96
+ "@glimmer/component": "^2.0.0",
97
+ "@glint/type-test": "2.0.1-unstable.845d5fa",
98
+ "@types/common-tags": "^1.8.0",
99
+ "@types/node": "^18.11.5",
100
+ "@types/semver": "^7.3.13",
101
+ "@types/uuid": "^8.3.4",
102
+ "@types/yargs": "^17.0.10",
103
+ "@typescript/server-harness": "latest",
104
+ "@vitest/ui": "~1.0.0",
105
+ "common-tags": "^1.8.0",
106
+ "execa": "^4.0.1",
107
+ "glint-monorepo-test-utils": "workspace:*",
108
+ "strip-ansi": "^6.0.0",
109
+ "typescript": ">=5.6.0"
110
+ },
111
+ "publishConfig": {
112
+ "access": "public"
113
+ }
114
+ }
@@ -0,0 +1,36 @@
1
+ import { runTsc } from '@volar/typescript/lib/quickstart/runTsc.js';
2
+ import { createEmberLanguagePlugin } from '../volar/ember-language-plugin.js';
3
+ import { findConfig } from '../config/index.js';
4
+
5
+ import { createRequire } from 'node:module';
6
+ const require = createRequire(import.meta.url);
7
+
8
+ export function run(): void {
9
+ let cwd = process.cwd();
10
+
11
+ const options = {
12
+ extraSupportedExtensions: ['.gjs', '.gts'],
13
+
14
+ extraExtensionsToRemove: [],
15
+
16
+ // With the above configuration, `{basename}.gts` will produce `{basename}.gts.d.ts`.
17
+ // If we would prefer `{basename}.d.ts`, we could use the following configuration instead:
18
+ //
19
+ // extraExtensionsToRemove: ['.gts', '.gjs'],
20
+ //
21
+ // See discussion here: https://github.com/typed-ember/glint/issues/628
22
+ };
23
+
24
+ const main = (): void =>
25
+ runTsc(require.resolve('typescript/lib/tsc'), options, (ts, options) => {
26
+ const glintConfig = findConfig(cwd);
27
+
28
+ if (glintConfig) {
29
+ const gtsLanguagePlugin = createEmberLanguagePlugin(glintConfig);
30
+ return [gtsLanguagePlugin];
31
+ } else {
32
+ return [];
33
+ }
34
+ });
35
+ main();
36
+ }
@@ -0,0 +1,33 @@
1
+ import { GlintConfigInput } from '@glint/ember-tsc/config-types';
2
+ import * as path from 'node:path';
3
+ import { GlintEnvironment } from './environment.js';
4
+
5
+ /**
6
+ * This class represents parsed Glint configuration from a `tsconfig` or `jsconfig` file,
7
+ * with methods for interrogating project configuration based on its contents.
8
+ */
9
+ export class GlintConfig {
10
+ declare public readonly ts: typeof import('typescript');
11
+ public readonly rootDir: string;
12
+ public readonly configPath: string;
13
+ public readonly environment: GlintEnvironment;
14
+
15
+ public constructor(
16
+ ts: typeof import('typescript'),
17
+ configPath: string,
18
+ config: GlintConfigInput,
19
+ ) {
20
+ Object.defineProperty(this, 'ts', { value: ts });
21
+ this.configPath = normalizePath(configPath);
22
+ this.rootDir = path.dirname(configPath);
23
+ this.environment = GlintEnvironment.load(config);
24
+ }
25
+ }
26
+
27
+ export function normalizePath(fileName: string): string {
28
+ if (path.sep !== '/') {
29
+ return fileName.split(path.sep).join('/');
30
+ }
31
+
32
+ return fileName;
33
+ }
@@ -0,0 +1,128 @@
1
+ import {
2
+ GlintEnvironmentConfig,
3
+ GlintExtensionConfig,
4
+ GlintExtensionsConfig,
5
+ GlintTagsConfig,
6
+ SourceKind,
7
+ } from '@glint/ember-tsc/config-types';
8
+ import * as path from 'node:path';
9
+ import SilentError from 'silent-error';
10
+
11
+ import emberTemplateImportsEnvironment from '../environment-ember-template-imports/-private/environment/index.js';
12
+
13
+ export const DEFAULT_EXTENSIONS: GlintExtensionsConfig = {
14
+ '.js': { kind: 'untyped-script' },
15
+ '.ts': { kind: 'typed-script' },
16
+ };
17
+
18
+ /**
19
+ * A GlintEnvironment represents the _merged_ configurations of one or more
20
+ * glint environments (e.g. ember-template-imports).
21
+ */
22
+ export class GlintEnvironment {
23
+ private tagConfig: GlintTagsConfig;
24
+ private extensionsConfig: GlintExtensionsConfig;
25
+
26
+ public constructor(
27
+ public readonly names: Array<string>,
28
+ config: GlintEnvironmentConfig,
29
+ ) {
30
+ this.tagConfig = config.tags ?? {};
31
+ // when is this populated? what is config?
32
+ this.extensionsConfig = config.extensions ?? {};
33
+ }
34
+
35
+ public static load(topLevelGlintConfigObject: any): GlintEnvironment {
36
+ // Glint V1:
37
+ let additionalGlobals = null;
38
+ let additionalSpecialForms = {};
39
+ if (topLevelGlintConfigObject) {
40
+ if (
41
+ topLevelGlintConfigObject.additionalGlobals ||
42
+ topLevelGlintConfigObject.additionalSpecialForms
43
+ ) {
44
+ additionalGlobals = topLevelGlintConfigObject.additionalGlobals;
45
+ additionalSpecialForms = topLevelGlintConfigObject.additionalSpecialForms ?? {};
46
+ } else {
47
+ if (Array.isArray(topLevelGlintConfigObject.environment)) {
48
+ // If it's a legacy array of environment names, e.g. ['ember-template-imports', 'ember-loose'],
49
+ // then there is no additional config such as additionalGlobals to extract.
50
+ } else {
51
+ if (typeof topLevelGlintConfigObject.environment === 'object') {
52
+ const emberTemplateImportsConfig =
53
+ topLevelGlintConfigObject.environment?.['ember-template-imports'] ?? {};
54
+ additionalGlobals = emberTemplateImportsConfig.additionalGlobals ?? [];
55
+ additionalSpecialForms = emberTemplateImportsConfig.additionalSpecialForms ?? {};
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ let tags: GlintTagsConfig = {};
62
+ let extensions: GlintExtensionsConfig = { ...DEFAULT_EXTENSIONS };
63
+
64
+ const envUserConfig = { additionalGlobals, additionalSpecialForms };
65
+
66
+ let config = emberTemplateImportsEnvironment(envUserConfig) as GlintEnvironmentConfig;
67
+
68
+ if (config.tags) {
69
+ for (let [importSource, specifiers] of Object.entries(config.tags)) {
70
+ tags[importSource] ??= {};
71
+ for (let [importSpecifier, tagConfig] of Object.entries(specifiers)) {
72
+ if (importSpecifier in tags[importSource]) {
73
+ throw new SilentError(
74
+ 'Multiple configured Glint environments attempted to define behavior for the tag `' +
75
+ importSpecifier +
76
+ "` in module '" +
77
+ importSource +
78
+ "'.",
79
+ );
80
+ }
81
+
82
+ tags[importSource][importSpecifier] = tagConfig;
83
+ }
84
+ }
85
+ }
86
+
87
+ if (config.extensions) {
88
+ for (let [extension, extensionConfig] of Object.entries(config.extensions)) {
89
+ if (extension in extensions) {
90
+ throw new SilentError(
91
+ 'Multiple configured Glint environments attempted to define handling for the ' +
92
+ extension +
93
+ ' file extension.',
94
+ );
95
+ }
96
+
97
+ extensions[extension] = extensionConfig;
98
+ }
99
+ }
100
+
101
+ return new GlintEnvironment(Object.keys(config), { tags, extensions });
102
+ }
103
+
104
+ public getSourceKind(fileName: string): SourceKind | 'unknown' {
105
+ let extension = path.extname(fileName);
106
+ return this.extensionsConfig[extension]?.kind ?? 'unknown';
107
+ }
108
+
109
+ public isUntypedScript(path: string): boolean {
110
+ return this.getSourceKind(path) === 'untyped-script';
111
+ }
112
+
113
+ /**
114
+ * Returns any custom configuration for the given file extension.
115
+ */
116
+ public getConfigForExtension(extension: string): GlintExtensionConfig | undefined {
117
+ return this.extensionsConfig[extension];
118
+ }
119
+
120
+ /**
121
+ * Returns an array of template tags that should be rewritten according to this
122
+ * config object, along with an import specifier indicating where the template types
123
+ * for each tag can be found.
124
+ */
125
+ public getConfiguredTemplateTags(): GlintTagsConfig {
126
+ return this.tagConfig;
127
+ }
128
+ }
@@ -0,0 +1,30 @@
1
+ import SilentError from 'silent-error';
2
+ import { GlintConfig } from './config.js';
3
+ import { ConfigLoader } from './loader.js';
4
+
5
+ export { GlintConfig } from './config.js';
6
+ export { GlintEnvironment } from './environment.js';
7
+ export { ConfigLoader, findTypeScript } from './loader.js';
8
+
9
+ /**
10
+ * Loads glint configuration, starting from the given directory
11
+ * and searching upwards and raising an error if no configuration
12
+ * is found.
13
+ */
14
+ export function loadConfig(from: string): GlintConfig {
15
+ let config = findConfig(from);
16
+ if (!config) {
17
+ throw new SilentError(`Unable to find Glint configuration for ${from}`);
18
+ }
19
+
20
+ return config;
21
+ }
22
+
23
+ /**
24
+ * Loads glint configuration, starting from the given directory
25
+ * and searching upwards. Returns `null` if no configuration is
26
+ * found.
27
+ */
28
+ export function findConfig(from: string): GlintConfig | null {
29
+ return new ConfigLoader().configForDirectory(from);
30
+ }
@@ -0,0 +1,143 @@
1
+ import { GlintConfigInput } from '@glint/ember-tsc/config-types';
2
+ import * as fs from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import * as path from 'node:path';
5
+ import SilentError from 'silent-error';
6
+ import type TS from 'typescript';
7
+ import { GlintConfig } from './config.js';
8
+
9
+ /**
10
+ * @private
11
+ *
12
+ * Only exported for testing purposes. Do not import.
13
+ */
14
+ export const require = createRequire(import.meta.url);
15
+
16
+ type TypeScript = typeof TS;
17
+
18
+ /**
19
+ * `ConfigLoader` provides an interface for finding the Glint config that
20
+ * applies to a given file or directory, ensuring that only a single instance
21
+ * of `GlintConfig` is ever created for a given `tsconfig.json` or
22
+ * `jsconfig.json` source file.
23
+ */
24
+ export class ConfigLoader {
25
+ private configs = new Map<string, GlintConfig | null>();
26
+
27
+ public configForFile(filePath: string): GlintConfig | null {
28
+ return this.configForDirectory(path.dirname(filePath));
29
+ }
30
+
31
+ public configForDirectory(directory: string): GlintConfig | null {
32
+ let ts = findTypeScript(directory);
33
+ if (!ts) return null;
34
+
35
+ let configPath = findNearestConfigFile(ts, directory);
36
+ if (!configPath) return null;
37
+
38
+ let existing = this.configs.get(configPath);
39
+ if (existing !== undefined) return existing;
40
+
41
+ let configInput = loadConfigInput(ts, configPath);
42
+ let config = new GlintConfig(ts, configPath, configInput || { environment: [] });
43
+
44
+ this.configs.set(configPath, config);
45
+
46
+ return config;
47
+ }
48
+ }
49
+
50
+ export function findTypeScript(fromDir: string): TypeScript | null {
51
+ let requireFrom = path.resolve(fromDir, 'package.json');
52
+ return (
53
+ tryResolve(() => createRequire(requireFrom)('typescript')) ??
54
+ tryResolve(() => require('typescript'))
55
+ );
56
+ }
57
+
58
+ function tryResolve<T>(load: () => T): T | null {
59
+ try {
60
+ return load();
61
+ } catch (error: any) {
62
+ if (error?.code === 'MODULE_NOT_FOUND') {
63
+ return null;
64
+ }
65
+
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ function parseConfigInput(
71
+ ts: TypeScript,
72
+ entryPath: string,
73
+ currentPath: string,
74
+ fullGlintConfig: Record<string, unknown>,
75
+ ): Record<string, unknown> {
76
+ let currentContents: any = ts.readConfigFile(currentPath, ts.sys.readFile).config;
77
+ let currentGlintConfig = currentContents.glint ?? {};
78
+
79
+ assert(
80
+ currentPath === entryPath || !currentGlintConfig.transform,
81
+ 'Glint `transform` options may not be specified in extended config.',
82
+ );
83
+
84
+ if (currentContents.extends) {
85
+ let paths: string[] = Array.isArray(currentContents.extends)
86
+ ? currentContents.extends
87
+ : [currentContents.extends];
88
+ for (let extendPath of paths) {
89
+ let currentExtendPath = path.resolve(path.dirname(currentPath), extendPath);
90
+ if (!fs.existsSync(currentExtendPath)) {
91
+ try {
92
+ currentExtendPath = require.resolve(currentContents.extends);
93
+ } catch {
94
+ // suppress the exception thrown by require.resolve for those scenarios where the file does not exist
95
+ }
96
+ }
97
+
98
+ fullGlintConfig = parseConfigInput(ts, entryPath, currentExtendPath, fullGlintConfig);
99
+ }
100
+ }
101
+
102
+ return { ...fullGlintConfig, ...currentGlintConfig };
103
+ }
104
+
105
+ export function loadConfigInput(ts: TypeScript, entryPath: string): GlintConfigInput | null {
106
+ return validateConfigInput(parseConfigInput(ts, entryPath, entryPath, {}));
107
+ }
108
+
109
+ function findNearestConfigFile(ts: TypeScript, searchFrom: string): string {
110
+ // Assume that the longest path is the most relevant one in the case that
111
+ // multiple config files exist at or above our current directory.
112
+ let configCandidates = [
113
+ ts.findConfigFile(searchFrom, ts.sys.fileExists, 'tsconfig.json'),
114
+ ts.findConfigFile(searchFrom, ts.sys.fileExists, 'jsconfig.json'),
115
+ ]
116
+ .filter((path): path is string => typeof path === 'string')
117
+ .sort((a, b) => b.length - a.length);
118
+
119
+ return configCandidates[0];
120
+ }
121
+
122
+ function validateConfigInput(input: Record<string, unknown>): GlintConfigInput | null {
123
+ if (!input['environment']) {
124
+ input['environment'] = [];
125
+ }
126
+
127
+ assert(
128
+ Array.isArray(input['environment'])
129
+ ? input['environment'].every((env) => typeof env === 'string')
130
+ : typeof input['environment'] === 'string' ||
131
+ (typeof input['environment'] === 'object' && input['environment']),
132
+ 'Glint config must specify an `environment` that is a string, array of strings, or an object ' +
133
+ 'mapping environment names to their config.',
134
+ );
135
+
136
+ return input as GlintConfigInput;
137
+ }
138
+
139
+ function assert(test: unknown, message: string): asserts test {
140
+ if (!test) {
141
+ throw new SilentError(`Glint config: ${message}`);
142
+ }
143
+ }
@@ -0,0 +1,85 @@
1
+ import type ts from 'typescript';
2
+
3
+ // This file is explicitly `.cts` so that environment packages written
4
+ // in CJS can import its types from `@glint/ember-tsc/config-types`.
5
+
6
+ type TSLib = typeof ts;
7
+
8
+ export type GlintConfigInput = {
9
+ environment: string | Array<string> | Record<string, unknown>;
10
+ };
11
+
12
+ export type GlintEnvironmentConfig = {
13
+ tags?: GlintTagsConfig;
14
+ extensions?: GlintExtensionsConfig;
15
+ };
16
+
17
+ export type GlintExtensionPreprocess<T> = (
18
+ source: string,
19
+ filePath: string,
20
+ ) => { contents: string; data?: T };
21
+
22
+ export type GlintEmitMetadata = {
23
+ prepend?: string;
24
+ append?: string;
25
+ templateLocation?: {
26
+ start: number;
27
+ end: number;
28
+ contentStart: number;
29
+ contentEnd: number;
30
+ };
31
+ };
32
+
33
+ export type GlintExtensionTransform<T> = (
34
+ data: T,
35
+ state: {
36
+ ts: TSLib;
37
+ context: ts.TransformationContext;
38
+ setEmitMetadata: (node: ts.TaggedTemplateExpression, meta: GlintEmitMetadata) => void;
39
+ },
40
+ ) => ts.Transformer<ts.Node>;
41
+
42
+ export type GlintSpecialForm =
43
+ | 'if'
44
+ | 'if-not'
45
+ | 'yield'
46
+ | 'object-literal'
47
+ | 'array-literal'
48
+ | 'bind-invokable'
49
+ | '==='
50
+ | '!=='
51
+ | '&&'
52
+ | '||'
53
+ | '!';
54
+
55
+ export type GlintSpecialFormConfig = {
56
+ globals?: { [global: string]: GlintSpecialForm };
57
+ imports?: {
58
+ [path: string]: {
59
+ [identifier: string]: GlintSpecialForm;
60
+ };
61
+ };
62
+ };
63
+
64
+ export type SourceKind = 'typed-script' | 'untyped-script';
65
+ export type GlintExtensionConfig<PreprocessData = any> = {
66
+ kind: SourceKind;
67
+ preprocess?: GlintExtensionPreprocess<PreprocessData>;
68
+ transform?: GlintExtensionTransform<PreprocessData>;
69
+ };
70
+
71
+ export type GlintExtensionsConfig = {
72
+ [extension: string]: GlintExtensionConfig;
73
+ };
74
+
75
+ export type GlintTagConfig = {
76
+ typesModule: string;
77
+ globals?: Array<string>;
78
+ specialForms?: GlintSpecialFormConfig;
79
+ };
80
+
81
+ export type GlintTagsConfig = {
82
+ [importSource: string]: {
83
+ [importSpecifier: string]: GlintTagConfig;
84
+ };
85
+ };
@@ -0,0 +1,14 @@
1
+ export type PreprocessData = {
2
+ templateLocations: Array<TemplateLocation>;
3
+ };
4
+
5
+ export type TemplateLocation = {
6
+ startTagOffset: number;
7
+ startTagLength: number;
8
+ endTagOffset: number;
9
+ endTagLength: number;
10
+ transformedStart: number;
11
+ transformedEnd: number;
12
+ };
13
+
14
+ export const GLOBAL_TAG = `___T`;