diff --git a/.changeset/fair-eels-kiss.md b/.changeset/fair-eels-kiss.md new file mode 100644 index 000000000..993fbd415 --- /dev/null +++ b/.changeset/fair-eels-kiss.md @@ -0,0 +1,10 @@ +--- +'@halfdomelabs/baseplate-plugin-storage': patch +'@halfdomelabs/project-builder-server': patch +'@halfdomelabs/project-builder-test': patch +'@halfdomelabs/project-builder-lib': patch +'@halfdomelabs/core-generators': patch +'@halfdomelabs/sync': patch +--- + +Support generation on Windows platforms diff --git a/packages/core-generators/src/generators/node/prettier/index.ts b/packages/core-generators/src/generators/node/prettier/index.ts index da001a30b..4c17c7ba1 100644 --- a/packages/core-generators/src/generators/node/prettier/index.ts +++ b/packages/core-generators/src/generators/node/prettier/index.ts @@ -10,6 +10,7 @@ import { import fs from 'fs-extra'; import _ from 'lodash'; import path from 'node:path'; +import { pathToFileURL } from 'node:url'; import { packageUp } from 'package-up'; import prettier from 'prettier'; import prettierPluginPackageJson from 'prettier-plugin-packagejson'; @@ -175,7 +176,10 @@ const PrettierGenerator = createGeneratorWithChildren({ if (result.version === prettier.version) { return prettier; } - const rawImport = (await import(result.modulePath)) as { + const rawImport = (await import( + // use file:// to support Windows + pathToFileURL(result.modulePath).href + )) as { default: PrettierModule; }; return rawImport.default; @@ -202,7 +206,9 @@ const PrettierGenerator = createGeneratorWithChildren({ return plugin.version === resolvedModule.version ? plugin.default - : (import(resolvedModule.modulePath) as Plugin); + : (import( + pathToFileURL(resolvedModule.modulePath).href + ) as Plugin); }), ); diff --git a/packages/core-generators/src/utils/path.ts b/packages/core-generators/src/utils/path.ts index c39b70aa8..154516140 100644 --- a/packages/core-generators/src/utils/path.ts +++ b/packages/core-generators/src/utils/path.ts @@ -1,8 +1,13 @@ +import path from 'node:path'; + /** * Builds out the full path so it can be used for imports/writing to file * @param path Path to the file with file extension */ -export function makeImportAndFilePath(path: string): [string, string] { - const importPath = `@/${path.replace(/\.(ts|tsx)$/, '.js')}`; - return [importPath, path]; +export function makeImportAndFilePath(filePath: string): [string, string] { + const importPath = `@/${filePath + .replace(/\.(ts|tsx)$/, '.js') + // normalize path separators for Windows to POSIX for imports + .replaceAll(path.sep, path.posix.sep)}`; + return [importPath, filePath]; } diff --git a/packages/core-generators/src/writers/typescript/imports.ts b/packages/core-generators/src/writers/typescript/imports.ts index 813f16aa6..ad38ecfe2 100644 --- a/packages/core-generators/src/writers/typescript/imports.ts +++ b/packages/core-generators/src/writers/typescript/imports.ts @@ -80,7 +80,9 @@ export function resolveModule( // figure out relative directory const absolutePath = moduleSpecifier.slice(2); const relativePathImport = (() => { - const relativePath = path.relative(directory, absolutePath); + const relativePath = path + .relative(directory, absolutePath) + .replaceAll(path.sep, path.posix.sep); return relativePath.startsWith('./') || relativePath.startsWith('../') || diff --git a/packages/project-builder-lib/src/plugin-tools/plugin-loader.ts b/packages/project-builder-lib/src/plugin-tools/plugin-loader.ts index 179a75d0e..372542d97 100644 --- a/packages/project-builder-lib/src/plugin-tools/plugin-loader.ts +++ b/packages/project-builder-lib/src/plugin-tools/plugin-loader.ts @@ -145,10 +145,9 @@ function getWebEntrypointImport( entrypointPath: string, ): string { const pathWithoutExtension = entrypointPath.replace(/\.[jt]sx?$/, ''); - const relativeEntrypoint = path.relative( - pluginDirectory, - pathWithoutExtension, - ); + const relativeEntrypoint = path + .relative(pluginDirectory, pathWithoutExtension) + .replace(/\\/g, '/'); return `${pluginName}/${relativeEntrypoint}`; } diff --git a/packages/project-builder-server/src/plugins/node-plugin-store.ts b/packages/project-builder-server/src/plugins/node-plugin-store.ts index 992117c8b..f67469ac0 100644 --- a/packages/project-builder-server/src/plugins/node-plugin-store.ts +++ b/packages/project-builder-server/src/plugins/node-plugin-store.ts @@ -12,6 +12,7 @@ import { modelTransformerCompilerSpec, } from '@halfdomelabs/project-builder-lib'; import path from 'node:path'; +import { pathToFileURL } from 'node:url'; import { discoverPlugins } from './plugin-discovery.js'; @@ -29,7 +30,7 @@ export async function createNodePluginStore( metadata: plugin, modules: await Promise.all( plugin.nodeModulePaths.map(async (modulePath) => { - const mod = (await import(modulePath)) as + const mod = (await import(pathToFileURL(modulePath).href)) as | { default: PluginPlatformModule } | PluginPlatformModule; const unwrappedModule = 'default' in mod ? mod.default : mod; diff --git a/packages/project-builder-test/src/runner/discover-tests.ts b/packages/project-builder-test/src/runner/discover-tests.ts index 37d4a617f..497944dff 100644 --- a/packages/project-builder-test/src/runner/discover-tests.ts +++ b/packages/project-builder-test/src/runner/discover-tests.ts @@ -1,5 +1,6 @@ import { globby } from 'globby'; import path from 'node:path'; +import { pathToFileURL } from 'node:url'; import type { ProjectBuilderTest } from '@src/types.js'; @@ -22,7 +23,9 @@ export async function discoverTests( return Promise.all( matchingTestFiles.map(async (testFile) => { - const file = (await import(path.join(testDirectory, testFile))) as { + const file = (await import( + pathToFileURL(path.join(testDirectory, testFile)).href + )) as { default?: ProjectBuilderTest; }; if (!file.default || typeof file.default !== 'object') { diff --git a/packages/sync/src/core/generator-output.ts b/packages/sync/src/core/generator-output.ts index 6ea950b0d..7da79c7c8 100644 --- a/packages/sync/src/core/generator-output.ts +++ b/packages/sync/src/core/generator-output.ts @@ -176,9 +176,15 @@ export class OutputBuilder implements GeneratorOutputBuilder { } resolvePath(relativePath: string): string { - return this.baseDirectory - ? path.join(this.baseDirectory, relativePath) - : relativePath; + return ( + ( + this.baseDirectory + ? path.join(this.baseDirectory, relativePath) + : relativePath + ) + // normalize all paths to POSIX style / paths + .replaceAll(path.sep, path.posix.sep) + ); } setBaseDirectory(baseDirectory: string): void { diff --git a/packages/sync/src/core/loader.ts b/packages/sync/src/core/loader.ts index 926c94404..9d4b72f29 100644 --- a/packages/sync/src/core/loader.ts +++ b/packages/sync/src/core/loader.ts @@ -83,7 +83,7 @@ export async function loadGeneratorsForModule( `Generator function lacks a parseDescriptor function: ${generatorFolder}`, ); } - const name = `${moduleName.replace(/-generators$/, '')}/${folder}`; + const name = `${moduleName.replace(/-generators$/, '')}/${folder.replaceAll(path.sep, path.posix.sep)}`; return { [name]: { diff --git a/packages/sync/src/utils/require.ts b/packages/sync/src/utils/require.ts index 681ae22a7..c07b1bb16 100644 --- a/packages/sync/src/utils/require.ts +++ b/packages/sync/src/utils/require.ts @@ -1,4 +1,5 @@ import path from 'node:path'; +import { pathToFileURL } from 'node:url'; /** * Simple function to load a module dynamically @@ -6,7 +7,10 @@ import path from 'node:path'; * @param module Name of module to load */ export async function getModuleDefault(module: string): Promise { - const importedModule = (await import(path.join(module, 'index.js'))) as { + const fileUrl = module.startsWith('file://') + ? module + : pathToFileURL(module).href; + const importedModule = (await import(path.join(fileUrl, 'index.js'))) as { default: T; }; return importedModule.default; diff --git a/plugins/baseplate-plugin-storage/src/generators/fastify/storage-module/index.ts b/plugins/baseplate-plugin-storage/src/generators/fastify/storage-module/index.ts index 54015246f..857c91248 100644 --- a/plugins/baseplate-plugin-storage/src/generators/fastify/storage-module/index.ts +++ b/plugins/baseplate-plugin-storage/src/generators/fastify/storage-module/index.ts @@ -78,7 +78,7 @@ const StorageModuleGenerator = createGeneratorWithTasks({ pothosSetup.getTypeReferences().addInputType({ typeName: 'FileUploadInput', exportName: 'fileUploadInputInputType', - moduleName: `@/${path.join( + moduleName: `@/${path.posix.join( moduleFolder, 'schema/file-upload.input-type.js', )}`,