@defold-typescript/tstl-plugin 0.28.3 → 0.30.0

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.
@@ -1,3 +1,2 @@
1
- import { type BuildConfig } from "@defold-typescript/transpiler";
2
- import type { SceneReadHost } from "./scene-documents";
1
+ import { type BuildConfig, type SceneReadHost } from "@defold-typescript/transpiler";
3
2
  export declare function readBuildConfigFromHost(host: SceneReadHost, projectRoot: string): BuildConfig;
@@ -0,0 +1,38 @@
1
+ import ts from "typescript";
2
+ export type PluginFactory = (modules: {
3
+ typescript: typeof import("typescript");
4
+ }) => {
5
+ create(info: ts.server.PluginCreateInfo): ts.LanguageService;
6
+ };
7
+ export declare const SCENE_DOCUMENTS: Record<string, string>;
8
+ export interface ProxyHost {
9
+ documents: Record<string, string>;
10
+ directoryReads: string[][];
11
+ openWatchers: number;
12
+ fireDirectory(hostPath: string): void;
13
+ }
14
+ export interface CompletionSetup {
15
+ service: ts.LanguageService;
16
+ host: ProxyHost;
17
+ baseDisposeCalls(): number;
18
+ detailsCalls(): unknown[][];
19
+ }
20
+ export declare function completionSetup(options: {
21
+ source: string;
22
+ base: ts.WithMetadata<ts.CompletionInfo> | undefined;
23
+ documents?: Record<string, string>;
24
+ serverHost?: boolean;
25
+ watch?: boolean;
26
+ baseDispose?: boolean;
27
+ baseDetails?: ts.CompletionEntryDetails;
28
+ fileName?: string;
29
+ init?: PluginFactory;
30
+ }): CompletionSetup;
31
+ export declare function completionProxy(options: {
32
+ source: string;
33
+ base: ts.WithMetadata<ts.CompletionInfo> | undefined;
34
+ documents?: Record<string, string>;
35
+ serverHost?: boolean;
36
+ fileName?: string;
37
+ init?: PluginFactory;
38
+ }): ts.LanguageService;
package/dist/index.cjs ADDED
@@ -0,0 +1,6 @@
1
+ // tsserver resolves a plugin with Node10 resolution — `exports` is not
2
+ // consulted — and then rejects the loaded value unless it is itself a function.
3
+ // `require()` of the ESM entry yields the namespace object instead, so this
4
+ // CommonJS shim is what `main` points at: it unwraps the factory, and the ESM
5
+ // bundle stays the single build of the plugin.
6
+ module.exports = require("./index.js").default;
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { readFileSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import {
5
+ ANIMATION_ASSET_EXTENSIONS as ANIMATION_ASSET_EXTENSIONS2,
5
6
  buildConfigKeyIndex as buildConfigKeyIndex2,
6
7
  buildGuiNodeIndex as buildGuiNodeIndex2,
7
8
  buildInputActionIndex as buildInputActionIndex2,
@@ -10,14 +11,22 @@ import {
10
11
  buildSpriteAnimationIndex as buildSpriteAnimationIndex2,
11
12
  componentIdOfSameObjectAddress as componentIdOfSameObjectAddress2,
12
13
  computeOutputRel as computeOutputRel2,
14
+ displayPathOf as displayPathOf3,
15
+ GAME_PROJECT_DOCUMENT as GAME_PROJECT_DOCUMENT2,
16
+ GUI_EXTENSIONS as GUI_EXTENSIONS2,
13
17
  getProgramDiagnostics,
18
+ INPUT_BINDING_EXTENSIONS as INPUT_BINDING_EXTENSIONS2,
14
19
  isAddressClass as isAddressClass2,
15
20
  isFragmentCaret as isFragmentCaret2,
21
+ PROJECT_EXTENSIONS as PROJECT_EXTENSIONS2,
16
22
  resolveClassifiedSlotAtPosition
17
23
  } from "@defold-typescript/transpiler";
18
24
 
19
25
  // src/build-config.ts
20
- import { DEFAULT_INCLUDE, parseBuildConfig } from "@defold-typescript/transpiler";
26
+ import {
27
+ DEFAULT_INCLUDE,
28
+ parseBuildConfig
29
+ } from "@defold-typescript/transpiler";
21
30
  var ALONGSIDE = { outDir: undefined, include: DEFAULT_INCLUDE };
22
31
  function readBuildConfigFromHost(host, projectRoot) {
23
32
  const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -78,63 +87,14 @@ function buildWholeLiteralCompletionEntries(input) {
78
87
  });
79
88
  }
80
89
 
81
- // src/scene-documents.ts
82
- import { isDefignoredPath } from "@defold-typescript/transpiler";
83
- var SCENE_EXTENSIONS = [".go", ".collection"];
84
- var GUI_EXTENSIONS = [".gui"];
85
- var INPUT_BINDING_EXTENSIONS = [".input_binding"];
86
- var ANIMATION_ASSET_EXTENSIONS = [".atlas", ".tilesource", ".sprite"];
87
- var PROJECT_EXTENSIONS = [".project"];
88
- var GAME_PROJECT_DOCUMENT = "game.project";
89
- function displayPathOf(projectRoot, filePath) {
90
- const path = filePath.replace(/\\/g, "/");
91
- const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
92
- return path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
93
- }
94
- function isBuildOutput(displayPath) {
95
- return displayPath.split("/").includes("build");
96
- }
97
- function isExcludedProjectPath(displayPath) {
98
- return isBuildOutput(displayPath) || isDefignoredPath(displayPath);
99
- }
100
- function readSceneDocuments(host, projectRoot, extensions = SCENE_EXTENSIONS) {
101
- const documents = new Map;
102
- const unreadable = [];
103
- const paths = [];
104
- if (!host.readDirectory) {
105
- unreadable.push("the editor host cannot enumerate project files, so no scene source was read");
106
- return { documents, unreadable, paths };
107
- }
108
- for (const filePath of host.readDirectory(projectRoot, extensions)) {
109
- const displayPath = displayPathOf(projectRoot, filePath);
110
- if (isExcludedProjectPath(displayPath))
111
- continue;
112
- const text = host.readFile(filePath);
113
- if (text === undefined) {
114
- unreadable.push(`${displayPath}: could not be read`);
115
- continue;
116
- }
117
- documents.set(displayPath, text);
118
- paths.push(filePath);
119
- }
120
- return { documents, unreadable, paths };
121
- }
122
- function listProjectResourcePaths(host, projectRoot, extensions) {
123
- if (!host.readDirectory)
124
- return new Set;
125
- const paths = [];
126
- for (const filePath of host.readDirectory(projectRoot, extensions)) {
127
- const displayPath = displayPathOf(projectRoot, filePath);
128
- if (isExcludedProjectPath(displayPath))
129
- continue;
130
- if (!extensions.some((extension) => displayPath.endsWith(extension)))
131
- continue;
132
- paths.push(`/${displayPath}`);
133
- }
134
- return new Set(paths.sort());
135
- }
136
-
137
90
  // src/scene-index-cache.ts
91
+ import {
92
+ displayPathOf,
93
+ isExcludedProjectPath,
94
+ listProjectResourcePaths,
95
+ readSceneDocuments,
96
+ SCENE_EXTENSIONS
97
+ } from "@defold-typescript/transpiler";
138
98
  function cacheKey(extensions) {
139
99
  return [...extensions].sort().join("|");
140
100
  }
@@ -250,6 +210,7 @@ function createSceneIndexCache(host, projectRoot) {
250
210
 
251
211
  // src/scene-provenance.ts
252
212
  import {
213
+ ANIMATION_ASSET_EXTENSIONS,
253
214
  buildConfigKeyIndex,
254
215
  buildGuiNodeIndex,
255
216
  buildInputActionIndex,
@@ -258,8 +219,13 @@ import {
258
219
  buildSpriteAnimationIndex,
259
220
  componentIdOfSameObjectAddress,
260
221
  computeOutputRel,
222
+ displayPathOf as displayPathOf2,
223
+ GAME_PROJECT_DOCUMENT,
224
+ GUI_EXTENSIONS,
225
+ INPUT_BINDING_EXTENSIONS,
261
226
  isAddressClass,
262
- isFragmentCaret
227
+ isFragmentCaret,
228
+ PROJECT_EXTENSIONS
263
229
  } from "@defold-typescript/transpiler";
264
230
  var COMPONENT_PROVENANCE = "provenance:component-ids";
265
231
  var ACTION_PROVENANCE = "provenance:input-actions";
@@ -317,7 +283,7 @@ function actionProvenance(cache) {
317
283
  function nodeProvenance(cache, fileName) {
318
284
  const byResource = cache.derived(GUI_PROVENANCE, () => byClaimedScript(cache.documents(GUI_EXTENSIONS).documents));
319
285
  const config = readBuildConfigFromHost(cache.host, cache.projectRoot);
320
- const resource = computeOutputRel(displayPathOf(cache.projectRoot, fileName), config, "gui-script");
286
+ const resource = computeOutputRel(displayPathOf2(cache.projectRoot, fileName), config, "gui-script");
321
287
  return byResource.get(resource) ?? new Map;
322
288
  }
323
289
  function pathProvenance(cache) {
@@ -333,7 +299,7 @@ function animationProvenance(input) {
333
299
  assets: cache.documents(ANIMATION_ASSET_EXTENSIONS).documents
334
300
  }));
335
301
  const config = readBuildConfigFromHost(cache.host, cache.projectRoot);
336
- const resource = computeOutputRel(displayPathOf(cache.projectRoot, fileName), config, "script");
302
+ const resource = computeOutputRel(displayPathOf2(cache.projectRoot, fileName), config, "script");
337
303
  const tileSet = index.tileSetByScriptResource.get(resource)?.get(component);
338
304
  if (tileSet === undefined)
339
305
  return [];
@@ -411,9 +377,9 @@ function objectPathEntries(slot, position, cache, baseEntries) {
411
377
  }
412
378
  function nodeEntries(slot, cache, fileName, baseEntries) {
413
379
  const { projectRoot } = cache;
414
- const index = cache.derived("gui-nodes", () => buildGuiNodeIndex2(cache.documents(GUI_EXTENSIONS).documents));
380
+ const index = cache.derived("gui-nodes", () => buildGuiNodeIndex2(cache.documents(GUI_EXTENSIONS2).documents));
415
381
  const config = readBuildConfigFromHost(cache.host, projectRoot);
416
- const resource = computeOutputRel2(displayPathOf(projectRoot, fileName), config, "gui-script");
382
+ const resource = computeOutputRel2(displayPathOf3(projectRoot, fileName), config, "gui-script");
417
383
  const ids = index.byScriptResource.get(resource);
418
384
  return ids === undefined ? [] : buildWholeLiteralCompletionEntries({ slot, ids, baseEntries });
419
385
  }
@@ -425,10 +391,10 @@ function animationEntries(slot, cache, fileName, baseEntries) {
425
391
  const { projectRoot } = cache;
426
392
  const index = cache.derived("sprite-animations", () => buildSpriteAnimationIndex2({
427
393
  scenes: cache.documents().documents,
428
- assets: cache.documents(ANIMATION_ASSET_EXTENSIONS).documents
394
+ assets: cache.documents(ANIMATION_ASSET_EXTENSIONS2).documents
429
395
  }));
430
396
  const config = readBuildConfigFromHost(cache.host, projectRoot);
431
- const resource = computeOutputRel2(displayPathOf(projectRoot, fileName), config, "script");
397
+ const resource = computeOutputRel2(displayPathOf3(projectRoot, fileName), config, "script");
432
398
  const ids = index.byScriptResource.get(resource)?.get(component);
433
399
  return ids === undefined ? [] : buildWholeLiteralCompletionEntries({ slot, ids, baseEntries });
434
400
  }
@@ -441,7 +407,7 @@ function resourceEntries(slot, cache, baseEntries) {
441
407
  return buildWholeLiteralCompletionEntries({ slot, ids, baseEntries });
442
408
  }
443
409
  function configKeyEntries(slot, cache, baseEntries) {
444
- const text = cache.documents(PROJECT_EXTENSIONS).documents.get(GAME_PROJECT_DOCUMENT);
410
+ const text = cache.documents(PROJECT_EXTENSIONS2).documents.get(GAME_PROJECT_DOCUMENT2);
445
411
  if (text === undefined) {
446
412
  return [];
447
413
  }
@@ -449,7 +415,7 @@ function configKeyEntries(slot, cache, baseEntries) {
449
415
  return buildWholeLiteralCompletionEntries({ slot, ids, baseEntries });
450
416
  }
451
417
  function actionIdEntries(slot, cache, baseEntries) {
452
- const ids = cache.derived("input-actions", () => buildInputActionIndex2(cache.documents(INPUT_BINDING_EXTENSIONS).documents));
418
+ const ids = cache.derived("input-actions", () => buildInputActionIndex2(cache.documents(INPUT_BINDING_EXTENSIONS2).documents));
453
419
  return buildWholeLiteralCompletionEntries({ slot, ids, baseEntries });
454
420
  }
455
421
  function provenancePanel(entryName, declaredIn) {
@@ -1,5 +1,5 @@
1
+ import { readSceneDocuments, type SceneReadHost } from "@defold-typescript/transpiler";
1
2
  import type * as ts from "typescript";
2
- import { readSceneDocuments, type SceneReadHost } from "./scene-documents";
3
3
  export interface SceneWatchHost extends SceneReadHost {
4
4
  watchFile?(path: string, callback: ts.FileWatcherCallback, pollingInterval?: number): ts.FileWatcher;
5
5
  watchDirectory?(path: string, callback: ts.DirectoryWatcherCallback, recursive?: boolean): ts.FileWatcher;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defold-typescript/tstl-plugin",
3
- "version": "0.28.3",
3
+ "version": "0.30.0",
4
4
  "description": "TypeScript language-service plugin surfacing Defold transpiler diagnostics live in the editor.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,32 +11,34 @@
11
11
  "homepage": "https://github.com/defold-typescript/toolchain#readme",
12
12
  "bugs": "https://github.com/defold-typescript/toolchain/issues",
13
13
  "type": "module",
14
- "main": "./dist/index.js",
14
+ "main": "./dist/index.cjs",
15
15
  "types": "./dist/index.d.ts",
16
16
  "exports": {
17
17
  ".": {
18
18
  "types": "./dist/index.d.ts",
19
19
  "bun": "./src/index.ts",
20
- "import": "./dist/index.js"
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
21
22
  }
22
23
  },
23
24
  "files": [
24
25
  "dist",
25
26
  "src",
26
27
  "!src/**/*.test.ts",
28
+ "!src/**/completion-harness.ts",
27
29
  "!src/**/__snapshots__"
28
30
  ],
29
31
  "publishConfig": {
30
32
  "access": "public"
31
33
  },
32
34
  "scripts": {
33
- "build": "rm -rf dist && bun build src/index.ts --target=node --format=esm --packages=external --outdir=dist && tsc -p tsconfig.build.json --emitDeclarationOnly",
35
+ "build": "rm -rf dist && bun build src/index.ts --target=node --format=esm --packages=external --outdir=dist && cp src/require-entry.cjs dist/index.cjs && tsc -p tsconfig.build.json --emitDeclarationOnly",
34
36
  "typecheck": "tsc -p tsconfig.json --noEmit",
35
37
  "test": "bun test"
36
38
  },
37
39
  "dependencies": {
38
- "@defold-typescript/transpiler": "0.28.3",
39
- "@defold-typescript/types": "0.28.3"
40
+ "@defold-typescript/transpiler": "0.30.0",
41
+ "@defold-typescript/types": "0.30.0"
40
42
  },
41
43
  "peerDependencies": {
42
44
  "typescript": ">=5.0.0 <7"
@@ -1,5 +1,9 @@
1
- import { type BuildConfig, DEFAULT_INCLUDE, parseBuildConfig } from "@defold-typescript/transpiler";
2
- import type { SceneReadHost } from "./scene-documents";
1
+ import {
2
+ type BuildConfig,
3
+ DEFAULT_INCLUDE,
4
+ parseBuildConfig,
5
+ type SceneReadHost,
6
+ } from "@defold-typescript/transpiler";
3
7
 
4
8
  // Alongside output is what the build itself does with no `outDir`, so it is also
5
9
  // the honest answer when the config cannot be read: a wrong guess would offer
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import {
4
+ ANIMATION_ASSET_EXTENSIONS,
4
5
  buildConfigKeyIndex,
5
6
  buildGuiNodeIndex,
6
7
  buildInputActionIndex,
@@ -10,9 +11,14 @@ import {
10
11
  type ClassifiedSlot,
11
12
  componentIdOfSameObjectAddress,
12
13
  computeOutputRel,
14
+ displayPathOf,
15
+ GAME_PROJECT_DOCUMENT,
16
+ GUI_EXTENSIONS,
13
17
  getProgramDiagnostics,
18
+ INPUT_BINDING_EXTENSIONS,
14
19
  isAddressClass,
15
20
  isFragmentCaret,
21
+ PROJECT_EXTENSIONS,
16
22
  resolveClassifiedSlotAtPosition,
17
23
  } from "@defold-typescript/transpiler";
18
24
  import type { UrlParameterTable } from "@defold-typescript/types";
@@ -25,14 +31,6 @@ import {
25
31
  CONTRIBUTED_ENTRY_KIND,
26
32
  DEFOLD_COMPLETION_SOURCE,
27
33
  } from "./scene-completions";
28
- import {
29
- ANIMATION_ASSET_EXTENSIONS,
30
- displayPathOf,
31
- GAME_PROJECT_DOCUMENT,
32
- GUI_EXTENSIONS,
33
- INPUT_BINDING_EXTENSIONS,
34
- PROJECT_EXTENSIONS,
35
- } from "./scene-documents";
36
34
  import {
37
35
  createSceneIndexCache,
38
36
  type SceneIndexCache,
@@ -0,0 +1,6 @@
1
+ // tsserver resolves a plugin with Node10 resolution — `exports` is not
2
+ // consulted — and then rejects the loaded value unless it is itself a function.
3
+ // `require()` of the ESM entry yields the namespace object instead, so this
4
+ // CommonJS shim is what `main` points at: it unwraps the factory, and the ESM
5
+ // bundle stays the single build of the plugin.
6
+ module.exports = require("./index.js").default;
@@ -1,4 +1,3 @@
1
- import type * as ts from "typescript";
2
1
  import {
3
2
  displayPathOf,
4
3
  isExcludedProjectPath,
@@ -6,7 +5,8 @@ import {
6
5
  readSceneDocuments,
7
6
  SCENE_EXTENSIONS,
8
7
  type SceneReadHost,
9
- } from "./scene-documents";
8
+ } from "@defold-typescript/transpiler";
9
+ import type * as ts from "typescript";
10
10
 
11
11
  // `SceneReadHost` plus the two watch facilities `ts.System` declares as
12
12
  // optional, typed off the editor's own callback types so the real
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ANIMATION_ASSET_EXTENSIONS,
2
3
  buildConfigKeyIndex,
3
4
  buildGuiNodeIndex,
4
5
  buildInputActionIndex,
@@ -8,18 +9,15 @@ import {
8
9
  type ClassifiedSlot,
9
10
  componentIdOfSameObjectAddress,
10
11
  computeOutputRel,
11
- isAddressClass,
12
- isFragmentCaret,
13
- } from "@defold-typescript/transpiler";
14
- import { readBuildConfigFromHost } from "./build-config";
15
- import {
16
- ANIMATION_ASSET_EXTENSIONS,
17
12
  displayPathOf,
18
13
  GAME_PROJECT_DOCUMENT,
19
14
  GUI_EXTENSIONS,
20
15
  INPUT_BINDING_EXTENSIONS,
16
+ isAddressClass,
17
+ isFragmentCaret,
21
18
  PROJECT_EXTENSIONS,
22
- } from "./scene-documents";
19
+ } from "@defold-typescript/transpiler";
20
+ import { readBuildConfigFromHost } from "./build-config";
23
21
  import type { SceneIndexCache } from "./scene-index-cache";
24
22
 
25
23
  // Keys of their own under the same cache the completion indexes use, so a
@@ -1,18 +0,0 @@
1
- export interface SceneReadHost {
2
- readDirectory?(path: string, extensions?: readonly string[]): string[];
3
- readFile(path: string): string | undefined;
4
- }
5
- export declare const SCENE_EXTENSIONS: string[];
6
- export declare const GUI_EXTENSIONS: string[];
7
- export declare const INPUT_BINDING_EXTENSIONS: string[];
8
- export declare const ANIMATION_ASSET_EXTENSIONS: string[];
9
- export declare const PROJECT_EXTENSIONS: string[];
10
- export declare const GAME_PROJECT_DOCUMENT = "game.project";
11
- export declare function displayPathOf(projectRoot: string, filePath: string): string;
12
- export declare function isExcludedProjectPath(displayPath: string): boolean;
13
- export declare function readSceneDocuments(host: SceneReadHost, projectRoot: string, extensions?: readonly string[]): {
14
- documents: Map<string, string>;
15
- unreadable: string[];
16
- paths: string[];
17
- };
18
- export declare function listProjectResourcePaths(host: SceneReadHost, projectRoot: string, extensions: readonly string[]): Set<string>;
@@ -1,126 +0,0 @@
1
- import { isDefignoredPath } from "@defold-typescript/transpiler";
2
-
3
- // The narrow slice of `ts.server.ServerHost` this needs: the real host
4
- // satisfies it structurally, and a test fake is two methods rather than a whole
5
- // server. `readDirectory` is optional because a host may not provide it, and a
6
- // plugin that throws takes the editor's completions down with it.
7
- export interface SceneReadHost {
8
- readDirectory?(path: string, extensions?: readonly string[]): string[];
9
- readFile(path: string): string | undefined;
10
- }
11
-
12
- export const SCENE_EXTENSIONS = [".go", ".collection"];
13
-
14
- // The extension sets more than one reader asks the host for. They live here
15
- // rather than beside either caller because the index cache serves exactly the
16
- // sets it is handed: a second definition that drifted would walk — and watch —
17
- // a universe the other reader never invalidates.
18
- export const GUI_EXTENSIONS = [".gui"];
19
- export const INPUT_BINDING_EXTENSIONS = [".input_binding"];
20
-
21
- // The documents an animation id is declared by: an atlas or tile source names
22
- // the ids, and a `.sprite` is the hop a referenced component takes to reach one.
23
- export const ANIMATION_ASSET_EXTENSIONS = [".atlas", ".tilesource", ".sprite"];
24
-
25
- // The walk returns every `.project` the project holds, so the lookup is by
26
- // display path — a vendored `*.project` declares keys this project's readers
27
- // cannot resolve.
28
- export const PROJECT_EXTENSIONS = [".project"];
29
- export const GAME_PROJECT_DOCUMENT = "game.project";
30
-
31
- // The project-relative name a file is keyed by — the same name the editor
32
- // reports for a program file, so a scene's claim on a script can be looked up
33
- // against the file being edited.
34
- export function displayPathOf(projectRoot: string, filePath: string): string {
35
- const path = filePath.replace(/\\/g, "/");
36
- const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
37
- return path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
38
- }
39
-
40
- // What both walks exclude is what Defold does not load as a project resource:
41
- // `build/` output, plus the directories the scaffolded `.defignore` names
42
- // (`isDefignoredPath`, root-anchored because a `.defignore` line is a
43
- // root-relative path).
44
- //
45
- // Bob writes `_generated_*.go` copies of the project's scenes under `build/`;
46
- // reading them would report every id twice, against files no author edits. The
47
- // segment test runs on the project-relative path, so a project that itself
48
- // lives under a directory named `build` is not excluded wholesale — a different
49
- // rule from `.defignore`'s, because bob writes those copies below whatever
50
- // depth it is pointed at.
51
- function isBuildOutput(displayPath: string): boolean {
52
- return displayPath.split("/").includes("build");
53
- }
54
-
55
- // The single rule, exported because the index cache filters watch events with
56
- // it: a copy in the watcher could drift from what the walks exclude, and an
57
- // event the walk would have ignored is exactly the event that must not throw the
58
- // cache away — bob writes `_generated_*.go` throughout a build.
59
- export function isExcludedProjectPath(displayPath: string): boolean {
60
- return isBuildOutput(displayPath) || isDefignoredPath(displayPath);
61
- }
62
-
63
- // Read the project's own scene sources through the editor host — by default the
64
- // `.go`/`.collection` set the component-id universe is built from, or whatever
65
- // `extensions` names instead. The two universes stay disjoint: a `.gui` declares
66
- // node ids, not component ids, so folding it into the default would feed gui
67
- // text to `buildSceneComponentIndex`. Keys are project-relative display paths,
68
- // matching what `buildSceneComponentIndex` reports in `incomplete`, and every
69
- // file that could not be read is named in `unreadable` — a universe with a
70
- // silent hole cannot be reasoned about. `paths` names the host paths actually
71
- // read — what a watcher must be registered on, which cannot be reconstructed
72
- // from a display path for a file outside the project root.
73
- export function readSceneDocuments(
74
- host: SceneReadHost,
75
- projectRoot: string,
76
- extensions: readonly string[] = SCENE_EXTENSIONS,
77
- ): { documents: Map<string, string>; unreadable: string[]; paths: string[] } {
78
- const documents = new Map<string, string>();
79
- const unreadable: string[] = [];
80
- const paths: string[] = [];
81
-
82
- if (!host.readDirectory) {
83
- unreadable.push("the editor host cannot enumerate project files, so no scene source was read");
84
- return { documents, unreadable, paths };
85
- }
86
-
87
- for (const filePath of host.readDirectory(projectRoot, extensions)) {
88
- const displayPath = displayPathOf(projectRoot, filePath);
89
- if (isExcludedProjectPath(displayPath)) continue;
90
- const text = host.readFile(filePath);
91
- if (text === undefined) {
92
- unreadable.push(`${displayPath}: could not be read`);
93
- continue;
94
- }
95
- documents.set(displayPath, text);
96
- paths.push(filePath);
97
- }
98
-
99
- return { documents, unreadable, paths };
100
- }
101
-
102
- // The project's own files of the given kinds, as the `/`-prefixed
103
- // project-relative paths a Defold resource property names. Nothing is read: a
104
- // resource path is the whole suggestion, so the walk is the entire universe.
105
- //
106
- // The extension filter is re-applied rather than trusted. `readSceneDocuments`
107
- // can take the host at its word because a wrong document merely contributes no
108
- // ids, but here a wrong file *is* the suggestion — a host that ignored its
109
- // `extensions` argument would turn a `.font` slot into a project-wide file dump.
110
- export function listProjectResourcePaths(
111
- host: SceneReadHost,
112
- projectRoot: string,
113
- extensions: readonly string[],
114
- ): Set<string> {
115
- if (!host.readDirectory) return new Set();
116
-
117
- const paths: string[] = [];
118
- for (const filePath of host.readDirectory(projectRoot, extensions)) {
119
- const displayPath = displayPathOf(projectRoot, filePath);
120
- if (isExcludedProjectPath(displayPath)) continue;
121
- if (!extensions.some((extension) => displayPath.endsWith(extension))) continue;
122
- paths.push(`/${displayPath}`);
123
- }
124
-
125
- return new Set(paths.sort());
126
- }