ttsc 0.31.4 → 0.32.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.
- package/cmd/ttsc/compiler_argument_cwd_test.go +38 -38
- package/cmd/ttscserver/main.go +2 -12
- package/cmd/ttscserver/resolve_launch_uses_native_flag_authority_test.go +7 -7
- package/driver/lsp.go +4 -43
- package/driver/rewrite.go +1 -1
- package/internal/e2etrace/completion_hints.go +3 -3
- package/internal/e2etrace/completion_hints_test.go +26 -12
- package/internal/graph/build.go +5 -6
- package/internal/graph/graph.go +3 -3
- package/internal/graph/line_model.go +2 -35
- package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +13 -36
- package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +9 -3
- package/internal/lspserver/lsp_plugin.go +19 -0
- package/internal/lspserver/lsp_proxy.go +9 -129
- package/internal/lspserver/lsp_server.go +0 -8
- package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +6 -36
- package/internal/sourceprocess/windows_target_owns_suspended_admission_test.go +5 -5
- package/lib/compiler/internal/build/BuildExecution.js +11 -3
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/TsgoArguments.js.map +1 -1
- package/lib/compiler/internal/project/CompilerProjectSelection.d.ts +9 -8
- package/lib/compiler/internal/project/CompilerProjectSelection.js +11 -9
- package/lib/compiler/internal/project/CompilerProjectSelection.js.map +1 -1
- package/lib/compiler/internal/project/resolveOwningProjectConfig.d.ts +20 -8
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js +21 -12
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.d.ts +5 -4
- package/lib/compiler/internal/runSingleFileEmit.js +5 -4
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/flags/ParseOptions.d.ts +2 -2
- package/lib/internal/E2ETrace.d.ts +1 -0
- package/lib/internal/E2ETrace.js.map +1 -1
- package/lib/internal/OwnedNativeProcess.d.ts +2 -2
- package/lib/internal/OwnedNativeProcess.js +2 -2
- package/lib/internal/SourceNativeRetirement.d.ts +8 -7
- package/lib/internal/SourceNativeRetirement.js +19 -10
- package/lib/internal/SourceNativeRetirement.js.map +1 -1
- package/lib/internal/TtsxNodeOptions.d.ts +79 -0
- package/lib/internal/TtsxNodeOptions.js +121 -0
- package/lib/internal/TtsxNodeOptions.js.map +1 -0
- package/lib/internal/javascriptRuntimeCapabilities.js +4 -1
- package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
- package/lib/internal/parseWindowsDirectoryCaseSensitivity.d.ts +5 -5
- package/lib/internal/parseWindowsDirectoryCaseSensitivity.js +5 -5
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.d.ts +35 -0
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.js +209 -0
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.js.map +1 -0
- package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js +2 -143
- package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js.map +1 -1
- package/lib/internal/probeLocalProcess.d.ts +5 -1
- package/lib/internal/probeLocalProcess.js +9 -7
- package/lib/internal/probeLocalProcess.js.map +1 -1
- package/lib/internal/projectInputPathIdentity.d.ts +1 -0
- package/lib/internal/projectInputPathIdentity.js +1 -0
- package/lib/internal/projectInputPathIdentity.js.map +1 -1
- package/lib/launcher/internal/parseTtsxCLI.d.ts +5 -4
- package/lib/launcher/internal/parseTtsxCLI.js +5 -4
- package/lib/launcher/internal/parseTtsxCLI.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/resolveSingleFileOutput.d.ts +8 -9
- package/lib/launcher/internal/resolveSingleFileOutput.js +8 -9
- package/lib/launcher/internal/resolveSingleFileOutput.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +5 -5
- package/lib/launcher/internal/runTtsx.js +5 -2
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtime/ProcessOwnedDirectory.d.ts +2 -0
- package/lib/launcher/internal/runtime/ProcessOwnedDirectory.js +2 -1
- package/lib/launcher/internal/runtime/ProcessOwnedDirectory.js.map +1 -1
- package/lib/launcher/internal/runtime/RuntimeEntrySources.d.ts +40 -0
- package/lib/launcher/internal/runtime/RuntimeEntrySources.js +57 -0
- package/lib/launcher/internal/runtime/RuntimeEntrySources.js.map +1 -0
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.d.ts +5 -4
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.js +8 -6
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.js.map +1 -1
- package/lib/launcher/internal/runtime/commonJsExportNames.d.ts +2 -1
- package/lib/launcher/internal/runtime/commonJsExportNames.js +2 -1
- package/lib/launcher/internal/runtime/commonJsExportNames.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +35 -9
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/runtime/isLocalProcessGone.d.ts +1 -1
- package/lib/launcher/internal/runtime/isLocalProcessGone.js +4 -4
- package/lib/launcher/internal/runtime/isLocalProcessGone.js.map +1 -1
- package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.js +3 -1
- package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.js.map +1 -1
- package/lib/launcher/internal/watch/FseventsStreams.d.ts +2 -0
- package/lib/launcher/internal/watch/FseventsStreams.js +19 -0
- package/lib/launcher/internal/watch/FseventsStreams.js.map +1 -1
- package/lib/launcher/internal/watch/WatchTopology.d.ts +74 -12
- package/lib/launcher/internal/watch/WatchTopology.js +301 -92
- package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
- package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.d.ts +4 -1
- package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js +3 -2
- package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.js +17 -9
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/load/resolveNativeSource.js +2 -3
- package/lib/plugin/internal/load/resolveNativeSource.js.map +1 -1
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.d.ts +4 -1
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +9 -2
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js.map +1 -1
- package/lib/structures/internal/TtscCommonOptions.d.ts +2 -2
- package/package.json +9 -9
- package/src/compiler/internal/build/BuildExecution.ts +15 -6
- package/src/compiler/internal/build/TsgoArguments.ts +4 -1
- package/src/compiler/internal/project/CompilerProjectSelection.ts +14 -14
- package/src/compiler/internal/project/resolveOwningProjectConfig.ts +29 -14
- package/src/compiler/internal/runSingleFileEmit.ts +11 -7
- package/src/flags/ParseOptions.ts +2 -2
- package/src/internal/E2ETrace.ts +5 -1
- package/src/internal/OwnedNativeProcess.ts +2 -2
- package/src/internal/SourceNativeRetirement.ts +42 -19
- package/src/internal/TtsxNodeOptions.ts +124 -0
- package/src/internal/javascriptRuntimeCapabilities.ts +6 -1
- package/src/internal/parseWindowsDirectoryCaseSensitivity.ts +5 -5
- package/src/internal/pathIdentity/createCaseSensitivityObservations.ts +242 -0
- package/src/internal/pathIdentity/createFilesystemPathIdentityContext.ts +2 -169
- package/src/internal/probeLocalProcess.ts +13 -8
- package/src/internal/projectInputPathIdentity.ts +1 -0
- package/src/launcher/internal/parseTtsxCLI.ts +5 -4
- package/src/launcher/internal/prepareExecution.ts +4 -1
- package/src/launcher/internal/resolveSingleFileOutput.ts +8 -9
- package/src/launcher/internal/runTtsc.ts +5 -5
- package/src/launcher/internal/runTtsx.ts +17 -8
- package/src/launcher/internal/runtime/ProcessOwnedDirectory.ts +5 -1
- package/src/launcher/internal/runtime/RuntimeEntrySources.ts +57 -0
- package/src/launcher/internal/runtime/RuntimeProjectOwnership.ts +23 -10
- package/src/launcher/internal/runtime/commonJsExportNames.ts +11 -4
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +55 -13
- package/src/launcher/internal/runtime/isLocalProcessGone.ts +5 -3
- package/src/launcher/internal/runtime/resolveRuntimeCleanTargets.ts +17 -5
- package/src/launcher/internal/watch/FseventsStreams.ts +22 -0
- package/src/launcher/internal/watch/WatchTopology.ts +387 -99
- package/src/launcher/internal/watch/projectInputReloadEventShouldNotify.ts +14 -9
- package/src/plugin/internal/load/loadProjectPlugins.ts +17 -3
- package/src/plugin/internal/load/resolveNativeSource.ts +10 -4
- package/src/plugin/internal/source/pluginModuleReplaceDirectories.ts +10 -1
- package/src/structures/internal/TtscCommonOptions.ts +2 -2
- package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +0 -78
- package/internal/graphsymbols/provider.go +0 -650
- package/internal/lspserver/lsp_symbols.go +0 -212
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
3
|
import { type ProjectInputPathIdentity } from "../../../internal/pathIdentity/ProjectInputPathIdentity";
|
|
4
|
+
import { type ProjectInputPathIdentityContext } from "../../../internal/pathIdentity/ProjectInputPathIdentityContext";
|
|
4
5
|
import { createProjectInputPathIdentityContext } from "../../../internal/pathIdentity/createProjectInputPathIdentityContext";
|
|
5
6
|
import { literalGlobRoot } from "./literalGlobRoot";
|
|
6
7
|
|
|
@@ -12,6 +13,8 @@ import { literalGlobRoot } from "./literalGlobRoot";
|
|
|
12
13
|
* lane only after the surrounding change detector admits the event; unchanged
|
|
13
14
|
* bytes remain quiet before this classifier is observed.
|
|
14
15
|
*
|
|
16
|
+
* @param identities The decision's identity transaction; absence creates a
|
|
17
|
+
* native one for this classification alone.
|
|
15
18
|
* @evidence contracts/common.md#principled-implementation Exact selection files and immediate resolution-directory entries choose execution reload; a strictly nested declared glob can explain its own ancestor's membership delta without exempting unrelated selection changes.
|
|
16
19
|
* @evidence contracts/common.md#clear-and-simple-design Exact-file membership, immediate-entry membership and causal explanations have distinct helpers under one classification operation.
|
|
17
20
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts A data exemption must explain the same directory's observed delta, not cancel every reload because some unrelated data event occurred.
|
|
@@ -22,15 +25,17 @@ import { literalGlobRoot } from "./literalGlobRoot";
|
|
|
22
25
|
*
|
|
23
26
|
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Identity caches and predicate collections are local to one decision, without a resident historical cache or native handle.
|
|
24
27
|
*/
|
|
25
|
-
export function projectInputReloadEventShouldNotify(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
export function projectInputReloadEventShouldNotify(
|
|
29
|
+
input: {
|
|
30
|
+
causedBy?: readonly string[];
|
|
31
|
+
changed?: string;
|
|
32
|
+
changedInputs: readonly string[];
|
|
33
|
+
reloadDirectories?: readonly string[];
|
|
34
|
+
reloadFiles: readonly string[];
|
|
35
|
+
globs?: readonly string[];
|
|
36
|
+
},
|
|
37
|
+
identities: ProjectInputPathIdentityContext = createProjectInputPathIdentityContext(),
|
|
38
|
+
): boolean {
|
|
34
39
|
const reloadFiles = new Set(
|
|
35
40
|
input.reloadFiles.map((location) => identities.resolve(location).key),
|
|
36
41
|
);
|
|
@@ -9,6 +9,7 @@ import { readProjectConfig } from "../../../compiler/internal/project/readProjec
|
|
|
9
9
|
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
10
10
|
import { E2ETrace } from "../../../internal/E2ETrace";
|
|
11
11
|
import { OwnedSynchronousProcess } from "../../../internal/OwnedSynchronousProcess";
|
|
12
|
+
import { TtsxNodeOptions } from "../../../internal/TtsxNodeOptions";
|
|
12
13
|
import { createCanonicalTempDirectory } from "../../../internal/createCanonicalTempDirectory";
|
|
13
14
|
import { javascriptRuntimeCapabilities } from "../../../internal/javascriptRuntimeCapabilities";
|
|
14
15
|
import { resolveNodeBinary } from "../../../internal/resolveNodeBinary";
|
|
@@ -445,6 +446,7 @@ export function loadProjectPlugins(options: {
|
|
|
445
446
|
effectiveEnv,
|
|
446
447
|
watchReplacements,
|
|
447
448
|
packageReaders,
|
|
449
|
+
sourceIdentities,
|
|
448
450
|
))
|
|
449
451
|
if (reportsPluginSource(directory)) interests.add(directory);
|
|
450
452
|
}
|
|
@@ -534,6 +536,7 @@ export function loadProjectPlugins(options: {
|
|
|
534
536
|
effectiveEnv,
|
|
535
537
|
watchReplacements,
|
|
536
538
|
packageReaders,
|
|
539
|
+
sourceIdentities,
|
|
537
540
|
);
|
|
538
541
|
// Admission can now narrow the provisional interests without restamping the
|
|
539
542
|
// retained package/module baselines. Final host errors still keep these roots.
|
|
@@ -736,8 +739,10 @@ export function loadProjectPlugins(options: {
|
|
|
736
739
|
binary,
|
|
737
740
|
// This fallback is compiled from our utility-host, whose actual writer
|
|
738
741
|
// publishes provenance and supports a separate compiler argument cwd.
|
|
739
|
-
// A separately selected executable host must opt
|
|
740
|
-
//
|
|
742
|
+
// A separately selected executable host must opt in itself; a linked
|
|
743
|
+
// library cannot certify that foreign host. An undeclared capability
|
|
744
|
+
// only withholds the optional protocol: build execution still runs such
|
|
745
|
+
// a host and observes it from outside, never rejecting it.
|
|
741
746
|
capabilities:
|
|
742
747
|
record.stage === "transform" &&
|
|
743
748
|
record.kind === "linked" &&
|
|
@@ -1436,9 +1441,13 @@ class CommonJsDescriptorLoadError extends Error {
|
|
|
1436
1441
|
function loadCommonJsDescriptor(
|
|
1437
1442
|
request: string,
|
|
1438
1443
|
context: ITtscPluginFactoryContext,
|
|
1439
|
-
|
|
1444
|
+
loadEnv: NodeJS.ProcessEnv,
|
|
1440
1445
|
descriptorCache: DescriptorCacheOptions,
|
|
1441
1446
|
): IsolatedPluginDescriptor {
|
|
1447
|
+
// The evaluator is ttsc's own helper: inside a ttsx run it gets the user's
|
|
1448
|
+
// NODE_OPTIONS, not ttsx's preloads, which would refuse the descriptor cache
|
|
1449
|
+
// and run in every evaluation (#1740). The runtime probe below does the same.
|
|
1450
|
+
const effectiveEnv = TtsxNodeOptions.forHelpers(loadEnv);
|
|
1442
1451
|
const runtime = pluginDescriptorRuntimeBinary(effectiveEnv);
|
|
1443
1452
|
const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
|
|
1444
1453
|
const runtimeCapabilities = javascriptRuntimeCapabilities(
|
|
@@ -2347,6 +2356,7 @@ function pluginBuildDirectories(
|
|
|
2347
2356
|
env: NodeJS.ProcessEnv,
|
|
2348
2357
|
replacements?: Map<string, readonly string[]>,
|
|
2349
2358
|
readers?: Map<string, SourcePluginWorkspace.GoModReader>,
|
|
2359
|
+
identities?: PluginContentIdentities.Store,
|
|
2350
2360
|
): string[] {
|
|
2351
2361
|
const directories = new Set<string>();
|
|
2352
2362
|
for (const record of records) {
|
|
@@ -2361,6 +2371,7 @@ function pluginBuildDirectories(
|
|
|
2361
2371
|
env,
|
|
2362
2372
|
replacements,
|
|
2363
2373
|
readers,
|
|
2374
|
+
identities,
|
|
2364
2375
|
))
|
|
2365
2376
|
directories.add(directory);
|
|
2366
2377
|
}
|
|
@@ -2380,17 +2391,20 @@ function pluginReplacementWatchDirectories(
|
|
|
2380
2391
|
env: NodeJS.ProcessEnv,
|
|
2381
2392
|
observed?: Map<string, readonly string[]>,
|
|
2382
2393
|
readers?: Map<string, SourcePluginWorkspace.GoModReader>,
|
|
2394
|
+
identities?: PluginContentIdentities.Store,
|
|
2383
2395
|
): readonly string[] {
|
|
2384
2396
|
const previous = observed?.get(moduleRoot);
|
|
2385
2397
|
if (previous !== undefined) return previous;
|
|
2386
2398
|
let directories: readonly string[];
|
|
2387
2399
|
try {
|
|
2400
|
+
// The load's store goes with the reader this registers first (#1739).
|
|
2388
2401
|
directories = pluginModuleReplaceDirectories(
|
|
2389
2402
|
moduleRoot,
|
|
2390
2403
|
env,
|
|
2391
2404
|
undefined,
|
|
2392
2405
|
undefined,
|
|
2393
2406
|
readers,
|
|
2407
|
+
identities,
|
|
2394
2408
|
).map((replacement) => replacement.directory);
|
|
2395
2409
|
} catch {
|
|
2396
2410
|
// An unreadable manifest/tool is not valid metadata. The already observed
|
|
@@ -30,13 +30,19 @@ export function resolveNativeSource(
|
|
|
30
30
|
plugin: ITtscPlugin,
|
|
31
31
|
config: ITtscProjectPluginConfig,
|
|
32
32
|
index: number,
|
|
33
|
-
options?: {
|
|
33
|
+
options?: {
|
|
34
|
+
env?: NodeJS.ProcessEnv;
|
|
35
|
+
observation?: NativeSourcePackages.Package;
|
|
36
|
+
},
|
|
34
37
|
): { kind: "executable" | "linked"; moduleRoot: string } {
|
|
35
38
|
const label = pluginLabel(plugin, config, index);
|
|
36
39
|
requirePluginSource(source, label);
|
|
37
40
|
const { moduleRoot } = resolvePluginGoModule(source, label);
|
|
38
|
-
const observation =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const observation =
|
|
42
|
+
options?.observation ??
|
|
43
|
+
NativeSourcePackages.propose(
|
|
44
|
+
[{ source, label, ownModule: plugin.stage === "check" }],
|
|
45
|
+
SidecarEnvironment.merge(options?.env ?? process.env),
|
|
46
|
+
)[0]!.observation;
|
|
41
47
|
return { kind: NativeSourcePackages.kind(observation, label), moduleRoot };
|
|
42
48
|
}
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { resolvePhysicalPath } from "../../../internal/pathIdentity/resolvePhysicalPath";
|
|
5
5
|
import { GoToolResolution } from "./GoToolResolution";
|
|
6
6
|
import type { IPluginModuleReplaceDirectory } from "./IPluginModuleReplaceDirectory";
|
|
7
|
+
import type { PluginContentIdentities } from "./PluginContentIdentities";
|
|
7
8
|
import { SourcePluginWorkspace } from "./SourcePluginWorkspace";
|
|
8
9
|
import { resolveGoCompiler } from "./resolveGoCompiler";
|
|
9
10
|
import { selectPluginModuleReplaceDirectories } from "./selectPluginModuleReplaceDirectories";
|
|
@@ -30,6 +31,8 @@ import { selectPluginModuleReplaceDirectories } from "./selectPluginModuleReplac
|
|
|
30
31
|
* @param env The build's effective environment.
|
|
31
32
|
* @param goBinary The Go tool the build runs, or `undefined` to resolve it as
|
|
32
33
|
* the build does.
|
|
34
|
+
* @param identities The load's record store, carried by a reader this call
|
|
35
|
+
* registers so the load's later reads reuse recorded syntax.
|
|
33
36
|
* @returns Each replacement outside the module, sorted by module path: the
|
|
34
37
|
* replaced module path and version, the target as `go.mod` spells it, and the
|
|
35
38
|
* target's absolute path.
|
|
@@ -52,6 +55,7 @@ export function pluginModuleReplaceDirectories(
|
|
|
52
55
|
goBinary?: string,
|
|
53
56
|
reader?: SourcePluginWorkspace.GoModReader,
|
|
54
57
|
readers?: Map<string, SourcePluginWorkspace.GoModReader>,
|
|
58
|
+
identities?: PluginContentIdentities.Store,
|
|
55
59
|
): IPluginModuleReplaceDirectory[] {
|
|
56
60
|
const root = path.resolve(moduleRoot);
|
|
57
61
|
let text: string;
|
|
@@ -72,7 +76,12 @@ export function pluginModuleReplaceDirectories(
|
|
|
72
76
|
root,
|
|
73
77
|
);
|
|
74
78
|
const parsed = (
|
|
75
|
-
reader ??
|
|
79
|
+
reader ??
|
|
80
|
+
// WARNING (#1739): the first reader registered for a Go binary serves the
|
|
81
|
+
// whole load, so it must carry the load's record store, or every later
|
|
82
|
+
// reader request of the load gets a store-less one and the go.mod syntax
|
|
83
|
+
// records are never read or written.
|
|
84
|
+
SourcePluginWorkspace.createGoModReader(go, root, env, readers, identities)
|
|
76
85
|
).read(root);
|
|
77
86
|
// Parsed syntax may be shared; physical containment is current native state
|
|
78
87
|
// and must be recomputed even when these manifest bytes are unchanged.
|
|
@@ -86,8 +86,8 @@ export interface TtscCommonOptions {
|
|
|
86
86
|
}[];
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
|
-
* Retained native compiler argument base when project selection redirects
|
|
90
|
-
*
|
|
89
|
+
* Retained native compiler argument base when project selection redirects the
|
|
90
|
+
* Program to a different root. Absent retains the selected project root.
|
|
91
91
|
* Response frames and relative native options use this base; plugin/rule
|
|
92
92
|
* context and config-relative paths retain their separate project authority.
|
|
93
93
|
*/
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
package graphsymbols
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"testing"
|
|
5
|
-
"unicode/utf8"
|
|
6
|
-
|
|
7
|
-
"github.com/samchon/ttsc/packages/ttsc/internal/graph"
|
|
8
|
-
"github.com/samchon/ttsc/packages/ttsc/internal/lspserver"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
// TestPositionHelpersFollowECMALineTerminators verifies graph-backed LSP
|
|
12
|
-
// positions use the compiler's LF, CRLF, CR, LS, and PS line boundaries.
|
|
13
|
-
//
|
|
14
|
-
// An offset-to-position helper that counted only LF while its inverse counted
|
|
15
|
-
// CR too would map an editor cursor to a graph offset that returns on a
|
|
16
|
-
// different line. Literal starts and ends establish three authored logical
|
|
17
|
-
// lines; the test walks their UTF-8 boundaries, including an emoji, and requires
|
|
18
|
-
// a round trip. Columns are not compared to literal UTF-16 counts, so symmetric
|
|
19
|
-
// column mistakes can pass. No editor/server request is exercised.
|
|
20
|
-
//
|
|
21
|
-
// 1. Build three lines with each ECMAScript terminator.
|
|
22
|
-
// 2. Enumerate every valid cursor boundary before each terminator.
|
|
23
|
-
// 3. Convert each offset to UTF-16 LSP position and back to the same offset.
|
|
24
|
-
//
|
|
25
|
-
// @evidence contracts/testing.md#behavioral-verification Verifies graph-backed LSP positions use the compiler's LF, CRLF, CR, LS, and PS line boundaries.
|
|
26
|
-
// @evidence contracts/testing.md#independent-expectations Each case embeds one ECMAScript terminator (LF, CRLF, CR, LS or PS) in a three-line literal, so the expected line count (three) and the line of every offset follow from the language's line-terminator definition. Columns are checked only by an offset -> position -> offset round trip over every UTF-8 rune boundary (including the two-unit emoji), not against literal UTF-16 column numbers, so a column error made symmetrically by both helpers would not be detected.
|
|
27
|
-
// @evidence contracts/testing.md#distinguishing-cases Build three lines with each ECMAScript terminator; Enumerate every valid cursor boundary before each terminator; Convert each offset to UTF-16 LSP position and back to the same offset; the five terminator subtests differ only in the terminator, and a position on the line index just past the last line must not resolve (negative case). No empty-text or out-of-range-column input is exercised here.
|
|
28
|
-
// @evidence contracts/testing.md#execution-ownership Directly calls the maintained line and position helpers on authored UTF-8 strings in this process. Literal byte boundaries establish enumeration; round-trip column expectations share the two converters and are not a separate UTF-16 oracle. It creates no native fixture, loads no Program, installs no consumer, and starts no product process or editor/server connection.
|
|
29
|
-
func TestPositionHelpersFollowECMALineTerminators(t *testing.T) {
|
|
30
|
-
cases := []struct {
|
|
31
|
-
name string
|
|
32
|
-
terminator string
|
|
33
|
-
}{
|
|
34
|
-
{name: "LF", terminator: "\n"},
|
|
35
|
-
{name: "CRLF", terminator: "\r\n"},
|
|
36
|
-
{name: "CR", terminator: "\r"},
|
|
37
|
-
{name: "LS", terminator: "\u2028"},
|
|
38
|
-
{name: "PS", terminator: "\u2029"},
|
|
39
|
-
}
|
|
40
|
-
for _, tc := range cases {
|
|
41
|
-
t.Run(tc.name, func(t *testing.T) {
|
|
42
|
-
text := "alpha😀" + tc.terminator + "beta" + tc.terminator + "gamma"
|
|
43
|
-
starts := graph.ECMALineStarts(text)
|
|
44
|
-
if len(starts) != 3 {
|
|
45
|
-
t.Fatalf("line starts = %v, want three lines", starts)
|
|
46
|
-
}
|
|
47
|
-
expectedStarts := []int{0, 9 + len(tc.terminator), 13 + 2*len(tc.terminator)}
|
|
48
|
-
expectedEnds := []int{9, 13 + len(tc.terminator), len(text)}
|
|
49
|
-
for line, start := range starts {
|
|
50
|
-
end := graph.LineEnd(text, starts, line)
|
|
51
|
-
if start != expectedStarts[line] || end != expectedEnds[line] {
|
|
52
|
-
t.Fatalf("line %d boundaries = (%d, %d), want (%d, %d)", line, start, end, expectedStarts[line], expectedEnds[line])
|
|
53
|
-
}
|
|
54
|
-
for offset := start; ; {
|
|
55
|
-
position := offsetToPosition(text, offset)
|
|
56
|
-
if position.Line != line {
|
|
57
|
-
t.Fatalf("offset %d position line = %d, want %d", offset, position.Line, line)
|
|
58
|
-
}
|
|
59
|
-
restored, ok := lspPositionToOffset(text, position)
|
|
60
|
-
if !ok || restored != offset {
|
|
61
|
-
t.Fatalf("offset %d -> %+v -> (%d, %t), want itself", offset, position, restored, ok)
|
|
62
|
-
}
|
|
63
|
-
if offset == end {
|
|
64
|
-
break
|
|
65
|
-
}
|
|
66
|
-
_, size := utf8.DecodeRuneInString(text[offset:])
|
|
67
|
-
if size == 0 {
|
|
68
|
-
t.Fatal("unexpected zero-width UTF-8 rune")
|
|
69
|
-
}
|
|
70
|
-
offset += size
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if _, ok := lspPositionToOffset(text, lspserver.LSPPosition{Line: len(starts), Character: 0}); ok {
|
|
74
|
-
t.Fatal("position on a nonexistent source line must not resolve")
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
}
|