Skip to content

Commit

Permalink
feat: plugin target cache
Browse files Browse the repository at this point in the history
  • Loading branch information
Phillip9587 committed Apr 12, 2024
1 parent 35424c6 commit faa0320
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 19 deletions.
1 change: 1 addition & 0 deletions nx-stylelint/src/plugins/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ describe('nx-stylelint/plugin', () => {
{
"projects": {
"apps/my-app": {
"root": "apps/my-app",
"targets": {
"stylelint": {
"cache": true,
Expand Down
75 changes: 60 additions & 15 deletions nx-stylelint/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { CreateNodes } from '@nx/devkit';
import {
CreateDependencies,
CreateNodes,
TargetConfiguration,
readJsonFile,
writeJsonFile,
cacheDir,
} from '@nx/devkit';
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
import { existsSync } from 'node:fs';
import * as nodePath from 'node:path';
import { getInputConfigFiles } from '../utils/config-file';
Expand All @@ -8,10 +16,28 @@ export interface StylelintPluginOptions {
lintFilePatterns?: string | string[];
}

const cachePath = nodePath.join(cacheDir, 'stylelint.hash');
const targetsCache = existsSync(cachePath) ? readTargetsCache() : {};

const calculatedTargets: Record<string, Record<string, TargetConfiguration>> = {};

function readTargetsCache(): Record<string, Record<string, TargetConfiguration>> {
return readJsonFile(cachePath);
}

function writeTargetsToCache(targets: Record<string, Record<string, TargetConfiguration>>) {
writeJsonFile(cachePath, targets);
}

export const createDependencies: CreateDependencies = () => {
writeTargetsToCache(calculatedTargets);
return [];
};

export const createNodes: CreateNodes<StylelintPluginOptions> = [
'**/.stylelintrc.{json,yml,yaml,js,cjs,mjs,ts}',
async (configFilePath, options, context) => {
const { targetName, lintFilePatterns } = normalizeOptions(options);
const normalizedOptions = normalizeOptions(options);

const projectRoot = nodePath.dirname(configFilePath);

Expand All @@ -22,29 +48,48 @@ export const createNodes: CreateNodes<StylelintPluginOptions> = [
)
return {};

const inputConfigFiles = await getInputConfigFiles(configFilePath, projectRoot);
const hash = calculateHashForCreateNodes(projectRoot, normalizedOptions, context);
const targets = targetsCache[hash] ?? (await buildStylelintTargets(configFilePath, projectRoot, normalizedOptions));

calculatedTargets[hash] = targets;

return {
projects: {
[projectRoot]: {
targets: {
[targetName]: {
command: `stylelint`,
cache: true,
options: {
cwd: projectRoot,
args: [...lintFilePatterns.map((pattern) => `"${pattern}"`)],
},
inputs: ['default', ...inputConfigFiles, { externalDependencies: ['stylelint'] }],
},
},
root: projectRoot,
targets: targets,
},
},
};
},
];

function normalizeOptions(options: StylelintPluginOptions | undefined) {
async function buildStylelintTargets(
configFilePath: string,
projectRoot: string,
options: NormalizedStylelintPluginOptions,
): Promise<Record<string, TargetConfiguration>> {
const inputConfigFiles = await getInputConfigFiles(configFilePath, projectRoot);

return {
[options.targetName]: {
command: `stylelint`,
cache: true,
options: {
cwd: projectRoot,
args: [...options.lintFilePatterns.map((pattern) => `"${pattern}"`)],
},
inputs: ['default', ...inputConfigFiles, { externalDependencies: ['stylelint'] }],
},
};
}

interface NormalizedStylelintPluginOptions {
targetName: string;
lintFilePatterns: string[];
}

function normalizeOptions(options: StylelintPluginOptions | undefined): NormalizedStylelintPluginOptions {
return {
targetName: options?.targetName ?? 'stylelint',
lintFilePatterns: options?.lintFilePatterns ? [options?.lintFilePatterns].flat() : ['**/*.css'],
Expand Down
6 changes: 2 additions & 4 deletions nx-stylelint/src/utils/config-file.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { joinPathFragments, offsetFromRoot, readJson, workspaceRoot, writeJson, type Tree } from '@nx/devkit';
import { cosmiconfig } from 'cosmiconfig';
import { existsSync } from 'node:fs';
import { dirname, isAbsolute, join, relative } from 'node:path';
import type { Config, Config as StylelintConfig } from 'stylelint';
import { PROJECT_STYLELINT_CONFIG_SCSS_OVERRIDE, ROOT_STYLELINT_CONFIG, ROOT_STYLELINT_CONFIG_SCSS } from './config';
import { isRelativePath } from './path';
import { loadStylelintConfig } from './cosmiconfig';

export const STYLELINT_CONFIG_FILE_PATTERN = '.stylelintrc(.(json|yml|yaml|js))?';

Expand Down Expand Up @@ -38,8 +38,6 @@ export function isCompatibleRootConfig(tree: Tree): boolean {
return config.ignoreFiles === '**/*' || (Array.isArray(config.ignoreFiles) && config.ignoreFiles.includes('**/*'));
}

const explorer = cosmiconfig('stylelint', { cache: false, stopDir: workspaceRoot });

export async function getInputConfigFiles(configFilePath: string, projectRoot: string): Promise<string[]> {
return [...(await readAffectingStylelintConfigFiles(configFilePath))]
.map((configFilePath) => {
Expand All @@ -61,7 +59,7 @@ export async function readAffectingStylelintConfigFiles(configFilePath: string):
if (!existsSync(configFilePath)) return new Set();

try {
const result = await explorer.load(configFilePath);
const result = await loadStylelintConfig(configFilePath);
if (!result) return new Set();

const stylelintConfigFiles = new Set<string>([result.filepath]);
Expand Down
6 changes: 6 additions & 0 deletions nx-stylelint/src/utils/cosmiconfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { workspaceRoot } from '@nx/devkit';
import { cosmiconfig } from 'cosmiconfig';

const explorer = cosmiconfig('stylelint', { cache: false, stopDir: workspaceRoot });

export const loadStylelintConfig = (filepath: string) => explorer.load(filepath);

0 comments on commit faa0320

Please sign in to comment.