@directus/extensions-sdk 9.14.2 → 9.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/cjs/cli/commands/build.d.ts +6 -8
  2. package/dist/cjs/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cjs/cli/commands/build.js +242 -71
  4. package/dist/cjs/cli/commands/create.d.ts.map +1 -1
  5. package/dist/cjs/cli/commands/create.js +27 -33
  6. package/dist/cjs/cli/run.js +5 -5
  7. package/dist/cjs/cli/types.d.ts +9 -0
  8. package/dist/cjs/cli/types.d.ts.map +1 -1
  9. package/dist/cjs/cli/utils/load-config.d.ts +2 -1
  10. package/dist/cjs/cli/utils/load-config.d.ts.map +1 -1
  11. package/dist/cjs/cli/utils/logger.d.ts +2 -1
  12. package/dist/cjs/cli/utils/logger.d.ts.map +1 -1
  13. package/dist/cjs/cli/utils/logger.js +11 -1
  14. package/dist/cjs/cli/utils/to-object.d.ts +2 -0
  15. package/dist/cjs/cli/utils/to-object.d.ts.map +1 -0
  16. package/dist/cjs/cli/utils/to-object.js +17 -0
  17. package/dist/cjs/index.d.ts +1 -1
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/index.js +3 -1
  20. package/dist/esm/cli/commands/build.d.ts +6 -8
  21. package/dist/esm/cli/commands/build.d.ts.map +1 -1
  22. package/dist/esm/cli/commands/build.js +242 -71
  23. package/dist/esm/cli/commands/create.d.ts.map +1 -1
  24. package/dist/esm/cli/commands/create.js +25 -31
  25. package/dist/esm/cli/run.js +5 -5
  26. package/dist/esm/cli/types.d.ts +9 -0
  27. package/dist/esm/cli/types.d.ts.map +1 -1
  28. package/dist/esm/cli/utils/load-config.d.ts +2 -1
  29. package/dist/esm/cli/utils/load-config.d.ts.map +1 -1
  30. package/dist/esm/cli/utils/logger.d.ts +2 -1
  31. package/dist/esm/cli/utils/logger.d.ts.map +1 -1
  32. package/dist/esm/cli/utils/logger.js +9 -1
  33. package/dist/esm/cli/utils/to-object.d.ts +2 -0
  34. package/dist/esm/cli/utils/to-object.d.ts.map +1 -0
  35. package/dist/esm/cli/utils/to-object.js +14 -0
  36. package/dist/esm/index.d.ts +1 -1
  37. package/dist/esm/index.d.ts.map +1 -1
  38. package/dist/esm/index.js +1 -1
  39. package/package.json +3 -3
  40. package/src/cli/commands/build.ts +358 -93
  41. package/src/cli/commands/create.ts +33 -30
  42. package/src/cli/run.ts +5 -5
  43. package/src/cli/types.ts +8 -0
  44. package/src/cli/utils/load-config.ts +2 -1
  45. package/src/cli/utils/logger.ts +11 -1
  46. package/src/cli/utils/to-object.ts +16 -0
  47. package/src/index.ts +2 -0
  48. package/templates/common/typescript/tsconfig.json +2 -1
  49. package/templates/operation/javascript/src/api.js +6 -0
  50. package/templates/operation/javascript/src/app.js +23 -0
  51. package/templates/operation/typescript/src/api.ts +12 -0
  52. package/templates/operation/typescript/src/app.ts +25 -0
  53. package/templates/operation/typescript/src/shims.d.ts +5 -0
@@ -3,10 +3,17 @@ import chalk from 'chalk';
3
3
  import fse from 'fs-extra';
4
4
  import execa from 'execa';
5
5
  import ora from 'ora';
