Skip to content

NPM version Downloads

@commerce-klaus/eslint-config-sfcc ​

Shareable ESLint flat config for Salesforce Commerce Cloud (SFCC) projects.

This package continues @jenssimon/eslint-config-sfcc under the Commerce Klaus organization.

Modern JavaScript where SFCC supports it ​

This config is not an ES5 style guide. Its goal is to let SFCC projects use the most modern, idiomatic JavaScript that is known to run reliably on the platform, while catching unsupported features before deployment.

Compatibility policy

Write modern JavaScript by default. A feature is restricted only when SFCC/Rhino does not support it reliably or when it conflicts with an SFCC-specific runtime contract.

AreaPolicyExamples
Verified modern JavaScriptUse itconst/let, arrow functions, destructuring, template literals, generators, for...of
Standard library APIsUse APIs verified on supported SFCC versionsArray.from, String.prototype.includes, Object.values, Number.isFinite
Known runtime gapsReport before the code reaches a sandboxclasses, default parameters, spread syntax, Promise, dynamic import(), unsupported builtins
SFCC runtime contractsPrefer platform-compatible patternsCommonJS modules, valid cartridge paths, public Custom API exports, registered hook exports
Rhino-specific behaviorApply targeted compatibility rulessafe const usage, loop declarations, repeated names in nested blocks
Legacy or ambiguous syntaxReject or migrate to standard JavaScript.ds files, E4X-like markup, Rhino import globals, empty(...), Java-style String.equals(...)

ES5 code remains valid, but it is the compatibility floor, not the target style.

Verified modern syntax and APIs
  • Language syntax: const and let, arrow functions, destructuring, template literals, generator functions, exponentiation, and for...of
  • Array: Array.from, Array.of, Array.prototype.find, Array.prototype.findIndex, and Array.prototype.includes
  • String: String.fromCodePoint and the includes, startsWith, endsWith, repeat, padStart, padEnd, trimStart, and trimEnd prototype methods
  • Object: Object.assign, Object.values, Object.entries, and Object.fromEntries
  • Number: Number.isFinite, Number.isNaN, Number.isSafeInteger, Number.parseInt, and Number.parseFloat
  • Globals and primitives: globalThis and BigInt

The rule configuration and integration tests define the compatibility contract. Features outside this verified set may still be restricted when the sandbox cannot execute them reliably.

Install ​

bash
pnpm add -D eslint @commerce-klaus/eslint-config-sfcc
bash
yarn add -D eslint @commerce-klaus/eslint-config-sfcc
bash
npm install -D eslint @commerce-klaus/eslint-config-sfcc
bash
vp install -D eslint @commerce-klaus/eslint-config-sfcc

Use in eslint.config.js ​

eslint.config.js
js
import { defineConfig } from "eslint/config"
import sfcc from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  // ...
  sfcc.configs.recommended,
)

By default, JavaScript files under cartridges/ are linted. Client-side and static asset folders are excluded. The config disables Node.js and browser globals inherited from earlier flat config entries, then enables only the CommonJS and SFCC runtime globals available to server-side cartridge code. The Unicorn rule that discourages asterisk prefixes in documentation comments is disabled so standard JSDoc annotations remain usable for SFCC type information.

Older compatibility modes ​

The recommended config follows the current SFCC Script API. Add a compatibility preset after recommended when a code version targets an older compatibility mode:

eslint.config.js
js
import sfcc from "@commerce-klaus/eslint-config-sfcc"
import { defineConfig } from "eslint/config"

export default defineConfig(sfcc.configs.recommended, sfcc.configs["compatibility-21.2"])
PresetAdditional restrictions
compatibility-21.2Disallows BigInt, globalThis, and Object.entries, Object.values, and Object.fromEntries; disables conflicting Unicorn replacement suggestions
compatibility-22.7Currently none; establishes an explicit 22.7 contract for future Script API additions

Use createCompatibilityConfig() to apply an older mode to a custom cartridges directory or explicit file globs:

eslint.config.js
js
import { createCompatibilityConfig } from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  sfcc.configs.recommended,
  createCompatibilityConfig("21.2", { cartridgesDir: "commerce/cartridges" }),
)

Compatibility presets are additive restrictions. They do not replace recommended and must be composed after it.

SFCC module resolution ​

