Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: move to file-services/resolve as default resolver #2907

Merged
merged 8 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
28 changes: 27 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/cli/src/cli-codemod.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
11 changes: 5 additions & 6 deletions packages/cli/src/code-format.ts
Original file line number Diff line number Diff line change
@@ -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]')
Expand Down Expand Up @@ -134,7 +133,7 @@ for (const request of requires) {
}

function readDirectoryDeep(dirPath: string, fileSuffixFilter = '.st.css', res = new Set<string>()) {
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);
Expand All @@ -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, {
Expand Down Expand Up @@ -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')) {
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/config/projects-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> | undefined;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/assets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/test/build.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -701,7 +701,7 @@ describe('build stand alone', () => {
requireModule: () => ({}),
resolveOptions: {
alias: {
'@colors': '/colors',
'@colors/*': '/colors/*',
},
},
});
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/test/cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
barak007 marked this conversation as resolved.
Show resolved Hide resolved
const { createLegacyResolver } = require('@stylable/webpack-plugin');

module.exports = {
defaultConfig(fs) {
return {
resolveModule: createDefaultResolver(fs, {
resolveModule: createLegacyResolver(fs, {
alias: {
'@colors': resolve(__dirname, './colors')
}
Expand Down Expand Up @@ -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/webpack-plugin');

module.exports = {
defaultConfig(fs) {
return {
resolveModule: createDefaultResolver(fs, {
resolveModule: createLegacyResolver(fs, {
plugins: [new TsconfigPathsPlugin({ configFile: join(${JSON.stringify(
tempDir.path
)},'tsconfig.json') })],
Expand Down
2 changes: 1 addition & 1 deletion packages/core-test-kit/src/generate-test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion packages/core-test-kit/test/inline-expectations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
"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",
"balanced-match": "^2.0.0",
"css-selector-tokenizer": "^0.8.0",
"cssesc": "^3.0.0",
"enhanced-resolve": "^5.15.0",
"is-vendor-prefixed": "^4.0.0",
"lodash.clonedeep": "^4.5.0",
"lodash.clonedeepwith": "^4.5.0",
Expand Down
47 changes: 12 additions & 35 deletions packages/core/src/module-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,24 @@
// in browser build this gets remapped to an empty object via our package.json->"browser"
barak007 marked this conversation as resolved.
Show resolved Hide resolved
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<string, unknown> })
._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'],
barak007 marked this conversation as resolved.
Show resolved Hide resolved
...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') {
idoros marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(`Stylable could not resolve ${JSON.stringify(request)} from ${JSON.stringify(directoryPath)}`);
}
return res.resolvedFile;
};
}
4 changes: 3 additions & 1 deletion packages/core/src/stylable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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?: {
idoros marked this conversation as resolved.
Show resolved Hide resolved
alias?: any;
symlinks?: boolean;
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions packages/core/test/features/st-import.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 "/"`;
idoros marked this conversation as resolved.
Show resolved Hide resolved
const resolveErrorMessagePackage = `Stylable could not resolve "missing-package/index.st.css" from "/"`;

testStylableCore(`
/* @transform-error(relative) word(./missing.st.css) ${stImportDiagnostics.UNKNOWN_IMPORTED_FILE(
Expand Down Expand Up @@ -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(
Expand Down
Loading