Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions src/extensions/default/TypeScriptSupport/CodeIntelligence.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ define(function (require, exports, module) {
// row then offers to re-enable.
const PREF_CREATED = "tsCodeIntel.created";

// Global user preference: set false to stop auto-creating configs in new projects entirely
// (surfaced both in the preferences file and as a checkbox in the config settings panel).
const PREF_AUTO_CREATE = "codeIntel.autoCreateConfig";
PreferencesManager.definePreference(PREF_AUTO_CREATE, "boolean", true, {
description: Strings.DESCRIPTION_CODE_INTEL_AUTO_CREATE
});

// "Learn more" -> the TypeScript/JavaScript config reference (documents every compilerOption in
// the jsconfig.json we generate: module, target, moduleResolution, checkJs, jsx, ...).
const DOCS_URL = "https://www.typescriptlang.org/tsconfig/";
Expand Down Expand Up @@ -93,19 +100,37 @@ define(function (require, exports, module) {
};
}

// Modern, type-error-free defaults. `jsx: "react"` only affects .jsx/.tsx, harmless elsewhere.
// One UNIVERSAL, permissive template - deliberately not a per-flavor detection matrix. It has
// to serve editor intelligence (never builds) across every JS flavor a project may use:
// - module "preserve" (TS 5.4+): resolves BOTH `import` and `require()` and never demands file
// extensions on relative imports (nodenext would, breaking go-to-def in extensionless ESM JS);
// implies bundler moduleResolution + esModuleInterop + resolveJsonModule. Per-file CJS-vs-ESM
// classification stays driven by file extension + nearest package.json "type" regardless - so
// Node-CJS, Node-ESM, bundler and browser projects all resolve under this one setting.
// - target "esnext" with no `lib` includes DOM by default -> browser globals just work.
// - jsx "react-jsx": modern automatic runtime, no "Cannot find name 'React'" friction.
// - allowUmdGlobalAccess: module files may reference UMD/browser globals (jQuery-style) without
// imports - an intelligence win for browser/UMD projects, acceptable looseness for an
// editor-only, checkJs:false-by-default config.
// - typeAcquisition.enable: THE critical line. ATA (tsserver auto-fetching @types/node and types
// for package.json deps via npm, even with no node_modules) defaults ON for jsconfig but OFF
// for tsconfig - without this, the jsconfig->tsconfig upgrade would silently kill Node
// builtin/require("pkg") IntelliSense. Explicit on both file types; degrades gracefully to
// locally installed @types when npm/network are unavailable.
// Known limitation: tsserver cannot infer AMD/RequireJS-style modules cross-file (no config
// fixes that); users can still add their own paths/baseUrl, which the preserve-merge keeps.
// compilerOptions from an existing managed config being rewritten/upgraded are preserved over
// the defaults; `checkJs` (TypeScript-grade type checking of JS) is applied only when the caller
// passes it, else the preserved value stands. tsconfig.json - unlike editor-only jsconfig - is
// read by real build tools, so it additionally gets allowJs (JS files stay first-class in mixed
// projects) and noEmit (an accidental `npx tsc` must never emit files next to sources).
// the defaults; `checkJs` is applied only when the caller passes it, else the preserved value
// stands. tsconfig.json - unlike editor-only jsconfig - is read by real build tools, so it
// additionally gets allowJs (JS files stay first-class in mixed projects) and noEmit (an
// accidental `npx tsc` must never emit files next to sources).
function _configContent(fileName, existingCompilerOptions, checkJs) {
const compilerOptions = Object.assign({
module: "esnext",
module: "preserve",
target: "esnext",
moduleResolution: "bundler",
checkJs: false,
jsx: "react"
jsx: "react-jsx",
allowUmdGlobalAccess: true
}, existingCompilerOptions || {});
if (checkJs !== undefined) {
compilerOptions.checkJs = !!checkJs;
Expand All @@ -117,7 +142,8 @@ define(function (require, exports, module) {
return {
autoGeneratedByPhoenixCode: _marker(),
compilerOptions: compilerOptions,
exclude: ["node_modules", "dist", "build"]
typeAcquisition: { enable: true },
exclude: ["node_modules", "bower_components", "dist", "build"]
};
}

Expand Down Expand Up @@ -447,6 +473,9 @@ define(function (require, exports, module) {
if (Phoenix.isTestWindow) {
return; // never write configs from a test window - it would pollute fixtures
}
if (PreferencesManager.get(PREF_AUTO_CREATE) === false) {
return; // the user opted out of auto-creation (managing existing configs is unaffected)
}
if (!editor || !editor.document) {
return;
}
Expand Down Expand Up @@ -563,6 +592,8 @@ define(function (require, exports, module) {

exports.init = init;
exports.promptEnable = promptEnable;
exports.PREF_AUTO_CREATE = PREF_AUTO_CREATE;
exports.DOCS_URL = DOCS_URL;
// exposed for unit tests (pure function; the event-driven flow never runs in test windows)
exports._configContent = _configContent;
});
Loading
Loading