SFCC resolves server-side modules in the context of an ordered cartridge path. Entries on the left have higher precedence, so the order is part of application behavior rather than a filesystem detail.

  • */cartridge/... selects the first matching module in cartridge-path order.
  • ~/cartridge/... selects a module from the importing file's own cartridge.
  • <cartridge>/cartridge/... selects a module from one named cartridge.
  • module.superModule selects the next matching implementation after the current cartridge.
  • dw/* refers to platform APIs and is not resolved from the project filesystem.

Commerce Klaus shares these rules across its ESLint, TypeScript, Babel, Vite, and Vitest integrations. See Understanding SFCC module resolution for the complete model, examples, and edge cases.

Commerce Klaus can read these options from one shared commerce-klaus.config.ts or .js file. Package options remain supported and override the central values.

The recommended config enables sfcc/valid-require-path. By default, the rule validates whether static require() and import() identifiers use a supported SFCC form. Enable checkCartridgeExists through createRecommendedConfig() to also resolve */, ~/, and named cartridge references against the project filesystem and report missing modules.

ESLint validates source code; it does not transform or execute cartridge modules. dw/* imports are accepted as platform boundaries rather than looked up on disk. module.superModule is recognized as SFCC syntax, while the opt-in sfcc/no-proprietary-module-syntax rule can prohibit it together with */ and ~/ when a project requires portable CommonJS modules.

The shared SFCC settings define the cartridges directory, cartridge order, site metadata, and additional bare modules used for filesystem validation.

Generated types preset ​

Projects that run sfcc-ts-sync-types can enforce generated types at metadata boundaries with the opt-in generated-types preset:

eslint.config.js
js
import { defineConfig } from "eslint/config"
import sfcc from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  sfcc.configs.recommended,
  sfcc.configs["generated-types"],
)

The preset verifies metadata-driven function boundaries and enables:

RuleGenerated contract
prefer-generated-job-step-typesSfccJobSteps.Definitions from steptypes.json
prefer-generated-hook-typesSfccHooks aliases for registered Salesforce system hooks
prefer-generated-custom-api-typesCustom API Handler and local Response values from OAS

Missing or broader @type annotations receive an editor suggestion that inserts or replaces the generated type. All three rules follow the exported local binding, so both const handler = function () {} and function handler() {} declarations are supported. The Custom API rule also follows a local identifier passed to RESTResponseMgr.createSuccess() within that handler and applies the generated operation Response type.

Generated custom attribute declarations are not enforced by this preset. Access through typed platform APIs such as Product.custom and CustomObjectMgr.getCustomObject() is already inferred automatically. A standalone helper parameter named custom does not contain enough information to determine its system or custom object type without guessing.

Use createGeneratedTypesConfig() when the metadata resolver needs an explicit cartridge path or a non-default cartridges directory:

eslint.config.js
js
import sfcc, { createGeneratedTypesConfig } from "@commerce-klaus/eslint-config-sfcc"
import { defineConfig } from "eslint/config"

export default defineConfig(
  sfcc.configs.recommended,
  createGeneratedTypesConfig({
    cartridgesDir: "commerce/cartridges",
    sfcc: { cartridgePath: ["app_custom", "app_base"] },
  }),
)

Storefront architecture presets ​

Storefront presets are policy overlays that describe which controller architecture a project uses. Compose one after recommended:

They do not change the JavaScript compatibility baseline: modern syntax and standard library APIs supported by SFCC remain allowed in every storefront preset. sitegenesis/no-global-require also remains enabled in every preset because the rule limits itself to files under cartridge/controllers/.

eslint.config.js
js
import { defineConfig } from "eslint/config"
import sfcc from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  sfcc.configs.recommended,
  sfcc.configs["storefront-next"],
)
PresetEnabled architecture rules
storefront-nextno-controllers, no-forms, no-isml-rendering, no-pipeline-api, no-proprietary-module-syntax (*/ only), no-sfra-server, prefer-tilde-require-path
pwano-controllers, no-forms, no-isml-rendering, no-pipeline-api, no-proprietary-module-syntax (*/ only), no-sfra-server, prefer-tilde-require-path
sfrano-pipeline-api
sitegenesis-controllersno-pipeline-api, no-sfra-server
sitegenesis-pipelinesno-sfra-server

pwa and storefront-next currently enforce the same headless boundaries. They have separate semantic names so their policies can evolve independently as their platform contracts diverge.

Both headless presets require named cartridge imports instead of */ lookup and ~/ for imports from the current cartridge. Together, these rules distinguish local dependencies from explicit cross-cartridge dependencies. The presets continue to allow module.superModule; enable sfcc/no-proprietary-module-syntax directly when a project also prohibits that form.

