Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0f5d4c3
fix: add global fields FVRs in export
Jun 15, 2026
babff65
Merge branch 'development' into fix/DX-8587
Jun 30, 2026
8ab39bd
feat: add global field rule handling to content type
Jun 30, 2026
3a15a12
Merge branch 'development' into fix/DX-8587
naman-contentstack Jul 1, 2026
59de86d
feat: enhance field rules audit to include global fields and add corr…
Jul 1, 2026
922e81a
fix: typo in test case name
naman-contentstack Jul 7, 2026
08b53a9
fix: update the commented msg
naman-contentstack Jul 7, 2026
b894e01
Merge pull request #291 from contentstack/main
naman-contentstack Jul 13, 2026
af8818e
Merge branch 'development' into fix/DX-8587
Jul 16, 2026
3537a04
refactor: success logging for content types import
Jul 16, 2026
3143916
Merge pull request #232 from contentstack/fix/DX-8587
naman-contentstack Jul 21, 2026
c7cca9a
test(cli-plugins): repair failing unit test suites across packages [D…
netrajpatel Jul 21, 2026
b40ac61
chore(deps): override fast-uri and ws to patched versions [DX-9770]
netrajpatel Jul 21, 2026
80b2abb
chore(lint): repair ESLint 10 flat configs across 10 packages [DX-9770]
netrajpatel Jul 21, 2026
fbd63ec
chore(lint): standardize lint scripts, decouple from test, add Lint w…
netrajpatel Jul 21, 2026
b629e96
Merge remote-tracking branch 'origin/development' into DX-9770
netrajpatel Jul 21, 2026
2bacec4
chore(deps): consolidate dependency overrides into pnpm-workspace.yam…
netrajpatel Jul 22, 2026
c8f7fe4
Merge pull request #303 from contentstack/DX-9770
netrajpatel Jul 22, 2026
db3fcc5
fix: snyk issues
Jul 22, 2026
ac1d659
Merge pull request #305 from contentstack/snyk_fixes
naman-contentstack Jul 22, 2026
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
21 changes: 21 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Lint

on:
pull_request:
types: [opened, synchronize, reopened]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10.28.0
- uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: 'pnpm'
- run: pnpm install --no-frozen-lockfile
- run: pnpm -r --sort --workspace-concurrency=1 run build
- run: pnpm run lint
4 changes: 2 additions & 2 deletions .talismanrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fileignoreconfig:
- filename: pnpm-lock.yaml
checksum: 4be4721031793b5ec6957b17778969b715ded2d15a6b6231b6c066735abd7233
- filename: pnpm-lock.yaml
checksum: c3bcd614567a430c43ef8c3aa5a4ea2e006486137ba8397d58f01de89b858a1e
version: '1.0'
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"clean:packages": "pnpm -r --filter './packages/*' run clean",
"build": "pnpm -r --filter './packages/*' run build",
"test": "pnpm -r --filter './packages/*' run test",
"lint": "pnpm -r --filter './packages/*' run lint",
"prepack": "pnpm -r --filter './packages/*' run prepack",
"bootstrap": "pnpm install",
"clean:modules": "rm -rf node_modules packages/**/node_modules",
Expand All @@ -27,4 +28,4 @@
"workspaces": [
"packages/*"
]
}
}
49 changes: 26 additions & 23 deletions packages/contentstack-apps-cli/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
import tseslint from 'typescript-eslint';
import globals from 'globals';
import unicorn from 'eslint-plugin-unicorn';
import n from 'eslint-plugin-n';

