mirror of
https://github.com/strapi/strapi.git
synced 2025-09-07 15:49:24 +00:00
Migrate latest to ts
This commit is contained in:
parent
c779954631
commit
ddaa9e6775
@ -0,0 +1,14 @@
|
||||
import type { Utils } from '@strapi/strapi';
|
||||
|
||||
const expectExit = async (code: number, fn: Utils.Function.Any) => {
|
||||
const exit = jest.spyOn(process, 'exit').mockImplementation((number) => {
|
||||
throw new Error(`process.exit: ${number}`);
|
||||
});
|
||||
await expect(async () => {
|
||||
await fn();
|
||||
}).rejects.toThrow('process.exit');
|
||||
expect(exit).toHaveBeenCalledWith(code);
|
||||
exit.mockRestore();
|
||||
};
|
||||
|
||||
export { expectExit };
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "testing",
|
||||
"version": "0.0.0"
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
|
||||
const {
|
||||
loadPkg,
|
||||
validatePkg,
|
||||
validateExportsOrdering,
|
||||
parseExports,
|
||||
getExportExtensionMap,
|
||||
} = require('../pkg');
|
||||
|
||||
const loggerMock = {
|
||||
debug: jest.fn(),
|
||||
info: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
|
||||
describe('pkg', () => {
|
||||
const tmpfolder = path.resolve(__dirname, '.tmp');
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('loadPkg', () => {
|
||||
beforeEach(async () => {
|
||||
await fs.mkdir(tmpfolder);
|
||||
await fs.copyFile(
|
||||
path.resolve(__dirname, 'fixtures', 'test.pkg.json'),
|
||||
path.resolve(tmpfolder, 'package.json')
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tmpfolder, { recursive: true });
|
||||
});
|
||||
|
||||
it('should succesfully load the package.json closest to the cwd provided & call the debug logger', async () => {
|
||||
const pkg = await loadPkg({ cwd: tmpfolder, logger: loggerMock });
|
||||
|
||||
expect(pkg).toMatchInlineSnapshot(`
|
||||
{
|
||||
"name": "testing",
|
||||
"version": "0.0.0",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(loggerMock.debug).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw an error if it cannot find a package.json', async () => {
|
||||
await expect(
|
||||
loadPkg({ cwd: '/', logger: loggerMock })
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Could not find a package.json in the current directory"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validatePkg', () => {
|
||||
it("should return the validated package.json if it's valid", async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
};
|
||||
|
||||
const validatedPkg = await validatePkg({ pkg });
|
||||
|
||||
expect(validatedPkg).toMatchInlineSnapshot(`
|
||||
{
|
||||
"name": "testing",
|
||||
"version": "0.0.0",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should fail if a required field is missing and call the error logger with the correct message', async () => {
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
version: '0.0.0',
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'name' in 'package.json' is required as type '[35mstring[39m'"`
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'version' in 'package.json' is required as type '[35mstring[39m'"`
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if a required field does not match the correct type and call the error logger with the correct message', async () => {
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
version: 0,
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'version' in 'package.json' must be of type '[35mstring[39m' (recieved '[35mnumber[39m')"`
|
||||
);
|
||||
});
|
||||
|
||||
it("should fail if the regex for a field doesn't match and call the error logger with the correct message", async () => {
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
apple: './apple.xyzx',
|
||||
},
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'exports.apple' in 'package.json' must be of type '[35m/^\\.\\/.*\\.json$/[39m' (recieved the value '[35m./apple.xyzx[39m')"`
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
type: 'something',
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'type' in 'package.json' must be of type '[35m/(commonjs|module)/[39m' (recieved the value '[35msomething[39m')"`
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the exports object does not match expectations', async () => {
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: 'hello',
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'exports' in 'package.json' must be of type '[35mobject[39m' (recieved '[35mstring[39m')"`
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
validatePkg({
|
||||
pkg: {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
import: './admin/index.js',
|
||||
something: 'xyz',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'exports["./admin"]' in 'package.json' contains the unknown key [35msomething[39m, for compatability only the following keys are allowed: [35m['types', 'source', 'import', 'require', 'default'][39m"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateExportsOrdering', () => {
|
||||
it('should throw if there are no exports at all and log that error', async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
};
|
||||
|
||||
await expect(
|
||||
validateExportsOrdering({ pkg, logger: loggerMock })
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"'package.json' must contain a 'main' and 'module' property"`
|
||||
);
|
||||
});
|
||||
|
||||
it("should return the package if there is at least a 'main' or 'module' property", async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
main: './index.js',
|
||||
};
|
||||
|
||||
const validatedPkg = await validateExportsOrdering({ pkg, logger: loggerMock });
|
||||
|
||||
expect(validatedPkg).toMatchInlineSnapshot(`
|
||||
{
|
||||
"main": "./index.js",
|
||||
"name": "testing",
|
||||
"version": "0.0.0",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should return the package if there is an exports property with a valid structure', async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.js',
|
||||
require: './admin/index.cjs',
|
||||
default: './admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const validatedPkg = await validateExportsOrdering({ pkg, logger: loggerMock });
|
||||
|
||||
expect(validatedPkg).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exports": {
|
||||
"./admin": {
|
||||
"default": "./admin/index.js",
|
||||
"import": "./admin/index.js",
|
||||
"require": "./admin/index.cjs",
|
||||
"types": "./admin/index.d.ts",
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
},
|
||||
"name": "testing",
|
||||
"version": "0.0.0",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw if the types property is not the first in an export object', async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
'./admin': {
|
||||
import: './admin/index.js',
|
||||
types: './admin/index.d.ts',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await expect(
|
||||
validateExportsOrdering({ pkg, logger: loggerMock })
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"exports["./admin"]: the 'types' property should be the first property"`
|
||||
);
|
||||
});
|
||||
|
||||
it('should log a warning if the require property comes before the import property in an export object', async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
'./admin': {
|
||||
require: './admin/index.cjs',
|
||||
import: './admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await validateExportsOrdering({ pkg, logger: loggerMock });
|
||||
|
||||
expect(loggerMock.warn.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
[
|
||||
"exports["./admin"]: the 'import' property should come before the 'require' property",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should log a warning if the import property comes the module property in an export object', async () => {
|
||||
const pkg = {
|
||||
name: 'testing',
|
||||
version: '0.0.0',
|
||||
exports: {
|
||||
'./admin': {
|
||||
import: './admin/index.js',
|
||||
module: './admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await validateExportsOrdering({ pkg, logger: loggerMock });
|
||||
|
||||
expect(loggerMock.warn.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
[
|
||||
"exports["./admin"]: the 'module' property should come before 'import' property",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getExportExtensionMap', () => {
|
||||
it('should just return the default mapping', async () => {
|
||||
expect(getExportExtensionMap()).toMatchInlineSnapshot(`
|
||||
{
|
||||
"commonjs": {
|
||||
"cjs": ".js",
|
||||
"es": ".mjs",
|
||||
},
|
||||
"module": {
|
||||
"cjs": ".cjs",
|
||||
"es": ".js",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseExports', () => {
|
||||
const extMap = getExportExtensionMap();
|
||||
|
||||
it('should by default return a root exports map using the standard export fields from the pkg.json', () => {
|
||||
const pkg = {
|
||||
types: './dist/index.d.ts',
|
||||
main: './dist/index.js',
|
||||
module: './dist/index.mjs',
|
||||
source: './src/index.ts',
|
||||
};
|
||||
|
||||
expect(parseExports({ pkg, extMap })).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"_path": ".",
|
||||
"default": "./dist/index.mjs",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js",
|
||||
"source": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it("should not return anything if the standard export fields don't exist and there is no export map", () => {
|
||||
const pkg = {};
|
||||
|
||||
expect(parseExports({ pkg, extMap })).toMatchInlineSnapshot(`[]`);
|
||||
});
|
||||
|
||||
it('should return a combination of the standard export fields and the export map if they both exist', () => {
|
||||
const pkg = {
|
||||
types: './dist/index.d.ts',
|
||||
main: './dist/index.js',
|
||||
module: './dist/index.mjs',
|
||||
source: './src/index.ts',
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.mjs',
|
||||
require: './admin/index.js',
|
||||
default: './admin/index.js',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(parseExports({ pkg, extMap })).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"_path": ".",
|
||||
"default": "./dist/index.mjs",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js",
|
||||
"source": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
},
|
||||
{
|
||||
"_exported": true,
|
||||
"_path": "./admin",
|
||||
"default": "./admin/index.js",
|
||||
"import": "./admin/index.mjs",
|
||||
"require": "./admin/index.js",
|
||||
"source": "./src/admin/index.js",
|
||||
"types": "./admin/index.d.ts",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should return just the exports map if there are no standard export fields and the export map exists', () => {
|
||||
const pkg = {
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.mjs',
|
||||
require: './admin/index.js',
|
||||
default: './admin/index.js',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(parseExports({ pkg, extMap })).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"_exported": true,
|
||||
"_path": "./admin",
|
||||
"default": "./admin/index.js",
|
||||
"import": "./admin/index.mjs",
|
||||
"require": "./admin/index.js",
|
||||
"source": "./src/admin/index.js",
|
||||
"types": "./admin/index.d.ts",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error if you try to use an exports map without supplying an export for the package.json file', () => {
|
||||
const pkg = {
|
||||
exports: {
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.mjs',
|
||||
require: './admin/index.js',
|
||||
default: './admin/index.js',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => parseExports({ pkg, extMap })).toThrowErrorMatchingInlineSnapshot(`
|
||||
"
|
||||
- package.json: \`exports["./package.json"] must be declared."
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error if the pkg.json type is undefined and you try to export like a module', () => {
|
||||
const pkg = {
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.js',
|
||||
require: './admin/index.cjs',
|
||||
default: './admin/index.cjs',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => parseExports({ pkg, extMap, type: 'module' }))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"
|
||||
- package.json with \`type: "undefined"\` - \`exports["./admin"].require\` must end with ".js"
|
||||
- package.json with \`type: "undefined"\` - \`exports["./admin"].import\` must end with ".mjs""
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error if the pkg.json type is commonjs and you try to export like a module', () => {
|
||||
const pkg = {
|
||||
type: 'commonjs',
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.js',
|
||||
require: './admin/index.cjs',
|
||||
default: './admin/index.cjs',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => parseExports({ pkg, extMap, type: 'module' }))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"
|
||||
- package.json with \`type: "commonjs"\` - \`exports["./admin"].require\` must end with ".js"
|
||||
- package.json with \`type: "commonjs"\` - \`exports["./admin"].import\` must end with ".mjs""
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error if the pkg.json type is module and you try to export like a commonjs', () => {
|
||||
const pkg = {
|
||||
type: 'module',
|
||||
exports: {
|
||||
'./package.json': './package.json',
|
||||
'./admin': {
|
||||
types: './admin/index.d.ts',
|
||||
import: './admin/index.mjs',
|
||||
require: './admin/index.js',
|
||||
default: './admin/index.js',
|
||||
source: './src/admin/index.js',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => parseExports({ pkg, extMap, type: 'module' }))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"
|
||||
- package.json with \`type: "module"\` - \`exports["./admin"].require\` must end with ".cjs"
|
||||
- package.json with \`type: "module"\` - \`exports["./admin"].import\` must end with ".js""
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,68 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { Command } = require('commander');
|
||||
|
||||
const strapiCommands = {
|
||||
'admin/create-user': require('./actions/admin/create-user/command'),
|
||||
'admin/reset-user-password': require('./actions/admin/reset-user-password/command'),
|
||||
build: require('./actions/build-command/command'), // in 'build-command' to avoid problems with 'build' being commonly ignored
|
||||
'components/list': require('./actions/components/list/command'),
|
||||
'configuration/dump': require('./actions/configuration/dump/command'),
|
||||
'configuration/restore': require('./actions/configuration/restore/command'),
|
||||
console: require('./actions/console/command'),
|
||||
'content-types/list': require('./actions/content-types/list/command'),
|
||||
'controllers/list': require('./actions/controllers/list/command'),
|
||||
develop: require('./actions/develop/command'),
|
||||
export: require('./actions/export/command'),
|
||||
generate: require('./actions/generate/command'),
|
||||
'hooks/list': require('./actions/hooks/list/command'),
|
||||
import: require('./actions/import/command'),
|
||||
install: require('./actions/install/command'),
|
||||
'middlewares/list': require('./actions/middlewares/list/command'),
|
||||
new: require('./actions/new/command'),
|
||||
'plugin/build': require('./actions/plugin/build-command/command'),
|
||||
'policies/list': require('./actions/policies/list/command'),
|
||||
report: require('./actions/report/command'),
|
||||
'routes/list': require('./actions/routes/list/command'),
|
||||
'services/list': require('./actions/services/list/command'),
|
||||
start: require('./actions/start/command'),
|
||||
'telemetry/disable': require('./actions/telemetry/disable/command'),
|
||||
'telemetry/enable': require('./actions/telemetry/enable/command'),
|
||||
'templates/generate': require('./actions/templates/generate/command'),
|
||||
transfer: require('./actions/transfer/command'),
|
||||
'ts/generate-types': require('./actions/ts/generate-types/command'),
|
||||
uninstall: require('./actions/uninstall/command'),
|
||||
version: require('./actions/version/command'),
|
||||
'watch-admin': require('./actions/watch-admin/command'),
|
||||
};
|
||||
|
||||
const buildStrapiCommand = (argv, command = new Command()) => {
|
||||
// Initial program setup
|
||||
command.storeOptionsAsProperties(false).allowUnknownOption(true);
|
||||
|
||||
// Help command
|
||||
command.helpOption('-h, --help', 'Display help for command');
|
||||
command.addHelpCommand('help [command]', 'Display help for command');
|
||||
|
||||
// Load all commands
|
||||
Object.keys(strapiCommands).forEach((name) => {
|
||||
try {
|
||||
// Add this command to the Commander command object
|
||||
strapiCommands[name]({ command, argv });
|
||||
} catch (e) {
|
||||
console.error(`Failed to load command ${name}`, e);
|
||||
}
|
||||
});
|
||||
|
||||
return command;
|
||||
};
|
||||
|
||||
const runStrapiCommand = async (argv = process.argv, command = new Command()) => {
|
||||
await buildStrapiCommand(argv, command).parseAsync(argv);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
runStrapiCommand,
|
||||
buildStrapiCommand,
|
||||
strapiCommands,
|
||||
};
|
@ -1,453 +0,0 @@
|
||||
import type { Database } from '@strapi/database';
|
||||
import type { Comomn, EntityService, Shared } from '@strapi/strapi';
|
||||
|
||||
// TODO move custom fields types to a separate file
|
||||
interface CustomFieldServerOptions {
|
||||
/**
|
||||
* The name of the custom field
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The name of the plugin creating the custom field
|
||||
*/
|
||||
pluginId?: string;
|
||||
|
||||
/**
|
||||
* The existing Strapi data type the custom field uses
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* Settings for the input size in the Admin UI
|
||||
*/
|
||||
inputSize?: {
|
||||
default: 4 | 6 | 8 | 12;
|
||||
isResizable: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface CustomFields {
|
||||
register: (customFields: CustomFieldServerOptions[] | CustomFieldServerOptions) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Strapi interface implemented by the main Strapi class.
|
||||
*/
|
||||
export interface Strapi {
|
||||
/**
|
||||
* Getter for the Strapi enterprise edition configuration
|
||||
*/
|
||||
readonly EE: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi configuration container
|
||||
*/
|
||||
readonly config: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi admin container
|
||||
*/
|
||||
readonly admin: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi auth container
|
||||
*/
|
||||
readonly auth: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi content API container
|
||||
*/
|
||||
readonly contentAPI: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi sanitizers container
|
||||
*/
|
||||
readonly sanitizers: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi validators container
|
||||
*/
|
||||
readonly validators: any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi services container
|
||||
*
|
||||
* It returns all the registered services
|
||||
*/
|
||||
readonly services: Shared.Services;
|
||||
|
||||
/**
|
||||
* Find a service using its unique identifier
|
||||
*/
|
||||
service<TService extends Common.Service = Common.Service>(uid: string): TService | undefined;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi controllers container
|
||||
*
|
||||
* It returns all the registered controllers
|
||||
*/
|
||||
readonly controllers: Shared.Controllers;
|
||||
|
||||
/**
|
||||
* Find a controller using its unique identifier
|
||||
*/
|
||||
controller<TContentTypeUID extends Common.UID.Controller>(
|
||||
uid: TContentTypeUID
|
||||
): Shared.Controllers[TContentTypeUID];
|
||||
|
||||
/**
|
||||
* Getter for the Strapi content types container
|
||||
*
|
||||
* It returns all the registered content types
|
||||
*/
|
||||
readonly contentTypes: any;
|
||||
|
||||
/**
|
||||
* Find a content type using its unique identifier
|
||||
*/
|
||||
contentType(uid: string): any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi component container
|
||||
*
|
||||
* It returns all the registered components
|
||||
*/
|
||||
readonly components: any;
|
||||
|
||||
/**
|
||||
* The custom fields registry
|
||||
*
|
||||
* It returns the custom fields interface
|
||||
*/
|
||||
readonly customFields: CustomFields;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi policies container
|
||||
*
|
||||
* It returns all the registered policies
|
||||
*/
|
||||
readonly policies: any;
|
||||
|
||||
/**
|
||||
* Find a policy using its name
|
||||
*/
|
||||
policy(name: string): any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi middlewares container
|
||||
*
|
||||
* It returns all the registered middlewares
|
||||
*/
|
||||
readonly middlewares: any;
|
||||
|
||||
/**
|
||||
* Find a middleware using its name
|
||||
*/
|
||||
middleware(): any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi plugins container
|
||||
*
|
||||
* It returns all the registered plugins
|
||||
*/
|
||||
readonly plugins: any;
|
||||
|
||||
/**
|
||||
* Find a plugin using its name
|
||||
*/
|
||||
plugin(name: string): any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi hooks container
|
||||
*
|
||||
* It returns all the registered hooks
|
||||
*/
|
||||
readonly hooks: any;
|
||||
|
||||
/**
|
||||
* Find a hook using its name
|
||||
*/
|
||||
hook(): any;
|
||||
|
||||
/**
|
||||
* Getter for the Strapi APIs container
|
||||
*
|
||||
* It returns all the registered APIs
|
||||
*/
|
||||
readonly api: any;
|
||||
|
||||
/**
|
||||
* Strapi Register Lifecycle.
|
||||
*
|
||||
* - Load
|
||||
* - The user application
|
||||
* - The plugins
|
||||
* - The admin
|
||||
* - The APIs
|
||||
* - The components
|
||||
* - The middlewares
|
||||
* - The policies
|
||||
* - Trigger Strapi internal bootstrap
|
||||
* - Create the webhooks runner
|
||||
* - Create the internal hooks registry.
|
||||
* - Init the telemetry cron job and middleware
|
||||
* - Run all the `register` lifecycle methods loaded by the user application or the enabled plugins
|
||||
*/
|
||||
register(): Promise<Strapi>;
|
||||
|
||||
/**
|
||||
* Bootstraping phase.
|
||||
*
|
||||
* - Load all the content types
|
||||
* - Initialize the database layer
|
||||
* - Initialize the entity service
|
||||
* - Run the schemas/database synchronization
|
||||
* - Start the webhooks and initializing middlewares and routes
|
||||
* - Run all the `bootstrap` lifecycle methods loaded by the
|
||||
* user application or the enabled plugins
|
||||
*/
|
||||
bootstrap(): Promise<Strapi>;
|
||||
|
||||
/**
|
||||
* Destroy phase
|
||||
*
|
||||
* - Destroy Strapi server
|
||||
* - Run all the `destroy` lifecycle methods loaded by the
|
||||
* user application or the enabled plugins
|
||||
* - Cleanup the event hub
|
||||
* - Gracefully stop the database
|
||||
* - Stop the telemetry and cron instance
|
||||
* - Cleanup the global scope by removing global.strapi
|
||||
*/
|
||||
destroy(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Run all functions registered for a given lifecycle. (Strapi core, user app, plugins)
|
||||
*/
|
||||
runLifecyclesFunctions<T extends Lifecycles[keyof Lifecycles]>(lifecycleName: T): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load the application if needed and start the server
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Stop the server and provide a custom error and message
|
||||
*/
|
||||
stopWithError<TError = unknown>(error: TError, customMessage?: string): void;
|
||||
|
||||
/**
|
||||
* Gracefully stop the server
|
||||
* Call the destroy method.
|
||||
*/
|
||||
stop(code?: number): void;
|
||||
|
||||
/**
|
||||
* Load the server and the user application.
|
||||
* It basically triggers the register and bootstrap phases
|
||||
*/
|
||||
load(): Promise<Strapi>;
|
||||
|
||||
/**
|
||||
* Restart the server and reload all the configuration.
|
||||
* It re-runs all the lifecycles phases.
|
||||
*
|
||||
* @example
|
||||
* ``` ts
|
||||
* setImmediate(() => strapi.reload());
|
||||
* ```
|
||||
*/
|
||||
reload(): () => void;
|
||||
|
||||
/**
|
||||
* Initialize and start all the webhooks registered in the webhook store
|
||||
*/
|
||||
startWebhooks(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Method called when the server is fully initialized and listen to incomming requests.
|
||||
* It handles tasks such as logging the startup message
|
||||
* or automatically opening the administration panel.
|
||||
*/
|
||||
postListen(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Start listening for incomming requests
|
||||
*/
|
||||
listen(): Promise<void | Error>;
|
||||
|
||||
/**
|
||||
* Opent he administration panel in a browser if the option is enabled.
|
||||
* You can disable it using the admin.autoOpen configuration variable.
|
||||
*
|
||||
* Note: It only works in development envs.
|
||||
*/
|
||||
openAdmin(options: { isInitialized: boolean }): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load the admin panel server logic into the server code and initialize its configuration.
|
||||
*/
|
||||
loadAdmin(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Resolve every enabled plugin and load them into the application.
|
||||
*/
|
||||
loadPlugins(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load every global policies in the policies container by
|
||||
* reading from the `strapi.dirs.dist.policies` directory.
|
||||
*/
|
||||
loadPolicies(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load every APIs and their components (config, routes, controllers, services,
|
||||
* policies, middlewares, content-types) in the API container.
|
||||
*/
|
||||
loadAPIs(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Resolve every components in the user application and store them in `strapi.components`
|
||||
*/
|
||||
loadComponents(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load every global and core middlewares in the middlewares container by
|
||||
* reading from the `strapi.dirs.dist.middlewares` and internal middlewares directory.
|
||||
*/
|
||||
loadMiddlewares(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load the user application in the server by reading the `src/index.js` file.
|
||||
*/
|
||||
loadApp(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Add internal hooks to the hooks container.
|
||||
* Those hooks are meant for internal usage and might break in future releases.
|
||||
*/
|
||||
registerInternalHooks(): void;
|
||||
|
||||
/**
|
||||
* Find a model (content-type, component) based on its unique identifier.
|
||||
*/
|
||||
getModel(uid: string): any;
|
||||
|
||||
/**
|
||||
* Binds database queries for a specific model based on its unique identifier.
|
||||
*/
|
||||
query(uid: string): any;
|
||||
|
||||
/**
|
||||
* Main Strapi container holding all the registries and providers (config, content-types, services, policies, etc...)
|
||||
*/
|
||||
container: any;
|
||||
|
||||
/**
|
||||
* References to all the directories handled by Strapi
|
||||
*/
|
||||
dirs: StrapiDirectories;
|
||||
|
||||
/**
|
||||
* Internal flag used to check if the application has been loaded
|
||||
*/
|
||||
isLoaded: boolean;
|
||||
|
||||
/**
|
||||
* Fully reload the application
|
||||
*/
|
||||
reload(): void;
|
||||
|
||||
/**
|
||||
* Holds a reference to the Koa application and the http server used by Strapi
|
||||
*/
|
||||
server: any;
|
||||
|
||||
/**
|
||||
* Strapi util used to manage application files
|
||||
*/
|
||||
fs: any;
|
||||
|
||||
/**
|
||||
* Event hub used to send and receive events from anywhere in the application
|
||||
*/
|
||||
eventHub: any;
|
||||
|
||||
/**
|
||||
* Internal util used to log stats and messages on application Startup
|
||||
*/
|
||||
startupLogger: any;
|
||||
|
||||
/**
|
||||
* Strapi logger used to send errors, warning or information messages
|
||||
*/
|
||||
log: any;
|
||||
|
||||
/**
|
||||
* Used to manage cron within Strapi
|
||||
*/
|
||||
cron: any;
|
||||
|
||||
/**
|
||||
* Telemetry util used to collect anonymous data on the application usage
|
||||
*/
|
||||
telemetry: any;
|
||||
|
||||
/**
|
||||
* Used to access ctx from anywhere within the Strapi application
|
||||
*/
|
||||
requestContext: any;
|
||||
|
||||
/**
|
||||
* Strapi DB layer instance
|
||||
*/
|
||||
db: Database;
|
||||
|
||||
/**
|
||||
* Core Store accessor
|
||||
*/
|
||||
store: any;
|
||||
|
||||
/**
|
||||
* Entity Validator instance
|
||||
*/
|
||||
entityValidator: any;
|
||||
|
||||
/**
|
||||
* Entity Service instance
|
||||
*/
|
||||
entityService: EntityService.EntityService;
|
||||
}
|
||||
|
||||
export interface Lifecycles {
|
||||
REGISTER: 'register';
|
||||
BOOTSTRAP: 'bootstrap';
|
||||
DESTROY: 'destroy';
|
||||
}
|
||||
|
||||
export interface StrapiDirectories {
|
||||
static: {
|
||||
public: string;
|
||||
};
|
||||
app: {
|
||||
root: string;
|
||||
src: string;
|
||||
api: string;
|
||||
components: string;
|
||||
extensions: string;
|
||||
policies: string;
|
||||
middlewares: string;
|
||||
config: string;
|
||||
};
|
||||
dist: {
|
||||
root: string;
|
||||
src: string;
|
||||
api: string;
|
||||
components: string;
|
||||
extensions: string;
|
||||
policies: string;
|
||||
middlewares: string;
|
||||
config: string;
|
||||
};
|
||||
}
|
@ -1,27 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs/promises');
|
||||
const boxen = require('boxen');
|
||||
const chalk = require('chalk');
|
||||
const ora = require('ora');
|
||||
const { createLogger } = require('../../../utils/logger');
|
||||
const { notifyExperimentalCommand } = require('../../../utils/helpers');
|
||||
const {
|
||||
import fs from 'fs/promises';
|
||||
import boxen from 'boxen';
|
||||
import chalk from 'chalk';
|
||||
import ora from 'ora';
|
||||
import { createLogger } from '../../../utils/logger';
|
||||
import { notifyExperimentalCommand } from '../../../utils/helpers';
|
||||
import {
|
||||
loadPkg,
|
||||
validatePkg,
|
||||
validateExportsOrdering,
|
||||
getExportExtensionMap,
|
||||
} = require('../../../utils/pkg');
|
||||
const { createBuildContext, createBuildTasks } = require('../../../builders/packages');
|
||||
const { buildTaskHandlers } = require('../../../builders/tasks');
|
||||
} from '../../../utils/pkg';
|
||||
import { createBuildContext, createBuildTasks } from '../../../builders/packages';
|
||||
import { buildTaskHandlers } from '../../../builders/tasks';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} args
|
||||
* @param {boolean} args.force
|
||||
* @param {boolean} args.debug
|
||||
*/
|
||||
module.exports = async ({ force, debug }) => {
|
||||
interface ActionOptions {
|
||||
force?: boolean;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export default async ({ force, debug }: ActionOptions) => {
|
||||
const logger = createLogger({ debug, timestamp: false });
|
||||
try {
|
||||
/**
|
||||
@ -106,13 +103,10 @@ module.exports = async ({ force, debug }) => {
|
||||
}
|
||||
|
||||
for (const task of buildTasks) {
|
||||
/**
|
||||
* @type {import('../../../builders/tasks').TaskHandler<any>}
|
||||
*/
|
||||
const handler = buildTaskHandlers[task.type];
|
||||
const handler = buildTaskHandlers(task);
|
||||
handler.print(ctx, task);
|
||||
|
||||
await handler.run(ctx, task).catch((err) => {
|
||||
await handler.run(ctx, task).catch((err: NodeJS.ErrnoException) => {
|
||||
if (err instanceof Error) {
|
||||
logger.error(err.message);
|
||||
}
|
||||
@ -124,14 +118,16 @@ module.exports = async ({ force, debug }) => {
|
||||
logger.error(
|
||||
'There seems to be an unexpected error, try again with --debug for more information \n'
|
||||
);
|
||||
console.log(
|
||||
chalk.red(
|
||||
boxen(err.stack, {
|
||||
padding: 1,
|
||||
align: 'left',
|
||||
})
|
||||
)
|
||||
);
|
||||
if (err instanceof Error && err.stack) {
|
||||
console.log(
|
||||
chalk.red(
|
||||
boxen(err.stack, {
|
||||
padding: 1,
|
||||
align: 'left',
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
@ -1,13 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const { forceOption } = require('../../../utils/commander');
|
||||
const { getLocalScript } = require('../../../utils/helpers');
|
||||
import { forceOption } from '../../../utils/commander';
|
||||
import { getLocalScript } from '../../../utils/helpers';
|
||||
import type { StrapiCommand } from '../../../types';
|
||||
|
||||
/**
|
||||
* `$ strapi plugin:build`
|
||||
* @param {import('../../../../types/core/commands').AddCommandOptions} options
|
||||
*/
|
||||
module.exports = ({ command }) => {
|
||||
const command: StrapiCommand = ({ command }) => {
|
||||
command
|
||||
.command('plugin:build')
|
||||
.description('Bundle your strapi plugin for publishing.')
|
||||
@ -15,3 +13,5 @@ module.exports = ({ command }) => {
|
||||
.option('-d, --debug', 'Enable debugging mode with verbose logs', false)
|
||||
.action(getLocalScript('plugin/build-command'));
|
||||
};
|
||||
|
||||
export default command;
|
@ -1,35 +1,40 @@
|
||||
'use strict';
|
||||
import path from 'path';
|
||||
import browserslistToEsbuild from 'browserslist-to-esbuild';
|
||||
import { parseExports, PackageJson, ExtMap, Export } from '../utils/pkg';
|
||||
import type { Logger } from '../utils/logger';
|
||||
import type { ViteTask } from './tasks/vite';
|
||||
import type { DtsTask } from './tasks/dts';
|
||||
|
||||
const path = require('path');
|
||||
const browserslistToEsbuild = require('browserslist-to-esbuild');
|
||||
interface BuildContextArgs {
|
||||
cwd: string;
|
||||
extMap: ExtMap;
|
||||
logger: Logger;
|
||||
pkg: PackageJson;
|
||||
}
|
||||
|
||||
const { parseExports } = require('../utils/pkg');
|
||||
export type Target = 'node' | 'web' | '*';
|
||||
|
||||
/**
|
||||
* @typedef {Object} BuildContextArgs
|
||||
* @property {string} cwd
|
||||
* @property {import('../utils/pkg').ExtMap} extMap
|
||||
* @property {import('../utils/logger').Logger} logger
|
||||
* @property {import('../utils/pkg').PackageJson} pkg
|
||||
*/
|
||||
export type Targets = {
|
||||
[target in Target]: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} Targets
|
||||
* @property {string[]} node
|
||||
* @property {string[]} web
|
||||
* @property {string[]} *
|
||||
*/
|
||||
export interface BuildContext {
|
||||
cwd: string;
|
||||
exports: Record<string, Export>;
|
||||
external: string[];
|
||||
extMap: ExtMap;
|
||||
logger: Logger;
|
||||
pkg: PackageJson;
|
||||
targets: Targets;
|
||||
distPath: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BuildContext
|
||||
* @property {string} cwd
|
||||
* @property {import('../utils/pkg').Export[]} exports
|
||||
* @property {string[]} external
|
||||
* @property {import('../utils/pkg').ExtMap} extMap
|
||||
* @property {import('../utils/logger').Logger} logger
|
||||
* @property {import('../utils/pkg').PackageJson} pkg
|
||||
* @property {Targets} targets
|
||||
*/
|
||||
export interface BuildTask {
|
||||
type: 'build:js' | 'build:dts';
|
||||
entries: unknown[];
|
||||
format?: 'cjs' | 'es';
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const DEFAULT_BROWSERS_LIST_CONFIG = [
|
||||
'last 3 major versions',
|
||||
@ -43,30 +48,33 @@ const DEFAULT_BROWSERS_LIST_CONFIG = [
|
||||
* @description Create a build context for the pipeline we're creating,
|
||||
* this is shared among tasks so they all use the same settings for core pieces
|
||||
* such as a target, distPath, externals etc.
|
||||
*
|
||||
* @type {(args: BuildContextArgs) => Promise<BuildContext>}
|
||||
*/
|
||||
const createBuildContext = async ({ cwd, extMap, logger, pkg }) => {
|
||||
const createBuildContext = async ({
|
||||
cwd,
|
||||
extMap,
|
||||
logger,
|
||||
pkg,
|
||||
}: BuildContextArgs): Promise<BuildContext> => {
|
||||
const targets = {
|
||||
'*': browserslistToEsbuild(pkg.browserslist ?? DEFAULT_BROWSERS_LIST_CONFIG),
|
||||
node: browserslistToEsbuild(['node 16.0.0']),
|
||||
web: ['esnext'],
|
||||
};
|
||||
|
||||
const exports = parseExports({ extMap, pkg }).reduce((acc, x) => {
|
||||
const exportsArray = parseExports({ extMap, pkg }).reduce((acc, x) => {
|
||||
const { _path: exportPath, ...exportEntry } = x;
|
||||
|
||||
return { ...acc, [exportPath]: exportEntry };
|
||||
}, {});
|
||||
}, {} as Record<string, Export>);
|
||||
|
||||
const external = [
|
||||
...(pkg.dependencies ? Object.keys(pkg.dependencies) : []),
|
||||
...(pkg.peerDependencies ? Object.keys(pkg.peerDependencies) : []),
|
||||
];
|
||||
|
||||
const outputPaths = Object.values(exports)
|
||||
const outputPaths = Object.values(exportsArray)
|
||||
.flatMap((exportEntry) => {
|
||||
return [exportEntry.import, exportEntry.require].filter(Boolean);
|
||||
return [exportEntry.import, exportEntry.require].filter((v): v is string => Boolean(v));
|
||||
})
|
||||
.map((p) => path.resolve(cwd, p));
|
||||
|
||||
@ -86,7 +94,7 @@ const createBuildContext = async ({ cwd, extMap, logger, pkg }) => {
|
||||
logger,
|
||||
cwd,
|
||||
pkg,
|
||||
exports,
|
||||
exports: exportsArray,
|
||||
external,
|
||||
distPath,
|
||||
targets,
|
||||
@ -94,17 +102,11 @@ const createBuildContext = async ({ cwd, extMap, logger, pkg }) => {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {(containerPath: string, itemPath: string) => boolean}
|
||||
*/
|
||||
const pathContains = (containerPath, itemPath) => {
|
||||
const pathContains = (containerPath: string, itemPath: string): boolean => {
|
||||
return !path.relative(containerPath, itemPath).startsWith('..');
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {(filePaths: string[]) => string | undefined}
|
||||
*/
|
||||
const findCommonDirPath = (filePaths) => {
|
||||
const findCommonDirPath = (filePaths: string[]) => {
|
||||
/**
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
@ -138,38 +140,36 @@ const findCommonDirPath = (filePaths) => {
|
||||
return commonPath;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {import('./tasks/vite').ViteTask | import('./tasks/dts').DtsTask} BuildTask
|
||||
*/
|
||||
type Task = ViteTask | DtsTask;
|
||||
|
||||
/**
|
||||
* @description Create the build tasks for the pipeline, this
|
||||
* comes from the exports map we've created in the build context.
|
||||
* But handles each export line uniquely with space to add more
|
||||
* as the standard develops.
|
||||
*
|
||||
* @type {(args: BuildContext) => Promise<BuildTask[]>}
|
||||
*/
|
||||
const createBuildTasks = async (ctx) => {
|
||||
/**
|
||||
* @type {BuildTask[]}
|
||||
*/
|
||||
const tasks = [];
|
||||
const createBuildTasks = async (ctx: BuildContext): Promise<Task[]> => {
|
||||
const tasks: Task[] = [];
|
||||
|
||||
/**
|
||||
* @type {import('./tasks/dts').DtsTask}
|
||||
*/
|
||||
const dtsTask = {
|
||||
const dtsTask: DtsTask = {
|
||||
type: 'build:dts',
|
||||
entries: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {Record<string, import('./tasks/vite').ViteTask>}
|
||||
*/
|
||||
const viteTasks = {};
|
||||
const viteTasks: Record<string, ViteTask> = {};
|
||||
|
||||
const createViteTask = (format, runtime, { output, ...restEntry }) => {
|
||||
const createViteTask = (
|
||||
format: 'cjs' | 'es',
|
||||
runtime: Target,
|
||||
{
|
||||
output,
|
||||
...restEntry
|
||||
}: {
|
||||
output: string;
|
||||
path: string;
|
||||
entry: string;
|
||||
}
|
||||
) => {
|
||||
const buildId = `${format}:${output}`;
|
||||
|
||||
if (viteTasks[buildId]) {
|
||||
@ -208,11 +208,8 @@ const createBuildTasks = async (ctx) => {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {keyof Target}
|
||||
*/
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
const runtime = exp._path.includes('strapi-admin')
|
||||
const runtime: Target = exp._path.includes('strapi-admin')
|
||||
? 'web'
|
||||
: exp._path.includes('strapi-server')
|
||||
? 'node'
|
||||
@ -224,7 +221,7 @@ const createBuildTasks = async (ctx) => {
|
||||
*/
|
||||
createViteTask('cjs', runtime, {
|
||||
path: exp._path,
|
||||
entry: exp.source,
|
||||
entry: exp.source ?? 'src/index.ts',
|
||||
output: exp.require,
|
||||
});
|
||||
}
|
||||
@ -235,7 +232,7 @@ const createBuildTasks = async (ctx) => {
|
||||
*/
|
||||
createViteTask('es', runtime, {
|
||||
path: exp._path,
|
||||
entry: exp.source,
|
||||
entry: exp.source ?? 'src/index.ts',
|
||||
output: exp.import,
|
||||
});
|
||||
}
|
||||
@ -246,7 +243,4 @@ const createBuildTasks = async (ctx) => {
|
||||
return tasks;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createBuildContext,
|
||||
createBuildTasks,
|
||||
};
|
||||
export { createBuildContext, createBuildTasks };
|
@ -1,18 +1,33 @@
|
||||
'use strict';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import ora from 'ora';
|
||||
import ts from 'typescript';
|
||||
import type { Logger } from '../../utils/logger';
|
||||
import type { TaskHandler } from '.';
|
||||
import type { BuildTask } from '../packages';
|
||||
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const ora = require('ora');
|
||||
const ts = require('typescript');
|
||||
interface LoadTsConfigOptions {
|
||||
cwd: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
class TSConfigNotFoundError extends Error {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
// constructor(message, options) {
|
||||
// super(message, options);
|
||||
// }
|
||||
|
||||
get code() {
|
||||
return 'TS_CONFIG_NOT_FOUND';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Load a tsconfig.json file and return the parsed config
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @type {(args: { cwd: string; path: string }) => Promise<ts.ParsedCommandLine>)}
|
||||
*/
|
||||
const loadTsConfig = async ({ cwd, path }) => {
|
||||
const loadTsConfig = async ({ cwd, path }: LoadTsConfigOptions) => {
|
||||
const configPath = ts.findConfigFile(cwd, ts.sys.fileExists, path);
|
||||
|
||||
if (!configPath) {
|
||||
@ -24,25 +39,19 @@ const loadTsConfig = async ({ cwd, path }) => {
|
||||
return ts.parseJsonConfigFileContent(configFile.config, ts.sys, cwd);
|
||||
};
|
||||
|
||||
class TSConfigNotFoundError extends Error {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
}
|
||||
|
||||
get code() {
|
||||
return 'TS_CONFIG_NOT_FOUND';
|
||||
}
|
||||
interface BuildTypesOptions {
|
||||
cwd: string;
|
||||
logger: Logger;
|
||||
outDir: string;
|
||||
tsconfig: ts.ParsedCommandLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @type {(args: { cwd: string; logger: import('../../utils/logger').Logger; outDir: string; tsconfig: ts.ParsedCommandLine }) => Promise<void>}
|
||||
*/
|
||||
const buildTypes = ({ cwd, logger, outDir, tsconfig }) => {
|
||||
const buildTypes = ({ cwd, logger, outDir, tsconfig }: BuildTypesOptions) => {
|
||||
const compilerOptions = {
|
||||
...tsconfig.options,
|
||||
declaration: true,
|
||||
@ -102,23 +111,19 @@ const buildTypes = ({ cwd, logger, outDir, tsconfig }) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} DtsTaskEntry
|
||||
* @property {string} exportPath
|
||||
* @property {string} sourcePath
|
||||
* @property {string} targetPath
|
||||
*/
|
||||
export interface DtsTaskEntry {
|
||||
importId: string;
|
||||
exportPath: string;
|
||||
sourcePath?: string;
|
||||
targetPath: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} DtsTask
|
||||
* @property {"build:dts"} type
|
||||
* @property {DtsTaskEntry[]} entries
|
||||
*/
|
||||
export interface DtsTask extends BuildTask {
|
||||
type: 'build:dts';
|
||||
entries: DtsTaskEntry[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import('./index').TaskHandler<DtsTask>}
|
||||
*/
|
||||
const dtsTask = {
|
||||
const dtsTask: TaskHandler<DtsTask> = {
|
||||
_spinner: null,
|
||||
print(ctx, task) {
|
||||
const entries = [
|
||||
@ -146,7 +151,7 @@ const dtsTask = {
|
||||
* TODO: this will not scale and assumes all project sourcePaths are `src/index.ts`
|
||||
* so we can go back to the "root" of the project...
|
||||
*/
|
||||
cwd: path.join(ctx.cwd, entry.sourcePath, '..', '..'),
|
||||
cwd: path.join(ctx.cwd, entry.sourcePath ?? 'src/index.ts', '..', '..'),
|
||||
path: 'tsconfig.build.json',
|
||||
}).catch((err) => {
|
||||
if (err instanceof TSConfigNotFoundError) {
|
||||
@ -187,13 +192,13 @@ const dtsTask = {
|
||||
}
|
||||
},
|
||||
async success() {
|
||||
this._spinner.succeed('Built type files');
|
||||
this._spinner?.succeed('Built type files');
|
||||
},
|
||||
async fail(ctx, task, err) {
|
||||
this._spinner.fail('Failed to build type files');
|
||||
this._spinner?.fail('Failed to build type files');
|
||||
|
||||
throw err;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = { dtsTask };
|
||||
export { dtsTask };
|
@ -1,29 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { dtsTask } = require('./dts');
|
||||
const { viteTask } = require('./vite');
|
||||
|
||||
/**
|
||||
* @template Task
|
||||
* @param {Task}
|
||||
* @returns {Task}
|
||||
*
|
||||
* @typedef {Object} TaskHandler
|
||||
* @property {(ctx: import("../packages").BuildContext, task: Task) => import('ora').Ora} print
|
||||
* @property {(ctx: import("../packages").BuildContext, task: Task) => Promise<void>} run
|
||||
* @property {(ctx: import("../packages").BuildContext, task: Task) => Promise<void>} success
|
||||
* @property {(ctx: import("../packages").BuildContext, task: Task, err: unknown) => Promise<void>} fail
|
||||
* @property {import('ora').Ora | null} _spinner
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {{ "build:js": TaskHandler<import("./vite").ViteTask>; "build:dts": TaskHandler<import("./dts").DtsTask>; }}}
|
||||
*/
|
||||
const buildTaskHandlers = {
|
||||
'build:js': viteTask,
|
||||
'build:dts': dtsTask,
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
buildTaskHandlers,
|
||||
};
|
23
packages/core/strapi/src/commands/builders/tasks/index.ts
Normal file
23
packages/core/strapi/src/commands/builders/tasks/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { Ora } from 'ora';
|
||||
import { dtsTask, DtsTask } from './dts';
|
||||
import { viteTask, ViteTask } from './vite';
|
||||
import type { BuildContext, BuildTask } from '../packages';
|
||||
|
||||
export interface TaskHandler<Task extends BuildTask> {
|
||||
print: (ctx: BuildContext, task: Task) => void;
|
||||
run: (ctx: BuildContext, task: Task) => Promise<void>;
|
||||
success: (ctx: BuildContext, task: Task) => Promise<void>;
|
||||
fail: (ctx: BuildContext, task: Task, err: unknown) => Promise<void>;
|
||||
_spinner: Ora | null;
|
||||
}
|
||||
|
||||
const handlers = {
|
||||
'build:js': viteTask,
|
||||
'build:dts': dtsTask,
|
||||
};
|
||||
|
||||
const buildTaskHandlers = <T extends ViteTask | DtsTask>(t: T): TaskHandler<T> => {
|
||||
return handlers[t.type] as TaskHandler<T>;
|
||||
};
|
||||
|
||||
export { buildTaskHandlers };
|
@ -1,17 +1,18 @@
|
||||
'use strict';
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import path from 'path';
|
||||
// @ts-ignore
|
||||
import { build, createLogger, InlineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import ora from 'ora';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const path = require('path');
|
||||
const { build, createLogger } = require('vite');
|
||||
const react = require('@vitejs/plugin-react');
|
||||
const ora = require('ora');
|
||||
const chalk = require('chalk');
|
||||
import type { TaskHandler } from '.';
|
||||
import type { BuildContext, BuildTask, Target } from '../packages';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @type {(ctx: import('../packages').BuildContext, task: ViteTask) => import('vite').UserConfig}
|
||||
*/
|
||||
const resolveViteConfig = (ctx, task) => {
|
||||
const resolveViteConfig = (ctx: BuildContext, task: ViteTask): InlineConfig => {
|
||||
const { cwd, distPath, targets, external, extMap, pkg } = ctx;
|
||||
const { entries, format, output, runtime } = task;
|
||||
const outputExt = extMap[pkg.type || 'commonjs'][format];
|
||||
@ -22,10 +23,7 @@ const resolveViteConfig = (ctx, task) => {
|
||||
customLogger.warnOnce = (msg) => ctx.logger.warn(msg);
|
||||
customLogger.error = (msg) => ctx.logger.error(msg);
|
||||
|
||||
/**
|
||||
* @type {import('vite').InlineConfig}
|
||||
*/
|
||||
const config = {
|
||||
const config: InlineConfig = {
|
||||
configFile: false,
|
||||
root: cwd,
|
||||
mode: 'production',
|
||||
@ -79,25 +77,20 @@ const resolveViteConfig = (ctx, task) => {
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} ViteTaskEntry
|
||||
* @property {string} path
|
||||
* @property {string} entry
|
||||
*/
|
||||
interface ViteTaskEntry {
|
||||
path: string;
|
||||
entry: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ViteTask
|
||||
* @property {"build:js"} type
|
||||
* @property {ViteTaskEntry[]} entries
|
||||
* @property {string} format
|
||||
* @property {string} output
|
||||
* @property {keyof import('../packages').Targets} runtime
|
||||
*/
|
||||
export interface ViteTask extends BuildTask {
|
||||
type: 'build:js';
|
||||
entries: ViteTaskEntry[];
|
||||
format: 'cjs' | 'es';
|
||||
output: string;
|
||||
runtime: Target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import('./index').TaskHandler<ViteTask>}
|
||||
*/
|
||||
const viteTask = {
|
||||
const viteTask: TaskHandler<ViteTask> = {
|
||||
_spinner: null,
|
||||
print(ctx, task) {
|
||||
const targetLines = [
|
||||
@ -130,15 +123,13 @@ const viteTask = {
|
||||
}
|
||||
},
|
||||
async success() {
|
||||
this._spinner.succeed('Built javascript files');
|
||||
this._spinner?.succeed('Built javascript files');
|
||||
},
|
||||
async fail(ctx, task, err) {
|
||||
this._spinner.fail('Failed to build javascript files');
|
||||
this._spinner?.fail('Failed to build javascript files');
|
||||
|
||||
throw err;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
viteTask,
|
||||
};
|
||||
export { viteTask };
|
@ -10,10 +10,8 @@ import consoleCommand from './actions/console/command';
|
||||
import listContentTypes from './actions/content-types/list/command';
|
||||
import listControllers from './actions/controllers/list/command';
|
||||
import developCommand from './actions/develop/command';
|
||||
// import exportCommand from './actions/export/command';
|
||||
import generateCommand from './actions/generate/command';
|
||||
import listHooks from './actions/hooks/list/command';
|
||||
// import importCommand from './actions/import/command';
|
||||
import installCommand from './actions/install/command';
|
||||
import listMiddlewares from './actions/middlewares/list/command';
|
||||
import newCommand from './actions/new/command';
|
||||
@ -25,11 +23,11 @@ import startCommand from './actions/start/command';
|
||||
import disableTelemetry from './actions/telemetry/disable/command';
|
||||
import enableTelemetry from './actions/telemetry/enable/command';
|
||||
import generateTemplates from './actions/templates/generate/command';
|
||||
// import transferCommand from './actions/transfer/command';
|
||||
import generateTsTypes from './actions/ts/generate-types/command';
|
||||
import uninstallCommand from './actions/uninstall/command';
|
||||
import versionCommand from './actions/version/command';
|
||||
import watchAdminCommand from './actions/watch-admin/command';
|
||||
import buildPluginCommand from './actions/plugin/build-command/command';
|
||||
|
||||
const strapiCommands = {
|
||||
createAdminUser,
|
||||
@ -59,6 +57,7 @@ const strapiCommands = {
|
||||
uninstallCommand,
|
||||
versionCommand,
|
||||
watchAdminCommand,
|
||||
buildPluginCommand,
|
||||
} as const;
|
||||
|
||||
const buildStrapiCommand = (argv: string[], command = new Command()) => {
|
||||
|
@ -1,25 +1,14 @@
|
||||
<<<<<<< HEAD:packages/core/strapi/src/commands/utils/helpers.ts
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
import { yellow, red, green } from 'chalk';
|
||||
import chalk, { yellow, red, green } from 'chalk';
|
||||
import { has, isString, isArray } from 'lodash/fp';
|
||||
import resolveCwd from 'resolve-cwd';
|
||||
import { prompt } from 'inquirer';
|
||||
import boxen from 'boxen';
|
||||
import type { Command } from 'commander';
|
||||
=======
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Helper functions for the Strapi CLI
|
||||
*/
|
||||
|
||||
const { yellow, red, green } = require('chalk');
|
||||
const { isString, isArray } = require('lodash/fp');
|
||||
const resolveCwd = require('resolve-cwd');
|
||||
const { has } = require('lodash/fp');
|
||||
const { prompt } = require('inquirer');
|
||||
const boxen = require('boxen');
|
||||
const chalk = require('chalk');
|
||||
>>>>>>> main:packages/core/strapi/lib/commands/utils/helpers.js
|
||||
|
||||
const bytesPerKb = 1024;
|
||||
const sizes = ['B ', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
@ -133,16 +122,11 @@ const assertCwdContainsStrapiProject = (name: string) => {
|
||||
|
||||
try {
|
||||
const pkgJSON = require(`${process.cwd()}/package.json`);
|
||||
<<<<<<< HEAD:packages/core/strapi/src/commands/utils/helpers.ts
|
||||
if (!has('dependencies.@strapi/strapi', pkgJSON)) {
|
||||
logErrorAndExit();
|
||||
=======
|
||||
if (
|
||||
!has('dependencies.@strapi/strapi', pkgJSON) &&
|
||||
!has('devDependencies.@strapi/strapi', pkgJSON)
|
||||
) {
|
||||
logErrorAndExit(name);
|
||||
>>>>>>> main:packages/core/strapi/lib/commands/utils/helpers.js
|
||||
logErrorAndExit();
|
||||
}
|
||||
} catch (err) {
|
||||
logErrorAndExit();
|
||||
@ -176,9 +160,6 @@ const getLocalScript =
|
||||
});
|
||||
};
|
||||
|
||||
<<<<<<< HEAD:packages/core/strapi/src/commands/utils/helpers.ts
|
||||
export {
|
||||
=======
|
||||
/**
|
||||
* @description Notify users this is an experimental command and get them to approve first
|
||||
* this can be opted out by passing `yes` as a property of the args object.
|
||||
@ -194,7 +175,7 @@ export {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
const notifyExperimentalCommand = async ({ force } = {}) => {
|
||||
const notifyExperimentalCommand = async ({ force }: { force?: boolean } = {}) => {
|
||||
console.log(
|
||||
boxen(
|
||||
`The ${chalk.bold(
|
||||
@ -224,8 +205,7 @@ const notifyExperimentalCommand = async ({ force } = {}) => {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
>>>>>>> main:packages/core/strapi/lib/commands/utils/helpers.js
|
||||
export {
|
||||
exitWith,
|
||||
assertUrlHasProtocol,
|
||||
ifOptions,
|
||||
|
@ -1,26 +1,22 @@
|
||||
'use strict';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const chalk = require('chalk');
|
||||
export interface LoggerOptions {
|
||||
silent?: boolean;
|
||||
debug?: boolean;
|
||||
timestamp?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{ silent?: boolean; debug?: boolean; timestamp?: boolean; }} LoggerOptions
|
||||
*/
|
||||
export interface Logger {
|
||||
warnings: number;
|
||||
errors: number;
|
||||
debug: (...args: unknown[]) => void;
|
||||
info: (...args: unknown[]) => void;
|
||||
warn: (...args: unknown[]) => void;
|
||||
error: (...args: unknown[]) => void;
|
||||
log: (...args: unknown[]) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} Logger
|
||||
* @property {number} warnings
|
||||
* @property {number} errors
|
||||
* @property {(...args: any[]) => void} debug
|
||||
* @property {(...args: any[]) => void} info
|
||||
* @property {(...args: any[]) => void} warn
|
||||
* @property {(...args: any[]) => void} error
|
||||
* @property {(...args: any[]) => void} log
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {(options: LoggerOptions) => Logger}
|
||||
*/
|
||||
const createLogger = (options = {}) => {
|
||||
const createLogger = (options: LoggerOptions = {}): Logger => {
|
||||
const { silent = false, debug = false, timestamp = true } = options;
|
||||
|
||||
const state = { errors: 0, warning: 0 };
|
||||
@ -92,6 +88,4 @@ const createLogger = (options = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createLogger,
|
||||
};
|
||||
export { createLogger };
|
@ -1,9 +1,36 @@
|
||||
'use strict';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import * as yup from 'yup';
|
||||
import type { Logger } from './logger';
|
||||
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const yup = require('yup');
|
||||
export interface PackageJson extends Omit<yup.Asserts<typeof packageJsonSchema>, 'exports'> {
|
||||
type: Extensions;
|
||||
exports?: {
|
||||
[key: string]: Export | string;
|
||||
};
|
||||
browserslist?: string[];
|
||||
}
|
||||
|
||||
export type Extensions = 'commonjs' | 'module';
|
||||
export type ExtMap = {
|
||||
[key in Extensions]: {
|
||||
cjs: string;
|
||||
es: string;
|
||||
};
|
||||
};
|
||||
|
||||
export interface Export {
|
||||
types?: string;
|
||||
source?: string;
|
||||
require?: string;
|
||||
import?: string;
|
||||
default?: string;
|
||||
}
|
||||
|
||||
export interface ExportWithMeta extends Export {
|
||||
_path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility functions for loading and validating package.json
|
||||
@ -18,14 +45,19 @@ const yup = require('yup');
|
||||
const packageJsonSchema = yup.object({
|
||||
name: yup.string().required(),
|
||||
version: yup.string().required(),
|
||||
type: yup.string().matches(/(commonjs|module)/),
|
||||
type: yup.mixed().oneOf(['commonjs', 'module']),
|
||||
license: yup.string(),
|
||||
bin: yup.mixed().oneOf([
|
||||
yup.string(),
|
||||
yup.object({
|
||||
[yup.string()]: yup.string(),
|
||||
}),
|
||||
]),
|
||||
bin: yup.lazy((value) =>
|
||||
typeof value === 'object'
|
||||
? yup.object(
|
||||
Object.entries(value).reduce((acc, [key]) => {
|
||||
acc[key] = yup.string().required();
|
||||
|
||||
return acc;
|
||||
}, {} as Record<string, yup.SchemaOf<string>>)
|
||||
)
|
||||
: yup.string()
|
||||
),
|
||||
main: yup.string(),
|
||||
module: yup.string(),
|
||||
source: yup.string(),
|
||||
@ -52,7 +84,7 @@ const packageJsonSchema = yup.object({
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {})
|
||||
}, {} as Record<string, yup.SchemaOf<string> | yup.SchemaOf<Export>>)
|
||||
: undefined
|
||||
)
|
||||
),
|
||||
@ -64,18 +96,18 @@ const packageJsonSchema = yup.object({
|
||||
engines: yup.object(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef {import('yup').Asserts<typeof packageJsonSchema>} PackageJson
|
||||
*/
|
||||
interface LoadPkgOptions {
|
||||
cwd: string;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description being a task to load the package.json starting from the current working directory
|
||||
* using a shallow find for the package.json and `fs` to read the file. If no package.json is found,
|
||||
* the process will throw with an appropriate error message.
|
||||
*
|
||||
* @type {(args: { cwd: string, logger: import('./logger').Logger }) => Promise<object>}
|
||||
*/
|
||||
const loadPkg = async ({ cwd, logger }) => {
|
||||
const loadPkg = async ({ cwd, logger }: LoadPkgOptions): Promise<PackageJson> => {
|
||||
const directory = path.resolve(cwd);
|
||||
|
||||
const pkgPath = path.join(directory, 'package.json');
|
||||
@ -95,10 +127,8 @@ const loadPkg = async ({ cwd, logger }) => {
|
||||
/**
|
||||
* @description validate the package.json against a standardised schema using `yup`.
|
||||
* If the validation fails, the process will throw with an appropriate error message.
|
||||
*
|
||||
* @type {(args: { pkg: object }) => Promise<PackageJson | null>}
|
||||
*/
|
||||
const validatePkg = async ({ pkg }) => {
|
||||
const validatePkg = async ({ pkg }: { pkg: PackageJson }) => {
|
||||
try {
|
||||
const validatedPkg = await packageJsonSchema.validate(pkg, {
|
||||
strict: true,
|
||||
@ -111,14 +141,14 @@ const validatePkg = async ({ pkg }) => {
|
||||
case 'required':
|
||||
throw new Error(
|
||||
`'${err.path}' in 'package.json' is required as type '${chalk.magenta(
|
||||
yup.reach(packageJsonSchema, err.path).type
|
||||
yup.reach(packageJsonSchema, err.path ?? '').type
|
||||
)}'`
|
||||
);
|
||||
case 'matches':
|
||||
throw new Error(
|
||||
`'${err.path}' in 'package.json' must be of type '${chalk.magenta(
|
||||
err.params.regex
|
||||
)}' (recieved the value '${chalk.magenta(err.params.value)}')`
|
||||
err.params?.regex
|
||||
)}' (recieved the value '${chalk.magenta(err.params?.value)}')`
|
||||
);
|
||||
/**
|
||||
* This will only be thrown if there are keys in the export map
|
||||
@ -127,7 +157,7 @@ const validatePkg = async ({ pkg }) => {
|
||||
case 'noUnknown':
|
||||
throw new Error(
|
||||
`'${err.path}' in 'package.json' contains the unknown key ${chalk.magenta(
|
||||
err.params.unknown
|
||||
err.params?.unknown
|
||||
)}, for compatability only the following keys are allowed: ${chalk.magenta(
|
||||
"['types', 'source', 'import', 'require', 'default']"
|
||||
)}`
|
||||
@ -135,8 +165,8 @@ const validatePkg = async ({ pkg }) => {
|
||||
default:
|
||||
throw new Error(
|
||||
`'${err.path}' in 'package.json' must be of type '${chalk.magenta(
|
||||
err.params.type
|
||||
)}' (recieved '${chalk.magenta(typeof err.params.value)}')`
|
||||
err.params?.type
|
||||
)}' (recieved '${chalk.magenta(typeof err.params?.value)}')`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -145,15 +175,21 @@ const validatePkg = async ({ pkg }) => {
|
||||
}
|
||||
};
|
||||
|
||||
interface ValidateExportsOrderingOptions {
|
||||
pkg: PackageJson;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description validate the `exports` property of the package.json against a set of rules.
|
||||
* If the validation fails, the process will throw with an appropriate error message. If
|
||||
* there is no `exports` property we check the standard export-like properties on the root
|
||||
* of the package.json.
|
||||
*
|
||||
* @type {(args: { pkg: object, logger: import('./logger').Logger }) => Promise<PackageJson>}
|
||||
*/
|
||||
const validateExportsOrdering = async ({ pkg, logger }) => {
|
||||
const validateExportsOrdering = async ({
|
||||
pkg,
|
||||
logger,
|
||||
}: ValidateExportsOrderingOptions): Promise<PackageJson> => {
|
||||
if (pkg.exports) {
|
||||
const exports = Object.entries(pkg.exports);
|
||||
|
||||
@ -195,7 +231,7 @@ const validateExportsOrdering = async ({ pkg, logger }) => {
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
function assertFirst(key, arr) {
|
||||
function assertFirst(key: string, arr: string[]) {
|
||||
const aIdx = arr.indexOf(key);
|
||||
|
||||
// if not found, then we don't care
|
||||
@ -207,7 +243,7 @@ function assertFirst(key, arr) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function assertLast(key, arr) {
|
||||
function assertLast(key: string, arr: string[]) {
|
||||
const aIdx = arr.indexOf(key);
|
||||
|
||||
// if not found, then we don't care
|
||||
@ -219,7 +255,7 @@ function assertLast(key, arr) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function assertOrder(keyA, keyB, arr) {
|
||||
function assertOrder(keyA: string, keyB: string, arr: string[]) {
|
||||
const aIdx = arr.indexOf(keyA);
|
||||
const bIdx = arr.indexOf(keyB);
|
||||
|
||||
@ -231,24 +267,10 @@ function assertOrder(keyA, keyB, arr) {
|
||||
return aIdx < bIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Extensions
|
||||
* @property {string} commonjs
|
||||
* @property {string} esm
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ExtMap
|
||||
* @property {Extensions} commonjs
|
||||
* @property {Extensions} esm
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @type {ExtMap}
|
||||
*/
|
||||
const DEFAULT_PKG_EXT_MAP = {
|
||||
const DEFAULT_PKG_EXT_MAP: ExtMap = {
|
||||
// pkg.type: "commonjs"
|
||||
commonjs: {
|
||||
cjs: '.js',
|
||||
@ -266,21 +288,24 @@ const DEFAULT_PKG_EXT_MAP = {
|
||||
* We potentially might need to support legacy exports or as package
|
||||
* development continues we have space to tweak this.
|
||||
*
|
||||
* @type {() => ExtMap}
|
||||
*/
|
||||
const getExportExtensionMap = () => {
|
||||
const getExportExtensionMap = (): ExtMap => {
|
||||
return DEFAULT_PKG_EXT_MAP;
|
||||
};
|
||||
|
||||
interface ValidateExportsOptions {
|
||||
extMap: ExtMap;
|
||||
pkg: PackageJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @description validate the `require` and `import` properties of a given exports maps from the package.json
|
||||
* returning if any errors are found.
|
||||
*
|
||||
* @type {(_exports: unknown, options: {extMap: ExtMap; pkg: PackageJson}) => string[]}
|
||||
*/
|
||||
const validateExports = (_exports, options) => {
|
||||
const validateExports = (_exports: ExportWithMeta[], options: ValidateExportsOptions): string[] => {
|
||||
const { extMap, pkg } = options;
|
||||
const ext = extMap[pkg.type || 'commonjs'];
|
||||
|
||||
@ -303,27 +328,17 @@ const validateExports = (_exports, options) => {
|
||||
return errors;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} Export
|
||||
* @property {string} _path the path of the export, `.` for the root.
|
||||
* @property {string=} types the path to the types file
|
||||
* @property {string} source the path to the source file
|
||||
* @property {string=} require the path to the commonjs require file
|
||||
* @property {string=} import the path to the esm import file
|
||||
* @property {string=} default the path to the default file
|
||||
*/
|
||||
interface ParseExportsOptions {
|
||||
extMap: ExtMap;
|
||||
pkg: PackageJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description parse the exports map from the package.json into a standardised
|
||||
* format that we can use to generate build tasks from.
|
||||
*
|
||||
* @type {(args: { extMap: ExtMap, pkg: PackageJson }) => Export[]}
|
||||
*/
|
||||
const parseExports = ({ extMap, pkg }) => {
|
||||
/**
|
||||
* @type {Export}
|
||||
*/
|
||||
const rootExport = {
|
||||
const parseExports = ({ extMap, pkg }: ParseExportsOptions): ExportWithMeta[] => {
|
||||
const rootExport: ExportWithMeta = {
|
||||
_path: '.',
|
||||
types: pkg.types,
|
||||
source: pkg.source,
|
||||
@ -332,15 +347,9 @@ const parseExports = ({ extMap, pkg }) => {
|
||||
default: pkg.module || pkg.main,
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {Export[]}
|
||||
*/
|
||||
const extraExports = [];
|
||||
const extraExports: ExportWithMeta[] = [];
|
||||
|
||||
/**
|
||||
* @type {string[]}
|
||||
*/
|
||||
const errors = [];
|
||||
const errors: string[] = [];
|
||||
|
||||
if (pkg.exports) {
|
||||
if (!pkg.exports['./package.json']) {
|
||||
@ -394,14 +403,14 @@ const parseExports = ({ extMap, pkg }) => {
|
||||
});
|
||||
}
|
||||
|
||||
const _exports = [
|
||||
const _exports: ExportWithMeta[] = [
|
||||
/**
|
||||
* In the case of strapi plugins, we don't have a root export because we
|
||||
* ship a server side and client side package. So this can be completely omitted.
|
||||
*/
|
||||
Object.values(rootExport).some((exp) => exp !== rootExport._path && Boolean(exp)) && rootExport,
|
||||
...extraExports,
|
||||
].filter(Boolean);
|
||||
].filter((v): v is ExportWithMeta => Boolean(v));
|
||||
|
||||
errors.push(...validateExports(_exports, { extMap, pkg }));
|
||||
|
||||
@ -412,10 +421,4 @@ const parseExports = ({ extMap, pkg }) => {
|
||||
return _exports;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
loadPkg,
|
||||
validatePkg,
|
||||
validateExportsOrdering,
|
||||
getExportExtensionMap,
|
||||
parseExports,
|
||||
};
|
||||
export { loadPkg, validatePkg, validateExportsOrdering, getExportExtensionMap, parseExports };
|
@ -2,7 +2,7 @@ import type { Attribute, Common, Utils } from '../../../../../types';
|
||||
|
||||
import type * as Operator from './operators';
|
||||
import type * as AttributeUtils from '../attributes';
|
||||
import type Params from '../index';
|
||||
import type * as Params from '../index';
|
||||
|
||||
export { Operator };
|
||||
|
||||
|
@ -1,10 +1,15 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "es2015",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user