The sitegenesis-pipelines preset applies to JavaScript only. It is the only preset that permits access to dw/system/Pipeline; all other presets reject pipeline execution. ESLint cannot validate pipeline XML files.

Restrict a preset to selected cartridges ​

Use createStorefrontConfig() when a repository contains multiple storefront architectures:

eslint.config.js
js
import { defineConfig } from "eslint/config"
import sfcc, { createStorefrontConfig } from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  sfcc.configs.recommended,
  createStorefrontConfig("sitegenesis-controllers", {
    cartridges: ["app_sitegenesis"],
  }),
  createStorefrontConfig("pwa", {
    cartridges: ["app_pwa", "int_pwa_backend"],
  }),
)

The helper accepts cartridgesDir, cartridges, and files. Explicit files globs take precedence over generated cartridge globs. Because each overlay both enables its own policy and disables incompatible controller rules, later presets can safely override recommended for their selected files.

The recommended config deliberately disables selected rules from commonly used ESLint presets when they suggest syntax, APIs, or module patterns that SFCC/Rhino does not support. This allows you to combine the SFCC config with those presets without forcing otherwise valid server-side SFCC code into incompatible modern JavaScript patterns.

The compatibility overrides cover:

  • ESLint recommended and core rules: disables rules such as object-shorthand, prefer-object-spread, prefer-rest-params, and prefer-spread that can suggest unsupported syntax or APIs. The core prefer-const rule is replaced by SFCC-aware rules that account for Rhino's scoping behavior.
  • eslint-plugin-unicorn: disables modern syntax and API preferences such as prefer-at, prefer-module, prefer-spread, and prefer-string-replace-all, as well as rules whose fixes or assumptions are unsafe for Rhino and SFCC APIs.
  • typescript-eslint: disables @typescript-eslint/no-require-imports because SFCC server-side modules use CommonJS require().
  • eslint-plugin-sonarjs: disables sonarjs/no-implicit-global because its assumptions conflict with SFCC's server-side module environment.

These overrides only take effect for rules enabled by another config in your ESLint setup; this package does not otherwise enable the external presets.

Use with Oxlint ​

Oxlint can run the included sfcc and sitegenesis plugins through its alpha JavaScript plugin API. Create an oxlint.config.mjs file that exports the included preset:

oxlint.config.mjs
js
import sfcc from "@commerce-klaus/eslint-config-sfcc/configs/oxlint"

export default sfcc

The preset loads both plugins and enables the supported SFCC and SiteGenesis rules. sfcc/no-ds-files is excluded because Oxlint ignores .ds files. sfcc/no-e4x-syntax and sfcc/no-type-annotations are excluded because their invalid JavaScript syntax causes Oxlint parser errors before JavaScript plugins can run.

For custom rule severities, import the rule record directly:

oxlint.config.mjs
js
import sfcc, { oxlintRules } from "@commerce-klaus/eslint-config-sfcc"

export default {
  lint: {
    ...sfcc.lint,
    rules: {
      ...oxlintRules,
      "sfcc/prefer-const": "warn",
    },
  },
}

Rules use their syntax-based behavior in Oxlint. Oxlint JavaScript plugins do not provide TypeScript parser services, so type-aware refinements are unavailable.

ESLint after Oxlint ​

Run ESLint after Oxlint to cover only the three rules that Oxlint cannot run: sfcc/no-ds-files, sfcc/no-e4x-syntax, and sfcc/no-type-annotations.

This optional fallback requires @typescript-eslint/parser:

bash
pnpm add -D @typescript-eslint/parser
bash
yarn add -D @typescript-eslint/parser
bash
npm install -D @typescript-eslint/parser
bash
vp install -D @typescript-eslint/parser
eslint.config.js
js
import { defineConfig } from "eslint/config"
import eslintAfterOxlint from "@commerce-klaus/eslint-config-sfcc/configs/eslint-after-oxlint"

export default defineConfig(eslintAfterOxlint)

This config deliberately does not enable the Oxlint-compatible rules, so the second lint pass does not duplicate their diagnostics. The subpath also exports createEslintAfterOxlintConfig() when the cartridge path, file globs, or ignored paths differ from the defaults.

Customize with shared SFCC settings ​

By default, sfcc/valid-require-path validates path patterns only and allows bare server requires.

