diff --git a/package-lock.json b/package-lock.json index ab85b19eb6..0b6b9042bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -524,6 +524,25 @@ "@file-services/types": "^8.2.0" } }, + "node_modules/@file-services/resolve": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@file-services/resolve/-/resolve-8.2.0.tgz", + "integrity": "sha512-uwl6bRS8t4t31JxyGZ7aSdIuixojYoYLHambTOM16xqQkXBjXBqfGyQMyyJirxpMTpvWx4rIuAdhIP2dPeBYHg==", + "dependencies": { + "type-fest": "^4.3.1" + } + }, + "node_modules/@file-services/resolve/node_modules/type-fest": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.3.1.tgz", + "integrity": "sha512-pphNW/msgOUSkJbH58x8sqpq8uQj6b0ZKGxEsLKMUnGorRcDjrUaLS+39+/ub41JNTwrrMyJcUB8+YZs3mbwqw==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@file-services/types": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@file-services/types/-/types-8.2.0.tgz", @@ -6923,6 +6942,7 @@ "version": "5.16.0", "license": "MIT", "dependencies": { + "@file-services/resolve": "^8.2.0", "@tokey/css-selector-parser": "^0.6.2", "@tokey/css-value-parser": "^0.1.4", "@tokey/imports-parser": "^1.0.0", diff --git a/packages/cli/src/cli-codemod.ts b/packages/cli/src/cli-codemod.ts index 19f8f4bce8..c0690bf965 100644 --- a/packages/cli/src/cli-codemod.ts +++ b/packages/cli/src/cli-codemod.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node -import fs from 'fs'; +import fs from '@file-services/node'; import { resolve } from 'path'; import yargs from 'yargs'; import { codeMods } from './code-mods/code-mods'; diff --git a/packages/cli/src/code-format.ts b/packages/cli/src/code-format.ts index a7f2267d9a..343e9a935a 100644 --- a/packages/cli/src/code-format.ts +++ b/packages/cli/src/code-format.ts @@ -1,11 +1,10 @@ #!/usr/bin/env node import yargs from 'yargs'; -import { nodeFs } from '@file-services/node'; +import fs from '@file-services/node'; import { getDocumentFormatting, formatCSS } from '@stylable/code-formatter'; import { createLogger } from './logger'; -import { writeFileSync } from 'fs'; -const { join } = nodeFs; +const { join, writeFileSync } = fs; const argv = yargs .usage('$0 [options]') @@ -134,7 +133,7 @@ for (const request of requires) { } function readDirectoryDeep(dirPath: string, fileSuffixFilter = '.st.css', res = new Set()) { - const items = nodeFs.readdirSync(dirPath, { withFileTypes: true }); + const items = fs.readdirSync(dirPath, { withFileTypes: true }); for (const item of items) { const path = join(dirPath, item.name); @@ -150,7 +149,7 @@ function readDirectoryDeep(dirPath: string, fileSuffixFilter = '.st.css', res = } function formatStylesheet(filePath: string) { - const fileContent = nodeFs.readFileSync(filePath, 'utf-8'); + const fileContent = fs.readFileSync(filePath, 'utf-8'); const newText = experimental ? formatCSS(fileContent, { @@ -188,7 +187,7 @@ if (debug) { log('Starting code formatting'); } -const formatPathStats = nodeFs.statSync(target); +const formatPathStats = fs.statSync(target); if (formatPathStats.isFile()) { if (target.endsWith('.st.css')) { diff --git a/packages/cli/src/config/projects-config.ts b/packages/cli/src/config/projects-config.ts index 8593229098..21e1992f28 100644 --- a/packages/cli/src/config/projects-config.ts +++ b/packages/cli/src/config/projects-config.ts @@ -15,6 +15,7 @@ import { createDefaultOptions, mergeBuildOptions, validateOptions } from './reso import { resolveNpmRequests } from './resolve-requests'; import type { ModuleResolver } from '@stylable/core/dist/index-internal'; import type { MinimalFS, processNamespace } from '@stylable/core'; +import type { IFileSystem } from '@file-services/types'; interface StylableRuntimeConfigs { stcConfig?: Configuration | undefined; @@ -64,21 +65,21 @@ export async function projectsConfig( } // todo: make fs not optional next major version -export function resolveConfig(context: string, request?: string, fs?: MinimalFS) { +export function resolveConfig(context: string, request?: string, fs?: IFileSystem | MinimalFS) { return request ? requireConfigFile(request, context, fs) : resolveConfigFile(context, fs); } -function requireConfigFile(request: string, context: string, fs?: MinimalFS) { +function requireConfigFile(request: string, context: string, fs?: IFileSystem | MinimalFS) { const path = require.resolve(request, { paths: [context] }); const config = resolveConfigValue(require(path), fs); return config ? { config, path } : undefined; } -function resolveConfigFile(context: string, fs?: MinimalFS) { +function resolveConfigFile(context: string, fs?: IFileSystem | MinimalFS) { return loadStylableConfig(context, (config) => resolveConfigValue(config, fs)); } -function resolveConfigValue(config: any, fs?: MinimalFS) { +function resolveConfigValue(config: any, fs?: IFileSystem | MinimalFS) { return tryRun( (): StylableRuntimeConfigs => ({ stcConfig: isSTCConfig(config) diff --git a/packages/cli/test/assets.spec.ts b/packages/cli/test/assets.spec.ts index c5e72cb111..ae2594da7f 100644 --- a/packages/cli/test/assets.spec.ts +++ b/packages/cli/test/assets.spec.ts @@ -18,7 +18,7 @@ describe('assets', function () { '/src/other.st.css': '.other {}', '/node_modules/styles/3rd-party.css': '.third-party {}', }); - const resolve = createDefaultResolver(fs, {}); + const resolve = createDefaultResolver({ fs }); const stylable = new Stylable({ projectRoot: '/', fileSystem: fs, diff --git a/packages/cli/test/build.spec.ts b/packages/cli/test/build.spec.ts index 09bebd5fec..5a91ead56b 100644 --- a/packages/cli/test/build.spec.ts +++ b/packages/cli/test/build.spec.ts @@ -682,7 +682,7 @@ describe('build stand alone', () => { expect(dtsSourceMapContent).to.contain(`"main.st.css"`); }); - describe('resolver', () => { + describe('resolver (build)', () => { it('should be able to build with enhanced-resolver alias configured', async () => { const identifier = 'build-identifier'; const fs = createMemoryFs({ @@ -701,7 +701,7 @@ describe('build stand alone', () => { requireModule: () => ({}), resolveOptions: { alias: { - '@colors': '/colors', + '@colors/*': '/colors/*', }, }, }); diff --git a/packages/cli/test/cli.spec.ts b/packages/cli/test/cli.spec.ts index 92959dfc27..b8a48176e0 100644 --- a/packages/cli/test/cli.spec.ts +++ b/packages/cli/test/cli.spec.ts @@ -558,18 +558,18 @@ describe('Stylable Cli', function () { }); }); - describe('resolver', () => { + describe('resolver (cli)', () => { it('should be able to build with enhanced-resolver alias configured', () => { populateDirectorySync(tempDir.path, { 'package.json': `{"name": "test", "version": "0.0.0"}`, 'stylable.config.js': ` const { resolve } = require('node:path'); - const { createDefaultResolver } = require('@stylable/core'); + const { createLegacyResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { alias: { '@colors': resolve(__dirname, './colors') } @@ -618,12 +618,12 @@ describe('Stylable Cli', function () { 'stylable.config.js': ` const { join } = require('path'); const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin'); - const { createDefaultResolver } = require('@stylable/core'); + const { createLegacyResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { plugins: [new TsconfigPathsPlugin({ configFile: join(${JSON.stringify( tempDir.path )},'tsconfig.json') })], diff --git a/packages/core-test-kit/src/generate-test-util.ts b/packages/core-test-kit/src/generate-test-util.ts index a94af7f17a..58ce39ec95 100644 --- a/packages/core-test-kit/src/generate-test-util.ts +++ b/packages/core-test-kit/src/generate-test-util.ts @@ -62,7 +62,7 @@ export function generateInfra(config: InfraConfig, diagnostics: Diagnostics = ne createDiagnostics: () => diagnostics, }); - const resolveModule = createDefaultResolver(fs, {}); + const resolveModule = createDefaultResolver({ fs }); const resolvePath = (context: string | undefined = '/', moduleId: string) => resolveModule(context, moduleId); diff --git a/packages/core-test-kit/test/inline-expectations.spec.ts b/packages/core-test-kit/test/inline-expectations.spec.ts index e59d1b0506..25d168163e 100644 --- a/packages/core-test-kit/test/inline-expectations.spec.ts +++ b/packages/core-test-kit/test/inline-expectations.spec.ts @@ -1021,7 +1021,7 @@ describe('inline-expectations', () => { ); }); it(`should throw on possible location mismatch`, () => { - const resolveErrorMessage = `resolve './unknown.st.css' in '/'\n No description file found in / or above\n No description file found in / or above\n no extension\n /unknown.st.css doesn't exist\n .js\n /unknown.st.css.js doesn't exist\n .json\n /unknown.st.css.json doesn't exist\n .node\n /unknown.st.css.node doesn't exist\n as directory\n /unknown.st.css doesn't exist`; + const resolveErrorMessage = 'Stylable could not resolve "./unknown.st.css" from "/"'; const result = generateStylableResult({ entry: `/style.st.css`, files: { diff --git a/packages/core/package.json b/packages/core/package.json index 297a3eaf58..7347e9d624 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -10,6 +10,7 @@ "module": false }, "dependencies": { + "@file-services/resolve": "^8.2.0", "@tokey/css-selector-parser": "^0.6.2", "@tokey/css-value-parser": "^0.1.4", "@tokey/imports-parser": "^1.0.0", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index cd0ea213d8..13a13941e3 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -32,6 +32,7 @@ export { } from './helpers/namespace'; export { processNamespace } from './stylable-processor'; export { CustomValueStrategy, createCustomValue } from './custom-values'; +export { createLegacyResolver } from './legacy-module-resolver'; export { createDefaultResolver } from './module-resolver'; // low-level api diff --git a/packages/core/src/legacy-module-resolver.ts b/packages/core/src/legacy-module-resolver.ts new file mode 100644 index 0000000000..92d0885d3f --- /dev/null +++ b/packages/core/src/legacy-module-resolver.ts @@ -0,0 +1,47 @@ +// in browser build this gets remapped to an empty object via our package.json->"browser" +import nodeModule from 'module'; +// importing the factory directly, as we feed it our own fs, and don't want graceful-fs to be implicitly imported +// this allows @stylable/core to be bundled for browser usage without special custom configuration +import ResolverFactory from 'enhanced-resolve/lib/ResolverFactory.js'; +import type { ModuleResolver } from './types'; +import type { MinimalFS } from './cached-process-file'; + +function bundleSafeRequireExtensions(): string[] { + let extensions: string[]; + try { + // we use nodeModule here to avoid bundling warnings about require.extensions we always has fallback for browsers + extensions = Object.keys( + (nodeModule as typeof nodeModule & { _extensions?: Record }) + ._extensions ?? {} + ); + } catch (e) { + extensions = []; + } + return extensions.length ? extensions : ['.js', '.json']; +} + +const resolverContext = {}; + +export function createLegacyResolver(fileSystem: MinimalFS, resolveOptions: any): ModuleResolver { + const extensions = + resolveOptions.extensions && resolveOptions.extensions.length + ? resolveOptions.extensions + : bundleSafeRequireExtensions(); + const eResolver = ResolverFactory.createResolver({ + ...resolveOptions, + extensions, + useSyncFileSystemCalls: true, + cache: false, + fileSystem, + }); + + return (directoryPath, request): string => { + const res = eResolver.resolveSync(resolverContext, directoryPath, request); + if (res === false) { + throw new Error( + `Stylable does not support browser field 'false' values. ${request} resolved to 'false' from ${directoryPath}` + ); + } + return res; + }; +} diff --git a/packages/core/src/module-resolver.ts b/packages/core/src/module-resolver.ts index a6d42bd225..f628ab2916 100644 --- a/packages/core/src/module-resolver.ts +++ b/packages/core/src/module-resolver.ts @@ -1,47 +1,24 @@ // in browser build this gets remapped to an empty object via our package.json->"browser" -import nodeModule from 'module'; -// importing the factory directly, as we feed it our own fs, and don't want graceful-fs to be implicitly imported -// this allows @stylable/core to be bundled for browser usage without special custom configuration -import ResolverFactory from 'enhanced-resolve/lib/ResolverFactory.js'; -import type { ModuleResolver } from './types'; -import type { MinimalFS } from './cached-process-file'; - -function bundleSafeRequireExtensions(): string[] { - let extensions: string[]; - try { - // we use nodeModule here to avoid bundling warnings about require.extensions we always has fallback for browsers - extensions = Object.keys( - (nodeModule as typeof nodeModule & { _extensions?: Record }) - ._extensions ?? {} - ); - } catch (e) { - extensions = []; - } - return extensions.length ? extensions : ['.js', '.json']; -} -const resolverContext = {}; +import { IRequestResolverOptions, createRequestResolver } from '@file-services/resolve'; +import type { ModuleResolver } from './types'; -export function createDefaultResolver(fileSystem: MinimalFS, resolveOptions: any): ModuleResolver { - const extensions = - resolveOptions.extensions && resolveOptions.extensions.length - ? resolveOptions.extensions - : bundleSafeRequireExtensions(); - const eResolver = ResolverFactory.createResolver({ - ...resolveOptions, - extensions, - useSyncFileSystemCalls: true, - cache: false, - fileSystem, +export function createDefaultResolver(options: IRequestResolverOptions): ModuleResolver { + const resolver = createRequestResolver({ + extensions: ['.js', '.json', '.mjs', '.cjs', '.ts', '.mts', '.cts'], + ...options, }); return (directoryPath, request): string => { - const res = eResolver.resolveSync(resolverContext, directoryPath, request); - if (res === false) { + const res = resolver(directoryPath, request); + if (res.resolvedFile === false) { throw new Error( `Stylable does not support browser field 'false' values. ${request} resolved to 'false' from ${directoryPath}` ); } - return res; + if (typeof res.resolvedFile !== 'string') { + throw new Error(`Stylable could not resolve ${JSON.stringify(request)} from ${JSON.stringify(directoryPath)}`); + } + return res.resolvedFile; }; } diff --git a/packages/core/src/stylable.ts b/packages/core/src/stylable.ts index a02327ca4d..6e76231aee 100644 --- a/packages/core/src/stylable.ts +++ b/packages/core/src/stylable.ts @@ -24,6 +24,7 @@ export interface StylableConfig { requireModule?: (path: string) => any; onProcess?: (meta: StylableMeta, path: string) => StylableMeta; hooks?: TransformHooks; + /** @deprecated provide a `resolveModule` instead */ resolveOptions?: { alias?: any; symlinks?: boolean; @@ -105,7 +106,8 @@ export class Stylable { this.mode = config.mode || `production`; this.resolveNamespace = config.resolveNamespace; this.moduleResolver = - config.resolveModule || createDefaultResolver(this.fileSystem, this.resolveOptions); + config.resolveModule || + createDefaultResolver({ fs: this.fileSystem, ...this.resolveOptions }); this.cssParser = config.cssParser || cssParse; this.resolverCache = config.resolverCache; // ToDo: v5 default to `new Map()` this.fileProcessorCache = config.fileProcessorCache; diff --git a/packages/core/test/features/st-import.spec.ts b/packages/core/test/features/st-import.spec.ts index 203e4517ac..67fe55e65c 100644 --- a/packages/core/test/features/st-import.spec.ts +++ b/packages/core/test/features/st-import.spec.ts @@ -211,8 +211,8 @@ describe(`features/st-import`, () => { `); }); it(`should error on unresolved file`, () => { - const resolveErrorMessage = `resolve './missing.st.css' in '/'\n No description file found in / or above\n No description file found in / or above\n no extension\n /missing.st.css doesn't exist\n .js\n /missing.st.css.js doesn't exist\n .json\n /missing.st.css.json doesn't exist\n .node\n /missing.st.css.node doesn't exist\n as directory\n /missing.st.css doesn't exist`; - const resolveErrorMessagePackage = `resolve 'missing-package/index.st.css' in '/'\n Parsed request is a module\n No description file found in / or above\n resolve as module\n /node_modules doesn't exist or is not a directory`; + const resolveErrorMessage = `Stylable could not resolve "./missing.st.css" from "/"`; + const resolveErrorMessagePackage = `Stylable could not resolve "missing-package/index.st.css" from "/"`; testStylableCore(` /* @transform-error(relative) word(./missing.st.css) ${stImportDiagnostics.UNKNOWN_IMPORTED_FILE( @@ -533,9 +533,9 @@ describe(`features/st-import`, () => { `); }); it(`should error on unresolved file`, () => { - const resolveErrorMessage = `resolve './missing.st.css' in '/'\n No description file found in / or above\n No description file found in / or above\n no extension\n /missing.st.css doesn't exist\n .js\n /missing.st.css.js doesn't exist\n .json\n /missing.st.css.json doesn't exist\n .node\n /missing.st.css.node doesn't exist\n as directory\n /missing.st.css doesn't exist`; - const resolveErrorMessagePackage = `resolve 'missing-package/index.st.css' in '/'\n Parsed request is a module\n No description file found in / or above\n resolve as module\n /node_modules doesn't exist or is not a directory`; - + const resolveErrorMessage = `Stylable could not resolve "./missing.st.css" from "/"`; + const resolveErrorMessagePackage = `Stylable could not resolve "missing-package/index.st.css" from "/"`; + testStylableCore(` :import{ /* @transform-error(relative) word(./missing.st.css) ${stImportDiagnostics.UNKNOWN_IMPORTED_FILE( diff --git a/packages/e2e-test-kit/src/dts-kit.ts b/packages/e2e-test-kit/src/dts-kit.ts index 7e8a4610af..b9fb4637e8 100644 --- a/packages/e2e-test-kit/src/dts-kit.ts +++ b/packages/e2e-test-kit/src/dts-kit.ts @@ -1,5 +1,5 @@ -import fs, { readFileSync, symlinkSync, writeFileSync } from 'fs'; -import { join } from 'path'; +import { nodeFs as fs } from '@file-services/node'; +import { join } from 'node:path'; import { Stylable } from '@stylable/core'; import { generateDTSContent } from '@stylable/module-utils'; import { createTempDirectorySync, ITempDirectorySync } from './file-system-helpers'; @@ -27,18 +27,19 @@ export class DTSKit { resolveNamespace(ns) { return ns; }, + }); } public populate(files: Record, generateDts = true) { for (const filePath in files) { - writeFileSync(this.sourcePath(filePath), files[filePath]); + fs.writeFileSync(this.sourcePath(filePath), files[filePath]); if (generateDts && filePath.endsWith('.st.css')) { this.genDTS(filePath); } } for (const filePath in this.testKit) { - writeFileSync(this.sourcePath(filePath), this.testKit[filePath]); + fs.writeFileSync(this.sourcePath(filePath), this.testKit[filePath]); } } @@ -81,11 +82,11 @@ export class DTSKit { } public write(internalPath: string, content: string) { - writeFileSync(this.sourcePath(internalPath), content); + fs.writeFileSync(this.sourcePath(internalPath), content); } public read(internalPath: string) { - return readFileSync(this.sourcePath(internalPath), { encoding: 'utf8' }); + return fs.readFileSync(this.sourcePath(internalPath), { encoding: 'utf8' }); } public dispose() { @@ -93,7 +94,7 @@ export class DTSKit { } public linkNodeModules() { - symlinkSync( + fs.symlinkSync( join(__dirname, '../../../node_modules'), join(this.tmp.path, 'node_modules'), 'junction' diff --git a/packages/esbuild/package.json b/packages/esbuild/package.json index 4fd251c4ff..3603e0706c 100644 --- a/packages/esbuild/package.json +++ b/packages/esbuild/package.json @@ -4,7 +4,7 @@ "description": "Stylable plugin for esbuild", "main": "dist/index.js", "scripts": { - "test": "mocha \"dist/test/**/*.spec.js\"" + "test": "mocha \"dist/test/**/*.spec.js\" --timeout 10000" }, "peerDependencies": { "esbuild": ">=0.17.18" diff --git a/packages/esbuild/src/stylable-esbuild-plugin.ts b/packages/esbuild/src/stylable-esbuild-plugin.ts index f503786744..39ad9459ca 100644 --- a/packages/esbuild/src/stylable-esbuild-plugin.ts +++ b/packages/esbuild/src/stylable-esbuild-plugin.ts @@ -1,4 +1,4 @@ -import fs, { readFileSync, writeFileSync } from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import { relative, join, isAbsolute, dirname } from 'path'; import type { Plugin, PluginBuild } from 'esbuild'; import { @@ -365,10 +365,10 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi } const distFilePath = join(stylable.projectRoot, distFile); - writeFileSync( + fs.writeFileSync( distFilePath, sortMarkersByDepth( - readFileSync(distFilePath, 'utf8'), + fs.readFileSync(distFilePath, 'utf8'), stylable, idForPath, optimize.removeUnusedComponents ? mapping : {} diff --git a/packages/esbuild/test/e2e/rebuild/rebuild.spec.ts b/packages/esbuild/test/e2e/rebuild/rebuild.spec.ts index b5eb406009..2d2f1e1f7f 100644 --- a/packages/esbuild/test/e2e/rebuild/rebuild.spec.ts +++ b/packages/esbuild/test/e2e/rebuild/rebuild.spec.ts @@ -2,12 +2,12 @@ import { expect } from 'chai'; import { ESBuildTestKit } from '../esbuild-testkit'; import { sleep } from 'promise-assist'; -describe('Stylable ESBuild plugin rebuild on change', () => { +describe('Stylable ESBuild plugin rebuild on change', function () { const tk = new ESBuildTestKit(); afterEach(() => tk.dispose()); - it('should pick up rebuild', async () => { + it('should pick up rebuild', async function () { const { context, read, write } = await tk.build({ project: 'rebuild', tmp: true, diff --git a/packages/eslint-plugin-stylable/src/stylable-es-lint.ts b/packages/eslint-plugin-stylable/src/stylable-es-lint.ts index 1c331fcc4d..c3eac93b09 100644 --- a/packages/eslint-plugin-stylable/src/stylable-es-lint.ts +++ b/packages/eslint-plugin-stylable/src/stylable-es-lint.ts @@ -1,4 +1,4 @@ -import fs from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import path from 'path'; import { Stylable, StylableMeta, createDefaultResolver } from '@stylable/core'; import { safeParse, StylableExports } from '@stylable/core/dist/index-internal'; @@ -22,7 +22,7 @@ export default createRule({ defaultOptions: [{ exposeDiagnosticsReports: false, resolveOptions: {} }], // TODO: allow to pass resolve config create(context, options) { const [{ exposeDiagnosticsReports, resolveOptions }] = options as Options; - const moduleResolver = createDefaultResolver(fs, resolveOptions); + const moduleResolver = createDefaultResolver({ fs, ...resolveOptions }); const stylable = new Stylable({ fileSystem: fs, diff --git a/packages/experimental-loader/src/stylable-transform-loader.ts b/packages/experimental-loader/src/stylable-transform-loader.ts index 08c41df9b2..045d1003e6 100644 --- a/packages/experimental-loader/src/stylable-transform-loader.ts +++ b/packages/experimental-loader/src/stylable-transform-loader.ts @@ -1,5 +1,5 @@ import postcss from 'postcss'; -import { processNamespace, MinimalFS } from '@stylable/core'; +import { processNamespace, MinimalFS, createLegacyResolver } from '@stylable/core'; import { emitDiagnostics, DiagnosticsMode, @@ -64,11 +64,15 @@ const stylableLoader: LoaderDefinition = function (content) { }; const mode = this._compiler!.options.mode === 'development' ? 'development' : 'production'; + const resolveModule = createLegacyResolver( + this.fs as unknown as MinimalFS, + this._compiler!.options.resolve + ); const stylable = getStylable(this._compiler!, { projectRoot: this.rootContext, fileSystem: this.fs as unknown as MinimalFS, mode, - resolveOptions: this._compiler!.options.resolve, + resolveModule, resolveNamespace, }); diff --git a/packages/jest/src/jest.ts b/packages/jest/src/jest.ts index 89f6534ab8..6ea00c3462 100644 --- a/packages/jest/src/jest.ts +++ b/packages/jest/src/jest.ts @@ -1,4 +1,4 @@ -import fs from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import type { StylableConfig } from '@stylable/core'; import { validateDefaultConfig } from '@stylable/core/dist/index-internal'; import { stylableModuleFactory } from '@stylable/module-utils'; diff --git a/packages/jest/test/fixtures/default-config/stylable.config.js b/packages/jest/test/fixtures/default-config/stylable.config.js index 082a068b76..9f34ddffeb 100644 --- a/packages/jest/test/fixtures/default-config/stylable.config.js +++ b/packages/jest/test/fixtures/default-config/stylable.config.js @@ -5,9 +5,10 @@ const { createDefaultResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createDefaultResolver({ + fs, alias: { - 'wp-alias': join(__dirname, 'webpack-alias1'), + 'wp-alias/*': join(__dirname, 'webpack-alias1') + '/*', }, }), }; diff --git a/packages/jest/test/jest.spec.ts b/packages/jest/test/jest.spec.ts index 6fe03f9505..d246f9fff0 100644 --- a/packages/jest/test/jest.spec.ts +++ b/packages/jest/test/jest.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import fs, { readFileSync } from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import nodeEval from 'node-eval'; import stylableTransformer from '@stylable/jest'; import type { RuntimeStylesheet } from '@stylable/runtime'; @@ -9,7 +9,7 @@ import { createDefaultResolver } from '@stylable/core'; describe('jest process', () => { it('should process stylable sources using createTransformer API', () => { const filename = require.resolve('@stylable/jest/test/fixtures/test.st.css'); - const content = readFileSync(filename, 'utf8'); + const content = fs.readFileSync(filename, 'utf8'); const transformer = stylableTransformer.createTransformer(); const module = nodeEval( @@ -23,7 +23,7 @@ describe('jest process', () => { it('should process stylable sources with a custom namespace resolver', () => { const filename = require.resolve('@stylable/jest/test/fixtures/test.st.css'); - const content = readFileSync(filename, 'utf8'); + const content = fs.readFileSync(filename, 'utf8'); const transformer = stylableTransformer.createTransformer({ stylable: { resolveNamespace: (ns, _srcPath) => `${ns}-custom` }, }); @@ -41,7 +41,7 @@ describe('jest process', () => { const filename = require.resolve( '@stylable/jest/test/fixtures/default-config/index.st.css' ); - const content = readFileSync(filename, 'utf8'); + const content = fs.readFileSync(filename, 'utf8'); const transformer = stylableTransformer.createTransformer({ stylable: { resolveNamespace: (ns, _srcPath) => `${ns}-custom` }, configPath: join(dirname(filename), 'stylable.config.js'), @@ -59,13 +59,14 @@ describe('jest process', () => { const filename = require.resolve( '@stylable/jest/test/fixtures/default-config/index.st.css' ); - const content = readFileSync(filename, 'utf8'); + const content = fs.readFileSync(filename, 'utf8'); const transformer = stylableTransformer.createTransformer({ stylable: { resolveNamespace: (ns, _srcPath) => `${ns}-custom`, - resolveModule: createDefaultResolver(fs, { + resolveModule: createDefaultResolver({ + fs, alias: { - 'wp-alias': join(dirname(filename), 'webpack-alias2'), + 'wp-alias/*': join(dirname(filename), 'webpack-alias2') + '/*', }, }), }, @@ -84,7 +85,7 @@ describe('jest process', () => { const filename = require.resolve( '@stylable/jest/test/fixtures/default-config/index.st.css' ); - const content = readFileSync(filename, 'utf8'); + const content = fs.readFileSync(filename, 'utf8'); let foundError = false; try { diff --git a/packages/jest/test/tsconfig.json b/packages/jest/test/tsconfig.json index 979f55c8f2..90dd6d979c 100644 --- a/packages/jest/test/tsconfig.json +++ b/packages/jest/test/tsconfig.json @@ -4,5 +4,9 @@ "outDir": "../dist/test", "types": ["node", "externals", "mocha"] }, - "references": [{ "path": "../../runtime/src" }, { "path": "../src" }] + "references": [ + { "path": "../../runtime/src" }, + { "path": "../../core/src" }, + { "path": "../src" } + ] } diff --git a/packages/language-service/test/lib-new/features/ls-st-import.spec.ts b/packages/language-service/test/lib-new/features/ls-st-import.spec.ts index ad94d2ec77..797291cea8 100644 --- a/packages/language-service/test/lib-new/features/ls-st-import.spec.ts +++ b/packages/language-service/test/lib-new/features/ls-st-import.spec.ts @@ -1287,7 +1287,7 @@ describe('LS: st-import', () => { }, } ); - const defaultResolveModule = createDefaultResolver(fs, {}); + const defaultResolveModule = createDefaultResolver({ fs }); const entryPath = fs.join(tempDir.path, 'src', 'entry.st.css'); /** * mapping like this cannot override the original resolved package diff --git a/packages/module-utils/test/generate-dts.spec.ts b/packages/module-utils/test/generate-dts.spec.ts index 348dcbfc1f..e1f871eecb 100644 --- a/packages/module-utils/test/generate-dts.spec.ts +++ b/packages/module-utils/test/generate-dts.spec.ts @@ -219,7 +219,7 @@ describe('Generate DTS', function () { it('should not expose imported symbols', () => { tk.populate({ 'origin.st.css': ` - .cls { + .cls { container-name: cont; } @property --customProp; @@ -254,7 +254,6 @@ describe('Generate DTS', function () { eq(classes.cls); eq(classes.CompRoot); eq(vars.customProp); - eq(vars.customProp); eq(stVars.buildVar); eq(keyframes.anim); eq(containers.cont); diff --git a/packages/node/src/find-files.ts b/packages/node/src/find-files.ts index 5de3e3a4a6..99b28fa329 100644 --- a/packages/node/src/find-files.ts +++ b/packages/node/src/find-files.ts @@ -1,6 +1,6 @@ import type { IFileSystem } from '@file-services/types'; -export type FileSystem = any; +export type FileSystem = IFileSystem; export function findFiles( fs: Pick, diff --git a/packages/node/src/require-hook.ts b/packages/node/src/require-hook.ts index 274d3701d9..1cb21d2b34 100644 --- a/packages/node/src/require-hook.ts +++ b/packages/node/src/require-hook.ts @@ -1,7 +1,7 @@ import type { StylableConfig } from '@stylable/core'; import { validateDefaultConfig } from '@stylable/core/dist/index-internal'; import { stylableModuleFactory } from '@stylable/module-utils'; -import fs from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import { defaultStylableMatcher } from './common'; import { resolveNamespace } from './resolve-namespace'; diff --git a/packages/node/test/fixtures/default-config/stylable.config.js b/packages/node/test/fixtures/default-config/stylable.config.js index 082a068b76..d7b409a624 100644 --- a/packages/node/test/fixtures/default-config/stylable.config.js +++ b/packages/node/test/fixtures/default-config/stylable.config.js @@ -1,13 +1,14 @@ //@ts-check -const { join } = require('path'); +const { posix: {join} } = require('path'); const { createDefaultResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createDefaultResolver({ + fs, alias: { - 'wp-alias': join(__dirname, 'webpack-alias1'), + 'wp-alias/*': join(__dirname, 'webpack-alias1') + '/*', }, }), }; diff --git a/packages/node/test/loader.spec.ts b/packages/node/test/loader.spec.ts index 677a23251d..91de802f89 100644 --- a/packages/node/test/loader.spec.ts +++ b/packages/node/test/loader.spec.ts @@ -69,7 +69,7 @@ describeIf(nodeMajorVersion > 14)('node loader', () => { console.log(classes); `, 'stylable.config.js': ` - export function defaultConfig(fs) { + export function defaultConfig() { return { resolveNamespace(namespace, path) { return 'x-' + namespace; @@ -107,7 +107,7 @@ describeIf(nodeMajorVersion > 14)('node loader', () => { `, 'stylable.config.js': ` module.exports = { - defaultConfig(fs) { + defaultConfig() { return { resolveNamespace(namespace, path) { return 'x-' + namespace; diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index 5c786f0b64..2901d94a5b 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -1,5 +1,5 @@ import type { Plugin } from 'rollup'; -import fs from 'fs'; +import { nodeFs as fs } from '@file-services/node'; import { join, parse } from 'path'; import { Stylable, StylableConfig } from '@stylable/core'; import { diff --git a/packages/rollup-plugin/test/projects/config-file-resolver-override/stylable.config.js b/packages/rollup-plugin/test/projects/config-file-resolver-override/stylable.config.js index 9874207acc..c77bcd164f 100644 --- a/packages/rollup-plugin/test/projects/config-file-resolver-override/stylable.config.js +++ b/packages/rollup-plugin/test/projects/config-file-resolver-override/stylable.config.js @@ -4,9 +4,10 @@ module.exports = { const { createDefaultResolver } = require('@stylable/core'); const { join } = require('path'); return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createDefaultResolver({ + fs, alias: { - components: join(__dirname, 'src/components'), + 'components/*': join(__dirname, 'src/components') + '/*', }, }), }; diff --git a/packages/rollup-plugin/test/rollup-native-css.spec.ts b/packages/rollup-plugin/test/rollup-native-css.spec.ts index e49e10936c..ca4b206030 100644 --- a/packages/rollup-plugin/test/rollup-native-css.spec.ts +++ b/packages/rollup-plugin/test/rollup-native-css.spec.ts @@ -2,14 +2,14 @@ import { expect } from 'chai'; import { rollupRunner } from './test-kit/rollup-runner'; import { getProjectPath } from './test-kit/test-helpers'; import { createDefaultResolver } from '@stylable/core'; -import { nodeFs } from '@file-services/node'; +import { nodeFs as fs } from '@file-services/node'; describe('StylableRollupPlugin - import native CSS', function () { this.timeout(30000); const project = 'native-css'; - const resolve = createDefaultResolver(nodeFs, {}); + const resolve = createDefaultResolver({ fs }); const runner = rollupRunner({ projectPath: getProjectPath(project), entry: './src/index.js', diff --git a/packages/webpack-extensions/src/stylable-manifest-plugin.ts b/packages/webpack-extensions/src/stylable-manifest-plugin.ts index b524d2be53..c258223cf6 100644 --- a/packages/webpack-extensions/src/stylable-manifest-plugin.ts +++ b/packages/webpack-extensions/src/stylable-manifest-plugin.ts @@ -1,4 +1,4 @@ -import { Stylable, StylableMeta } from '@stylable/core'; +import { Stylable, StylableMeta, createLegacyResolver } from '@stylable/core'; import { STSymbol } from '@stylable/core/dist/index-internal'; import { resolveNamespace } from '@stylable/node'; import { createMetadataForStylesheet } from './create-metadata-stylesheet'; @@ -55,6 +55,17 @@ export class StylableManifestPlugin { this.options = Object.assign({}, defaultOptions, options); } public apply(compiler: Compiler) { + const fs = { + readlinkSync: (filePath: string) => + (compiler.inputFileSystem as any).readlinkSync(filePath), + statSync: (filePath: string) => (compiler.inputFileSystem as any).statSync(filePath), + readFileSync: (filePath: string) => + (compiler.inputFileSystem as any).readFileSync(filePath).toString(), + }; + const resolveModule = createLegacyResolver(fs, { + ...compiler.options.resolve, + extensions: [], + }); const stylable = new Stylable({ projectRoot: compiler.context, fileSystem: { @@ -65,10 +76,7 @@ export class StylableManifestPlugin { (compiler.inputFileSystem as any).readFileSync(filePath).toString(), }, mode: compiler.options.mode === 'development' ? 'development' : 'production', - resolveOptions: { - ...compiler.options.resolve, - extensions: [], - }, + resolveModule, resolverCache: new Map(), resolveNamespace: this.options.resolveNamespace, }); diff --git a/packages/webpack-extensions/src/stylable-metadata-loader.ts b/packages/webpack-extensions/src/stylable-metadata-loader.ts index 113bc252e2..744986f822 100644 --- a/packages/webpack-extensions/src/stylable-metadata-loader.ts +++ b/packages/webpack-extensions/src/stylable-metadata-loader.ts @@ -1,4 +1,4 @@ -import { Stylable, processNamespace, MinimalFS } from '@stylable/core'; +import { Stylable, processNamespace, MinimalFS, createLegacyResolver } from '@stylable/core'; import { createStylableResolverCacheMap } from '@stylable/webpack-plugin'; import findConfig from 'find-config'; import type { LoaderDefinition, LoaderContext } from 'webpack'; @@ -49,14 +49,15 @@ function createStylable( if (!loader._compiler) { throw new Error('Stylable metadata loader requires a compiler instance'); } + const resolveModule = createLegacyResolver(loader.fs as unknown as MinimalFS, { + ...loader._compiler.options.resolve, + extensions: [], + }); return new Stylable({ projectRoot: loader.rootContext, fileSystem: loader.fs as unknown as MinimalFS, mode: loader._compiler.options.mode === 'development' ? 'development' : 'production', - resolveOptions: { - ...loader._compiler.options.resolve, - extensions: [], - }, + resolveModule, resolveNamespace, resolverCache: createStylableResolverCacheMap(loader._compiler), }); diff --git a/packages/webpack-plugin/src/plugin.ts b/packages/webpack-plugin/src/plugin.ts index 5a4b2c5165..5cb4fd56ac 100644 --- a/packages/webpack-plugin/src/plugin.ts +++ b/packages/webpack-plugin/src/plugin.ts @@ -1,4 +1,4 @@ -import { MinimalFS, Stylable, StylableConfig } from '@stylable/core'; +import { MinimalFS, Stylable, StylableConfig, createLegacyResolver } from '@stylable/core'; import { OptimizeConfig, DiagnosticsMode, @@ -369,7 +369,10 @@ export class StylableWebpackPlugin { const stylableConfig = this.getStylableConfig(compiler)?.config; validateDefaultConfig(stylableConfig?.defaultConfig); - + const resolveModule = createLegacyResolver(topLevelFs, { + ...resolverOptions, + extensions: [], // use Stylable's default extensions + }); this.stylable = new Stylable( this.options.stylableConfig( { @@ -380,16 +383,13 @@ export class StylableWebpackPlugin { */ fileSystem: topLevelFs, mode: compiler.options.mode === 'production' ? 'production' : 'development', - resolveOptions: { - ...resolverOptions, - extensions: [], // use Stylable's default extensions - }, resolveNamespace: createNamespaceStrategyNode({ hashSalt: compiler.options.output.hashSalt || '', }), requireModule: createDecacheRequire(compiler), optimizer: this.options.optimizer, resolverCache: createStylableResolverCacheMap(compiler), + resolveModule, /** * config order is user determined * each configuration points receives the default options, diff --git a/packages/webpack-plugin/test/e2e/projects/native-css/webpack.config.js b/packages/webpack-plugin/test/e2e/projects/native-css/webpack.config.js index 22d2a1b545..1ad1238a8b 100644 --- a/packages/webpack-plugin/test/e2e/projects/native-css/webpack.config.js +++ b/packages/webpack-plugin/test/e2e/projects/native-css/webpack.config.js @@ -1,4 +1,4 @@ -const { createDefaultResolver } = require('@stylable/core'); +const { createLegacyResolver } = require('@stylable/core'); const { StylableWebpackPlugin } = require('@stylable/webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); @@ -12,7 +12,8 @@ module.exports = { new StylableWebpackPlugin({ stylableConfig(config, compiler) { // set custom resolve for test - const resolve = createDefaultResolver(compiler.inputFileSystem, {}); + + const resolve = createLegacyResolver(compiler.inputFileSystem, {}); config.resolveModule = (path, request) => { if (request === './resolve-me') { return resolve(path, './custom-resolved.css'); diff --git a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/stylable.config.js b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/stylable.config.js index 7971ad948f..4d5a8e08c3 100644 --- a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/stylable.config.js +++ b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/stylable.config.js @@ -1,11 +1,11 @@ //@ts-check const { join } = require('path'); -const { createDefaultResolver } = require('@stylable/core'); +const { createLegacyResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { alias: { 'wp-alias': join(__dirname, 'src/wrong'), }, diff --git a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/webpack.config.js b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/webpack.config.js index add3a604c2..0296b3c91e 100644 --- a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/webpack.config.js +++ b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-inline-override/webpack.config.js @@ -1,7 +1,7 @@ const { StylableWebpackPlugin } = require('@stylable/webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { join } = require('path'); -const { createDefaultResolver } = require('@stylable/core'); +const { createLegacyResolver } = require('@stylable/core'); /** @type {import('webpack').Configuration} */ module.exports = { @@ -12,7 +12,7 @@ module.exports = { new StylableWebpackPlugin({ stylableConfig: (config) => ({ ...config, - resolveModule: createDefaultResolver(config.fileSystem, { + resolveModule: createLegacyResolver(config.fileSystem, { alias: { 'wp-alias': join(__dirname, 'src/webpack-alias'), }, diff --git a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-override/stylable.config.js b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-override/stylable.config.js index 20ecdf356c..0d37e1b9c3 100644 --- a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-override/stylable.config.js +++ b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver-override/stylable.config.js @@ -1,11 +1,11 @@ //@ts-check const { join } = require('path'); -const { createDefaultResolver } = require('@stylable/core'); +const { createLegacyResolver } = require('@stylable/core'); module.exports = { defaultConfig(fs) { return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { alias: { 'wp-alias': join(__dirname, 'src/wrong'), }, @@ -18,7 +18,7 @@ module.exports = { stylableConfig(defaultStylableConfig) { return { ...defaultStylableConfig, - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { alias: { 'wp-alias': join(__dirname, 'src/webpack-alias'), }, diff --git a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver/stylable.config.js b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver/stylable.config.js index 35a295be6b..25bfdf59c3 100644 --- a/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver/stylable.config.js +++ b/packages/webpack-plugin/test/e2e/projects/stylable-config-resolver/stylable.config.js @@ -1,12 +1,16 @@ //@ts-check const { join } = require('path'); -const { createDefaultResolver } = require('@stylable/core'); +const { createLegacyResolver } = require('@stylable/core'); const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin'); module.exports = { defaultConfig(fs) { + ///////////////////////////////////////// + ///////////////////////////////////////// + ///////////////////////////////////////// + ///////////////////////////////////////// return { - resolveModule: createDefaultResolver(fs, { + resolveModule: createLegacyResolver(fs, { alias: { 'wp-alias': join(__dirname, 'src/webpack-alias'), },