export default [
...tseslint.configs.recommended,
{
ignores: [
'lib/**/*',
'test/**/*',
'dist/**/*',
],
ignores: ['lib/**/*', 'test/**/*', 'types/**/*', 'node_modules/**/*', '*.js'],
},
{
languageOptions: {
parser: tseslint.parser,
parserOptions: {
project: './tsconfig.json',
sourceType: 'module',
},
sourceType: 'module',
globals: {
...globals.node,
},
},
// unicorn/node registered (not enabled) so pre-existing inline eslint-disable
// directives that reference their rules resolve under ESLint 10 flat config.
plugins: {
'@typescript-eslint': tseslint.plugin,
unicorn,
node: n,
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'none',
},
],
'@typescript-eslint/prefer-namespace-keyword': 'error',
quotes: 'off',
semi: 'off',
// Pre-existing lint debt surfaced once the ESLint-10 flat-config crash was
// fixed. Kept visible as warnings (tracked for follow-up cleanup) rather
// than blocking, since these rules were never enforced while lint crashed.
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none', ignoreRestSiblings: true }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-expressions': ['warn', { allowShortCircuit: true, allowTernary: true }],
'@typescript-eslint/no-require-imports': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-wrapper-object-types': 'warn',
'@typescript-eslint/no-unsafe-function-type': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-this-alias': 'warn',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-redeclare': 'off',
eqeqeq: ['error', 'smart'],
'id-match': 'error',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-var': 'warn',
eqeqeq: 'warn',
'no-eval': 'error',
'no-var': 'error',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-require-imports': 'off',
'prefer-const': 'error',
},
},
];
];
3 changes: 1 addition & 2 deletions packages/contentstack-apps-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@
},
"scripts": {
"build": "pnpm clean && tsc -b",
"lint": "eslint . --ext .ts",
"lint": "eslint \"src/**/*.ts\"",
"postpack": "shx rm -f oclif.manifest.json",
"posttest": "pnpm lint",
"prepack": "pnpm build && oclif manifest && oclif readme",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
"version": "oclif readme && git add README.md",
Expand Down
54 changes: 46 additions & 8 deletions packages/contentstack-audit/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,50 @@
import oclif from 'eslint-config-oclif';
import oclifTypescript from 'eslint-config-oclif-typescript';
import tseslint from 'typescript-eslint';
import globals from 'globals';
import unicorn from 'eslint-plugin-unicorn';
import n from 'eslint-plugin-n';

export default [
oclif,
oclifTypescript,
...tseslint.configs.recommended,
{
ignores: [
'dist/**/*',
],
ignores: ['lib/**/*', 'test/**/*', 'types/**/*', 'node_modules/**/*', '*.js'],
},
];
{
languageOptions: {
parser: tseslint.parser,
parserOptions: {
sourceType: 'module',
},
globals: {
...globals.node,
},
},
// unicorn/node registered (not enabled) so pre-existing inline eslint-disable
// directives that reference their rules resolve under ESLint 10 flat config.
plugins: {
'@typescript-eslint': tseslint.plugin,
unicorn,
node: n,
},
rules: {
// Pre-existing lint debt surfaced once the ESLint-10 flat-config crash was
// fixed. Kept visible as warnings (tracked for follow-up cleanup) rather
// than blocking, since these rules were never enforced while lint crashed.
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none', ignoreRestSiblings: true }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-expressions': ['warn', { allowShortCircuit: true, allowTernary: true }],
'@typescript-eslint/no-require-imports': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-wrapper-object-types': 'warn',
'@typescript-eslint/no-unsafe-function-type': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-this-alias': 'warn',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-redeclare': 'off',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-var': 'warn',
eqeqeq: 'warn',
'no-eval': 'error',
},
},
];
3 changes: 1 addition & 2 deletions packages/contentstack-audit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@
},
"scripts": {
"build": "pnpm compile && oclif manifest && oclif readme",
"lint": "eslint . --ext .ts",
"lint": "eslint \"src/**/*.ts\"",
"postpack": "shx rm -f oclif.manifest.json",
"posttest": "npm run lint",
"compile": "tsc -b tsconfig.json",
"prepack": "pnpm compile && oclif manifest && oclif readme",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
Expand Down
25 changes: 21 additions & 4 deletions packages/contentstack-audit/src/audit-base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,20 +340,37 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
);

break;
case 'field-rules':
case 'field-rules': {
log.info('Executing field-rules audit', this.auditContext);
// NOTE: We are using the fixed content-type for validation of field rules
// NOTE: We are using the fixed content-type/global-field for validation of field rules.
const data = this.getCtAndGfSchema();
constructorParam.ctSchema = data.ctSchema;
constructorParam.gfSchema = data.gfSchema;
missingFieldRules = await new FieldRule(cloneDeep(constructorParam)).run();

// Field rules live on both content types and global fields. FieldRule.run() picks its
// schema from moduleName, so invoke it once per schema (overriding moduleName per
// instance) and merge the results. Merged object is keyed by schema uid; a content type
// and global field sharing a uid would collide, which is not expected in practice.
const ctFieldRules = await new FieldRule(
cloneDeep({ ...constructorParam, moduleName: 'content-types' }),
).run();
let gfFieldRules: Record<string, any> = {};
if (data.gfSchema?.length) {
gfFieldRules = await new FieldRule(
cloneDeep({ ...constructorParam, moduleName: 'global-fields' }),
).run();
}
missingFieldRules = { ...ctFieldRules, ...gfFieldRules };

await this.prepareReport(module, missingFieldRules);
this.getAffectedData('field-rules', dataModuleWise['content-types'], missingFieldRules);
const total = (data.ctSchema?.length || 0) + (data.gfSchema?.length || 0);
this.getAffectedData('field-rules', { Total: total }, missingFieldRules);
log.success(
`Field-rules audit completed. Found ${Object.keys(missingFieldRules || {}).length} issues`,
this.auditContext,
);
break;
}
case 'composable-studio':
log.info('Executing composable-studio audit', this.auditContext);
missingRefsInComposableStudio = await new ComposableStudio(cloneDeep(constructorParam)).run();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,53 @@ describe('Field Rules', () => {
});
});

