diff --git a/.eslintrc.json b/.eslintrc.json index 0b5cb28d..1bee8957 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,7 @@ { - "extends": ["@exabyte-io/eslint-config"] + "extends": [ + "@exabyte-io/eslint-config", + "plugin:import/typescript" + ] } diff --git a/package-lock.json b/package-lock.json index 6913a8e6..3581e67a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2835,6 +2835,16 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, "enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -3183,6 +3193,52 @@ } } }, + "eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "dependencies": { + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + } + } + }, "eslint-module-utils": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", @@ -3801,6 +3857,15 @@ "get-intrinsic": "^1.1.1" } }, + "get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3940,6 +4005,23 @@ } } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -5896,6 +5978,12 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "resolve.exports": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", @@ -6289,6 +6377,12 @@ } } }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", diff --git a/package.json b/package.json index a4941544..04ffa0ac 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "eslint-plugin-react": "7.30.0", "eslint-plugin-simple-import-sort": "7.0.0", "eslint-import-resolver-exports": "^1.0.0-beta.2", + "eslint-import-resolver-typescript": "^3.6.1", "husky": "^7.0.4", "lint-staged": "^12.1.2", "mocha": "^9.1.3", diff --git a/src/utils/file.js b/src/utils/file.js index b738774e..7eb06e3e 100644 --- a/src/utils/file.js +++ b/src/utils/file.js @@ -1,6 +1,10 @@ import fs from "fs"; +import yaml from "js-yaml"; +import setValue from "lodash/set"; import path from "path"; +import { JsYamlAllSchemas } from "./yaml"; + const FILE_EXTENSION_TO_PROGRAMMING_LANGUAGE_MAP = { in: "fortran", sh: "shell", @@ -76,3 +80,84 @@ export function createObjectPathFromFilePath(filePath, root) { const parentDirs = root ? path.relative(root, dirname).split(path.sep) : []; return [...parentDirs, basename].map((item) => `['${item}']`).join(""); } + +/** + * Reads asset file and stores asset data in target object under object path which reflects the file system. + * @param {Object} targetObject - Object in which asset data should be stored + * @param {string} assetPath - Absolute path to asset file. + * @param {string} assetRoot - Path to asset root directory to construct relative path. + */ +export function loadAndInsertAssetData(targetObject, assetPath, assetRoot) { + const fileContent = fs.readFileSync(assetPath, "utf8"); + const data = yaml.load(fileContent, { schema: JsYamlAllSchemas }); + const objectPath = createObjectPathFromFilePath(assetPath, assetRoot); + setValue(targetObject, objectPath, data); +} + +/** + * Traverse asset folder recursively and load Yaml asset files. + * @param currPath {string} - path to asset directory + * @param {Object} targetObj - Object in which assets are assigned + * @param {string} assetRoot - Path to asset root directory to construct relative path. + */ +export function getAssetDataFromPath(currPath, targetObj, assetRoot) { + const branches = getDirectories(currPath); + const assetFiles = getFilesInDirectory(currPath, [".yml", ".yaml"], false); + + assetFiles.forEach((asset) => { + try { + loadAndInsertAssetData(targetObj, path.join(currPath, asset), assetRoot); + } catch (e) { + console.log(e); + } + }); + branches.forEach((b) => { + getAssetDataFromPath(path.resolve(currPath, b), targetObj, assetRoot); + }); +} + +/** + * Serialize object as JS source file. + * @param {object} obj + * @param {string} obj.config - Object config to serialize. + * @param {string} obj.targetPath - Path to target JS source file. + * @param {string} obj.dataKey - Object key for data in target JS source file. + * @param {boolean} obj.debug - Whether to print messages to console. + * @param {boolean} obj.eslintDisable - Whether add eslint-disable flag to top of file. + */ +export function buildJSAssetFromConfig({ + config, + targetPath, + dataKey = "", + debug = true, + eslintDisable = true, +}) { + const ignore = eslintDisable ? "/* eslint-disable */\n" : ""; + const moduleExport = dataKey + ? `module.exports = {${dataKey}: ` + JSON.stringify(config) + "}" + : `module.exports = ${JSON.stringify(config)}`; + fs.writeFileSync(targetPath, ignore + moduleExport + "\n", "utf8"); + if (debug) console.log(`Written config to "${targetPath}"`); +} + +/** + * Serialize object from Yaml as JS source file. + * @param {object} obj + * @param {string} obj.assetPath - Path to Yaml asset. + * @param {string} obj.targetPath - Path to target JS source file. + * @param {string} obj.dataKey - Object key for data in target JS source file. + * @param {boolean} obj.debug - Whether to print messages to console. + * @param {boolean} obj.eslintDisable - Whether add eslint-disable flag to top of file. + */ +export function buildJsAssetFromYaml({ + assetPath, + targetPath, + dataKey = "", + debug = true, + eslintDisable = true, +}) { + const fileContent = fs.readFileSync(assetPath); + const config = yaml.load(fileContent, { schema: JsYamlAllSchemas }); + buildJSAssetFromConfig({ config, targetPath, dataKey, debug: false, eslintDisable }); + if (debug) console.log(`Written asset "${assetPath}" to "${targetPath}"`); +} diff --git a/src/utils/index.ts b/src/utils/index.ts index c464eecd..4fd2cef4 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,8 +4,11 @@ import { cloneClass, extendClass, extendClassStaticProps, extendThis } from "./c import { deepClone } from "./clone"; import { refreshCodeMirror } from "./codemirror"; import { + buildJSAssetFromConfig, + buildJsAssetFromYaml, createObjectPathFromFilePath, formatFileSize, + getAssetDataFromPath, getDirectories, getFilesInDirectory, getProgrammingLanguageFromFileExtension, @@ -27,7 +30,7 @@ import { sortKeysDeepForObject, stringifyObject, } from "./object"; -import { getSchemaWithDependencies, buildNamedEntitySchema } from "./schemas"; +import { buildNamedEntitySchema, getSchemaWithDependencies } from "./schemas"; import { getSearchQuerySelector } from "./selector"; import { convertArabicToRoman, @@ -62,6 +65,9 @@ export { sortKeysDeepForObject, stringifyObject, getProgrammingLanguageFromFileExtension, + getAssetDataFromPath, + buildJSAssetFromConfig, + buildJsAssetFromYaml, formatFileSize, calculateHashFromObject, calculateHashFromString, diff --git a/src/utils/schemas.ts b/src/utils/schemas.ts index 0b0f096b..68d30b07 100644 --- a/src/utils/schemas.ts +++ b/src/utils/schemas.ts @@ -1,10 +1,9 @@ import { JSONSchema } from "@exabyte-io/esse.js/schema"; +import { JSONSchema7Definition } from "json-schema"; import forEach from "lodash/forEach"; import hasProperty from "lodash/has"; import isEmpty from "lodash/isEmpty"; -import { JSONSchema7Definition } from "json-schema"; - import { JSONSchemasInterface } from "../JSONSchemasInterface"; export * from "@exabyte-io/esse.js/lib/js/esse/schemaUtils"; @@ -245,7 +244,6 @@ const buildNamedEntitiesDependencies = (entities: NamedEntity[]) => { schemaByNamedEntityName(entity.name) || defaultNamedEntitySchema(entity.name); return { - ...filterForGenerativeProperties(schema), }; }),