Use createRecommendedConfig({ sfcc: ... }) to define shared SFCC plugin options centrally. These values are exposed through ESLint settings.sfcc, so future sfcc/* rules can reuse them without adding per-rule options.

eslint.config.js
js
import { defineConfig } from "eslint/config"
import { createRecommendedConfig } from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig(
  createRecommendedConfig({
    cartridgesDir: "cartridges",
    sfcc: {
      // Optional: allow additional bare module ids
      allowBareModules: ["server", "proxyquire"],
      // Optional: verify cartridgeName/* plus */* and ~/* against filesystem
      checkCartridgeExists: true,
      // Optional: explicit cartridge order for */* lookup (otherwise folders in cartridgesDir are used)
      cartridgePath: ["app_storefront", "modules", "app_custom"],
      // Optional: path to site template directory (defaults to sites/site_template when site is set)
      siteTemplatePath: "sites/site_template",
      // Optional: site id under <siteTemplatePath>/sites/<site>/site.xml
      site: "example",
    },
  }),
)

Register plugins manually ​

The recommended config already registers both built-in plugins. Register them manually only when composing individual rules without the preset.

eslint.config.js
js
import { defineConfig } from "eslint/config"
import { sfcc as sfccPlugin, sitegenesis } from "@commerce-klaus/eslint-config-sfcc"

export default defineConfig({
  plugins: {
    sfcc: sfccPlugin,
    sitegenesis,
  },
  rules: {
    "sfcc/prefer-const": "error",
    "sitegenesis/no-global-require": "error",
  },
})

Compatibility Guide ​

Use this section to decide whether a pattern is safe on SFCC, requires a targeted lint fix, or must be migrated before ESLint can parse it.

Quick reference ​

PatternResultRecommended action
XML and XMLList identifiersAllowedConstructor-style references remain available.
Static JSX/E4X-like markupLint errorConvert it to XML(\...`); see [sfcc/no-e4x-syntax`](rules/sfcc/no-e4x-syntax.md).
Dynamic JSX/E4X-like markupLint errorRefactor manually; no automatic conversion is offered.
Type annotations in .jsLint errorMove types to JSDoc; see sfcc/no-type-annotations.
importScript, importPackage, or importClassLint errorUse CommonJS require(); see sfcc/no-rhino-import-globals.
SFCC empty(...)Lint errorUse an explicit type-appropriate check; see sfcc/no-empty-global.
Java-style String.equals(...)Lint errorUse strict equality; see sfcc/no-string-equals.
String.rawLint errorUse an escaped string literal; see sfcc/no-string-raw.
.ds fileLint errorRename it to .js; see sfcc/no-ds-files.
default xml namespace = "..." or for each (...)Parser errorRewrite it before lint rules can run.

Rhino const strategy ​

Use const wherever Rhino can handle it reliably. Three coordinated rules keep declarations modern without introducing Rhino scoping failures.

ContextDeclarationRule
Function top level, never reassignedconstsfcc/prefer-const
Loop header or declaration inside a loop bodyletsfcc/rhino-const-compat
Nested block with a unique nameconstAllowed; no rule reports it.
Nested blocks that reuse the same declaration nameletsfcc/rhino-const-conflict

The rules are designed to run together: sfcc/prefer-const modernizes safe bindings, while the Rhino-specific rules protect loop and nested-block scopes. Repeated --fix runs therefore remain stable.

See all three rules in one example
js
function route() {
  let topLevel = 1 // sfcc/prefer-const -> const

  for (let i = 0; i < 3; i += 1) {
    const loopValue = i * 2 // sfcc/rhino-const-compat -> let
    process(loopValue)
  }

  if (flagA) {
    const temp = 1 // sfcc/rhino-const-conflict -> let
    process(temp)
  }
  if (flagB) {
    const temp = 2 // sfcc/rhino-const-conflict -> let
    process(temp)
  }

  return topLevel
}

Rhino can treat nested const declarations as function-scoped. A unique nested binding is safe, but reusing the same name in another nested block can produce a redeclaration error even though modern JavaScript accepts it.

E4X and parser boundaries ​

sfcc/no-e4x-syntax runs only after ESLint has parsed the file. It can report JSX/E4X-like elements and fragments that the configured parser accepts. Static markup receives an explicit XML(...) conversion suggestion; dynamic markup is reported without a suggestion because preserving escaping and runtime behavior requires manual review.

Some Rhino/E4X-era constructs are rejected earlier. default xml namespace = "..." and for each (value in collection) cause fatal parser errors, so no ESLint rule can inspect them. Rewrite these constructs manually using explicit XML handling and standard loops.

Migration Recipes ​

These focused replacements cover the legacy syntax most likely to prevent modern linting.

Iterate values ​