6
- import { EXTENSION_TYPES, EXTENSION_PKG_KEY, EXTENSION_LANGUAGES } from '@directus/shared/constants';
7
- import { isAppExtension, isExtension } from '@directus/shared/utils';
6
+ import {
7
+ EXTENSION_TYPES,
8
+ EXTENSION_PKG_KEY,
9
+ EXTENSION_LANGUAGES,
10
+ HYBRID_EXTENSION_TYPES,
11
+ API_OR_HYBRID_EXTENSION_TYPES,
12
+ APP_OR_HYBRID_EXTENSION_TYPES,
13
+ } from '@directus/shared/constants';
14
+ import { isIn } from '@directus/shared/utils';
8
15
  import { ExtensionType } from '@directus/shared/types';
9
- import log from '../utils/logger';
16
+ import { log } from '../utils/logger';
10
17
  import { isLanguage, languageToShort } from '../utils/languages';
11
18
  import renameMap from '../utils/rename-map';
12
19
  import { Language } from '../types';
@@ -21,9 +28,9 @@ type CreateOptions = { language: string };
21
28
  export default async function create(type: string, name: string, options: CreateOptions): Promise<void> {
22
29
  const targetPath = path.resolve(name);
23
30
 
24
- if (!isExtension(type)) {
31
+ if (!isIn(type, EXTENSION_TYPES)) {
25
32
  log(
26
- `Extension type ${chalk.bold(type)} does not exist. Available extension types: ${EXTENSION_TYPES.map((t) =>
33
+ `Extension type ${chalk.bold(type)} is not supported. Available extension types: ${EXTENSION_TYPES.map((t) =>
27
34
  chalk.bold.magenta(t)
28
35
  ).join(', ')}.`,
29
36
  'error'
@@ -57,7 +64,7 @@ export default async function create(type: string, name: string, options: Create
57
64
  process.exit(1);
58
65
  }
59
66
 
60
- const spinner = ora(`Scaffolding Directus extension...`).start();
67
+ const spinner = ora(chalk.bold('Scaffolding Directus extension...')).start();
61
68
 
62
69
  await fse.ensureDir(targetPath);
63
70
 
@@ -65,14 +72,19 @@ export default async function create(type: string, name: string, options: Create
65
72
  await fse.copy(path.join(TEMPLATE_PATH, type, options.language), targetPath);
66
73
  await renameMap(targetPath, (name) => (name.startsWith('_') ? `.${name.substring(1)}` : null));
67
74
 
75
+ const entryPath = isIn(type, HYBRID_EXTENSION_TYPES) ? { app: 'dist/app.js', api: 'dist/api.js' } : 'dist/index.js';
76
+ const sourcePath = isIn(type, HYBRID_EXTENSION_TYPES)
77
+ ? { app: `src/app.${languageToShort(options.language)}`, api: `src/api.${languageToShort(options.language)}` }
78
+ : `src/index.${languageToShort(options.language)}`;
79
+
68
80
  const packageManifest = {
69
81
  name: `directus-extension-${name}`,
70
82
  version: '1.0.0',
71
83
  keywords: ['directus', 'directus-extension', `directus-custom-${type}`],
72
84
  [EXTENSION_PKG_KEY]: {
73
85
  type,
74
- path: 'dist/index.js',
75
- source: `src/index.${languageToShort(options.language)}`,
86
+ path: entryPath,
87
+ source: sourcePath,
76
88
  host: `^${pkg.version}`,
77
89
  },
78
90
  scripts: {
@@ -92,7 +104,7 @@ export default async function create(type: string, name: string, options: Create
92
104
  Your ${type} extension has been created at ${chalk.green(targetPath)}
93
105
 
94
106
  To start developing, run:
95
- ${chalk.blue('cd')} c
107
+ ${chalk.blue('cd')} ${name}
96
108
  ${chalk.blue('npm run')} dev
97
109
 
98
110
  and then to build for production, run:
@@ -101,25 +113,16 @@ and then to build for production, run:
101
113
  }
102
114
 
103
115
  async function getPackageDeps(type: ExtensionType, language: Language) {
104
- if (isAppExtension(type)) {
105
- return {
106
- '@directus/extensions-sdk': pkg.version,
107
- ...(language === 'typescript'
108
- ? {
109
- typescript: `^${await getPackageVersion('typescript')}`,
110
- }
111
- : {}),
112
- vue: `^${await getPackageVersion('vue')}`,
113
- };
114
- } else {
115
- return {
116
- '@directus/extensions-sdk': pkg.version,
117
- ...(language === 'typescript'
118
- ? {
119
- '@types/node': `^${await getPackageVersion('@types/node')}`,
120
- typescript: `^${await getPackageVersion('typescript')}`,
121
- }
122
- : {}),
123
- };
124
- }
116
+ return {
117
+ '@directus/extensions-sdk': pkg.version,
118
+ ...(language === 'typescript'
119
+ ? {
120
+ ...(isIn(type, API_OR_HYBRID_EXTENSION_TYPES)
121
+ ? { '@types/node': `^${await getPackageVersion('@types/node')}` }
122
+ : {}),
123
+ typescript: `^${await getPackageVersion('typescript')}`,
124
+ }
125
+ : {}),
126
+ ...(isIn(type, APP_OR_HYBRID_EXTENSION_TYPES) ? { vue: `^${await getPackageVersion('vue')}` } : {}),
127
+ };
125
128
  }
package/src/cli/run.ts CHANGED
@@ -19,11 +19,11 @@ program
19
19
  program
20
20
  .command('build')
21
21
  .description('Bundle a Directus extension to a single entrypoint')
22
- .option('-t, --type <type>', 'overwrite the extension type read from package manifest')
23
- .option('-i, --input <file>', 'overwrite the entrypoint read from package manifest')
24
- .option('-o, --output <file>', 'overwrite the output file read from package manifest')
25
- .option('-l, --language <language>', 'overwrite the language to use')
26
- .option('-f, --force', 'ignore the package manifest')
22
+ .option('-t, --type <type>', 'specify the extension type instead of reading from package manifest')
23
+ .option('-i, --input <file>', 'specify the entrypoint instead of reading from package manifest')
24
+ .option('-o, --output <file>', 'specify the output file instead of reading from package manifest')
25
+ .option('-l, --language <language>', '[DEPRECATED]')
26
+ .option('-f, --force', '[DEPRECATED]')
27
27
  .option('-w, --watch', 'watch and rebuild on changes')
28
28
  .option('--no-minify', 'disable minification')
29
29
  .option('--sourcemap', 'include source maps in output')
package/src/cli/types.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  import { EXTENSION_LANGUAGES } from '@directus/shared/constants';
2
+ import { Plugin, RollupOptions, OutputOptions as RollupOutputOptions } from 'rollup';
2
3
 
3
4
  export type Language = typeof EXTENSION_LANGUAGES[number];
4
5
  export type LanguageShort = 'js' | 'ts';
6
+
7
+ export type Config = {
8
+ plugins?: Plugin[];
9
+ };
10
+
11
+ export type RollupConfig = { rollupOptions: RollupOptions; rollupOutputOptions: RollupOutputOptions };
12
+ export type RollupMode = 'browser' | 'node';
@@ -1,12 +1,13 @@
1
1
  import path from 'path';
2
2
  import fse from 'fs-extra';
3
+ import { Config } from '../types';
3
4
 
4
5
  const CONFIG_FILE_NAMES = ['extension.config.js', 'extension.config.mjs', 'extension.config.cjs'];
5
6
 
6
7
  // This is needed to work around Typescript always transpiling import() to require() for CommonJS targets.
7
8
  const _import = new Function('url', 'return import(url)');
8
9
 
9
- export default async function loadConfig(): Promise<Record<string, any>> {
10
+ export default async function loadConfig(): Promise<Config> {
10
11
  for (const fileName of CONFIG_FILE_NAMES) {
11
12
  if (await fse.pathExists(fileName)) {
12
13
  const configFile = await _import(
@@ -1,8 +1,9 @@
1
1
  /* eslint-disable no-console */
2
2
 
3
+ import readline from 'readline';
3
4
  import chalk from 'chalk';
4
5
 
5
- export default function log(message: string, type?: 'info' | 'warn' | 'error'): void {
6
+ export function log(message: string, type?: 'info' | 'warn' | 'error'): void {
6
7
  if (type === 'info') {
7
8
  console.log(`${chalk.bold.gray('[Info]')} ${message}`);
8
9
  } else if (type === 'warn') {
@@ -13,3 +14,12 @@ export default function log(message: string, type?: 'info' | 'warn' | 'error'):
13
14
  console.log(message);
14
15
  }
15
16
  }
17
+
18
+ export function clear() {
19
+ const repeatCount = process.stdout.rows - 2;
20
+ const blank = repeatCount > 0 ? '\n'.repeat(repeatCount) : '';
21
+ console.log(blank);
22
+
23
+ readline.cursorTo(process.stdout, 0, 0);
24
+ readline.clearScreenDown(process.stdout);
25
+ }
@@ -0,0 +1,16 @@
1
+ export default function toObject(val: string): Record<string, string> | null {
2
+ const arr = val.split(',');
3
+
4
+ const obj: Record<string, string> = {};
5
+ for (const v of arr) {
6
+ const sub = v.match(/^([^:]+):(.+)$/);
7
+
8
+ if (sub) {
9
+ obj[sub[1]!] = sub[2]!;
10
+ } else {
11
+ return null;
12
+ }
13
+ }
14
+
15
+ return obj;
16
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ export {
6
6
  definePanel,
7
7
  defineHook,
8
8
  defineEndpoint,
9
+ defineOperationApp,
10
+ defineOperationApi,
9
11
  getFieldsFromTemplate,
10
12
  getRelationType,
11
13
  } from '@directus/shared/utils';
@@ -22,7 +22,8 @@
22
22
  "forceConsistentCasingInFileNames": true,
23
23
  "allowSyntheticDefaultImports": true,
24
24
  "isolatedModules": true,
25
- "rootDir": "./src"
25
+ "rootDir": "./src",
26
+ "sourceMap": true
26
27
  },
27
28
  "include": ["./src/**/*.ts"]
28
29
  }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ id: 'custom',
3
+ handler: ({ text }) => {
4
+ console.log(text);
5
+ },
6
+ };
@@ -0,0 +1,23 @@
1
+ export default {
2
+ id: 'custom',
3
+ name: 'Custom',
4
+ icon: 'box',
5
+ description: 'This is my custom operation!',
6
+ overview: ({ text }) => [
7
+ {
8
+ label: 'Text',
9
+ text: text,
10
+ },
11
+ ],
12
+ options: [
13
+ {
14
+ field: 'text',
15
+ name: 'Text',
16
+ type: 'string',
17
+ meta: {
18
+ width: 'full',
19
+ interface: 'input',
20
+ },
21
+ },
22
+ ],
23
+ };
@@ -0,0 +1,12 @@
1
+ import { defineOperationApi } from '@directus/extensions-sdk';
2
+
3
+ type Options = {
4
+ text: string;
5
+ };
6
+
7
+ export default defineOperationApi<Options>({
8
+ id: 'custom',
9
+ handler: ({ text }) => {
10
+ console.log(text);
11
+ },
12
+ });
@@ -0,0 +1,25 @@
1
+ import { defineOperationApp } from '@directus/extensions-sdk';
2
+
3
+ export default defineOperationApp({
4
+ id: 'custom',
5
+ name: 'Custom',
6
+ icon: 'box',
7
+ description: 'This is my custom operation!',
8
+ overview: ({ text }) => [
9
+ {
10
+ label: 'Text',
11
+ text: text,
12
+ },
13
+ ],
14
+ options: [
15
+ {
16
+ field: 'text',
17
+ name: 'Text',
18
+ type: 'string',
19
+ meta: {
20
+ width: 'full',
21
+ interface: 'input',
22
+ },
23
+ },
24
+ ],
25
+ });
@@ -0,0 +1,5 @@
1
+ declare module '*.vue' {
2
+ import { DefineComponent } from 'vue';
3
+ const component: DefineComponent<{}, {}, any>;
4
+ export default component;
5
+ }