mmir-plugin-exports
v2.7.1
Published
generate module-ids.gen.js and module-cofig.gen.js for mmir-plugins
Downloads
20
Maintainers
Readme
Plugin Exports
Utilities for creating metadata files (module-ids.gen.js
, module-config.gen.js
) and
tools for managing compatiblity modules, typings, and project metadata.
Overview:
pluginexport
: Creating and Updatingmodule-ids.gen.js
pluginexport
: Creating and Updatingmodule-config.gen.js
createcompat
: Creating Media Plugin Compatibility Modulesdtsdownlevel
: Creating Compatibility Typings- Cordova Helper Scripts for MODE
copycordovascripts
: Install / Copy Scripts into Pluginupdateversion
: Updateversion
Field innpm
andcordova
Configuration Files
pluginexport
: Creating and Updating module-ids.gen.js
running pluginexport <dir>
parses the package.json
of a plugin and
- creates alias i.e.
paths
entries for all files in (recursively except for workers (sub)dir(s))directories.lib
- creates a list of
workers
for all files in (non-recursive!)<custom field> mmir.workers
string | Array<string>
: single or list of directory/ies or file(s)
- creates a list of exported
modules
for (non-recursive!)<custom field> mmir.exports
:string | Array<string>
: single or list of directory/ies or file(s)
- creates a list of exported
files
for (non-recursive!)<custom field> mmir.exportedFiles
:string | Array<string>
: single or list of file(s)
- creates an object
modes
for<custom field> mmir.modes
:{[modeName: string]: ModeDefinition}
: where eachModeDefinition
may have file-replacement-mappings and, optionally,exports
andexportFiles
fieldsModeDefinition
:{[originalFile: string]: ReplacementFile, exports?, exportFiles?}
- creates (string) entry
buildConfig
for<custom field> mmir.buildConfig
:string
: a file(s) containing a CommonJS module that exports a single or a list of (mmir) build configurations for the plugin
- adds as entry to exported
modules
with alias/path for the plugin itself, i.e{<plugin ID>: <main file>}
main
- creates a list of
dependencies
for all entries independencies
pluginexport
: Creating and Updating module-config.gen.js
running pluginexport <dir>
parses the config.d.ts
of a plugin and
- exports the properties (name) of
[.*]PluginConfig
interface aspluginName
:export interface SomeNamePluginConfig { <the plugin config name>: <the config entry type>; }
- if there is only one property specified, the generated module will represent a single plugin, e.g.
pluginName: "someName", config: [ ...
- if multiple properties are declared, the generated module's
pluginName
will be an array and an additional fieldplugins
will hold the corresponding plugin information, e.g.pluginName: ["pl1", "pl2"], plugins: { pl1: { pluginName: "pl1", config: [ ...
- the properties' type will be used as "main" entry point for creating the config-list, e.g.
->somePluginName: SomePluginConfigEntry; ... } export interface SomePluginConfigEntry extends MediaManagerPluginEntry { someConfig: string; }
pluginName: "somePluginName", config: ["someConfig"],
- optionally, if relevant for the plugin, the SpeechConfig entry is specified by adding it as Union type:
->somePluginName: SomePluginConfigEntry | SomePluginSpeechConfigEntry; ... } ... export interface SomePluginSpeechConfigEntry extends SpeechConfigPluginEntry { someSpeechConfig: string; }
pluginName: "somePluginName", config: ..., speechConfig: ["someSpeechConfig"],
- if configuration-properties (or speech-configuration) have JSDoc
@default
values specified, they will be included in the propertydefaultValues
(NOTE the default value must beJSON.parse
'able or simple string):
->somePluginName: SomePluginConfigEntry | SomePluginSpeechConfigEntry; ... } ... export interface SomePluginConfigEntry extends MediaManagerPluginEntry { /** @default theDefault */ someConfig: string; } export interface SomePluginSpeechConfigEntry extends SpeechConfigPluginEntry { /** @default 7 */ someSpeechNumConfig: number; }
pluginName: "somePluginName", config: [/** <js-doc> */"someConfig"], speechConfig: [/** <js-doc> */"someSpeechNumConfig"], defaultValues: { someConfig: "theDefault"}, defaultspeechValues: { someSpeechNumConfig: 7},
- if there is only one property specified, the generated module will represent a single plugin, e.g.
- exports other interfaces (their properties) with suffix PluginSpeechConfigEntry as speechConfig-property lists:
export interface SomeNamePluginSpeechConfigEntry {...
- NOTE should extend
mmir.SpeechConfigPluginEntry
- NOTE should extend
- exports other interfaces (their properties) with suffix PluginConfigEntry as config-property lists:
export interface AnotherNamePluginConfigEntry {...
- NOTE should extend
mmir.MediaManagerPluginEntry
- NOTE should extend
- exports enums as properties:
export enum SomeName {...
- NOTE: protected/special property names (for properties in
<*>PluginConfigEntry
and<*>PluginSpeechConfigEntry
)mod
: module name for the configuration entry ofMediaManager.plugins.env
ctx
: the (optional) context for the configuration entry ofMediaManager.plugins.env
config
: the custom plugin-configuration for the configuration entry ofMediaManager.plugins.env
NOTE all interfaces etc. must be defined in the root of config.d.ts
In addition, if it exists, 'pluginexport' parses the build-configuration file build-config.ts
and collects all export
ed
variables of type AppConfig
(type from module mmir-tooling
) into a list and stores it into field buildConfigs
.
(In addition, exported variables which's type end with AppConfig
are also collected into the field buildConfigs
, e.g. SomeAppConfig
)
For example:
import { AppConfig } from 'mmir-tooling';
import { WebpackAppConfig } from 'mmir-webpack';
export const buildConfig: AppConfig = {
states: {
models: {
myStateModel: {
moduleId: 'mmirf/myCustomStateModel',
file: __dirname + '/states/my-model.xml'
},
myOtherModel: {
moduleId: 'mmirf/otherCustomStateModel',
file: __dirname + '/states/my-other-model.xml'
},
}
}
};
export const buildConfigLibDependencies: WebpackAppConfig = {
includeModules: ['mmirf/util/extendDeep']
};
->
buildConfigs: [
{
states: {
models: {
myStateModel: {
moduleId: 'mmirf/myCustomStateModel',
file: __dirname + '/states/my-model.xml'
},
myOtherModel: {
moduleId: 'mmirf/otherCustomStateModel',
file: __dirname + '/states/my-other-model.xml'
},
}
}
},
{
includeModules: ['mmirf/util/extendDeep']
}
]
NOTE 1: build-configuration parsing only considers AppConfig
variables that are immediately initialized or creator functions that return build configurations (or FALSY values).
Example with build-config creator function:
import { PluginExportBuildConfigCreator , AppConfig } from 'mmir-tooling';
// a dynamic build-config specification using a creator function with:
// type PluginExportBuildConfigCreator = (pluginConfig: PluginConfig & TTSPluginSpeechConfig, runtimeConfig: RuntimeConfiguration, pluginBuildConfigs: PluginExportBuildConfig[]) => PluginExportBuildConfig;
export const buildConfigLibDependencies: PluginExportBuildConfigCreator = function(pluginConfig, runtimeConfig, pluginBuildConfigs) {
if(pluginConfig && pluginConfig.encoder === 'wav'){
return {
includeModules: ['mmir-plugin-encoder-core/workers/wavEncoder']
}
}
};
// ... and a non-dynamic build-config specification:
export const buildConfig: AppConfig = {
states: {
models: {
myStateModel: {
moduleId: 'mmirf/myCustomStateModel',
file: __dirname + '/states/my-model.xml'
}
}
}
};
->
buildConfigs: [
function(pluginConfig, _runtimeConfig, _pluginBuildConfigs) {
if(pluginConfig && pluginConfig.encoder === 'wav'){
return {
includeModules: ['mmir-plugin-encoder-core/workers/wavEncoder']
}
}
},
{
states: {
models: {
myStateModel: {
moduleId: 'mmirf/myCustomStateModel',
file: __dirname + '/states/my-model.xml'
}
}
}
}
],
NOTE 2: The build-config creator function must be specified using pure javascript
,
i.e. without any typescript
annotations except for the function type itself
(i.e. PluginExportBuildConfigCreator
); if the creator function returns a
FALSY value, it will be ignored.
If a module defines multiple plugins, build-configs for specific plugins can be
specified via PluginBuildConfig
, similar to the configuration definitions via PluginConfig
.
//define specific build-configs per plugin:
export class PluginBuildConfig {
/*
* list of build-configs for plugin asrAndroid
* NOTE: variables must be defined as const in the main module context (see below)
*/
asrAndroid: Partial<WebpackAppConfig>[] = [
simpleBuildConfigLibDependencies,
{
includeModules: ['direct/declaration']
}
];
/*
* single of build-config for plugin ttsAndroid
*/
ttsAndroid: PluginExportBuildConfigCreator = function(_pluginConfig, _runtimeConfig, _pluginBuildConfigs) {
return {
includeModules: ['member/direct/other/module']
}
};
}
/*
* referenced in specific build-config for asrAndroid
*/
const simpleBuildConfigLibDependencies: WebpackAppConfig = {
includeModules: ['mmirf/util/extendDeep']
};
/*
* non-specific build-config (i.e. for all plugins) need to be exported
*/
export const buildConfigLibDependencies: PluginExportBuildConfigCreator = function(pluginConfig, _runtimeConfig, _pluginBuildConfigs) {
if(pluginConfig && pluginConfig.encoder === 'wav'){
return {
includeModules: ['mmir-plugin-encoder-core/workers/wavEncoder']
}
}
};
createcompat
: Creating Media Plugin Compatibility Modules
running createcompat <dir>
if run with a directory as input:
parses the package.json
of the plugin and
- for each entry in
<custom field> mmir.compat.{<name>: <entry>}
a compatibility is created:<name>
: the source file (relative path within the package)<entry>
: the details for generating the compatibility module with{file: <file path>, type: <module type>, exportedName?: string}
:file
: the target file path where the created module will be stored (within the package)type
: the module type, one of"media" | "asr" | "tts" | "custom" | "none"
(DEFAULT: "media")exportedName
: iftype
is "custom", the name for the (global) variable must be specified, to which the module will be exportedtemplate
: iftype
is "none", the template file into which the original content will be inserted (use/*orig-content*/
as placeholder in the template file to indicate, where the original file content should be inserted)async
: (OPTIONAL) in casetype
is not"media"
this boolean value indicates if the plugin'sdefine
dependencies need to be required asynchronously (i.e. have not been required before; in case oftype
"media"
the dependencies will already be required asynchronously)
if specified, an async-wrapper will be generated, but:
[WARNING] note that the compatibility code will produces errors, if the exported object/function of plugin is immediately used (i.e. works only if exported object/function is used asynchronously)dependencyMapping
: (OPTIONAL) mapping for dependencies (in plugin'sdefine
statement): will be replaced in the generated compatibility code
example:dependencyMapping: {"mmirf/events": "./eventEmitter.js"}
additionalDependencies
: (OPTIONAL) map of additional dependencies (for the plugin'sdefine
statement):{<variable name>: <dependency>}
will be appended to the existing dependencies in the generated compatibility code
example:additionalDependencies: {"eventWrapper": "./eventEmitterWrapper.js"}
NOTEadditionalDependencies
are not subject to the replacement ofdependencyMapping
- examples:
mmir.compat = {"./www/voiceRecorder.js": {"file": "./res/voiceRecorderCompat.js", "type": "custom", "exportedName": "Recorder"}}
mmir.compat = {"./www/webAudioInput.js": {"file": "./www/alt/webAudioInputCompat.js","type": "media"}
mmir.compat = {"./www/encoder.js": {"file": "./www/alt/encoderCompat.js","type": "none","template":"./res/enconder-compat-template.js"}
dtsdownlevel
: Creating Compatibility Typings
running dtsdownlevel <dir>
will create backwards compatible typings *.d.ts
for use in projects that use typescript
< 3.8
(the targeted compatiblity level is typescript
version 3.5).
By default, the dtsdownlevel
script will copy the downleveled typings to <dir>/ts3.6
, which can be made available for
backwards compatibility, by adding an entry to the package.json
file, e.g. for the input typings directory lib
:
"typesVersions": {
"<3.9": {
"lib/*": [
"lib/ts3.6/*"
]
}
},
The option --dir <out-dir>
allows to specify a custom output directory (as a subdirectory of the input <dir>
):dtsdownlevel <dir> --dir <out-dir>
By default, the dtsdownlevel
will abort, if the targeted <out-dir>
is not empty.
Using the --force
flag will empty the <out-dir>
, i.e. force writing to the directory,
even if it is not empty.
Cordova Helper Scripts for MODE
The helper scripts will add support for cordova configuration/variable entry MMIR_PLUGIN_MODE
(in plugin's plugin.xml
or the using project's config.xml
), for using mode
dependent
implementation files.
Supported modes are
- "normal": the default implementation
- "compat": the compatibility implementation file(s)
- "wepack": special modus for
webpack
driven builds:
if webpack includes the implementation files during the build process, empty webpack-mode files can be added, to avoid including duplicate/unused source files.
For example, a plugin may specify in its plugin.xml
<!-- MMIR_PLUGIN_MODE: "normal" | "compat" | "webpack" -->
<preference name="MMIR_PLUGIN_MODE" default="normal" />
<hook src="res/js/before_plugin_install_hook.js" type="before_plugin_install" />
When the cordova plugin is installed, it will read the compat
-configuration of the plugin's package.json
in custom field "mmir"
, e.g.
"mmir": {
"compat": {
"./www/myImpl.js": {
"file": "./www/alt/myImplCompat.js",
"type": "asr"
}
}
},
and use its source- and target-directory for applying the webpack
or compat
mode:
for any file of the source directory for which a file with suffix Webpack
(for webpack
mode), or Compat
(for compat
mode), the replacement
file will be used in case the corresponding mode is activated.
In the example above, the source directory would be "./www" and the target directory where the mode-files need to be located, would be at "./www/alt".
A specific mode can be activated in various ways:
- as variable via a preference-tag in the plugin's
plugin.xml
(i.e. setting the default mode):<variable name="MMIR_PLUGIN_MODE" value="normal" />
- via command-line arguement when installing the plugin:
cordova plugin add ... --variable MMIR_PLUGIN_MODE=webpack
- by a preference-tag in the using-project's
config.xml
:
NOTE if the preference-tag is added to<preference name="MMIR_PLUGIN_MODE" value="webpack" />
config.xml
before installing/adding the cordova plugin, the command-line argument can be omitted
copycordovascripts
: Install / Copy Scripts into Plugin
after adding entry into package.json
:
"scripts": {
"install-cordova-scripts": "copycordovascripts res/js"
}
running the command:
npm run install-cordova-scripts
will copy the cordova helper scripts into the plugin's sub-directory res/js/
.
updateversion
: Update version
Field in npm
and cordova
Configuration Files
The script
updateversion <directory> --set-version <version>
allows to update the version in npm
and cordova
configuration files without
reformatting the files.
The target directory will be scanned for the following configuration files:
package.json
package-lock.json
(needs to explicitly enabled with flag--enable-package-lock
)config.xml
(cordova
app project configuration)plugin.xml
(cordova
plugin project configuration)
Updating for specific files can be disabled by --disable-<package | config | plugin>
.
If no version is specified with --set-version <version>
, the version is read from
package.json
by default, and the other configuration files are updated with it.
Alternatively, the version can be read from another configuration file using
--from-<package | config | plugin>
.
In addition, the script may target a specific file, or multiple files and directories
updateversion <file1> <directory1> <file2> --set-version <version>
For writing version information to arbitrary text files, regluar rexpressions can be used. However, if specifying an regular expression, it cannot target files that were discovered by parsing an directory, i.e. the file must be specifically be given.
The regular expression must be specified in form of a JavaScript RegExp literal, e.g.
/^(my-exprsion) matches$/i
If the expression contains spaces, it must be wrapped in quotes.
Example:
updateversion <file> --version-regexp "/@version \d+\.\d+\.\d+/i" --from-package
For conveinance, §VERSION§
can be used as a placeholder to match version strings
that follow the semantic versioning convention (e.g. 1.0.4-alpha
):
updateversion <file> --version-regexp "/@version §VERSION§/i" --from-package
If capture groups are used in the regular expression, an additional argument allows
to specify a replacement pattern which can contain references to the capture groups
$<group number>
(where the first group has number 1
).
The version number (either specified by --set-version
or read from a configuration
file) can be referenced by the special group number 0
, i.e. $0
.
Example:
updateversion <file> --version-regexp "/(@version) \d+\.\d+\.\d+/i" --replace-pattern "$1 $0" --from-package
which would a replacement string for the version number <version>
: "@version <version>"
(i.e. instead of replacing the complete match with the version number)
Note that §VERSION§
defines one capture groupt itself, e.g.
# in this example capture group $2 would contain the original (found) version string
updateversion <file> --version-regexp "/(@version) §VERSION§( production)/i" --replace-pattern "$1 $0$3" --from-package
For conveinance, the script can be added to the package.json
after installing
the package, e.g. the following will update the version that is read from the
package.json
file, and will update all supported configuration files (inlcuding
package-lock.json
), except for the plugin.xml
file:
"scripts": {
"update-version": "updateversion ./ --enable-package-lock --disable-plugin"
}