describe('global field rules', () => {
const gfWithRuleSchema = () => [
{
uid: 'gf_with_rule',
title: 'GF With Rule',
schema: [{ uid: 'single_line', data_type: 'text', display_name: 'Single Line' }],
field_rules: [
{
conditions: [{ operand_field: 'single_line', operator: 'equals', value: 'x' }],
actions: [{ action: 'show', target_field: 'missing_field' }],
},
],
},
];

fancy
.stdout({ print: process.env.PRINT === 'true' || false })
.stub(FieldRule.prototype, 'prepareEntryMetaData', async () => {})
.stub(FieldRule.prototype, 'prerequisiteData', async () => {})
.it("scans a global field's own field_rules and flags missing target fields", async () => {
const gfInstance = new FieldRule({
...constructorParam,
moduleName: 'global-fields',
gfSchema: gfWithRuleSchema() as any,
});
const result = await gfInstance.run();
expect(result).to.have.property('gf_with_rule');
expect(JSON.stringify(result)).to.include('missing_field');
});

fancy
.stdout({ print: process.env.PRINT === 'true' || false })
.stub(FieldRule.prototype, 'prepareEntryMetaData', async () => {})
.stub(FieldRule.prototype, 'prerequisiteData', async () => {})
.it('does not flag a global field whose field_rules reference existing fields', async () => {
const okSchema = gfWithRuleSchema();
okSchema[0].field_rules[0].actions[0].target_field = 'single_line';
const gfInstance = new FieldRule({
...constructorParam,
moduleName: 'global-fields',
gfSchema: okSchema as any,
});
const result = await gfInstance.run();
expect(result).to.not.have.property('gf_with_rule');
});
});

describe('writeFixContent method', () => {
fancy
.stdout({ print: process.env.PRINT === 'true' || false })
Expand Down
65 changes: 31 additions & 34 deletions packages/contentstack-bootstrap/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,50 @@
import tseslint from 'typescript-eslint';
import globals from 'globals';
import mocha from 'eslint-plugin-mocha';
import unicorn from 'eslint-plugin-unicorn';
import n from 'eslint-plugin-n';

export default [
...tseslint.configs.recommended,

{
ignores: ['lib/**/*', 'test/**/*', 'types/**/*', 'node_modules/**/*', '*.js'],
},
{
languageOptions: {
parser: tseslint.parser,
parserOptions: {
sourceType: 'module',
},
globals: {
...globals.node,
...globals.mocha,
},
},

// unicorn/node registered (not enabled) so pre-existing inline eslint-disable
// directives that reference their rules resolve under ESLint 10 flat config.
plugins: {
'@typescript-eslint': tseslint.plugin,
mocha: mocha,
unicorn,
node: n,
},

rules: {
'unicorn/no-abusive-eslint-disable': 'off',
// Pre-existing lint debt surfaced once the ESLint-10 flat-config crash was
// fixed. Kept visible as warnings (tracked for follow-up cleanup) rather
// than blocking, since these rules were never enforced while lint crashed.
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none', ignoreRestSiblings: true }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-expressions': ['warn', { allowShortCircuit: true, allowTernary: true }],
'@typescript-eslint/no-require-imports': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-wrapper-object-types': 'warn',
'@typescript-eslint/no-unsafe-function-type': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-this-alias': 'warn',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
indent: 'off',
'object-curly-spacing': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
},
],
'mocha/no-async-describe': 'off',
'mocha/no-identical-title': 'off',
'mocha/no-mocha-arrows': 'off',
'mocha/no-setup-in-describe': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'prefer-const': 'error',
'no-fallthrough': 'error',
'no-prototype-builtins': 'off',
},
},

{
files: ['*.d.ts'],

rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-redeclare': 'off',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-var': 'warn',
eqeqeq: 'warn',
'no-eval': 'error',
},
},
];
];
3 changes: 2 additions & 1 deletion packages/contentstack-bootstrap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"version": "oclif readme && git add README.md",
"test": "npm run build && npm run test:e2e",
"test:e2e": "nyc mocha \"test/**/*.test.js\" || exit 0",
"test:report": "nyc --reporter=lcov mocha \"test/**/*.test.js\""
"test:report": "nyc --reporter=lcov mocha \"test/**/*.test.js\"",
"lint": "eslint \"src/**/*.ts\""
},
"dependencies": {
"@contentstack/cli-cm-seed": "~1.15.7",
Expand Down
Loading
Loading