flaglint 0.5.1 → 0.5.2

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/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## [0.5.2] - 2026-05-27
11
+
12
+ ### Fixed
13
+
14
+ - Fixed LaunchDarkly client provenance for aliased named `init` imports from both
15
+ supported Node.js server SDK package names. Calls initialized via
16
+ `import { init as ldInit } from "@launchdarkly/node-server-sdk"` or legacy
17
+ `launchdarkly-node-server-sdk` are now consistently detected by `scan`,
18
+ enforced by `validate --no-direct-launchdarkly`, emitted in validation SARIF,
19
+ and handled by existing guarded migration dry-run/apply flows.
20
+ - No migration safety boundary changed: `migrate --apply` still requires a proven
21
+ OpenFeature client binding and continues to skip dynamic keys, detail
22
+ evaluations, bulk calls, unknown fallbacks, and ambiguous cases.
23
+
10
24
  ## [0.5.1] - 2026-05-27
11
25
 
12
26
  ### Fixed
package/README.md CHANGED
@@ -440,8 +440,8 @@ reviewers see them in the PR without running anything locally.
440
440
 
441
441
  Validated against 120 deterministic benchmark cases within the supported LaunchDarkly Node.js server-side SDK scope. 100% precision and recall are limited to those 120 tested cases and to the Node.js server-side SDK call patterns explicitly listed in the Supported API matrix above.
442
442
 
443
- Detection is AST-based, not regex: client binding patterns, import aliases, and CJS require
444
- forms are resolved before matching.
443
+ Detection is AST-based, not regex: client binding patterns, named `init` import aliases,
444
+ OpenFeature import aliases, and CJS require forms are resolved before matching.
445
445
 
446
446
  ---
447
447
 
@@ -178,6 +178,7 @@ function walk(root, visit) {
178
178
  }
179
179
  function collectLDClients(ast) {
180
180
  const ldNamespaces = /* @__PURE__ */ new Set();
181
+ const ldInitFunctions = /* @__PURE__ */ new Set();
181
182
  for (const stmt of ast.body) {
182
183
  if (stmt.type === "ImportDeclaration") {
183
184
  const importDecl = stmt;
@@ -186,6 +187,12 @@ function collectLDClients(ast) {
186
187
  if (spec.type === "ImportNamespaceSpecifier" || spec.type === "ImportDefaultSpecifier") {
187
188
  ldNamespaces.add(spec.local.name);
188
189
  }
190
+ if (spec.type === "ImportSpecifier") {
191
+ const importedName = spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value;
192
+ if (importedName === "init") {
193
+ ldInitFunctions.add(spec.local.name);
194
+ }
195
+ }
189
196
  }
190
197
  }
191
198
  continue;
@@ -203,7 +210,7 @@ function collectLDClients(ast) {
203
210
  }
204
211
  }
205
212
  }
206
- if (ldNamespaces.size === 0) return /* @__PURE__ */ new Set();
213
+ if (ldNamespaces.size === 0 && ldInitFunctions.size === 0) return /* @__PURE__ */ new Set();
207
214
  const ldClients = /* @__PURE__ */ new Set();
208
215
  walk(ast, (node) => {
209
216
  if (node.type !== "VariableDeclaration") return;
@@ -211,6 +218,10 @@ function collectLDClients(ast) {
211
218
  for (const decl of varDecl.declarations) {
212
219
  if (decl.id.type !== "Identifier" || !decl.init || decl.init.type !== "CallExpression") continue;
213
220
  const initCall = decl.init;
221
+ if (initCall.callee.type === "Identifier" && ldInitFunctions.has(initCall.callee.name)) {
222
+ ldClients.add(decl.id.name);
223
+ continue;
224
+ }
214
225
  if (initCall.callee.type !== "MemberExpression" || initCall.callee.computed) continue;
215
226
  const initCallee = initCall.callee;
216
227
  if (initCallee.object.type === "Identifier" && initCallee.property.type === "Identifier" && ldNamespaces.has(initCallee.object.name) && initCallee.property.name === "init") {
@@ -740,7 +751,7 @@ function formatHTML(result, options) {
740
751
  <div class="card"><div class="card-num orange">${manualCount}</div><div class="card-label">Manual Review (${manualPct}%)</div></div>
741
752
  <div class="card"><div class="card-num blue">${detailBulkCount}</div><div class="card-label">Detail/Bulk Calls</div></div>` : "";
742
753
  const title = options.title ? esc(options.title) : "FlagLint Scan Report";
743
- const version = true ? "0.5.1" : "0.1.0";
754
+ const version = true ? "0.5.2" : "0.1.0";
744
755
  return `<!DOCTYPE html>
745
756
  <html lang="en">
746
757
  <head>
@@ -1193,7 +1204,7 @@ function formatMigrationReport(analysis) {
1193
1204
  unsupportedUnknownCount
1194
1205
  } = analysis;
1195
1206
  const date = (/* @__PURE__ */ new Date()).toLocaleDateString();
1196
- const version = true ? "0.5.1" : "0.1.0";
1207
+ const version = true ? "0.5.2" : "0.1.0";
1197
1208
  const lines = [];
1198
1209
  lines.push("# OpenFeature Migration Inventory");
1199
1210
  lines.push(`Generated by FlagLint v${version} on ${date}`);
@@ -1957,7 +1968,7 @@ Examples:
1957
1968
  // src/cli.ts
1958
1969
  function createCLI() {
1959
1970
  const program2 = new Command();
1960
- program2.name("flaglint").description("LaunchDarkly Node.js server SDK -> OpenFeature migration.").version("0.5.1", "-v, --version", "output the current version").addHelpText(
1971
+ program2.name("flaglint").description("LaunchDarkly Node.js server SDK -> OpenFeature migration.").version("0.5.2", "-v, --version", "output the current version").addHelpText(
1961
1972
  "after",
1962
1973
  `
1963
1974
  Examples:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flaglint",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "LaunchDarkly Node.js server SDK -> OpenFeature migration.",
5
5
  "type": "module",
6
6
  "bin": {