diff --git a/build.sh b/build.sh index 5c5300dc08..9e8e14a713 100644 --- a/build.sh +++ b/build.sh @@ -7,6 +7,11 @@ cd server npm run generate cd .. +echo "running \`npm run build\` for \`config\`" +cd config +npm run build +cd .. + echo "running \`npm run build\` for \`common\`" cd common npm run build diff --git a/client/package-lock.json b/client/package-lock.json index 6929ed2154..33243d4f13 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -42,6 +42,7 @@ "convict-format-with-validator": "^6.2.0", "cookie": "^0.4.1", "coral-common": "../common/dist", + "coral-config": "../config/dist", "cors": "^2.8.5", "cron": "^1.8.2", "csv-stringify": "^5.3.6", @@ -356,6 +357,7 @@ } }, "../common/dist": {}, + "../config/dist": {}, "node_modules/@ampproject/toolbox-cache-url": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/@ampproject/toolbox-cache-url/-/toolbox-cache-url-2.9.0.tgz", @@ -15288,6 +15290,10 @@ "resolved": "../common/dist", "link": true }, + "node_modules/coral-config": { + "resolved": "../config/dist", + "link": true + }, "node_modules/core-js": { "version": "3.6.4", "hasInstallScript": true, @@ -60709,6 +60715,9 @@ "coral-common": { "version": "file:../common/dist" }, + "coral-config": { + "version": "file:../config/dist" + }, "core-js": { "version": "3.6.4" }, diff --git a/client/package.json b/client/package.json index f1d7906fd3..5c172d4167 100644 --- a/client/package.json +++ b/client/package.json @@ -62,6 +62,7 @@ "license": "Apache-2.0", "dependencies": { "coral-common": "../common/dist", + "coral-config": "../config/dist", "@ampproject/toolbox-cache-url": "^2.9.0", "@coralproject/bunyan-prettystream": "^0.1.4", "@fluent/bundle": "^0.15.1", @@ -450,7 +451,7 @@ "bundlesize": [ { "path": "./dist/static/assets/js/embed.js", - "maxSize": "30 kB", + "maxSize": "30.05 kB", "maxSizeOld": "17 kB" }, { diff --git a/client/src/core/client/embed/Coral.ts b/client/src/core/client/embed/Coral.ts index 712ae276fb..5647c4dda5 100644 --- a/client/src/core/client/embed/Coral.ts +++ b/client/src/core/client/embed/Coral.ts @@ -1,6 +1,6 @@ import { EventEmitter2 } from "eventemitter2"; +import { parse } from "querystringify"; -import { parseQuery } from "coral-common/common/lib/utils"; import { getCurrentScriptOrigin } from "coral-framework/helpers"; import resolveStoryURL from "coral-framework/helpers/resolveStoryURL"; @@ -43,7 +43,7 @@ export interface Config { export function createStreamEmbed(config: Config): StreamEmbed { // Parse query params - const query = parseQuery(location.search); + const query = parse(location.search); const embedEventEmitter = new EventEmitter2({ wildcard: true, delimiter: ".", diff --git a/client/src/core/client/embed/StreamEmbed.ts b/client/src/core/client/embed/StreamEmbed.ts index e55088a229..3beeef82c5 100644 --- a/client/src/core/client/embed/StreamEmbed.ts +++ b/client/src/core/client/embed/StreamEmbed.ts @@ -1,5 +1,4 @@ -import { EmbedBootstrapConfig } from "coral-common/common/lib/config"; -import ensureEndSlash from "coral-common/common/lib/utils/ensureEndSlash"; +import { EmbedBootstrapConfig } from "coral-config/config"; import { getBrowserInfo } from "coral-framework/lib/browserInfo"; import { EventEmitter2 } from "eventemitter2"; @@ -31,6 +30,12 @@ const LOAD_BOOTSTRAP_RETRY_DELAY = 2000; const LOAD_BOOTSTRAP_RETRY_DELAY_MULTIPLIER = process.env.NODE_ENV === "production" ? 2000 : 0; +const END_SLASH_REGEX = /\/$/; + +export default function ensureEndSlash(p: string) { + return END_SLASH_REGEX.exec(p) ? p : `${p}/`; +} + export interface StreamEmbedConfig { storyID?: string; storyURL?: string; @@ -51,6 +56,7 @@ export interface StreamEmbedConfig { graphQLSubscriptionURI?: string; customScrollContainer?: HTMLElement; } + export class StreamEmbed { /** * Every interval rounded to this value in ms will be passed when loading diff --git a/client/src/core/client/embed/decorators/withEventEmitter.ts b/client/src/core/client/embed/decorators/withEventEmitter.ts index a6303e749d..699e670c5a 100644 --- a/client/src/core/client/embed/decorators/withEventEmitter.ts +++ b/client/src/core/client/embed/decorators/withEventEmitter.ts @@ -1,6 +1,9 @@ import { EventEmitter2 } from "eventemitter2"; -import startsWith from "coral-common/common/lib/utils/startsWith"; +/** A substitute for string.startsWith */ +function startsWith(str: string, search: string, pos?: number) { + return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; +} const withEventEmitter = ( streamEventEmitter: EventEmitter2, diff --git a/client/src/core/client/embed/decorators/withSetCommentID.ts b/client/src/core/client/embed/decorators/withSetCommentID.ts index cbaa376ca2..2e3bcb8e1e 100644 --- a/client/src/core/client/embed/decorators/withSetCommentID.ts +++ b/client/src/core/client/embed/decorators/withSetCommentID.ts @@ -1,12 +1,37 @@ import { EventEmitter2 } from "eventemitter2"; +import qs, { parse } from "querystringify"; -import { parseQuery, stringifyQuery } from "coral-common/common/lib/utils"; import { buildURL } from "coral-framework/utils"; import { CleanupCallback } from "./types"; +/** + * From the `querystringify` project: + * This transforms a given object in to a query string. + * By default we return the query string without a ? prefix. + * If you want to prefix it by default simply supply true as second argument. + * If it should be prefixed by something else simply supply a string with the + * prefix value as second argument. + * + * In addition keys that have an undefined value are removed from the query. + */ +function stringifyQuery( + obj: Record, + prefix?: string | boolean +): string { + const copy: Record = {}; + Object.keys(obj).forEach((key) => { + if (obj[key] === undefined) { + return; + } + + copy[key] = obj[key]; + }); + return qs.stringify(copy, prefix); +} + function getCurrentCommentID() { - return parseQuery(location.search).commentID; + return parse(location.search).commentID; } const withSetCommentID = ( @@ -15,7 +40,7 @@ const withSetCommentID = ( // Add the permalink comment id to the query. streamEventEmitter.on("stream.setCommentID", (id: string) => { const search = stringifyQuery({ - ...parseQuery(location.search), + ...parse(location.search), commentID: id || undefined, }); diff --git a/common/lib/config.ts b/common/lib/config.ts index 8b8d74c011..d368bf4e23 100644 --- a/common/lib/config.ts +++ b/common/lib/config.ts @@ -1,91 +1,14 @@ -import { LanguageCode } from "./helpers"; +import { + EmbedBootstrapConfig as EBC, + ReporterConfig as RC, + SentryReporterConfig as SRC, + StaticConfig as SC, +} from "coral-config/config"; -/** - * SentryReporterConfig is the ReporterConfig for the Sentry service. - */ -export interface SentryReporterConfig { - name: "sentry"; +export interface SentryReporterConfig extends SRC {} - /** - * dsn is the string representing this particular integration. - */ - dsn: string; -} +export type ReporterConfig = RC; -export type ReporterConfig = SentryReporterConfig; +export interface StaticConfig extends SC {} -/** - * StaticConfig is the configuration provided to the client javascript via a - * JSON blob on the HTML of the embedding page. - */ -export interface StaticConfig { - /** - * staticURI is prepended to the static url's that are included on the static - * pages. - */ - staticURI: string; - - /** - * tenantDomain is the domain of the currently requested tenant. - */ - tenantDomain?: string; - - /** - * reporter stores the reporter configuration for the current reporter - * available. - */ - reporter?: ReporterConfig; - - /** - * graphQLSubscriptionURI is the endpoint that should be used when trying to - * execute subscription GraphQL requests. If an empty string, the default - * should be used that's based on the iFrame location. - */ - graphQLSubscriptionURI: string; - - /** - * featureFlags are all the feature flags currently enabled on the tenant. - */ - featureFlags: string[]; - - /** - * flattenReplies is whether or not flattenReplies is enabled on the tenant. - */ - flattenReplies: boolean; - - /** - * forceAdminLocalAuth is whether local authentication is always available - * for this Coral deployment. This is useful for ensuring that Coral service - * teams can access the admin with their Coral local authentication. - */ - forceAdminLocalAuth: boolean; - - /** - * archivingEnabled will be true when the deployment has set a valid MongoDB - * URI for MONGODB_ARCHIVE_URI. - */ - archivingEnabled: boolean; - - /** - * autoArchiveOlderThanMs is the time in milliseconds that a story will - * be kept before being auto-archived. - */ - autoArchiveOlderThanMs: number; -} - -export interface EmbedBootstrapConfig { - locale: LanguageCode; - assets: { - js: { - src: string; - }[]; - css: { - src: string; - }[]; - }; - customFontsCSSURL: string | undefined; - customCSSURL: string | undefined; - defaultFontsCSSURL: string | undefined; - disableDefaultFonts: boolean; - staticConfig: StaticConfig; -} +export interface EmbedBootstrapConfig extends EBC {} diff --git a/common/lib/helpers/i18n/locales.ts b/common/lib/helpers/i18n/locales.ts index ac78656d53..383be8a2b1 100644 --- a/common/lib/helpers/i18n/locales.ts +++ b/common/lib/helpers/i18n/locales.ts @@ -1,31 +1,10 @@ +import { LanguageCode as LC } from "coral-config/i18n/locales"; + /** * LanguageCode is the type represented by the internally identifiable types for * the different languages that can be supported in the BCP 47 format. */ -export type LanguageCode = - | "af-ZA" - | "ar-AE" - | "en-US" - | "pt-BR" - | "es" - | "de" - | "tr-TR" - | "hu" - | "id-ID" - | "it-IT" - | "ja-JP" - | "de-CH" - | "nl-NL" - | "da" - | "fr-FR" - | "ro" - | "fi-FI" - | "sv" - | "sk-SK" - | "pl" - | "ru" - | "nb-NO" - | "zh-CN"; +export type LanguageCode = LC; /** * LOCALES_MAP contains a map of language codes associated with their diff --git a/common/package-lock.json b/common/package-lock.json index 89b32c4c2c..1924bda431 100644 --- a/common/package-lock.json +++ b/common/package-lock.json @@ -9,6 +9,7 @@ "version": "8.3.1", "license": "ISC", "dependencies": { + "coral-config": "../config/dist", "dompurify": "^2.0.17", "he": "^1.2.0", "jest": "^26.4.2", @@ -41,6 +42,7 @@ "@types/url-regex-safe": "^1.0.0" } }, + "../config/dist": {}, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -2050,6 +2052,10 @@ "node": ">=0.10.0" } }, + "node_modules/coral-config": { + "resolved": "../config/dist", + "link": true + }, "node_modules/core-js-pure": { "version": "3.31.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.1.tgz", @@ -8697,6 +8703,9 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, + "coral-config": { + "version": "file:../config/dist" + }, "core-js-pure": { "version": "3.31.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.1.tgz", diff --git a/common/package.json b/common/package.json index 07ad2d8fc4..73cda7aa06 100644 --- a/common/package.json +++ b/common/package.json @@ -27,6 +27,7 @@ "@types/url-regex-safe": "^1.0.0" }, "dependencies": { + "coral-config": "../config/dist", "dompurify": "^2.0.17", "he": "^1.2.0", "jest": "^26.4.2", diff --git a/config/.eslintignore b/config/.eslintignore new file mode 100644 index 0000000000..cbd0d05e38 --- /dev/null +++ b/config/.eslintignore @@ -0,0 +1,5 @@ +*.d.ts +*.graphql.ts +**/__generated__/** +docs/build +docs/.docusaurus \ No newline at end of file diff --git a/config/.eslintrc.js b/config/.eslintrc.js new file mode 100644 index 0000000000..b2acd8fcca --- /dev/null +++ b/config/.eslintrc.js @@ -0,0 +1,279 @@ +const typescriptEslintRecommended = + require("@typescript-eslint/eslint-plugin/dist/configs/eslint-recommended") + .overrides[0]; +const typescriptRecommended = require("@typescript-eslint/eslint-plugin/dist/configs/recommended.js"); +const typescriptRecommendedTypeChecking = require("@typescript-eslint/eslint-plugin/dist/configs/recommended-requiring-type-checking.js"); +const typescriptEslintPrettier = require("eslint-config-prettier/@typescript-eslint"); +const react = require("eslint-plugin-react").configs.recommended; +const jsxA11y = require("eslint-plugin-jsx-a11y").configs.recommended; +const reactPrettier = require("eslint-config-prettier/react"); + +const typescriptOverrides = { + files: ["*.ts", "*.tsx"], + parser: "@typescript-eslint/parser", + parserOptions: { + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, + plugins: [ + "@typescript-eslint", + "@typescript-eslint/tslint", + "react", + "jsx-a11y", + "react-hooks", + ], + settings: { + react: { + version: "detect", + }, + }, + rules: Object.assign( + typescriptEslintRecommended.rules, + typescriptRecommended.rules, + typescriptEslintPrettier.rules, + react.rules, + jsxA11y.rules, + reactPrettier.rules, + { + // TODO: (cvle) make this an error + "react-hooks/exhaustive-deps": "warn", + "@typescript-eslint/adjacent-overload-signatures": "error", + // TODO: (cvle) change `readonly` param to `array-simple` when upgraded typescript. + "@typescript-eslint/array-type": [ + "error", + { default: "array-simple", readonly: "generic" }, + ], + "@typescript-eslint/ban-types": [ + "error", + { + types: { + "{}": false, + object: false, + extendDefaults: true, + }, + }, + ], + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + overrides: { + constructors: "off", + }, + }, + ], + "@typescript-eslint/indent": "off", + "@typescript-eslint/member-delimiter-style": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { args: "none", ignoreRestSiblings: true }, + ], + "@typescript-eslint/no-use-before-define": "off", // TODO: (cvle) Should be on? + "@typescript-eslint/no-use-before-declare": "off", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/triple-slash-reference": "error", + "@typescript-eslint/type-annotation-spacing": "off", + "@typescript-eslint/unified-signatures": "error", + // (cvle) disabled, because the way we use labels in our code cause to many + // false positives. + "jsx-a11y/label-has-associated-control": "off", + "react/display-name": "error", + "react/prop-types": "off", + "react/no-unescaped-entities": "off", + "no-empty-function": "off", + // (tessalt) disabled because video elements are only used to display gifs, which have no audio + "jsx-a11y/media-has-caption": "off", + } + ), +}; + +const jestTypeCheckingOverrides = { + files: ["test/**/*.ts", "test/**/*.tsx"], + rules: { + "@typescript-eslint/no-floating-promises": "off", + }, +}; + +const typescriptTypeCheckingOverrides = { + files: ["*.ts", "*.tsx"], + parserOptions: { + project: [ + "./tsconfig.json", + "./src/tsconfig.json", + "./src/core/client/tsconfig.json", + ], + // TODO: (cvle) this is a workaround, see: https://github.com/typescript-eslint/typescript-eslint/issues/1091. + createDefaultProgram: true, + }, + rules: Object.assign(typescriptRecommendedTypeChecking.rules, { + "@typescript-eslint/tslint/config": [ + "error", + { + rules: { + "ordered-imports": { + options: { + // Legacy sorting until this is fixed: https://github.com/SoominHan/import-sorter/issues/60 + "import-sources-order": "case-insensitive-legacy", + "module-source-path": "full", + "named-imports-order": "case-insensitive-legacy", + }, + }, + }, + }, + ], + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-return": "off", + // 28.11.19: (cvle) Disabled because behavior of regexp.exec seems different than str.match? + "@typescript-eslint/prefer-regexp-exec": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/unbound-method": "off", // 10.10.19: (cvle) seems to give false positive. + }), + overrides: [jestTypeCheckingOverrides], +}; + +const jestOverrides = { + env: { + jest: true, + }, + files: ["test/**/*.ts", "test/**/*.tsx", "**/*.spec.ts", "**/*.spec.tsx"], + globals: { + expectAndFail: "readonly", + fail: "readonly", + }, + rules: { + "no-restricted-globals": "off", + }, +}; + +// Setup the overrides. +const overrides = [jestOverrides, typescriptOverrides]; +// Skip type information to make it faster! +if (process.env.FAST_LINT !== "true") { + overrides.push(typescriptTypeCheckingOverrides); +} + +module.exports = { + overrides, + env: { + browser: true, + es6: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:jsdoc/recommended", + "plugin:prettier/recommended", + "plugin:react-hooks/recommended", + "plugin:react/recommended", + "prettier", + ], + parserOptions: { + ecmaVersion: 2018, + }, + settings: { + react: { + version: "detect", + }, + }, + rules: { + "arrow-body-style": "off", + "arrow-parens": ["off", "as-needed"], + camelcase: "off", + complexity: "off", + "constructor-super": "error", + "spaced-comment": ["error", "always"], + curly: "error", + "dot-notation": "error", + "eol-last": "off", + eqeqeq: "error", + "guard-for-in": "error", + "jsdoc/check-param-names": "off", + "jsdoc/require-jsdoc": "off", + "jsdoc/require-returns": "off", + "jsdoc/require-param": "off", + "jsdoc/require-param-type": "off", + "jsdoc/require-returns-type": "off", + "linebreak-style": "off", + "max-classes-per-file": ["error", 1], + "member-ordering": "off", + "new-parens": "off", + "newline-per-chained-call": "off", + "no-bitwise": "error", + "no-caller": "error", + "no-cond-assign": "error", + "no-console": "error", + "no-debugger": "error", + "no-empty": "error", + "no-eval": "error", + "no-extra-semi": "off", + "no-fallthrough": "error", + "no-invalid-this": "off", + "no-irregular-whitespace": "off", + "no-multiple-empty-lines": "off", + "no-new-wrappers": "error", + "no-restricted-globals": [ + "error", + { + name: "window", + message: + "Get it from 'CoralContext' if possible. Otherwise ignore and make sure using 'window' globally will work in all environments: 'SSR', 'Testing', and 'Browser'", + }, + { + name: "document", + message: "Replace with `window.document`", + }, + { + name: "localStorage", + message: "Replace with `window.localStorage`", + }, + { + name: "sessionStorage", + message: "Replace with `window.sessionStorage`", + }, + { + name: "confirm", + message: "Replace with `window.confirm`", + }, + ], + "no-prototype-builtins": "error", + "no-shadow": "error", + "no-throw-literal": "error", + "no-undef": "off", + "no-undef-init": "error", + "no-unsafe-finally": "error", + "no-unused-expressions": "error", + "no-unused-labels": "error", + "no-unused-vars": ["error", { args: "none", ignoreRestSiblings: true }], + "no-var": "error", + "object-shorthand": "error", + "one-var": "off", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "quote-props": "off", + radix: "error", + "require-atomic-updates": "off", + "space-before-function-paren": "off", + "sort-imports": "off", + "use-isnan": "error", + "valid-typeof": "off", + }, +}; diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000000..9b0419c905 --- /dev/null +++ b/config/.gitignore @@ -0,0 +1,25 @@ +# don't include the dependancies +node_modules/ + +# don't include any logs +npm-debug.log* + +# don't include any yarn files +yarn-error.log +yarn.lock + +# don't include any OS/editor files +.env +.idea/ +.vs +.docz +.next +*.swp +*.DS_STORE + +# don't include any generated files +dist +*.css.d.ts +__generated__ +persisted-queries.json +docs/out diff --git a/config/lib/config.ts b/config/lib/config.ts new file mode 100644 index 0000000000..3d5123571d --- /dev/null +++ b/config/lib/config.ts @@ -0,0 +1,91 @@ +import { LanguageCode } from "./i18n/locales"; + +/** + * SentryReporterConfig is the ReporterConfig for the Sentry service. + */ +export interface SentryReporterConfig { + name: "sentry"; + + /** + * dsn is the string representing this particular integration. + */ + dsn: string; +} + +export type ReporterConfig = SentryReporterConfig; + +/** + * StaticConfig is the configuration provided to the client javascript via a + * JSON blob on the HTML of the embedding page. + */ +export interface StaticConfig { + /** + * staticURI is prepended to the static url's that are included on the static + * pages. + */ + staticURI: string; + + /** + * tenantDomain is the domain of the currently requested tenant. + */ + tenantDomain?: string; + + /** + * reporter stores the reporter configuration for the current reporter + * available. + */ + reporter?: ReporterConfig; + + /** + * graphQLSubscriptionURI is the endpoint that should be used when trying to + * execute subscription GraphQL requests. If an empty string, the default + * should be used that's based on the iFrame location. + */ + graphQLSubscriptionURI: string; + + /** + * featureFlags are all the feature flags currently enabled on the tenant. + */ + featureFlags: string[]; + + /** + * flattenReplies is whether or not flattenReplies is enabled on the tenant. + */ + flattenReplies: boolean; + + /** + * forceAdminLocalAuth is whether local authentication is always available + * for this Coral deployment. This is useful for ensuring that Coral service + * teams can access the admin with their Coral local authentication. + */ + forceAdminLocalAuth: boolean; + + /** + * archivingEnabled will be true when the deployment has set a valid MongoDB + * URI for MONGODB_ARCHIVE_URI. + */ + archivingEnabled: boolean; + + /** + * autoArchiveOlderThanMs is the time in milliseconds that a story will + * be kept before being auto-archived. + */ + autoArchiveOlderThanMs: number; +} + +export interface EmbedBootstrapConfig { + locale: LanguageCode; + assets: { + js: { + src: string; + }[]; + css: { + src: string; + }[]; + }; + customFontsCSSURL: string | undefined; + customCSSURL: string | undefined; + defaultFontsCSSURL: string | undefined; + disableDefaultFonts: boolean; + staticConfig: StaticConfig; +} diff --git a/config/lib/i18n/locales.ts b/config/lib/i18n/locales.ts new file mode 100644 index 0000000000..bd3765e3fd --- /dev/null +++ b/config/lib/i18n/locales.ts @@ -0,0 +1,28 @@ +/** + * LanguageCode is the type represented by the internally identifiable types for + * the different languages that can be supported in the BCP 47 format. + */ +export type LanguageCode = + | "af-ZA" + | "ar-AE" + | "en-US" + | "pt-BR" + | "es" + | "de" + | "tr-TR" + | "hu" + | "id-ID" + | "it-IT" + | "ja-JP" + | "de-CH" + | "nl-NL" + | "da" + | "fr-FR" + | "ro" + | "fi-FI" + | "sv" + | "sk-SK" + | "pl" + | "ru" + | "nb-NO" + | "zh-CN"; \ No newline at end of file diff --git a/config/package-lock.json b/config/package-lock.json new file mode 100644 index 0000000000..463864d067 --- /dev/null +++ b/config/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "common", + "version": "8.3.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "common", + "version": "8.3.1", + "license": "ISC", + "dependencies": { + "typescript": "^3.9.5" + }, + "devDependencies": {} + }, + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==" + } + } +} diff --git a/config/package.json b/config/package.json new file mode 100644 index 0000000000..33b2f531f2 --- /dev/null +++ b/config/package.json @@ -0,0 +1,17 @@ +{ + "name": "common", + "version": "8.3.1", + "description": "", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc --project tsconfig.json" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": {}, + "dependencies": { + "typescript": "^3.9.5" + } +} \ No newline at end of file diff --git a/config/tsconfig.json b/config/tsconfig.json new file mode 100644 index 0000000000..b65c3d978f --- /dev/null +++ b/config/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "allowJs": true, + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "noUnusedLocals": true, + "noImplicitThis": true, + "noImplicitReturns": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noErrorTruncation": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "lib": ["dom", "es2018", "esnext.asynciterable"], + "baseUrl": "./", + "paths": { + "coral-common/*": ["./lib/*"] + }, + "declaration": true, + "outDir": "./dist", + }, + "include": [ + "./lib/**/*.ts", + "./lib/**/.*.js", + "./lib/types/**/*.d.ts", + ], + "exclude": ["node_modules"] +} diff --git a/generate.sh b/generate.sh index eb6e806b1c..fcfc670c91 100644 --- a/generate.sh +++ b/generate.sh @@ -7,6 +7,11 @@ cd server npm run generate cd .. +echo "running \`npm run build\` for \`config\`" +cd config +npm run build +cd .. + echo "running \`npm run build\` for \`common\`" cd common npm run build diff --git a/initialize.sh b/initialize.sh index b44f2e87f1..459f390e9a 100644 --- a/initialize.sh +++ b/initialize.sh @@ -14,11 +14,9 @@ echo "running \`npm install\` for sub-directories" sh npm-i.sh -echo "generating schema types for client, common" +echo "running generation steps for sub-directories" -cd server -npm run generate -cd .. +sh generate.sh echo "creating a \`client\` build to generate manifests"