diff
- for each (item in items) {
+ for (let item of items) {
    process(item)
  }

Iterate object keys and values ​

diff
- for each (value in obj) {
-   process(value)
+ for (let key in obj) {
+   if (Object.prototype.hasOwnProperty.call(obj, key)) {
+     let value = obj[key]
+     process(value)
+   }
  }

Replace E4X literal markup ​

diff
- const payload = (
-   <request>
-     <id>{id}</id>
-   </request>
- )
+ const payload = XML(`<request><id>${id}</id></request>`)

default xml namespace = "..." is also parser-incompatible in modern JavaScript and must be refactored manually.

Built-in Plugins ​

This package ships two built-in ESLint plugins, both automatically registered in the recommended config:

  1. sfcc for general SFCC/Rhino compatibility rules
  2. sitegenesis for the SiteGenesis-specific controller rule ported from eslint-plugin-sitegenesis

sfcc ​

The sfcc plugin contains the general Rhino/SFCC runtime rules:

Recommended is not a ranking

Every rule in this plugin addresses an intentional compatibility or project-policy concern, whether or not it is enabled by the recommended config. The preset is a conservative baseline; opt-in rules are provided for conventions that depend on a team's architecture or migration goals. This distinction follows the Commerce Klaus philosophy of making platform constraints and project decisions explicit.

RuleDescriptionDefault
sfcc/no-controllersDisallows files below cartridge/controllers/ for Storefront Next, PWA, or selected cartridges that must remain controller-free.Off
sfcc/no-custom-apiDisallows JavaScript below cartridge/rest-apis/ in cartridges that must not expose Custom APIs.Off
sfcc/no-ds-filesDisallows legacy .ds files in SFCC projects. Use .js files instead.error
sfcc/no-dw-apiDisallows SFCC dw/* APIs in portable domain, utility, or shared cartridges, with support for exact and namespace allow lists.Off
sfcc/no-e4x-syntaxDisallows JSX/E4X-like tag syntax (e.g. <a/>) in SFCC JavaScript to avoid parser ambiguity and unsupported runtime patterns.error
sfcc/no-empty-globalDisallows the SFCC-specific empty(...) global. Use explicit checks such as .length === 0, Object.keys(...).length === 0, or .isEmpty() instead.error
sfcc/no-formsDisallows SFCC dw/web/Form* modules and the SFRA server.forms API in headless cartridges.Off
sfcc/no-hooksDisallows scripts registered by a cartridge's hooks.json, including Salesforce and project-specific hooks.Off
sfcc/no-isml-renderingDisallows ISML/template modules and SFRA response rendering in headless cartridges.Off
sfcc/no-page-designerDisallows dw/experience/* APIs in cartridges that must remain independent of Page Designer.Off
sfcc/no-pipeline-apiDisallows JavaScript access to the legacy dw/system/Pipeline API.Off
sfcc/no-platform-globalsDisallows stateful SFCC globals (customer, request, response, and session) in favor of explicit dependencies.Off
sfcc/no-proprietary-module-syntaxDisallows configurable SFCC-specific module syntax (*/*, ~/*, and module.superModule) for projects that require portable modules.Off
sfcc/no-custom-api-additional-propertiesDisallows additionalProperties in Custom API request body schemas, since the platform does not register such endpoints.error
sfcc/no-custom-api-response-methodsDisallows legacy global response APIs in Custom API implementations, which must return JSON through RESTResponseMgr.error
sfcc/no-string-equalsDisallows Java-style String.equals(...) calls in JavaScript files. Use strict equality (===) instead.error
sfcc/no-string-rawDisallows String.raw because affected SFCC Rhino versions can expose its result as an internal ConsString to Java-backed platform APIs.error
sfcc/no-type-annotationsDisallows type annotation syntax in JavaScript files (e.g. const x: string = ..., function y(): number {}). Rhino/E4X may accept it, but it is invalid in standard JavaScript; use JSDoc typing instead.error
sfcc/no-rhino-import-globalsDisallows legacy Rhino globals importScript(...), importPackage(...), and importClass(...). Use CommonJS require() instead.error
sfcc/no-rhino-extensionsDisallows Rhino and LiveConnect runtime globals such as Iterator, Packages, java, and javax.Off
sfcc/no-service-frameworkDisallows dw/svc/* APIs in cartridges that must delegate external communication to an integration layer.Off
sfcc/no-sfra-serverDisallows the SFRA server module in headless and SiteGenesis cartridges.Off
sfcc/prefer-native-collectionsPrefers native Array, Map, and Set collections over explicit imports of concrete dw/util collection implementations.Off
sfcc/prefer-constRequires const for let declarations that are never reassigned, excluding Rhino-sensitive nested/loop contexts.error
sfcc/require-file-extensionRequires explicit .js, .ds, or .json extensions in relative and cartridge module paths, with cartridge-aware auto-fixes when resolvable.Off
sfcc/rhino-const-compatEnforces let instead of const in Rhino loop-critical contexts (loop headers and declarations inside loop bodies) and supports auto-fix.error
sfcc/rhino-const-conflictDetects same-name const declarations in nested blocks within the same function (Rhino treats them as function-scoped) and supports auto-fix to let.error
sfcc/valid-custom-api-dir-nameRequires Custom API rest-apis directory names to contain only lowercase alphanumeric characters and hyphens.error
sfcc/valid-custom-api-exportRequires a public static CommonJS export for each Custom API endpoint mapped to the file in the rest-apis api.json.error
sfcc/valid-hook-exportRequires a static CommonJS export for each Salesforce hook method registered for the file in the cartridge's hooks.json.error
sfcc/valid-job-step-exportRequires static CommonJS exports for the functions configured for the file in effective steptypes.json job step definitions.error
sfcc/valid-require-pathValidates SFCC-compatible require() paths (dw/*, cartridgeName/*, ./*, ../*, */*, ~/*) and supports optional filesystem existence checks.error
sfcc/valid-step-type-definitionReports invalid job step definitions directly in cartridge steptypes.json files.error

The recommended config intentionally combines these sfcc/* rules so --fix does not bounce between conflicting suggestions: Rhino-unsafe const becomes let, while genuinely safe top-level function bindings still become const.

sitegenesis ​

sitegenesis only contains sitegenesis/no-global-require.

That rule is enabled in the recommended config by default, because it is still useful protection for repositories that contain SiteGenesis-style controller code. In non-SiteGenesis projects it is effectively dormant, because it only applies to files under cartridge/controllers/.

RuleDescriptionDefault
sitegenesis/no-global-requireDisallows top-level require() calls in controller files when not every route function uses them. Only applies to files under cartridge/controllers/.error

Package history and migration ​

This package was originally maintained and published as @jenssimon/eslint-config-sfcc. Version 5.0.0 of that package introduced ESLint Flat Config and the breaking changes described below. Development continued under the @jenssimon scope before the package moved to Commerce Klaus as @commerce-klaus/eslint-config-sfcc, whose release history starts at version 1.0.0.

If you use @jenssimon/eslint-config-sfcc version 4 or earlier, migrate both the ESLint configuration format and the package name. If you already use version 5 or later under the @jenssimon scope, your configuration is already based on Flat Config; update the dependency and imports to the @commerce-klaus package name and review the current configuration API.

Migrating from @jenssimon/eslint-config-sfcc <= v4 ​

This is a major release with breaking changes.

What changed ​

ESLint Flat Config The package now uses the flat config format (eslint.config.js). The legacy .eslintrc-based format is no longer supported.

Focus: compatibility, not formatting The config no longer enforces any code style or formatting rules. Its sole purpose is to detect JavaScript features that are not supported on SFCC sandboxes (Rhino engine). Formatting should be handled separately, e.g. with Prettier or Oxfmt.

No more base config The previous version extended @jenssimon/eslint-config-base (Airbnb style guide). This dependency has been removed entirely. Rules like comma-dangle, no-var, import/*, consistent-return, etc. are no longer part of this config.

eslint-plugin-es5 → eslint-plugin-es The old eslint-plugin-es5 has been replaced by eslint-plugin-es. Rules have been mapped accordingly.

No more SiteGenesis / SFRA configs The sfra and sfra-storefront configurations have been removed. These configurations were specific to SFRA and SiteGenesis and are not part of this general-purpose SFCC config. The external eslint-plugin-sitegenesis dependency is no longer used — sitegenesis/no-global-require is now built in, and the Rhino-specific general rules live in the built-in sfcc plugin.

Migration steps ​

  1. Replace .eslintrc.* with eslint.config.js
  2. Update the package name and import (see Usage above)
  3. Remove @jenssimon/eslint-config-base, eslint-plugin-es5, and eslint-plugin-sitegenesis from your dependencies — sitegenesis/no-global-require is built in and the general Rhino rules are now sfcc/*
  4. Add any formatting rules you need directly to your own eslint.config.js

Development ​

bash
vp install
vp test
vp check
vp pack

Released under the MIT License.