tsifdef 1.1.8

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 (71) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/CHANGELOG.zh-CN.md +22 -0
  3. package/CONTRIBUTING.md +52 -0
  4. package/INTEGRATION.md +166 -0
  5. package/INTEGRATION.zh-CN.md +159 -0
  6. package/LICENSE +210 -0
  7. package/README.md +150 -0
  8. package/README.zh-CN.md +141 -0
  9. package/SECURITY.md +15 -0
  10. package/assets/icon-mono.svg +15 -0
  11. package/assets/icon.png +0 -0
  12. package/assets/icon.svg +16 -0
  13. package/dist/cli/build.d.ts +70 -0
  14. package/dist/cli/build.js +298 -0
  15. package/dist/cli/config.d.ts +30 -0
  16. package/dist/cli/config.js +135 -0
  17. package/dist/cli/diagnostics.d.ts +3 -0
  18. package/dist/cli/diagnostics.js +31 -0
  19. package/dist/cli/index.d.ts +6 -0
  20. package/dist/cli/index.js +35 -0
  21. package/dist/cli/main.d.ts +9 -0
  22. package/dist/cli/main.js +165 -0
  23. package/dist/cli/precompile.d.ts +38 -0
  24. package/dist/cli/precompile.js +192 -0
  25. package/dist/cli/source-files.d.ts +10 -0
  26. package/dist/cli/source-files.js +75 -0
  27. package/dist/cli/watch.d.ts +34 -0
  28. package/dist/cli/watch.js +183 -0
  29. package/dist/core/conditional.d.ts +18 -0
  30. package/dist/core/conditional.js +126 -0
  31. package/dist/core/expression.d.ts +44 -0
  32. package/dist/core/expression.js +224 -0
  33. package/dist/core/index.d.ts +7 -0
  34. package/dist/core/index.js +37 -0
  35. package/dist/core/projection.d.ts +15 -0
  36. package/dist/core/projection.js +99 -0
  37. package/dist/core/scanner.d.ts +33 -0
  38. package/dist/core/scanner.js +344 -0
  39. package/dist/eslint/package.d.ts +10 -0
  40. package/dist/eslint/package.js +55 -0
  41. package/dist/eslint/parser.d.ts +35 -0
  42. package/dist/eslint/parser.js +59 -0
  43. package/dist/eslint/plugin.d.ts +78 -0
  44. package/dist/eslint/plugin.js +229 -0
  45. package/dist/eslint/projection.d.ts +11 -0
  46. package/dist/eslint/projection.js +116 -0
  47. package/dist/tsserver/host-projection.d.ts +45 -0
  48. package/dist/tsserver/host-projection.js +160 -0
  49. package/dist/tsserver/index.d.ts +3 -0
  50. package/dist/tsserver/index.js +32 -0
  51. package/dist/tsserver/plugin.d.ts +15 -0
  52. package/dist/tsserver/plugin.js +129 -0
  53. package/dist/tsserver/project-controller.d.ts +37 -0
  54. package/dist/tsserver/project-controller.js +60 -0
  55. package/dist/version.d.ts +3 -0
  56. package/dist/version.js +20 -0
  57. package/dist/vscode/document-analysis.d.ts +62 -0
  58. package/dist/vscode/document-analysis.js +111 -0
  59. package/dist/vscode/extension.d.ts +133 -0
  60. package/dist/vscode/extension.js +241 -0
  61. package/dist/vscode/host.d.ts +79 -0
  62. package/dist/vscode/host.js +16 -0
  63. package/dist/vscode/index.d.ts +7 -0
  64. package/dist/vscode/index.js +36 -0
  65. package/dist/vscode/macro-presentation.d.ts +43 -0
  66. package/dist/vscode/macro-presentation.js +130 -0
  67. package/dist/vscode/package-profile.d.ts +27 -0
  68. package/dist/vscode/package-profile.js +142 -0
  69. package/dist/vscode/profile-state.d.ts +22 -0
  70. package/dist/vscode/profile-state.js +81 -0
  71. package/package.json +129 -0
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ // Copyright (C) 2026 Tencent. All rights reserved.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.PackageProfileController = void 0;
17
+ const config_js_1 = require("../cli/config.js");
18
+ /** Coalesce watcher bursts (atomic writes fire several events) into one reload. */
19
+ const RELOAD_DEBOUNCE_MS = 150;
20
+ /** Retries for a transient read miss while an atomic write swaps the file in. */
21
+ const READ_RETRIES = 5;
22
+ const READ_RETRY_DELAY_MS = 60;
23
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
24
+ /** Watches the package-owned Profile pointer and synchronizes all editor consumers. */
25
+ class PackageProfileController {
26
+ host;
27
+ state;
28
+ onDefinitions;
29
+ watcher;
30
+ debounceTimer;
31
+ appliedIdentity;
32
+ initialized = false;
33
+ constructor(host, state, onDefinitions) {
34
+ this.host = host;
35
+ this.state = state;
36
+ this.onDefinitions = onDefinitions;
37
+ }
38
+ activate() {
39
+ // Debounce watcher events: an atomic write (temp file + rename) emits a
40
+ // burst, and reacting to each one caused a reload/refresh storm.
41
+ this.watcher = this.host.watchProjectConfiguration(() => this.scheduleReload());
42
+ void this.reload();
43
+ }
44
+ dispose() {
45
+ if (this.debounceTimer !== undefined)
46
+ clearTimeout(this.debounceTimer);
47
+ this.debounceTimer = undefined;
48
+ this.watcher?.dispose();
49
+ this.watcher = undefined;
50
+ }
51
+ scheduleReload() {
52
+ if (this.debounceTimer !== undefined)
53
+ clearTimeout(this.debounceTimer);
54
+ this.debounceTimer = setTimeout(() => {
55
+ this.debounceTimer = undefined;
56
+ void this.reload();
57
+ }, RELOAD_DEBOUNCE_MS);
58
+ }
59
+ async reload() {
60
+ const root = this.host.workspaceRoot();
61
+ if (root === undefined) {
62
+ this.onDefinitions(undefined);
63
+ this.state.setProfile(undefined);
64
+ await this.applyTypeScriptProfile("none", {});
65
+ return;
66
+ }
67
+ let profilePath;
68
+ try {
69
+ const configuration = await (0, config_js_1.discoverProjectConfiguration)(root);
70
+ if (configuration === undefined) {
71
+ this.onDefinitions(undefined);
72
+ this.state.setProfile(undefined);
73
+ await this.applyTypeScriptProfile("none", {});
74
+ return;
75
+ }
76
+ profilePath = configuration.profilePath;
77
+ const profile = await this.loadProfileWithRetry(profilePath);
78
+ const token = profileToken(profile.definitions);
79
+ this.onDefinitions(profile.definitions);
80
+ this.state.setProfile(profilePath);
81
+ const pluginConfiguration = {
82
+ profileFile: profilePath,
83
+ profileToken: token,
84
+ };
85
+ await this.applyTypeScriptProfile(`${profilePath}:${token}`, pluginConfiguration);
86
+ }
87
+ catch (error) {
88
+ this.onDefinitions(undefined);
89
+ const message = `Failed to load TSIfDef project configuration${profilePath === undefined ? "" : ` '${profilePath}'`}: ${error instanceof Error ? error.message : String(error)}`;
90
+ this.state.setProfile(profilePath, message);
91
+ await this.applyTypeScriptProfile("none", {});
92
+ this.host.showErrorMessage(message);
93
+ }
94
+ }
95
+ async applyTypeScriptProfile(nextIdentity, pluginConfiguration) {
96
+ const firstValidProfile = !this.initialized && nextIdentity !== "none";
97
+ const changed = this.initialized && this.appliedIdentity !== nextIdentity;
98
+ this.appliedIdentity = nextIdentity;
99
+ this.initialized = true;
100
+ await this.host.configureTypeScriptPlugin("tsifdef-tsserver", pluginConfiguration);
101
+ if (!firstValidProfile && !changed) {
102
+ return;
103
+ }
104
+ // VSCode 启动时可能先恢复并诊断已打开文档,再完成插件配置。首次加载有效
105
+ // Profile 和后续 Profile 变化都走完整刷新,保证已有诊断经过 TSIfDef。
106
+ await this.host.restartTypeScriptServer();
107
+ await this.host.configureTypeScriptPlugin("tsifdef-tsserver", pluginConfiguration);
108
+ await this.host.reloadTypeScriptProjects();
109
+ }
110
+ /**
111
+ * Load the Profile, retrying a few times on a transient failure. An atomic
112
+ * writer (temp file + rename) briefly leaves the path missing; reacting to
113
+ * that momentary miss made the Profile flap to "none" and back, restarting
114
+ * the server in a loop.
115
+ */
116
+ async loadProfileWithRetry(profilePath) {
117
+ let lastError;
118
+ for (let attempt = 0; attempt <= READ_RETRIES; attempt += 1) {
119
+ try {
120
+ return await (0, config_js_1.loadProfileFile)(profilePath);
121
+ }
122
+ catch (error) {
123
+ lastError = error;
124
+ if (attempt < READ_RETRIES)
125
+ await delay(READ_RETRY_DELAY_MS);
126
+ }
127
+ }
128
+ throw lastError;
129
+ }
130
+ }
131
+ exports.PackageProfileController = PackageProfileController;
132
+ /** A stable token that changes whenever the enabled macro set changes. */
133
+ function profileToken(definitions) {
134
+ const names = Object.keys(definitions).sort().join(",");
135
+ let hash = 2166136261;
136
+ for (let index = 0; index < names.length; index += 1) {
137
+ hash ^= names.charCodeAt(index);
138
+ hash = Math.imul(hash, 16777619);
139
+ }
140
+ return (hash >>> 0).toString(16);
141
+ }
142
+ //# sourceMappingURL=package-profile.js.map
@@ -0,0 +1,22 @@
1
+ import type { ExtensionHost } from "./host.js";
2
+ export declare const activeProfileCommand: "tsifdef.activeProfile";
3
+ export interface EffectiveProfile {
4
+ readonly profile: string | undefined;
5
+ readonly source: "package.json" | undefined;
6
+ }
7
+ /** Presents the package-selected Profile; package.json remains the only state source. */
8
+ export declare class ProfileStateController {
9
+ private readonly host;
10
+ private statusItem;
11
+ private profile;
12
+ private loadError;
13
+ private readonly disposables;
14
+ constructor(host: ExtensionHost);
15
+ activate(): void;
16
+ dispose(): void;
17
+ effectiveProfile(): EffectiveProfile;
18
+ setProfile(profile: string | undefined, error?: string): void;
19
+ activeProfilePath(): string;
20
+ private refresh;
21
+ }
22
+ //# sourceMappingURL=profile-state.d.ts.map
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ // Copyright (C) 2026 Tencent. All rights reserved.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.ProfileStateController = exports.activeProfileCommand = void 0;
17
+ const node_path_1 = require("node:path");
18
+ exports.activeProfileCommand = "tsifdef.activeProfile";
19
+ function profileFileName(profile) {
20
+ return (0, node_path_1.basename)(profile.replaceAll("\\", "/"));
21
+ }
22
+ /** Presents the package-selected Profile; package.json remains the only state source. */
23
+ class ProfileStateController {
24
+ host;
25
+ statusItem;
26
+ profile;
27
+ loadError;
28
+ disposables = [];
29
+ constructor(host) {
30
+ this.host = host;
31
+ }
32
+ activate() {
33
+ this.statusItem = this.host.createStatusBarItem();
34
+ this.disposables.push(this.statusItem);
35
+ this.disposables.push(this.host.registerCommand(exports.activeProfileCommand, () => this.activeProfilePath()));
36
+ this.refresh();
37
+ }
38
+ dispose() {
39
+ for (const disposable of this.disposables.splice(0).reverse())
40
+ disposable.dispose();
41
+ this.statusItem = undefined;
42
+ }
43
+ effectiveProfile() {
44
+ return { profile: this.profile, source: this.profile === undefined ? undefined : "package.json" };
45
+ }
46
+ setProfile(profile, error) {
47
+ this.profile = profile;
48
+ this.loadError = error;
49
+ this.refresh();
50
+ }
51
+ activeProfilePath() {
52
+ if (this.profile === undefined)
53
+ throw new Error("No TSIfDef Profile is selected in package.json.");
54
+ return this.profile;
55
+ }
56
+ refresh() {
57
+ if (this.statusItem === undefined)
58
+ return;
59
+ if (this.profile === undefined) {
60
+ this.statusItem.text = "$(versions) TSIfDef: none";
61
+ this.statusItem.tooltip = this.loadError ?? "No package.json TSIfDef Profile is available.";
62
+ if (this.loadError === undefined) {
63
+ this.statusItem.hide();
64
+ }
65
+ else {
66
+ this.statusItem.show();
67
+ }
68
+ return;
69
+ }
70
+ this.statusItem.show();
71
+ if (this.loadError !== undefined) {
72
+ this.statusItem.text = `$(error) TSIfDef: ${profileFileName(this.profile)} (unavailable)`;
73
+ this.statusItem.tooltip = this.loadError;
74
+ return;
75
+ }
76
+ this.statusItem.text = `$(versions) TSIfDef: ${profileFileName(this.profile)}`;
77
+ this.statusItem.tooltip = `TSIfDef Profile '${this.profile}' from package.json.`;
78
+ }
79
+ }
80
+ exports.ProfileStateController = ProfileStateController;
81
+ //# sourceMappingURL=profile-state.js.map
package/package.json ADDED
@@ -0,0 +1,129 @@
1
+ {
2
+ "name": "tsifdef",
3
+ "version": "1.1.8",
4
+ "description": "Source-level conditional compilation for TypeScript",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Tencent/TSIfDef.git"
9
+ },
10
+ "homepage": "https://github.com/Tencent/TSIfDef#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/Tencent/TSIfDef/issues"
13
+ },
14
+ "keywords": [
15
+ "typescript",
16
+ "conditional-compilation",
17
+ "preprocessor",
18
+ "vscode",
19
+ "eslint"
20
+ ],
21
+ "files": [
22
+ "assets/",
23
+ "dist/**/*.d.ts",
24
+ "dist/**/*.js",
25
+ "CHANGELOG.md",
26
+ "CHANGELOG.zh-CN.md",
27
+ "CONTRIBUTING.md",
28
+ "INTEGRATION.md",
29
+ "INTEGRATION.zh-CN.md",
30
+ "LICENSE",
31
+ "README.md",
32
+ "README.zh-CN.md",
33
+ "SECURITY.md"
34
+ ],
35
+ "main": "dist/vscode/extension.js",
36
+ "types": "dist/eslint/package.d.ts",
37
+ "publisher": "tencent",
38
+ "displayName": "TSIfDef",
39
+ "icon": "assets/icon.png",
40
+ "bin": {
41
+ "tsifdef": "dist/cli/main.js"
42
+ },
43
+ "exports": {
44
+ ".": {
45
+ "types": "./dist/eslint/package.d.ts",
46
+ "require": "./dist/eslint/package.js",
47
+ "default": "./dist/eslint/package.js"
48
+ },
49
+ "./core": {
50
+ "types": "./dist/core/index.d.ts",
51
+ "require": "./dist/core/index.js",
52
+ "default": "./dist/core/index.js"
53
+ },
54
+ "./eslint-plugin": {
55
+ "types": "./dist/eslint/plugin.d.ts",
56
+ "require": "./dist/eslint/plugin.js",
57
+ "default": "./dist/eslint/plugin.js"
58
+ },
59
+ "./eslint-parser": {
60
+ "types": "./dist/eslint/parser.d.ts",
61
+ "require": "./dist/eslint/parser.js",
62
+ "default": "./dist/eslint/parser.js"
63
+ },
64
+ "./parser": {
65
+ "types": "./dist/eslint/parser.d.ts",
66
+ "require": "./dist/eslint/parser.js",
67
+ "default": "./dist/eslint/parser.js"
68
+ }
69
+ },
70
+ "engines": {
71
+ "node": ">=18.17",
72
+ "vscode": "^1.85.0"
73
+ },
74
+ "activationEvents": [
75
+ "onLanguage:typescript",
76
+ "onLanguage:typescriptreact"
77
+ ],
78
+ "contributes": {
79
+ "commands": [],
80
+ "typescriptServerPlugins": [
81
+ {
82
+ "name": "tsifdef-tsserver",
83
+ "enableForWorkspaceTypeScriptVersions": true
84
+ }
85
+ ]
86
+ },
87
+ "scripts": {
88
+ "sync-version": "node scripts/sync-version.cjs",
89
+ "clean": "node -e \"const fs=require('node:fs'); for (const path of ['dist','.test-dist']) fs.rmSync(path,{recursive:true,force:true})\"",
90
+ "build": "npm run sync-version && npm run clean && tsc -p tsconfig.build.json",
91
+ "prepare-tsserver-plugin": "node scripts/prepare-tsserver-plugin.cjs",
92
+ "typecheck": "tsc -p tsconfig.json",
93
+ "test": "npm run build && tsc -p tsconfig.test.json && node scripts/run-tests.cjs",
94
+ "vscode:prepublish": "npm run build && npm run prepare-tsserver-plugin",
95
+ "package:tgz": "npm run build && npm pack --pack-destination release",
96
+ "package:vsix": "node scripts/release.cjs --vsix-only",
97
+ "release": "npm run sync-version && node scripts/release.cjs"
98
+ },
99
+ "devDependencies": {
100
+ "@types/node": "22.15.3",
101
+ "@typescript-eslint/parser": "5.62.0",
102
+ "@vscode/vsce": "3.9.2",
103
+ "eslint": "8.57.1",
104
+ "eslint9": "npm:eslint@9.39.5",
105
+ "eslint-plugin-import": "2.32.0",
106
+ "ovsx": "1.2.0",
107
+ "typescript-eslint-parser6": "npm:@typescript-eslint/parser@6.21.0",
108
+ "typescript-eslint-parser7": "npm:@typescript-eslint/parser@7.18.0",
109
+ "typescript-eslint-parser8": "npm:@typescript-eslint/parser@8.70.0",
110
+ "tsifdef-tsserver": "file:./scripts/packaging/tsserver",
111
+ "yauzl": "^3.4.0",
112
+ "yazl": "^2.5.1"
113
+ },
114
+ "peerDependencies": {
115
+ "@typescript-eslint/parser": "^5.62.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
116
+ "eslint": "^8.57.0 || ^9.0.0"
117
+ },
118
+ "peerDependenciesMeta": {
119
+ "@typescript-eslint/parser": {
120
+ "optional": true
121
+ },
122
+ "eslint": {
123
+ "optional": true
124
+ }
125
+ },
126
+ "dependencies": {
127
+ "typescript": "5.5.4"
128
+ }
129
+ }