mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-06 09:47:43 +02:00
add platform package
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Don't allow people to merge changes to these generated files, because the result
|
||||
# may be invalid. You need to run "rush update" again.
|
||||
pnpm-lock.yaml merge=binary
|
||||
shrinkwrap.yaml merge=binary
|
||||
npm-shrinkwrap.json merge=binary
|
||||
yarn.lock merge=binary
|
||||
|
||||
# Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic
|
||||
# syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor
|
||||
# may also require a special configuration to allow comments in JSON.
|
||||
#
|
||||
# For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088
|
||||
#
|
||||
*.json linguist-language=JSON-with-Comments
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
.heft/
|
||||
lib/
|
||||
_api-extractor-temp/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# OS X temporary files
|
||||
.DS_Store
|
||||
|
||||
# Rush temporary files
|
||||
common/deploy/
|
||||
common/temp/
|
||||
common/autoinstallers/*/.npmrc
|
||||
**/.rush/temp/
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '8.9.4'
|
||||
script:
|
||||
- set -e
|
||||
|
||||
- echo 'Checking for missing change logs...' && echo -en 'travis_fold:start:change\\r'
|
||||
- git fetch origin master:refs/remotes/origin/master -a
|
||||
- node common/scripts/install-run-rush.js change -v
|
||||
- echo -en 'travis_fold:end:change\\r'
|
||||
|
||||
- echo 'Installing...' && echo -en 'travis_fold:start:install\\r'
|
||||
- node common/scripts/install-run-rush.js install
|
||||
- echo -en 'travis_fold:end:install\\r'
|
||||
|
||||
- echo 'Building...' && echo -en 'travis_fold:start:build\\r'
|
||||
- node common/scripts/install-run-rush.js rebuild --verbose
|
||||
- echo -en 'travis_fold:end:build\\r'
|
||||
@@ -0,0 +1,22 @@
|
||||
# Rush uses this file to configure the NPM package registry during installation. It is applicable
|
||||
# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install",
|
||||
# "rush update", and the "install-run.js" scripts.
|
||||
#
|
||||
# NOTE: The "rush publish" command uses .npmrc-publish instead.
|
||||
#
|
||||
# Before invoking the package manager, Rush will copy this file to the folder where installation
|
||||
# is performed. The copied file will omit any config lines that reference environment variables
|
||||
# that are undefined in that session; this avoids problems that would otherwise result due to
|
||||
# a missing variable being replaced by an empty string.
|
||||
#
|
||||
# * * * SECURITY WARNING * * *
|
||||
#
|
||||
# It is NOT recommended to store authentication tokens in a text file on a lab machine, because
|
||||
# other unrelated processes may be able to read the file. Also, the file may persist indefinitely,
|
||||
# for example if the machine loses power. A safer practice is to pass the token via an
|
||||
# environment variable, which can be referenced from .npmrc using ${} expansion. For example:
|
||||
#
|
||||
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
|
||||
#
|
||||
registry=https://registry.npmjs.org/
|
||||
always-auth=false
|
||||
@@ -0,0 +1,20 @@
|
||||
# This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish
|
||||
# is used by the "rush publish" command, as publishing often involves different credentials
|
||||
# and registries than other operations.
|
||||
#
|
||||
# Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc"
|
||||
# and then temporarily map that folder as the "home directory" for the current user account.
|
||||
# This enables the same settings to apply for each project folder that gets published. The copied file
|
||||
# will omit any config lines that reference environment variables that are undefined in that session;
|
||||
# this avoids problems that would otherwise result due to a missing variable being replaced by
|
||||
# an empty string.
|
||||
#
|
||||
# * * * SECURITY WARNING * * *
|
||||
#
|
||||
# It is NOT recommended to store authentication tokens in a text file on a lab machine, because
|
||||
# other unrelated processes may be able to read the file. Also, the file may persist indefinitely,
|
||||
# for example if the machine loses power. A safer practice is to pass the token via an
|
||||
# environment variable, which can be referenced from .npmrc using ${} expansion. For example:
|
||||
#
|
||||
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
|
||||
#
|
||||
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* When using the PNPM package manager, you can use pnpmfile.js to workaround
|
||||
* dependencies that have mistakes in their package.json file. (This feature is
|
||||
* functionally similar to Yarn's "resolutions".)
|
||||
*
|
||||
* For details, see the PNPM documentation:
|
||||
* https://pnpm.js.org/docs/en/hooks.html
|
||||
*
|
||||
* IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE
|
||||
* ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run
|
||||
* "rush update --full" so that PNPM will recalculate all version selections.
|
||||
*/
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This hook is invoked during installation before a package's dependencies
|
||||
* are selected.
|
||||
* The `packageJson` parameter is the deserialized package.json
|
||||
* contents for the package that is about to be installed.
|
||||
* The `context` parameter provides a log() function.
|
||||
* The return value is the updated object.
|
||||
*/
|
||||
function readPackage(packageJson, context) {
|
||||
|
||||
// // The karma types have a missing dependency on typings from the log4js package.
|
||||
// if (packageJson.name === '@types/karma') {
|
||||
// context.log('Fixed up dependencies for @types/karma');
|
||||
// packageJson.dependencies['log4js'] = '0.6.38';
|
||||
// }
|
||||
|
||||
return packageJson;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* This configuration file manages Rush integration with JFrog Artifactory services.
|
||||
* More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json",
|
||||
|
||||
"packageRegistry": {
|
||||
/**
|
||||
* (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry.
|
||||
* When enabled, "rush install" will automatically detect when the user's ~/.npmrc
|
||||
* authentication token is missing or expired. And "rush setup" will prompt the user to
|
||||
* renew their token.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
"enabled": false,
|
||||
|
||||
/**
|
||||
* (Required) Specify the URL of your NPM registry. This is the same URL that appears in
|
||||
* your .npmrc file. It should look something like this example:
|
||||
*
|
||||
* https://your-company.jfrog.io/your-project/api/npm/npm-private/
|
||||
*/
|
||||
"registryUrl": "",
|
||||
|
||||
/**
|
||||
* A list of custom strings that "rush setup" should add to the user's ~/.npmrc file at the time
|
||||
* when the token is updated. This could be used for example to configure the company registry
|
||||
* to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush
|
||||
* operations like "rush add" and "rush install", which get their mappings from the monorepo's
|
||||
* common/config/rush/.npmrc file).
|
||||
*
|
||||
* NOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful
|
||||
* about adding settings that may interfere with other work outside the monorepo.
|
||||
*/
|
||||
"userNpmrcLinesToAdd": [
|
||||
// "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/"
|
||||
],
|
||||
|
||||
/**
|
||||
* (Required) Specifies the URL of the Artifactory control panel where the user can generate
|
||||
* an API key. This URL is printed after the "visitWebsite" message.
|
||||
* It should look something like this example: https://your-company.jfrog.io/
|
||||
* Specify an empty string to suppress this line entirely.
|
||||
*/
|
||||
"artifactoryWebsiteUrl": "",
|
||||
|
||||
/**
|
||||
* These settings allow the "rush setup" interactive prompts to be customized, for
|
||||
* example with messages specific to your team or configuration. Specify an empty string
|
||||
* to suppress that message entirely.
|
||||
*/
|
||||
"messageOverrides": {
|
||||
/**
|
||||
* Overrides the message that normally says:
|
||||
* "This monorepo consumes packages from an Artifactory private NPM registry."
|
||||
*/
|
||||
// "introduction": "",
|
||||
/**
|
||||
* Overrides the message that normally says:
|
||||
* "Please contact the repository maintainers for help with setting up an Artifactory user account."
|
||||
*/
|
||||
// "obtainAnAccount": "",
|
||||
/**
|
||||
* Overrides the message that normally says:
|
||||
* "Please open this URL in your web browser:"
|
||||
*
|
||||
* The "artifactoryWebsiteUrl" string is printed after this message.
|
||||
*/
|
||||
// "visitWebsite": "",
|
||||
/**
|
||||
* Overrides the message that normally says:
|
||||
* "Your user name appears in the upper-right corner of the JFrog website."
|
||||
*/
|
||||
// "locateUserName": "",
|
||||
/**
|
||||
* Overrides the message that normally says:
|
||||
* "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key'
|
||||
* button if you haven't already done so previously."
|
||||
*/
|
||||
// "locateApiKey": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* This configuration file manages Rush's build cache feature.
|
||||
* More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json",
|
||||
|
||||
/**
|
||||
* (Required) EXPERIMENTAL - Set this to true to enable the build cache feature.
|
||||
*
|
||||
* See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature.
|
||||
*/
|
||||
"buildCacheEnabled": false,
|
||||
|
||||
/**
|
||||
* (Required) Choose where project build outputs will be cached.
|
||||
*
|
||||
* Possible values: "local-only", "azure-blob-storage", "amazon-s3"
|
||||
*/
|
||||
"cacheProvider": "local-only",
|
||||
|
||||
/**
|
||||
* Setting this property overrides the cache entry ID. If this property is set, it must contain
|
||||
* a [hash] token. It may also contain a [projectName] or a [projectName:normalize] token.
|
||||
*/
|
||||
// "cacheEntryNamePattern": "[projectName:normalize]-[hash]"
|
||||
|
||||
/**
|
||||
* Use this configuration with "cacheProvider"="azure-blob-storage"
|
||||
*/
|
||||
"azureBlobStorageConfiguration": {
|
||||
/**
|
||||
* (Required) The name of the the Azure storage account to use for build cache.
|
||||
*/
|
||||
// "storageAccountName": "example",
|
||||
|
||||
/**
|
||||
* (Required) The name of the container in the Azure storage account to use for build cache.
|
||||
*/
|
||||
// "storageContainerName": "my-container",
|
||||
|
||||
/**
|
||||
* The Azure environment the storage account exists in. Defaults to AzurePublicCloud.
|
||||
*
|
||||
* Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment"
|
||||
*/
|
||||
// "azureEnvironment": "AzurePublicCloud",
|
||||
|
||||
/**
|
||||
* An optional prefix for cache item blob names.
|
||||
*/
|
||||
// "blobPrefix": "my-prefix",
|
||||
|
||||
/**
|
||||
* If set to true, allow writing to the cache. Defaults to false.
|
||||
*/
|
||||
// "isCacheWriteAllowed": true
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this configuration with "cacheProvider"="amazon-s3"
|
||||
*/
|
||||
"amazonS3Configuration": {
|
||||
/**
|
||||
* (Required) The Amazon S3 region of the bucket to use for build cache (e.g. "us-east-1").
|
||||
*/
|
||||
// "s3Region": "us-east-1",
|
||||
|
||||
/**
|
||||
* The name of the bucket in Amazon S3 to use for build cache.
|
||||
*/
|
||||
// (Required) "s3Bucket": "my-bucket",
|
||||
|
||||
/**
|
||||
* An optional prefix ("folder") for cache items.
|
||||
*/
|
||||
// "s3Prefix": "my-prefix",
|
||||
|
||||
/**
|
||||
* If set to true, allow writing to the cache. Defaults to false.
|
||||
*/
|
||||
// "isCacheWriteAllowed": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* This configuration file defines custom commands for the "rush" command-line.
|
||||
* More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json",
|
||||
|
||||
/**
|
||||
* Custom "commands" introduce new verbs for the command-line. To see the help for these
|
||||
* example commands, try "rush --help", "rush my-bulk-command --help", or
|
||||
* "rush my-global-command --help".
|
||||
*/
|
||||
"commands": [
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Determines the type of custom command.
|
||||
// * Rush's "bulk" commands are invoked separately for each project. Rush will look in
|
||||
// * each project's package.json file for a "scripts" entry whose name matches the
|
||||
// * command name. By default, the command will run for every project in the repo,
|
||||
// * according to the dependency graph (similar to how "rush build" works).
|
||||
// * The set of projects can be restricted e.g. using the "--to" or "--from" parameters.
|
||||
// */
|
||||
// "commandKind": "bulk",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The name that will be typed as part of the command line. This is also the name
|
||||
// * of the "scripts" hook in the project's package.json file.
|
||||
// * The name should be comprised of lower case words separated by hyphens or colons. The name should include an
|
||||
// * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands
|
||||
// * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc).
|
||||
// *
|
||||
// * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command
|
||||
// * and will call the "rebuild" script instead of the "build" script.
|
||||
// */
|
||||
// "name": "my-bulk-command",
|
||||
//
|
||||
// /**
|
||||
// * (Required) A short summary of the custom command to be shown when printing command line
|
||||
// * help, e.g. "rush --help".
|
||||
// */
|
||||
// "summary": "Example bulk custom command",
|
||||
//
|
||||
// /**
|
||||
// * A detailed description of the command to be shown when printing command line
|
||||
// * help (e.g. "rush --help my-command").
|
||||
// * If omitted, the "summary" text will be shown instead.
|
||||
// *
|
||||
// * Whenever you introduce commands/parameters, taking a little time to write meaningful
|
||||
// * documentation can make a big difference for the developer experience in your repo.
|
||||
// */
|
||||
// "description": "This is an example custom command that runs separately for each project",
|
||||
//
|
||||
// /**
|
||||
// * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously
|
||||
// * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the
|
||||
// * same time.) If your command makes sense to run concurrently with other operations,
|
||||
// * set "safeForSimultaneousRushProcesses" to true to disable this protection.
|
||||
// *
|
||||
// * In particular, this is needed for custom scripts that invoke other Rush commands.
|
||||
// */
|
||||
// "safeForSimultaneousRushProcesses": false,
|
||||
//
|
||||
// /**
|
||||
// * (Required) If true, then this command is safe to be run in parallel, i.e. executed
|
||||
// * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism
|
||||
// * projects will not start processing until their dependencies have completed processing.
|
||||
// */
|
||||
// "enableParallelism": false,
|
||||
//
|
||||
// /**
|
||||
// * Normally projects will be processed according to their dependency order: a given project will not start
|
||||
// * processing the command until all of its dependencies have completed. This restriction doesn't apply for
|
||||
// * certain operations, for example a "clean" task that deletes output files. In this case
|
||||
// * you can set "ignoreDependencyOrder" to true to increase parallelism.
|
||||
// */
|
||||
// "ignoreDependencyOrder": false,
|
||||
//
|
||||
// /**
|
||||
// * Normally Rush requires that each project's package.json has a "scripts" entry matching
|
||||
// * the custom command name. To disable this check, set "ignoreMissingScript" to true;
|
||||
// * projects with a missing definition will be skipped.
|
||||
// */
|
||||
// "ignoreMissingScript": false,
|
||||
//
|
||||
// /**
|
||||
// * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings:
|
||||
// * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors".
|
||||
// * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects.
|
||||
// * - If the shell script returns a zero process exit code but writes something to its stderr stream,
|
||||
// * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent
|
||||
// * Rush from processing downstream projects.
|
||||
// *
|
||||
// * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because
|
||||
// * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design.
|
||||
// * In an active monorepo, we've found that if you allow any warnings in your master branch, it inadvertently
|
||||
// * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings
|
||||
// * have accumulated that warnings no longer serve any useful purpose.
|
||||
// *
|
||||
// * Sometimes a poorly behaved task will write output to stderr even though its operation was successful.
|
||||
// * In that case, it's strongly recommended to fix the task. However, as a workaround you can set
|
||||
// * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only.
|
||||
// *
|
||||
// * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true.
|
||||
// */
|
||||
// "allowWarningsInSuccessfulBuild": false,
|
||||
//
|
||||
// /**
|
||||
// * If true then this command will be incremental like the built-in "build" command
|
||||
// */
|
||||
// "incremental": false,
|
||||
//
|
||||
// /**
|
||||
// * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush
|
||||
// * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a
|
||||
// * change is detected, the command will be invoked again for the changed project and any selected projects that
|
||||
// * directly or indirectly depend on it.
|
||||
// *
|
||||
// * For details, refer to the website article "Using watch mode".
|
||||
// */
|
||||
// "watchForChanges": false,
|
||||
//
|
||||
// /**
|
||||
// * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of
|
||||
// * projects' own folders.
|
||||
// */
|
||||
// "disableBuildCache": false
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Determines the type of custom command.
|
||||
// * Rush's "global" commands are invoked once for the entire repo.
|
||||
// */
|
||||
// "commandKind": "global",
|
||||
//
|
||||
// "name": "my-global-command",
|
||||
// "summary": "Example global custom command",
|
||||
// "description": "This is an example custom command that runs once for the entire repo",
|
||||
//
|
||||
// "safeForSimultaneousRushProcesses": false,
|
||||
//
|
||||
// /**
|
||||
// * (Required) A script that will be invoked using the OS shell. The working directory will be
|
||||
// * the folder that contains rush.json. If custom parameters are associated with this command, their
|
||||
// * values will be appended to the end of this string.
|
||||
// */
|
||||
// "shellCommand": "node common/scripts/my-global-command.js",
|
||||
//
|
||||
// /**
|
||||
// * If your "shellCommand" script depends on NPM packages, the recommended best practice is
|
||||
// * to make it into a regular Rush project that builds using your normal toolchain. In cases where
|
||||
// * the command needs to work without first having to run "rush build", the recommended practice
|
||||
// * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it.
|
||||
// *
|
||||
// * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with
|
||||
// * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to
|
||||
// * install these dependencies before an associated command is invoked. Autoinstallers have the
|
||||
// * advantage that they work even in a branch where "rush install" is broken, which makes them a
|
||||
// * good solution for Git hook scripts. But they have the disadvantages of not being buildable
|
||||
// * projects, and of increasing the overall installation footprint for your monorepo.
|
||||
// *
|
||||
// * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name.
|
||||
// * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and
|
||||
// * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when
|
||||
// * invoking the "shellCommand".
|
||||
// */
|
||||
// // "autoinstallerName": "my-task"
|
||||
// }
|
||||
],
|
||||
|
||||
/**
|
||||
* Custom "parameters" introduce new parameters for specified Rush command-line commands.
|
||||
* For example, you might define a "--production" parameter for the "rush build" command.
|
||||
*/
|
||||
"parameters": [
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Determines the type of custom parameter.
|
||||
// * A "flag" is a custom command-line parameter whose presence acts as an on/off switch.
|
||||
// */
|
||||
// "parameterKind": "flag",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The long name of the parameter. It must be lower-case and use dash delimiters.
|
||||
// */
|
||||
// "longName": "--my-flag",
|
||||
//
|
||||
// /**
|
||||
// * An optional alternative short name for the parameter. It must be a dash followed by a single
|
||||
// * lower-case or upper-case letter, which is case-sensitive.
|
||||
// *
|
||||
// * NOTE: The Rush developers recommend that automation scripts should always use the long name
|
||||
// * to improve readability. The short name is only intended as a convenience for humans.
|
||||
// * The alphabet letters run out quickly, and are difficult to memorize, so *only* use
|
||||
// * a short name if you expect the parameter to be needed very often in everyday operations.
|
||||
// */
|
||||
// "shortName": "-m",
|
||||
//
|
||||
// /**
|
||||
// * (Required) A long description to be shown in the command-line help.
|
||||
// *
|
||||
// * Whenever you introduce commands/parameters, taking a little time to write meaningful
|
||||
// * documentation can make a big difference for the developer experience in your repo.
|
||||
// */
|
||||
// "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects",
|
||||
//
|
||||
// /**
|
||||
// * (Required) A list of custom commands and/or built-in Rush commands that this parameter may
|
||||
// * be used with. The parameter will be appended to the shell command that Rush invokes.
|
||||
// */
|
||||
// "associatedCommands": ["build", "rebuild"]
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Determines the type of custom parameter.
|
||||
// * A "string" is a custom command-line parameter whose value is a simple text string.
|
||||
// */
|
||||
// "parameterKind": "string",
|
||||
// "longName": "--my-string",
|
||||
// "description": "A custom string parameter for the \"my-global-command\" custom command",
|
||||
//
|
||||
// "associatedCommands": ["my-global-command"],
|
||||
//
|
||||
// /**
|
||||
// * The name of the argument, which will be shown in the command-line help.
|
||||
// *
|
||||
// * For example, if the parameter name is '--count" and the argument name is "NUMBER",
|
||||
// * then the command-line help would display "--count NUMBER". The argument name must
|
||||
// * be comprised of upper-case letters, numbers, and underscores. It should be kept short.
|
||||
// */
|
||||
// "argumentName": "SOME_TEXT",
|
||||
//
|
||||
// /**
|
||||
// * If true, this parameter must be included with the command. The default is false.
|
||||
// */
|
||||
// "required": false
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Determines the type of custom parameter.
|
||||
// * A "choice" is a custom command-line parameter whose argument must be chosen from a list of
|
||||
// * allowable alternatives.
|
||||
// */
|
||||
// "parameterKind": "choice",
|
||||
// "longName": "--my-choice",
|
||||
// "description": "A custom choice parameter for the \"my-global-command\" custom command",
|
||||
//
|
||||
// "associatedCommands": ["my-global-command"],
|
||||
//
|
||||
// /**
|
||||
// * If true, this parameter must be included with the command. The default is false.
|
||||
// */
|
||||
// "required": false,
|
||||
//
|
||||
// /**
|
||||
// * Normally if a parameter is omitted from the command line, it will not be passed
|
||||
// * to the shell command. this value will be inserted by default. Whereas if a "defaultValue"
|
||||
// * is defined, the parameter will always be passed to the shell command, and will use the
|
||||
// * default value if unspecified. The value must be one of the defined alternatives.
|
||||
// */
|
||||
// "defaultValue": "vanilla",
|
||||
//
|
||||
// /**
|
||||
// * (Required) A list of alternative argument values that can be chosen for this parameter.
|
||||
// */
|
||||
// "alternatives": [
|
||||
// {
|
||||
// /**
|
||||
// * A token that is one of the alternatives that can be used with the choice parameter,
|
||||
// * e.g. "vanilla" in "--flavor vanilla".
|
||||
// */
|
||||
// "name": "vanilla",
|
||||
//
|
||||
// /**
|
||||
// * A detailed description for the alternative that can be shown in the command-line help.
|
||||
// *
|
||||
// * Whenever you introduce commands/parameters, taking a little time to write meaningful
|
||||
// * documentation can make a big difference for the developer experience in your repo.
|
||||
// */
|
||||
// "description": "Use the vanilla flavor (the default)"
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// "name": "chocolate",
|
||||
// "description": "Use the chocolate flavor"
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// "name": "strawberry",
|
||||
// "description": "Use the strawberry flavor"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* This configuration file specifies NPM dependency version selections that affect all projects
|
||||
* in a Rush repo. More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json",
|
||||
|
||||
/**
|
||||
* A table that specifies a "preferred version" for a given NPM package. This feature is typically used
|
||||
* to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies.
|
||||
*
|
||||
* The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into
|
||||
* the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager
|
||||
* will calculate versions. The specific effect depends on your package manager. Generally it will have no
|
||||
* effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be
|
||||
* achieved using the pnpmfile.js hook. See the Rush documentation for more details.
|
||||
*
|
||||
* After modifying this field, it's recommended to run "rush update --full" so that the package manager
|
||||
* will recalculate all version selections.
|
||||
*/
|
||||
"preferredVersions": {
|
||||
/**
|
||||
* When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo,
|
||||
* instead of the latest version.
|
||||
*/
|
||||
// "some-library": "1.2.3"
|
||||
},
|
||||
|
||||
/**
|
||||
* When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions,
|
||||
* except in cases where different projects specify different version ranges for a given dependency. For older
|
||||
* package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause
|
||||
* trouble for indirect dependencies with incompatible peerDependencies ranges.
|
||||
*
|
||||
* The default value is true. If you're encountering installation errors related to peer dependencies,
|
||||
* it's recommended to set this to false.
|
||||
*
|
||||
* After modifying this field, it's recommended to run "rush update --full" so that the package manager
|
||||
* will recalculate all version selections.
|
||||
*/
|
||||
// "implicitlyPreferredVersions": false,
|
||||
|
||||
/**
|
||||
* The "rush check" command can be used to enforce that every project in the repo must specify
|
||||
* the same SemVer range for a given dependency. However, sometimes exceptions are needed.
|
||||
* The allowedAlternativeVersions table allows you to list other SemVer ranges that will be
|
||||
* accepted by "rush check" for a given dependency.
|
||||
*
|
||||
* IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE
|
||||
* USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO).
|
||||
* This design avoids unnecessary churn in this file.
|
||||
*/
|
||||
"allowedAlternativeVersions": {
|
||||
/**
|
||||
* For example, allow some projects to use an older TypeScript compiler
|
||||
* (in addition to whatever "usual" version is being used by other projects in the repo):
|
||||
*/
|
||||
// "typescript": [
|
||||
// "~2.4.0"
|
||||
// ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* This configuration file allows repo maintainers to enable and disable experimental
|
||||
* Rush features. More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json",
|
||||
|
||||
/**
|
||||
* By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'.
|
||||
* Set this option to true to pass '--frozen-lockfile' instead for faster installs.
|
||||
*/
|
||||
// "usePnpmFrozenLockfileForRushInstall": true,
|
||||
|
||||
/**
|
||||
* By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'.
|
||||
* Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes.
|
||||
*/
|
||||
// "usePnpmPreferFrozenLockfileForRushUpdate": true,
|
||||
|
||||
/**
|
||||
* If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies.
|
||||
* Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not
|
||||
* cause hash changes.
|
||||
*/
|
||||
// "omitImportersFromPreventManualShrinkwrapChanges": true,
|
||||
|
||||
/**
|
||||
* If true, the chmod field in temporary project tar headers will not be normalized.
|
||||
* This normalization can help ensure consistent tarball integrity across platforms.
|
||||
*/
|
||||
// "noChmodFieldInTarHeaderNormalization": true
|
||||
}
|
||||
Generated
+5190
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* This is configuration file is used for advanced publishing configurations with Rush.
|
||||
* More documentation is available on the Rush website: https://rushjs.io
|
||||
*/
|
||||
|
||||
/**
|
||||
* A list of version policy definitions. A "version policy" is a custom package versioning
|
||||
* strategy that affects "rush change", "rush version", and "rush publish". The strategy applies
|
||||
* to a set of projects that are specified using the "versionPolicyName" field in rush.json.
|
||||
*/
|
||||
[
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion").
|
||||
// *
|
||||
// * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This
|
||||
// * strategy is appropriate for a set of packages that act as selectable components of a
|
||||
// * unified product. The entire set of packages are always published together, and always share
|
||||
// * the same NPM version number. When the packages depend on other packages in the set, the
|
||||
// * SemVer range is usually restricted to a single version.
|
||||
// */
|
||||
// "definitionName": "lockStepVersion",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The name that will be used for the "versionPolicyName" field in rush.json.
|
||||
// * This name is also used command-line parameters such as "--version-policy"
|
||||
// * and "--to-version-policy".
|
||||
// */
|
||||
// "policyName": "MyBigFramework",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The current version. All packages belonging to the set should have this version
|
||||
// * in the current branch. When bumping versions, Rush uses this to determine the next version.
|
||||
// * (The "version" field in package.json is NOT considered.)
|
||||
// */
|
||||
// "version": "1.0.0",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The type of bump that will be performed when publishing the next release.
|
||||
// * When creating a release branch in Git, this field should be updated according to the
|
||||
// * type of release.
|
||||
// *
|
||||
// * Valid values are: "prerelease", "release", "minor", "patch", "major"
|
||||
// */
|
||||
// "nextBump": "prerelease",
|
||||
//
|
||||
// /**
|
||||
// * (Optional) If specified, all packages in the set share a common CHANGELOG.md file.
|
||||
// * This file is stored with the specified "main" project, which must be a member of the set.
|
||||
// *
|
||||
// * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each
|
||||
// * package in the set.
|
||||
// */
|
||||
// "mainProject": "my-app",
|
||||
//
|
||||
// /**
|
||||
// * (Optional) If enabled, the "rush change" command will prompt the user for their email address
|
||||
// * and include it in the JSON change files. If an organization maintains multiple repos, tracking
|
||||
// * this contact information may be useful for a service that automatically upgrades packages and
|
||||
// * needs to notify engineers whose change may be responsible for a downstream build break. It might
|
||||
// * also be useful for crediting contributors. Rush itself does not do anything with the collected
|
||||
// * email addresses. The default value is "false".
|
||||
// */
|
||||
// // "includeEmailInChangeFile": true
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion").
|
||||
// *
|
||||
// * The "individualVersion" mode specifies that the projects will use "individual versioning".
|
||||
// * This is the typical NPM model where each package has an independent version number
|
||||
// * and CHANGELOG.md file. Although a single CI definition is responsible for publishing the
|
||||
// * packages, they otherwise don't have any special relationship. The version bumping will
|
||||
// * depend on how developers answer the "rush change" questions for each package that
|
||||
// * is changed.
|
||||
// */
|
||||
// "definitionName": "individualVersion",
|
||||
//
|
||||
// "policyName": "MyRandomLibraries",
|
||||
//
|
||||
// /**
|
||||
// * (Optional) This can be used to enforce that all packages in the set must share a common
|
||||
// * major version number, e.g. because they are from the same major release branch.
|
||||
// * It can also be used to discourage people from accidentally making "MAJOR" SemVer changes
|
||||
// * inappropriately. The minor/patch version parts will be bumped independently according
|
||||
// * to the types of changes made to each project, according to the "rush change" command.
|
||||
// */
|
||||
// "lockedMajor": 3,
|
||||
//
|
||||
// /**
|
||||
// * (Optional) When publishing is managed by Rush, by default the "rush change" command will
|
||||
// * request changes for any projects that are modified by a pull request. These change entries
|
||||
// * will produce a CHANGELOG.md file. If you author your CHANGELOG.md manually or announce updates
|
||||
// * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects
|
||||
// * belonging to this version policy.
|
||||
// */
|
||||
// "exemptFromRushChange": false,
|
||||
//
|
||||
// // "includeEmailInChangeFile": true
|
||||
// }
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This is an example Git hook for use with Rush. To enable this hook, rename this file
|
||||
# to "commit-msg" and then run "rush install", which will copy it from common/git-hooks
|
||||
# to the .git/hooks folder.
|
||||
#
|
||||
# TO LEARN MORE ABOUT GIT HOOKS
|
||||
#
|
||||
# The Git documentation is here: https://git-scm.com/docs/githooks
|
||||
# Some helpful resources: https://githooks.com
|
||||
#
|
||||
# ABOUT THIS EXAMPLE
|
||||
#
|
||||
# The commit-msg hook is called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero status after issuing
|
||||
# an appropriate message if it wants to stop the commit. The hook is allowed to edit
|
||||
# the commit message file.
|
||||
|
||||
# This example enforces that commit message should contain a minimum amount of
|
||||
# description text.
|
||||
if [ `cat $1 | wc -w` -lt 3 ]; then
|
||||
echo ""
|
||||
echo "Invalid commit message: The message must contain at least 3 words."
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See the @microsoft/rush package's LICENSE file for license information.
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
|
||||
//
|
||||
// This script is intended for usage in an automated build environment where the Rush command may not have
|
||||
// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush
|
||||
// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it.
|
||||
// An example usage would be:
|
||||
//
|
||||
// node common/scripts/install-run-rush.js install
|
||||
//
|
||||
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
|
||||
const path = __importStar(require("path"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const install_run_1 = require("./install-run");
|
||||
const PACKAGE_NAME = '@microsoft/rush';
|
||||
const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION';
|
||||
function _getRushVersion() {
|
||||
const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION];
|
||||
if (rushPreviewVersion !== undefined) {
|
||||
console.log(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`);
|
||||
return rushPreviewVersion;
|
||||
}
|
||||
const rushJsonFolder = install_run_1.findRushJsonFolder();
|
||||
const rushJsonPath = path.join(rushJsonFolder, install_run_1.RUSH_JSON_FILENAME);
|
||||
try {
|
||||
const rushJsonContents = fs.readFileSync(rushJsonPath, 'utf-8');
|
||||
// Use a regular expression to parse out the rushVersion value because rush.json supports comments,
|
||||
// but JSON.parse does not and we don't want to pull in more dependencies than we need to in this script.
|
||||
const rushJsonMatches = rushJsonContents.match(/\"rushVersion\"\s*\:\s*\"([0-9a-zA-Z.+\-]+)\"/);
|
||||
return rushJsonMatches[1];
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to determine the required version of Rush from rush.json (${rushJsonFolder}). ` +
|
||||
"The 'rushVersion' field is either not assigned in rush.json or was specified " +
|
||||
'using an unexpected syntax.');
|
||||
}
|
||||
}
|
||||
function _run() {
|
||||
const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv;
|
||||
// Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the
|
||||
// appropriate binary inside the rush package to run
|
||||
const scriptName = path.basename(scriptPath);
|
||||
const bin = scriptName.toLowerCase() === 'install-run-rushx.js' ? 'rushx' : 'rush';
|
||||
if (!nodePath || !scriptPath) {
|
||||
throw new Error('Unexpected exception: could not detect node path or script path');
|
||||
}
|
||||
if (process.argv.length < 3) {
|
||||
console.log(`Usage: ${scriptName} <command> [args...]`);
|
||||
if (scriptName === 'install-run-rush.js') {
|
||||
console.log(`Example: ${scriptName} build --to myproject`);
|
||||
}
|
||||
else {
|
||||
console.log(`Example: ${scriptName} custom-command`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
install_run_1.runWithErrorAndStatusCode(() => {
|
||||
const version = _getRushVersion();
|
||||
console.log(`The rush.json configuration requests Rush version ${version}`);
|
||||
return install_run_1.installAndRun(PACKAGE_NAME, version, bin, packageBinArgs);
|
||||
});
|
||||
}
|
||||
_run();
|
||||
//# sourceMappingURL=install-run-rush.js.map
|
||||
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See the @microsoft/rush package's LICENSE file for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
|
||||
//
|
||||
// This script is intended for usage in an automated build environment where the Rush command may not have
|
||||
// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush
|
||||
// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the
|
||||
// rushx command.
|
||||
//
|
||||
// An example usage would be:
|
||||
//
|
||||
// node common/scripts/install-run-rushx.js custom-command
|
||||
//
|
||||
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
|
||||
require("./install-run-rush");
|
||||
//# sourceMappingURL=install-run-rushx.js.map
|
||||
@@ -0,0 +1,478 @@
|
||||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See the @microsoft/rush package's LICENSE file for license information.
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runWithErrorAndStatusCode = exports.installAndRun = exports.findRushJsonFolder = exports.getNpmPath = exports.RUSH_JSON_FILENAME = void 0;
|
||||
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
|
||||
//
|
||||
// This script is intended for usage in an automated build environment where a Node tool may not have
|
||||
// been preinstalled, or may have an unpredictable version. This script will automatically install the specified
|
||||
// version of the specified tool (if not already installed), and then pass a command-line to it.
|
||||
// An example usage would be:
|
||||
//
|
||||
// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io
|
||||
//
|
||||
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
|
||||
const childProcess = __importStar(require("child_process"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const os = __importStar(require("os"));
|
||||
const path = __importStar(require("path"));
|
||||
exports.RUSH_JSON_FILENAME = 'rush.json';
|
||||
const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER';
|
||||
const INSTALLED_FLAG_FILENAME = 'installed.flag';
|
||||
const NODE_MODULES_FOLDER_NAME = 'node_modules';
|
||||
const PACKAGE_JSON_FILENAME = 'package.json';
|
||||
/**
|
||||
* Parse a package specifier (in the form of name\@version) into name and version parts.
|
||||
*/
|
||||
function _parsePackageSpecifier(rawPackageSpecifier) {
|
||||
rawPackageSpecifier = (rawPackageSpecifier || '').trim();
|
||||
const separatorIndex = rawPackageSpecifier.lastIndexOf('@');
|
||||
let name;
|
||||
let version = undefined;
|
||||
if (separatorIndex === 0) {
|
||||
// The specifier starts with a scope and doesn't have a version specified
|
||||
name = rawPackageSpecifier;
|
||||
}
|
||||
else if (separatorIndex === -1) {
|
||||
// The specifier doesn't have a version
|
||||
name = rawPackageSpecifier;
|
||||
}
|
||||
else {
|
||||
name = rawPackageSpecifier.substring(0, separatorIndex);
|
||||
version = rawPackageSpecifier.substring(separatorIndex + 1);
|
||||
}
|
||||
if (!name) {
|
||||
throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`);
|
||||
}
|
||||
return { name, version };
|
||||
}
|
||||
/**
|
||||
* As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims
|
||||
* unusable lines from the .npmrc file.
|
||||
*
|
||||
* Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in
|
||||
* the .npmrc file to provide different authentication tokens for different registry.
|
||||
* However, if the environment variable is undefined, it expands to an empty string, which
|
||||
* produces a valid-looking mapping with an invalid URL that causes an error. Instead,
|
||||
* we'd prefer to skip that line and continue looking in other places such as the user's
|
||||
* home directory.
|
||||
*
|
||||
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities.copyAndTrimNpmrcFile()
|
||||
*/
|
||||
function _copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath) {
|
||||
console.log(`Transforming ${sourceNpmrcPath}`); // Verbose
|
||||
console.log(` --> "${targetNpmrcPath}"`);
|
||||
let npmrcFileLines = fs.readFileSync(sourceNpmrcPath).toString().split('\n');
|
||||
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
|
||||
const resultLines = [];
|
||||
// This finds environment variable tokens that look like "${VAR_NAME}"
|
||||
const expansionRegExp = /\$\{([^\}]+)\}/g;
|
||||
// Comment lines start with "#" or ";"
|
||||
const commentRegExp = /^\s*[#;]/;
|
||||
// Trim out lines that reference environment variables that aren't defined
|
||||
for (const line of npmrcFileLines) {
|
||||
let lineShouldBeTrimmed = false;
|
||||
// Ignore comment lines
|
||||
if (!commentRegExp.test(line)) {
|
||||
const environmentVariables = line.match(expansionRegExp);
|
||||
if (environmentVariables) {
|
||||
for (const token of environmentVariables) {
|
||||
// Remove the leading "${" and the trailing "}" from the token
|
||||
const environmentVariableName = token.substring(2, token.length - 1);
|
||||
// Is the environment variable defined?
|
||||
if (!process.env[environmentVariableName]) {
|
||||
// No, so trim this line
|
||||
lineShouldBeTrimmed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lineShouldBeTrimmed) {
|
||||
// Example output:
|
||||
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
|
||||
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
|
||||
}
|
||||
else {
|
||||
resultLines.push(line);
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(targetNpmrcPath, resultLines.join(os.EOL));
|
||||
}
|
||||
/**
|
||||
* syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file.
|
||||
* If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder.
|
||||
*
|
||||
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc()
|
||||
*/
|
||||
function _syncNpmrc(sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish) {
|
||||
const sourceNpmrcPath = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish');
|
||||
const targetNpmrcPath = path.join(targetNpmrcFolder, '.npmrc');
|
||||
try {
|
||||
if (fs.existsSync(sourceNpmrcPath)) {
|
||||
_copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath);
|
||||
}
|
||||
else if (fs.existsSync(targetNpmrcPath)) {
|
||||
// If the source .npmrc doesn't exist and there is one in the target, delete the one in the target
|
||||
console.log(`Deleting ${targetNpmrcPath}`); // Verbose
|
||||
fs.unlinkSync(targetNpmrcPath);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Error syncing .npmrc file: ${e}`);
|
||||
}
|
||||
}
|
||||
let _npmPath = undefined;
|
||||
/**
|
||||
* Get the absolute path to the npm executable
|
||||
*/
|
||||
function getNpmPath() {
|
||||
if (!_npmPath) {
|
||||
try {
|
||||
if (os.platform() === 'win32') {
|
||||
// We're on Windows
|
||||
const whereOutput = childProcess.execSync('where npm', { stdio: [] }).toString();
|
||||
const lines = whereOutput.split(os.EOL).filter((line) => !!line);
|
||||
// take the last result, we are looking for a .cmd command
|
||||
// see https://github.com/microsoft/rushstack/issues/759
|
||||
_npmPath = lines[lines.length - 1];
|
||||
}
|
||||
else {
|
||||
// We aren't on Windows - assume we're on *NIX or Darwin
|
||||
_npmPath = childProcess.execSync('command -v npm', { stdio: [] }).toString();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to determine the path to the NPM tool: ${e}`);
|
||||
}
|
||||
_npmPath = _npmPath.trim();
|
||||
if (!fs.existsSync(_npmPath)) {
|
||||
throw new Error('The NPM executable does not exist');
|
||||
}
|
||||
}
|
||||
return _npmPath;
|
||||
}
|
||||
exports.getNpmPath = getNpmPath;
|
||||
function _ensureFolder(folderPath) {
|
||||
if (!fs.existsSync(folderPath)) {
|
||||
const parentDir = path.dirname(folderPath);
|
||||
_ensureFolder(parentDir);
|
||||
fs.mkdirSync(folderPath);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create missing directories under the specified base directory, and return the resolved directory.
|
||||
*
|
||||
* Does not support "." or ".." path segments.
|
||||
* Assumes the baseFolder exists.
|
||||
*/
|
||||
function _ensureAndJoinPath(baseFolder, ...pathSegments) {
|
||||
let joinedPath = baseFolder;
|
||||
try {
|
||||
for (let pathSegment of pathSegments) {
|
||||
pathSegment = pathSegment.replace(/[\\\/]/g, '+');
|
||||
joinedPath = path.join(joinedPath, pathSegment);
|
||||
if (!fs.existsSync(joinedPath)) {
|
||||
fs.mkdirSync(joinedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Error building local installation folder (${path.join(baseFolder, ...pathSegments)}): ${e}`);
|
||||
}
|
||||
return joinedPath;
|
||||
}
|
||||
function _getRushTempFolder(rushCommonFolder) {
|
||||
const rushTempFolder = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME];
|
||||
if (rushTempFolder !== undefined) {
|
||||
_ensureFolder(rushTempFolder);
|
||||
return rushTempFolder;
|
||||
}
|
||||
else {
|
||||
return _ensureAndJoinPath(rushCommonFolder, 'temp');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolve a package specifier to a static version
|
||||
*/
|
||||
function _resolvePackageVersion(rushCommonFolder, { name, version }) {
|
||||
if (!version) {
|
||||
version = '*'; // If no version is specified, use the latest version
|
||||
}
|
||||
if (version.match(/^[a-zA-Z0-9\-\+\.]+$/)) {
|
||||
// If the version contains only characters that we recognize to be used in static version specifiers,
|
||||
// pass the version through
|
||||
return version;
|
||||
}
|
||||
else {
|
||||
// version resolves to
|
||||
try {
|
||||
const rushTempFolder = _getRushTempFolder(rushCommonFolder);
|
||||
const sourceNpmrcFolder = path.join(rushCommonFolder, 'config', 'rush');
|
||||
_syncNpmrc(sourceNpmrcFolder, rushTempFolder);
|
||||
const npmPath = getNpmPath();
|
||||
// This returns something that looks like:
|
||||
// @microsoft/rush@3.0.0 '3.0.0'
|
||||
// @microsoft/rush@3.0.1 '3.0.1'
|
||||
// ...
|
||||
// @microsoft/rush@3.0.20 '3.0.20'
|
||||
// <blank line>
|
||||
const npmVersionSpawnResult = childProcess.spawnSync(npmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier'], {
|
||||
cwd: rushTempFolder,
|
||||
stdio: []
|
||||
});
|
||||
if (npmVersionSpawnResult.status !== 0) {
|
||||
throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`);
|
||||
}
|
||||
const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString();
|
||||
const versionLines = npmViewVersionOutput.split('\n').filter((line) => !!line);
|
||||
const latestVersion = versionLines[versionLines.length - 1];
|
||||
if (!latestVersion) {
|
||||
throw new Error('No versions found for the specified version range.');
|
||||
}
|
||||
const versionMatches = latestVersion.match(/^.+\s\'(.+)\'$/);
|
||||
if (!versionMatches) {
|
||||
throw new Error(`Invalid npm output ${latestVersion}`);
|
||||
}
|
||||
return versionMatches[1];
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
let _rushJsonFolder;
|
||||
/**
|
||||
* Find the absolute path to the folder containing rush.json
|
||||
*/
|
||||
function findRushJsonFolder() {
|
||||
if (!_rushJsonFolder) {
|
||||
let basePath = __dirname;
|
||||
let tempPath = __dirname;
|
||||
do {
|
||||
const testRushJsonPath = path.join(basePath, exports.RUSH_JSON_FILENAME);
|
||||
if (fs.existsSync(testRushJsonPath)) {
|
||||
_rushJsonFolder = basePath;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
basePath = tempPath;
|
||||
}
|
||||
} while (basePath !== (tempPath = path.dirname(basePath))); // Exit the loop when we hit the disk root
|
||||
if (!_rushJsonFolder) {
|
||||
throw new Error('Unable to find rush.json.');
|
||||
}
|
||||
}
|
||||
return _rushJsonFolder;
|
||||
}
|
||||
exports.findRushJsonFolder = findRushJsonFolder;
|
||||
/**
|
||||
* Detects if the package in the specified directory is installed
|
||||
*/
|
||||
function _isPackageAlreadyInstalled(packageInstallFolder) {
|
||||
try {
|
||||
const flagFilePath = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME);
|
||||
if (!fs.existsSync(flagFilePath)) {
|
||||
return false;
|
||||
}
|
||||
const fileContents = fs.readFileSync(flagFilePath).toString();
|
||||
return fileContents.trim() === process.version;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Removes the following files and directories under the specified folder path:
|
||||
* - installed.flag
|
||||
* -
|
||||
* - node_modules
|
||||
*/
|
||||
function _cleanInstallFolder(rushTempFolder, packageInstallFolder) {
|
||||
try {
|
||||
const flagFile = path.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME);
|
||||
if (fs.existsSync(flagFile)) {
|
||||
fs.unlinkSync(flagFile);
|
||||
}
|
||||
const packageLockFile = path.resolve(packageInstallFolder, 'package-lock.json');
|
||||
if (fs.existsSync(packageLockFile)) {
|
||||
fs.unlinkSync(packageLockFile);
|
||||
}
|
||||
const nodeModulesFolder = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME);
|
||||
if (fs.existsSync(nodeModulesFolder)) {
|
||||
const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler');
|
||||
fs.renameSync(nodeModulesFolder, path.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`));
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`);
|
||||
}
|
||||
}
|
||||
function _createPackageJson(packageInstallFolder, name, version) {
|
||||
try {
|
||||
const packageJsonContents = {
|
||||
name: 'ci-rush',
|
||||
version: '0.0.0',
|
||||
dependencies: {
|
||||
[name]: version
|
||||
},
|
||||
description: "DON'T WARN",
|
||||
repository: "DON'T WARN",
|
||||
license: 'MIT'
|
||||
};
|
||||
const packageJsonPath = path.join(packageInstallFolder, PACKAGE_JSON_FILENAME);
|
||||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2));
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to create package.json: ${e}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Run "npm install" in the package install folder.
|
||||
*/
|
||||
function _installPackage(packageInstallFolder, name, version) {
|
||||
try {
|
||||
console.log(`Installing ${name}...`);
|
||||
const npmPath = getNpmPath();
|
||||
const result = childProcess.spawnSync(npmPath, ['install'], {
|
||||
stdio: 'inherit',
|
||||
cwd: packageInstallFolder,
|
||||
env: process.env
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
throw new Error('"npm install" encountered an error');
|
||||
}
|
||||
console.log(`Successfully installed ${name}@${version}`);
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to install package: ${e}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the ".bin" path for the package.
|
||||
*/
|
||||
function _getBinPath(packageInstallFolder, binName) {
|
||||
const binFolderPath = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin');
|
||||
const resolvedBinName = os.platform() === 'win32' ? `${binName}.cmd` : binName;
|
||||
return path.resolve(binFolderPath, resolvedBinName);
|
||||
}
|
||||
/**
|
||||
* Write a flag file to the package's install directory, signifying that the install was successful.
|
||||
*/
|
||||
function _writeFlagFile(packageInstallFolder) {
|
||||
try {
|
||||
const flagFilePath = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME);
|
||||
fs.writeFileSync(flagFilePath, process.version);
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`);
|
||||
}
|
||||
}
|
||||
function installAndRun(packageName, packageVersion, packageBinName, packageBinArgs) {
|
||||
const rushJsonFolder = findRushJsonFolder();
|
||||
const rushCommonFolder = path.join(rushJsonFolder, 'common');
|
||||
const rushTempFolder = _getRushTempFolder(rushCommonFolder);
|
||||
const packageInstallFolder = _ensureAndJoinPath(rushTempFolder, 'install-run', `${packageName}@${packageVersion}`);
|
||||
if (!_isPackageAlreadyInstalled(packageInstallFolder)) {
|
||||
// The package isn't already installed
|
||||
_cleanInstallFolder(rushTempFolder, packageInstallFolder);
|
||||
const sourceNpmrcFolder = path.join(rushCommonFolder, 'config', 'rush');
|
||||
_syncNpmrc(sourceNpmrcFolder, packageInstallFolder);
|
||||
_createPackageJson(packageInstallFolder, packageName, packageVersion);
|
||||
_installPackage(packageInstallFolder, packageName, packageVersion);
|
||||
_writeFlagFile(packageInstallFolder);
|
||||
}
|
||||
const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`;
|
||||
const statusMessageLine = new Array(statusMessage.length + 1).join('-');
|
||||
console.log(os.EOL + statusMessage + os.EOL + statusMessageLine + os.EOL);
|
||||
const binPath = _getBinPath(packageInstallFolder, packageBinName);
|
||||
const binFolderPath = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin');
|
||||
// Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to
|
||||
// assign via the process.env proxy to ensure that we append to the right PATH key.
|
||||
const originalEnvPath = process.env.PATH || '';
|
||||
let result;
|
||||
try {
|
||||
// Node.js on Windows can not spawn a file when the path has a space on it
|
||||
// unless the path gets wrapped in a cmd friendly way and shell mode is used
|
||||
const shouldUseShell = binPath.includes(' ') && os.platform() === 'win32';
|
||||
const platformBinPath = shouldUseShell ? `"${binPath}"` : binPath;
|
||||
process.env.PATH = [binFolderPath, originalEnvPath].join(path.delimiter);
|
||||
result = childProcess.spawnSync(platformBinPath, packageBinArgs, {
|
||||
stdio: 'inherit',
|
||||
windowsVerbatimArguments: false,
|
||||
shell: shouldUseShell,
|
||||
cwd: process.cwd(),
|
||||
env: process.env
|
||||
});
|
||||
}
|
||||
finally {
|
||||
process.env.PATH = originalEnvPath;
|
||||
}
|
||||
if (result.status !== null) {
|
||||
return result.status;
|
||||
}
|
||||
else {
|
||||
throw result.error || new Error('An unknown error occurred.');
|
||||
}
|
||||
}
|
||||
exports.installAndRun = installAndRun;
|
||||
function runWithErrorAndStatusCode(fn) {
|
||||
process.exitCode = 1;
|
||||
try {
|
||||
const exitCode = fn();
|
||||
process.exitCode = exitCode;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(os.EOL + os.EOL + e.toString() + os.EOL + os.EOL);
|
||||
}
|
||||
}
|
||||
exports.runWithErrorAndStatusCode = runWithErrorAndStatusCode;
|
||||
function _run() {
|
||||
const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, rawPackageSpecifier /* qrcode@^1.2.0 */, packageBinName /* qrcode */, ...packageBinArgs /* [-f, myproject/lib] */] = process.argv;
|
||||
if (!nodePath) {
|
||||
throw new Error('Unexpected exception: could not detect node path');
|
||||
}
|
||||
if (path.basename(scriptPath).toLowerCase() !== 'install-run.js') {
|
||||
// If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control
|
||||
// to the script that (presumably) imported this file
|
||||
return;
|
||||
}
|
||||
if (process.argv.length < 4) {
|
||||
console.log('Usage: install-run.js <package>@<version> <command> [args...]');
|
||||
console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io');
|
||||
process.exit(1);
|
||||
}
|
||||
runWithErrorAndStatusCode(() => {
|
||||
const rushJsonFolder = findRushJsonFolder();
|
||||
const rushCommonFolder = _ensureAndJoinPath(rushJsonFolder, 'common');
|
||||
const packageSpecifier = _parsePackageSpecifier(rawPackageSpecifier);
|
||||
const name = packageSpecifier.name;
|
||||
const version = _resolvePackageVersion(rushCommonFolder, packageSpecifier);
|
||||
if (packageSpecifier.version !== version) {
|
||||
console.log(`Resolved to ${name}@${version}`);
|
||||
}
|
||||
return installAndRun(name, version, packageBinName, packageBinArgs);
|
||||
});
|
||||
}
|
||||
_run();
|
||||
//# sourceMappingURL=install-run.js.map
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@anticrm/platform-rig",
|
||||
"version": "0.5.0",
|
||||
"scripts": {
|
||||
"build": ""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/heft-jest-plugin":"~0.1.15",
|
||||
"@rushstack/heft":"^0.35.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/api-extractor": "~7.18.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
|
||||
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS require().
|
||||
*
|
||||
* SUPPORTED TOKENS: none
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "extends": "./shared/api-extractor-base.json"
|
||||
// "extends": "my-package/include/api-extractor-base.json"
|
||||
|
||||
/**
|
||||
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
|
||||
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
|
||||
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
|
||||
* will be reported.
|
||||
*
|
||||
* SUPPORTED TOKENS: <lookup>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "projectFolder": "..",
|
||||
|
||||
/**
|
||||
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
*/
|
||||
"mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
|
||||
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
|
||||
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
|
||||
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports library2. To avoid this, we can specify:
|
||||
*
|
||||
* "bundledPackages": [ "library2" ],
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for library1.
|
||||
*/
|
||||
"bundledPackages": [],
|
||||
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*/
|
||||
"compiler": {
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* Note: This setting will be ignored if "overrideTsconfig" is used.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
|
||||
*/
|
||||
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
* The object must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
|
||||
*
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
// "overrideTsconfig": {
|
||||
// . . .
|
||||
// }
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
|
||||
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
|
||||
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "skipLibCheck": true,
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the API report file (*.api.md) will be generated.
|
||||
*/
|
||||
"apiReport": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate an API report.
|
||||
*/
|
||||
"enabled": false,
|
||||
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
|
||||
* a full file path.
|
||||
*
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
|
||||
*
|
||||
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
|
||||
*/
|
||||
// "reportFileName": "<unscopedPackageName>.api.md",
|
||||
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/etc/"
|
||||
*/
|
||||
"reportFolder": "<projectFolder>/_api-review/",
|
||||
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
"reportTempFolder": "<projectFolder>/_api-extractor-temp/"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*/
|
||||
"docModel": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate a doc model file.
|
||||
*/
|
||||
"enabled": true,
|
||||
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
*/
|
||||
"apiJsonFilePath": "<projectFolder>/_api-extractor-temp/doc-models/<unscopedPackageName>.api.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*/
|
||||
"dtsRollup": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
"enabled": false
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
|
||||
*/
|
||||
// "untrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
* This file will include only declarations that are marked as "@public" or "@beta".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
* This file will include only declarations that are marked as "@public".
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
|
||||
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "omitTrimmingComments": true
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*/
|
||||
"tsdocMetadata": {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*
|
||||
* DEFAULT VALUE: true
|
||||
*/
|
||||
// "enabled": true,
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
|
||||
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to "tsdoc-metadata.json" in the package folder.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
|
||||
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*
|
||||
* DEFAULT VALUE: "crlf"
|
||||
*/
|
||||
// "newlineKind": "crlf",
|
||||
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
|
||||
*/
|
||||
"messages": {
|
||||
/**
|
||||
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
|
||||
* the input .d.ts files.
|
||||
*
|
||||
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"compilerMessageReporting": {
|
||||
/**
|
||||
* Configures the default routing for messages that don't match an explicit rule in this table.
|
||||
*/
|
||||
"default": {
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log. Note that
|
||||
* the "addToApiReportFile" property may supersede this option.
|
||||
*
|
||||
* Possible values: "error", "warning", "none"
|
||||
*
|
||||
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
|
||||
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
|
||||
* the "--local" option), the warning is displayed but the build will not fail.
|
||||
*
|
||||
* DEFAULT VALUE: "warning"
|
||||
*/
|
||||
"logLevel": "warning"
|
||||
|
||||
/**
|
||||
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the "logLevel" option.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "TS2551": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
|
||||
*
|
||||
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
|
||||
*/
|
||||
"extractorMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "ae-extra-release-tag": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*
|
||||
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"tsdocMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "tsdoc-link-tag-unescaped-text": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/heft/heft.schema.json",
|
||||
|
||||
"eventActions": [
|
||||
{
|
||||
"actionKind": "deleteGlobs",
|
||||
"heftEvent": "clean",
|
||||
"actionId": "defaultClean",
|
||||
"globsToDelete": ["dist", "lib", "temp"]
|
||||
}
|
||||
],
|
||||
"heftPlugins": [
|
||||
{
|
||||
"plugin": "@rushstack/heft-jest-plugin"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json",
|
||||
"testEnvironment": "node",
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
],
|
||||
"testMatch": ["**/?(*.)+(spec|test).[jt]s?(x)"],
|
||||
"collectCoverage": true,
|
||||
"coverageDirectory": "coverage",
|
||||
"coverageReporters": ["text", ["lcov", { "projectRoot": "../../" }]]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"types": ["heft-jest"],
|
||||
"lib": [
|
||||
"esnext",
|
||||
"esnext.intl",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
extends: 'standard-with-typescript',
|
||||
parserOptions: {
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
|
||||
/**
|
||||
* (Required) The name of the rig package to inherit from.
|
||||
* It should be an NPM package name with the "-rig" suffix.
|
||||
*/
|
||||
"rigPackageName": "@anticrm/platform-rig"
|
||||
|
||||
/**
|
||||
* (Optional) Selects a config profile from the rig package. The name must consist of
|
||||
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
||||
* If omitted, then the "default" profile will be used."
|
||||
*/
|
||||
// "rigProfile": "your-profile-name"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@anticrm/platform",
|
||||
"version": "0.5.0",
|
||||
"main": "lib/index.js",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "heft build --clean",
|
||||
"build:docs": "api-extractor run --local",
|
||||
"test": "jest",
|
||||
"lint": "ts-standard src",
|
||||
"lint:fix": "eslint --fix ./src",
|
||||
"format": "prettier --write 'src/**/*.{ts*,js*,yml}' && ts-standard --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig":"~0.5.0",
|
||||
"@types/heft-jest":"^1.0.2",
|
||||
"eslint-plugin-promise":"4",
|
||||
"eslint-plugin-import":"2",
|
||||
"eslint-plugin-node":"11",
|
||||
"@typescript-eslint/eslint-plugin":"4",
|
||||
"eslint-config-standard-with-typescript":"^20.0.0",
|
||||
"typescript":"^4.3.5",
|
||||
"eslint":"^7.32.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser":"^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"intl-messageformat": "^9.7.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, IntlString } from '../platform'
|
||||
import platform, { plugin } from '../platform'
|
||||
import { Severity, Status } from '../status'
|
||||
|
||||
import { addStringsLoader, translate } from '../i18n'
|
||||
import { addEventListener, PlatformEvent, removeEventListener } from '../event'
|
||||
|
||||
const testId = 'test-strings' as Plugin
|
||||
|
||||
const test = plugin(testId, {
|
||||
string: {
|
||||
loadingPlugin: '' as IntlString<{ plugin: string }>
|
||||
}
|
||||
})
|
||||
|
||||
describe('i18n', () => {
|
||||
it('should translate string', async () => {
|
||||
addStringsLoader(testId, async (locale: string) => await import(`./lang/${locale}.json`))
|
||||
const translated = await translate(test.string.loadingPlugin, { plugin: 'xxx' })
|
||||
expect(translated).toBe('Loading plugin <b>xxx</b>...')
|
||||
})
|
||||
|
||||
it('should return id when no translation found', async () => {
|
||||
const id = (testId + '.inexistent') as IntlString
|
||||
const inexistent = await translate(id, {})
|
||||
expect(inexistent).toBe(id)
|
||||
})
|
||||
|
||||
it('should cache translated string', async () => {
|
||||
const translated = await translate(test.string.loadingPlugin, { plugin: 'xxx' })
|
||||
expect(translated).toBe('Loading plugin <b>xxx</b>...')
|
||||
})
|
||||
|
||||
it('should emit status and return id when no loader', async () => {
|
||||
expect.assertions(2)
|
||||
const plugin = 'plugin-without-string-loader'
|
||||
const message = `${plugin}.string.id`
|
||||
|
||||
const checkStatus = new Status(Severity.ERROR, platform.status.NoLoaderForStrings, { plugin })
|
||||
const eventListener = async (event: string, data: any): Promise<void> => {
|
||||
expect(data).toEqual(checkStatus)
|
||||
}
|
||||
addEventListener(PlatformEvent, eventListener)
|
||||
const translated = await translate(message as IntlString, {})
|
||||
expect(translated).toBe(message)
|
||||
removeEventListener(PlatformEvent, eventListener)
|
||||
})
|
||||
|
||||
it('should emit status and return id when bad loader', async () => {
|
||||
expect.assertions(2)
|
||||
const plugin = 'component-for-bad-loader'
|
||||
const message = `${plugin}.string.id`
|
||||
const errorMessage = 'bad loader'
|
||||
addStringsLoader(plugin as Plugin, (locale: string) => {
|
||||
throw new Error(errorMessage)
|
||||
})
|
||||
|
||||
const checkStatus = new Status(Severity.ERROR, platform.status.UnknownError, { message: errorMessage })
|
||||
const eventListener = async (event: string, data: any): Promise<void> => {
|
||||
expect(data).toEqual(checkStatus)
|
||||
}
|
||||
addEventListener(PlatformEvent, eventListener)
|
||||
const translated = await translate(message as IntlString, {})
|
||||
expect(translated).toBe(message)
|
||||
removeEventListener(PlatformEvent, eventListener)
|
||||
})
|
||||
|
||||
it('should cache error', async () => {
|
||||
const plugin = 'component'
|
||||
const message = `${plugin}.string.id`
|
||||
|
||||
const checkStatus = new Status(Severity.ERROR, platform.status.NoLoaderForStrings, { plugin })
|
||||
let calls = 0
|
||||
const eventListener = async (event: string, data: any): Promise<void> => {
|
||||
++calls
|
||||
expect(data).toEqual(checkStatus)
|
||||
}
|
||||
|
||||
addEventListener(PlatformEvent, eventListener)
|
||||
const t1 = await translate(message as IntlString, {})
|
||||
const t2 = await translate(message as IntlString, {})
|
||||
expect(t1).toBe(t2)
|
||||
removeEventListener(PlatformEvent, eventListener)
|
||||
expect(calls).toBe(1)
|
||||
})
|
||||
|
||||
it('should return message when bad id', async () => {
|
||||
expect.assertions(2)
|
||||
const message = 'testMessage' as IntlString
|
||||
const checkStatus = new Status(Severity.ERROR, platform.status.InvalidId, { id: message })
|
||||
const eventListener = async (event: string, data: any): Promise<void> => {
|
||||
expect(data).toEqual(checkStatus)
|
||||
}
|
||||
addEventListener(PlatformEvent, eventListener)
|
||||
const translated = await translate(message, {})
|
||||
expect(translated).toBe(message)
|
||||
removeEventListener(PlatformEvent, eventListener)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { StatusCode, Plugin, Id } from '../platform'
|
||||
import { plugin, mergeIds } from '../platform'
|
||||
import { _parseId } from '../ident'
|
||||
|
||||
describe('ident', () => {
|
||||
const test = 'test' as Plugin
|
||||
|
||||
it('should identify resources', () => {
|
||||
const ids = plugin(test, {
|
||||
status: {
|
||||
MyString: '' as StatusCode<{}>
|
||||
}
|
||||
})
|
||||
expect(ids.status.MyString).toBe('test.status.MyString')
|
||||
})
|
||||
|
||||
it('should merge ids', () => {
|
||||
const ids = plugin(test, {
|
||||
resource: {
|
||||
MyString: '' as StatusCode<{}>
|
||||
}
|
||||
})
|
||||
const merged = mergeIds(test, ids, {
|
||||
resource: {
|
||||
OneMore: '' as StatusCode<{}>
|
||||
},
|
||||
more: {
|
||||
X: '' as StatusCode<{}>
|
||||
}
|
||||
})
|
||||
expect(merged.resource.MyString).toBe('test.resource.MyString')
|
||||
expect(merged.resource.OneMore).toBe('test.resource.OneMore')
|
||||
expect(merged.more.X).toBe('test.more.X')
|
||||
})
|
||||
|
||||
it('should fail overwriting ids', () => {
|
||||
const ids = plugin(test, {
|
||||
resource: {
|
||||
MyString: '' as StatusCode<{}>
|
||||
}
|
||||
})
|
||||
const f = (): any =>
|
||||
mergeIds(test, ids, {
|
||||
resource: {
|
||||
MyString: 'xxx' as StatusCode<{}>
|
||||
}
|
||||
})
|
||||
expect(f).toThrowError("'identify' overwrites")
|
||||
})
|
||||
|
||||
it('should fail to parse id', () => {
|
||||
expect(() => _parseId('bad id' as Id)).toThrowError(
|
||||
'ERROR: platform.status.InvalidId'
|
||||
)
|
||||
})
|
||||
|
||||
it('should parse id', () => {
|
||||
expect(_parseId('comp.res.X' as Id)).toEqual({
|
||||
kind: 'res',
|
||||
component: 'comp',
|
||||
name: 'X'
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"string": {
|
||||
"loadingPlugin": "Loading plugin '<b>'{plugin}'</b>'..."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
test: {
|
||||
X: 'Test'
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, IntlString, Resource } from '../platform'
|
||||
import { plugin } from '../platform'
|
||||
import { addLocation, getResource } from '../resource'
|
||||
|
||||
describe('resource', () => {
|
||||
const test = 'test' as Plugin
|
||||
|
||||
const testPlugin = plugin(test, {
|
||||
string: {
|
||||
Hello: '' as IntlString<{ name: string }>
|
||||
},
|
||||
test: {
|
||||
X: '' as Resource<string>
|
||||
}
|
||||
})
|
||||
|
||||
addLocation(test, async () => await import('./plugin'))
|
||||
|
||||
it('should load resource', async () => {
|
||||
const string = await getResource(testPlugin.test.X)
|
||||
expect(string).toBe('Test')
|
||||
const cached = await getResource(testPlugin.test.X)
|
||||
expect(cached).toBe('Test')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Status, unknownError, OK } from './status'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const PlatformEvent = 'platform-event'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type EventListener = (event: string, data: any) => Promise<void>
|
||||
|
||||
const eventListeners = new Map<string, EventListener[]>()
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param event -
|
||||
* @param listener -
|
||||
*/
|
||||
export function addEventListener (event: string, listener: EventListener): void {
|
||||
const listeners = eventListeners.get(event)
|
||||
if (listeners !== undefined) {
|
||||
listeners.push(listener)
|
||||
} else {
|
||||
eventListeners.set(event, [listener])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param event -
|
||||
* @param listener -
|
||||
*/
|
||||
export function removeEventListener (
|
||||
event: string,
|
||||
listener: EventListener
|
||||
): void {
|
||||
const listeners = eventListeners.get(event)
|
||||
if (listeners !== undefined) {
|
||||
listeners.splice(listeners.indexOf(listener), 1)
|
||||
}
|
||||
}
|
||||
|
||||
async function broadcastEvent (event: string, data: any): Promise<void> {
|
||||
const listeners = eventListeners.get(event)
|
||||
if (listeners !== undefined) {
|
||||
const promises = listeners.map(
|
||||
async (listener) => await listener(event, data)
|
||||
)
|
||||
return await (Promise.all(promises) as unknown as Promise<void>)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param status -
|
||||
* @returns
|
||||
*/
|
||||
export async function setPlatformStatus (status: Status | Error): Promise<void> {
|
||||
if (status instanceof Error) {
|
||||
return await broadcastEvent(PlatformEvent, unknownError(status))
|
||||
} else {
|
||||
return await broadcastEvent(PlatformEvent, status)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param status -
|
||||
* @param promise -
|
||||
* @returns
|
||||
*/
|
||||
export async function monitor<T> (
|
||||
status: Status,
|
||||
promise: Promise<T>
|
||||
): Promise<T> {
|
||||
void setPlatformStatus(status) // eslint-disable-line no-void
|
||||
try {
|
||||
const result = await promise
|
||||
void setPlatformStatus(OK) // eslint-disable-line no-void
|
||||
return result
|
||||
} catch (err) {
|
||||
void setPlatformStatus(err) // eslint-disable-line no-void
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, IntlString } from './platform'
|
||||
import { Status, Severity, unknownError } from './status'
|
||||
import { _parseId } from './ident'
|
||||
import { setPlatformStatus } from './event'
|
||||
import { IntlMessageFormat } from 'intl-messageformat'
|
||||
|
||||
import platform from './platform'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Loader = (locale: string) => Promise<Record<string, string | Record<string, string>>>
|
||||
|
||||
type Messages = Record<string, IntlString | Record<string, IntlString>>
|
||||
|
||||
const locale = 'en'
|
||||
|
||||
const loaders = new Map<Plugin, Loader>()
|
||||
const translations = new Map<Plugin, Messages | Status>()
|
||||
const cache = new Map<IntlString, IntlMessageFormat | Status>()
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param plugin -
|
||||
* @param loader -
|
||||
*/
|
||||
export function addStringsLoader (plugin: Plugin, loader: Loader): void {
|
||||
loaders.set(plugin, loader)
|
||||
}
|
||||
|
||||
async function loadTranslationsForComponent (plugin: Plugin): Promise<Messages | Status> {
|
||||
const loader = loaders.get(plugin)
|
||||
if (loader === undefined) {
|
||||
const status = new Status(Severity.ERROR, platform.status.NoLoaderForStrings, { plugin })
|
||||
await setPlatformStatus(status)
|
||||
return status
|
||||
}
|
||||
try {
|
||||
return (await loader(locale)) as Record<string, IntlString> | Status
|
||||
} catch (err) {
|
||||
const status = unknownError(err)
|
||||
await setPlatformStatus(status)
|
||||
return status
|
||||
}
|
||||
}
|
||||
|
||||
async function getTranslation (message: IntlString): Promise<IntlString | Status> {
|
||||
try {
|
||||
const id = _parseId(message)
|
||||
let messages = translations.get(id.component)
|
||||
if (messages === undefined) {
|
||||
messages = await loadTranslationsForComponent(id.component)
|
||||
translations.set(id.component, messages)
|
||||
}
|
||||
if (messages instanceof Status) {
|
||||
return messages
|
||||
}
|
||||
return (
|
||||
(id.kind !== undefined
|
||||
? (messages[id.kind] as Record<string, IntlString>)?.[id.name]
|
||||
: (messages[id.name] as IntlString)) ?? message
|
||||
)
|
||||
} catch (err) {
|
||||
const status = unknownError(err)
|
||||
await setPlatformStatus(status)
|
||||
return status
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param message -
|
||||
* @param params -
|
||||
* @returns
|
||||
*/
|
||||
export async function translate<P extends Record<string, any>> (message: IntlString<P>, params: P): Promise<string> {
|
||||
const compiled = cache.get(message)
|
||||
if (compiled !== undefined) {
|
||||
if (compiled instanceof Status) {
|
||||
return message
|
||||
}
|
||||
return compiled.format(params)
|
||||
} else {
|
||||
const translation = await getTranslation(message)
|
||||
if (translation instanceof Status) {
|
||||
cache.set(message, translation)
|
||||
return message
|
||||
}
|
||||
const compiled = new IntlMessageFormat(translation, locale)
|
||||
cache.set(message, compiled)
|
||||
return compiled.format(params)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Id, Plugin } from './platform'
|
||||
import { PlatformError, Status, Severity } from './status'
|
||||
import platform from './platform'
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface _IdInfo {
|
||||
component: Plugin
|
||||
kind: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function _parseId (id: Id): _IdInfo {
|
||||
const path = id.split('.')
|
||||
if (path.length !== 3) {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, platform.status.InvalidId, { id })
|
||||
)
|
||||
}
|
||||
return {
|
||||
component: path[0] as Plugin,
|
||||
kind: path[1],
|
||||
name: path[2]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { addStringsLoader } from './i18n'
|
||||
import { platformId } from './platform'
|
||||
import type { Metadata } from './metadata'
|
||||
|
||||
export * from './platform'
|
||||
export * from './status'
|
||||
export * from './event'
|
||||
export * from './resource'
|
||||
export * from './i18n'
|
||||
export * from './metadata'
|
||||
export * from './rpc'
|
||||
|
||||
addStringsLoader(platformId, async (lang: string) => {
|
||||
switch (lang) {
|
||||
case 'en':
|
||||
return (await import('./lang/en.json'))
|
||||
}
|
||||
throw new Error('unsupported language')
|
||||
})
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type URL = string
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Asset = Metadata<URL>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"status": {
|
||||
"loadingPlugin": "Loading plugin '<b>'{plugin}'</b>'..."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Id } from './platform'
|
||||
|
||||
/**
|
||||
* Platform Metadata Identifier (PMI).
|
||||
*
|
||||
* 'Metadata' is simply any JavaScript object, which is used to configure platform, e.g. IP addresses.
|
||||
* Another example of metadata is an asset URL. The logic behind providing asset URLs as metadata is
|
||||
* we know URL at compile time only and URLs vary depending on deployment options.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type Metadata<T> = Id & { __metadata: T }
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ExtractType<T, X extends Record<string, Metadata<T>>> = {
|
||||
[P in keyof X]: X[P] extends Metadata<infer Z> ? Z : never;
|
||||
}
|
||||
|
||||
const metadata = new Map<Metadata<any>, any>()
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param id -
|
||||
* @returns
|
||||
*/
|
||||
export function getMetadata<T> (id: Metadata<T>): T | undefined {
|
||||
return metadata.get(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param id -
|
||||
* @param value -
|
||||
*/
|
||||
export function setMetadata<T> (id: Metadata<T>, value: T): void {
|
||||
metadata.set(id, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param ids -
|
||||
* @param data -
|
||||
*/
|
||||
export function loadMetadata<T, X extends Record<string, Metadata<T>>> (
|
||||
ids: X,
|
||||
data: ExtractType<T, X>
|
||||
): void {
|
||||
for (const key in ids) {
|
||||
const id = ids[key]
|
||||
const resource = data[key]
|
||||
if (resource === undefined) {
|
||||
throw new Error(`no metadata provided, key: ${key}, id: ${String(id)}`)
|
||||
}
|
||||
metadata.set(id, resource)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/**
|
||||
* Id in format 'plugin.resource-kind.id'
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type Id = string & { __id: true }
|
||||
|
||||
/**
|
||||
* Plugin Id
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type Plugin = string & { __plugin: true }
|
||||
|
||||
/**
|
||||
* Platform Resource Identifier (PRI)
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Almost anything in the Anticrm Platform is a `Resource`. Resources referenced by Platform Resource Identifier (PRI).
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* `core.string.ClassLabel` as Resource<string> // translated string according to current language and i18n settings
|
||||
* `workbench.icon.Add` as Resource<URL> // URL to SVG sprites
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type Resource<T> = Id & { __resource: T }
|
||||
|
||||
/**
|
||||
* Internationalized string Id
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type IntlString<T extends Record<string, any> = {}> = Id & { __intl_string: T }
|
||||
|
||||
/**
|
||||
* Status Code. Also works as i18n string Id for status description.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type StatusCode<T extends Record<string, any> = {}> = IntlString<T>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Namespace = Record<string, Record<string, string>>
|
||||
|
||||
function identify (
|
||||
result: Record<string, any>,
|
||||
prefix: string,
|
||||
namespace: Record<string, any>
|
||||
): Namespace {
|
||||
for (const key in namespace) {
|
||||
const value = namespace[key]
|
||||
if (typeof result[key] === 'string') {
|
||||
throw new Error(`'identify' overwrites '${key}'.`)
|
||||
}
|
||||
const ident = prefix + '.' + key
|
||||
result[key] =
|
||||
typeof value === 'string'
|
||||
? ident
|
||||
: identify(result[key] ?? {}, ident, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines plugin Ids.
|
||||
*
|
||||
* @public
|
||||
* @param plugin -
|
||||
* @param namespace -
|
||||
* @returns
|
||||
*/
|
||||
export function plugin<N extends Namespace> (plugin: Plugin, namespace: N): N {
|
||||
return identify({}, plugin, namespace) as N
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges plugin Ids with Ids provided.
|
||||
*
|
||||
* @public
|
||||
* @param plugin -
|
||||
* @param ns -
|
||||
* @param merge -
|
||||
* @returns
|
||||
*/
|
||||
export function mergeIds<N extends Namespace, M extends Namespace> (
|
||||
plugin: Plugin,
|
||||
ns: N,
|
||||
merge: M
|
||||
): N & M {
|
||||
return identify({ ...ns }, plugin, merge) as N & M
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const platformId = 'platform' as Plugin
|
||||
|
||||
export default plugin(platformId, {
|
||||
status: {
|
||||
OK: '' as StatusCode,
|
||||
UnknownError: '' as StatusCode<{ message: string }>,
|
||||
InvalidId: '' as StatusCode<{ id: string }>,
|
||||
|
||||
LoadingPlugin: '' as StatusCode<{ plugin: string }>,
|
||||
NoLocationForPlugin: '' as StatusCode<{ plugin: Plugin }>,
|
||||
ResourceNotFound: '' as StatusCode<{ resource: Resource<any> }>,
|
||||
|
||||
NoLoaderForStrings: '' as StatusCode<{ plugin: Plugin }>,
|
||||
|
||||
BadRequest: '' as StatusCode
|
||||
// Forbidden: '' as StatusCode,
|
||||
// Unauthorized: '' as StatusCode,
|
||||
// UnknownMethod: '' as StatusCode<{ method: string }>
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Resource, Plugin } from './platform'
|
||||
import { Status, Severity, PlatformError } from './status'
|
||||
import { _parseId } from './ident'
|
||||
import { monitor } from './event'
|
||||
|
||||
import platform from './platform'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Resources = Record<string, Record<string, any>>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface PluginModule<R extends Resources> {
|
||||
default: () => Promise<R>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type PluginLoader<R extends Resources> = () => Promise<PluginModule<R>>
|
||||
|
||||
const locations = new Map<Plugin, PluginLoader<Resources>>()
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param plugin -
|
||||
* @param module -
|
||||
*/
|
||||
export function addLocation<R extends Resources> (
|
||||
plugin: Plugin,
|
||||
module: PluginLoader<R>
|
||||
): void {
|
||||
locations.set(plugin, module)
|
||||
}
|
||||
|
||||
function getLocation (plugin: Plugin): PluginLoader<Resources> {
|
||||
const location = locations.get(plugin)
|
||||
if (location === undefined) {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, platform.status.NoLocationForPlugin, {
|
||||
plugin
|
||||
})
|
||||
)
|
||||
}
|
||||
return location
|
||||
}
|
||||
|
||||
const loading = new Map<Plugin, Promise<Resources>>()
|
||||
|
||||
async function loadPlugin (id: Plugin): Promise<Resources> {
|
||||
console.log('loading plugin ', id)
|
||||
let pluginLoader = loading.get(id)
|
||||
if (pluginLoader === undefined) {
|
||||
const status = new Status(Severity.INFO, platform.status.LoadingPlugin, {
|
||||
plugin: id
|
||||
})
|
||||
pluginLoader = monitor(status, getLocation(id)()).then(
|
||||
async (plugin) => await plugin.default()
|
||||
)
|
||||
loading.set(id, pluginLoader)
|
||||
}
|
||||
return await pluginLoader
|
||||
}
|
||||
|
||||
const cachedResource = new Map<string, any>()
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param resource -
|
||||
* @returns
|
||||
*/
|
||||
export async function getResource<T> (resource: Resource<T>): Promise<T> {
|
||||
const cached = cachedResource.get(resource)
|
||||
if (cached !== undefined) {
|
||||
return cached
|
||||
}
|
||||
const info = _parseId(resource)
|
||||
const resources = loading.get(info.component) ?? loadPlugin(info.component)
|
||||
const value = (await resources)[info.kind]?.[info.name]
|
||||
if (value === undefined) {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, platform.status.ResourceNotFound, { resource })
|
||||
)
|
||||
}
|
||||
cachedResource.set(resource, value)
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import platform from './platform'
|
||||
import { PlatformError, Severity, Status } from './status'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ReqId = string | number
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export class Request<P extends any[], M extends string = string> {
|
||||
id?: ReqId
|
||||
method: M
|
||||
params: P
|
||||
|
||||
constructor (method: M, ...params: P) {
|
||||
this.method = method
|
||||
this.params = params
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Response object define a server response on transaction request.
|
||||
* Also used to inform other clients about operations being performed by server.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface Response<R> {
|
||||
result?: R
|
||||
id?: ReqId
|
||||
error?: Status
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param object -
|
||||
* @returns
|
||||
*/
|
||||
export function serialize (object: Request<any> | Response<any>): string {
|
||||
return JSON.stringify(object)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param response -
|
||||
* @returns
|
||||
*/
|
||||
export function readResponse<D> (response: string): Response<D> {
|
||||
return JSON.parse(response)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param request -
|
||||
* @returns
|
||||
*/
|
||||
export function readRequest<P extends any[]> (request: string): Request<P> {
|
||||
const result: Request<P> = JSON.parse(request)
|
||||
if (typeof result.method !== 'string') {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, platform.status.BadRequest, {})
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param status -
|
||||
* @param id -
|
||||
* @returns
|
||||
*/
|
||||
export function fromStatus (status: Status, id?: ReqId): Response<any> {
|
||||
return { id, error: status }
|
||||
}
|
||||
|
||||
// class DeferredPromise {
|
||||
// promise: Promise<any>
|
||||
// resolve!: <T>(value: T) => void
|
||||
// reject!: (reason?: any) => void
|
||||
// constructor () {
|
||||
// // eslint-disable-next-line promise/param-names
|
||||
// this.promise = new Promise((resolve, reject) => {
|
||||
// this.resolve = resolve
|
||||
// this.reject = reject
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Process requests and handle responses.
|
||||
// * Also allow to handle non identified results passed from other side.
|
||||
// *
|
||||
// * Hold operations in progress and allow to retry them if required.
|
||||
// */
|
||||
// export abstract class RequestProcessor {
|
||||
// private reqIndex: number = 0
|
||||
// private readonly requests = new Map<ReqId, DeferredPromise>()
|
||||
|
||||
// protected abstract send (request: Request<any>): void
|
||||
// protected abstract notify (response: Response<any>): void
|
||||
|
||||
// protected process (response: Response<any>): void {
|
||||
// if (response.id !== undefined) {
|
||||
// const req = this.requests.get(response.id)
|
||||
// if (req !== undefined) {
|
||||
// if (response.error !== undefined) {
|
||||
// req.reject(new PlatformError(response.error))
|
||||
// return
|
||||
// } else {
|
||||
// req.resolve(response.result)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.notify(response)
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Reject all waited pending operations.
|
||||
// *
|
||||
// * This method is intended to be executed by protocol listening parts to
|
||||
// * cancal any pending requests to control UI is not hang.
|
||||
// *
|
||||
// * @param reason - Why request was rejected.
|
||||
// */
|
||||
// protected reject (status: Status): void {
|
||||
// // We need to reply requests in case they are missed.
|
||||
// for (const op of this.requests.entries()) {
|
||||
// op[1].reject(new PlatformError(status))
|
||||
// }
|
||||
// this.requests.clear()
|
||||
// }
|
||||
|
||||
// protected async request (method: string, ...params: any[]): Promise<any> {
|
||||
// const id = ++this.reqIndex
|
||||
// const promise = new DeferredPromise()
|
||||
// this.requests.set(id, promise)
|
||||
|
||||
// // Send request
|
||||
// this.send({ id, method, params })
|
||||
|
||||
// // Waiting to be complete.
|
||||
// return await promise.promise
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/**
|
||||
* Anticrm Platform Foundation Types
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
import type { StatusCode } from './platform'
|
||||
import platform from './platform'
|
||||
|
||||
/**
|
||||
* Status severity
|
||||
* @public
|
||||
*/
|
||||
export enum Severity {
|
||||
OK = 'OK',
|
||||
INFO = 'INFO',
|
||||
WARNING = 'WARNING',
|
||||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of an operation
|
||||
* @public
|
||||
*/
|
||||
export class Status<P = {}> {
|
||||
readonly severity: Severity
|
||||
readonly code: StatusCode<P>
|
||||
readonly params: P
|
||||
|
||||
constructor (severity: Severity, code: StatusCode<P>, params: P) {
|
||||
this.severity = severity
|
||||
this.code = code
|
||||
this.params = params
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error object wrapping `Status`
|
||||
* @public
|
||||
*/
|
||||
export class PlatformError<P extends Record<string, any>> extends Error {
|
||||
readonly status: Status<P>
|
||||
|
||||
constructor (status: Status<P>) {
|
||||
super(`${status.severity}: ${status.code}`)
|
||||
this.status = status
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OK Status
|
||||
* @public
|
||||
*/
|
||||
export const OK = new Status(Severity.OK, platform.status.OK, {})
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param message -
|
||||
* @returns
|
||||
*/
|
||||
export function unknownStatus (message: string): Status<{}> {
|
||||
return new Status(Severity.ERROR, platform.status.UnknownError, { message })
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates unknown error status
|
||||
* @public
|
||||
*/
|
||||
export function unknownError (err: Error): Status {
|
||||
return err instanceof PlatformError ? err.status : unknownStatus(err.message)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
/**
|
||||
* This is the main configuration file for Rush.
|
||||
* For full documentation, please see https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
|
||||
|
||||
/**
|
||||
* (Required) This specifies the version of the Rush engine to be used in this repo.
|
||||
* Rush's "version selector" feature ensures that the globally installed tool will
|
||||
* behave like this release, regardless of which version is installed globally.
|
||||
*
|
||||
* The common/scripts/install-run-rush.js automation script also uses this version.
|
||||
*
|
||||
* NOTE: If you upgrade to a new major version of Rush, you should replace the "v5"
|
||||
* path segment in the "$schema" field for all your Rush config files. This will ensure
|
||||
* correct error-underlining and tab-completion for editors such as VS Code.
|
||||
*/
|
||||
"rushVersion": "5.50.0",
|
||||
|
||||
/**
|
||||
* The next field selects which package manager should be installed and determines its version.
|
||||
* Rush installs its own local copy of the package manager to ensure that your build process
|
||||
* is fully isolated from whatever tools are present in the local environment.
|
||||
*
|
||||
* Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation
|
||||
* for details about these alternatives.
|
||||
*/
|
||||
"pnpmVersion": "6.11.5",
|
||||
|
||||
// "npmVersion": "4.5.0",
|
||||
// "yarnVersion": "1.9.4",
|
||||
|
||||
/**
|
||||
* Options that are only used when the PNPM package manager is selected
|
||||
*/
|
||||
"pnpmOptions": {
|
||||
/**
|
||||
* Specifies the location of the PNPM store. There are two possible values:
|
||||
*
|
||||
* - "local" - use the "pnpm-store" folder in the current configured temp folder:
|
||||
* "common/temp/pnpm-store" by default.
|
||||
* - "global" - use PNPM's global store, which has the benefit of being shared
|
||||
* across multiple repo folders, but the disadvantage of less isolation for builds
|
||||
* (e.g. bugs or incompatibilities when two repos use different releases of PNPM)
|
||||
*
|
||||
* RUSH_PNPM_STORE_PATH will override the directory that will be used as the store
|
||||
*
|
||||
* In all cases, the store path will be overridden by the environment variable RUSH_PNPM_STORE_PATH.
|
||||
*
|
||||
* The default value is "local".
|
||||
*/
|
||||
// "pnpmStore": "local",
|
||||
|
||||
/**
|
||||
* If true, then Rush will add the "--strict-peer-dependencies" option when invoking PNPM.
|
||||
* This causes "rush install" to fail if there are unsatisfied peer dependencies, which is
|
||||
* an invalid state that can cause build failures or incompatible dependency versions.
|
||||
* (For historical reasons, JavaScript package managers generally do not treat this invalid
|
||||
* state as an error.)
|
||||
*
|
||||
* The default value is false to avoid legacy compatibility issues.
|
||||
* It is strongly recommended to set strictPeerDependencies=true.
|
||||
*/
|
||||
// "strictPeerDependencies": true,
|
||||
|
||||
/**
|
||||
* Configures the strategy used to select versions during installation.
|
||||
*
|
||||
* This feature requires PNPM version 3.1 or newer. It corresponds to the "--resolution-strategy" command-line
|
||||
* option for PNPM. Possible values are "fast" and "fewer-dependencies". PNPM's default is "fast", but this may
|
||||
* be incompatible with certain packages, for example the "@types" packages from DefinitelyTyped. Rush's default
|
||||
* is "fewer-dependencies", which causes PNPM to avoid installing a newer version if an already installed version
|
||||
* can be reused; this is more similar to NPM's algorithm.
|
||||
*
|
||||
* After modifying this field, it's recommended to run "rush update --full" so that the package manager
|
||||
* will recalculate all version selections.
|
||||
*/
|
||||
// "resolutionStrategy": "fast",
|
||||
|
||||
/**
|
||||
* If true, then `rush install` will report an error if manual modifications
|
||||
* were made to the PNPM shrinkwrap file without running "rush update" afterwards.
|
||||
*
|
||||
* This feature protects against accidental inconsistencies that may be introduced
|
||||
* if the PNPM shrinkwrap file ("pnpm-lock.yaml") is manually edited. When this
|
||||
* feature is enabled, "rush update" will append a hash to the file as a YAML comment,
|
||||
* and then "rush update" and "rush install" will validate the hash. Note that this does not prohibit
|
||||
* manual modifications, but merely requires "rush update" be run
|
||||
* afterwards, ensuring that PNPM can report or repair any potential inconsistencies.
|
||||
*
|
||||
* To temporarily disable this validation when invoking "rush install", use the
|
||||
* "--bypass-policy" command-line parameter.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
// "preventManualShrinkwrapChanges": true,
|
||||
|
||||
/**
|
||||
* If true, then `rush install` will use the PNPM workspaces feature to perform the
|
||||
* install.
|
||||
*
|
||||
* This feature uses PNPM to perform the entire monorepo install. When using workspaces, Rush will
|
||||
* generate a "pnpm-workspace.yaml" file referencing all local projects to install. Rush will
|
||||
* also generate a "pnpmfile.js" which is used to provide preferred versions support. When install
|
||||
* is run, this pnpmfile will be used to replace dependency version ranges with a smaller subset
|
||||
* of the original range. If the preferred version is not fully a subset of the original version
|
||||
* range, it will be left as-is. After this, the pnpmfile.js provided in the repository (if one
|
||||
* exists) will be called to further modify package dependencies.
|
||||
*
|
||||
* This option is experimental. The default value is false.
|
||||
*/
|
||||
// "useWorkspaces": true
|
||||
},
|
||||
|
||||
/**
|
||||
* Older releases of the Node.js engine may be missing features required by your system.
|
||||
* Other releases may have bugs. In particular, the "latest" version will not be a
|
||||
* Long Term Support (LTS) version and is likely to have regressions.
|
||||
*
|
||||
* Specify a SemVer range to ensure developers use a Node.js version that is appropriate
|
||||
* for your repo.
|
||||
*
|
||||
* LTS schedule: https://nodejs.org/en/about/releases/
|
||||
* LTS versions: https://nodejs.org/en/download/releases/
|
||||
*/
|
||||
"nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0",
|
||||
|
||||
/**
|
||||
* Odd-numbered major versions of Node.js are experimental. Even-numbered releases
|
||||
* spend six months in a stabilization period before the first Long Term Support (LTS) version.
|
||||
* For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended
|
||||
* for production usage because they frequently have bugs. They may cause Rush itself
|
||||
* to malfunction.
|
||||
*
|
||||
* Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing
|
||||
* pre-LTS versions in preparation for supporting the first LTS version, you can use this setting
|
||||
* to disable Rush's warning.
|
||||
*/
|
||||
// "suppressNodeLtsWarning": false,
|
||||
|
||||
/**
|
||||
* If you would like the version specifiers for your dependencies to be consistent, then
|
||||
* uncomment this line. This is effectively similar to running "rush check" before any
|
||||
* of the following commands:
|
||||
*
|
||||
* rush install, rush update, rush link, rush version, rush publish
|
||||
*
|
||||
* In some cases you may want this turned on, but need to allow certain packages to use a different
|
||||
* version. In those cases, you will need to add an entry to the "allowedAlternativeVersions"
|
||||
* section of the common-versions.json.
|
||||
*/
|
||||
// "ensureConsistentVersions": true,
|
||||
|
||||
/**
|
||||
* Large monorepos can become intimidating for newcomers if project folder paths don't follow
|
||||
* a consistent and recognizable pattern. When the system allows nested folder trees,
|
||||
* we've found that teams will often use subfolders to create islands that isolate
|
||||
* their work from others ("shipping the org"). This hinders collaboration and code sharing.
|
||||
*
|
||||
* The Rush developers recommend a "category folder" model, where buildable project folders
|
||||
* must always be exactly two levels below the repo root. The parent folder acts as the category.
|
||||
* This provides a basic facility for grouping related projects (e.g. "apps", "libraries",
|
||||
* "tools", "prototypes") while still encouraging teams to organize their projects into
|
||||
* a unified taxonomy. Limiting to 2 levels seems very restrictive at first, but if you have
|
||||
* 20 categories and 20 projects in each category, this scheme can easily accommodate hundreds
|
||||
* of projects. In practice, you will find that the folder hierarchy needs to be rebalanced
|
||||
* occasionally, but if that's painful, it's a warning sign that your development style may
|
||||
* discourage refactoring. Reorganizing the categories should be an enlightening discussion
|
||||
* that brings people together, and maybe also identifies poor coding practices (e.g. file
|
||||
* references that reach into other project's folders without using Node.js module resolution).
|
||||
*
|
||||
* The defaults are projectFolderMinDepth=1 and projectFolderMaxDepth=2.
|
||||
*
|
||||
* To remove these restrictions, you could set projectFolderMinDepth=1
|
||||
* and set projectFolderMaxDepth to a large number.
|
||||
*/
|
||||
// "projectFolderMinDepth": 2,
|
||||
// "projectFolderMaxDepth": 2,
|
||||
|
||||
/**
|
||||
* Today the npmjs.com registry enforces fairly strict naming rules for packages, but in the early
|
||||
* days there was no standard and hardly any enforcement. A few large legacy projects are still using
|
||||
* nonstandard package names, and private registries sometimes allow it. Set "allowMostlyStandardPackageNames"
|
||||
* to true to relax Rush's enforcement of package names. This allows upper case letters and in the future may
|
||||
* relax other rules, however we want to minimize these exceptions. Many popular tools use certain punctuation
|
||||
* characters as delimiters, based on the assumption that they will never appear in a package name; thus if we relax
|
||||
* the rules too much it is likely to cause very confusing malfunctions.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
// "allowMostlyStandardPackageNames": true,
|
||||
|
||||
/**
|
||||
* This feature helps you to review and approve new packages before they are introduced
|
||||
* to your monorepo. For example, you may be concerned about licensing, code quality,
|
||||
* performance, or simply accumulating too many libraries with overlapping functionality.
|
||||
* The approvals are tracked in two config files "browser-approved-packages.json"
|
||||
* and "nonbrowser-approved-packages.json". See the Rush documentation for details.
|
||||
*/
|
||||
// "approvedPackagesPolicy": {
|
||||
// /**
|
||||
// * The review categories allow you to say for example "This library is approved for usage
|
||||
// * in prototypes, but not in production code."
|
||||
// *
|
||||
// * Each project can be associated with one review category, by assigning the "reviewCategory" field
|
||||
// * in the "projects" section of rush.json. The approval is then recorded in the files
|
||||
// * "common/config/rush/browser-approved-packages.json" and "nonbrowser-approved-packages.json"
|
||||
// * which are automatically generated during "rush update".
|
||||
// *
|
||||
// * Designate categories with whatever granularity is appropriate for your review process,
|
||||
// * or you could just have a single category called "default".
|
||||
// */
|
||||
// "reviewCategories": [
|
||||
// // Some example categories:
|
||||
// "production", // projects that ship to production
|
||||
// "tools", // non-shipping projects that are part of the developer toolchain
|
||||
// "prototypes" // experiments that should mostly be ignored by the review process
|
||||
// ],
|
||||
//
|
||||
// /**
|
||||
// * A list of NPM package scopes that will be excluded from review.
|
||||
// * We recommend to exclude TypeScript typings (the "@types" scope), because
|
||||
// * if the underlying package was already approved, this would imply that the typings
|
||||
// * are also approved.
|
||||
// */
|
||||
// // "ignoredNpmScopes": ["@types"]
|
||||
// },
|
||||
|
||||
/**
|
||||
* If you use Git as your version control system, this section has some additional
|
||||
* optional features you can use.
|
||||
*/
|
||||
"gitPolicy": {
|
||||
/**
|
||||
* Work at a big company? Tired of finding Git commits at work with unprofessional Git
|
||||
* emails such as "beer-lover@my-college.edu"? Rush can validate people's Git email address
|
||||
* before they get started.
|
||||
*
|
||||
* Define a list of regular expressions describing allowable e-mail patterns for Git commits.
|
||||
* They are case-insensitive anchored JavaScript RegExps. Example: ".*@example\.com"
|
||||
*
|
||||
* IMPORTANT: Because these are regular expressions encoded as JSON string literals,
|
||||
* RegExp escapes need two backslashes, and ordinary periods should be "\\.".
|
||||
*/
|
||||
// "allowedEmailRegExps": [
|
||||
// "[^@]+@users\\.noreply\\.github\\.com",
|
||||
// "travis@example\\.org"
|
||||
// ],
|
||||
|
||||
/**
|
||||
* When Rush reports that the address is malformed, the notice can include an example
|
||||
* of a recommended email. Make sure it conforms to one of the allowedEmailRegExps
|
||||
* expressions.
|
||||
*/
|
||||
// "sampleEmail": "mrexample@users.noreply.github.com",
|
||||
|
||||
/**
|
||||
* The commit message to use when committing changes during 'rush publish'.
|
||||
*
|
||||
* For example, if you want to prevent these commits from triggering a CI build,
|
||||
* you might configure your system's trigger to look for a special string such as "[skip-ci]"
|
||||
* in the commit message, and then customize Rush's message to contain that string.
|
||||
*/
|
||||
// "versionBumpCommitMessage": "Applying package updates. [skip-ci]",
|
||||
|
||||
/**
|
||||
* The commit message to use when committing changes during 'rush version'.
|
||||
*
|
||||
* For example, if you want to prevent these commits from triggering a CI build,
|
||||
* you might configure your system's trigger to look for a special string such as "[skip-ci]"
|
||||
* in the commit message, and then customize Rush's message to contain that string.
|
||||
*/
|
||||
// "changeLogUpdateCommitMessage": "Deleting change files and updating change logs for package updates. [skip-ci]"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
/**
|
||||
* The URL of this Git repository, used by "rush change" to determine the base branch for your PR.
|
||||
*
|
||||
* The "rush change" command needs to determine which files are affected by your PR diff.
|
||||
* If you merged or cherry-picked commits from the master branch into your PR branch, those commits
|
||||
* should be excluded from this diff (since they belong to some other PR). In order to do that,
|
||||
* Rush needs to know where to find the base branch for your PR. This information cannot be
|
||||
* determined from Git alone, since the "pull request" feature is not a Git concept. Ideally
|
||||
* Rush would use a vendor-specific protocol to query the information from GitHub, Azure DevOps, etc.
|
||||
* But to keep things simple, "rush change" simply assumes that your PR is against the "master" branch
|
||||
* of the Git remote indicated by the repository.url setting in rush.json. If you are working in
|
||||
* a GitHub "fork" of the real repo, this setting will be different from the repository URL of your
|
||||
* your PR branch, and in this situation "rush change" will also automatically invoke "git fetch"
|
||||
* to retrieve the latest activity for the remote master branch.
|
||||
*/
|
||||
// "url": "https://github.com/microsoft/rush-example",
|
||||
|
||||
/**
|
||||
* The default branch name. This tells "rush change" which remote branch to compare against.
|
||||
* The default value is "master"
|
||||
*/
|
||||
// "defaultBranch": "master",
|
||||
|
||||
/**
|
||||
* The default remote. This tells "rush change" which remote to compare against if the remote URL is
|
||||
* not set or if a remote matching the provided remote URL is not found.
|
||||
*/
|
||||
// "defaultRemote": "origin"
|
||||
},
|
||||
|
||||
/**
|
||||
* Event hooks are customized script actions that Rush executes when specific events occur
|
||||
*/
|
||||
"eventHooks": {
|
||||
/**
|
||||
* The list of shell commands to run before the Rush installation starts
|
||||
*/
|
||||
"preRushInstall": [
|
||||
// "common/scripts/pre-rush-install.js"
|
||||
],
|
||||
|
||||
/**
|
||||
* The list of shell commands to run after the Rush installation finishes
|
||||
*/
|
||||
"postRushInstall": [],
|
||||
|
||||
/**
|
||||
* The list of shell commands to run before the Rush build command starts
|
||||
*/
|
||||
"preRushBuild": [],
|
||||
|
||||
/**
|
||||
* The list of shell commands to run after the Rush build command finishes
|
||||
*/
|
||||
"postRushBuild": []
|
||||
},
|
||||
|
||||
/**
|
||||
* Installation variants allow you to maintain a parallel set of configuration files that can be
|
||||
* used to build the entire monorepo with an alternate set of dependencies. For example, suppose
|
||||
* you upgrade all your projects to use a new release of an important framework, but during a transition period
|
||||
* you intend to maintain compatibility with the old release. In this situation, you probably want your
|
||||
* CI validation to build the entire repo twice: once with the old release, and once with the new release.
|
||||
*
|
||||
* Rush "installation variants" correspond to sets of config files located under this folder:
|
||||
*
|
||||
* common/config/rush/variants/<variant_name>
|
||||
*
|
||||
* The variant folder can contain an alternate common-versions.json file. Its "preferredVersions" field can be used
|
||||
* to select older versions of dependencies (within a loose SemVer range specified in your package.json files).
|
||||
* To install a variant, run "rush install --variant <variant_name>".
|
||||
*
|
||||
* For more details and instructions, see this article: https://rushjs.io/pages/advanced/installation_variants/
|
||||
*/
|
||||
"variants": [
|
||||
// {
|
||||
// /**
|
||||
// * The folder name for this variant.
|
||||
// */
|
||||
// "variantName": "old-sdk",
|
||||
//
|
||||
// /**
|
||||
// * An informative description
|
||||
// */
|
||||
// "description": "Build this repo using the previous release of the SDK"
|
||||
// }
|
||||
],
|
||||
|
||||
/**
|
||||
* Rush can collect anonymous telemetry about everyday developer activity such as
|
||||
* success/failure of installs, builds, and other operations. You can use this to identify
|
||||
* problems with your toolchain or Rush itself. THIS TELEMETRY IS NOT SHARED WITH MICROSOFT.
|
||||
* It is written into JSON files in the common/temp folder. It's up to you to write scripts
|
||||
* that read these JSON files and do something with them. These scripts are typically registered
|
||||
* in the "eventHooks" section.
|
||||
*/
|
||||
// "telemetryEnabled": false,
|
||||
|
||||
/**
|
||||
* Allows creation of hotfix changes. This feature is experimental so it is disabled by default.
|
||||
* If this is set, 'rush change' only allows a 'hotfix' change type to be specified. This change type
|
||||
* will be used when publishing subsequent changes from the monorepo.
|
||||
*/
|
||||
// "hotfixChangeEnabled": false,
|
||||
|
||||
/**
|
||||
* (Required) This is the inventory of projects to be managed by Rush.
|
||||
*
|
||||
* Rush does not automatically scan for projects using wildcards, for a few reasons:
|
||||
* 1. Depth-first scans are expensive, particularly when tools need to repeatedly collect the list.
|
||||
* 2. On a caching CI machine, scans can accidentally pick up files left behind from a previous build.
|
||||
* 3. It's useful to have a centralized inventory of all projects and their important metadata.
|
||||
*/
|
||||
"projects": [
|
||||
// {
|
||||
// /**
|
||||
// * The NPM package name of the project (must match package.json)
|
||||
// */
|
||||
// "packageName": "my-app",
|
||||
//
|
||||
// /**
|
||||
// * The path to the project folder, relative to the rush.json config file.
|
||||
// */
|
||||
// "projectFolder": "apps/my-app",
|
||||
//
|
||||
// /**
|
||||
// * An optional category for usage in the "browser-approved-packages.json"
|
||||
// * and "nonbrowser-approved-packages.json" files. The value must be one of the
|
||||
// * strings from the "reviewCategories" defined above.
|
||||
// */
|
||||
// "reviewCategory": "production",
|
||||
//
|
||||
// /**
|
||||
// * A list of local projects that appear as devDependencies for this project, but cannot be
|
||||
// * locally linked because it would create a cyclic dependency; instead, the last published
|
||||
// * version will be installed in the Common folder.
|
||||
// */
|
||||
// "cyclicDependencyProjects": [
|
||||
// // "my-toolchain"
|
||||
// ],
|
||||
//
|
||||
// /**
|
||||
// * If true, then this project will be ignored by the "rush check" command.
|
||||
// * The default value is false.
|
||||
// */
|
||||
// // "skipRushCheck": false,
|
||||
//
|
||||
// /**
|
||||
// * A flag indicating that changes to this project will be published to npm, which affects
|
||||
// * the Rush change and publish workflows. The default value is false.
|
||||
// * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both.
|
||||
// */
|
||||
// // "shouldPublish": false,
|
||||
//
|
||||
// /**
|
||||
// * Facilitates postprocessing of a project's files prior to publishing.
|
||||
// *
|
||||
// * If specified, the "publishFolder" is the relative path to a subfolder of the project folder.
|
||||
// * The "rush publish" command will publish the subfolder instead of the project folder. The subfolder
|
||||
// * must contain its own package.json file, which is typically a build output.
|
||||
// */
|
||||
// // "publishFolder": "temp/publish",
|
||||
//
|
||||
// /**
|
||||
// * An optional version policy associated with the project. Version policies are defined
|
||||
// * in "version-policies.json" file. See the "rush publish" documentation for more info.
|
||||
// * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both.
|
||||
// */
|
||||
// // "versionPolicyName": ""
|
||||
// },
|
||||
//
|
||||
{
|
||||
"packageName": "@anticrm/platform",
|
||||
"projectFolder": "packages/platform",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/platform-rig",
|
||||
"projectFolder": "packages/platform-rig",
|
||||
"shouldPublish": true
|
||||
}
|
||||
//
|
||||
// {
|
||||
// "packageName": "my-toolchain",
|
||||
// "projectFolder": "tools/my-toolchain",
|
||||
// "reviewCategory": "tools"
|
||||
// }
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user