diff --git a/.gitignore b/.gitignore index c66d7811..e6f7af6a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ test/fixtures/ts/node_modules/aliyun-egg/ !test/fixtures/test-demo-app/node_modules/ !test/fixtures/test-demo-app-esm/node_modules/ +!test/fixtures/test-postinstall/node_modules/ +!test/fixtures/test path with space/**/node_modules/ + .mochawesome-reports run .tmp @@ -36,6 +39,7 @@ yarn.lock dist test/fixtures/example-declarations/typings/ !test/fixtures/example-declarations/node_modules +!test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/dist/ .package-lock.json .tshy* .eslintcache diff --git a/scripts/postinstall.mjs b/scripts/postinstall.mjs index 94ca9053..a3abf130 100644 --- a/scripts/postinstall.mjs +++ b/scripts/postinstall.mjs @@ -52,7 +52,7 @@ async function main() { // https://github.com/eggjs/egg-ts-helper/pull/104 process.env.ETS_SCRIPT_FRAMEWORK = frameworkPackageName; console.log('[@eggjs/bin/postinstall] run %s on %s', etsBinFile, npmRunRoot); - runScript(`node ${etsBinFile}`); + runScript(`node "${etsBinFile}"`); } } } diff --git a/src/baseCommand.ts b/src/baseCommand.ts index db12bc1e..a819c727 100644 --- a/src/baseCommand.ts +++ b/src/baseCommand.ts @@ -1,6 +1,7 @@ import { debuglog } from 'node:util'; import { pathToFileURL } from 'node:url'; import path from 'node:path'; +import os from 'node:os'; import { fork, ForkOptions, ChildProcess } from 'node:child_process'; import { Command, Flags, Interfaces } from '@oclif/core'; import { importResolve } from '@eggjs/utils'; @@ -261,7 +262,7 @@ export abstract class BaseCommand extends Command { paths: findPaths, }); debug('run ets first: %o', etsBin); - await runScript(`node ${etsBin}`); + await runScript(`node "${etsBin}"`); } if (this.pkgEgg.revert) { @@ -327,9 +328,13 @@ export abstract class BaseCommand extends Command { protected formatImportModule(modulePath: string) { if (this.isESM) { - return `--import ${pathToFileURL(modulePath).href}`; + return `--import "${pathToFileURL(modulePath).href}"`; } - return `--require ${modulePath}`; + if (os.platform() === 'win32') { + // windows path need to escape backslash: `node --require "C:\\path\\to\\module"` + return `--require "${path.win32.normalize(modulePath).replace(/\\/g, '\\\\')}"`; + } + return `--require "${modulePath}"`; } protected addNodeOptions(options: string) { diff --git a/src/commands/dev.ts b/src/commands/dev.ts index cc687e1b..8e0c0823 100644 --- a/src/commands/dev.ts +++ b/src/commands/dev.ts @@ -44,8 +44,15 @@ export default class Dev extends BaseCommand { const requires = await this.formatRequires(); const execArgv: string[] = []; for (const r of requires) { - const imports = this.formatImportModule(r).split(' '); - execArgv.push(...imports); + const module = this.formatImportModule(r); + + // Remove the quotes from the path + // --require "module path" -> ['--require', 'module path'] + // --import "module path" -> ['--import', 'module path'] + const splitIndex = module.indexOf(' '); + if (splitIndex !== -1) { + execArgv.push(module.slice(0, splitIndex), module.slice(splitIndex + 2, -1)); + } } await this.forkNode(serverBin, args, { execArgv }); } diff --git a/test/commands/cov.test.ts b/test/commands/cov.test.ts index 49d0aaab..b7d2f49f 100644 --- a/test/commands/cov.test.ts +++ b/test/commands/cov.test.ts @@ -147,7 +147,15 @@ describe('test/commands/cov.test.ts', () => { // .debug() .expect('stdout', /1\) should fail/) .expect('stdout', /1 failing/) - .expect('stderr', /exit with code 1/) + // The formatted coverage report will automatically wrap when output. + // There is a certain probability that it will be truncated. + // For example: + // ==== Coverage Summary ==== + // Error: xxxxxxxxx.js exit + // with code 1 + // Code: 1 + + // .expect('stderr', /exit with code 1/) .expect('code', 1) .end(); }); diff --git a/test/commands/dev.test.ts b/test/commands/dev.test.ts index 6af649d5..1c17f33e 100644 --- a/test/commands/dev.test.ts +++ b/test/commands/dev.test.ts @@ -231,4 +231,58 @@ describe('test/commands/dev.test.ts', () => { .expect('code', 0) .end(); }); + + describe('work on special path', () => { + it('should work with space in path', () => { + return coffee.fork(eggBin, [ 'dev' ], { + cwd: getFixtures('test path with space/example-app'), + }) + // .debug() + .expect('stdout', /Hello, world!/) + .expect('code', 0) + .end(); + }); + + it('should support declarations with space in path', () => { + return coffee.fork(eggBin, [ 'dev' ], { + cwd: getFixtures('test path with space/example-declarations'), + }) + // .debug() + .expect('stdout', /Hi, I am Egg TS helper!/) + .expect('code', 0) + .end(); + }); + + it('should support egg.require with space in path', () => { + return coffee.fork(eggBin, [ 'dev' ], { + cwd: getFixtures('test path with space/example-egg-require'), + }) + // .debug() + .expect('stdout', /hey, you require me by --require/) + .expect('code', 0) + .end(); + }); + + it('should support --require with space in path', () => { + return coffee.fork(eggBin, [ 'dev', '--require', getFixtures('test path with space/require script.cjs') ], { + cwd: getFixtures('test path with space/example-require-script'), + }) + // .debug() + .expect('stdout', /hey, you require me by --require/) + .expect('code', 0) + .end(); + }); + + it('should support --import with space in path', () => { + return coffee.fork(eggBin, [ 'dev', '--import', getFixtures('test path with space/require script.mjs') ], { + cwd: getFixtures('test path with space/example-import-script'), + }) + // .debug() + .expect('stdout', /hey, you require me by --import/) + .expect('code', 0) + .end(); + }); + + }); + }); diff --git a/test/commands/test.test.ts b/test/commands/test.test.ts index e0bf2ee7..ce626e60 100644 --- a/test/commands/test.test.ts +++ b/test/commands/test.test.ts @@ -394,4 +394,16 @@ describe('test/commands/test.test.ts', () => { .end(); }); }); + + describe('work on special path', () => { + it('should work with space in path', () => { + return coffee.fork(eggBin, [ 'test' ], { + cwd: getFixtures('test path with space/test-files'), + }) + // .debug() + .expect('stdout', /should success/) + .expect('code', 0) + .end(); + }); + }); }); diff --git a/test/fixtures/example-ts-error-stack/node_modules/egg/index.js b/test/fixtures/example-ts-error-stack/node_modules/egg/index.js index 3a6c26e9..1b233725 100644 --- a/test/fixtures/example-ts-error-stack/node_modules/egg/index.js +++ b/test/fixtures/example-ts-error-stack/node_modules/egg/index.js @@ -5,4 +5,4 @@ module.exports = require('../../../../../node_modules/egg'); setTimeout(() => { console.log('exit by master test end'); process.exit(0); -}, require('os').platform() === 'win32' ? 11000 : 10000); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-app/app.ts b/test/fixtures/test path with space/example-app/app.ts new file mode 100644 index 00000000..a095265a --- /dev/null +++ b/test/fixtures/test path with space/example-app/app.ts @@ -0,0 +1,4 @@ + +export default function () { + console.log('Hello, world!'); +} diff --git a/test/fixtures/test path with space/example-app/node_modules/egg/index.js b/test/fixtures/test path with space/example-app/node_modules/egg/index.js new file mode 100644 index 00000000..64b113f8 --- /dev/null +++ b/test/fixtures/test path with space/example-app/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-app/node_modules/egg/package.json b/test/fixtures/test path with space/example-app/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test path with space/example-app/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test path with space/example-app/package.json b/test/fixtures/test path with space/example-app/package.json new file mode 100644 index 00000000..9ddbbc90 --- /dev/null +++ b/test/fixtures/test path with space/example-app/package.json @@ -0,0 +1,9 @@ +{ + "name": "example-app", + "egg": { + "typescript": true + }, + "dependencies": { + "egg": "*" + } +} diff --git a/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/dist/bin.js b/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/dist/bin.js new file mode 100644 index 00000000..61e9860f --- /dev/null +++ b/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/dist/bin.js @@ -0,0 +1,2 @@ + +console.log('Hi, I am Egg TS helper!'); diff --git a/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/package.json b/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/package.json new file mode 100644 index 00000000..2c6bbb59 --- /dev/null +++ b/test/fixtures/test path with space/example-declarations/node_modules/egg-ts-helper/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg-ts-helper" +} diff --git a/test/fixtures/test path with space/example-declarations/node_modules/egg/index.js b/test/fixtures/test path with space/example-declarations/node_modules/egg/index.js new file mode 100644 index 00000000..64b113f8 --- /dev/null +++ b/test/fixtures/test path with space/example-declarations/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-declarations/node_modules/egg/package.json b/test/fixtures/test path with space/example-declarations/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test path with space/example-declarations/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test path with space/example-declarations/package.json b/test/fixtures/test path with space/example-declarations/package.json new file mode 100644 index 00000000..4ff083d4 --- /dev/null +++ b/test/fixtures/test path with space/example-declarations/package.json @@ -0,0 +1,9 @@ +{ + "name": "example-declarations", + "egg": { + "declarations": true + }, + "dependencies": { + "egg": "*" + } +} diff --git a/test/fixtures/test path with space/example-egg-require/node_modules/egg/index.js b/test/fixtures/test path with space/example-egg-require/node_modules/egg/index.js new file mode 100644 index 00000000..64b113f8 --- /dev/null +++ b/test/fixtures/test path with space/example-egg-require/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-egg-require/node_modules/egg/package.json b/test/fixtures/test path with space/example-egg-require/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test path with space/example-egg-require/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test path with space/example-egg-require/package.json b/test/fixtures/test path with space/example-egg-require/package.json new file mode 100644 index 00000000..4216ac52 --- /dev/null +++ b/test/fixtures/test path with space/example-egg-require/package.json @@ -0,0 +1,8 @@ +{ + "name": "example-egg-require", + "egg": { + "require": [ + "../require script.cjs" + ] + } +} diff --git a/test/fixtures/test path with space/example-import-script/node_modules/egg/index.js b/test/fixtures/test path with space/example-import-script/node_modules/egg/index.js new file mode 100644 index 00000000..64b113f8 --- /dev/null +++ b/test/fixtures/test path with space/example-import-script/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-import-script/node_modules/egg/package.json b/test/fixtures/test path with space/example-import-script/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test path with space/example-import-script/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test path with space/example-import-script/package.json b/test/fixtures/test path with space/example-import-script/package.json new file mode 100644 index 00000000..49bbc207 --- /dev/null +++ b/test/fixtures/test path with space/example-import-script/package.json @@ -0,0 +1,4 @@ +{ + "name": "example-import-script", + "type": "module" +} diff --git a/test/fixtures/test path with space/example-require-script/node_modules/egg/index.js b/test/fixtures/test path with space/example-require-script/node_modules/egg/index.js new file mode 100644 index 00000000..64b113f8 --- /dev/null +++ b/test/fixtures/test path with space/example-require-script/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, require('os').platform() === 'win32' ? 21000 : 10000); diff --git a/test/fixtures/test path with space/example-require-script/node_modules/egg/package.json b/test/fixtures/test path with space/example-require-script/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test path with space/example-require-script/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test path with space/example-require-script/package.json b/test/fixtures/test path with space/example-require-script/package.json new file mode 100644 index 00000000..f2933061 --- /dev/null +++ b/test/fixtures/test path with space/example-require-script/package.json @@ -0,0 +1,3 @@ +{ + "name": "example-require-script" +} diff --git a/test/fixtures/test path with space/require script.cjs b/test/fixtures/test path with space/require script.cjs new file mode 100644 index 00000000..7b674d1e --- /dev/null +++ b/test/fixtures/test path with space/require script.cjs @@ -0,0 +1 @@ +console.log('hey, you require me by --require'); diff --git a/test/fixtures/test path with space/require script.mjs b/test/fixtures/test path with space/require script.mjs new file mode 100644 index 00000000..e843d5f2 --- /dev/null +++ b/test/fixtures/test path with space/require script.mjs @@ -0,0 +1 @@ +console.log('hey, you require me by --import'); diff --git a/test/fixtures/test path with space/test-files/package.json b/test/fixtures/test path with space/test-files/package.json new file mode 100644 index 00000000..37cbfb28 --- /dev/null +++ b/test/fixtures/test path with space/test-files/package.json @@ -0,0 +1,3 @@ +{ + "name": "test-files" +} diff --git a/test/fixtures/test path with space/test-files/test/t e s t.test.js b/test/fixtures/test path with space/test-files/test/t e s t.test.js new file mode 100644 index 00000000..9d8c9000 --- /dev/null +++ b/test/fixtures/test path with space/test-files/test/t e s t.test.js @@ -0,0 +1,9 @@ +'use strict'; + +const assert = require('assert'); + +describe('test', () => { + it('should success', () => { + assert(true); + }); +}); diff --git a/test/fixtures/test-postinstall/node_modules/egg/index.js b/test/fixtures/test-postinstall/node_modules/egg/index.js new file mode 100644 index 00000000..35a2064f --- /dev/null +++ b/test/fixtures/test-postinstall/node_modules/egg/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = require('../../../../../node_modules/egg'); + +setTimeout(() => { + console.log('exit by master test end'); + process.exit(0); +}, 10000); diff --git a/test/fixtures/test-postinstall/node_modules/egg/package.json b/test/fixtures/test-postinstall/node_modules/egg/package.json new file mode 100644 index 00000000..6697ad3f --- /dev/null +++ b/test/fixtures/test-postinstall/node_modules/egg/package.json @@ -0,0 +1,3 @@ +{ + "name": "egg" +} diff --git a/test/fixtures/test-postinstall/package.json b/test/fixtures/test-postinstall/package.json new file mode 100644 index 00000000..d18e56f8 --- /dev/null +++ b/test/fixtures/test-postinstall/package.json @@ -0,0 +1,9 @@ +{ + "name": "test-postinstall", + "egg": { + "typescript": true + }, + "dependencies": { + "egg": "*" + } +} diff --git a/test/fixtures/test-postinstall/typings/app/index.d.ts b/test/fixtures/test-postinstall/typings/app/index.d.ts new file mode 100644 index 00000000..5869d6fa --- /dev/null +++ b/test/fixtures/test-postinstall/typings/app/index.d.ts @@ -0,0 +1,7 @@ +// This file is created by egg-ts-helper@3.1.1 +// Do not modify this file!!!!!!!!! +/* eslint-disable */ + +import 'egg'; +export * from 'egg'; +export as namespace Egg; diff --git a/test/fixtures/test-postinstall/typings/config/plugin.d.ts b/test/fixtures/test-postinstall/typings/config/plugin.d.ts new file mode 100644 index 00000000..8d386d10 --- /dev/null +++ b/test/fixtures/test-postinstall/typings/config/plugin.d.ts @@ -0,0 +1,34 @@ +// This file is created by egg-ts-helper@3.1.1 +// Do not modify this file!!!!!!!!! +/* eslint-disable */ + +import 'egg'; +import '@eggjs/onerror'; +import '@eggjs/session'; +import '@eggjs/i18n'; +import '@eggjs/watcher'; +import '@eggjs/multipart'; +import '@eggjs/security'; +import '@eggjs/development'; +import '@eggjs/logrotator'; +import '@eggjs/schedule'; +import '@eggjs/static'; +import '@eggjs/jsonp'; +import '@eggjs/view'; +import { EggPluginItem } from 'egg'; +declare module 'egg' { + interface EggPlugin { + onerror?: EggPluginItem; + session?: EggPluginItem; + i18n?: EggPluginItem; + watcher?: EggPluginItem; + multipart?: EggPluginItem; + security?: EggPluginItem; + development?: EggPluginItem; + logrotator?: EggPluginItem; + schedule?: EggPluginItem; + static?: EggPluginItem; + jsonp?: EggPluginItem; + view?: EggPluginItem; + } +} \ No newline at end of file diff --git a/test/postinstall.test.ts b/test/postinstall.test.ts new file mode 100644 index 00000000..77d1ae24 --- /dev/null +++ b/test/postinstall.test.ts @@ -0,0 +1,41 @@ +import path from 'node:path'; +import coffee from './coffee.js'; +import { getRootDirname, getFixtures } from './helper.js'; + +describe('test/postinstall.test.ts', () => { + const postInstallScript = path.join(getRootDirname(), 'scripts/postinstall.mjs'); + const NODE_DEBUG = '@eggjs/bin/scripts/postinstall'; + + it('should work', () => { + const cwd = getFixtures('test-postinstall'); + return coffee.fork(postInstallScript, [], { + cwd, + env: { + NODE_DEBUG, + npm_rootpath: cwd, + }, + }) + // .debug() + .expect('stdout', /\[egg\-ts\-helper\] create typings[\/\\]config[\/\\]plugin\.d\.ts/) + .expect('stdout', /\[egg\-ts\-helper\] create typings[\/\\]app[\/\\]index\.d\.ts/) + .expect('code', 0) + .end(); + }); + + it('should work with special path', () => { + const cwd = getFixtures('test path with space/example-declarations'); + const tsHelper = getFixtures('test path with space/example-declarations/node_modules/egg-ts-helper/dist/bin.js'); + return coffee.fork(postInstallScript, [ tsHelper ], { + cwd, + env: { + NODE_DEBUG, + npm_rootpath: cwd, + }, + }) + // .debug() + .expect('stdout', /Hi, I am Egg TS helper!/) + .expect('code', 0) + .end(); + }); + +});